X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..143464d58d2bd6378e74eec636961ceb0d32fb91:/bsd/dev/dtrace/fbt.c diff --git a/bsd/dev/dtrace/fbt.c b/bsd/dev/dtrace/fbt.c index f1b85f42f..3101debd1 100644 --- a/bsd/dev/dtrace/fbt.c +++ b/bsd/dev/dtrace/fbt.c @@ -2,9 +2,8 @@ * 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. @@ -20,11 +19,11 @@ * 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 @@ -33,9 +32,7 @@ #endif #include -#include - -extern struct mach_header _mh_execute_header; /* the kernel's mach header */ +#include #include #include @@ -55,16 +52,10 @@ extern struct mach_header _mh_execute_header; /* the kernel's mach header */ /* #include */ 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 */ @@ -114,25 +105,42 @@ fbt_destroy(void *arg, dtrace_id_t id, void *parg) } /*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) { @@ -140,14 +148,21 @@ fbt_enable(void *arg, dtrace_id_t id, void *parg) "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*/ @@ -156,11 +171,22 @@ fbt_disable(void *arg, dtrace_id_t id, void *parg) { #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(); } @@ -170,11 +196,22 @@ fbt_suspend(void *arg, dtrace_id_t id, void *parg) { #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(); } @@ -184,34 +221,32 @@ fbt_resume(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) { - 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(); } @@ -251,22 +286,26 @@ fbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) * 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); @@ -326,7 +365,7 @@ static dtrace_pops_t fbt_pops = { #if !defined(__APPLE__) fbt_getargdesc, #else - NULL, /* XXX where to look for xnu? */ + NULL, /* FIXME: where to look for xnu? */ #endif /* __APPLE__ */ NULL, NULL, @@ -364,6 +403,7 @@ fbt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 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, @@ -371,6 +411,15 @@ fbt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 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; @@ -411,8 +460,8 @@ static struct cdevsw fbt_cdevsw = 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 @@ -420,64 +469,22 @@ struct modctl g_fbt_kernctl; 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