PERFORCE change 101279 for review

Howard Su howardsu at FreeBSD.org
Tue Jul 11 16:18:39 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=101279

Change 101279 by howardsu at 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 at 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 at 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);
 }
 


More information about the p4-projects mailing list