summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/abi/apptrace/amd64/Makefile38
-rw-r--r--usr/src/cmd/abi/apptracecmd/apptrace.c4
-rw-r--r--usr/src/cmd/dtrace/dtrace.c69
-rw-r--r--usr/src/lib/libdtrace/common/dt_cc.c13
-rw-r--r--usr/src/lib/libdtrace/common/dt_parser.c8
-rw-r--r--usr/src/lib/libdtrace/common/dt_pid.c409
-rw-r--r--usr/src/lib/libdtrace/common/dt_pid.h8
-rw-r--r--usr/src/lib/libdtrace/common/dt_proc.c97
-rw-r--r--usr/src/lib/libdtrace/common/dt_proc.h16
-rw-r--r--usr/src/lib/libdtrace/common/dt_program.c215
-rw-r--r--usr/src/lib/libdtrace/common/dt_work.c21
-rw-r--r--usr/src/lib/libdtrace/common/dtrace.h9
-rw-r--r--usr/src/lib/libdtrace/spec/dtrace.spec6
-rw-r--r--usr/src/uts/sparc/dtrace/dtrace_isa.c16
14 files changed, 640 insertions, 289 deletions
diff --git a/usr/src/cmd/abi/apptrace/amd64/Makefile b/usr/src/cmd/abi/apptrace/amd64/Makefile
deleted file mode 100644
index 5f319ca4dd..0000000000
--- a/usr/src/cmd/abi/apptrace/amd64/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# 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.
-#
-# 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
-#
-#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# ident "%Z%%M% %I% %E% SMI"
-#
-
-include ../Makefile.com
-
-.KEEP_STATE:
-
-all: $(OBJDIR) $(PICDIR) .WAIT $(APPTRACELIB) .WAIT $(INTCPTLIB)
-
-install: all $(ROOTLIBABI64) .WAIT $(ROOTLIBABILIBS64)
-
-include ../Makefile.targ
-include ../../Makefile.sub.64
diff --git a/usr/src/cmd/abi/apptracecmd/apptrace.c b/usr/src/cmd/abi/apptracecmd/apptrace.c
index 44af91c920..1782f990b5 100644
--- a/usr/src/cmd/abi/apptracecmd/apptrace.c
+++ b/usr/src/cmd/abi/apptracecmd/apptrace.c
@@ -21,7 +21,7 @@
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -366,7 +366,7 @@ usage(char const *prog)
" A comma separated list of interfaces to trace.\n"
" A list preceded by ! is an exlusion list.\n"
" -v <verboselist>\n"
- " A comman separated list of interfaces to trace\n"
+ " A comma separated list of interfaces to trace\n"
" verbosely.\n"
" A list preceded by ! is an exclusion list.\n"
" Interfaces matched in -v do not also need to be\n"
diff --git a/usr/src/cmd/dtrace/dtrace.c b/usr/src/cmd/dtrace/dtrace.c
index ed60a06a62..c725e79346 100644
--- a/usr/src/cmd/dtrace/dtrace.c
+++ b/usr/src/cmd/dtrace/dtrace.c
@@ -60,13 +60,14 @@ typedef struct dtrace_cmd {
#define DMODE_ANON 2 /* compile program for anonymous tracing (-A) */
#define DMODE_LINK 3 /* compile program for linking with ELF (-G) */
#define DMODE_LIST 4 /* compile program and list probes (-l) */
+#define DMODE_HEADER 5 /* compile program for headergen (-h) */
#define E_SUCCESS 0
#define E_ERROR 1
#define E_USAGE 2
static const char DTRACE_OPTSTR[] =
- "3:6:aAb:Bc:CD:ef:FGHi:I:lL:m:n:o:p:P:qs:SU:vVwx:X:Z";
+ "3:6:aAb:Bc:CD:ef:FGhHi:I:lL:m:n:o:p:P:qs:SU:vVwx:X:Z";
static char **g_argv;
static int g_argc;
@@ -114,7 +115,7 @@ usage(FILE *fp)
{
static const char predact[] = "[[ predicate ] action ]";
- (void) fprintf(fp, "Usage: %s [-32|-64] [-aACeFGHlqSvVwZ] "
+ (void) fprintf(fp, "Usage: %s [-32|-64] [-aACeFGhHlqSvVwZ] "
"[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] "
"[-o output] [-p pid] [-s script] [-U name]\n\t"
"[-x opt[=val]] [-X a|c|s|t]\n\n"
@@ -141,6 +142,7 @@ usage(FILE *fp)
"\t-f enable or list probes matching the specified function name\n"
"\t-F coalesce trace output by function\n"
"\t-G generate an ELF file containing embedded dtrace program\n"
+ "\t-h generate a header file with definitions for static probes\n"
"\t-H print included files when invoking preprocessor\n"
"\t-i enable or list probes matching the specified probe id\n"
"\t-I add include directory to preprocessor search path\n"
@@ -732,12 +734,17 @@ compile_str(dtrace_cmd_t *dcp)
/*ARGSUSED*/
static void
-prochandler(struct ps_prochandle *P, void *arg)
+prochandler(struct ps_prochandle *P, const char *msg, void *arg)
{
const psinfo_t *prp = Ppsinfo(P);
int pid = Pstatus(P)->pr_pid;
char name[SIG2STR_MAX];
+ if (msg != NULL) {
+ notice("pid %d: %s\n", pid, msg);
+ return;
+ }
+
switch (Pstate(P)) {
case PS_UNDEAD:
/*
@@ -1215,6 +1222,14 @@ main(int argc, char *argv[])
done = 1;
break;
+ case 'h':
+ g_mode = DMODE_HEADER;
+ g_oflags |= DTRACE_O_NODEV;
+ g_cflags |= DTRACE_C_ZDEFS; /* -h implies -Z */
+ g_exec = 0;
+ mode++;
+ break;
+
case 'G':
g_mode = DMODE_LINK;
g_oflags |= DTRACE_O_NODEV;
@@ -1245,7 +1260,7 @@ main(int argc, char *argv[])
}
if (mode > 1) {
- (void) fprintf(stderr, "%s: only one of the [-AGlV] options "
+ (void) fprintf(stderr, "%s: only one of the [-AGhlV] options "
"can be specified at a time\n", g_pname);
return (E_USAGE);
}
@@ -1622,6 +1637,52 @@ main(int argc, char *argv[])
dtrace_close(g_dtp);
return (g_status);
+
+ case DMODE_HEADER:
+ if (g_cmdc == 0) {
+ (void) fprintf(stderr, "%s: -h requires one or more "
+ "scripts or enabling options\n", g_pname);
+ dtrace_close(g_dtp);
+ return (E_USAGE);
+ }
+
+ if (g_ofile == NULL) {
+ char *p;
+
+ if (g_cmdc > 1) {
+ (void) fprintf(stderr, "%s: -h requires an "
+ "output file if multiple scripts are "
+ "specified\n", g_pname);
+ dtrace_close(g_dtp);
+ return (E_USAGE);
+ }
+
+ if ((p = strrchr(g_cmdv[0].dc_arg, '.')) == NULL ||
+ strcmp(p, ".d") != 0) {
+ (void) fprintf(stderr, "%s: -h requires an "
+ "output file if no scripts are "
+ "specified\n", g_pname);
+ dtrace_close(g_dtp);
+ return (E_USAGE);
+ }
+
+ p[0] = '\0'; /* strip .d suffix */
+ g_ofile = p = g_cmdv[0].dc_ofile;
+ (void) snprintf(p, sizeof (g_cmdv[0].dc_ofile),
+ "%s.h", basename(g_cmdv[0].dc_arg));
+ }
+
+ if ((g_ofp = fopen(g_ofile, "w")) == NULL)
+ fatal("failed to open header file '%s'", g_ofile);
+
+ oprintf("/*\n * Generated by dtrace(1M).\n */\n\n");
+
+ if (dtrace_program_header(g_dtp, g_ofp, g_ofile) != 0 ||
+ fclose(g_ofp) == EOF)
+ dfatal("failed to create header file %s", g_ofile);
+
+ dtrace_close(g_dtp);
+ return (g_status);
}
/*
diff --git a/usr/src/lib/libdtrace/common/dt_cc.c b/usr/src/lib/libdtrace/common/dt_cc.c
index e4272187dd..9d95f480c1 100644
--- a/usr/src/lib/libdtrace/common/dt_cc.c
+++ b/usr/src/lib/libdtrace/common/dt_cc.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1434,10 +1435,14 @@ dt_setcontext(dtrace_hdl_t *dtp, dtrace_probedesc_t *pdp)
/*
* If the provider name ends with what could be interpreted as a
* number, we assume that it's a pid and that we may need to
- * dynamically create those probes for that process.
+ * dynamically create those probes for that process. On an error,
+ * dt_pid_create_probes() will set the error message and tag --
+ * we just have to longjmp() out of here.
*/
- if (isdigit(pdp->dtpd_provider[strlen(pdp->dtpd_provider) - 1]))
- dt_pid_create_probes(pdp, dtp);
+ if (isdigit(pdp->dtpd_provider[strlen(pdp->dtpd_provider) - 1]) &&
+ dt_pid_create_probes(pdp, dtp, yypcb) != 0) {
+ longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
+ }
/*
* Call dt_probe_info() to get the probe arguments and attributes. If
diff --git a/usr/src/lib/libdtrace/common/dt_parser.c b/usr/src/lib/libdtrace/common/dt_parser.c
index 07db59982e..9aabc18565 100644
--- a/usr/src/lib/libdtrace/common/dt_parser.c
+++ b/usr/src/lib/libdtrace/common/dt_parser.c
@@ -2498,6 +2498,7 @@ dt_node_provider(char *name, dt_node_t *probes)
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
dt_node_t *dnp = dt_node_alloc(DT_NODE_PROVIDER);
dt_node_t *lnp;
+ size_t len;
dnp->dn_provname = name;
dnp->dn_probes = probes;
@@ -2507,11 +2508,16 @@ dt_node_provider(char *name, dt_node_t *probes)
"contain scoping operator: %s\n", name);
}
- if (strlen(name) >= DTRACE_PROVNAMELEN) {
+ if ((len = strlen(name)) >= DTRACE_PROVNAMELEN) {
dnerror(dnp, D_PROV_BADNAME, "provider name may not exceed %d "
"characters: %s\n", DTRACE_PROVNAMELEN - 1, name);
}
+ if (isdigit(name[len - 1])) {
+ dnerror(dnp, D_PROV_BADNAME, "provider name may not "
+ "end with a digit: %s\n", name);
+ }
+
/*
* Check to see if the provider is already defined or visible through
* dtrace(7D). If so, set dn_provred to treat it as a re-declaration.
diff --git a/usr/src/lib/libdtrace/common/dt_pid.c b/usr/src/lib/libdtrace/common/dt_pid.c
index b91cf6ef56..35f51ec1c3 100644
--- a/usr/src/lib/libdtrace/common/dt_pid.c
+++ b/usr/src/lib/libdtrace/common/dt_pid.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,19 +43,21 @@
#include <dt_string.h>
typedef struct dt_pid_probe {
- dtrace_hdl_t *dpp_dtp;
- struct ps_prochandle *dpp_pr;
- const char *dpp_mod;
- char *dpp_func;
- const char *dpp_name;
- const char *dpp_obj;
- uintptr_t dpp_pc;
- size_t dpp_size;
- Lmid_t dpp_lmid;
- uint_t dpp_nmatches;
- uint64_t dpp_stret[4];
- GElf_Sym dpp_last;
- uint_t dpp_last_taken;
+ dtrace_hdl_t *dpp_dtp;
+ dt_pcb_t *dpp_pcb;
+ dt_proc_t *dpp_dpr;
+ struct ps_prochandle *dpp_pr;
+ const char *dpp_mod;
+ char *dpp_func;
+ const char *dpp_name;
+ const char *dpp_obj;
+ uintptr_t dpp_pc;
+ size_t dpp_size;
+ Lmid_t dpp_lmid;
+ uint_t dpp_nmatches;
+ uint64_t dpp_stret[4];
+ GElf_Sym dpp_last;
+ uint_t dpp_last_taken;
} dt_pid_probe_t;
/*
@@ -70,19 +73,39 @@ dt_pid_objname(char *buf, size_t len, Lmid_t lmid, const char *obj)
(void) snprintf(buf, len, "LM%lx`%s", lmid, obj);
}
-static void
-dt_pid_error(dtrace_hdl_t *dtp, dt_errtag_t tag, const char *fmt, ...)
+static int
+dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr,
+ fasttrap_probe_spec_t *ftp, dt_errtag_t tag, const char *fmt, ...)
{
va_list ap;
+ int len;
+
+ if (ftp != NULL)
+ dt_free(dtp, ftp);
va_start(ap, fmt);
- dt_set_errmsg(dtp, dt_errtag(tag), NULL, NULL, 0, fmt, ap);
+ if (pcb == NULL) {
+ assert(dpr != NULL);
+ len = vsnprintf(dpr->dpr_errmsg, sizeof (dpr->dpr_errmsg),
+ fmt, ap);
+ assert(len >= 2);
+ if (dpr->dpr_errmsg[len - 2] == '\n')
+ dpr->dpr_errmsg[len - 2] = '\0';
+ } else {
+ dt_set_errmsg(dtp, dt_errtag(tag), pcb->pcb_region,
+ pcb->pcb_filetag, pcb->pcb_fileptr ? yylineno : 0, fmt, ap);
+ }
va_end(ap);
+
+ return (1);
}
-static void
+static int
dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
{
+ dtrace_hdl_t *dtp = pp->dpp_dtp;
+ dt_pcb_t *pcb = pp->dpp_pcb;
+ dt_proc_t *dpr = pp->dpp_dpr;
fasttrap_probe_spec_t *ftp;
uint64_t off;
char *end;
@@ -100,12 +123,9 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
sz = sizeof (fasttrap_probe_spec_t) + (isdash ? 4 :
(symp->st_size - 1) * sizeof (ftp->ftps_offs[0]));
- if (sz < 4000) {
- ftp = alloca(sz);
- sz = 0;
- } else if ((ftp = malloc(sz)) == NULL) {
- dt_dprintf("proc_per_sym: malloc(%lu) failed\n", sz);
- return;
+ if ((ftp = dt_alloc(dtp, sz)) == NULL) {
+ dt_dprintf("proc_per_sym: dt_alloc(%lu) failed\n", sz);
+ return (1); /* errno is set for us */
}
ftp->ftps_pid = pid;
@@ -115,17 +135,24 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
pp->dpp_obj);
if (!isdash && gmatch("return", pp->dpp_name)) {
- if (dt_pid_create_return_probe(pp->dpp_pr, pp->dpp_dtp,
- ftp, symp, pp->dpp_stret) < 0)
- goto create_err;
+ if (dt_pid_create_return_probe(pp->dpp_pr, dtp, ftp, symp,
+ pp->dpp_stret) < 0) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL, "failed to create return probe "
+ "for '%s': %s", func,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
nmatches++;
}
if (!isdash && gmatch("entry", pp->dpp_name)) {
- if (dt_pid_create_entry_probe(pp->dpp_pr, pp->dpp_dtp,
- ftp, symp) < 0)
- goto create_err;
+ if (dt_pid_create_entry_probe(pp->dpp_pr, dtp, ftp, symp) < 0) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL, "failed to create entry probe "
+ "for '%s': %s", func,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
nmatches++;
}
@@ -134,65 +161,51 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
if (!glob && nmatches == 0) {
off = strtoull(pp->dpp_name, &end, 16);
if (*end != '\0') {
- if (sz != 0)
- free(ftp);
- dt_proc_release(pp->dpp_dtp, pp->dpp_pr);
- xyerror(D_PROC_NAME, "'%s' is an invalid probe name\n",
- pp->dpp_name);
+ return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_NAME,
+ "'%s' is an invalid probe name", pp->dpp_name));
}
if (off >= symp->st_size) {
- dt_pid_error(pp->dpp_dtp, D_PROC_OFF, "offset "
- "0x%llx outside of function '%s'\n",
- (u_longlong_t)off, func);
- goto out;
+ return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_OFF,
+ "offset 0x%llx outside of function '%s'",
+ (u_longlong_t)off, func));
}
err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp,
symp, off);
- if (err == DT_PROC_ERR)
- goto create_err;
+ if (err == DT_PROC_ERR) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL, "failed to create probe at "
+ "'%s+0x%llx': %s", func, (u_longlong_t)off,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
+
if (err == DT_PROC_ALIGN) {
-#ifdef __sparc
- if (sz != 0)
- free(ftp);
- dt_proc_release(pp->dpp_dtp, pp->dpp_pr);
- xyerror(D_PROC_ALIGN, "offset 0x%llx is not properly "
- "aligned\n", (u_longlong_t)off);
-#else
- dt_pid_error(pp->dpp_dtp, D_PROC_ALIGN, "offset "
- "0x%llx is not aligned on an instruction\n",
- (u_longlong_t)off);
- goto out;
-#endif
+ return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_ALIGN,
+ "offset 0x%llx is not aligned on an instruction",
+ (u_longlong_t)off));
}
nmatches++;
} else if (glob && !isdash) {
if (dt_pid_create_glob_offset_probes(pp->dpp_pr,
- pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0)
- goto create_err;
+ pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) {
+ return (dt_pid_error(dtp, pcb, dpr, ftp,
+ D_PROC_CREATEFAIL,
+ "failed to create offset probes in '%s': %s", func,
+ dtrace_errmsg(dtp, dtrace_errno(dtp))));
+ }
nmatches++;
}
pp->dpp_nmatches += nmatches;
-out:
- if (sz != 0)
- free(ftp);
- return;
+ dt_free(dtp, ftp);
-create_err:
- if (sz != 0)
- free(ftp);
-
- dt_proc_release(pp->dpp_dtp, pp->dpp_pr);
- dt_pid_error(pp->dpp_dtp, D_PROC_CREATEFAIL, "failed to create "
- "probe in process %d: %s", (int)pid,
- dtrace_errmsg(pp->dpp_dtp, dtrace_errno(pp->dpp_dtp)));
+ return (0);
}
static int
@@ -208,7 +221,8 @@ dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func)
return (0);
}
- if (symp->st_value != pp->dpp_last.st_value ||
+ if (pp->dpp_last_taken == 0 ||
+ symp->st_value != pp->dpp_last.st_value ||
symp->st_size != pp->dpp_last.st_size) {
/*
* Due to 4524008, _init and _fini may have a bloated st_size.
@@ -220,25 +234,26 @@ dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func)
if (strcmp(func, "_init") == 0 || strcmp(func, "_fini") == 0)
return (0);
- if (gmatch(func, pp->dpp_func)) {
- dt_pid_per_sym(pp, symp, func);
- pp->dpp_last_taken = 1;
+ if ((pp->dpp_last_taken = gmatch(func, pp->dpp_func)) != 0) {
+ pp->dpp_last = *symp;
+ return (dt_pid_per_sym(pp, symp, func));
}
-
- pp->dpp_last = *symp;
}
return (0);
}
-static void
+static int
dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
{
dt_pid_probe_t *pp = arg;
+ dtrace_hdl_t *dtp = pp->dpp_dtp;
+ dt_pcb_t *pcb = pp->dpp_pcb;
+ dt_proc_t *dpr = pp->dpp_dpr;
GElf_Sym sym;
if (obj == NULL)
- return;
+ return (0);
(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
@@ -302,12 +317,12 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
PR_MODEL_ILP32 ? -1U : -1ULL;
} else if (!strisglob(pp->dpp_mod)) {
- dt_proc_release(pp->dpp_dtp, pp->dpp_pr);
- xyerror(D_PROC_FUNC, "failed to lookup '%s' "
- "in module '%s'\n", pp->dpp_func,
- pp->dpp_mod);
+ return (dt_pid_error(dtp, pcb, dpr, NULL,
+ D_PROC_FUNC,
+ "failed to lookup '%s' in module '%s'",
+ pp->dpp_func, pp->dpp_mod));
} else {
- return;
+ return (0);
}
}
@@ -316,58 +331,60 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
*/
if (GELF_ST_TYPE(sym.st_info) != STT_FUNC ||
sym.st_shndx == SHN_UNDEF || sym.st_size == 0)
- return;
+ return (0);
/*
* We don't instrument PLTs -- they're dynamically rewritten,
* and, so, inherently dicey to instrument.
*/
if (Ppltdest(pp->dpp_pr, sym.st_value) != NULL)
- return;
+ return (0);
(void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func,
DTRACE_FUNCNAMELEN, &sym);
- dt_pid_per_sym(pp, &sym, pp->dpp_func);
+ return (dt_pid_per_sym(pp, &sym, pp->dpp_func));
} else {
uint_t nmatches = pp->dpp_nmatches;
- (void) Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
- BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp);
+ if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
+ BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
+ return (1);
if (nmatches == pp->dpp_nmatches) {
/*
* If we didn't match anything in the PR_SYMTAB, try
* the PR_DYNSYM.
*/
- (void) Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_DYNSYM,
- BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp);
+ if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_DYNSYM,
+ BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
+ return (1);
}
}
+
+ return (0);
}
static int
dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj)
{
+ char name[DTRACE_MODNAMELEN];
dt_pid_probe_t *pp = arg;
- if (gmatch(obj, pp->dpp_mod)) {
- dt_pid_per_mod(pp, pmp, obj);
- } else {
- char name[DTRACE_MODNAMELEN];
+ if (gmatch(obj, pp->dpp_mod))
+ return (dt_pid_per_mod(pp, pmp, obj));
- (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
+ (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
- if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
- pp->dpp_obj = obj;
- else
- pp->dpp_obj++;
+ if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
+ pp->dpp_obj = obj;
+ else
+ pp->dpp_obj++;
- dt_pid_objname(name, sizeof (name), pp->dpp_lmid, obj);
+ dt_pid_objname(name, sizeof (name), pp->dpp_lmid, obj);
- if (gmatch(name, pp->dpp_mod))
- dt_pid_per_mod(pp, pmp, obj);
- }
+ if (gmatch(name, pp->dpp_mod))
+ return (dt_pid_per_mod(pp, pmp, obj));
return (0);
}
@@ -417,29 +434,38 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
}
-static void
-dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, pid_t pid)
+static int
+dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
+ dt_pcb_t *pcb, dt_proc_t *dpr)
{
dt_pid_probe_t pp;
+ int ret = 0;
- pp.dpp_pr = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
- if (pp.dpp_pr == NULL)
- longjmp(dtp->dt_pcb->pcb_jmpbuf, EDT_COMPILER);
+ /*
+ * Disable breakpoints so they don't interfere with our disassembly.
+ */
+ dt_proc_bpdisable(dpr);
+
+ pp.dpp_dtp = dtp;
+ pp.dpp_dpr = dpr;
+ pp.dpp_pr = dpr->dpr_proc;
+ pp.dpp_pcb = pcb;
/*
* We can only trace dynamically-linked executables (since we've
* hidden some magic in ld.so.1 as well as libc.so.1).
*/
if (Pname_to_map(pp.dpp_pr, PR_OBJ_LDSO) == NULL) {
- dt_proc_release(dtp, pp.dpp_pr);
- xyerror(D_PROC_DYN, "process %s is not a dynamically-linked "
- "executable\n", &pdp->dtpd_provider[3]);
+ dt_proc_bpenable(dpr);
+ return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_DYN,
+ "process %s is not a dynamically-linked executable",
+ &pdp->dtpd_provider[3]));
}
- pp.dpp_dtp = dtp;
pp.dpp_mod = pdp->dtpd_mod[0] != '\0' ? pdp->dtpd_mod : "*";
pp.dpp_func = pdp->dtpd_func[0] != '\0' ? pdp->dtpd_func : "*";
pp.dpp_name = pdp->dtpd_name[0] != '\0' ? pdp->dtpd_name : "*";
+ pp.dpp_last_taken = 0;
if (strcmp(pp.dpp_func, "-") == 0) {
const prmap_t *aout, *pmp;
@@ -451,15 +477,17 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, pid_t pid)
(aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL ||
(pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
aout->pr_vaddr != pmp->pr_vaddr) {
- dt_proc_release(dtp, pp.dpp_pr);
- xyerror(D_PROC_LIB, "only the a.out module is valid "
- "with the '-' function\n");
+ dt_proc_bpenable(dpr);
+ return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_LIB,
+ "only the a.out module is valid with the "
+ "'-' function"));
}
if (strisglob(pp.dpp_name)) {
- dt_proc_release(dtp, pp.dpp_pr);
- xyerror(D_PROC_NAME, "only individual addresses may "
- "be specified with the '-' function\n");
+ dt_proc_bpenable(dpr);
+ return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_NAME,
+ "only individual addresses may be specified "
+ "with the '-' function"));
}
}
@@ -469,13 +497,13 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, pid_t pid)
* pattern. An empty module name is treated as '*'.
*/
if (strisglob(pp.dpp_mod)) {
- (void) Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp);
+ ret = Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp);
} else {
const prmap_t *pmp;
char *obj;
/*
- * If can't find a matching module, don't sweat it -- either
+ * If we can't find a matching module, don't sweat it -- either
* we'll fail the enabling because the probes don't exist or
* we'll wait for that module to come along.
*/
@@ -485,11 +513,13 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, pid_t pid)
else
obj++;
- dt_pid_per_mod(&pp, pmp, obj);
+ ret = dt_pid_per_mod(&pp, pmp, obj);
}
}
- dt_proc_release(dtp, pp.dpp_pr);
+ dt_proc_bpenable(dpr);
+
+ return (ret);
}
static int
@@ -498,12 +528,11 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
struct ps_prochandle *P = data;
GElf_Sym sym;
prsyminfo_t sip;
- int fd;
dof_helper_t dh;
GElf_Half e_type;
const char *mname;
const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
- int i;
+ int i, fd = -1;
/*
* The symbol ___SUNW_dof is for lazy-loaded DOF sections, and
@@ -536,42 +565,51 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
sip.prs_lmid, mname);
- if ((fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
+ if (fd == -1 &&
+ (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("pr_open of helper device failed: %s\n",
strerror(errno));
- return (errno);
+ return (-1); /* errno is set for us */
}
- (void) pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh));
-
- if (pr_close(P, fd) != 0)
- return (errno);
+ if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
+ dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
}
+ if (fd != -1)
+ (void) pr_close(P, fd);
+
return (0);
}
static int
-dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dt_proc_t *dpr)
+dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
+ dt_pcb_t *pcb, dt_proc_t *dpr)
{
struct ps_prochandle *P = dpr->dpr_proc;
- int err;
+ int ret = 0;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
(void) Pupdate_maps(P);
- err = Pobject_iter(P, dt_pid_usdt_mapping, P);
+ if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
+ ret = -1;
+ (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
+ "failed to instantiate probes for pid %d: %s",
+ (int)Pstatus(P)->pr_pid, strerror(errno));
+ }
/*
* Put the module name in its canonical form.
*/
(void) dt_pid_fix_mod(pdp, P);
- return (err);
+ return (ret);
}
static pid_t
-dt_pid_get_pid(dtrace_probedesc_t *pdp, int *errp)
+dt_pid_get_pid(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
+ dt_proc_t *dpr)
{
pid_t pid;
char *c, *last = NULL, *end;
@@ -582,89 +620,100 @@ dt_pid_get_pid(dtrace_probedesc_t *pdp, int *errp)
}
if (last == NULL || (*(++last) == '\0')) {
- if (errp != NULL) {
- *errp = D_PROC_BADPROV;
- return (-1);
- }
- xyerror(D_PROC_BADPROV, "%s is not a valid provider\n",
- pdp->dtpd_provider);
+ (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPROV,
+ "'%s' is not a valid provider", pdp->dtpd_provider);
+ return (-1);
}
errno = 0;
pid = strtol(last, &end, 10);
if (errno != 0 || end == last || end[0] != '\0' || pid <= 0) {
- if (errp != NULL) {
- *errp = D_PROC_BADPID;
- return (-1);
- }
- xyerror(D_PROC_BADPID, "%s does not contain a valid pid\n",
- pdp->dtpd_provider);
+ (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPID,
+ "'%s' does not contain a valid pid", pdp->dtpd_provider);
+ return (-1);
}
- if (errp != NULL)
- *errp = 0;
-
return (pid);
}
-void
-dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp)
+int
+dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
{
- pid_t pid = dt_pid_get_pid(pdp, NULL);
char provname[DTRACE_PROVNAMELEN];
struct ps_prochandle *P;
dt_proc_t *dpr;
- int err = 0;
+ pid_t pid;
+ int err;
+
+ assert(pcb != NULL);
+
+ if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1)
+ return (-1);
if (dtp->dt_ftfd == -1) {
if (dtp->dt_fterr == ENOENT) {
- xyerror(D_PROC_NODEV, "pid provider is not "
- "installed on this system\n");
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
+ "pid provider is not installed on this system");
} else {
- xyerror(D_PROC_NODEV, "pid provider is not "
- "available: %s\n", strerror(dtp->dt_fterr));
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
+ "pid provider is not available: %s",
+ strerror(dtp->dt_fterr));
}
+
+ return (-1);
}
(void) snprintf(provname, sizeof (provname), "pid%d", (int)pid);
if (strcmp(provname, pdp->dtpd_provider) == 0) {
- dt_pid_create_pid_probes(pdp, dtp, pid);
- } else {
- if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL)
- longjmp(dtp->dt_pcb->pcb_jmpbuf, EDT_COMPILER);
+ if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE,
+ 0)) == NULL) {
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
+ "failed to grab process %d", (int)pid);
+ return (-1);
+ }
dpr = dt_proc_lookup(dtp, P, 0);
assert(dpr != NULL);
+ (void) pthread_mutex_lock(&dpr->dpr_lock);
+
+ err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr);
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
+ dt_proc_release(dtp, P);
+
+ } else {
+ if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) {
+ (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
+ "failed to grab process %d", (int)pid);
+ return (-1);
+ }
+
+ dpr = dt_proc_lookup(dtp, P, 0);
+ assert(dpr != NULL);
(void) pthread_mutex_lock(&dpr->dpr_lock);
if (!dpr->dpr_usdt) {
- err = dt_pid_create_usdt_probes(pdp, dpr);
+ err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr);
dpr->dpr_usdt = B_TRUE;
}
(void) pthread_mutex_unlock(&dpr->dpr_lock);
-
dt_proc_release(dtp, P);
-
- if (err != 0)
- dt_pid_error(dtp, D_PROC_USDT, "failed to instantiate "
- "probes for PID %d: %s", (int)pid, strerror(err));
}
+
+ return (err ? -1 : 0);
}
-void
+int
dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
dtrace_prog_t *pgp;
dt_stmt_t *stp;
- char provname[DTRACE_PROVNAMELEN];
dtrace_probedesc_t *pdp, pd;
pid_t pid;
- int err;
- int found = B_FALSE;
+ int ret = 0, found = B_FALSE;
for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL;
pgp = dt_list_next(pgp)) {
@@ -673,21 +722,23 @@ dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
stp = dt_list_next(stp)) {
pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe;
- pid = dt_pid_get_pid(pdp, &err);
- if (err != 0 || pid != dpr->dpr_pid)
+ pid = dt_pid_get_pid(pdp, dtp, NULL, dpr);
+ if (pid != dpr->dpr_pid)
continue;
found = B_TRUE;
pd = *pdp;
- (void) snprintf(provname, sizeof (provname), "pid%d",
- (int)pid);
-
- if (strcmp(provname, pdp->dtpd_provider) == 0)
- dt_pid_create_pid_probes(&pd, dtp, pid);
- else
- (void) dt_pid_create_usdt_probes(&pd, dpr);
+ if (strncmp(pdp->dtpd_provider, "pid", 3) == 0) {
+ if (dt_pid_create_pid_probes(&pd, dtp, NULL,
+ dpr) != 0)
+ ret = 1;
+ } else {
+ if (dt_pid_create_usdt_probes(&pd, dtp, NULL,
+ dpr) != 0)
+ ret = 1;
+ }
}
}
@@ -698,4 +749,6 @@ dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
*/
(void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL);
}
+
+ return (ret);
}
diff --git a/usr/src/lib/libdtrace/common/dt_pid.h b/usr/src/lib/libdtrace/common/dt_pid.h
index 30be3c2932..886e33d833 100644
--- a/usr/src/lib/libdtrace/common/dt_pid.h
+++ b/usr/src/lib/libdtrace/common/dt_pid.h
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -40,8 +41,9 @@ extern "C" {
#define DT_PROC_ERR (-1)
#define DT_PROC_ALIGN (-2)
-extern void dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *);
-extern void dt_pid_create_probes_module(dtrace_hdl_t *, dt_proc_t *);
+extern int dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *,
+ dt_pcb_t *pcb);
+extern int dt_pid_create_probes_module(dtrace_hdl_t *, dt_proc_t *);
extern int dt_pid_create_entry_probe(struct ps_prochandle *, dtrace_hdl_t *,
fasttrap_probe_spec_t *, const GElf_Sym *);
diff --git a/usr/src/lib/libdtrace/common/dt_proc.c b/usr/src/lib/libdtrace/common/dt_proc.c
index 0402c60cf1..66bc3aa011 100644
--- a/usr/src/lib/libdtrace/common/dt_proc.c
+++ b/usr/src/lib/libdtrace/common/dt_proc.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -161,7 +162,7 @@ dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
(void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
}
-static void
+void
dt_proc_bpenable(dt_proc_t *dpr)
{
dt_bkpt_t *dbp;
@@ -174,9 +175,11 @@ dt_proc_bpenable(dt_proc_t *dpr)
dbp->dbp_addr, &dbp->dbp_instr) == 0)
dbp->dbp_active = B_TRUE;
}
+
+ dt_dprintf("breakpoints enabled\n");
}
-static void
+void
dt_proc_bpdisable(dt_proc_t *dpr)
{
dt_bkpt_t *dbp;
@@ -189,6 +192,35 @@ dt_proc_bpdisable(dt_proc_t *dpr)
dbp->dbp_addr, dbp->dbp_instr) == 0)
dbp->dbp_active = B_FALSE;
}
+
+ dt_dprintf("breakpoints disabled\n");
+}
+
+static void
+dt_proc_notify(dtrace_hdl_t *dtp, dt_proc_hash_t *dph, dt_proc_t *dpr,
+ const char *msg)
+{
+ dt_proc_notify_t *dprn = dt_alloc(dtp, sizeof (dt_proc_notify_t));
+
+ if (dprn == NULL) {
+ dt_dprintf("failed to allocate notification for %d %s\n",
+ (int)dpr->dpr_pid, msg);
+ } else {
+ dprn->dprn_dpr = dpr;
+ if (msg == NULL)
+ dprn->dprn_errmsg[0] = '\0';
+ else
+ (void) strlcpy(dprn->dprn_errmsg, msg,
+ sizeof (dprn->dprn_errmsg));
+
+ (void) pthread_mutex_lock(&dph->dph_lock);
+
+ dprn->dprn_next = dph->dph_notify;
+ dph->dph_notify = dprn;
+
+ (void) pthread_cond_broadcast(&dph->dph_cv);
+ (void) pthread_mutex_unlock(&dph->dph_lock);
+ }
}
/*
@@ -239,12 +271,14 @@ dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
switch (rdm.type) {
case RD_DLACTIVITY:
- if (rdm.u.state == RD_CONSISTENT) {
- Pupdate_syms(dpr->dpr_proc);
- dt_proc_bpdisable(dpr);
- dt_pid_create_probes_module(dtp, dpr);
- dt_proc_bpenable(dpr);
- }
+ if (rdm.u.state != RD_CONSISTENT)
+ break;
+
+ Pupdate_syms(dpr->dpr_proc);
+ if (dt_pid_create_probes_module(dtp, dpr) != 0)
+ dt_proc_notify(dtp, dtp->dt_procs, dpr,
+ dpr->dpr_errmsg);
+
break;
case RD_PREINIT:
Pupdate_syms(dpr->dpr_proc);
@@ -588,15 +622,8 @@ pwait_locked:
* If the control thread detected PS_UNDEAD or PS_LOST, then enqueue
* the dt_proc_t structure on the dt_proc_hash_t notification list.
*/
- if (notify) {
- (void) pthread_mutex_lock(&dph->dph_lock);
-
- dpr->dpr_notify = dph->dph_notify;
- dph->dph_notify = dpr;
-
- (void) pthread_mutex_unlock(&dph->dph_lock);
- (void) pthread_cond_broadcast(&dph->dph_cv);
- }
+ if (notify)
+ dt_proc_notify(dtp, dph, dpr, NULL);
/*
* Destroy and remove any remaining breakpoints, set dpr_done and clear
@@ -609,8 +636,8 @@ pwait_locked:
dpr->dpr_done = B_TRUE;
dpr->dpr_tid = 0;
- (void) pthread_mutex_unlock(&dpr->dpr_lock);
(void) pthread_cond_broadcast(&dpr->dpr_cv);
+ (void) pthread_mutex_unlock(&dpr->dpr_lock);
return (NULL);
}
@@ -661,7 +688,7 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
{
dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
dt_proc_hash_t *dph = dtp->dt_procs;
- dt_proc_t *npr, **npp;
+ dt_proc_notify_t *npr, **npp;
int rflag;
assert(dpr != NULL);
@@ -723,16 +750,13 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
(void) dt_proc_lookup(dtp, P, B_TRUE);
npp = &dph->dph_notify;
- for (npr = *npp; npr != NULL; npr = npr->dpr_notify) {
- if (npr != dpr)
- npp = &npr->dpr_notify;
- else
- break;
- }
-
- if (npr != NULL) {
- *npp = npr->dpr_notify;
- npr->dpr_notify = NULL;
+ while ((npr = *npp) != NULL) {
+ if (npr->dprn_dpr == dpr) {
+ *npp = npr->dprn_next;
+ dt_free(dtp, npr);
+ } else {
+ npp = &npr->dprn_next;
+ }
}
(void) pthread_mutex_unlock(&dph->dph_lock);
@@ -814,15 +838,7 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
}
err = ESRCH; /* cause grab() or create() to fail */
- } else {
- /*
- * Disable breakpoints while the process is stopped so
- * the pid provider can correctly disassemble all
- * functions.
- */
- dt_proc_bpdisable(dpr);
}
-
} else {
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to create control thread for process-id %d: %s\n",
@@ -988,11 +1004,6 @@ dt_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P)
(void) pthread_mutex_lock(&dpr->dpr_lock);
if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {
- /*
- * Breakpoints are disabled while the process is stopped so
- * the pid provider can correctly disassemble all functions.
- */
- dt_proc_bpenable(dpr);
dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;
(void) pthread_cond_broadcast(&dpr->dpr_cv);
}
diff --git a/usr/src/lib/libdtrace/common/dt_proc.h b/usr/src/lib/libdtrace/common/dt_proc.h
index 2f2b0a67a7..fbc6f4aec1 100644
--- a/usr/src/lib/libdtrace/common/dt_proc.h
+++ b/usr/src/lib/libdtrace/common/dt_proc.h
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -41,9 +42,9 @@ extern "C" {
typedef struct dt_proc {
dt_list_t dpr_list; /* prev/next pointers for lru chain */
struct dt_proc *dpr_hash; /* next pointer for pid hash chain */
- struct dt_proc *dpr_notify; /* next pointer for notification list */
dtrace_hdl_t *dpr_hdl; /* back pointer to libdtrace handle */
struct ps_prochandle *dpr_proc; /* proc handle for libproc calls */
+ char dpr_errmsg[BUFSIZ]; /* error message */
rd_agent_t *dpr_rtld; /* rtld handle for librtld_db calls */
pthread_mutex_t dpr_lock; /* lock for manipulating dpr_hdl */
pthread_cond_t dpr_cv; /* cond for dpr_stop/quit/done */
@@ -60,6 +61,12 @@ typedef struct dt_proc {
dt_list_t dpr_bps; /* list of dt_bkpt_t structures */
} dt_proc_t;
+typedef struct dt_proc_notify {
+ dt_proc_t *dprn_dpr; /* process associated with the event */
+ char dprn_errmsg[BUFSIZ]; /* error message */
+ struct dt_proc_notify *dprn_next; /* next pointer */
+} dt_proc_notify_t;
+
#define DT_PROC_STOP_IDLE 0x01 /* idle on owner's stop request */
#define DT_PROC_STOP_CREATE 0x02 /* wait on dpr_cv at process exec */
#define DT_PROC_STOP_GRAB 0x04 /* wait on dpr_cv at process grab */
@@ -82,7 +89,7 @@ typedef struct dt_bkpt {
typedef struct dt_proc_hash {
pthread_mutex_t dph_lock; /* lock protecting dph_notify list */
pthread_cond_t dph_cv; /* cond for waiting for dph_notify */
- dt_proc_t *dph_notify; /* list of pending proc notifications */
+ dt_proc_notify_t *dph_notify; /* list of pending proc notifications */
dt_list_t dph_lrulist; /* list of dt_proc_t's in lru order */
uint_t dph_lrulim; /* limit on number of procs to hold */
uint_t dph_lrucnt; /* count of cached process handles */
@@ -100,6 +107,9 @@ extern void dt_proc_lock(dtrace_hdl_t *, struct ps_prochandle *);
extern void dt_proc_unlock(dtrace_hdl_t *, struct ps_prochandle *);
extern dt_proc_t *dt_proc_lookup(dtrace_hdl_t *, struct ps_prochandle *, int);
+extern void dt_proc_bpenable(dt_proc_t *);
+extern void dt_proc_bpdisable(dt_proc_t *);
+
extern void dt_proc_hash_create(dtrace_hdl_t *);
extern void dt_proc_hash_destroy(dtrace_hdl_t *);
diff --git a/usr/src/lib/libdtrace/common/dt_program.c b/usr/src/lib/libdtrace/common/dt_program.c
index c87d86aa8e..e0d3ada107 100644
--- a/usr/src/lib/libdtrace/common/dt_program.c
+++ b/usr/src/lib/libdtrace/common/dt_program.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,10 +32,13 @@
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
+#include <ctype.h>
+#include <alloca.h>
#include <dt_impl.h>
#include <dt_program.h>
#include <dt_printf.h>
+#include <dt_provider.h>
dtrace_prog_t *
dt_program_create(dtrace_hdl_t *dtp)
@@ -339,3 +343,212 @@ dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
dt_free(dtp, sdp);
}
+
+typedef struct dt_header_info {
+ dtrace_hdl_t *dthi_dtp; /* consumer handle */
+ FILE *dthi_out; /* output file */
+ char *dthi_pmname; /* provider macro name */
+ char *dthi_pfname; /* provider function name */
+} dt_header_info_t;
+
+
+static void
+dt_header_fmt_macro(char *buf, const char *str)
+{
+ for (;;) {
+ if (islower(*str)) {
+ *buf++ = *str++ + 'A' - 'a';
+ } else if (*str == '-') {
+ *buf++ = '_';
+ str++;
+ } else if (*str == '.') {
+ *buf++ = '_';
+ str++;
+ } else if ((*buf++ = *str++) == '\0') {
+ break;
+ }
+ }
+}
+
+static void
+dt_header_fmt_func(char *buf, const char *str)
+{
+ for (;;) {
+ if (*str == '-') {
+ *buf++ = '_';
+ *buf++ = '_';
+ str++;
+ } else if ((*buf++ = *str++) == '\0') {
+ break;
+ }
+ }
+}
+
+/*ARGSUSED*/
+static int
+dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
+{
+ dt_header_info_t *infop = data;
+ dtrace_hdl_t *dtp = infop->dthi_dtp;
+ dt_probe_t *prp = idp->di_data;
+ dt_node_t *dnp;
+ char buf[DT_TYPE_NAMELEN];
+ char *fname;
+ const char *p;
+ int i;
+
+ p = prp->pr_name;
+ for (i = 0; (p = strchr(p, '-')) != NULL; i++)
+ p++;
+
+ fname = alloca(strlen(prp->pr_name) + 1 + i);
+ dt_header_fmt_func(fname, prp->pr_name);
+
+ if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
+ infop->dthi_pfname, fname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
+ if (fprintf(infop->dthi_out, "%s",
+ ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
+ buf, sizeof (buf))) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (i + 1 != prp->pr_nargc &&
+ fprintf(infop->dthi_out, ", ") < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (fprintf(infop->dthi_out, ");\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
+{
+ dt_header_info_t *infop = data;
+ dtrace_hdl_t *dtp = infop->dthi_dtp;
+ dt_probe_t *prp = idp->di_data;
+ char *mname, *fname;
+ const char *p;
+ int i;
+
+ p = prp->pr_name;
+ for (i = 0; (p = strchr(p, '-')) != NULL; i++)
+ p++;
+
+ mname = alloca(strlen(prp->pr_name) + 1);
+ dt_header_fmt_macro(mname, prp->pr_name);
+
+ fname = alloca(strlen(prp->pr_name) + 1 + i);
+ dt_header_fmt_func(fname, prp->pr_name);
+
+ if (fprintf(infop->dthi_out, "#define\t%s_%s(",
+ infop->dthi_pmname, mname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ for (i = 0; i < prp->pr_nargc; i++) {
+ if (fprintf(infop->dthi_out, "arg%d", i) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (i + 1 != prp->pr_nargc &&
+ fprintf(infop->dthi_out, ", ") < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
+ infop->dthi_pfname, fname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ for (i = 0; i < prp->pr_nargc; i++) {
+ if (fprintf(infop->dthi_out, "arg%d", i) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (i + 1 != prp->pr_nargc &&
+ fprintf(infop->dthi_out, ", ") < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (fprintf(infop->dthi_out, ")\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ return (0);
+}
+
+static int
+dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
+{
+ dt_header_info_t info;
+ const char *p;
+ int i;
+
+ if (pvp->pv_flags & DT_PROVIDER_IMPL)
+ return (0);
+
+ p = pvp->pv_desc.dtvd_name;
+ for (i = 0; (p = strchr(p, '-')) != NULL; i++)
+ p++;
+
+ info.dthi_dtp = dtp;
+ info.dthi_out = out;
+
+ info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
+ dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
+
+ info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
+ dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
+
+
+ if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
+ return (-1); /* dt_errno is set for us */
+ if (fprintf(out, "\n\n") < 0)
+ return (dt_set_errno(dtp, errno));
+ if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
+ return (-1); /* dt_errno is set for us */
+
+ return (0);
+}
+
+int
+dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
+{
+ dt_provider_t *pvp;
+ char *mfname, *p;
+
+ if (fname != NULL) {
+ if ((p = strrchr(fname, '/')) != NULL)
+ fname = p + 1;
+
+ mfname = alloca(strlen(fname) + 1);
+ dt_header_fmt_macro(mfname, fname);
+ if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
+ mfname, mfname) < 0)
+ return (dt_set_errno(dtp, errno));
+ }
+
+ if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
+ return (-1);
+
+ for (pvp = dt_list_next(&dtp->dt_provlist);
+ pvp != NULL; pvp = dt_list_next(pvp)) {
+ if (dt_header_provider(dtp, pvp, out) != 0)
+ return (-1); /* dt_errno is set for us */
+ }
+
+ if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
+ return (dt_set_errno(dtp, errno));
+
+ if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
+ return (dt_set_errno(dtp, errno));
+
+ return (0);
+}
diff --git a/usr/src/lib/libdtrace/common/dt_work.c b/usr/src/lib/libdtrace/common/dt_work.c
index 64cc8ff176..97a7f62d69 100644
--- a/usr/src/lib/libdtrace/common/dt_work.c
+++ b/usr/src/lib/libdtrace/common/dt_work.c
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -47,7 +48,7 @@ dtrace_sleep(dtrace_hdl_t *dtp)
{
dt_proc_hash_t *dph = dtp->dt_procs;
dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY];
- dt_proc_t *dpr;
+ dt_proc_notify_t *dprn;
hrtime_t earliest = INT64_MAX;
struct timespec tv;
@@ -91,12 +92,18 @@ dtrace_sleep(dtrace_hdl_t *dtp)
*/
(void) pthread_cond_reltimedwait_np(&dph->dph_cv, &dph->dph_lock, &tv);
- while ((dpr = dph->dph_notify) != NULL) {
- dph->dph_notify = dpr->dpr_notify;
- dpr->dpr_notify = NULL;
+ while ((dprn = dph->dph_notify) != NULL) {
+ if (dtp->dt_prochdlr != NULL) {
+ char *err = dprn->dprn_errmsg;
+ if (*err == '\0')
+ err = NULL;
+
+ dtp->dt_prochdlr(dprn->dprn_dpr->dpr_proc, err,
+ dtp->dt_procarg);
+ }
- if (dtp->dt_prochdlr != NULL)
- dtp->dt_prochdlr(dpr->dpr_proc, dtp->dt_procarg);
+ dph->dph_notify = dprn->dprn_next;
+ dt_free(dtp, dprn);
}
(void) pthread_mutex_unlock(&dph->dph_lock);
diff --git a/usr/src/lib/libdtrace/common/dtrace.h b/usr/src/lib/libdtrace/common/dtrace.h
index 3d5998cb2f..fb0738bf38 100644
--- a/usr/src/lib/libdtrace/common/dtrace.h
+++ b/usr/src/lib/libdtrace/common/dtrace.h
@@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -49,7 +50,7 @@ extern "C" {
* Please refer to the "Solaris Dynamic Tracing Guide" for more information.
*/
-#define DTRACE_VERSION 2 /* library ABI interface version */
+#define DTRACE_VERSION 3 /* library ABI interface version */
struct ps_prochandle;
typedef struct dtrace_hdl dtrace_hdl_t;
@@ -133,6 +134,8 @@ extern void dtrace_program_info(dtrace_hdl_t *, dtrace_prog_t *,
extern int dtrace_program_link(dtrace_hdl_t *, dtrace_prog_t *,
uint_t, const char *, int, char *const []);
+extern int dtrace_program_header(dtrace_hdl_t *, FILE *, const char *);
+
extern void *dtrace_dof_create(dtrace_hdl_t *, dtrace_prog_t *, uint_t);
extern void dtrace_dof_destroy(dtrace_hdl_t *, void *);
@@ -294,7 +297,7 @@ typedef struct dtrace_dropdata {
typedef int dtrace_handle_drop_f(const dtrace_dropdata_t *, void *);
extern int dtrace_handle_drop(dtrace_hdl_t *, dtrace_handle_drop_f *, void *);
-typedef void dtrace_handle_proc_f(struct ps_prochandle *, void *);
+typedef void dtrace_handle_proc_f(struct ps_prochandle *, const char *, void *);
extern int dtrace_handle_proc(dtrace_hdl_t *, dtrace_handle_proc_f *, void *);
#define DTRACE_BUFDATA_AGGKEY 0x0001 /* aggregation key */
diff --git a/usr/src/lib/libdtrace/spec/dtrace.spec b/usr/src/lib/libdtrace/spec/dtrace.spec
index 95c15e598f..9d2fe94cbf 100644
--- a/usr/src/lib/libdtrace/spec/dtrace.spec
+++ b/usr/src/lib/libdtrace/spec/dtrace.spec
@@ -1,5 +1,5 @@
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -244,6 +244,10 @@ function dtrace_program_exec
version SUNWprivate_1.1
end
+function dtrace_program_header
+version SUNWprivate_1.1
+end
+
function dtrace_program_info
version SUNWprivate_1.1
end
diff --git a/usr/src/uts/sparc/dtrace/dtrace_isa.c b/usr/src/uts/sparc/dtrace/dtrace_isa.c
index 52e6a2fdaf..627cef869e 100644
--- a/usr/src/uts/sparc/dtrace/dtrace_isa.c
+++ b/usr/src/uts/sparc/dtrace/dtrace_isa.c
@@ -21,7 +21,7 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -389,6 +389,13 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t sp)
}
}
} else {
+ /*
+ * Truncate the stack pointer to 32-bits as there may be
+ * garbage in the upper bits which would normally be ignored
+ * by the processor in 32-bit mode.
+ */
+ sp = (uint32_t)sp;
+
for (;;) {
struct frame32 *fr = (struct frame32 *)sp;
uint32_t pc;
@@ -576,6 +583,13 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
pcstack_limit--;
}
} else {
+ /*
+ * Truncate the stack pointer to 32-bits as there may be
+ * garbage in the upper bits which would normally be ignored
+ * by the processor in 32-bit mode.
+ */
+ sp = (uint32_t)sp;
+
while (pcstack_limit > 0) {
struct frame32 *fr = (struct frame32 *)sp;
uint32_t pc;