summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorbmc <none@none>2005-08-30 14:48:05 -0700
committerbmc <none@none>2005-08-30 14:48:05 -0700
commita1b5e537933659371285214eae1db2603e6364b4 (patch)
tree0e310d875940b00d01f2e43f9481f1bbc706165f /usr/src
parent20bfb7bbfd42ba8121fb6ca123254c43402579ca (diff)
downloadillumos-gate-a1b5e537933659371285214eae1db2603e6364b4.tar.gz
6256581 System got a hang or a panic with dtrace+kmdb
6264573 unanchored dtrace_getpcstack is rather imprecise toward function end 6289517 dtrace doesn't like fd_intr anymore 6291378 dtrace helpers can interfere with the use of kmdb 6295554 dtrace doesn't report errors in ERROR probes 6311947 add umod()/ufunc()/usym(), mod()/func()/sym() 6311952 buffered handler should be called after printing each tuple element 6311956 drops induced by END are not recorded 6311958 should indicate missing jstack() frames due to string table overflows 6311960 allow some DTrace options to be set dynamically 6311963 jstack() produces stacks packed with "StubRoutines" 6311975 allow boolean DTrace options to be unset 6315028 allow quantize()/lquantize() increments to be D expressions 6315033 add dtrace_addr2str()/dtrace_uaddr2str() to libdtrace API 6315034 add ucaller variable 6315035 enablings containing USDT probes are not dynamically reevaluated 6315037 cannot aggregate on the return value of some subroutines 6315039 including <sys/kstat.h> in a D script induces compile-time error 6315087 stack() not correctly printed for 32-bit consumers on amd64 kernel 6315975 flowindent should operate on any probe ending in "-entry"/"-return" 6317350 symbol tables should not be discarded for UNDEAD processes
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/dtrace/dtrace.c20
-rw-r--r--usr/src/cmd/fm/modules/sun4u/USII-io-diagnosis/iod_main.c6
-rw-r--r--usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_cpu.c6
-rw-r--r--usr/src/cmd/intrstat/intrstat.c4
-rw-r--r--usr/src/cmd/lockstat/lockstat.c12
-rw-r--r--usr/src/cmd/mdb/common/modules/dtrace/dtrace.c6
-rw-r--r--usr/src/cmd/plockstat/plockstat.c6
-rw-r--r--usr/src/lib/libdtrace/common/dt_aggregate.c129
-rw-r--r--usr/src/lib/libdtrace/common/dt_cc.c179
-rw-r--r--usr/src/lib/libdtrace/common/dt_consume.c566
-rw-r--r--usr/src/lib/libdtrace/common/dt_errtags.h1
-rw-r--r--usr/src/lib/libdtrace/common/dt_handle.c97
-rw-r--r--usr/src/lib/libdtrace/common/dt_impl.h81
-rw-r--r--usr/src/lib/libdtrace/common/dt_open.c100
-rw-r--r--usr/src/lib/libdtrace/common/dt_options.c75
-rw-r--r--usr/src/lib/libdtrace/common/dt_parser.c23
-rw-r--r--usr/src/lib/libdtrace/common/dt_parser.h3
-rw-r--r--usr/src/lib/libdtrace/common/dt_printf.c251
-rw-r--r--usr/src/lib/libdtrace/common/dt_printf.h12
-rw-r--r--usr/src/lib/libdtrace/common/dt_subr.c111
-rw-r--r--usr/src/lib/libdtrace/common/dt_work.c84
-rw-r--r--usr/src/lib/libdtrace/common/dtrace.h38
-rw-r--r--usr/src/lib/libdtrace/spec/dtrace.spec12
-rw-r--r--usr/src/lib/libproc/common/Psymtab.c2
-rw-r--r--usr/src/uts/common/dtrace/dtrace.c287
-rw-r--r--usr/src/uts/common/io/kstat.c6
-rw-r--r--usr/src/uts/common/rpc/clnt_cots.c8
-rw-r--r--usr/src/uts/common/sys/dtrace.h8
-rw-r--r--usr/src/uts/common/sys/dtrace_impl.h9
-rw-r--r--usr/src/uts/common/sys/kstat.h8
-rw-r--r--usr/src/uts/intel/dtrace/fbt.c6
-rw-r--r--usr/src/uts/sparc/dtrace/dtrace_isa.c51
-rw-r--r--usr/src/uts/sparc/dtrace/fbt.c6
-rw-r--r--usr/src/uts/sparc/ml/fd_asm.s17
-rw-r--r--usr/src/uts/sun/io/fd.c1
35 files changed, 1766 insertions, 465 deletions
diff --git a/usr/src/cmd/dtrace/dtrace.c b/usr/src/cmd/dtrace/dtrace.c
index b8cc044d87..3dcfd8019d 100644
--- a/usr/src/cmd/dtrace/dtrace.c
+++ b/usr/src/cmd/dtrace/dtrace.c
@@ -766,7 +766,7 @@ prochandler(struct ps_prochandle *P, void *arg)
/*ARGSUSED*/
static int
-errhandler(dtrace_errdata_t *data, void *arg)
+errhandler(const dtrace_errdata_t *data, void *arg)
{
error(data->dteda_msg);
return (DTRACE_HANDLE_OK);
@@ -774,7 +774,7 @@ errhandler(dtrace_errdata_t *data, void *arg)
/*ARGSUSED*/
static int
-drophandler(dtrace_dropdata_t *data, void *arg)
+drophandler(const dtrace_dropdata_t *data, void *arg)
{
error(data->dtdda_msg);
return (DTRACE_HANDLE_OK);
@@ -782,6 +782,19 @@ drophandler(dtrace_dropdata_t *data, void *arg)
/*ARGSUSED*/
static int
+setopthandler(const dtrace_setoptdata_t *data, void *arg)
+{
+ if (strcmp(data->dtsda_option, "quiet") == 0)
+ g_quiet = data->dtsda_newval != DTRACEOPT_UNSET;
+
+ if (strcmp(data->dtsda_option, "flowindent") == 0)
+ g_flowindent = data->dtsda_newval != DTRACEOPT_UNSET;
+
+ return (DTRACE_HANDLE_OK);
+}
+
+/*ARGSUSED*/
+static int
chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
{
dtrace_actkind_t act;
@@ -1321,6 +1334,9 @@ main(int argc, char *argv[])
if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1)
dfatal("failed to establish proc handler");
+
+ if (dtrace_handle_setopt(g_dtp, &setopthandler, NULL) == -1)
+ dfatal("failed to establish setopt handler");
}
(void) dtrace_getopt(g_dtp, "flowindent", &opt);
diff --git a/usr/src/cmd/fm/modules/sun4u/USII-io-diagnosis/iod_main.c b/usr/src/cmd/fm/modules/sun4u/USII-io-diagnosis/iod_main.c
index 992b1d5870..93db56d094 100644
--- a/usr/src/cmd/fm/modules/sun4u/USII-io-diagnosis/iod_main.c
+++ b/usr/src/cmd/fm/modules/sun4u/USII-io-diagnosis/iod_main.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -127,9 +127,9 @@ iod_cpu_check_support(void)
if (strcmp(kn->name, "implementation") != 0)
continue;
- if (strncmp(kn->value.string.addr.ptr, "UltraSPARC-II",
+ if (strncmp(KSTAT_NAMED_STR_PTR(kn), "UltraSPARC-II",
sizeof ("UltraSPARC-II") - 1) == 0 &&
- strncmp(kn->value.string.addr.ptr, "UltraSPARC-III",
+ strncmp(KSTAT_NAMED_STR_PTR(kn), "UltraSPARC-III",
sizeof ("UltraSPARC-III") - 1) != 0) {
(void) kstat_close(kc);
return (1);
diff --git a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_cpu.c b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_cpu.c
index 5d0583a779..adb862474e 100644
--- a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_cpu.c
+++ b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_cpu.c
@@ -696,7 +696,7 @@ cpu_getfrustr(fmd_hdl_t *hdl, uint32_t cpuid)
for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
if (strcmp(kn->name, "cpu_fru") == 0) {
char *str = fmd_hdl_strdup(hdl,
- kn->value.string.addr.ptr, FMD_SLEEP);
+ KSTAT_NAMED_STR_PTR(kn), FMD_SLEEP);
(void) kstat_close(kc);
return (str);
}
@@ -1281,9 +1281,9 @@ cmd_cpu_check_support(void)
if (strcmp(kn->name, "implementation") != 0)
continue;
- if (strncmp(kn->value.string.addr.ptr, "UltraSPARC-III",
+ if (strncmp(KSTAT_NAMED_STR_PTR(kn), "UltraSPARC-III",
sizeof ("UltraSPARC-III") - 1) != 0 &&
- strncmp(kn->value.string.addr.ptr, "UltraSPARC-IV",
+ strncmp(KSTAT_NAMED_STR_PTR(kn), "UltraSPARC-IV",
sizeof ("UltraSPARC-IV") - 1) != 0) {
(void) kstat_close(kc);
return (0);
diff --git a/usr/src/cmd/intrstat/intrstat.c b/usr/src/cmd/intrstat/intrstat.c
index 35df72fe38..c0642fb4b2 100644
--- a/usr/src/cmd/intrstat/intrstat.c
+++ b/usr/src/cmd/intrstat/intrstat.c
@@ -171,13 +171,13 @@ print_header()
/*ARGSUSED*/
static int
-walk(dtrace_aggdata_t *data, void *arg)
+walk(const dtrace_aggdata_t *data, void *arg)
{
dtrace_aggdesc_t *aggdesc = data->dtada_desc;
dtrace_recdesc_t *nrec, *irec;
char *name, c[256];
int32_t *instance;
- static dtrace_aggdata_t *count;
+ static const dtrace_aggdata_t *count;
int i, j;
if (count == NULL) {
diff --git a/usr/src/cmd/lockstat/lockstat.c b/usr/src/cmd/lockstat/lockstat.c
index d2c672bd6f..c018f65714 100644
--- a/usr/src/cmd/lockstat/lockstat.c
+++ b/usr/src/cmd/lockstat/lockstat.c
@@ -834,7 +834,7 @@ status_check(void)
}
static void
-lsrec_fill(lsrec_t *lsrec, dtrace_recdesc_t *rec, int nrecs, caddr_t data)
+lsrec_fill(lsrec_t *lsrec, const dtrace_recdesc_t *rec, int nrecs, caddr_t data)
{
bzero(lsrec, g_recsize);
lsrec->ls_count = 1;
@@ -878,7 +878,7 @@ lsrec_fill(lsrec_t *lsrec, dtrace_recdesc_t *rec, int nrecs, caddr_t data)
/*ARGSUSED*/
static int
-count_aggregate(dtrace_aggdata_t *agg, void *arg)
+count_aggregate(const dtrace_aggdata_t *agg, void *arg)
{
*((size_t *)arg) += 1;
@@ -886,13 +886,13 @@ count_aggregate(dtrace_aggdata_t *agg, void *arg)
}
static int
-process_aggregate(dtrace_aggdata_t *agg, void *arg)
+process_aggregate(const dtrace_aggdata_t *agg, void *arg)
{
- dtrace_aggdesc_t *aggdesc = agg->dtada_desc;
+ const dtrace_aggdesc_t *aggdesc = agg->dtada_desc;
caddr_t data = agg->dtada_data;
lsdata_t *lsdata = arg;
lsrec_t *lsrec = lsdata->lsd_next;
- dtrace_recdesc_t *rec;
+ const dtrace_recdesc_t *rec;
uint64_t *avg, *quantized;
int i, j;
@@ -994,7 +994,7 @@ process_data(FILE *out, char *data)
/*ARGSUSED*/
static int
-drophandler(dtrace_dropdata_t *data, void *arg)
+drophandler(const dtrace_dropdata_t *data, void *arg)
{
g_dropped++;
(void) fprintf(stderr, "lockstat: warning: %s", data->dtdda_msg);
diff --git a/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c b/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c
index 8d919c33e6..3b625152d3 100644
--- a/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c
+++ b/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c
@@ -942,7 +942,7 @@ dtrace_dcmdprobe(const dtrace_probedata_t *data, void *arg)
/*ARGSUSED*/
static int
-dtrace_dcmderr(dtrace_errdata_t *data, void *arg)
+dtrace_dcmderr(const dtrace_errdata_t *data, void *arg)
{
mdb_warn(data->dteda_msg);
return (DTRACE_HANDLE_OK);
@@ -950,7 +950,7 @@ dtrace_dcmderr(dtrace_errdata_t *data, void *arg)
/*ARGSUSED*/
static int
-dtrace_dcmddrop(dtrace_dropdata_t *data, void *arg)
+dtrace_dcmddrop(const dtrace_dropdata_t *data, void *arg)
{
mdb_warn(data->dtdda_msg);
return (DTRACE_HANDLE_OK);
@@ -958,7 +958,7 @@ dtrace_dcmddrop(dtrace_dropdata_t *data, void *arg)
/*ARGSUSED*/
static int
-dtrace_dcmdbuffered(dtrace_bufdata_t *bufdata, void *arg)
+dtrace_dcmdbuffered(const dtrace_bufdata_t *bufdata, void *arg)
{
mdb_printf("%s", bufdata->dtbda_buffered);
return (DTRACE_HANDLE_OK);
diff --git a/usr/src/cmd/plockstat/plockstat.c b/usr/src/cmd/plockstat/plockstat.c
index 10e418a996..adf00bdf4a 100644
--- a/usr/src/cmd/plockstat/plockstat.c
+++ b/usr/src/cmd/plockstat/plockstat.c
@@ -429,13 +429,13 @@ getsym(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size,
/*ARGSUSED*/
static int
-process_aggregate(dtrace_aggdata_t *agg, void *arg)
+process_aggregate(const dtrace_aggdata_t *agg, void *arg)
{
static dtrace_aggid_t last = DTRACE_AGGIDNONE;
static uint_t nent;
- dtrace_aggdesc_t *aggdesc = agg->dtada_desc;
+ const dtrace_aggdesc_t *aggdesc = agg->dtada_desc;
caddr_t data = agg->dtada_data;
- dtrace_recdesc_t *rec;
+ const dtrace_recdesc_t *rec;
uint64_t *a, count, avg;
char buf[256];
uintptr_t lock;
diff --git a/usr/src/lib/libdtrace/common/dt_aggregate.c b/usr/src/lib/libdtrace/common/dt_aggregate.c
index 74a0e49174..434bfe0777 100644
--- a/usr/src/lib/libdtrace/common/dt_aggregate.c
+++ b/usr/src/lib/libdtrace/common/dt_aggregate.c
@@ -102,26 +102,27 @@ dt_aggregate_lquantize(uint64_t *existing, uint64_t *new, size_t size)
existing[i] = existing[i] + new[i + 1];
}
-static int64_t
+static long double
dt_aggregate_lquantizedsum(uint64_t *lquanta)
{
uint64_t arg = *lquanta++;
int32_t base = DTRACE_LQUANTIZE_BASE(arg);
uint16_t step = DTRACE_LQUANTIZE_STEP(arg);
uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i;
- int64_t total = lquanta[0] * (base - 1);
+ long double total = (long double)lquanta[0] * (long double)(base - 1);
for (i = 0; i < levels; base += step, i++)
- total += lquanta[i + 1] * base;
+ total += (long double)lquanta[i + 1] * (long double)base;
- return (total + lquanta[levels + 1] * (base + 1));
+ return (total + (long double)lquanta[levels + 1] *
+ (long double)(base + 1));
}
static int
dt_aggregate_lquantizedcmp(uint64_t *lhs, uint64_t *rhs)
{
- int64_t lsum = dt_aggregate_lquantizedsum(lhs);
- int64_t rsum = dt_aggregate_lquantizedsum(rhs);
+ long double lsum = dt_aggregate_lquantizedsum(lhs);
+ long double rsum = dt_aggregate_lquantizedsum(rhs);
if (lsum > rsum)
return (1);
@@ -136,13 +137,13 @@ static int
dt_aggregate_quantizedcmp(uint64_t *lhs, uint64_t *rhs)
{
int nbuckets = DTRACE_QUANTIZE_NBUCKETS, i;
- int64_t ltotal = 0, rtotal = 0;
+ long double ltotal = 0, rtotal = 0;
for (i = 0; i < nbuckets; i++) {
int64_t bucketval = DTRACE_QUANTIZE_BUCKETVAL(i);
- ltotal += bucketval * lhs[i];
- rtotal += bucketval * rhs[i];
+ ltotal += (long double)bucketval * (long double)lhs[i];
+ rtotal += (long double)bucketval * (long double)rhs[i];
}
if (ltotal > rtotal)
@@ -154,6 +155,89 @@ dt_aggregate_quantizedcmp(uint64_t *lhs, uint64_t *rhs)
return (0);
}
+static void
+dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ uint64_t pid = data[0];
+ uint64_t *pc = &data[1];
+ struct ps_prochandle *P;
+ GElf_Sym sym;
+
+ if (dtp->dt_vector != NULL)
+ return;
+
+ if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
+ return;
+
+ dt_proc_lock(dtp, P);
+
+ if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0)
+ *pc = sym.st_value;
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+}
+
+static void
+dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ uint64_t pid = data[0];
+ uint64_t *pc = &data[1];
+ struct ps_prochandle *P;
+ const prmap_t *map;
+
+ if (dtp->dt_vector != NULL)
+ return;
+
+ if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
+ return;
+
+ dt_proc_lock(dtp, P);
+
+ if ((map = Paddr_to_map(P, *pc)) != NULL)
+ *pc = map->pr_vaddr;
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+}
+
+static void
+dt_aggregate_sym(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ GElf_Sym sym;
+ uint64_t *pc = data;
+
+ if (dtrace_lookup_by_addr(dtp, *pc, &sym, NULL) == 0)
+ *pc = sym.st_value;
+}
+
+static void
+dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *data)
+{
+ uint64_t *pc = data;
+ dt_module_t *dmp;
+
+ if (dtp->dt_vector != NULL) {
+ /*
+ * We don't have a way of just getting the module for a
+ * vectored open, and it doesn't seem to be worth defining
+ * one. This means that use of mod() won't get true
+ * aggregation in the postmortem case (some modules may
+ * appear more than once in aggregation output). It seems
+ * unlikely that anyone will ever notice or care...
+ */
+ return;
+ }
+
+ for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
+ dmp = dt_list_next(dmp)) {
+ if (*pc - dmp->dm_text_va < dmp->dm_text_size) {
+ *pc = dmp->dm_text_va;
+ return;
+ }
+ }
+}
+
static int
dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu)
{
@@ -234,6 +318,33 @@ dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu)
rec = &agg->dtagd_rec[j];
roffs = rec->dtrd_offset;
+ switch (rec->dtrd_action) {
+ case DTRACEACT_USYM:
+ dt_aggregate_usym(dtp,
+ /* LINTED - alignment */
+ (uint64_t *)&addr[roffs]);
+ break;
+
+ case DTRACEACT_UMOD:
+ dt_aggregate_umod(dtp,
+ /* LINTED - alignment */
+ (uint64_t *)&addr[roffs]);
+ break;
+
+ case DTRACEACT_SYM:
+ /* LINTED - alignment */
+ dt_aggregate_sym(dtp, (uint64_t *)&addr[roffs]);
+ break;
+
+ case DTRACEACT_MOD:
+ /* LINTED - alignment */
+ dt_aggregate_mod(dtp, (uint64_t *)&addr[roffs]);
+ break;
+
+ default:
+ break;
+ }
+
for (i = 0; i < rec->dtrd_size; i++)
hashval += addr[roffs + i];
}
diff --git a/usr/src/lib/libdtrace/common/dt_cc.c b/usr/src/lib/libdtrace/common/dt_cc.c
index 0648923bcb..508bbc7389 100644
--- a/usr/src/lib/libdtrace/common/dt_cc.c
+++ b/usr/src/lib/libdtrace/common/dt_cc.c
@@ -786,6 +786,61 @@ dt_action_ustack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
dt_action_ustack_args(dtp, ap, dnp);
}
+static void
+dt_action_setopt(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap;
+ dt_node_t *arg0, *arg1;
+
+ /*
+ * The prototype guarantees that we are called with either one or
+ * two arguments, and that any arguments that are present are strings.
+ */
+ arg0 = dnp->dn_args;
+ arg1 = arg0->dn_list;
+
+ ap = dt_stmt_action(dtp, sdp);
+ dt_cg(yypcb, arg0);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_LIBACT;
+ ap->dtad_arg = DT_ACT_SETOPT;
+
+ ap = dt_stmt_action(dtp, sdp);
+
+ if (arg1 == NULL) {
+ dt_action_difconst(ap, 0, DTRACEACT_LIBACT);
+ } else {
+ dt_cg(yypcb, arg1);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_LIBACT;
+ }
+
+ ap->dtad_arg = DT_ACT_SETOPT;
+}
+
+/*ARGSUSED*/
+static void
+dt_action_symmod_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap,
+ dt_node_t *dnp, dtrace_actkind_t kind)
+{
+ assert(kind == DTRACEACT_SYM || kind == DTRACEACT_MOD ||
+ kind == DTRACEACT_USYM || kind == DTRACEACT_UMOD ||
+ kind == DTRACEACT_UADDR);
+
+ dt_cg(yypcb, dnp);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = kind;
+ ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (uint64_t);
+}
+
+static void
+dt_action_symmod(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,
+ dtrace_actkind_t kind)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+ dt_action_symmod_args(dtp, ap, dnp->dn_args, kind);
+}
+
/*ARGSUSED*/
static void
dt_action_ftruncate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
@@ -924,6 +979,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
case DT_ACT_FTRUNCATE:
dt_action_ftruncate(dtp, dnp->dn_expr, sdp);
break;
+ case DT_ACT_MOD:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_MOD);
+ break;
case DT_ACT_NORMALIZE:
dt_action_normalize(dtp, dnp->dn_expr, sdp);
break;
@@ -939,6 +997,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
case DT_ACT_RAISE:
dt_action_raise(dtp, dnp->dn_expr, sdp);
break;
+ case DT_ACT_SETOPT:
+ dt_action_setopt(dtp, dnp->dn_expr, sdp);
+ break;
case DT_ACT_SPECULATE:
dt_action_speculate(dtp, dnp->dn_expr, sdp);
break;
@@ -948,6 +1009,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
case DT_ACT_STOP:
dt_action_stop(dtp, dnp->dn_expr, sdp);
break;
+ case DT_ACT_SYM:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_SYM);
+ break;
case DT_ACT_SYSTEM:
dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_SYSTEM);
break;
@@ -960,6 +1024,15 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
case DT_ACT_TRUNC:
dt_action_trunc(dtp, dnp->dn_expr, sdp);
break;
+ case DT_ACT_UADDR:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UADDR);
+ break;
+ case DT_ACT_UMOD:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UMOD);
+ break;
+ case DT_ACT_USYM:
+ dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_USYM);
+ break;
case DT_ACT_USTACK:
case DT_ACT_JSTACK:
dt_action_ustack(dtp, dnp->dn_expr, sdp);
@@ -985,9 +1058,10 @@ static void
dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
{
dt_ident_t *aid, *fid;
- dt_node_t *anp;
+ dt_node_t *anp, *incr = NULL;
dtrace_actdesc_t *ap;
- uint_t n = 1;
+ uint_t n = 1, argmax;
+ uint64_t arg = 0;
/*
* If the aggregation has no aggregating function applied to it, then
@@ -1029,35 +1103,52 @@ dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
dt_action_ustack_args(dtp, ap, anp);
continue;
}
- }
- dt_cg(yypcb, anp);
- ap->dtad_difo = dt_as(yypcb);
- ap->dtad_kind = DTRACEACT_DIFEXPR;
- }
+ switch (anp->dn_ident->di_id) {
+ case DT_ACT_UADDR:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_UADDR);
+ continue;
- assert(sdp->dtsd_aggdata == NULL);
- sdp->dtsd_aggdata = aid;
+ case DT_ACT_USYM:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_USYM);
+ continue;
- ap = dt_stmt_action(dtp, sdp);
- assert(fid->di_kind == DT_IDENT_AGGFUNC);
- assert(DTRACEACT_ISAGG(fid->di_id));
- ap->dtad_kind = fid->di_id;
- ap->dtad_ntuple = n;
+ case DT_ACT_UMOD:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_UMOD);
+ continue;
- if (dnp->dn_aggfun->dn_args != NULL) {
- dt_cg(yypcb, dnp->dn_aggfun->dn_args);
+ case DT_ACT_SYM:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_SYM);
+ continue;
+
+ case DT_ACT_MOD:
+ dt_action_symmod_args(dtp, ap,
+ anp->dn_args, DTRACEACT_MOD);
+ continue;
+
+ default:
+ break;
+ }
+ }
+
+ dt_cg(yypcb, anp);
ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_DIFEXPR;
}
if (fid->di_id == DTRACEAGG_LQUANTIZE) {
/*
- * For linear quantization, we have between two and three
- * arguments:
+ * For linear quantization, we have between two and four
+ * arguments in addition to the expression:
*
* arg1 => Base value
* arg2 => Limit value
* arg3 => Quantization level step size (defaults to 1)
+ * arg4 => Quantization increment value (defaults to 1)
*/
dt_node_t *arg1 = dnp->dn_aggfun->dn_args->dn_list;
dt_node_t *arg2 = arg1->dn_list;
@@ -1122,10 +1213,60 @@ dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
"levels must be a 16-bit quantity\n");
}
- ap->dtad_arg = (step << DTRACE_LQUANTIZE_STEPSHIFT) |
+ arg = (step << DTRACE_LQUANTIZE_STEPSHIFT) |
(nlevels << DTRACE_LQUANTIZE_LEVELSHIFT) |
((baseval << DTRACE_LQUANTIZE_BASESHIFT) &
DTRACE_LQUANTIZE_BASEMASK);
+
+ incr = arg3 != NULL ? arg3->dn_list : NULL;
+ argmax = 5;
+ }
+
+ if (fid->di_id == DTRACEAGG_QUANTIZE) {
+ incr = dnp->dn_aggfun->dn_args->dn_list;
+ argmax = 2;
+ }
+
+ if (incr != NULL) {
+ if (!dt_node_is_scalar(incr)) {
+ dnerror(dnp, D_PROTO_ARG, "%s( ) increment value "
+ "(argument #%d) must be of scalar type\n",
+ fid->di_name, argmax);
+ }
+
+ if ((anp = incr->dn_list) != NULL) {
+ int argc = argmax;
+
+ for (; anp != NULL; anp = anp->dn_list)
+ argc++;
+
+ dnerror(incr, D_PROTO_LEN, "%s( ) prototype "
+ "mismatch: %d args passed, at most %d expected",
+ fid->di_name, argc, argmax);
+ }
+
+ ap = dt_stmt_action(dtp, sdp);
+ n++;
+
+ dt_cg(yypcb, incr);
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_difo->dtdo_rtype = dt_void_rtype;
+ ap->dtad_kind = DTRACEACT_DIFEXPR;
+ }
+
+ assert(sdp->dtsd_aggdata == NULL);
+ sdp->dtsd_aggdata = aid;
+
+ ap = dt_stmt_action(dtp, sdp);
+ assert(fid->di_kind == DT_IDENT_AGGFUNC);
+ assert(DTRACEACT_ISAGG(fid->di_id));
+ ap->dtad_kind = fid->di_id;
+ ap->dtad_ntuple = n;
+ ap->dtad_arg = arg;
+
+ if (dnp->dn_aggfun->dn_args != NULL) {
+ dt_cg(yypcb, dnp->dn_aggfun->dn_args);
+ ap->dtad_difo = dt_as(yypcb);
}
}
diff --git a/usr/src/lib/libdtrace/common/dt_consume.c b/usr/src/lib/libdtrace/common/dt_consume.c
index 3d238eeb55..5ceeea1665 100644
--- a/usr/src/lib/libdtrace/common/dt_consume.c
+++ b/usr/src/lib/libdtrace/common/dt_consume.c
@@ -34,28 +34,57 @@
#include <assert.h>
#include <ctype.h>
#include <alloca.h>
-
#include <dt_impl.h>
+/*
+ * We declare this here because (1) we need it and (2) we want to avoid a
+ * dependency on libm in libdtrace.
+ */
+static long double
+dt_fabsl(long double x)
+{
+ if (x < 0)
+ return (-x);
+
+ return (x);
+}
+
static int
dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last,
dtrace_bufdesc_t *buf, size_t offs)
{
dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd;
dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd;
- char *p = pd->dtpd_provider, *n = pd->dtpd_name;
+ char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub;
dtrace_flowkind_t flow = DTRACEFLOW_NONE;
const char *str = NULL;
static const char *e_str[2] = { " -> ", " => " };
static const char *r_str[2] = { " <- ", " <= " };
+ static const char *ent = "entry", *ret = "return";
+ static int entlen = 0, retlen = 0;
dtrace_epid_t next, id = epd->dtepd_epid;
int rval;
- if (strcmp(n, "entry") == 0) {
+ if (entlen == 0) {
+ assert(retlen == 0);
+ entlen = strlen(ent);
+ retlen = strlen(ret);
+ }
+
+ /*
+ * If the name of the probe is "entry" or ends with "-entry", we
+ * treat it as an entry; if it is "return" or ends with "-return",
+ * we treat it as a return. (This allows application-provided probes
+ * like "method-entry" or "function-entry" to participate in flow
+ * indentation -- without accidentally misinterpreting popular probe
+ * names like "carpentry", "gentry" or "Coventry".)
+ */
+ if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' &&
+ (sub == n || sub[-1] == '-')) {
flow = DTRACEFLOW_ENTRY;
str = e_str[strcmp(p, "syscall") == 0];
- } else if (strcmp(n, "return") == 0 ||
- strcmp(n, "exit") == 0) {
+ } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' &&
+ (sub == n || sub[-1] == '-')) {
flow = DTRACEFLOW_RETURN;
str = r_str[strcmp(p, "syscall") == 0];
}
@@ -134,12 +163,73 @@ dt_nullrec()
}
int
+dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
+ uint64_t normal, long double total, char positives, char negatives)
+{
+ long double f;
+ uint_t depth, len = 40;
+
+ const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
+ const char *spaces = " ";
+
+ assert(strlen(ats) == len && strlen(spaces) == len);
+ assert(!(total == 0 && (positives || negatives)));
+ assert(!(val < 0 && !negatives));
+ assert(!(val > 0 && !positives));
+ assert(!(val != 0 && total == 0));
+
+ if (!negatives) {
+ if (positives) {
+ f = (dt_fabsl((long double)val) * len) / total;
+ depth = (uint_t)(f + 0.5);
+ } else {
+ depth = 0;
+ }
+
+ return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth,
+ spaces + depth, (long long)val / normal));
+ }
+
+ if (!positives) {
+ f = (dt_fabsl((long double)val) * len) / total;
+ depth = (uint_t)(f + 0.5);
+
+ return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth,
+ ats + len - depth, (long long)val / normal));
+ }
+
+ /*
+ * If we're here, we have both positive and negative bucket values.
+ * To express this graphically, we're going to generate both positive
+ * and negative bars separated by a centerline. These bars are half
+ * the size of normal quantize()/lquantize() bars, so we divide the
+ * length in half before calculating the bar length.
+ */
+ len /= 2;
+ ats = &ats[len];
+ spaces = &spaces[len];
+
+ f = (dt_fabsl((long double)val) * len) / total;
+ depth = (uint_t)(f + 0.5);
+
+ if (val <= 0) {
+ return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth,
+ ats + len - depth, len, "", (long long)val / normal));
+ } else {
+ return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "",
+ ats + len - depth, spaces + depth,
+ (long long)val / normal));
+ }
+}
+
+int
dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
size_t size, uint64_t normal)
{
- const uint64_t *data = addr;
+ const int64_t *data = addr;
int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
- uint64_t total_bin_count = 0;
+ long double total = 0;
+ char positives = 0, negatives = 0;
if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
return (dt_set_errno(dtp, EDT_DMISMATCH));
@@ -147,31 +237,42 @@ dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0)
first_bin++;
- if (first_bin > 0)
- first_bin--;
+ if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) {
+ /*
+ * There isn't any data. This is possible if (and only if)
+ * negative increment values have been used. In this case,
+ * we'll print the buckets around 0.
+ */
+ first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1;
+ last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1;
+ } else {
+ if (first_bin > 0)
+ first_bin--;
- while (last_bin > 0 && data[last_bin] == 0)
- last_bin--;
+ while (last_bin > 0 && data[last_bin] == 0)
+ last_bin--;
- if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1)
- last_bin++;
+ if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1)
+ last_bin++;
+ }
- for (i = first_bin; i <= last_bin; i++)
- total_bin_count += data[i];
+ for (i = first_bin; i <= last_bin; i++) {
+ positives |= (data[i] > 0);
+ negatives |= (data[i] < 0);
+ total += dt_fabsl((long double)data[i]);
+ }
if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
"------------- Distribution -------------", "count") < 0)
return (-1);
for (i = first_bin; i <= last_bin; i++) {
- float f = ((float)data[i] * 40.0) / (float)total_bin_count;
- uint_t depth = (uint_t)(f + 0.5);
-
- if (dt_printf(dtp, fp, "%16lld |%s%s %-9llu\n",
- (long long)DTRACE_QUANTIZE_BUCKETVAL(i),
- "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth,
- " " + depth,
- (u_longlong_t)data[i] / normal) < 0)
+ if (dt_printf(dtp, fp, "%16lld ",
+ (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0)
+ return (-1);
+
+ if (dt_print_quantline(dtp, fp, data[i], normal, total,
+ positives, negatives) < 0)
return (-1);
}
@@ -182,10 +283,12 @@ int
dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
size_t size, uint64_t normal)
{
- const uint64_t *data = addr;
+ const int64_t *data = addr;
int i, first_bin, last_bin, base;
- uint64_t arg, total_bin_count = 0;
+ uint64_t arg;
+ long double total = 0;
uint16_t step, levels;
+ char positives = 0, negatives = 0;
if (size < sizeof (uint64_t))
return (dt_set_errno(dtp, EDT_DMISMATCH));
@@ -206,25 +309,31 @@ dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
while (first_bin < levels + 1 && data[first_bin] == 0)
first_bin++;
- if (first_bin > 0)
- first_bin--;
+ if (first_bin == levels + 1) {
+ first_bin = 0;
+ last_bin = 2;
+ } else {
+ if (first_bin > 0)
+ first_bin--;
- while (last_bin > 0 && data[last_bin] == 0)
- last_bin--;
+ while (last_bin > 0 && data[last_bin] == 0)
+ last_bin--;
- if (last_bin < levels + 1)
- last_bin++;
+ if (last_bin < levels + 1)
+ last_bin++;
+ }
- for (i = first_bin; i <= last_bin; i++)
- total_bin_count += data[i];
+ for (i = first_bin; i <= last_bin; i++) {
+ positives |= (data[i] > 0);
+ negatives |= (data[i] < 0);
+ total += dt_fabsl((long double)data[i]);
+ }
if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
"------------- Distribution -------------", "count") < 0)
return (-1);
for (i = first_bin; i <= last_bin; i++) {
- float f = ((float)data[i] * 40.0) / (float)total_bin_count;
- uint_t depth = (uint_t)(f + 0.5);
char c[32];
int err;
@@ -241,10 +350,8 @@ dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
base + (i - 1) * step);
}
- if (err < 0 || dt_printf(dtp, fp, "|%s%s %-9llu\n",
- "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth,
- " " + depth,
- (u_longlong_t)data[i] / normal) < 0)
+ if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal,
+ total, positives, negatives) < 0)
return (-1);
}
@@ -379,13 +486,13 @@ raw:
int
dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
- caddr_t addr, int depth)
+ caddr_t addr, int depth, int size)
{
- pc_t *pc = (pc_t *)(uintptr_t)addr;
dtrace_syminfo_t dts;
GElf_Sym sym;
int i, indent;
char c[PATH_MAX * 2];
+ uint64_t pc;
if (dt_printf(dtp, fp, "\n") < 0)
return (-1);
@@ -398,15 +505,35 @@ dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
else
indent = _dtrace_stkindent;
- for (i = 0; i < depth && pc[i] != NULL; i++) {
+ for (i = 0; i < depth; i++) {
+ switch (size) {
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ pc = *((uint32_t *)addr);
+ break;
+
+ case sizeof (uint64_t):
+ /* LINTED - alignment */
+ pc = *((uint64_t *)addr);
+ break;
+
+ default:
+ return (dt_set_errno(dtp, EDT_BADSTACKPC));
+ }
+
+ if (pc == NULL)
+ break;
+
+ addr += size;
+
if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
return (-1);
- if (dtrace_lookup_by_addr(dtp, pc[i], &sym, &dts) == 0) {
- if (pc[i] > sym.st_value) {
+ if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
+ if (pc > sym.st_value) {
(void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
dts.dts_object, dts.dts_name,
- (u_longlong_t)pc[i] - sym.st_value);
+ pc - sym.st_value);
} else {
(void) snprintf(c, sizeof (c), "%s`%s",
dts.dts_object, dts.dts_name);
@@ -417,13 +544,11 @@ dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
* a NULL GElf_Sym -- indicating that we're only
* interested in the containing module.
*/
- if (dtrace_lookup_by_addr(dtp, pc[i],
- NULL, &dts) == 0) {
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
(void) snprintf(c, sizeof (c), "%s`0x%llx",
- dts.dts_object, (u_longlong_t)pc[i]);
+ dts.dts_object, pc);
} else {
- (void) snprintf(c, sizeof (c), "0x%llx",
- (u_longlong_t)pc[i]);
+ (void) snprintf(c, sizeof (c), "0x%llx", pc);
}
}
@@ -441,7 +566,8 @@ int
dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
caddr_t addr, uint64_t arg)
{
- uint64_t *pc = (uint64_t *)(uintptr_t)addr;
+ /* LINTED - alignment */
+ uint64_t *pc = (uint64_t *)addr;
uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
@@ -484,6 +610,8 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
for (i = 0; i < depth && pc[i] != NULL; i++) {
+ const prmap_t *map;
+
if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
break;
@@ -499,7 +627,22 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
(void) snprintf(c, sizeof (c),
"%s`%s", dt_basename(objname), name);
}
- } else if (str != NULL && str[0] != '\0') {
+ } else if (str != NULL && str[0] != '\0' &&
+ (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
+ (map->pr_mflags & MA_WRITE)))) {
+ /*
+ * If the current string pointer in the string table
+ * does not point to an empty string _and_ the program
+ * counter falls in a writable region, we'll use the
+ * string from the string table instead of the raw
+ * address. This last condition is necessary because
+ * some (broken) ustack helpers will return a string
+ * even for a program counter that they can't
+ * identify. If we have a string for a program
+ * counter that falls in a segment that isn't
+ * writable, we assume that we have fallen into this
+ * case and we refuse to use the string.
+ */
(void) snprintf(c, sizeof (c), "%s", str);
} else {
if (P != NULL && Pobjname(P, pc[i], objname,
@@ -533,13 +676,151 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
return (err);
}
+static int
+dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
+{
+ /* LINTED - alignment */
+ uint64_t pid = ((uint64_t *)addr)[0];
+ /* LINTED - alignment */
+ uint64_t pc = ((uint64_t *)addr)[1];
+ const char *format = " %-50s";
+ char *s;
+ int n, len = 256;
+
+ if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) {
+ struct ps_prochandle *P;
+
+ if ((P = dt_proc_grab(dtp, pid,
+ PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) {
+ GElf_Sym sym;
+
+ dt_proc_lock(dtp, P);
+
+ if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
+ pc = sym.st_value;
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+ }
+
+ do {
+ n = len;
+ s = alloca(n);
+ } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) >= n);
+
+ return (dt_printf(dtp, fp, format, s));
+}
+
+int
+dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
+{
+ /* LINTED - alignment */
+ uint64_t pid = ((uint64_t *)addr)[0];
+ /* LINTED - alignment */
+ uint64_t pc = ((uint64_t *)addr)[1];
+ int err = 0;
+
+ char objname[PATH_MAX], c[PATH_MAX * 2];
+ struct ps_prochandle *P;
+
+ if (format == NULL)
+ format = " %-50s";
+
+ /*
+ * See the comment in dt_print_ustack() for the rationale for
+ * printing raw addresses in the vectored case.
+ */
+ if (dtp->dt_vector == NULL)
+ P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
+ else
+ P = NULL;
+
+ if (P != NULL)
+ dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
+
+ if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != NULL) {
+ (void) snprintf(c, sizeof (c), "%s", dt_basename(objname));
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
+ }
+
+ err = dt_printf(dtp, fp, format, c);
+
+ if (P != NULL) {
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+
+ return (err);
+}
+
+static int
+dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
+{
+ /* LINTED - alignment */
+ uint64_t pc = *((uint64_t *)addr);
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+ char c[PATH_MAX * 2];
+
+ if (format == NULL)
+ format = " %-50s";
+
+ if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s`%s",
+ dts.dts_object, dts.dts_name);
+ } else {
+ /*
+ * We'll repeat the lookup, but this time we'll specify a
+ * NULL GElf_Sym -- indicating that we're only interested in
+ * the containing module.
+ */
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dts.dts_object, (u_longlong_t)pc);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx",
+ (u_longlong_t)pc);
+ }
+ }
+
+ if (dt_printf(dtp, fp, format, c) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
+{
+ /* LINTED - alignment */
+ uint64_t pc = *((uint64_t *)addr);
+ dtrace_syminfo_t dts;
+ char c[PATH_MAX * 2];
+
+ if (format == NULL)
+ format = " %-50s";
+
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s", dts.dts_object);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
+ }
+
+ if (dt_printf(dtp, fp, format, c) < 0)
+ return (-1);
+
+ return (0);
+}
+
typedef struct dt_normal {
dtrace_aggvarid_t dtnd_id;
uint64_t dtnd_normal;
} dt_normal_t;
static int
-dt_normalize_agg(dtrace_aggdata_t *aggdata, void *arg)
+dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
{
dt_normal_t *normal = arg;
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
@@ -552,7 +833,7 @@ dt_normalize_agg(dtrace_aggdata_t *aggdata, void *arg)
if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset))
return (DTRACE_AGGWALK_NEXT);
- aggdata->dtada_normal = normal->dtnd_normal;
+ ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal;
return (DTRACE_AGGWALK_NORMALIZE);
}
@@ -609,7 +890,7 @@ dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
}
static int
-dt_denormalize_agg(dtrace_aggdata_t *aggdata, void *arg)
+dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
{
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
@@ -625,7 +906,7 @@ dt_denormalize_agg(dtrace_aggdata_t *aggdata, void *arg)
}
static int
-dt_clear_agg(dtrace_aggdata_t *aggdata, void *arg)
+dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg)
{
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
@@ -646,7 +927,7 @@ typedef struct dt_trunc {
} dt_trunc_t;
static int
-dt_trunc_agg(dtrace_aggdata_t *aggdata, void *arg)
+dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg)
{
dt_trunc_t *trunc = arg;
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
@@ -732,7 +1013,7 @@ dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
}
int
-dt_print_agg(dtrace_aggdata_t *aggdata, void *arg)
+dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg)
{
int i, err = 0;
dt_print_aggdata_t *pd = arg;
@@ -774,8 +1055,8 @@ dt_print_agg(dtrace_aggdata_t *aggdata, void *arg)
normal = DTRACEACT_ISAGG(act) ? aggdata->dtada_normal : 1;
if (act == DTRACEACT_STACK) {
- int depth = rec->dtrd_size / sizeof (pc_t);
- err = dt_print_stack(dtp, fp, NULL, addr, depth);
+ err = dt_print_stack(dtp, fp, NULL, addr,
+ rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg);
goto nextrec;
}
@@ -785,6 +1066,26 @@ dt_print_agg(dtrace_aggdata_t *aggdata, void *arg)
goto nextrec;
}
+ if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) {
+ err = dt_print_usym(dtp, fp, addr, act);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_UMOD) {
+ err = dt_print_umod(dtp, fp, NULL, addr);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_SYM) {
+ err = dt_print_sym(dtp, fp, NULL, addr);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_MOD) {
+ err = dt_print_mod(dtp, fp, NULL, addr);
+ goto nextrec;
+ }
+
if (act == DTRACEAGG_QUANTIZE) {
err = dt_print_quantize(dtp, fp, addr, size, normal);
goto nextrec;
@@ -842,6 +1143,44 @@ nextrec:
return (err < 0 ? -1 : 0);
}
+
+int
+dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
+ const char *option, const char *value)
+{
+ int len, rval;
+ char *msg;
+ const char *errstr;
+ dtrace_setoptdata_t optdata;
+
+ bzero(&optdata, sizeof (optdata));
+ (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval);
+
+ if (dtrace_setopt(dtp, option, value) == 0) {
+ (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval);
+ optdata.dtsda_probe = data;
+ optdata.dtsda_option = option;
+ optdata.dtsda_handle = dtp;
+
+ if ((rval = dt_handle_setopt(dtp, &optdata)) != 0)
+ return (rval);
+
+ return (0);
+ }
+
+ errstr = dtrace_errmsg(dtp, dtrace_errno(dtp));
+ len = strlen(option) + strlen(value) + strlen(errstr) + 80;
+ msg = alloca(len);
+
+ (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n",
+ option, value, errstr);
+
+ if ((rval = dt_handle_liberr(dtp, data, msg)) == 0)
+ return (0);
+
+ return (rval);
+}
+
static int
dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg)
@@ -923,27 +1262,34 @@ again:
addr = data.dtpda_data;
if (act == DTRACEACT_LIBACT) {
- if (rec->dtrd_arg == DT_ACT_CLEAR) {
- dtrace_aggvarid_t id;
+ uint64_t arg = rec->dtrd_arg;
+ dtrace_aggvarid_t id;
+ switch (arg) {
+ case DT_ACT_CLEAR:
/* LINTED - alignment */
id = *((dtrace_aggvarid_t *)addr);
(void) dtrace_aggregate_walk(dtp,
dt_clear_agg, &id);
continue;
- }
-
- if (rec->dtrd_arg == DT_ACT_DENORMALIZE) {
- dtrace_aggvarid_t id;
+ case DT_ACT_DENORMALIZE:
/* LINTED - alignment */
id = *((dtrace_aggvarid_t *)addr);
(void) dtrace_aggregate_walk(dtp,
dt_denormalize_agg, &id);
continue;
- }
- if (rec->dtrd_arg == DT_ACT_NORMALIZE) {
+ case DT_ACT_FTRUNCATE:
+ if (fp == NULL)
+ continue;
+
+ (void) fflush(fp);
+ (void) ftruncate(fileno(fp), 0);
+ (void) fseeko(fp, 0, SEEK_SET);
+ continue;
+
+ case DT_ACT_NORMALIZE:
if (i == epd->dtepd_nrecs - 1)
return (dt_set_errno(dtp,
EDT_BADNORMAL));
@@ -954,9 +1300,49 @@ again:
i++;
continue;
+
+ case DT_ACT_SETOPT: {
+ uint64_t *opts = dtp->dt_options;
+ dtrace_recdesc_t *valrec;
+ uint32_t valsize;
+ caddr_t val;
+ int rv;
+
+ if (i == epd->dtepd_nrecs - 1) {
+ return (dt_set_errno(dtp,
+ EDT_BADSETOPT));
+ }
+
+ valrec = &epd->dtepd_rec[++i];
+ valsize = valrec->dtrd_size;
+
+ if (valrec->dtrd_action != act ||
+ valrec->dtrd_arg != arg) {
+ return (dt_set_errno(dtp,
+ EDT_BADSETOPT));
+ }
+
+ if (valsize > sizeof (uint64_t)) {
+ val = buf->dtbd_data + offs +
+ valrec->dtrd_offset;
+ } else {
+ val = "1";
+ }
+
+ rv = dt_setopt(dtp, &data, addr, val);
+
+ if (rv != 0)
+ return (-1);
+
+ flow = (opts[DTRACEOPT_FLOWINDENT] !=
+ DTRACEOPT_UNSET);
+ quiet = (opts[DTRACEOPT_QUIET] !=
+ DTRACEOPT_UNSET);
+
+ continue;
}
- if (rec->dtrd_arg == DT_ACT_TRUNC) {
+ case DT_ACT_TRUNC:
if (i == epd->dtepd_nrecs - 1)
return (dt_set_errno(dtp,
EDT_BADTRUNC));
@@ -967,15 +1353,8 @@ again:
i++;
continue;
- }
-
- if (rec->dtrd_arg == DT_ACT_FTRUNCATE) {
- if (fp == NULL)
- continue;
- (void) fflush(fp);
- (void) ftruncate(fileno(fp), 0);
- (void) fseeko(fp, 0, SEEK_SET);
+ default:
continue;
}
}
@@ -992,9 +1371,10 @@ again:
return (dt_set_errno(dtp, EDT_BADRVAL));
if (act == DTRACEACT_STACK) {
- int depth = rec->dtrd_size / sizeof (pc_t);
- if (dt_print_stack(dtp, fp, NULL,
- addr, depth) < 0)
+ int depth = rec->dtrd_arg;
+
+ if (dt_print_stack(dtp, fp, NULL, addr, depth,
+ rec->dtrd_size / depth) < 0)
return (-1);
goto nextrec;
}
@@ -1007,6 +1387,30 @@ again:
goto nextrec;
}
+ if (act == DTRACEACT_SYM) {
+ if (dt_print_sym(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_MOD) {
+ if (dt_print_mod(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) {
+ if (dt_print_usym(dtp, fp, addr, act) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
+ if (act == DTRACEACT_UMOD) {
+ if (dt_print_umod(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ goto nextrec;
+ }
+
if (DTRACEACT_ISPRINTFLIKE(act)) {
void *fmtdata;
int (*func)(dtrace_hdl_t *, FILE *, void *,
@@ -1169,7 +1573,7 @@ dt_consume_begin_record(const dtrace_probedata_t *data,
}
static int
-dt_consume_begin_error(dtrace_errdata_t *data, void *arg)
+dt_consume_begin_error(const dtrace_errdata_t *data, void *arg)
{
dt_begin_t *begin = (dt_begin_t *)arg;
dtrace_probedesc_t *pd = data->dteda_pdesc;
diff --git a/usr/src/lib/libdtrace/common/dt_errtags.h b/usr/src/lib/libdtrace/common/dt_errtags.h
index b8489cd7fc..23e790831b 100644
--- a/usr/src/lib/libdtrace/common/dt_errtags.h
+++ b/usr/src/lib/libdtrace/common/dt_errtags.h
@@ -201,6 +201,7 @@ typedef enum {
D_LQUANT_STEPVAL, /* lquantize() bad step value */
D_LQUANT_STEPLARGE, /* lquantize() step too large */
D_LQUANT_STEPSMALL, /* lquantize() step too small */
+ D_QUANT_PROTO, /* quantize() prototype mismatch */
D_PROC_OFF, /* byte offset exceeds function size */
D_PROC_ALIGN, /* byte offset has invalid alignment */
D_PROC_NAME, /* invalid process probe name */
diff --git a/usr/src/lib/libdtrace/common/dt_handle.c b/usr/src/lib/libdtrace/common/dt_handle.c
index 2e8e668010..e6ed51af7d 100644
--- a/usr/src/lib/libdtrace/common/dt_handle.c
+++ b/usr/src/lib/libdtrace/common/dt_handle.c
@@ -127,6 +127,19 @@ dtrace_handle_buffered(dtrace_hdl_t *dtp, dtrace_handle_buffered_f *hdlr,
return (0);
}
+int
+dtrace_handle_setopt(dtrace_hdl_t *dtp, dtrace_handle_setopt_f *hdlr,
+ void *arg)
+{
+ if (hdlr == NULL)
+ return (dt_set_errno(dtp, EINVAL));
+
+ dtp->dt_setopthdlr = hdlr;
+ dtp->dt_setoptarg = arg;
+
+ return (0);
+}
+
#define DT_REC(type, ndx) *((type *)((uintptr_t)data->dtpda_data + \
epd->dtepd_rec[(ndx)].dtrd_offset))
@@ -261,12 +274,45 @@ dt_handle_liberr(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
return (0);
}
+#define DROPTAG(x) x, #x
+
+static const struct {
+ dtrace_dropkind_t dtdrg_kind;
+ char *dtdrg_tag;
+} _dt_droptags[] = {
+ { DROPTAG(DTRACEDROP_PRINCIPAL) },
+ { DROPTAG(DTRACEDROP_AGGREGATION) },
+ { DROPTAG(DTRACEDROP_DYNAMIC) },
+ { DROPTAG(DTRACEDROP_DYNRINSE) },
+ { DROPTAG(DTRACEDROP_DYNDIRTY) },
+ { DROPTAG(DTRACEDROP_SPEC) },
+ { DROPTAG(DTRACEDROP_SPECBUSY) },
+ { DROPTAG(DTRACEDROP_SPECUNAVAIL) },
+ { DROPTAG(DTRACEDROP_DBLERROR) },
+ { DROPTAG(DTRACEDROP_STKSTROVERFLOW) },
+ { 0, NULL }
+};
+
+static const char *
+dt_droptag(dtrace_dropkind_t kind)
+{
+ int i;
+
+ for (i = 0; _dt_droptags[i].dtdrg_tag != NULL; i++) {
+ if (_dt_droptags[i].dtdrg_kind == kind)
+ return (_dt_droptags[i].dtdrg_tag);
+ }
+
+ return ("DTRACEDROP_UNKNOWN");
+}
+
int
dt_handle_cpudrop(dtrace_hdl_t *dtp, processorid_t cpu,
dtrace_dropkind_t what, uint64_t howmany)
{
dtrace_dropdata_t drop;
- char str[80];
+ char str[80], *s;
+ int size;
assert(what == DTRACEDROP_PRINCIPAL || what == DTRACEDROP_AGGREGATION);
@@ -277,7 +323,16 @@ dt_handle_cpudrop(dtrace_hdl_t *dtp, processorid_t cpu,
drop.dtdda_drops = howmany;
drop.dtdda_msg = str;
- (void) snprintf(str, sizeof (str), "%llu %sdrop%s on CPU %d\n",
+ if (dtp->dt_droptags) {
+ (void) snprintf(str, sizeof (str), "[%s] ", dt_droptag(what));
+ s = &str[strlen(str)];
+ size = sizeof (str) - (s - str);
+ } else {
+ s = str;
+ size = sizeof (str);
+ }
+
+ (void) snprintf(s, size, "%llu %sdrop%s on CPU %d\n",
howmany, what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
howmany > 1 ? "s" : "", cpu);
@@ -320,6 +375,14 @@ static const struct {
offsetof(dtrace_status_t, dtst_specdrops_unavail),
"failed speculation", " (no speculative buffer available)" },
+ { DTRACEDROP_STKSTROVERFLOW,
+ offsetof(dtrace_status_t, dtst_stkstroverflows),
+ "jstack()/ustack() string table overflow" },
+
+ { DTRACEDROP_DBLERROR,
+ offsetof(dtrace_status_t, dtst_dblerrors),
+ "error", " in ERROR probe enabling" },
+
{ 0, 0, NULL }
};
@@ -327,9 +390,9 @@ int
dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new)
{
dtrace_dropdata_t drop;
- char str[80];
+ char str[80], *s;
uintptr_t base = (uintptr_t)new, obase = (uintptr_t)old;
- int i;
+ int i, size;
bzero(&drop, sizeof (drop));
drop.dtdda_handle = dtp;
@@ -352,7 +415,17 @@ dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new)
if (nval == oval)
continue;
- (void) snprintf(str, sizeof (str), "%llu %s%s%s\n", nval - oval,
+ if (dtp->dt_droptags) {
+ (void) snprintf(str, sizeof (str), "[%s] ",
+ dt_droptag(_dt_droptab[i].dtdrt_kind));
+ s = &str[strlen(str)];
+ size = sizeof (str) - (s - str);
+ } else {
+ s = str;
+ size = sizeof (str);
+ }
+
+ (void) snprintf(s, size, "%llu %s%s%s\n", nval - oval,
_dt_droptab[i].dtdrt_str, (nval - oval > 1) ? "s" : "",
_dt_droptab[i].dtdrt_msg != NULL ?
_dt_droptab[i].dtdrt_msg : "");
@@ -373,6 +446,20 @@ dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new)
}
int
+dt_handle_setopt(dtrace_hdl_t *dtp, dtrace_setoptdata_t *data)
+{
+ void *arg = dtp->dt_setoptarg;
+
+ if (dtp->dt_setopthdlr == NULL)
+ return (0);
+
+ if ((*dtp->dt_setopthdlr)(data, arg) == DTRACE_HANDLE_ABORT)
+ return (dt_set_errno(dtp, EDT_DIRABORT));
+
+ return (0);
+}
+
+int
dt_handle(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
{
dtrace_eprobedesc_t *epd = data->dtpda_edesc;
diff --git a/usr/src/lib/libdtrace/common/dt_impl.h b/usr/src/lib/libdtrace/common/dt_impl.h
index 055f3744e2..bc27d709fc 100644
--- a/usr/src/lib/libdtrace/common/dt_impl.h
+++ b/usr/src/lib/libdtrace/common/dt_impl.h
@@ -217,6 +217,8 @@ struct dtrace_hdl {
ctf_id_t dt_type_str; /* cached CTF identifier for string type */
ctf_id_t dt_type_dyn; /* cached CTF identifier for <DYN> type */
ctf_id_t dt_type_stack; /* cached CTF identifier for stack type */
+ ctf_id_t dt_type_symaddr; /* cached CTF identifier for _symaddr type */
+ ctf_id_t dt_type_usymaddr; /* cached CTF ident. for _usymaddr type */
size_t dt_maxprobe; /* max enabled probe ID */
dtrace_eprobedesc_t **dt_edesc; /* enabled probe descriptions */
dtrace_probedesc_t **dt_pdesc; /* probe descriptions for enabled prbs */
@@ -236,6 +238,7 @@ struct dtrace_hdl {
char *dt_ld_path; /* pathname of ld(1) to invoke if needed */
dt_list_t dt_lib_path; /* linked-list forming library search path */
uint_t dt_lazyload; /* boolean: set via -xlazyload */
+ uint_t dt_droptags; /* boolean: set via -xdroptags */
uint_t dt_active; /* boolean: set once tracing is active */
uint_t dt_stopped; /* boolean: set once tracing is stopped */
processorid_t dt_beganon; /* CPU that executed BEGIN probe (if any) */
@@ -266,6 +269,8 @@ struct dtrace_hdl {
void *dt_droparg; /* drop handler argument */
dtrace_handle_proc_f *dt_prochdlr; /* proc handler, if any */
void *dt_procarg; /* proc handler argument */
+ dtrace_handle_setopt_f *dt_setopthdlr; /* setopt handler, if any */
+ void *dt_setoptarg; /* setopt handler argument */
dtrace_status_t dt_status[2]; /* status cache */
int dt_statusgen; /* current status generation */
hrtime_t dt_laststatus; /* last status */
@@ -352,29 +357,50 @@ struct dtrace_hdl {
#define DT_STACK_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_STACK_TYPE(dtp) ((dtp)->dt_type_stack)
-#define DT_ACT_PRINTF 0 /* printf() action */
-#define DT_ACT_TRACE 1 /* trace() action */
-#define DT_ACT_TRACEMEM 2 /* tracemem() action */
-#define DT_ACT_STACK 3 /* stack() action */
-#define DT_ACT_STOP 4 /* stop() action */
-#define DT_ACT_BREAKPOINT 5 /* breakpoint() action */
-#define DT_ACT_PANIC 6 /* panic() action */
-#define DT_ACT_SPECULATE 7 /* speculate() action */
-#define DT_ACT_COMMIT 8 /* commit() action */
-#define DT_ACT_DISCARD 9 /* discard() action */
-#define DT_ACT_CHILL 10 /* chill() action */
-#define DT_ACT_EXIT 11 /* exit() action */
-#define DT_ACT_USTACK 12 /* ustack() action */
-#define DT_ACT_PRINTA 13 /* printa() action */
-#define DT_ACT_RAISE 14 /* raise() action */
-#define DT_ACT_CLEAR 15 /* clear() action */
-#define DT_ACT_NORMALIZE 16 /* normalize() action */
-#define DT_ACT_DENORMALIZE 17 /* denormalize() action */
-#define DT_ACT_TRUNC 18 /* trunc() action */
-#define DT_ACT_SYSTEM 19 /* system() action */
-#define DT_ACT_JSTACK 20 /* jstack() action */
-#define DT_ACT_FTRUNCATE 21 /* ftruncate() action */
-#define DT_ACT_FREOPEN 22 /* freopen() action */
+#define DT_SYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_SYMADDR_TYPE(dtp) ((dtp)->dt_type_symaddr)
+
+#define DT_USYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
+#define DT_USYMADDR_TYPE(dtp) ((dtp)->dt_type_usymaddr)
+
+/*
+ * Actions and subroutines are both DT_NODE_FUNC nodes; to avoid confusing
+ * an action for a subroutine (or vice versa), we assure that the DT_ACT_*
+ * constants and the DIF_SUBR_* constants occupy non-overlapping ranges by
+ * starting the DT_ACT_* constants at DIF_SUBR_MAX + 1.
+ */
+#define DT_ACT_BASE DIF_SUBR_MAX + 1
+#define DT_ACT(n) (DT_ACT_BASE + (n))
+
+#define DT_ACT_PRINTF DT_ACT(0) /* printf() action */
+#define DT_ACT_TRACE DT_ACT(1) /* trace() action */
+#define DT_ACT_TRACEMEM DT_ACT(2) /* tracemem() action */
+#define DT_ACT_STACK DT_ACT(3) /* stack() action */
+#define DT_ACT_STOP DT_ACT(4) /* stop() action */
+#define DT_ACT_BREAKPOINT DT_ACT(5) /* breakpoint() action */
+#define DT_ACT_PANIC DT_ACT(6) /* panic() action */
+#define DT_ACT_SPECULATE DT_ACT(7) /* speculate() action */
+#define DT_ACT_COMMIT DT_ACT(8) /* commit() action */
+#define DT_ACT_DISCARD DT_ACT(9) /* discard() action */
+#define DT_ACT_CHILL DT_ACT(10) /* chill() action */
+#define DT_ACT_EXIT DT_ACT(11) /* exit() action */
+#define DT_ACT_USTACK DT_ACT(12) /* ustack() action */
+#define DT_ACT_PRINTA DT_ACT(13) /* printa() action */
+#define DT_ACT_RAISE DT_ACT(14) /* raise() action */
+#define DT_ACT_CLEAR DT_ACT(15) /* clear() action */
+#define DT_ACT_NORMALIZE DT_ACT(16) /* normalize() action */
+#define DT_ACT_DENORMALIZE DT_ACT(17) /* denormalize() action */
+#define DT_ACT_TRUNC DT_ACT(18) /* trunc() action */
+#define DT_ACT_SYSTEM DT_ACT(19) /* system() action */
+#define DT_ACT_JSTACK DT_ACT(20) /* jstack() action */
+#define DT_ACT_FTRUNCATE DT_ACT(21) /* ftruncate() action */
+#define DT_ACT_FREOPEN DT_ACT(22) /* freopen() action */
+#define DT_ACT_SYM DT_ACT(23) /* sym()/func() actions */
+#define DT_ACT_MOD DT_ACT(24) /* mod() action */
+#define DT_ACT_USYM DT_ACT(25) /* usym()/ufunc() actions */
+#define DT_ACT_UMOD DT_ACT(26) /* umod() action */
+#define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */
+#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
/*
* Sentinel to tell freopen() to restore the saved stdout. This must not
@@ -456,7 +482,9 @@ enum {
EDT_HARDWIRE, /* failed to load hard-wired definitions */
EDT_ELFVERSION, /* libelf is out-of-date w.r.t libdtrace */
EDT_NOBUFFERED, /* attempt to buffer output without handler */
- EDT_UNSTABLE /* description matched unstable set of probes */
+ EDT_UNSTABLE, /* description matched unstable set of probes */
+ EDT_BADSETOPT, /* invalid setopt library action */
+ EDT_BADSTACKPC /* invalid stack program counter size */
};
/*
@@ -522,7 +550,7 @@ extern ulong_t dt_popcb(const ulong_t *, ulong_t);
extern int dt_buffered_enable(dtrace_hdl_t *);
extern int dt_buffered_flush(dtrace_hdl_t *, dtrace_probedata_t *,
- dtrace_recdesc_t *, dtrace_aggdata_t *);
+ const dtrace_recdesc_t *, const dtrace_aggdata_t *);
extern void dt_buffered_disable(dtrace_hdl_t *);
extern void dt_buffered_destroy(dtrace_hdl_t *);
@@ -565,7 +593,7 @@ extern int dt_print_quantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
extern int dt_print_lquantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
-extern int dt_print_agg(dtrace_aggdata_t *, void *);
+extern int dt_print_agg(const dtrace_aggdata_t *, void *);
extern int dt_handle(dtrace_hdl_t *, dtrace_probedata_t *);
extern int dt_handle_liberr(dtrace_hdl_t *,
@@ -574,6 +602,7 @@ extern int dt_handle_cpudrop(dtrace_hdl_t *, processorid_t,
dtrace_dropkind_t, uint64_t);
extern int dt_handle_status(dtrace_hdl_t *,
dtrace_status_t *, dtrace_status_t *);
+extern int dt_handle_setopt(dtrace_hdl_t *, dtrace_setoptdata_t *);
extern dt_pcb_t *yypcb; /* pointer to current parser control block */
extern char yyintprefix; /* int token prefix for macros (+/-) */
diff --git a/usr/src/lib/libdtrace/common/dt_open.c b/usr/src/lib/libdtrace/common/dt_open.c
index ae1eb076a6..f2c7713d85 100644
--- a/usr/src/lib/libdtrace/common/dt_open.c
+++ b/usr/src/lib/libdtrace/common/dt_open.c
@@ -187,6 +187,8 @@ static const dt_ident_t _dtrace_globals[] = {
DT_VERS_1_1, &dt_idops_func, "void(@, ...)" },
{ "ftruncate", DT_IDENT_ACTFUNC, 0, DT_ACT_FTRUNCATE, DT_ATTR_STABCMN,
DT_VERS_1_0, &dt_idops_func, "void()" },
+{ "func", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" },
{ "getmajor", DT_IDENT_FUNC, 0, DIF_SUBR_GETMAJOR,
DT_ATTR_EVOLCMN, DT_VERS_1_0,
&dt_idops_func, "genunix`major_t(genunix`dev_t)" },
@@ -210,6 +212,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "void(@)" },
{ "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@)" },
+{ "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" },
{ "msgdsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGDSIZE,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "size_t(mblk_t *)" },
@@ -251,7 +255,7 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "int(pid_t)" },
{ "quantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_QUANTIZE,
DT_ATTR_STABCMN, DT_VERS_1_0,
- &dt_idops_func, "void(@)" },
+ &dt_idops_func, "void(@, ...)" },
{ "raise", DT_IDENT_ACTFUNC, 0, DT_ACT_RAISE, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(int)" },
{ "rand", DT_IDENT_FUNC, 0, DIF_SUBR_RAND, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -269,6 +273,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "int(genunix`krwlock_t *)" },
{ "self", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "void" },
+{ "setopt", DT_IDENT_ACTFUNC, 0, DT_ACT_SETOPT, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "void(const char *, [const char *])" },
{ "speculate", DT_IDENT_ACTFUNC, 0, DT_ACT_SPECULATE,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(int)" },
@@ -298,6 +304,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "string(const char *, int, [int])" },
{ "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@)" },
+{ "sym", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" },
{ "system", DT_IDENT_ACTFUNC, 0, DT_ACT_SYSTEM, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@, ...)" },
{ "this", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -314,6 +322,14 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "void(@, size_t)" },
{ "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN,
DT_VERS_1_0, &dt_idops_func, "void(...)" },
+{ "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+{ "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_type, "uint64_t" },
+{ "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+{ "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
{ "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_regs, NULL },
{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -321,6 +337,8 @@ static const dt_ident_t _dtrace_globals[] = {
{ "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
DT_ATTR_STABCMN, DT_VERS_1_2,
&dt_idops_type, "uint32_t" },
+{ "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
+ DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
{ "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint64_t" },
@@ -1114,9 +1132,16 @@ alloc:
dtp->dt_type_stack = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
"stack", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+ dtp->dt_type_symaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ "_symaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+
+ dtp->dt_type_usymaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
+ "_usymaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+
if (dtp->dt_type_func == CTF_ERR || dtp->dt_type_fptr == CTF_ERR ||
dtp->dt_type_str == CTF_ERR || dtp->dt_type_dyn == CTF_ERR ||
- dtp->dt_type_stack == CTF_ERR) {
+ dtp->dt_type_stack == CTF_ERR || dtp->dt_type_symaddr == CTF_ERR ||
+ dtp->dt_type_usymaddr == CTF_ERR) {
dt_dprintf("failed to add intrinsic to D container: %s\n",
ctf_errmsg(ctf_errno(dmp->dm_ctfp)));
return (set_open_errno(dtp, errp, EDT_CTF));
@@ -1288,77 +1313,6 @@ dtrace_close(dtrace_hdl_t *dtp)
}
int
-dtrace_go(dtrace_hdl_t *dtp)
-{
- void *dof;
- int err;
-
- if (dtp->dt_active)
- return (dt_set_errno(dtp, EINVAL));
-
- /*
- * If a dtrace:::ERROR program and callback are registered, enable the
- * program before we start tracing. If this fails for a vector open
- * with ENOTTY, we permit dtrace_go() to succeed so that vector clients
- * such as mdb's dtrace module can execute the rest of dtrace_go() even
- * though they do not provide support for the DTRACEIOC_ENABLE ioctl.
- */
- if (dtp->dt_errprog != NULL &&
- dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 && (
- dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
- return (-1); /* dt_errno has been set for us */
-
- if ((dof = dtrace_getopt_dof(dtp)) == NULL)
- return (-1); /* dt_errno has been set for us */
-
- err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
- dtrace_dof_destroy(dtp, dof);
-
- if (err == -1 && (errno != ENOTTY || dtp->dt_vector == NULL))
- return (dt_set_errno(dtp, errno));
-
- if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
- if (errno == EACCES)
- return (dt_set_errno(dtp, EDT_DESTRUCTIVE));
-
- if (errno == EALREADY)
- return (dt_set_errno(dtp, EDT_ISANON));
-
- if (errno == ENOENT)
- return (dt_set_errno(dtp, EDT_NOANON));
-
- if (errno == E2BIG)
- return (dt_set_errno(dtp, EDT_ENDTOOBIG));
-
- if (errno == ENOSPC)
- return (dt_set_errno(dtp, EDT_BUFTOOSMALL));
-
- return (dt_set_errno(dtp, errno));
- }
-
- dtp->dt_active = 1;
-
- if (dt_options_load(dtp) == -1)
- return (dt_set_errno(dtp, errno));
-
- return (dt_aggregate_go(dtp));
-}
-
-int
-dtrace_stop(dtrace_hdl_t *dtp)
-{
- if (dtp->dt_stopped)
- return (0);
-
- if (dt_ioctl(dtp, DTRACEIOC_STOP, &dtp->dt_endedon) == -1)
- return (dt_set_errno(dtp, errno));
-
- dtp->dt_stopped = 1;
-
- return (0);
-}
-
-int
dtrace_provider_modules(dtrace_hdl_t *dtp, const char **mods, int nmods)
{
dt_provmod_t *prov;
diff --git a/usr/src/lib/libdtrace/common/dt_options.c b/usr/src/lib/libdtrace/common/dt_options.c
index 5119368aca..1c776f5933 100644
--- a/usr/src/lib/libdtrace/common/dt_options.c
+++ b/usr/src/lib/libdtrace/common/dt_options.c
@@ -197,6 +197,14 @@ dt_opt_ctypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
/*ARGSUSED*/
static int
+dt_opt_droptags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ dtp->dt_droptags = 1;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
dt_opt_dtypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
int fd;
@@ -507,8 +515,39 @@ dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
char *end;
dtrace_optval_t val = 0;
+ int i;
+
+ const struct {
+ char *positive;
+ char *negative;
+ } couples[] = {
+ { "yes", "no" },
+ { "enable", "disable" },
+ { "enabled", "disabled" },
+ { "true", "false" },
+ { "on", "off" },
+ { "set", "unset" },
+ { NULL }
+ };
if (arg != NULL) {
+ if (arg[0] == '\0') {
+ val = DTRACEOPT_UNSET;
+ goto out;
+ }
+
+ for (i = 0; couples[i].positive != NULL; i++) {
+ if (strcasecmp(couples[i].positive, arg) == 0) {
+ val = 1;
+ goto out;
+ }
+
+ if (strcasecmp(couples[i].negative, arg) == 0) {
+ val = DTRACEOPT_UNSET;
+ goto out;
+ }
+ }
+
errno = 0;
val = strtoull(arg, &end, 0);
@@ -516,6 +555,7 @@ dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
return (dt_set_errno(dtp, EDT_BADOPTVAL));
}
+out:
dtp->dt_options[option] = val;
return (0);
}
@@ -810,6 +850,7 @@ static const dt_option_t _dtrace_ctoptions[] = {
{ "dtypes", dt_opt_dtypes },
{ "debug", dt_opt_debug },
{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
+ { "droptags", dt_opt_droptags },
{ "empty", dt_opt_cflags, DTRACE_C_EMPTY },
{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
{ "evaltime", dt_opt_evaltime },
@@ -844,7 +885,6 @@ static const dt_option_t _dtrace_ctoptions[] = {
* Run-time options.
*/
static const dt_option_t _dtrace_rtoptions[] = {
- { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
{ "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
{ "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
{ "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
@@ -853,23 +893,30 @@ static const dt_option_t _dtrace_rtoptions[] = {
{ "cpu", dt_opt_runtime, DTRACEOPT_CPU },
{ "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
{ "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
- { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
{ "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
- { "jstackstrsize", dt_opt_runtime, DTRACEOPT_JSTACKSTRSIZE },
+ { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
- { "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
- { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
{ "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
{ "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
- { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
- { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
{ NULL }
};
+/*
+ * Dynamic run-time options.
+ */
+static const dt_option_t _dtrace_drtoptions[] = {
+ { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
+ { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
+ { "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
+ { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
+ { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
+ { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
+};
+
int
dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
{
@@ -889,6 +936,13 @@ dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
}
}
+ for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
+ if (strcmp(op->o_name, opt) == 0) {
+ *val = dtp->dt_options[op->o_option];
+ return (0);
+ }
+ }
+
return (dt_set_errno(dtp, EDT_BADOPTNAME));
}
@@ -905,10 +959,15 @@ dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
return (op->o_func(dtp, val, op->o_option));
}
+ for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
+ if (strcmp(op->o_name, opt) == 0)
+ return (op->o_func(dtp, val, op->o_option));
+ }
+
for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
if (strcmp(op->o_name, opt) == 0) {
/*
- * Currently, no run-time option may be set while
+ * Only dynamic run-time options may be set while
* tracing is active.
*/
if (dtp->dt_active)
diff --git a/usr/src/lib/libdtrace/common/dt_parser.c b/usr/src/lib/libdtrace/common/dt_parser.c
index e55907615e..4cf93888cc 100644
--- a/usr/src/lib/libdtrace/common/dt_parser.c
+++ b/usr/src/lib/libdtrace/common/dt_parser.c
@@ -916,6 +916,20 @@ dt_node_is_stack(const dt_node_t *dnp)
}
int
+dt_node_is_symaddr(const dt_node_t *dnp)
+{
+ return (dnp->dn_ctfp == DT_SYMADDR_CTFP(yypcb->pcb_hdl) &&
+ dnp->dn_type == DT_SYMADDR_TYPE(yypcb->pcb_hdl));
+}
+
+int
+dt_node_is_usymaddr(const dt_node_t *dnp)
+{
+ return (dnp->dn_ctfp == DT_USYMADDR_CTFP(yypcb->pcb_hdl) &&
+ dnp->dn_type == DT_USYMADDR_TYPE(yypcb->pcb_hdl));
+}
+
+int
dt_node_is_strcompat(const dt_node_t *dnp)
{
ctf_file_t *fp = dnp->dn_ctfp;
@@ -971,6 +985,9 @@ dt_node_is_void(const dt_node_t *dnp)
if (dt_node_is_stack(dnp))
return (0);
+ if (dt_node_is_symaddr(dnp) || dt_node_is_usymaddr(dnp))
+ return (0);
+
type = ctf_type_resolve(fp, dnp->dn_type);
return (ctf_type_kind(fp, type) == CTF_K_INTEGER &&
@@ -1107,6 +1124,12 @@ dt_node_is_argcompat(const dt_node_t *lp, const dt_node_t *rp)
if (dt_node_is_stack(lp) && dt_node_is_stack(rp))
return (1); /* stack types are compatible */
+ if (dt_node_is_symaddr(lp) && dt_node_is_symaddr(rp))
+ return (1); /* symaddr types are compatible */
+
+ if (dt_node_is_usymaddr(lp) && dt_node_is_usymaddr(rp))
+ return (1); /* usymaddr types are compatible */
+
switch (ctf_type_kind(lfp, ctf_type_resolve(lfp, lp->dn_type))) {
case CTF_K_FUNCTION:
case CTF_K_STRUCT:
diff --git a/usr/src/lib/libdtrace/common/dt_parser.h b/usr/src/lib/libdtrace/common/dt_parser.h
index 127b013045..ebd828b3a1 100644
--- a/usr/src/lib/libdtrace/common/dt_parser.h
+++ b/usr/src/lib/libdtrace/common/dt_parser.h
@@ -178,6 +178,9 @@ extern int dt_node_is_scalar(const dt_node_t *);
extern int dt_node_is_arith(const dt_node_t *);
extern int dt_node_is_vfptr(const dt_node_t *);
extern int dt_node_is_dynamic(const dt_node_t *);
+extern int dt_node_is_stack(const dt_node_t *);
+extern int dt_node_is_symaddr(const dt_node_t *);
+extern int dt_node_is_usymaddr(const dt_node_t *);
extern int dt_node_is_string(const dt_node_t *);
extern int dt_node_is_strcompat(const dt_node_t *);
extern int dt_node_is_pointer(const dt_node_t *);
diff --git a/usr/src/lib/libdtrace/common/dt_printf.c b/usr/src/lib/libdtrace/common/dt_printf.c
index dff27acc4b..20ebbe94c0 100644
--- a/usr/src/lib/libdtrace/common/dt_printf.c
+++ b/usr/src/lib/libdtrace/common/dt_printf.c
@@ -41,14 +41,45 @@
/*ARGSUSED*/
static int
-pfcheck_addr(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
}
/*ARGSUSED*/
static int
-pfcheck_str(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_kaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp) ||
+ dt_node_is_symaddr(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_uaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ dtrace_hdl_t *dtp = pfv->pfv_dtp;
+ dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
+
+ if (dt_node_is_usymaddr(dnp))
+ return (1);
+
+ if (idp == NULL || idp->di_id == 0)
+ return (0);
+
+ return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_stack(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
+{
+ return (dt_node_is_stack(dnp));
+}
+
+/*ARGSUSED*/
+static int
+pfcheck_str(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
ctf_file_t *ctfp;
ctf_encoding_t e;
@@ -70,7 +101,7 @@ pfcheck_str(dt_pfargd_t *pfd, dt_node_t *dnp)
/*ARGSUSED*/
static int
-pfcheck_wstr(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_wstr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
ctf_file_t *ctfp = dnp->dn_ctfp;
ctf_id_t base = ctf_type_resolve(ctfp, dnp->dn_type);
@@ -87,7 +118,7 @@ pfcheck_wstr(dt_pfargd_t *pfd, dt_node_t *dnp)
/*ARGSUSED*/
static int
-pfcheck_csi(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_csi(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
return (dt_node_is_integer(dnp) &&
dt_node_type_size(dnp) <= sizeof (int));
@@ -95,20 +126,21 @@ pfcheck_csi(dt_pfargd_t *pfd, dt_node_t *dnp)
/*ARGSUSED*/
static int
-pfcheck_fp(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_fp(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
return (dt_node_is_float(dnp));
}
/*ARGSUSED*/
static int
-pfcheck_xint(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_xint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
return (dt_node_is_integer(dnp));
}
+/*ARGSUSED*/
static int
-pfcheck_dint(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
if (dnp->dn_flags & DT_NF_SIGNED)
pfd->pfd_flags |= DT_PFCONV_SIGNED;
@@ -120,7 +152,7 @@ pfcheck_dint(dt_pfargd_t *pfd, dt_node_t *dnp)
/*ARGSUSED*/
static int
-pfcheck_xshort(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_xshort(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
ctf_file_t *ctfp = dnp->dn_ctfp;
ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
@@ -133,7 +165,7 @@ pfcheck_xshort(dt_pfargd_t *pfd, dt_node_t *dnp)
/*ARGSUSED*/
static int
-pfcheck_xlong(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_xlong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
ctf_file_t *ctfp = dnp->dn_ctfp;
ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
@@ -146,7 +178,7 @@ pfcheck_xlong(dt_pfargd_t *pfd, dt_node_t *dnp)
/*ARGSUSED*/
static int
-pfcheck_xlonglong(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_xlonglong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
ctf_file_t *ctfp = dnp->dn_ctfp;
ctf_id_t type = dnp->dn_type;
@@ -175,8 +207,9 @@ pfcheck_xlonglong(dt_pfargd_t *pfd, dt_node_t *dnp)
return (0);
}
+/*ARGSUSED*/
static int
-pfcheck_type(dt_pfargd_t *pfd, dt_node_t *dnp)
+pfcheck_type(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
return (ctf_type_compat(dnp->dn_ctfp, ctf_type_resolve(dnp->dn_ctfp,
dnp->dn_type), pfd->pfd_conv->pfc_dctfp, pfd->pfd_conv->pfc_dtype));
@@ -271,13 +304,9 @@ static int
pfprint_addr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
{
- dtrace_syminfo_t dts;
- GElf_Sym sym;
- GElf_Addr val;
-
- size_t n = 20; /* for 0x%llx\0 */
char *s;
- int err;
+ int n, len = 256;
+ uint64_t val;
switch (size) {
case sizeof (uint32_t):
@@ -290,32 +319,28 @@ pfprint_addr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
return (dt_set_errno(dtp, EDT_DMISMATCH));
}
- if ((err = dtrace_lookup_by_addr(dtp, val, &sym, &dts)) == 0)
- n += strlen(dts.dts_object) + strlen(dts.dts_name) + 2; /* +` */
+ do {
+ n = len;
+ s = alloca(n);
+ } while ((len = dtrace_addr2str(dtp, val, s, n)) >= n);
- s = alloca(n);
+ return (dt_printf(dtp, fp, format, s));
+}
- if (err == 0 && val != sym.st_value) {
- (void) snprintf(s, n, "%s`%s+0x%llx", dts.dts_object,
- dts.dts_name, (u_longlong_t)val - sym.st_value);
- } else if (err == 0) {
- (void) snprintf(s, n, "%s`%s",
- dts.dts_object, dts.dts_name);
- } else {
- /*
- * We'll repeat the lookup, but this time we'll specify a NULL
- * GElf_Sym -- indicating that we're only interested in the
- * containing module.
- */
- if (dtrace_lookup_by_addr(dtp, val, NULL, &dts) == 0) {
- (void) snprintf(s, n, "%s`0x%llx", dts.dts_object,
- (u_longlong_t)val);
- } else {
- (void) snprintf(s, n, "0x%llx", (u_longlong_t)val);
- }
- }
+/*ARGSUSED*/
+static int
+pfprint_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_print_mod(dtp, fp, format, (caddr_t)addr));
+}
- return (dt_printf(dtp, fp, format, s));
+/*ARGSUSED*/
+static int
+pfprint_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
+{
+ return (dt_print_umod(dtp, fp, format, (caddr_t)addr));
}
/*ARGSUSED*/
@@ -323,13 +348,11 @@ static int
pfprint_uaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
{
- u_longlong_t val;
+ char *s;
+ int n, len = 256;
+ uint64_t val, pid = 0;
+
dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
- char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
- struct ps_prochandle *P = NULL;
- pid_t pid;
- GElf_Sym sym;
- char *obj;
switch (size) {
case sizeof (uint32_t):
@@ -338,42 +361,23 @@ pfprint_uaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
case sizeof (uint64_t):
val = (u_longlong_t)*((uint64_t *)addr);
break;
+ case sizeof (uint64_t) * 2:
+ pid = ((uint64_t *)(uintptr_t)addr)[0];
+ val = ((uint64_t *)(uintptr_t)addr)[1];
+ break;
default:
return (dt_set_errno(dtp, EDT_DMISMATCH));
}
- if (dtp->dt_vector == NULL && idp != NULL && (pid = idp->di_id) != 0)
- P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
-
- if (P == NULL) {
- (void) snprintf(c, sizeof (c), "0x%llx", val);
- return (dt_printf(dtp, fp, format, c));
- }
-
- dt_proc_lock(dtp, P);
-
- if (Plookup_by_addr(P, val, name, sizeof (name), &sym) == 0) {
- (void) Pobjname(P, val, objname, sizeof (objname));
-
- obj = dt_basename(objname);
+ if (pid == 0 && dtp->dt_vector == NULL && idp != NULL)
+ pid = idp->di_id;
- if (val > sym.st_value) {
- (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", obj,
- name, (u_longlong_t)(val - sym.st_value));
- } else {
- (void) snprintf(c, sizeof (c), "%s`%s", obj, name);
- }
- } else if (Pobjname(P, val, objname, sizeof (objname)) != NULL) {
- (void) snprintf(c, sizeof (c), "%s`0x%llx",
- dt_basename(objname), val);
- } else {
- (void) snprintf(c, sizeof (c), "0x%llx", val);
- }
-
- dt_proc_unlock(dtp, P);
- dt_proc_release(dtp, P);
+ do {
+ n = len;
+ s = alloca(n);
+ } while ((len = dtrace_uaddr2str(dtp, pid, val, s, n)) >= n);
- return (dt_printf(dtp, fp, format, c));
+ return (dt_printf(dtp, fp, format, s));
}
/*ARGSUSED*/
@@ -381,7 +385,7 @@ static int
pfprint_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
const dt_pfargd_t *pfd, const void *vaddr, size_t size, uint64_t normal)
{
- int depth = size / sizeof (pc_t), width;
+ int width;
dtrace_optval_t saved = dtp->dt_options[DTRACEOPT_STACKINDENT];
const dtrace_recdesc_t *rec = pfd->pfd_rec;
caddr_t addr = (caddr_t)vaddr;
@@ -414,7 +418,8 @@ pfprint_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
break;
case DTRACEACT_STACK:
- err = dt_print_stack(dtp, fp, format, addr, depth);
+ err = dt_print_stack(dtp, fp, format, addr, rec->dtrd_arg,
+ rec->dtrd_size / rec->dtrd_arg);
break;
default:
@@ -554,6 +559,8 @@ static const char pfproto_xint[] = "char, short, int, long, or long long";
static const char pfproto_csi[] = "char, short, or int";
static const char pfproto_fp[] = "float, double, or long double";
static const char pfproto_addr[] = "pointer or integer";
+static const char pfproto_uaddr[] =
+ "pointer or integer (with -p/-c) or _usymaddr (without -p/-c)";
static const char pfproto_cstr[] = "char [] or string (or use stringof)";
static const char pfproto_wstr[] = "wchar_t []";
@@ -565,8 +572,8 @@ static const char pfproto_wstr[] = "wchar_t []";
* string of the types expected for use in error messages.
*/
static const dt_pfconv_t _dtrace_conversions[] = {
-{ "a", "s", pfproto_addr, pfcheck_addr, pfprint_addr },
-{ "A", "s", pfproto_addr, pfcheck_addr, pfprint_uaddr },
+{ "a", "s", pfproto_addr, pfcheck_kaddr, pfprint_addr },
+{ "A", "s", pfproto_uaddr, pfcheck_uaddr, pfprint_uaddr },
{ "c", "c", pfproto_csi, pfcheck_csi, pfprint_sint },
{ "C", "s", pfproto_csi, pfcheck_csi, pfprint_echr },
{ "d", "d", pfproto_xint, pfcheck_dint, pfprint_dint },
@@ -582,7 +589,7 @@ static const dt_pfconv_t _dtrace_conversions[] = {
{ "hx", "x", "short", pfcheck_xshort, pfprint_uint },
{ "hX", "X", "short", pfcheck_xshort, pfprint_uint },
{ "i", "i", pfproto_xint, pfcheck_dint, pfprint_dint },
-{ "k", "s", "stack", pfcheck_type, pfprint_stack },
+{ "k", "s", "stack", pfcheck_stack, pfprint_stack },
{ "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */
{ "ld", "d", "long", pfcheck_type, pfprint_sint },
{ "li", "i", "long", pfcheck_type, pfprint_sint },
@@ -757,6 +764,7 @@ dt_printf_create(dtrace_hdl_t *dtp, const char *s)
pfv->pfv_argv = NULL;
pfv->pfv_argc = 0;
pfv->pfv_flags = 0;
+ pfv->pfv_dtp = dtp;
for (q = format; (p = strchr(q, '%')) != NULL; q = *p ? p + 1 : p) {
uint_t namelen = 0;
@@ -904,21 +912,6 @@ dt_printf_create(dtrace_hdl_t *dtp, const char *s)
name[namelen] = '\0';
}
- if (strcmp(name, "A") == 0) {
- dt_ident_t *idp;
-
- idp = dt_idhash_lookup(dtp->dt_macros, "target");
-
- if (idp == NULL || idp->di_id == 0) {
- yywarn("format conversion #%u only "
- "valid when target process is specified\n",
- pfv->pfv_argc);
-
- dt_printf_destroy(pfv);
- return (dt_printf_error(dtp, EDT_COMPILER));
- }
- }
-
pfd->pfd_conv = dt_pfdict_lookup(dtp, name);
if (pfd->pfd_conv == NULL) {
@@ -982,6 +975,8 @@ dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
"%s( ) format string is empty\n", func);
}
+ pfv->pfv_flags = flags;
+
/*
* We fake up a parse node representing the type that can be used with
* an aggregation result conversion. For now we hardcode the signed
@@ -1095,7 +1090,7 @@ dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
* string by concatenating together any required printf(3C)
* size prefixes with the conversion's native format string.
*/
- if (pfc->pfc_check(pfd, vnp) == 0) {
+ if (pfc->pfc_check(pfv, pfd, vnp) == 0) {
xyerror(D_PRINTF_ARG_TYPE,
"%s( ) %s is incompatible with "
"conversion #%d prototype:\n\tconversion: %%%s\n"
@@ -1110,8 +1105,6 @@ dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
"%s( ) prototype mismatch: only %d arguments "
"required by this format string\n", func, j);
}
-
- pfv->pfv_flags = flags;
}
static int
@@ -1184,13 +1177,14 @@ pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
static int
dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf,
- size_t len, uint64_t normal)
+ size_t len, const dtrace_aggdata_t *adp)
{
dt_pfargd_t *pfd = pfv->pfv_argv;
const dtrace_recdesc_t *recp = recs;
const dtrace_recdesc_t *aggr = NULL;
uchar_t *lim = (uchar_t *)buf + len;
char format[64] = "%";
+ uint64_t normal = adp ? adp->dtada_normal : 1;
int i;
/*
@@ -1200,6 +1194,7 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
* to prevent this record from being used with any other conversion.
*/
if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
+ assert(adp != NULL);
if (nrecs == 0)
return (dt_set_errno(dtp, EDT_DMISMATCH));
aggr = recp + nrecs - 1;
@@ -1226,6 +1221,18 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
if ((rval = dt_printf(dtp, fp, tmp)) < 0)
return (rval);
+
+ if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
+ /*
+ * For printa(), we flush the buffer after each
+ * prefix, setting the record to NULL to
+ * indicate that this does not correspond to
+ * a particular tuple element, but is rather
+ * part of the format string.
+ */
+ if (dt_buffered_flush(dtp, NULL, NULL, adp) < 0)
+ return (-1);
+ }
}
if (pfc == NULL) {
@@ -1294,6 +1301,12 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
case DTRACEAGG_LQUANTIZE:
func = pfprint_lquantize;
break;
+ case DTRACEACT_MOD:
+ func = pfprint_mod;
+ break;
+ case DTRACEACT_UMOD:
+ func = pfprint_umod;
+ break;
default:
func = pfc->pfc_print;
break;
@@ -1333,6 +1346,15 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
if (func(dtp, fp, format, pfd, addr, size,
rec == aggr ? normal : 1) < 0)
return (-1); /* errno is set for us */
+
+ if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
+ /*
+ * For printa(), we flush the buffer after each tuple
+ * element.
+ */
+ if (dt_buffered_flush(dtp, NULL, rec, adp) < 0)
+ return (-1);
+ }
}
return ((int)(recp - recs));
@@ -1357,7 +1379,7 @@ dtrace_sprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
bzero(dtp->dt_sprintf_buf, size);
dtp->dt_sprintf_buflen = size;
- rval = dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len, 1);
+ rval = dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len, NULL);
dtp->dt_sprintf_buflen = 0;
if (rval == -1)
@@ -1496,7 +1518,8 @@ dtrace_fprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
uint_t nrecs, const void *buf, size_t len)
{
- return (dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len, 1));
+ return (dt_printf_format(dtp, fp, fmtdata,
+ recp, nrecs, buf, len, NULL));
}
void *
@@ -1633,27 +1656,28 @@ dtrace_printf_format(dtrace_hdl_t *dtp, void *fmtdata, char *s, size_t len)
}
static int
-dt_fprinta(dtrace_aggdata_t *adp, void *arg)
+dt_fprinta(const dtrace_aggdata_t *adp, void *arg)
{
- dtrace_aggdesc_t *agg = adp->dtada_desc;
+ const dtrace_aggdesc_t *agg = adp->dtada_desc;
const dtrace_recdesc_t *recp = &agg->dtagd_rec[0];
uint_t nrecs = agg->dtagd_nrecs;
dt_pfwalk_t *pfw = arg;
+ dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp;
int id;
- if (dt_printf_getint(pfw->pfw_dtp, recp++, nrecs--,
+ if (dt_printf_getint(dtp, recp++, nrecs--,
adp->dtada_data, adp->dtada_size, &id) != 0 || pfw->pfw_aid != id)
return (0); /* no aggregation id or id does not match */
- if (dt_printf_format(pfw->pfw_dtp, pfw->pfw_fp, pfw->pfw_argv,
- recp, nrecs, adp->dtada_data, adp->dtada_size,
- adp->dtada_normal) == -1)
- return (pfw->pfw_err = pfw->pfw_dtp->dt_errno);
-
- agg->dtagd_flags |= DTRACE_AGD_PRINTED;
+ if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv,
+ recp, nrecs, adp->dtada_data, adp->dtada_size, adp) == -1)
+ return (pfw->pfw_err = dtp->dt_errno);
- if (dt_buffered_flush(pfw->pfw_dtp, NULL, &agg->dtagd_rec[0], adp) < 0)
- return (-1);
+ /*
+ * Cast away the const to set the bit indicating that this aggregation
+ * has been printed.
+ */
+ ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED;
return (0);
}
@@ -1671,7 +1695,6 @@ dtrace_fprinta(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
if (dt_printf_getint(dtp, recp++, nrecs--, buf, len, &id) == -1)
return (-1); /* errno is set for us */
- pfw.pfw_dtp = dtp;
pfw.pfw_argv = fmtdata;
pfw.pfw_aid = id;
pfw.pfw_fp = fp;
diff --git a/usr/src/lib/libdtrace/common/dt_printf.h b/usr/src/lib/libdtrace/common/dt_printf.h
index 2a9089861f..70677a67b3 100644
--- a/usr/src/lib/libdtrace/common/dt_printf.h
+++ b/usr/src/lib/libdtrace/common/dt_printf.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,9 +42,11 @@ struct dt_node;
struct dt_ident;
struct dt_pfconv;
+struct dt_pfargv;
struct dt_pfargd;
-typedef int dt_pfcheck_f(struct dt_pfargd *, struct dt_node *);
+typedef int dt_pfcheck_f(struct dt_pfargv *,
+ struct dt_pfargd *, struct dt_node *);
typedef int dt_pfprint_f(dtrace_hdl_t *, FILE *, const char *,
const struct dt_pfargd *, const void *, size_t, uint64_t);
@@ -91,6 +93,7 @@ typedef struct dt_pfargd {
#define DT_PFCONV_SIGNED 0x0200 /* arg is a signed integer */
typedef struct dt_pfargv {
+ dtrace_hdl_t *pfv_dtp; /* libdtrace client handle */
char *pfv_format; /* format string pointer */
dt_pfargd_t *pfv_argv; /* list of argument descriptors */
uint_t pfv_argc; /* number of argument descriptors */
@@ -98,7 +101,6 @@ typedef struct dt_pfargv {
} dt_pfargv_t;
typedef struct dt_pfwalk {
- dtrace_hdl_t *pfw_dtp; /* libdtrace client handle */
const dt_pfargv_t *pfw_argv; /* argument description list */
uint_t pfw_aid; /* aggregation variable identifier */
FILE *pfw_fp; /* file pointer to use for output */
@@ -118,9 +120,11 @@ extern void dt_printf_validate(dt_pfargv_t *, uint_t,
struct dt_ident *, int, dtrace_actkind_t, struct dt_node *);
extern int dt_print_stack(dtrace_hdl_t *, FILE *,
- const char *, caddr_t, int);
+ const char *, caddr_t, int, int);
extern int dt_print_ustack(dtrace_hdl_t *, FILE *,
const char *, caddr_t, uint64_t);
+extern int dt_print_mod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
+extern int dt_print_umod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libdtrace/common/dt_subr.c b/usr/src/lib/libdtrace/common/dt_subr.c
index 31c2c4a4d4..47a161df07 100644
--- a/usr/src/lib/libdtrace/common/dt_subr.c
+++ b/usr/src/lib/libdtrace/common/dt_subr.c
@@ -39,6 +39,7 @@
#include <alloca.h>
#include <assert.h>
#include <libgen.h>
+#include <limits.h>
#include <dt_impl.h>
@@ -655,7 +656,7 @@ dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...)
int
dt_buffered_flush(dtrace_hdl_t *dtp, dtrace_probedata_t *pdata,
- dtrace_recdesc_t *rec, dtrace_aggdata_t *agg)
+ const dtrace_recdesc_t *rec, const dtrace_aggdata_t *agg)
{
dtrace_bufdata_t data;
@@ -824,3 +825,111 @@ dt_mutex_held(pthread_mutex_t *lock)
extern int _mutex_held(struct _lwp_mutex *);
return (_mutex_held((struct _lwp_mutex *)lock));
}
+
+static int
+dt_string2str(char *s, char *str, int nbytes)
+{
+ int len = strlen(s);
+
+ if (nbytes == 0) {
+ /*
+ * Like snprintf(3C), we don't check the value of str if the
+ * number of bytes is 0.
+ */
+ return (len);
+ }
+
+ if (nbytes <= len) {
+ (void) strncpy(str, s, nbytes - 1);
+ /*
+ * Like snprintf(3C) (and unlike strncpy(3C)), we guarantee
+ * that the string is null-terminated.
+ */
+ str[nbytes - 1] = '\0';
+ } else {
+ (void) strcpy(str, s);
+ }
+
+ return (len);
+}
+
+int
+dtrace_addr2str(dtrace_hdl_t *dtp, uint64_t addr, char *str, int nbytes)
+{
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+
+ size_t n = 20; /* for 0x%llx\0 */
+ char *s;
+ int err;
+
+ if ((err = dtrace_lookup_by_addr(dtp, addr, &sym, &dts)) == 0)
+ n += strlen(dts.dts_object) + strlen(dts.dts_name) + 2; /* +` */
+
+ s = alloca(n);
+
+ if (err == 0 && addr != sym.st_value) {
+ (void) snprintf(s, n, "%s`%s+0x%llx", dts.dts_object,
+ dts.dts_name, (u_longlong_t)addr - sym.st_value);
+ } else if (err == 0) {
+ (void) snprintf(s, n, "%s`%s",
+ dts.dts_object, dts.dts_name);
+ } else {
+ /*
+ * We'll repeat the lookup, but this time we'll specify a NULL
+ * GElf_Sym -- indicating that we're only interested in the
+ * containing module.
+ */
+ if (dtrace_lookup_by_addr(dtp, addr, NULL, &dts) == 0) {
+ (void) snprintf(s, n, "%s`0x%llx", dts.dts_object,
+ (u_longlong_t)addr);
+ } else {
+ (void) snprintf(s, n, "0x%llx", (u_longlong_t)addr);
+ }
+ }
+
+ return (dt_string2str(s, str, nbytes));
+}
+
+int
+dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
+ uint64_t addr, char *str, int nbytes)
+{
+ char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
+ struct ps_prochandle *P = NULL;
+ GElf_Sym sym;
+ char *obj;
+
+ if (pid != 0)
+ P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
+
+ if (P == NULL) {
+ (void) snprintf(c, sizeof (c), "0x%llx", addr);
+ return (dt_string2str(c, str, nbytes));
+ }
+
+ dt_proc_lock(dtp, P);
+
+ if (Plookup_by_addr(P, addr, name, sizeof (name), &sym) == 0) {
+ (void) Pobjname(P, addr, objname, sizeof (objname));
+
+ obj = dt_basename(objname);
+
+ if (addr > sym.st_value) {
+ (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", obj,
+ name, (u_longlong_t)(addr - sym.st_value));
+ } else {
+ (void) snprintf(c, sizeof (c), "%s`%s", obj, name);
+ }
+ } else if (Pobjname(P, addr, objname, sizeof (objname)) != NULL) {
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dt_basename(objname), addr);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx", addr);
+ }
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+
+ return (dt_string2str(c, str, nbytes));
+}
diff --git a/usr/src/lib/libdtrace/common/dt_work.c b/usr/src/lib/libdtrace/common/dt_work.c
index 7ea8dc7dce..64cc8ff176 100644
--- a/usr/src/lib/libdtrace/common/dt_work.c
+++ b/usr/src/lib/libdtrace/common/dt_work.c
@@ -154,6 +154,90 @@ dtrace_status(dtrace_hdl_t *dtp)
return (DTRACE_STATUS_FILLED);
}
+int
+dtrace_go(dtrace_hdl_t *dtp)
+{
+ void *dof;
+ int err;
+
+ if (dtp->dt_active)
+ return (dt_set_errno(dtp, EINVAL));
+
+ /*
+ * If a dtrace:::ERROR program and callback are registered, enable the
+ * program before we start tracing. If this fails for a vector open
+ * with ENOTTY, we permit dtrace_go() to succeed so that vector clients
+ * such as mdb's dtrace module can execute the rest of dtrace_go() even
+ * though they do not provide support for the DTRACEIOC_ENABLE ioctl.
+ */
+ if (dtp->dt_errprog != NULL &&
+ dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 && (
+ dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
+ return (-1); /* dt_errno has been set for us */
+
+ if ((dof = dtrace_getopt_dof(dtp)) == NULL)
+ return (-1); /* dt_errno has been set for us */
+
+ err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
+ dtrace_dof_destroy(dtp, dof);
+
+ if (err == -1 && (errno != ENOTTY || dtp->dt_vector == NULL))
+ return (dt_set_errno(dtp, errno));
+
+ if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
+ if (errno == EACCES)
+ return (dt_set_errno(dtp, EDT_DESTRUCTIVE));
+
+ if (errno == EALREADY)
+ return (dt_set_errno(dtp, EDT_ISANON));
+
+ if (errno == ENOENT)
+ return (dt_set_errno(dtp, EDT_NOANON));
+
+ if (errno == E2BIG)
+ return (dt_set_errno(dtp, EDT_ENDTOOBIG));
+
+ if (errno == ENOSPC)
+ return (dt_set_errno(dtp, EDT_BUFTOOSMALL));
+
+ return (dt_set_errno(dtp, errno));
+ }
+
+ dtp->dt_active = 1;
+
+ if (dt_options_load(dtp) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ return (dt_aggregate_go(dtp));
+}
+
+int
+dtrace_stop(dtrace_hdl_t *dtp)
+{
+ int gen = dtp->dt_statusgen;
+
+ if (dtp->dt_stopped)
+ return (0);
+
+ if (dt_ioctl(dtp, DTRACEIOC_STOP, &dtp->dt_endedon) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ dtp->dt_stopped = 1;
+
+ /*
+ * Now that we're stopped, we're going to get status one final time.
+ */
+ if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ if (dt_handle_status(dtp, &dtp->dt_status[gen ^ 1],
+ &dtp->dt_status[gen]) == -1)
+ return (-1);
+
+ return (0);
+}
+
+
dtrace_workstatus_t
dtrace_work(dtrace_hdl_t *dtp, FILE *fp,
dtrace_consume_probe_f *pfunc, dtrace_consume_rec_f *rfunc, void *arg)
diff --git a/usr/src/lib/libdtrace/common/dtrace.h b/usr/src/lib/libdtrace/common/dtrace.h
index efeb44550a..6d8fa80dc9 100644
--- a/usr/src/lib/libdtrace/common/dtrace.h
+++ b/usr/src/lib/libdtrace/common/dtrace.h
@@ -267,7 +267,7 @@ typedef struct dtrace_errdata {
const char *dteda_msg; /* preconstructed message */
} dtrace_errdata_t;
-typedef int dtrace_handle_err_f(dtrace_errdata_t *, void *);
+typedef int dtrace_handle_err_f(const dtrace_errdata_t *, void *);
extern int dtrace_handle_err(dtrace_hdl_t *, dtrace_handle_err_f *, void *);
typedef enum {
@@ -278,7 +278,9 @@ typedef enum {
DTRACEDROP_DYNDIRTY, /* dyn drop due to dirty */
DTRACEDROP_SPEC, /* speculative drop */
DTRACEDROP_SPECBUSY, /* spec drop due to busy */
- DTRACEDROP_SPECUNAVAIL /* spec drop due to unavail */
+ DTRACEDROP_SPECUNAVAIL, /* spec drop due to unavail */
+ DTRACEDROP_STKSTROVERFLOW, /* stack string tab overflow */
+ DTRACEDROP_DBLERROR /* error in ERROR probe */
} dtrace_dropkind_t;
typedef struct dtrace_dropdata {
@@ -290,7 +292,7 @@ typedef struct dtrace_dropdata {
const char *dtdda_msg; /* preconstructed message */
} dtrace_dropdata_t;
-typedef int dtrace_handle_drop_f(dtrace_dropdata_t *, void *);
+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 *);
@@ -300,14 +302,26 @@ typedef struct dtrace_bufdata {
dtrace_hdl_t *dtbda_handle; /* handle to DTrace library */
const char *dtbda_buffered; /* buffered output */
dtrace_probedata_t *dtbda_probe; /* probe data */
- dtrace_recdesc_t *dtbda_recdesc; /* record description */
- dtrace_aggdata_t *dtbda_aggdata; /* aggregation data, if agg. */
+ const dtrace_recdesc_t *dtbda_recdesc; /* record description */
+ const dtrace_aggdata_t *dtbda_aggdata; /* aggregation data, if agg. */
} dtrace_bufdata_t;
-typedef int dtrace_handle_buffered_f(dtrace_bufdata_t *, void *);
+typedef int dtrace_handle_buffered_f(const dtrace_bufdata_t *, void *);
extern int dtrace_handle_buffered(dtrace_hdl_t *,
dtrace_handle_buffered_f *, void *);
+typedef struct dtrace_setoptdata {
+ dtrace_hdl_t *dtsda_handle; /* handle to DTrace library */
+ const dtrace_probedata_t *dtsda_probe; /* probe data */
+ const char *dtsda_option; /* option that was set */
+ dtrace_optval_t dtsda_oldval; /* old value */
+ dtrace_optval_t dtsda_newval; /* new value */
+} dtrace_setoptdata_t;
+
+typedef int dtrace_handle_setopt_f(const dtrace_setoptdata_t *, void *);
+extern int dtrace_handle_setopt(dtrace_hdl_t *,
+ dtrace_handle_setopt_f *, void *);
+
/*
* DTrace Aggregate Interface
*/
@@ -337,7 +351,7 @@ struct dtrace_aggdata {
caddr_t *dtada_percpu_delta; /* per CPU delta, if avail */
};
-typedef int dtrace_aggregate_f(dtrace_aggdata_t *, void *);
+typedef int dtrace_aggregate_f(const dtrace_aggdata_t *, void *);
typedef int dtrace_aggregate_walk_f(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
@@ -501,10 +515,14 @@ struct dtrace_vector {
/*
* DTrace Utility Functions
*
- * Library clients can use these functions to convert between string and
- * integer probe descriptions and the dtrace_probedesc_t representation
- * and to perform similar conversions on stability attributes.
+ * Library clients can use these functions to convert addresses strings, to
+ * convert between string and integer probe descriptions and the
+ * dtrace_probedesc_t representation, and to perform similar conversions on
+ * stability attributes.
*/
+extern int dtrace_addr2str(dtrace_hdl_t *, uint64_t, char *, int);
+extern int dtrace_uaddr2str(dtrace_hdl_t *, pid_t, uint64_t, char *, int);
+
extern int dtrace_xstr2desc(dtrace_hdl_t *, dtrace_probespec_t,
const char *, int, char *const [], dtrace_probedesc_t *);
diff --git a/usr/src/lib/libdtrace/spec/dtrace.spec b/usr/src/lib/libdtrace/spec/dtrace.spec
index 52f9e63519..95c15e598f 100644
--- a/usr/src/lib/libdtrace/spec/dtrace.spec
+++ b/usr/src/lib/libdtrace/spec/dtrace.spec
@@ -32,6 +32,10 @@ data _dtrace_version
version SUNWprivate_1.1
end
+function dtrace_addr2str
+version SUNWprivate_1.1
+end
+
function dtrace_aggregate_clear
version SUNWprivate_1.1
end
@@ -164,6 +168,10 @@ function dtrace_handle_proc
version SUNWprivate_1.1
end
+function dtrace_handle_setopt
+version SUNWprivate_1.1
+end
+
function dtrace_id2desc
version SUNWprivate_1.1
end
@@ -320,6 +328,10 @@ function dtrace_type_fcompile
version SUNWprivate_1.1
end
+function dtrace_uaddr2str
+version SUNWprivate_1.1
+end
+
function dtrace_update
version SUNWprivate_1.1
end
diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c
index 05dd4d570c..71e4f258f8 100644
--- a/usr/src/lib/libproc/common/Psymtab.c
+++ b/usr/src/lib/libproc/common/Psymtab.c
@@ -392,7 +392,7 @@ Pupdate_maps(struct ps_prochandle *P)
map_info_t *newmap, *newp;
map_info_t *mptr;
- if (P->info_valid)
+ if (P->info_valid || P->state == PS_UNDEAD)
return;
Preadauxvec(P);
diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c
index 5393ecb482..5fa76f6025 100644
--- a/usr/src/uts/common/dtrace/dtrace.c
+++ b/usr/src/uts/common/dtrace/dtrace.c
@@ -168,6 +168,7 @@ static int dtrace_nprobes; /* number of probes */
static dtrace_provider_t *dtrace_provider; /* provider list */
static dtrace_meta_t *dtrace_meta_pid; /* user-land meta provider */
static int dtrace_opens; /* number of opens */
+static int dtrace_helpers; /* number of helpers */
static void *dtrace_softstate; /* softstate pointer */
static dtrace_hash_t *dtrace_bymod; /* probes hashed by module */
static dtrace_hash_t *dtrace_byfunc; /* probes hashed by function */
@@ -180,12 +181,11 @@ static kmem_cache_t *dtrace_state_cache; /* cache for dynamic state */
static uint64_t dtrace_vtime_references; /* number of vtimestamp refs */
static kthread_t *dtrace_panicked; /* panicking thread */
static dtrace_ecb_t *dtrace_ecb_create_cache; /* cached created ECB */
-static int dtrace_double_errors; /* ERRORs inducing error */
static dtrace_genid_t dtrace_probegen; /* current probe generation */
static dtrace_helpers_t *dtrace_deferred_pid; /* deferred helper list */
static dtrace_enabling_t *dtrace_retained; /* list of retained enablings */
static dtrace_state_t *dtrace_state; /* temporary variable */
-static int dtrace_error; /* temporary variable */
+static int dtrace_err; /* temporary variable */
/*
* DTrace Locking
@@ -209,11 +209,13 @@ static int dtrace_error; /* temporary variable */
* calls into the providers -- which then call back into the framework,
* grabbing dtrace_lock.)
*
- * There are two other locks in the mix: mod_lock and cpu_lock. cpu_lock
- * continues its historical role as a coarse-grained lock; it is acquired
- * before both dtrace_provider_lock and dtrace_lock. mod_lock is slightly
- * stranger: it must be acquired _between_ dtrace_provider_lock and
- * dtrace_lock.
+ * There are two other locks in the mix: mod_lock and cpu_lock. With respect
+ * to dtrace_provider_lock and dtrace_lock, cpu_lock continues its historical
+ * role as a coarse-grained lock; it is acquired before both of these locks.
+ * With respect to dtrace_meta_lock, its behavior is stranger: cpu_lock must
+ * be acquired _between_ dtrace_meta_lock and any other DTrace locks.
+ * mod_lock is similar with respect to dtrace_provider_lock in that it must be
+ * acquired _between_ dtrace_provider_lock and dtrace_lock.
*/
static kmutex_t dtrace_lock; /* probe state lock */
static kmutex_t dtrace_provider_lock; /* provider state lock */
@@ -449,6 +451,45 @@ dtrace_assfail(const char *a, const char *f, int l)
}
/*
+ * Atomically increment a specified error counter from probe context.
+ */
+static void
+dtrace_error(uint32_t *counter)
+{
+ /*
+ * Most counters stored to in probe context are per-CPU counters.
+ * However, there are some error conditions that are sufficiently
+ * arcane that they don't merit per-CPU storage. If these counters
+ * are incremented concurrently on different CPUs, scalability will be
+ * adversely affected -- but we don't expect them to be white-hot in a
+ * correctly constructed enabling...
+ */
+ uint32_t oval, nval;
+
+ do {
+ oval = *counter;
+
+ if ((nval = oval + 1) == 0) {
+ /*
+ * If the counter would wrap, set it to 1 -- assuring
+ * that the counter is never zero when we have seen
+ * errors. (The counter must be 32-bits because we
+ * aren't guaranteed a 64-bit compare&swap operation.)
+ * To save this code both the infamy of being fingered
+ * by a priggish news story and the indignity of being
+ * the target of a neo-puritan witch trial, we're
+ * carefully avoiding any colorful description of the
+ * likelihood of this condition -- but suffice it to
+ * say that it is only slightly more likely than the
+ * overflow of predicate cache IDs, as discussed in
+ * dtrace_predicate_create().
+ */
+ nval = 1;
+ }
+ } while (dtrace_cas32(counter, oval, nval) != oval);
+}
+
+/*
* Use the DTRACE_LOADFUNC macro to define functions for each of loading a
* uint8_t, a uint16_t, a uint32_t and a uint64_t.
*/
@@ -1323,22 +1364,24 @@ retry:
return (dtrace_dynvar(dstate, nkeys, key, dsize, op));
}
+/*ARGSUSED*/
static void
-dtrace_aggregate_min(uint64_t *oval, uint64_t nval)
+dtrace_aggregate_min(uint64_t *oval, uint64_t nval, uint64_t arg)
{
if (nval < *oval)
*oval = nval;
}
+/*ARGSUSED*/
static void
-dtrace_aggregate_max(uint64_t *oval, uint64_t nval)
+dtrace_aggregate_max(uint64_t *oval, uint64_t nval, uint64_t arg)
{
if (nval > *oval)
*oval = nval;
}
static void
-dtrace_aggregate_quantize(uint64_t *quanta, uint64_t nval)
+dtrace_aggregate_quantize(uint64_t *quanta, uint64_t nval, uint64_t incr)
{
int i, zero = DTRACE_QUANTIZE_ZEROBUCKET;
int64_t val = (int64_t)nval;
@@ -1346,19 +1389,19 @@ dtrace_aggregate_quantize(uint64_t *quanta, uint64_t nval)
if (val < 0) {
for (i = 0; i < zero; i++) {
if (val <= DTRACE_QUANTIZE_BUCKETVAL(i)) {
- quanta[i]++;
+ quanta[i] += incr;
return;
}
}
} else {
for (i = zero + 1; i < DTRACE_QUANTIZE_NBUCKETS; i++) {
if (val < DTRACE_QUANTIZE_BUCKETVAL(i)) {
- quanta[i - 1]++;
+ quanta[i - 1] += incr;
return;
}
}
- quanta[DTRACE_QUANTIZE_NBUCKETS - 1]++;
+ quanta[DTRACE_QUANTIZE_NBUCKETS - 1] += incr;
return;
}
@@ -1366,7 +1409,7 @@ dtrace_aggregate_quantize(uint64_t *quanta, uint64_t nval)
}
static void
-dtrace_aggregate_lquantize(uint64_t *lquanta, uint64_t nval)
+dtrace_aggregate_lquantize(uint64_t *lquanta, uint64_t nval, uint64_t incr)
{
uint64_t arg = *lquanta++;
int32_t base = DTRACE_LQUANTIZE_BASE(arg);
@@ -1381,25 +1424,26 @@ dtrace_aggregate_lquantize(uint64_t *lquanta, uint64_t nval)
/*
* This is an underflow.
*/
- lquanta[0]++;
+ lquanta[0] += incr;
return;
}
level = (val - base) / step;
if (level < levels) {
- lquanta[level + 1]++;
+ lquanta[level + 1] += incr;
return;
}
/*
* This is an overflow.
*/
- lquanta[levels + 1]++;
+ lquanta[levels + 1] += incr;
}
+/*ARGSUSED*/
static void
-dtrace_aggregate_avg(uint64_t *data, uint64_t nval)
+dtrace_aggregate_avg(uint64_t *data, uint64_t nval, uint64_t arg)
{
data[0]++;
data[1] += nval;
@@ -1407,14 +1451,14 @@ dtrace_aggregate_avg(uint64_t *data, uint64_t nval)
/*ARGSUSED*/
static void
-dtrace_aggregate_count(uint64_t *oval, uint64_t nval)
+dtrace_aggregate_count(uint64_t *oval, uint64_t nval, uint64_t arg)
{
*oval = *oval + 1;
}
/*ARGSUSED*/
static void
-dtrace_aggregate_sum(uint64_t *oval, uint64_t nval)
+dtrace_aggregate_sum(uint64_t *oval, uint64_t nval, uint64_t arg)
{
*oval += nval;
}
@@ -1428,7 +1472,7 @@ dtrace_aggregate_sum(uint64_t *oval, uint64_t nval)
*/
static void
dtrace_aggregate(dtrace_aggregation_t *agg, dtrace_buffer_t *dbuf,
- intptr_t offset, dtrace_buffer_t *buf, uint64_t arg)
+ intptr_t offset, dtrace_buffer_t *buf, uint64_t expr, uint64_t arg)
{
dtrace_recdesc_t *rec = &agg->dtag_action.dta_rec;
uint32_t i, ndx, size, fsize;
@@ -1443,6 +1487,18 @@ dtrace_aggregate(dtrace_aggregation_t *agg, dtrace_buffer_t *dbuf,
if (buf == NULL)
return;
+ if (!agg->dtag_hasarg) {
+ /*
+ * Currently, only quantize() and lquantize() take additional
+ * arguments, and they have the same semantics: an increment
+ * value that defaults to 1 when not present. If additional
+ * aggregating actions take arguments, the setting of the
+ * default argument value will presumably have to become more
+ * sophisticated...
+ */
+ arg = 1;
+ }
+
action = agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION;
size = rec->dtrd_offset - agg->dtag_base;
fsize = size + rec->dtrd_size;
@@ -1553,7 +1609,7 @@ dtrace_aggregate(dtrace_aggregation_t *agg, dtrace_buffer_t *dbuf,
* This is a hit: we need to apply the aggregator to
* the value at this key.
*/
- agg->dtag_aggregate((uint64_t *)(kdata + size), arg);
+ agg->dtag_aggregate((uint64_t *)(kdata + size), expr, arg);
return;
next:
continue;
@@ -1607,7 +1663,7 @@ next:
* Finally, apply the aggregator.
*/
*((uint64_t *)(key->dtak_data + size)) = agg->dtag_initial;
- agg->dtag_aggregate((uint64_t *)(key->dtak_data + size), arg);
+ agg->dtag_aggregate((uint64_t *)(key->dtak_data + size), expr, arg);
}
/*
@@ -2030,21 +2086,21 @@ dtrace_speculation_buffer(dtrace_state_t *state, processorid_t cpuid,
*/
static uint64_t
dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
- uint64_t i)
+ uint64_t ndx)
{
/*
* If we're accessing one of the uncached arguments, we'll turn this
* into a reference in the args array.
*/
if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) {
- i = v - DIF_VAR_ARG0;
+ ndx = v - DIF_VAR_ARG0;
v = DIF_VAR_ARGS;
}
switch (v) {
case DIF_VAR_ARGS:
ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS);
- if (i >= sizeof (mstate->dtms_arg) /
+ if (ndx >= sizeof (mstate->dtms_arg) /
sizeof (mstate->dtms_arg[0])) {
int aframes = mstate->dtms_probe->dtpr_aframes + 2;
dtrace_provider_t *pv;
@@ -2054,9 +2110,9 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
if (pv->dtpv_pops.dtps_getargval != NULL)
val = pv->dtpv_pops.dtps_getargval(pv->dtpv_arg,
mstate->dtms_probe->dtpr_id,
- mstate->dtms_probe->dtpr_arg, i, aframes);
+ mstate->dtms_probe->dtpr_arg, ndx, aframes);
else
- val = dtrace_getarg(i, aframes);
+ val = dtrace_getarg(ndx, aframes);
/*
* This is regrettably required to keep the compiler
@@ -2073,7 +2129,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
ASSERT(0);
}
- return (mstate->dtms_arg[i]);
+ return (mstate->dtms_arg[ndx]);
case DIF_VAR_UREGS: {
klwp_t *lwp;
@@ -2087,7 +2143,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return (0);
}
- return (dtrace_getreg(lwp->lwp_regs, i));
+ return (dtrace_getreg(lwp->lwp_regs, ndx));
}
case DIF_VAR_CURTHREAD:
@@ -2187,6 +2243,28 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
}
return (mstate->dtms_caller);
+ case DIF_VAR_UCALLER:
+ if (!dtrace_priv_proc(state))
+ return (0);
+
+ if (!(mstate->dtms_present & DTRACE_MSTATE_UCALLER)) {
+ uint64_t ustack[3];
+
+ /*
+ * dtrace_getupcstack() fills in the first uint64_t
+ * with the current PID. The second uint64_t will
+ * be the program counter at user-level. The third
+ * uint64_t will contain the caller, which is what
+ * we're after.
+ */
+ ustack[2] = NULL;
+ dtrace_getupcstack(ustack, 3);
+ mstate->dtms_ucaller = ustack[2];
+ mstate->dtms_present |= DTRACE_MSTATE_UCALLER;
+ }
+
+ return (mstate->dtms_ucaller);
+
case DIF_VAR_PROBEPROV:
ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE);
return ((uint64_t)(uintptr_t)
@@ -2678,7 +2756,7 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
* While in the abstract one would wish for
* consistent position semantics across
* substr(), index() and rindex() -- or at the
- * very least self-consitent position
+ * very least self-consistent position
* semantics for index() and rindex() -- we
* instead opt to keep with the extant Perl
* semantics, in all their broken glory. (Do
@@ -4385,15 +4463,18 @@ dtrace_action_ustack(dtrace_mstate_t *mstate, dtrace_state_t *state,
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
+ offs += j + 1;
+ }
+
+ if (offs >= strsize) {
/*
- * If we didn't have room for all of the last string, break
- * out -- the loop at the end will take clear of zeroing the
- * remainder of the string table.
+ * If we didn't have room for all of the strings, we don't
+ * abort processing -- this needn't be a fatal error -- but we
+ * still want to increment a counter (dts_stkstroverflows) to
+ * allow this condition to be warned about. (If this is from
+ * a jstack() action, it is easily tuned via jstackstrsize.)
*/
- if (offs + j >= strsize)
- break;
-
- offs += j + 1;
+ dtrace_error(&state->dts_stkstroverflows);
}
while (offs < strsize)
@@ -4479,6 +4560,22 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
int committed = 0;
caddr_t tomax;
+ /*
+ * A little subtlety with the following (seemingly innocuous)
+ * declaration of the automatic 'val': by looking at the
+ * code, you might think that it could be declared in the
+ * action processing loop, below. (That is, it's only used in
+ * the action processing loop.) However, it must be declared
+ * out of that scope because in the case of DIF expression
+ * arguments to aggregating actions, one iteration of the
+ * action loop will use the last iteration's value.
+ */
+#ifdef lint
+ uint64_t val = 0;
+#else
+ uint64_t val;
+#endif
+
mstate.dtms_present = DTRACE_MSTATE_ARGS | DTRACE_MSTATE_PROBE;
*flags &= ~CPU_DTRACE_ERROR;
@@ -4623,7 +4720,6 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
for (act = ecb->dte_action; !(*flags & CPU_DTRACE_ERROR) &&
act != NULL; act = act->dta_next) {
- uint64_t val;
size_t valoffs;
dtrace_difo_t *dp;
dtrace_recdesc_t *rec = &act->dta_rec;
@@ -4644,7 +4740,16 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
if (*flags & CPU_DTRACE_ERROR)
continue;
- dtrace_aggregate(agg, buf, offs, aggbuf, v);
+ /*
+ * Note that we always pass the expression
+ * value from the previous iteration of the
+ * action loop. This value will only be used
+ * if there is an expression argument to the
+ * aggregating action, denoted by the
+ * dtag_hasarg field.
+ */
+ dtrace_aggregate(agg, buf,
+ offs, aggbuf, v, val);
continue;
}
@@ -4777,6 +4882,28 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
case DTRACEACT_FREOPEN:
break;
+ case DTRACEACT_SYM:
+ case DTRACEACT_MOD:
+ if (!dtrace_priv_kernel(state))
+ continue;
+ break;
+
+ case DTRACEACT_USYM:
+ case DTRACEACT_UMOD:
+ case DTRACEACT_UADDR: {
+ struct pid *pid = curthread->t_procp->p_pidp;
+
+ if (!dtrace_priv_proc(state))
+ continue;
+
+ DTRACE_STORE(uint64_t, tomax,
+ valoffs, (uint64_t)pid->pid_id);
+ DTRACE_STORE(uint64_t, tomax,
+ valoffs + sizeof (uint64_t), val);
+
+ continue;
+ }
+
case DTRACEACT_EXIT: {
/*
* For the exit action, we are going to attempt
@@ -4885,9 +5012,11 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
if (probe->dtpr_id == dtrace_probeid_error) {
/*
* There's nothing we can do -- we had an
- * error on the error probe.
+ * error on the error probe. We bump an
+ * error counter to at least indicate that
+ * this condition happened.
*/
- dtrace_double_errors++;
+ dtrace_error(&state->dts_dblerrors);
continue;
}
@@ -6408,6 +6537,15 @@ dtrace_helper_provide(dof_helper_t *dhp, pid_t pid)
dtrace_helper_provide_one(dhp, sec, pid);
}
+
+ /*
+ * We may have just created probes, so we must now rematch against
+ * any retained enablings. Note that this call will acquire both
+ * cpu_lock and dtrace_lock; the fact that we are holding
+ * dtrace_meta_lock now is what defines the ordering with respect to
+ * these three locks.
+ */
+ dtrace_enabling_matchall();
}
static void
@@ -8123,6 +8261,20 @@ err:
success:
/*
+ * If the last action in the tuple has a size of zero, it's actually
+ * an expression argument for the aggregating action.
+ */
+ ASSERT(ecb->dte_action_last != NULL);
+ act = ecb->dte_action_last;
+
+ if (act->dta_kind == DTRACEACT_DIFEXPR) {
+ ASSERT(act->dta_difo != NULL);
+
+ if (act->dta_difo->dtdo_rtype.dtdt_size == 0)
+ agg->dtag_hasarg = 1;
+ }
+
+ /*
* We need to allocate an id for this aggregation.
*/
aggid = (dtrace_aggid_t)(uintptr_t)vmem_alloc(state->dts_aggid_arena, 1,
@@ -8299,6 +8451,31 @@ dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc)
break;
+ case DTRACEACT_SYM:
+ case DTRACEACT_MOD:
+ if (dp == NULL || ((size = dp->dtdo_rtype.dtdt_size) !=
+ sizeof (uint64_t)) ||
+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF))
+ return (EINVAL);
+ break;
+
+ case DTRACEACT_USYM:
+ case DTRACEACT_UMOD:
+ case DTRACEACT_UADDR:
+ if (dp == NULL ||
+ (dp->dtdo_rtype.dtdt_size != sizeof (uint64_t)) ||
+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF))
+ return (EINVAL);
+
+ /*
+ * We have a slot for the pid, plus a slot for the
+ * argument. To keep things simple (aligned with
+ * bitness-neutral sizing), we store each as a 64-bit
+ * quantity.
+ */
+ size = 2 * sizeof (uint64_t);
+ break;
+
case DTRACEACT_STOP:
case DTRACEACT_BREAKPOINT:
case DTRACEACT_PANIC:
@@ -12167,7 +12344,7 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
(void) dtrace_helper_destroygen(help->dthps_generation);
dtrace_enabling_destroy(enab);
dtrace_dof_destroy(dof);
- dtrace_error = rv;
+ dtrace_err = rv;
return (-1);
}
@@ -12232,7 +12409,7 @@ dtrace_helpers_create(proc_t *p)
DTRACE_NHELPER_ACTIONS, KM_SLEEP);
p->p_dtrace_helpers = help;
- dtrace_opens++;
+ dtrace_helpers++;
return (help);
}
@@ -12248,7 +12425,7 @@ dtrace_helpers_destroy(void)
mutex_enter(&dtrace_lock);
ASSERT(p->p_dtrace_helpers != NULL);
- ASSERT(dtrace_opens > 0);
+ ASSERT(dtrace_helpers > 0);
help = p->p_dtrace_helpers;
vstate = &help->dthps_vstate;
@@ -12322,9 +12499,7 @@ dtrace_helpers_destroy(void)
sizeof (dtrace_helper_action_t *) * DTRACE_NHELPER_ACTIONS);
kmem_free(help, sizeof (dtrace_helpers_t));
- if (--dtrace_opens == 0)
- (void) kdi_dtrace_set(KDI_DTSET_DTRACE_DEACTIVATE);
-
+ --dtrace_helpers;
mutex_exit(&dtrace_lock);
}
@@ -12339,7 +12514,7 @@ dtrace_helpers_duplicate(proc_t *from, proc_t *to)
mutex_enter(&dtrace_lock);
ASSERT(from->p_dtrace_helpers != NULL);
- ASSERT(dtrace_opens > 0);
+ ASSERT(dtrace_helpers > 0);
help = from->p_dtrace_helpers;
newhelp = dtrace_helpers_create(to);
@@ -12967,7 +13142,7 @@ dtrace_ioctl_helper(int cmd, intptr_t arg, int *rv)
return (rval);
mutex_enter(&dtrace_lock);
- dtrace_error = 0;
+ dtrace_err = 0;
/*
* dtrace_helper_slurp() takes responsibility for the dof --
@@ -13670,6 +13845,8 @@ dtrace_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv)
stat.dtst_specdrops_busy = state->dts_speculations_busy;
stat.dtst_specdrops_unavail = state->dts_speculations_unavail;
+ stat.dtst_stkstroverflows = state->dts_stkstroverflows;
+ stat.dtst_dblerrors = state->dts_dblerrors;
stat.dtst_killed =
(state->dts_activity == DTRACE_ACTIVITY_KILLED);
stat.dtst_errors = nerrs;
@@ -13756,13 +13933,9 @@ dtrace_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
mutex_enter(&dtrace_provider_lock);
mutex_enter(&dtrace_lock);
- if (dtrace_opens > 0) {
- /*
- * This is only possible because of DTrace helpers attached
- * to a process -- they count as a DTrace open. If the locking
- * weren't such a mess, we could assert that p_dtrace_helpers
- * is non-NULL for some process.
- */
+ ASSERT(dtrace_opens == 0);
+
+ if (dtrace_helpers > 0) {
mutex_exit(&dtrace_provider_lock);
mutex_exit(&dtrace_lock);
mutex_exit(&cpu_lock);
diff --git a/usr/src/uts/common/io/kstat.c b/usr/src/uts/common/io/kstat.c
index 39bbb44459..0f00483f07 100644
--- a/usr/src/uts/common/io/kstat.c
+++ b/usr/src/uts/common/io/kstat.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -240,7 +240,7 @@ read_kstat_data(int *rvalp, void *user_ksp, int flag)
/*
* Cast 64-bit ptr to 32-bit.
*/
- kn->value.string.addr.ptr32 =
+ kn->value.str.addr.ptr32 =
(caddr32_t)(uintptr_t)
KSTAT_NAMED_STR_PTR(kn);
break;
@@ -554,7 +554,7 @@ write_kstat_data(int *rvalp, void *user_ksp, int flag, cred_t *cred)
if (model == DDI_MODEL_ILP32)
KSTAT_NAMED_STR_PTR(knew) =
(char *)(uintptr_t)
- knew->value.string.addr.ptr32;
+ knew->value.str.addr.ptr32;
#endif
/*
* Nothing special for NULL
diff --git a/usr/src/uts/common/rpc/clnt_cots.c b/usr/src/uts/common/rpc/clnt_cots.c
index 8613ca3188..d0790b86f4 100644
--- a/usr/src/uts/common/rpc/clnt_cots.c
+++ b/usr/src/uts/common/rpc/clnt_cots.c
@@ -1534,7 +1534,7 @@ conn_kstat_update(kstat_t *ksp, int rw)
cm_ksp_data->x_state.value.ui32 = cm_entry->x_state_flags;
if (cm_entry->x_server.buf) {
- fbuf = cm_ksp_data->x_server.value.string.addr.ptr;
+ fbuf = cm_ksp_data->x_server.value.str.addr.ptr;
if (cm_entry->x_family == AF_INET &&
cm_entry->x_server.len ==
sizeof (struct sockaddr_in)) {
@@ -2360,9 +2360,9 @@ connmgr_close(struct cm_xprt *cm_entry)
* server address in the update function
*/
if (((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
- x_server.value.string.addr.ptr != NULL)
+ x_server.value.str.addr.ptr != NULL)
kmem_free(((struct cm_kstat_xprt *)(cm_entry->x_ksp->
- ks_data))->x_server.value.string.addr.ptr,
+ ks_data))->x_server.value.str.addr.ptr,
INET6_ADDRSTRLEN);
kmem_free(cm_entry->x_ksp->ks_data,
cm_entry->x_ksp->ks_data_size);
@@ -2582,7 +2582,7 @@ connmgr_connect(
bcopy(&cm_kstat_template, cm_entry->x_ksp->ks_data,
cm_entry->x_ksp->ks_data_size);
((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
- x_server.value.string.addr.ptr =
+ x_server.value.str.addr.ptr =
kmem_alloc(INET6_ADDRSTRLEN, KM_SLEEP);
cm_entry->x_ksp->ks_update = conn_kstat_update;
diff --git a/usr/src/uts/common/sys/dtrace.h b/usr/src/uts/common/sys/dtrace.h
index 6b6ca65fce..1076d065e3 100644
--- a/usr/src/uts/common/sys/dtrace.h
+++ b/usr/src/uts/common/sys/dtrace.h
@@ -230,6 +230,7 @@ typedef enum dtrace_probespec {
#define DIF_VAR_ZONENAME 0x0119 /* zone name associated with process */
#define DIF_VAR_WALLTIMESTAMP 0x011a /* wall-clock timestamp */
#define DIF_VAR_USTACKDEPTH 0x011b /* user-land stack depth */
+#define DIF_VAR_UCALLER 0x011c /* user-level caller */
#define DIF_SUBR_RAND 0
#define DIF_SUBR_MUTEX_OWNED 1
@@ -380,6 +381,9 @@ typedef struct dtrace_difv {
#define DTRACEACT_PROC 0x0100
#define DTRACEACT_USTACK (DTRACEACT_PROC + 1)
#define DTRACEACT_JSTACK (DTRACEACT_PROC + 2)
+#define DTRACEACT_USYM (DTRACEACT_PROC + 3)
+#define DTRACEACT_UMOD (DTRACEACT_PROC + 4)
+#define DTRACEACT_UADDR (DTRACEACT_PROC + 5)
#define DTRACEACT_PROC_DESTRUCTIVE 0x0200
#define DTRACEACT_STOP (DTRACEACT_PROC_DESTRUCTIVE + 1)
@@ -391,6 +395,8 @@ typedef struct dtrace_difv {
#define DTRACEACT_KERNEL 0x0400
#define DTRACEACT_STACK (DTRACEACT_KERNEL + 1)
+#define DTRACEACT_SYM (DTRACEACT_KERNEL + 2)
+#define DTRACEACT_MOD (DTRACEACT_KERNEL + 3)
#define DTRACEACT_KERNEL_DESTRUCTIVE 0x0500
#define DTRACEACT_BREAKPOINT (DTRACEACT_KERNEL_DESTRUCTIVE + 1)
@@ -998,6 +1004,8 @@ typedef struct dtrace_status {
uint64_t dtst_specdrops_unavail; /* spec drops due to unavail */
uint64_t dtst_errors; /* total errors */
uint64_t dtst_filled; /* number of filled bufs */
+ uint64_t dtst_stkstroverflows; /* stack string tab overflows */
+ uint64_t dtst_dblerrors; /* errors in ERROR probes */
char dtst_killed; /* non-zero if killed */
char dtst_exiting; /* non-zero if exit() called */
char dtst_pad[6]; /* pad out to 64-bit align */
diff --git a/usr/src/uts/common/sys/dtrace_impl.h b/usr/src/uts/common/sys/dtrace_impl.h
index 974fb5369a..6777e0f25d 100644
--- a/usr/src/uts/common/sys/dtrace_impl.h
+++ b/usr/src/uts/common/sys/dtrace_impl.h
@@ -238,8 +238,9 @@ typedef struct dtrace_aggregation {
dtrace_ecb_t *dtag_ecb; /* corresponding ECB */
dtrace_action_t *dtag_first; /* first action in tuple */
uint32_t dtag_base; /* base of aggregation */
+ uint8_t dtag_hasarg; /* boolean: has argument */
uint64_t dtag_initial; /* initial value */
- void (*dtag_aggregate)(uint64_t *, uint64_t);
+ void (*dtag_aggregate)(uint64_t *, uint64_t, uint64_t);
} dtrace_aggregation_t;
/*
@@ -890,6 +891,7 @@ typedef struct dtrace_vstate {
#define DTRACE_MSTATE_FLTOFFS 0x00000080
#define DTRACE_MSTATE_WALLTIMESTAMP 0x00000100
#define DTRACE_MSTATE_USTACKDEPTH 0x00000200
+#define DTRACE_MSTATE_UCALLER 0x00000400
typedef struct dtrace_mstate {
uintptr_t dtms_scratch_base; /* base of scratch space */
@@ -904,6 +906,7 @@ typedef struct dtrace_mstate {
int dtms_ustackdepth; /* cached ustackdepth */
struct dtrace_probe *dtms_probe; /* current probe */
uintptr_t dtms_caller; /* cached caller */
+ uint64_t dtms_ucaller; /* cached user-level caller */
int dtms_ipl; /* cached interrupt pri lev */
int dtms_fltoffs; /* faulting DIFO offset */
uintptr_t dtms_strtok; /* saved strtok() pointer */
@@ -1088,9 +1091,11 @@ struct dtrace_state {
int dts_naggregations; /* number of aggregations */
dtrace_aggregation_t **dts_aggregations; /* aggregation array */
vmem_t *dts_aggid_arena; /* arena for aggregation IDs */
+ uint64_t dts_errors; /* total number of errors */
uint32_t dts_speculations_busy; /* number of spec. busy */
uint32_t dts_speculations_unavail; /* number of spec unavail */
- uint64_t dts_errors; /* total number of errors */
+ uint32_t dts_stkstroverflows; /* stack string tab overflows */
+ uint32_t dts_dblerrors; /* errors in ERROR probes */
uint32_t dts_reserve; /* space reserved for END */
hrtime_t dts_laststatus; /* time of last status */
cyclic_id_t dts_cleaner; /* cleaning cyclic */
diff --git a/usr/src/uts/common/sys/kstat.h b/usr/src/uts/common/sys/kstat.h
index f0950fa984..c311fd500b 100644
--- a/usr/src/uts/common/sys/kstat.h
+++ b/usr/src/uts/common/sys/kstat.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -457,7 +457,7 @@ typedef struct kstat_named {
char __pad[8]; /* 64-bit padding */
} addr;
uint32_t len; /* # bytes for strlen + '\0' */
- } string;
+ } str;
/*
* The int64_t and uint64_t types are not valid for a maximally conformant
* 32-bit compilation environment (cc -Xc) using compilers prior to the
@@ -533,13 +533,13 @@ typedef struct kstat_named {
/*
* Retrieve the pointer of the string contained in the given named kstat.
*/
-#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.string.addr.ptr)
+#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.str.addr.ptr)
/*
* Retrieve the length of the buffer required to store the string in the given
* named kstat.
*/
-#define KSTAT_NAMED_STR_BUFLEN(knptr) ((knptr)->value.string.len)
+#define KSTAT_NAMED_STR_BUFLEN(knptr) ((knptr)->value.str.len)
/*
* Interrupt statistics.
diff --git a/usr/src/uts/intel/dtrace/fbt.c b/usr/src/uts/intel/dtrace/fbt.c
index af00a0cdf4..050e8fbca1 100644
--- a/usr/src/uts/intel/dtrace/fbt.c
+++ b/usr/src/uts/intel/dtrace/fbt.c
@@ -231,9 +231,11 @@ fbt_provide_module(void *arg, struct modctl *ctl)
continue;
}
- if (strstr(name, "kdi_") == name) {
+ if (strstr(name, "kdi_") == name ||
+ strstr(name, "_kdi_") != NULL) {
/*
- * Anything beginning with "kdi_" is a part of the
+ * Any function name beginning with "kdi_" or
+ * containing the string "_kdi_" is a part of the
* kernel debugger interface and may be called in
* arbitrary context -- including probe context.
*/
diff --git a/usr/src/uts/sparc/dtrace/dtrace_isa.c b/usr/src/uts/sparc/dtrace/dtrace_isa.c
index 4c62ab0ec0..d5c332b51e 100644
--- a/usr/src/uts/sparc/dtrace/dtrace_isa.c
+++ b/usr/src/uts/sparc/dtrace/dtrace_isa.c
@@ -40,6 +40,7 @@
#define DTRACE_FMT3OP3 0x80000000
#define DTRACE_FMT3RS1_SHIFT 14
#define DTRACE_FMT3RD_SHIFT 25
+#define DTRACE_DISP22_SHIFT 10
#define DTRACE_RMASK 0x1f
#define DTRACE_REG_L0 16
#define DTRACE_REG_O7 15
@@ -54,6 +55,9 @@
#define DTRACE_CALL 0x40000000
#define DTRACE_JMPL_MASK 0x81f10000
#define DTRACE_JMPL 0x81c00000
+#define DTRACE_BA_MASK 0xdfc00000
+#define DTRACE_BA 0x10800000
+#define DTRACE_BA_MAX 10
extern int dtrace_getupcstack_top(uint64_t *, int, uintptr_t *);
extern int dtrace_getustackdepth_top(uintptr_t *);
@@ -134,11 +138,22 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *pc)
* has a whopping 455 straight instructions that manipulate
* only %g's and %o's.)
*/
- int delay = 0;
+ int delay = 0, branches = 0, taken = 0;
if (depth < pcstack_limit)
pcstack[depth++] = (pc_t)pc;
+ /*
+ * Our heuristic is exactly that -- a heuristic -- and there
+ * exists a possibility that we could be either be vectored
+ * off into the weeds (by following a bogus branch) or could
+ * wander off the end of the function and off the end of a
+ * text mapping (by not following a conditional branch at the
+ * end of the function that is effectively always taken). So
+ * as a precautionary measure, we set the NOFAULT flag.
+ */
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
+
for (;;) {
i = pc[j++];
@@ -202,6 +217,38 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *pc)
goto leaf;
/*
+ * If this is a ba (annulled or not), then we
+ * need to actually follow the branch. No, we
+ * don't look at the delay slot -- hopefully
+ * anything that can be gleaned from the delay
+ * slot can also be gleaned from the branch
+ * target. To prevent ourselves from iterating
+ * infinitely, we clamp the number of branches
+ * that we'll follow, and we refuse to follow
+ * the same branch twice consecutively. In
+ * both cases, we abort by deciding that we're
+ * looking at a leaf. While in theory this
+ * could be wrong (we could be in the middle of
+ * a loop in a non-leaf that ends with a ba and
+ * only manipulates outputs and globals in the
+ * body of the loop -- therefore leading us to
+ * the wrong conclusion), this doesn't seem to
+ * crop up in practice. (Or rather, this
+ * condition could not be deliberately induced,
+ * despite concerted effort.)
+ */
+ if ((i & DTRACE_BA_MASK) == DTRACE_BA) {
+ if (++branches == DTRACE_BA_MAX ||
+ taken == j)
+ goto nonleaf;
+
+ taken = j;
+ j += ((int)(i << DTRACE_DISP22_SHIFT) >>
+ DTRACE_DISP22_SHIFT) - 1;
+ continue;
+ }
+
+ /*
* Finally, if it's a save, it should be
* treated as a leaf; if it's a restore it
* should not be treated as a leaf.
@@ -225,7 +272,7 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *pc)
nonleaf:
aframes++;
leaf:
- ;
+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
}
if ((on_intr = CPU_ON_INTR(CPU)) != 0)
diff --git a/usr/src/uts/sparc/dtrace/fbt.c b/usr/src/uts/sparc/dtrace/fbt.c
index af8487ce57..d01f6cfb74 100644
--- a/usr/src/uts/sparc/dtrace/fbt.c
+++ b/usr/src/uts/sparc/dtrace/fbt.c
@@ -1121,9 +1121,11 @@ forreal:
continue;
}
- if (strstr(name, "kdi_") == name) {
+ if (strstr(name, "kdi_") == name ||
+ strstr(name, "_kdi_") != NULL) {
/*
- * Anything beginning with "kdi_" is a part of the
+ * Any function name beginning with "kdi_" or
+ * containing the string "_kdi_" is a part of the
* kernel debugger interface and may be called in
* arbitrary context -- including probe context.
*/
diff --git a/usr/src/uts/sparc/ml/fd_asm.s b/usr/src/uts/sparc/ml/fd_asm.s
index 21655206b8..400c97bf74 100644
--- a/usr/src/uts/sparc/ml/fd_asm.s
+++ b/usr/src/uts/sparc/ml/fd_asm.s
@@ -20,7 +20,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1989-1991, by Sun Microsystems, Inc.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#ident "%Z%%M% %I% %E% SMI"
@@ -68,8 +69,6 @@ fd_intr(caddr_t arg)
#define TRIGGER 0x33
ENTRY(fd_intr) ! fd standard interrupt handler
save %sp, -SA(MINFRAME), %sp
- clr %l1 ! came from standard interrupt handler
- ENTRY_NP(fd_fastintr) ! fd fast trap entry point
!
! Traverse the list of controllers until we find the first
! controller expecting an interrupt. Unfortunately, the
@@ -323,9 +322,6 @@ fd_intr(caddr_t arg)
sethi %hi(asm_mutex_spin_exit), %l7
jmpl %l7 + %lo(asm_mutex_spin_exit), %l7
add Fdc, FD_HILOCK, %l6
- tst %l1 ! %l1 != 0 fast trap handler
- bnz 1f
- nop
!
! schedule the soft interrupt if needed
@@ -346,18 +342,9 @@ fd_intr(caddr_t arg)
call ddi_trigger_softintr
ldn [Fdc + FD_SOFTID], %o0
-
- ! standard interrupt epilogue
.end: mov 1, %i0
ret
restore
-1:
- ! fast trap epilogue
- mov %l0, %psr ! restore psr - and user's ccodes
- nop
- nop
- jmp %l1 ! return from interrupt
- rett %l2
SET_SIZE(fd_intr)
.panic:
diff --git a/usr/src/uts/sun/io/fd.c b/usr/src/uts/sun/io/fd.c
index 78e9d371fa..2a5b60b273 100644
--- a/usr/src/uts/sun/io/fd.c
+++ b/usr/src/uts/sun/io/fd.c
@@ -241,7 +241,6 @@ static void release_sb_dma(struct fdctlr *fdc);
* External functions
*/
extern uint_t fd_intr(caddr_t); /* defined in fd_asm.s */
-extern uint_t fd_fastintr(void); /* defined in fd_asm.s */
extern void set_auxioreg();
extern void call_debug();