* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-/* #pragma ident "@(#)fbt.c 1.15 05/09/19 SMI" */
+/* #pragma ident "@(#)fbt.c 1.18 07/01/10 SMI" */
#ifdef KERNEL
#ifndef _KERNEL
#endif
#include <mach-o/loader.h>
-#include <kern/mach_header.h>
-
-extern struct mach_header _mh_execute_header; /* the kernel's mach header */
+#include <libkern/kernel_mach_header.h>
#include <sys/param.h>
#include <sys/systm.h>
/* #include <machine/trap.h> */
struct savearea_t; /* Used anonymously */
-typedef kern_return_t (*perfCallback)(int, struct savearea_t *, int, int);
-#if defined (__ppc__) || defined (__ppc64__)
-extern perfCallback tempDTraceTrapHook, tempDTraceIntHook;
-extern kern_return_t fbt_perfCallback(int, struct savearea_t *, int, int);
-extern kern_return_t fbt_perfIntCallback(int, struct savearea_t *, int, int);
-#else
+typedef kern_return_t (*perfCallback)(int, struct savearea_t *, uintptr_t *, __unused int);
extern perfCallback tempDTraceTrapHook;
-extern kern_return_t fbt_perfCallback(int, struct savearea_t *, int, int);
-#endif
+extern kern_return_t fbt_perfCallback(int, struct savearea_t *, uintptr_t *, __unused int);
#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
}
/*ARGSUSED*/
-static void
+int
fbt_enable(void *arg, dtrace_id_t id, void *parg)
{
#pragma unused(arg,id)
fbt_probe_t *fbt = parg;
- struct modctl *ctl = fbt->fbtp_ctl;
+ struct modctl *ctl = NULL;
-#if defined (__ppc__) || defined (__ppc64__)
- dtrace_casptr(&tempDTraceIntHook, NULL, fbt_perfIntCallback);
- if (tempDTraceIntHook != (perfCallback)fbt_perfIntCallback) {
+ for (; fbt != NULL; fbt = fbt->fbtp_next) {
+
+ ctl = fbt->fbtp_ctl;
+
+ if (!ctl->mod_loaded) {
if (fbt_verbose) {
- cmn_err(CE_NOTE, "fbt_enable is failing for probe %s "
- "in module %s: tempDTraceIntHook already occupied.",
+ cmn_err(CE_NOTE, "fbt is failing for probe %s "
+ "(module %s unloaded)",
fbt->fbtp_name, ctl->mod_modname);
}
- return;
+
+ continue;
}
-#endif
-
+
+ /*
+ * Now check that our modctl has the expected load count. If it
+ * doesn't, this module must have been unloaded and reloaded -- and
+ * we're not going to touch it.
+ */
+ if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) {
+ if (fbt_verbose) {
+ cmn_err(CE_NOTE, "fbt is failing for probe %s "
+ "(module %s reloaded)",
+ fbt->fbtp_name, ctl->mod_modname);
+ }
+
+ continue;
+ }
+
dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
if (fbt_verbose) {
"in module %s: tempDTraceTrapHook already occupied.",
fbt->fbtp_name, ctl->mod_modname);
}
- return;
+ continue;
}
- for (; fbt != NULL; fbt = fbt->fbtp_next)
+ if (fbt->fbtp_currentval != fbt->fbtp_patchval) {
(void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
sizeof(fbt->fbtp_patchval));
-
- dtrace_membar_consumer();
+ fbt->fbtp_currentval = fbt->fbtp_patchval;
+ ctl->mod_nenabled++;
+ }
+
+ }
+
+ dtrace_membar_consumer();
+
+ return (0);
}
/*ARGSUSED*/
{
#pragma unused(arg,id)
fbt_probe_t *fbt = parg;
+ struct modctl *ctl = NULL;
- for (; fbt != NULL; fbt = fbt->fbtp_next)
+ for (; fbt != NULL; fbt = fbt->fbtp_next) {
+ ctl = fbt->fbtp_ctl;
+
+ if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
+ continue;
+
+ if (fbt->fbtp_currentval != fbt->fbtp_savedval) {
(void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
sizeof(fbt->fbtp_savedval));
-
+ fbt->fbtp_currentval = fbt->fbtp_savedval;
+ ASSERT(ctl->mod_nenabled > 0);
+ ctl->mod_nenabled--;
+ }
+ }
dtrace_membar_consumer();
}
{
#pragma unused(arg,id)
fbt_probe_t *fbt = parg;
+ struct modctl *ctl = NULL;
- for (; fbt != NULL; fbt = fbt->fbtp_next)
- (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
+ for (; fbt != NULL; fbt = fbt->fbtp_next) {
+ ctl = fbt->fbtp_ctl;
+
+ ASSERT(ctl->mod_nenabled > 0);
+ if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
+ continue;
+
+ (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
sizeof(fbt->fbtp_savedval));
+
+ fbt->fbtp_currentval = fbt->fbtp_savedval;
+ }
+
dtrace_membar_consumer();
}
{
#pragma unused(arg,id)
fbt_probe_t *fbt = parg;
- struct modctl *ctl = fbt->fbtp_ctl;
+ struct modctl *ctl = NULL;
-#if defined (__ppc__) || defined (__ppc64__)
- dtrace_casptr(&tempDTraceIntHook, NULL, fbt_perfIntCallback);
- if (tempDTraceIntHook != (perfCallback)fbt_perfIntCallback) {
- if (fbt_verbose) {
- cmn_err(CE_NOTE, "fbt_enable is failing for probe %s "
- "in module %s: tempDTraceIntHook already occupied.",
- fbt->fbtp_name, ctl->mod_modname);
- }
- return;
- }
-#endif
+ for (; fbt != NULL; fbt = fbt->fbtp_next) {
+ ctl = fbt->fbtp_ctl;
+
+ ASSERT(ctl->mod_nenabled > 0);
+ if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
+ continue;
- dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
- if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
+ dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
+ if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
if (fbt_verbose) {
cmn_err(CE_NOTE, "fbt_resume is failing for probe %s "
"in module %s: tempDTraceTrapHook already occupied.",
fbt->fbtp_name, ctl->mod_modname);
}
return;
- }
+ }
- for (; fbt != NULL; fbt = fbt->fbtp_next)
- (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
+ (void)ml_nofault_copy( (vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
sizeof(fbt->fbtp_patchval));
+
+ fbt->fbtp_currentval = fbt->fbtp_patchval;
+ }
+
dtrace_membar_consumer();
}
* If we have a parent container, we must manually import it.
*/
if ((parent = ctf_parent_name(fp)) != NULL) {
- struct modctl *mod;
+ struct modctl *mp = &modules;
+ struct modctl *mod = NULL;
/*
* We must iterate over all modules to find the module that
* is our parent.
*/
- for (mod = &modules; mod != NULL; mod = mod->mod_next) {
- if (strcmp(mod->mod_filename, parent) == 0)
+ do {
+ if (strcmp(mp->mod_modname, parent) == 0) {
+ mod = mp;
break;
- }
+ }
+ } while ((mp = mp->mod_next) != &modules);
if (mod == NULL)
goto err;
- if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL)
+ if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) {
goto err;
+ }
if (ctf_import(fp, pfp) != 0) {
ctf_close(pfp);
#if !defined(__APPLE__)
fbt_getargdesc,
#else
- NULL, /* XXX where to look for xnu? */
+ NULL, /* FIXME: where to look for xnu? */
#endif /* __APPLE__ */
NULL,
NULL,
dtrace_invop_add(fbt_invop);
+#if !defined(__APPLE__)
if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0,
DDI_PSEUDO, NULL) == DDI_FAILURE ||
dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
fbt_cleanup(devi);
return (DDI_FAILURE);
}
+#else
+ if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0,
+ DDI_PSEUDO, 0) == DDI_FAILURE ||
+ dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
+ &fbt_pops, NULL, &fbt_id) != 0) {
+ fbt_cleanup(devi);
+ return (DDI_FAILURE);
+ }
+#endif /* __APPLE__ */
ddi_report_dev(devi);
fbt_devi = devi;
0 /* type */
};
-static int gDisableFBT = 0;
-struct modctl g_fbt_kernctl;
+int gIgnoreFBTBlacklist = 0;
+static int gFBTInited = 0;
#undef kmem_alloc /* from its binding to dt_kmem_alloc glue */
#undef kmem_free /* from its binding to dt_kmem_free glue */
#include <vm/vm_kern.h>
void
fbt_init( void )
{
-
- PE_parse_boot_arg("DisableFBT", &gDisableFBT);
-
- if (0 == gDisableFBT)
+ if (0 == gFBTInited)
{
int majdevno = cdevsw_add(FBT_MAJOR, &fbt_cdevsw);
- int size = 0, header_size, round_size;
- kern_return_t ret;
- void *p, *q;
if (majdevno < 0) {
printf("fbt_init: failed to allocate a major number!\n");
return;
}
+
+ PE_parse_boot_argn("IgnoreFBTBlacklist", &gIgnoreFBTBlacklist, sizeof (gIgnoreFBTBlacklist));
- /*
- * Capture the kernel's mach_header in its entirety and the contents of
- * its LINKEDIT segment (and only that segment). This is sufficient to
- * build all the fbt probes lazily the first time a client looks to
- * the fbt provider. Remeber thes on the global struct modctl g_fbt_kernctl.
- */
- header_size = sizeof(struct mach_header) + _mh_execute_header.sizeofcmds;
- p = getsegdatafromheader(&_mh_execute_header, SEG_LINKEDIT, &size);
-
- round_size = round_page_32(header_size + size);
- ret = kmem_alloc_pageable(kernel_map, (vm_offset_t *)&q, round_size);
-
- if (p && (ret == KERN_SUCCESS)) {
- struct segment_command *sgp;
-
- bcopy( (void *)&_mh_execute_header, q, header_size);
- bcopy( p, (char *)q + header_size, size);
-
- sgp = getsegbynamefromheader(q, SEG_LINKEDIT);
-
- if (sgp) {
- sgp->vmaddr = (unsigned long)((char *)q + header_size);
- g_fbt_kernctl.address = (vm_address_t)q;
- g_fbt_kernctl.size = header_size + size;
- } else {
- kmem_free(kernel_map, (vm_offset_t)q, round_size);
- g_fbt_kernctl.address = (vm_address_t)NULL;
- g_fbt_kernctl.size = 0;
- }
- } else {
- if (ret == KERN_SUCCESS)
- kmem_free(kernel_map, (vm_offset_t)q, round_size);
- g_fbt_kernctl.address = (vm_address_t)NULL;
- g_fbt_kernctl.size = 0;
- }
-
- strncpy((char *)&(g_fbt_kernctl.mod_modname), "mach_kernel", KMOD_MAX_NAME);
-
- fbt_attach( (dev_info_t *)majdevno, DDI_ATTACH );
-
- gDisableFBT = 1; /* Ensure this initialization occurs just one time. */
+ fbt_attach( (dev_info_t *)(uintptr_t)majdevno, DDI_ATTACH );
+
+ gFBTInited = 1; /* Ensure this initialization occurs just one time. */
}
else
- printf("fbt_init: DisableFBT non-zero, no FBT probes will be provided.\n");
+ panic("fbt_init: called twice!\n");
}
#undef FBT_MAJOR