aboutsummaryrefslogtreecommitdiff
path: root/sys/cddl/contrib/opensolaris/uts/common/dtrace
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2016-04-10 01:25:48 +0000
committerMark Johnston <markj@FreeBSD.org>2016-04-10 01:25:48 +0000
commitb52902867604a2a5141c0e5d5bcc7ed2c5f96ab8 (patch)
treefd9e73d2a0133421cd4a8af938b3c790bd50e959 /sys/cddl/contrib/opensolaris/uts/common/dtrace
parent8553156023784d4305fe505c15ede787e2eab614 (diff)
downloadsrc-b52902867604a2a5141c0e5d5bcc7ed2c5f96ab8.tar.gz
src-b52902867604a2a5141c0e5d5bcc7ed2c5f96ab8.zip
Implement support for boot-time DTrace.
This allows one to enable DTrace probes relatively early during boot, during SI_SUB_DTRACE_ANON, before dtrace(1) can invoked. The desired enabling is created using dtrace -A, which writes a /boot/dtrace.dof file and uses nextboot(8) to ensure that DTrace kernel modules are loaded and that the DOF file describing the enabling is loaded by loader(8) during the subsequent boot. The trace output can then be fetched with dtrace -a. With this commit, boot-time DTrace is only functional on i386 and amd64: on other architectures, the high-resolution timer frequency is initialized during SI_SUB_CLOCKS and is thus not available when the anonymous tracing state is initialized. On x86, the TSC is used and is thus available earlier. MFC after: 1 month Relnotes: yes
Notes
Notes: svn path=/head/; revision=297773
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/dtrace')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c161
1 files changed, 112 insertions, 49 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
index 7ec7dfdeaf99..00129751769e 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -117,6 +117,7 @@
#include <sys/ctype.h>
#include <sys/eventhandler.h>
#include <sys/limits.h>
+#include <sys/linker.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
@@ -11916,6 +11917,21 @@ dtrace_buffer_activate(dtrace_state_t *state)
dtrace_interrupt_enable(cookie);
}
+#ifdef __FreeBSD__
+/*
+ * Activate the specified per-CPU buffer. This is used instead of
+ * dtrace_buffer_activate() when APs have not yet started, i.e. when
+ * activating anonymous state.
+ */
+static void
+dtrace_buffer_activate_cpu(dtrace_state_t *state, int cpu)
+{
+
+ if (state->dts_buffer[cpu].dtb_tomax != NULL)
+ state->dts_buffer[cpu].dtb_flags &= ~DTRACEBUF_INACTIVE;
+}
+#endif
+
static int
dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
processorid_t cpu, int *factor)
@@ -12532,9 +12548,15 @@ dtrace_enabling_dump(dtrace_enabling_t *enab)
for (i = 0; i < enab->dten_ndesc; i++) {
dtrace_probedesc_t *desc = &enab->dten_desc[i]->dted_probe;
+#ifdef __FreeBSD__
+ printf("dtrace: enabling probe %d (%s:%s:%s:%s)\n", i,
+ desc->dtpd_provider, desc->dtpd_mod,
+ desc->dtpd_func, desc->dtpd_name);
+#else
cmn_err(CE_NOTE, "enabling probe %d (%s:%s:%s:%s)", i,
desc->dtpd_provider, desc->dtpd_mod,
desc->dtpd_func, desc->dtpd_name);
+#endif
}
}
@@ -13185,19 +13207,91 @@ dtrace_dof_char(char c)
return (c - 'a' + 10);
}
/* Should not reach here. */
- return (0);
+ return (UCHAR_MAX);
}
#endif /* __FreeBSD__ */
static dof_hdr_t *
dtrace_dof_property(const char *name)
{
+#ifdef __FreeBSD__
+ uint8_t *dofbuf;
+ u_char *data, *eol;
+ caddr_t doffile;
+ size_t bytes, len, i;
+ dof_hdr_t *dof;
+ u_char c1, c2;
+
+ dof = NULL;
+
+ doffile = preload_search_by_type("dtrace_dof");
+ if (doffile == NULL)
+ return (NULL);
+
+ data = preload_fetch_addr(doffile);
+ len = preload_fetch_size(doffile);
+ for (;;) {
+ /* Look for the end of the line. All lines end in a newline. */
+ eol = memchr(data, '\n', len);
+ if (eol == NULL)
+ return (NULL);
+
+ if (strncmp(name, data, strlen(name)) == 0)
+ break;
+
+ eol++; /* skip past the newline */
+ len -= eol - data;
+ data = eol;
+ }
+
+ /* We've found the data corresponding to the specified key. */
+
+ data += strlen(name) + 1; /* skip past the '=' */
+ len = eol - data;
+ bytes = len / 2;
+
+ if (bytes < sizeof(dof_hdr_t)) {
+ dtrace_dof_error(NULL, "truncated header");
+ goto doferr;
+ }
+
+ /*
+ * Each byte is represented by the two ASCII characters in its hex
+ * representation.
+ */
+ dofbuf = malloc(bytes, M_SOLARIS, M_WAITOK);
+ for (i = 0; i < bytes; i++) {
+ c1 = dtrace_dof_char(data[i * 2]);
+ c2 = dtrace_dof_char(data[i * 2 + 1]);
+ if (c1 == UCHAR_MAX || c2 == UCHAR_MAX) {
+ dtrace_dof_error(NULL, "invalid hex char in DOF");
+ goto doferr;
+ }
+ dofbuf[i] = c1 * 16 + c2;
+ }
+
+ dof = (dof_hdr_t *)dofbuf;
+ if (bytes < dof->dofh_loadsz) {
+ dtrace_dof_error(NULL, "truncated DOF");
+ goto doferr;
+ }
+
+ if (dof->dofh_loadsz >= dtrace_dof_maxsize) {
+ dtrace_dof_error(NULL, "oversized DOF");
+ goto doferr;
+ }
+
+ return (dof);
+
+doferr:
+ free(dof, M_SOLARIS);
+ return (NULL);
+#else /* __FreeBSD__ */
uchar_t *buf;
uint64_t loadsz;
unsigned int len, i;
dof_hdr_t *dof;
-#ifdef illumos
/*
* Unfortunately, array of values in .conf files are always (and
* only) interpreted to be integer arrays. We must read our DOF
@@ -13231,49 +13325,9 @@ dtrace_dof_property(const char *name)
dof = kmem_alloc(loadsz, KM_SLEEP);
bcopy(buf, dof, loadsz);
ddi_prop_free(buf);
-#else
- char *p;
- char *p_env;
-
- if ((p_env = kern_getenv(name)) == NULL)
- return (NULL);
-
- len = strlen(p_env) / 2;
-
- buf = kmem_alloc(len, KM_SLEEP);
-
- dof = (dof_hdr_t *) buf;
-
- p = p_env;
-
- for (i = 0; i < len; i++) {
- buf[i] = (dtrace_dof_char(p[0]) << 4) |
- dtrace_dof_char(p[1]);
- p += 2;
- }
-
- freeenv(p_env);
-
- if (len < sizeof (dof_hdr_t)) {
- kmem_free(buf, 0);
- dtrace_dof_error(NULL, "truncated header");
- return (NULL);
- }
-
- if (len < (loadsz = dof->dofh_loadsz)) {
- kmem_free(buf, 0);
- dtrace_dof_error(NULL, "truncated DOF");
- return (NULL);
- }
-
- if (loadsz >= dtrace_dof_maxsize) {
- kmem_free(buf, 0);
- dtrace_dof_error(NULL, "oversized DOF");
- return (NULL);
- }
-#endif
return (dof);
+#endif /* !__FreeBSD__ */
}
static void
@@ -14332,7 +14386,7 @@ static dtrace_state_t *
#ifdef illumos
dtrace_state_create(dev_t *devp, cred_t *cr)
#else
-dtrace_state_create(struct cdev *dev)
+dtrace_state_create(struct cdev *dev, struct ucred *cred __unused)
#endif
{
#ifdef illumos
@@ -14945,6 +14999,18 @@ dtrace_state_go(dtrace_state_t *state, processorid_t *cpu)
if (state->dts_activity == DTRACE_ACTIVITY_WARMUP)
state->dts_activity = DTRACE_ACTIVITY_ACTIVE;
+#ifdef __FreeBSD__
+ /*
+ * We enable anonymous tracing before APs are started, so we must
+ * activate buffers using the current CPU.
+ */
+ if (state == dtrace_anon.dta_state)
+ for (int i = 0; i < NCPU; i++)
+ dtrace_buffer_activate_cpu(state, i);
+ else
+ dtrace_xcall(DTRACE_CPUALL,
+ (dtrace_xcall_t)dtrace_buffer_activate, state);
+#else
/*
* Regardless of whether or not now we're in ACTIVE or DRAINING, we
* want each CPU to transition its principal buffer out of the
@@ -14955,6 +15021,7 @@ dtrace_state_go(dtrace_state_t *state, processorid_t *cpu)
*/
dtrace_xcall(DTRACE_CPUALL,
(dtrace_xcall_t)dtrace_buffer_activate, state);
+#endif
goto out;
err:
@@ -15316,11 +15383,7 @@ dtrace_anon_property(void)
* If we haven't allocated an anonymous state, we'll do so now.
*/
if ((state = dtrace_anon.dta_state) == NULL) {
-#ifdef illumos
state = dtrace_state_create(NULL, NULL);
-#else
- state = dtrace_state_create(NULL);
-#endif
dtrace_anon.dta_state = state;
if (state == NULL) {
@@ -17001,7 +17064,7 @@ dtrace_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
state = dtrace_state_create(devp, cred_p);
#else
- state = dtrace_state_create(dev);
+ state = dtrace_state_create(dev, NULL);
devfs_set_cdevpriv(state, dtrace_dtr);
#endif