Date: Tue, 11 Jul 2006 16:18:36 GMT From: Howard Su <howardsu@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 101279 for review Message-ID: <200607111618.k6BGIaSr057677@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=101279 Change 101279 by howardsu@su_laptop on 2006/07/11 16:17:54 one missing file in last commit Affected files ... .. //depot/projects/dtrace/src/sys/cddl/dev/sdt/sdt.c#4 edit Differences ... ==== //depot/projects/dtrace/src/sys/cddl/dev/sdt/sdt.c#4 (text+ko) ==== @@ -1,33 +1,33 @@ -/*- - * Copyright 2006 John Birrell <jb@FreeBSD.org> + +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * Portions Copyright 2006 John Birrell jb@freebsd.org * * $FreeBSD$ * - * Statically Defined Tracing (SDT) provider for DTrace. This driver relies - * on the 'sdt' backend kernel intrastructure which registers and - * de-registers SDT probes using SYSINIT/SYSUNINIT. - * + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #include <sys/cdefs.h> @@ -48,11 +48,13 @@ #include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> +#include <sys/pcpu.h> #include <sys/poll.h> #include <sys/proc.h> #include <sys/selinfo.h> #include <sys/smp.h> #include <sys/syscall.h> +#include <sys/sysctl.h> #include <sys/sysent.h> #include <sys/sysproto.h> #include <sys/uio.h> @@ -60,16 +62,24 @@ #include <machine/stdarg.h> #include <contrib/opensolaris/uts/common/sys/dtrace_impl.h> -#include <sys/sdt.h> +#include <contrib/opensolaris/uts/common/sys/sdt_impl.h> + +MALLOC_DECLARE(M_SDT); +MALLOC_DEFINE(M_SDT, "sdt", "Static Dtrace Tracing"); + +#define SDT_PATCHVAL 0xf0 +#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask) +#define SDT_PROBETAB_SIZE 0x1000/* 4k entries -- 16K total */ -static d_open_t sdt_open; -static int sdt_provide_ref(struct sdt_ref *, void *); +static d_open_t sdt_open; static int sdt_unload(void); -static void sdt_provide(void *, dtrace_probedesc_t *); +static void sdt_provide_module(void *, modctl_t *); static void sdt_destroy(void *, dtrace_id_t, void *); static void sdt_enable(void *, dtrace_id_t, void *); static void sdt_disable(void *, dtrace_id_t, void *); static void sdt_load(void *); +static void sdt_suspend(void *, dtrace_id_t, void *); +static void sdt_resume(void *, dtrace_id_t, void *); static struct cdevsw sdt_cdevsw = { .d_version = D_VERSION, @@ -77,21 +87,13 @@ .d_name = "sdt", }; -static dtrace_pattr_t sdt_attr = { -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_COMMON }, -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_COMMON }, -{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -}; - static dtrace_pops_t sdt_pops = { - sdt_provide, NULL, + sdt_provide_module, sdt_enable, sdt_disable, - NULL, - NULL, + sdt_suspend, + sdt_resume, NULL, NULL, NULL, @@ -99,90 +101,303 @@ }; static struct cdev *sdt_cdev; -static dtrace_provider_id_t sdt_id; +static sdt_probe_t **sdt_probetab; +static int sdt_probetab_size; +static int sdt_probetab_mask; +static int sdt_verbose = 1; -int -sdt_provide_ref(struct sdt_ref *ref, void *arg) +static int +sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval) { - if (dtrace_probe_lookup(sdt_id, ref->mod, ref->func, ref->name) != 0) + uintptr_t stack0, stack1, stack2, stack3, stack4; + sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; + + for (; sdt != NULL; sdt = sdt->sdp_hashnext) { + if ((uintptr_t)sdt->sdp_patchpoint == addr) { + int i = 0; + /* + * When accessing the arguments on the stack, + * we must protect against accessing beyond + * the stack. We can safely set NOFAULT here + * -- we know that interrupts are already + * disabled. + */ + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + stack0 = stack[i++]; + stack1 = stack[i++]; + stack2 = stack[i++]; + stack3 = stack[i++]; + stack4 = stack[i++]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | + CPU_DTRACE_BADADDR); + + dtrace_probe(sdt->sdp_id, stack0, stack1, + stack2, stack3, stack4); + return (DTRACE_INVOP_NOP); + } + } + + return (0); +} + +static int +sdt_provide_module_function(linker_file_t lf, linker_symval_t *symval, void *opaque) +{ + char *modname = opaque; + sdt_probedesc_t *sdpd; + sdt_probe_t *sdp, *old; + sdt_provider_t *prov; + int len; + + /* + * One for all, and all for one: if we haven't yet registered all of + * our providers, we'll refuse to provide anything. + */ + for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { + if (prov->sdtp_id == DTRACE_PROVNONE) + return (0); + } + + if (lf->sdt_nprobes != 0 || (sdpd = lf->sdt_probes) == NULL) return (0); - ref->id = dtrace_probe_create(sdt_id, ref->mod, ref->func, ref->name, 0, ref); + for (; sdpd != NULL; sdpd = sdpd->sdpd_next) { + char *name = sdpd->sdpd_name, *func, *nname; + int i, j; + sdt_provider_t *prov; + dtrace_id_t id; + + for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { + char *prefix = prov->sdtp_prefix; + + if (strncmp(name, prefix, strlen(prefix)) == 0) { + name += strlen(prefix); + break; + } + } + + nname = malloc(len = strlen(name) + 1, M_SDT, M_WAITOK); + + for (i = 0, j = 0; name[j] != '\0'; i++) { + if (name[j] == '_' && name[j + 1] == '_') { + nname[i] = '-'; + j += 2; + } else { + nname[i] = name[j++]; + } + } + + nname[i] = '\0'; + + sdp = malloc(sizeof (sdt_probe_t), M_SDT, M_WAITOK | M_ZERO); + sdp->sdp_loadcnt = lf->loadcnt; + sdp->sdp_ctl = lf; + sdp->sdp_name = nname; + sdp->sdp_namelen = len; + sdp->sdp_provider = prov; + + if (symval->name == NULL) + func = "<unknown>"; + else { + /* HACK: we need change prototype of _probe_lookup */ + func = malloc(strlen(symval->name) + 1, M_SDT, M_WAITOK); + strcpy(func, symval->name); + } + + /* + * We have our provider. Now create the probe. + */ + if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, + func, nname)) != DTRACE_IDNONE) { + old = dtrace_probe_arg(prov->sdtp_id, id); + ASSERT(old != NULL); + + sdp->sdp_next = old->sdp_next; + sdp->sdp_id = id; + old->sdp_next = sdp; + } else { + sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, + modname, func, nname, 3, sdp); + + lf->sdt_nprobes++; + } + + sdp->sdp_hashnext = + sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)]; + sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; - return (0); + sdp->sdp_patchval = SDT_PATCHVAL; + sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset; + sdp->sdp_savedval = *sdp->sdp_patchpoint; + if (symval->name != NULL) + free(func, M_SDT); + } + return (0); } /*ARGSUSED*/ static void -sdt_provide(void *arg, dtrace_probedesc_t *desc) +sdt_provide_module(void *arg, modctl_t *lf) { - sdt_ref_listall(sdt_provide_ref, NULL); + char modname[MAXPATHLEN]; + size_t len; + + strlcpy(modname, lf->filename, sizeof(modname)); + len = strlen(modname); + if (len > 3 && strcmp(modname + len - 3, ".ko") == 0) + modname[len - 3] = '\0'; + + /* + * List the functions in the module and the symbol values. + */ + linker_file_function_listall(lf, sdt_provide_module_function, modname); } /* ARGSUSED */ static void sdt_destroy(void *arg, dtrace_id_t id, void *parg) { + sdt_probe_t *sdt = parg, *next, *hash, *last; + modctl_t *ctl; + int ndx; + + do { + ctl = sdt->sdp_ctl; + + ctl->sdt_nentries--; + + /* + * Now we need to remove this probe from the sdt_probetab. + */ + ndx = SDT_ADDR2NDX(sdt->sdp_patchpoint); + last = NULL; + hash = sdt_probetab[ndx]; + + while (hash != sdt) { + ASSERT(hash != NULL); + last = hash; + hash = hash->sdp_hashnext; + } + + if (last != NULL) { + last->sdp_hashnext = sdt->sdp_hashnext; + } else { + sdt_probetab[ndx] = sdt->sdp_hashnext; + } + + next = sdt->sdp_next; + free(sdt, M_SDT); + + sdt = next; + } while (sdt != NULL); } /* ARGSUSED */ static void sdt_enable(void *arg, dtrace_id_t id, void *parg) { - struct sdt_ref *ref = parg; + sdt_probe_t *sdt = parg; + modctl_t *ctl = sdt->sdp_ctl; -#if defined(__i386__) - u_int16_t *p; + ctl->nenabled++; /* - * Point to the instruction after the start probe label. + * 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. */ - p = (u_int16_t *) ref->probe_start + 1; + if (ctl->loadcnt != sdt->sdp_loadcnt) { + if (sdt_verbose) { + printf("sdt is failing for probe %s " + "(module %s reloaded)", + sdt->sdp_name, ctl->filename); + } + + return; + } - /* - * Enable the probe. - */ - *p = ref->probe_enable; -#else -#error "Need machine dependent code!" -#endif + for (; sdt != NULL; sdt = sdt->sdp_next) { + if (sdt_verbose) + printf("sdt_enable %s\n",sdt->sdp_name); + *sdt->sdp_patchpoint = sdt->sdp_patchval; + } } /* ARGSUSED */ static void sdt_disable(void *arg, dtrace_id_t id, void *parg) { - struct sdt_ref *ref = parg; + sdt_probe_t *sdt = parg; + modctl_t *ctl = sdt->sdp_ctl; + + ASSERT(ctl->nenabled > 0); + ctl->nenabled--; + + if ((ctl->loadcnt != sdt->sdp_loadcnt)) + return; + + for (; sdt != NULL; sdt = sdt->sdp_next) + *sdt->sdp_patchpoint = sdt->sdp_savedval; +} + +/*ARGSUSED*/ +static void +sdt_suspend(void *arg, dtrace_id_t id, void *parg) +{ + sdt_probe_t *sdt = parg; + modctl_t *ctl = sdt->sdp_ctl; + + ASSERT(ctl->nenabled > 0); + + if ((ctl->loadcnt != sdt->sdp_loadcnt)) + return; + + for (; sdt != NULL; sdt = sdt->sdp_next) + *sdt->sdp_patchpoint = sdt->sdp_savedval; +} + +/*ARGSUSED*/ +static void +sdt_resume(void *arg, dtrace_id_t id, void *parg) +{ + sdt_probe_t *sdt = parg; + modctl_t *ctl = sdt->sdp_ctl; -#if defined(__i386__) - u_int16_t *p; + ASSERT(ctl->nenabled > 0); - /* - * Point to the instruction after the start probe label. - */ - p = (u_int16_t *) ref->probe_start + 1; + if ((ctl->loadcnt != sdt->sdp_loadcnt)) + return; - /* - * Disable the probe. - */ - *p = ref->probe_disable; -#else -#error "Need machine dependent code!" -#endif + for (; sdt != NULL; sdt = sdt->sdp_next) + *sdt->sdp_patchpoint = sdt->sdp_patchval; } static void sdt_load(void *dummy) { - if (dtrace_register("sdt", &sdt_attr, DTRACE_PRIV_USER, - NULL, &sdt_pops, NULL, &sdt_id) != 0) - return; + sdt_provider_t *prov; + + /* Default the probe table size if not specified. */ + if (sdt_probetab_size == 0) + sdt_probetab_size = SDT_PROBETAB_SIZE; + + /* Choose the hash mask for the probe table. */ + sdt_probetab_mask = sdt_probetab_size - 1; + + /* Allocate memory for the probe table. */ + sdt_probetab = malloc(sdt_probetab_size * sizeof + (sdt_probe_t *), M_SDT, M_WAITOK | M_ZERO); + + dtrace_invop_add(sdt_invop); - /* - * Register the read DTrace probe function pointer in place - * of the stub. - */ - sdt_probe_func = dtrace_probe; + for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { + if (dtrace_register(prov->sdtp_name, prov->sdtp_attr, + DTRACE_PRIV_USER, NULL, + &sdt_pops, prov, &prov->sdtp_id) != 0) { + printf("failed to register sdt provider %s", + prov->sdtp_name); + } + } } @@ -190,14 +405,25 @@ sdt_unload() { int error = 0; + sdt_provider_t *prov; + + /* De-register the invalid opcode handler. */ + dtrace_invop_remove(sdt_invop); - /* - * Restore the probe stub. - */ - sdt_probe_func = sdt_probe_stub; - - if ((error = dtrace_unregister(sdt_id)) != 0) - return (error); + /* De-register this DTrace provider. */ + for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { + if ((error = dtrace_unregister(prov->sdtp_id)) != 0) { + return (error); + } + else { + prov->sdtp_id = 0; + } + } + + /* Free the probe table. */ + free(sdt_probetab, M_SDT); + sdt_probetab = NULL; + sdt_probetab_mask = 0; destroy_dev(sdt_cdev); @@ -229,6 +455,7 @@ break; } + return (error); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607111618.k6BGIaSr057677>