diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/abi/apptrace/amd64/Makefile | 38 | ||||
-rw-r--r-- | usr/src/cmd/abi/apptracecmd/apptrace.c | 4 | ||||
-rw-r--r-- | usr/src/cmd/dtrace/dtrace.c | 69 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_cc.c | 13 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_parser.c | 8 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_pid.c | 409 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_pid.h | 8 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_proc.c | 97 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_proc.h | 16 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_program.c | 215 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_work.c | 21 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/common/dtrace.h | 9 | ||||
-rw-r--r-- | usr/src/lib/libdtrace/spec/dtrace.spec | 6 | ||||
-rw-r--r-- | usr/src/uts/sparc/dtrace/dtrace_isa.c | 16 |
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; |