diff options
Diffstat (limited to 'cddl/contrib/opensolaris/lib')
37 files changed, 1617 insertions, 223 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c index b0f2b4a..6b571fa 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c @@ -25,7 +25,7 @@ */ /* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ @@ -1301,6 +1301,231 @@ dtrace_aggregate_walk(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg) } static int +dt_aggregate_total(dtrace_hdl_t *dtp, boolean_t clear) +{ + dt_ahashent_t *h; + dtrace_aggdata_t **total; + dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id; + dt_aggregate_t *agp = &dtp->dt_aggregate; + dt_ahash_t *hash = &agp->dtat_hash; + uint32_t tflags; + + tflags = DTRACE_A_TOTAL | DTRACE_A_HASNEGATIVES | DTRACE_A_HASPOSITIVES; + + /* + * If we need to deliver per-aggregation totals, we're going to take + * three passes over the aggregate: one to clear everything out and + * determine our maximum aggregation ID, one to actually total + * everything up, and a final pass to assign the totals to the + * individual elements. + */ + for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { + dtrace_aggdata_t *aggdata = &h->dtahe_data; + + if ((id = dt_aggregate_aggvarid(h)) > max) + max = id; + + aggdata->dtada_total = 0; + aggdata->dtada_flags &= ~tflags; + } + + if (clear || max == DTRACE_AGGVARIDNONE) + return (0); + + total = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *)); + + if (total == NULL) + return (-1); + + for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { + dtrace_aggdata_t *aggdata = &h->dtahe_data; + dtrace_aggdesc_t *agg = aggdata->dtada_desc; + dtrace_recdesc_t *rec; + caddr_t data; + int64_t val, *addr; + + rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1]; + data = aggdata->dtada_data; + addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset); + + switch (rec->dtrd_action) { + case DTRACEAGG_STDDEV: + val = dt_stddev((uint64_t *)addr, 1); + break; + + case DTRACEAGG_SUM: + case DTRACEAGG_COUNT: + val = *addr; + break; + + case DTRACEAGG_AVG: + val = addr[0] ? (addr[1] / addr[0]) : 0; + break; + + default: + continue; + } + + if (total[agg->dtagd_varid] == NULL) { + total[agg->dtagd_varid] = aggdata; + aggdata->dtada_flags |= DTRACE_A_TOTAL; + } else { + aggdata = total[agg->dtagd_varid]; + } + + if (val > 0) + aggdata->dtada_flags |= DTRACE_A_HASPOSITIVES; + + if (val < 0) { + aggdata->dtada_flags |= DTRACE_A_HASNEGATIVES; + val = -val; + } + + if (dtp->dt_options[DTRACEOPT_AGGZOOM] != DTRACEOPT_UNSET) { + val = (int64_t)((long double)val * + (1 / DTRACE_AGGZOOM_MAX)); + + if (val > aggdata->dtada_total) + aggdata->dtada_total = val; + } else { + aggdata->dtada_total += val; + } + } + + /* + * And now one final pass to set everyone's total. + */ + for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { + dtrace_aggdata_t *aggdata = &h->dtahe_data, *t; + dtrace_aggdesc_t *agg = aggdata->dtada_desc; + + if ((t = total[agg->dtagd_varid]) == NULL || aggdata == t) + continue; + + aggdata->dtada_total = t->dtada_total; + aggdata->dtada_flags |= (t->dtada_flags & tflags); + } + + dt_free(dtp, total); + + return (0); +} + +static int +dt_aggregate_minmaxbin(dtrace_hdl_t *dtp, boolean_t clear) +{ + dt_ahashent_t *h; + dtrace_aggdata_t **minmax; + dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id; + dt_aggregate_t *agp = &dtp->dt_aggregate; + dt_ahash_t *hash = &agp->dtat_hash; + + for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { + dtrace_aggdata_t *aggdata = &h->dtahe_data; + + if ((id = dt_aggregate_aggvarid(h)) > max) + max = id; + + aggdata->dtada_minbin = 0; + aggdata->dtada_maxbin = 0; + aggdata->dtada_flags &= ~DTRACE_A_MINMAXBIN; + } + + if (clear || max == DTRACE_AGGVARIDNONE) + return (0); + + minmax = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *)); + + if (minmax == NULL) + return (-1); + + for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { + dtrace_aggdata_t *aggdata = &h->dtahe_data; + dtrace_aggdesc_t *agg = aggdata->dtada_desc; + dtrace_recdesc_t *rec; + caddr_t data; + int64_t *addr; + int minbin = -1, maxbin = -1, i; + int start = 0, size; + + rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1]; + size = rec->dtrd_size / sizeof (int64_t); + data = aggdata->dtada_data; + addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset); + + switch (rec->dtrd_action) { + case DTRACEAGG_LQUANTIZE: + /* + * For lquantize(), we always display the entire range + * of the aggregation when aggpack is set. + */ + start = 1; + minbin = start; + maxbin = size - 1 - start; + break; + + case DTRACEAGG_QUANTIZE: + for (i = start; i < size; i++) { + if (!addr[i]) + continue; + + if (minbin == -1) + minbin = i - start; + + maxbin = i - start; + } + + if (minbin == -1) { + /* + * If we have no data (e.g., due to a clear() + * or negative increments), we'll use the + * zero bucket as both our min and max. + */ + minbin = maxbin = DTRACE_QUANTIZE_ZEROBUCKET; + } + + break; + + default: + continue; + } + + if (minmax[agg->dtagd_varid] == NULL) { + minmax[agg->dtagd_varid] = aggdata; + aggdata->dtada_flags |= DTRACE_A_MINMAXBIN; + aggdata->dtada_minbin = minbin; + aggdata->dtada_maxbin = maxbin; + continue; + } + + if (minbin < minmax[agg->dtagd_varid]->dtada_minbin) + minmax[agg->dtagd_varid]->dtada_minbin = minbin; + + if (maxbin > minmax[agg->dtagd_varid]->dtada_maxbin) + minmax[agg->dtagd_varid]->dtada_maxbin = maxbin; + } + + /* + * And now one final pass to set everyone's minbin and maxbin. + */ + for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { + dtrace_aggdata_t *aggdata = &h->dtahe_data, *mm; + dtrace_aggdesc_t *agg = aggdata->dtada_desc; + + if ((mm = minmax[agg->dtagd_varid]) == NULL || aggdata == mm) + continue; + + aggdata->dtada_minbin = mm->dtada_minbin; + aggdata->dtada_maxbin = mm->dtada_maxbin; + aggdata->dtada_flags |= DTRACE_A_MINMAXBIN; + } + + dt_free(dtp, minmax); + + return (0); +} + +static int dt_aggregate_walk_sorted(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg, int (*sfunc)(const void *, const void *)) @@ -1309,6 +1534,23 @@ dt_aggregate_walk_sorted(dtrace_hdl_t *dtp, dt_ahashent_t *h, **sorted; dt_ahash_t *hash = &agp->dtat_hash; size_t i, nentries = 0; + int rval = -1; + + agp->dtat_flags &= ~(DTRACE_A_TOTAL | DTRACE_A_MINMAXBIN); + + if (dtp->dt_options[DTRACEOPT_AGGHIST] != DTRACEOPT_UNSET) { + agp->dtat_flags |= DTRACE_A_TOTAL; + + if (dt_aggregate_total(dtp, B_FALSE) != 0) + return (-1); + } + + if (dtp->dt_options[DTRACEOPT_AGGPACK] != DTRACEOPT_UNSET) { + agp->dtat_flags |= DTRACE_A_MINMAXBIN; + + if (dt_aggregate_minmaxbin(dtp, B_FALSE) != 0) + return (-1); + } for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) nentries++; @@ -1316,7 +1558,7 @@ dt_aggregate_walk_sorted(dtrace_hdl_t *dtp, sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *)); if (sorted == NULL) - return (-1); + goto out; for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall) sorted[i++] = h; @@ -1340,14 +1582,20 @@ dt_aggregate_walk_sorted(dtrace_hdl_t *dtp, for (i = 0; i < nentries; i++) { h = sorted[i]; - if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) { - dt_free(dtp, sorted); - return (-1); - } + if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) + goto out; } + rval = 0; +out: + if (agp->dtat_flags & DTRACE_A_TOTAL) + (void) dt_aggregate_total(dtp, B_TRUE); + + if (agp->dtat_flags & DTRACE_A_MINMAXBIN) + (void) dt_aggregate_minmaxbin(dtp, B_TRUE); + dt_free(dtp, sorted); - return (0); + return (rval); } int @@ -1870,6 +2118,8 @@ dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp, { dt_print_aggdata_t pd; + bzero(&pd, sizeof (pd)); + pd.dtpa_dtp = dtp; pd.dtpa_fp = fp; pd.dtpa_allunprint = 1; diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c index 457b8fd..f937261 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c @@ -23,8 +23,10 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013 Joyent, Inc. All rights reserved. + */ #include <sys/types.h> #include <strings.h> @@ -125,7 +127,7 @@ dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data) dvp->dtdv_flags |= DIFV_F_MOD; bzero(&dn, sizeof (dn)); - dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type); + dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type, B_FALSE); dt_node_diftype(pcb->pcb_hdl, &dn, &dvp->dtdv_type); idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c index 64b98c4..35b8f02 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent Inc. All rights reserved. + * Copyright (c) 2013, Joyent Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ @@ -663,6 +663,8 @@ dt_action_printflike(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp, static void dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) { + int ctflib; + dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE); const char *act = istrace ? "trace" : "print"; @@ -694,7 +696,10 @@ dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) * like arrays and function pointers that can't be resolved by * ctf_type_lookup(). This is later processed by dtrace_dof_create() * and turned into a reference into the string table so that we can - * get the type information when we process the data after the fact. + * get the type information when we process the data after the fact. In + * the case where we are referring to userland CTF data, we also need to + * to identify which ctf container in question we care about and encode + * that within the name. */ if (dnp->dn_ident->di_id == DT_ACT_PRINT) { dt_node_t *dret; @@ -705,11 +710,27 @@ dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp); n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1; + if (dmp->dm_pid != 0) { + ctflib = dt_module_getlibid(dtp, dmp, dret->dn_ctfp); + assert(ctflib >= 0); + n = snprintf(NULL, 0, "%s`%d`%ld", dmp->dm_name, + ctflib, dret->dn_type) + 1; + } else { + n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, + dret->dn_type) + 1; + } sdp->dtsd_strdata = dt_alloc(dtp, n); if (sdp->dtsd_strdata == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); (void) snprintf(sdp->dtsd_strdata, n, "%s`%ld", dmp->dm_name, dret->dn_type); + if (dmp->dm_pid != 0) { + (void) snprintf(sdp->dtsd_strdata, n, "%s`%d`%ld", + dmp->dm_name, ctflib, dret->dn_type); + } else { + (void) snprintf(sdp->dtsd_strdata, n, "%s`%ld", + dmp->dm_name, dret->dn_type); + } } ap->dtad_difo = dt_as(yypcb); @@ -2268,12 +2289,15 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path) dt_dprintf("skipping library %s, already processed " "library with the same name: %s", dp->d_name, dld->dtld_library); + (void) fclose(fp); continue; } dtp->dt_filetag = fname; - if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) + if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) { + (void) fclose(fp); return (-1); /* preserve dt_errno */ + } rv = dt_compile(dtp, DT_CTX_DPROG, DTRACE_PROBESPEC_NAME, NULL, @@ -2281,8 +2305,10 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path) if (rv != NULL && dtp->dt_errno && (dtp->dt_errno != EDT_COMPILER || - dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) + dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) { + (void) fclose(fp); return (-1); /* preserve dt_errno */ + } if (dtp->dt_errno) dt_dprintf("error parsing library %s: %s\n", diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c index 8d9e494..ae1ed00 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c @@ -24,7 +24,7 @@ */ /* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ @@ -59,6 +59,25 @@ dt_fabsl(long double x) return (x); } +static int +dt_ndigits(long long val) +{ + int rval = 1; + long long cmp = 10; + + if (val < 0) { + val = val == INT64_MIN ? INT64_MAX : -val; + rval++; + } + + while (val > cmp && cmp > 0) { + rval++; + cmp *= 10; + } + + return (rval < 4 ? 4 : rval); +} + /* * 128-bit arithmetic functions needed to support the stddev() aggregating * action. @@ -487,7 +506,125 @@ dt_nullrec() return (DTRACE_CONSUME_NEXT); } -int +static void +dt_quantize_total(dtrace_hdl_t *dtp, int64_t datum, long double *total) +{ + long double val = dt_fabsl((long double)datum); + + if (dtp->dt_options[DTRACEOPT_AGGZOOM] == DTRACEOPT_UNSET) { + *total += val; + return; + } + + /* + * If we're zooming in on an aggregation, we want the height of the + * highest value to be approximately 95% of total bar height -- so we + * adjust up by the reciprocal of DTRACE_AGGZOOM_MAX when comparing to + * our highest value. + */ + val *= 1 / DTRACE_AGGZOOM_MAX; + + if (*total < val) + *total = val; +} + +static int +dt_print_quanthdr(dtrace_hdl_t *dtp, FILE *fp, int width) +{ + return (dt_printf(dtp, fp, "\n%*s %41s %-9s\n", + width ? width : 16, width ? "key" : "value", + "------------- Distribution -------------", "count")); +} + +static int +dt_print_quanthdr_packed(dtrace_hdl_t *dtp, FILE *fp, int width, + const dtrace_aggdata_t *aggdata, dtrace_actkind_t action) +{ + int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin; + int minwidth, maxwidth, i; + + assert(action == DTRACEAGG_QUANTIZE || action == DTRACEAGG_LQUANTIZE); + + if (action == DTRACEAGG_QUANTIZE) { + if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET) + min--; + + if (max < DTRACE_QUANTIZE_NBUCKETS - 1) + max++; + + minwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(min)); + maxwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(max)); + } else { + maxwidth = 8; + minwidth = maxwidth - 1; + max++; + } + + if (dt_printf(dtp, fp, "\n%*s %*s .", + width, width > 0 ? "key" : "", minwidth, "min") < 0) + return (-1); + + for (i = min; i <= max; i++) { + if (dt_printf(dtp, fp, "-") < 0) + return (-1); + } + + return (dt_printf(dtp, fp, ". %*s | count\n", -maxwidth, "max")); +} + +/* + * We use a subset of the Unicode Block Elements (U+2588 through U+258F, + * inclusive) to represent aggregations via UTF-8 -- which are expressed via + * 3-byte UTF-8 sequences. + */ +#define DTRACE_AGGUTF8_FULL 0x2588 +#define DTRACE_AGGUTF8_BASE 0x258f +#define DTRACE_AGGUTF8_LEVELS 8 + +#define DTRACE_AGGUTF8_BYTE0(val) (0xe0 | ((val) >> 12)) +#define DTRACE_AGGUTF8_BYTE1(val) (0x80 | (((val) >> 6) & 0x3f)) +#define DTRACE_AGGUTF8_BYTE2(val) (0x80 | ((val) & 0x3f)) + +static int +dt_print_quantline_utf8(dtrace_hdl_t *dtp, FILE *fp, int64_t val, + uint64_t normal, long double total) +{ + uint_t len = 40, i, whole, partial; + long double f = (dt_fabsl((long double)val) * len) / total; + const char *spaces = " "; + + whole = (uint_t)f; + partial = (uint_t)((f - (long double)(uint_t)f) * + (long double)DTRACE_AGGUTF8_LEVELS); + + if (dt_printf(dtp, fp, "|") < 0) + return (-1); + + for (i = 0; i < whole; i++) { + if (dt_printf(dtp, fp, "%c%c%c", + DTRACE_AGGUTF8_BYTE0(DTRACE_AGGUTF8_FULL), + DTRACE_AGGUTF8_BYTE1(DTRACE_AGGUTF8_FULL), + DTRACE_AGGUTF8_BYTE2(DTRACE_AGGUTF8_FULL)) < 0) + return (-1); + } + + if (partial != 0) { + partial = DTRACE_AGGUTF8_BASE - (partial - 1); + + if (dt_printf(dtp, fp, "%c%c%c", + DTRACE_AGGUTF8_BYTE0(partial), + DTRACE_AGGUTF8_BYTE1(partial), + DTRACE_AGGUTF8_BYTE2(partial)) < 0) + return (-1); + + i++; + } + + return (dt_printf(dtp, fp, "%s %-9lld\n", spaces + i, + (long long)val / normal)); +} + +static int dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, uint64_t normal, long double total, char positives, char negatives) { @@ -505,6 +642,11 @@ dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, if (!negatives) { if (positives) { + if (dtp->dt_encoding == DT_ENCODING_UTF8) { + return (dt_print_quantline_utf8(dtp, fp, val, + normal, total)); + } + f = (dt_fabsl((long double)val) * len) / total; depth = (uint_t)(f + 0.5); } else { @@ -547,6 +689,73 @@ dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, } } +/* + * As with UTF-8 printing of aggregations, we use a subset of the Unicode + * Block Elements (U+2581 through U+2588, inclusive) to represent our packed + * aggregation. + */ +#define DTRACE_AGGPACK_BASE 0x2581 +#define DTRACE_AGGPACK_LEVELS 8 + +static int +dt_print_packed(dtrace_hdl_t *dtp, FILE *fp, + long double datum, long double total) +{ + static boolean_t utf8_checked = B_FALSE; + static boolean_t utf8; + char *ascii = "__xxxxXX"; + char *neg = "vvvvVV"; + unsigned int len; + long double val; + + if (!utf8_checked) { + char *term; + + /* + * We want to determine if we can reasonably emit UTF-8 for our + * packed aggregation. To do this, we will check for terminals + * that are known to be primitive to emit UTF-8 on these. + */ + utf8_checked = B_TRUE; + + if (dtp->dt_encoding == DT_ENCODING_ASCII) { + utf8 = B_FALSE; + } else if (dtp->dt_encoding == DT_ENCODING_UTF8) { + utf8 = B_TRUE; + } else if ((term = getenv("TERM")) != NULL && + (strcmp(term, "sun") == 0 || + strcmp(term, "sun-color") == 0) || + strcmp(term, "dumb") == 0) { + utf8 = B_FALSE; + } else { + utf8 = B_TRUE; + } + } + + if (datum == 0) + return (dt_printf(dtp, fp, " ")); + + if (datum < 0) { + len = strlen(neg); + val = dt_fabsl(datum * (len - 1)) / total; + return (dt_printf(dtp, fp, "%c", neg[(uint_t)(val + 0.5)])); + } + + if (utf8) { + int block = DTRACE_AGGPACK_BASE + (unsigned int)(((datum * + (DTRACE_AGGPACK_LEVELS - 1)) / total) + 0.5); + + return (dt_printf(dtp, fp, "%c%c%c", + DTRACE_AGGUTF8_BYTE0(block), + DTRACE_AGGUTF8_BYTE1(block), + DTRACE_AGGUTF8_BYTE2(block))); + } + + len = strlen(ascii); + val = (datum * (len - 1)) / total; + return (dt_printf(dtp, fp, "%c", ascii[(uint_t)(val + 0.5)])); +} + int dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, size_t size, uint64_t normal) @@ -564,9 +773,9 @@ dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 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. + * There isn't any data. This is possible if the aggregation + * has been clear()'d or if negative increment values have been + * used. Regardless, we'll print the buckets around 0. */ first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1; last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1; @@ -584,11 +793,10 @@ dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, for (i = first_bin; i <= last_bin; i++) { positives |= (data[i] > 0); negatives |= (data[i] < 0); - total += dt_fabsl((long double)data[i]); + dt_quantize_total(dtp, data[i], &total); } - if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", - "------------- Distribution -------------", "count") < 0) + if (dt_print_quanthdr(dtp, fp, 0) < 0) return (-1); for (i = first_bin; i <= last_bin; i++) { @@ -605,6 +813,48 @@ dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, } int +dt_print_quantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr, + size_t size, const dtrace_aggdata_t *aggdata) +{ + const int64_t *data = addr; + long double total = 0, count = 0; + int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin, i; + int64_t minval, maxval; + + if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) + return (dt_set_errno(dtp, EDT_DMISMATCH)); + + if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET) + min--; + + if (max < DTRACE_QUANTIZE_NBUCKETS - 1) + max++; + + minval = DTRACE_QUANTIZE_BUCKETVAL(min); + maxval = DTRACE_QUANTIZE_BUCKETVAL(max); + + if (dt_printf(dtp, fp, " %*lld :", dt_ndigits(minval), + (long long)minval) < 0) + return (-1); + + for (i = min; i <= max; i++) { + dt_quantize_total(dtp, data[i], &total); + count += data[i]; + } + + for (i = min; i <= max; i++) { + if (dt_print_packed(dtp, fp, data[i], total) < 0) + return (-1); + } + + if (dt_printf(dtp, fp, ": %*lld | %lld\n", + -dt_ndigits(maxval), (long long)maxval, (long long)count) < 0) + return (-1); + + return (0); +} + +int dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, size_t size, uint64_t normal) { @@ -651,7 +901,7 @@ dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, for (i = first_bin; i <= last_bin; i++) { positives |= (data[i] > 0); negatives |= (data[i] < 0); - total += dt_fabsl((long double)data[i]); + dt_quantize_total(dtp, data[i], &total); } if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", @@ -663,8 +913,7 @@ dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, int err; if (i == 0) { - (void) snprintf(c, sizeof (c), "< %d", - base / (uint32_t)normal); + (void) snprintf(c, sizeof (c), "< %d", base); err = dt_printf(dtp, fp, "%16s ", c); } else if (i == levels + 1) { (void) snprintf(c, sizeof (c), ">= %d", @@ -683,6 +932,59 @@ dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, return (0); } +/*ARGSUSED*/ +int +dt_print_lquantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr, + size_t size, const dtrace_aggdata_t *aggdata) +{ + const int64_t *data = addr; + long double total = 0, count = 0; + int min, max, base, err; + uint64_t arg; + uint16_t step, levels; + char c[32]; + unsigned int i; + + if (size < sizeof (uint64_t)) + return (dt_set_errno(dtp, EDT_DMISMATCH)); + + arg = *data++; + size -= sizeof (uint64_t); + + base = DTRACE_LQUANTIZE_BASE(arg); + step = DTRACE_LQUANTIZE_STEP(arg); + levels = DTRACE_LQUANTIZE_LEVELS(arg); + + if (size != sizeof (uint64_t) * (levels + 2)) + return (dt_set_errno(dtp, EDT_DMISMATCH)); + + min = 0; + max = levels + 1; + + if (min == 0) { + (void) snprintf(c, sizeof (c), "< %d", base); + err = dt_printf(dtp, fp, "%8s :", c); + } else { + err = dt_printf(dtp, fp, "%8d :", base + (min - 1) * step); + } + + if (err < 0) + return (-1); + + for (i = min; i <= max; i++) { + dt_quantize_total(dtp, data[i], &total); + count += data[i]; + } + + for (i = min; i <= max; i++) { + if (dt_print_packed(dtp, fp, data[i], total) < 0) + return (-1); + } + + (void) snprintf(c, sizeof (c), ">= %d", base + (levels * step)); + return (dt_printf(dtp, fp, ": %-8s | %lld\n", c, (long long)count)); +} + int dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, size_t size, uint64_t normal) @@ -740,7 +1042,7 @@ dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, for (i = first_bin; i <= last_bin; i++) { positives |= (data[i] > 0); negatives |= (data[i] < 0); - total += dt_fabsl((long double)data[i]); + dt_quantize_total(dtp, data[i], &total); } if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", @@ -823,7 +1125,7 @@ dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, } /*ARGSUSED*/ -int +static int dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, size_t nbytes, int width, int quiet, int forceraw) { @@ -876,10 +1178,12 @@ dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, if (j != nbytes) break; - if (quiet) + if (quiet) { return (dt_printf(dtp, fp, "%s", c)); - else - return (dt_printf(dtp, fp, " %-*s", width, c)); + } else { + return (dt_printf(dtp, fp, " %s%*s", + width < 0 ? " " : "", width, c)); + } } break; @@ -1793,10 +2097,83 @@ dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) static int dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, - caddr_t addr, size_t size, uint64_t normal) + caddr_t addr, size_t size, const dtrace_aggdata_t *aggdata, + uint64_t normal, dt_print_aggdata_t *pd) { - int err; + int err, width; dtrace_actkind_t act = rec->dtrd_action; + boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack; + dtrace_aggdesc_t *agg = aggdata->dtada_desc; + + static struct { + size_t size; + int width; + int packedwidth; + } *fmt, fmttab[] = { + { sizeof (uint8_t), 3, 3 }, + { sizeof (uint16_t), 5, 5 }, + { sizeof (uint32_t), 8, 8 }, + { sizeof (uint64_t), 16, 16 }, + { 0, -50, 16 } + }; + + if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid) { + dtrace_recdesc_t *r; + + width = 0; + + /* + * To print our quantization header for either an agghist or + * aggpack aggregation, we need to iterate through all of our + * of our records to determine their width. + */ + for (r = rec; !DTRACEACT_ISAGG(r->dtrd_action); r++) { + for (fmt = fmttab; fmt->size && + fmt->size != r->dtrd_size; fmt++) + continue; + + width += fmt->packedwidth + 1; + } + + if (pd->dtpa_agghist) { + if (dt_print_quanthdr(dtp, fp, width) < 0) + return (-1); + } else { + if (dt_print_quanthdr_packed(dtp, fp, + width, aggdata, r->dtrd_action) < 0) + return (-1); + } + + pd->dtpa_agghisthdr = agg->dtagd_varid; + } + + if (pd->dtpa_agghist && DTRACEACT_ISAGG(act)) { + char positives = aggdata->dtada_flags & DTRACE_A_HASPOSITIVES; + char negatives = aggdata->dtada_flags & DTRACE_A_HASNEGATIVES; + int64_t val; + + assert(act == DTRACEAGG_SUM || act == DTRACEAGG_COUNT); + val = (long long)*((uint64_t *)addr); + + if (dt_printf(dtp, fp, " ") < 0) + return (-1); + + return (dt_print_quantline(dtp, fp, val, normal, + aggdata->dtada_total, positives, negatives)); + } + + if (pd->dtpa_aggpack && DTRACEACT_ISAGG(act)) { + switch (act) { + case DTRACEAGG_QUANTIZE: + return (dt_print_quantize_packed(dtp, + fp, addr, size, aggdata)); + case DTRACEAGG_LQUANTIZE: + return (dt_print_lquantize_packed(dtp, + fp, addr, size, aggdata)); + default: + break; + } + } switch (act) { case DTRACEACT_STACK: @@ -1839,28 +2216,33 @@ dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, break; } + for (fmt = fmttab; fmt->size && fmt->size != size; fmt++) + continue; + + width = packed ? fmt->packedwidth : fmt->width; + switch (size) { case sizeof (uint64_t): - err = dt_printf(dtp, fp, " %16lld", + err = dt_printf(dtp, fp, " %*lld", width, /* LINTED - alignment */ (long long)*((uint64_t *)addr) / normal); break; case sizeof (uint32_t): /* LINTED - alignment */ - err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) / + err = dt_printf(dtp, fp, " %*d", width, *((uint32_t *)addr) / (uint32_t)normal); break; case sizeof (uint16_t): /* LINTED - alignment */ - err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) / + err = dt_printf(dtp, fp, " %*d", width, *((uint16_t *)addr) / (uint32_t)normal); break; case sizeof (uint8_t): - err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) / + err = dt_printf(dtp, fp, " %*d", width, *((uint8_t *)addr) / (uint32_t)normal); break; default: - err = dt_print_bytes(dtp, fp, addr, size, 50, 0, 0); + err = dt_print_bytes(dtp, fp, addr, size, width, 0, 0); break; } @@ -1881,6 +2263,9 @@ dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) caddr_t addr; size_t size; + pd->dtpa_agghist = (aggdata->dtada_flags & DTRACE_A_TOTAL); + pd->dtpa_aggpack = (aggdata->dtada_flags & DTRACE_A_MINMAXBIN); + /* * Iterate over each record description in the key, printing the traced * data, skipping the first datum (the tuple member created by the @@ -1897,7 +2282,8 @@ dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) break; } - if (dt_print_datum(dtp, fp, rec, addr, size, 1) < 0) + if (dt_print_datum(dtp, fp, rec, addr, + size, aggdata, 1, pd) < 0) return (-1); if (dt_buffered_flush(dtp, NULL, rec, aggdata, @@ -1920,7 +2306,8 @@ dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) assert(DTRACEACT_ISAGG(act)); normal = aggdata->dtada_normal; - if (dt_print_datum(dtp, fp, rec, addr, size, normal) < 0) + if (dt_print_datum(dtp, fp, rec, addr, + size, aggdata, normal, pd) < 0) return (-1); if (dt_buffered_flush(dtp, NULL, rec, aggdata, @@ -1931,8 +2318,10 @@ dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) agg->dtagd_flags |= DTRACE_AGD_PRINTED; } - if (dt_printf(dtp, fp, "\n") < 0) - return (-1); + if (!pd->dtpa_agghist && !pd->dtpa_aggpack) { + if (dt_printf(dtp, fp, "\n") < 0) + return (-1); + } if (dt_buffered_flush(dtp, NULL, NULL, aggdata, DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) @@ -2401,7 +2790,7 @@ nofmt: } n = dt_print_bytes(dtp, fp, addr, - tracememsize, 33, quiet, 1); + tracememsize, -33, quiet, 1); tracememsize = 0; @@ -2434,7 +2823,7 @@ nofmt: break; default: n = dt_print_bytes(dtp, fp, addr, - rec->dtrd_size, 33, quiet, 0); + rec->dtrd_size, -33, quiet, 0); break; } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c index 871fdd5..d717d56 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c @@ -21,7 +21,8 @@ */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013 Joyent, Inc. All rights reserved. * Use is subject to license terms. */ @@ -779,7 +780,7 @@ dt_decl_enumerator(char *s, dt_node_t *dnp) yyintdecimal = 0; dnp = dt_node_int(value); - dt_node_type_assign(dnp, dsp->ds_ctfp, dsp->ds_type); + dt_node_type_assign(dnp, dsp->ds_ctfp, dsp->ds_type, B_FALSE); if ((inp = malloc(sizeof (dt_idnode_t))) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); @@ -821,6 +822,8 @@ dt_decl_type(dt_decl_t *ddp, dtrace_typeinfo_t *tip) char *name; int rv; + tip->dtt_flags = 0; + /* * Based on our current #include depth and decl stack depth, determine * which dynamic CTF module and scope to use when adding any new types. @@ -828,6 +831,9 @@ dt_decl_type(dt_decl_t *ddp, dtrace_typeinfo_t *tip) dmp = yypcb->pcb_idepth ? dtp->dt_cdefs : dtp->dt_ddefs; flag = yypcb->pcb_dstack.ds_next ? CTF_ADD_NONROOT : CTF_ADD_ROOT; + if (ddp->dd_attr & DT_DA_USER) + tip->dtt_flags = DTT_FL_USER; + /* * If we have already cached a CTF type for this decl, then we just * return the type information for the cached type. diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h index 2933155..d322875 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h @@ -23,12 +23,14 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013 Joyent, Inc. All rights reserved. + */ #ifndef _DT_DECL_H #define _DT_DECL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <libctf.h> #include <dtrace.h> @@ -59,6 +61,7 @@ typedef struct dt_decl { #define DT_DA_RESTRICT 0x0040 /* qualify type as restrict */ #define DT_DA_VOLATILE 0x0080 /* qualify type as volatile */ #define DT_DA_PAREN 0x0100 /* parenthesis tag */ +#define DT_DA_USER 0x0200 /* user-land type specifier */ typedef enum dt_dclass { DT_DC_DEFAULT, /* no storage class specified */ diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c index fff4235..c0af364 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c @@ -26,7 +26,8 @@ */ /* - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013 Joyent, Inc. All rights reserved. */ #include <strings.h> @@ -312,9 +313,10 @@ dt_dis_typestr(const dtrace_diftype_t *t, char *buf, size_t len) (void) snprintf(ckind, sizeof (ckind), "0x%x", t->dtdt_ckind); } - if (t->dtdt_flags & DIF_TF_BYREF) { - (void) snprintf(buf, len, "%s (%s) by ref (size %lu)", - kind, ckind, (ulong_t)t->dtdt_size); + if (t->dtdt_flags & (DIF_TF_BYREF | DIF_TF_BYUREF)) { + (void) snprintf(buf, len, "%s (%s) by %sref (size %lu)", + kind, ckind, (t->dtdt_flags & DIF_TF_BYUREF) ? "user " : "", + (ulong_t)t->dtdt_size); } else { (void) snprintf(buf, len, "%s (%s) (size %lu)", kind, ckind, (ulong_t)t->dtdt_size); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c index d8dbbabb..2327ff7 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c @@ -111,7 +111,8 @@ static const struct { { EDT_BADAGGVAR, "Invalid aggregation variable identifier" }, { EDT_OVERSION, "Client requested deprecated version of library" }, { EDT_ENABLING_ERR, "Failed to enable probe" }, - { EDT_NOPROBES, "No probe sites found for declared provider" } + { EDT_NOPROBES, "No probe sites found for declared provider" }, + { EDT_CANTLOAD, "Failed to load module" }, }; static const int _dt_nerr = sizeof (_dt_errlist) / sizeof (_dt_errlist[0]); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y index 0c12623..07790f4 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y @@ -23,8 +23,10 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <dt_impl.h> @@ -102,6 +104,7 @@ %token DT_KEY_TYPEDEF %token DT_KEY_UNION %token DT_KEY_UNSIGNED +%token DT_KEY_USERLAND %token DT_KEY_VOID %token DT_KEY_VOLATILE %token DT_KEY_WHILE @@ -633,6 +636,7 @@ type_specifier: DT_KEY_VOID { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("void")); } | DT_KEY_DOUBLE { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("double")); } | DT_KEY_SIGNED { $$ = dt_decl_attr(DT_DA_SIGNED); } | DT_KEY_UNSIGNED { $$ = dt_decl_attr(DT_DA_UNSIGNED); } + | DT_KEY_USERLAND { $$ = dt_decl_attr(DT_DA_USER); } | DT_KEY_STRING { $$ = dt_decl_spec(CTF_K_TYPEDEF, DUP("string")); } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c index 13adbb4..5a2f0e4 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c @@ -22,6 +22,8 @@ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013 Joyent, Inc. All rights reserved. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -104,7 +106,7 @@ dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp, } } - dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); + dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); } /* @@ -163,7 +165,7 @@ dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) if (argc != 0) isp->dis_args[argc - 1].dn_list = NULL; - dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); + dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); } else { dt_idcook_sign(dnp, idp, argc, args, @@ -304,7 +306,7 @@ dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) } dt_node_type_assign(&isp->dis_args[i], - dtt.dtt_ctfp, dtt.dtt_type); + dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); } } @@ -391,7 +393,9 @@ dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap) dt_node_type_assign(dnp, prp->pr_argv[ap->dn_value].dtt_ctfp, - prp->pr_argv[ap->dn_value].dtt_type); + prp->pr_argv[ap->dn_value].dtt_type, + prp->pr_argv[ap->dn_value].dtt_flags & DTT_FL_USER ? + B_TRUE : B_FALSE); } else if ((dxp = dt_xlator_lookup(dtp, nnp, xnp, DT_XLATE_FUZZY)) != NULL || ( @@ -419,7 +423,8 @@ dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap) dnp->dn_ident->di_ctfp = xidp->di_ctfp; dnp->dn_ident->di_type = xidp->di_type; - dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); + dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), + B_FALSE); } else { xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s " @@ -465,7 +470,7 @@ dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap) idp->di_ctfp = dtt.dtt_ctfp; idp->di_type = dtt.dtt_type; - dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); + dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); } /*ARGSUSED*/ @@ -487,7 +492,7 @@ dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) idp->di_type = dtt.dtt_type; } - dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); + dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); } /*ARGSUSED*/ @@ -495,7 +500,7 @@ static void dt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) { if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR) - dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); + dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); } static void diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h index 2bae220..b7abbc2 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h @@ -146,6 +146,10 @@ typedef struct dt_module { caddr_t dm_reloc_offset; /* Symbol relocation offset. */ uintptr_t *dm_sec_offsets; #endif + pid_t dm_pid; /* pid for this module */ + uint_t dm_nctflibs; /* number of ctf children libraries */ + ctf_file_t **dm_libctfp; /* process library ctf pointers */ + char **dm_libctfn; /* names of process ctf containers */ } dt_module_t; #define DT_DM_LOADED 0x1 /* module symbol and type data is loaded */ @@ -189,6 +193,9 @@ typedef struct dt_print_aggdata { dtrace_aggvarid_t dtpa_id; /* aggregation variable of interest */ FILE *dtpa_fp; /* file pointer */ int dtpa_allunprint; /* print only unprinted aggregations */ + int dtpa_agghist; /* print aggregation as histogram */ + int dtpa_agghisthdr; /* aggregation histogram hdr printed */ + int dtpa_aggpack; /* pack quantized aggregations */ } dt_print_aggdata_t; typedef struct dt_dirpath { @@ -283,6 +290,7 @@ struct dtrace_hdl { uint_t dt_linktype; /* dtrace link output file type (see below) */ uint_t dt_xlatemode; /* dtrace translator linking mode (see below) */ uint_t dt_stdcmode; /* dtrace stdc compatibility mode (see below) */ + uint_t dt_encoding; /* dtrace output encoding (see below) */ uint_t dt_treedump; /* dtrace tree debug bitmap (see below) */ uint64_t dt_options[DTRACEOPT_MAX]; /* dtrace run-time options */ int dt_version; /* library version requested by client */ @@ -374,6 +382,14 @@ struct dtrace_hdl { #define DT_STDC_XT 3 /* ISO C + K&R C compat with ISO: __STDC__=0 */ /* + * Values for the dt_encoding property, which is used to force a particular + * character encoding (overriding default behavior and/or automatic detection). + */ +#define DT_ENCODING_UNSET 0 +#define DT_ENCODING_ASCII 1 +#define DT_ENCODING_UTF8 2 + +/* * Macro to test whether a given pass bit is set in the dt_treedump bit-vector. * If the bit for pass 'p' is set, the D compiler displays the parse tree for * the program by printing it to stderr at the end of compiler pass 'p'. @@ -536,7 +552,8 @@ enum { EDT_BADAGGVAR, /* invalid aggregation variable identifier */ EDT_OVERSION, /* client is requesting deprecated version */ EDT_ENABLING_ERR, /* failed to enable probe */ - EDT_NOPROBES /* no probes sites for declared provider */ + EDT_NOPROBES, /* no probes sites for declared provider */ + EDT_CANTLOAD /* failed to load a module */ }; /* diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l index b31933e..032d303 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l @@ -23,6 +23,10 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <string.h> #include <stdlib.h> @@ -93,13 +97,17 @@ static void unput(int); %} %e 1500 /* maximum nodes */ -%p 3700 /* maximum positions */ +%p 4900 /* maximum positions */ %n 600 /* maximum states */ +%a 3000 /* maximum transitions */ %s S0 S1 S2 S3 S4 RGX_AGG "@"[a-zA-Z_][0-9a-zA-Z_]* RGX_PSPEC [-$:a-zA-Z_.?*\\\[\]!][-$:0-9a-zA-Z_.`?*\\\[\]!]* +RGX_ALTIDENT [a-zA-Z_][0-9a-zA-Z_]* +RGX_LMID LM[0-9a-fA-F]+` +RGX_MOD_IDENT [a-zA-Z_`][0-9a-z.A-Z_`]*` RGX_IDENT [a-zA-Z_`][0-9a-zA-Z_`]* RGX_INT ([0-9]+|0[xX][0-9A-Fa-f]+)[uU]?[lL]?[lL]? RGX_FP ([0-9]+("."?)[0-9]*|"."[0-9]+)((e|E)("+"|-)?[0-9]+)?[fFlL]? @@ -169,6 +177,7 @@ if (yypcb->pcb_token != 0) { <S0>typedef return (DT_KEY_TYPEDEF); <S0>union return (DT_KEY_UNION); <S0>unsigned return (DT_KEY_UNSIGNED); +<S0>userland return (DT_KEY_USERLAND); <S0>void return (DT_KEY_VOID); <S0>volatile return (DT_KEY_VOLATILE); <S0>while return (DT_KEY_WHILE); @@ -347,7 +356,9 @@ if (yypcb->pcb_token != 0) { return (DT_TOK_INT); } -<S0>{RGX_IDENT} { +<S0>{RGX_IDENT} | +<S0>{RGX_MOD_IDENT}{RGX_IDENT} | +<S0>{RGX_MOD_IDENT} { return (id_or_type(yytext)); } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c index f31c600..2a43211 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c @@ -230,9 +230,6 @@ prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) #if defined(__arm__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); -#elif defined(__ia64__) -/* XXX */ -printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #elif defined(__i386) || defined(__amd64) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; @@ -424,8 +421,6 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) #ifdef DOODAD #if defined(__arm__) /* XXX */ -#elif defined(__ia64__) -/* XXX */ #elif defined(__mips__) /* XXX */ #elif defined(__powerpc__) @@ -535,8 +530,6 @@ dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) elf_file.ehdr.e_type = ET_REL; #if defined(__arm__) elf_file.ehdr.e_machine = EM_ARM; -#elif defined(__ia64__) - elf_file.ehdr.e_machine = EM_IA_64; #elif defined(__mips__) elf_file.ehdr.e_machine = EM_MIPS; #elif defined(__powerpc__) @@ -683,8 +676,6 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) elf_file.ehdr.e_type = ET_REL; #if defined(__arm__) elf_file.ehdr.e_machine = EM_ARM; -#elif defined(__ia64__) - elf_file.ehdr.e_machine = EM_IA_64; #elif defined(__mips__) elf_file.ehdr.e_machine = EM_MIPS; #elif defined(__powerpc__) @@ -814,15 +805,6 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); return (0); } -#elif defined(__ia64__) -/* XXX */ -static int -dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, - uint32_t *off) -{ -printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); - return (0); -} #elif defined(__mips__) /* XXX */ static int @@ -1235,9 +1217,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) if (dtp->dt_oflags & DTRACE_O_LP64) { eclass = ELFCLASS64; -#if defined(__ia64__) - emachine1 = emachine2 = EM_IA_64; -#elif defined(__mips__) +#if defined(__mips__) emachine1 = emachine2 = EM_MIPS; #elif defined(__powerpc__) emachine1 = emachine2 = EM_PPC64; @@ -1258,7 +1238,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) #elif defined(__sparc) emachine1 = EM_SPARC; emachine2 = EM_SPARC32PLUS; -#elif defined(__i386) || defined(__amd64) || defined(__ia64__) +#elif defined(__i386) || defined(__amd64) emachine1 = emachine2 = EM_386; #endif symsize = sizeof (Elf32_Sym); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c index 497faa9..e3905c1 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c @@ -22,6 +22,9 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <sys/types.h> #if defined(sun) @@ -50,6 +53,7 @@ #include <dirent.h> #if !defined(sun) #include <fcntl.h> +#include <libproc_compat.h> #endif #include <dt_strtab.h> @@ -462,6 +466,9 @@ static const dt_modops_t dt_modops_64 = { dt_module_t * dt_module_create(dtrace_hdl_t *dtp, const char *name) { + long pid; + char *eptr; + dt_ident_t *idp; uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; @@ -485,6 +492,32 @@ dt_module_create(dtrace_hdl_t *dtp, const char *name) else dmp->dm_ops = &dt_modops_32; + /* + * Modules for userland processes are special. They always refer to a + * specific process and have a copy of their CTF data from a specific + * instant in time. Any dt_module_t that begins with 'pid' is a module + * for a specific process, much like how any probe description that + * begins with 'pid' is special. pid123 refers to process 123. A module + * that is just 'pid' refers specifically to pid$target. This is + * generally done as D does not currently allow for macros to be + * evaluated when working with types. + */ + if (strncmp(dmp->dm_name, "pid", 3) == 0) { + errno = 0; + if (dmp->dm_name[3] == '\0') { + idp = dt_idhash_lookup(dtp->dt_macros, "target"); + if (idp != NULL && idp->di_id != 0) + dmp->dm_pid = idp->di_id; + } else { + pid = strtol(dmp->dm_name + 3, &eptr, 10); + if (errno == 0 && *eptr == '\0') + dmp->dm_pid = (pid_t)pid; + else + dt_dprintf("encountered malformed pid " + "module: %s\n", dmp->dm_name); + } + } + return (dmp); } @@ -554,12 +587,169 @@ dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp) return (0); } +typedef struct dt_module_cb_arg { + struct ps_prochandle *dpa_proc; + dtrace_hdl_t *dpa_dtp; + dt_module_t *dpa_dmp; + uint_t dpa_count; +} dt_module_cb_arg_t; + +/* ARGSUSED */ +static int +dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj) +{ + ctf_file_t *fp; + dt_module_cb_arg_t *dcp = arg; + + /* Try to grab a ctf container if it exists */ + fp = Pname_to_ctf(dcp->dpa_proc, obj); + if (fp != NULL) + dcp->dpa_count++; + return (0); +} + +/* ARGSUSED */ +static int +dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj) +{ + ctf_file_t *fp; + char buf[MAXPATHLEN], *p; + dt_module_cb_arg_t *dcp = arg; + int count = dcp->dpa_count; + Lmid_t lmid; + + fp = Pname_to_ctf(dcp->dpa_proc, obj); + if (fp == NULL) + return (0); + fp = ctf_dup(fp); + if (fp == NULL) + return (0); + dcp->dpa_dmp->dm_libctfp[count] = fp; + /* + * While it'd be nice to simply use objname here, because of our prior + * actions we'll always get a resolved object name to its on disk file. + * Like the pid provider, we need to tell a bit of a lie here. The type + * that the user thinks of is in terms of the libraries they requested, + * eg. libc.so.1, they don't care about the fact that it's + * libc_hwcap.so.1. + */ + (void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf)); + if ((p = strrchr(buf, '/')) == NULL) + p = buf; + else + p++; + + /* + * If for some reason we can't find a link map id for this module, which + * would be really quite weird. We instead just say the link map id is + * zero. + */ + if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0) + lmid = 0; + + if (lmid == 0) + dcp->dpa_dmp->dm_libctfn[count] = strdup(p); + else + (void) asprintf(&dcp->dpa_dmp->dm_libctfn[count], + "LM%x`%s", lmid, p); + if (dcp->dpa_dmp->dm_libctfn[count] == NULL) + return (1); + ctf_setspecific(fp, dcp->dpa_dmp); + dcp->dpa_count++; + return (0); +} + +/* + * We've been asked to load data that belongs to another process. As such we're + * going to pgrab it at this instant, load everything that we might ever care + * about, and then drive on. The reason for this is that the process that we're + * interested in might be changing. As long as we have grabbed it, then this + * can't be a problem for us. + * + * For now, we're actually going to punt on most things and just try to get CTF + * data, nothing else. Basically this is only useful as a source of type + * information, we can't go and do the stacktrace lookups, etc. + */ +static int +dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp) +{ + struct ps_prochandle *p; + dt_module_cb_arg_t arg; + + /* + * Note that on success we do not release this hold. We must hold this + * for our life time. + */ + p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE); + if (p == NULL) { + dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + dt_proc_lock(dtp, p); + + arg.dpa_proc = p; + arg.dpa_dtp = dtp; + arg.dpa_dmp = dmp; + arg.dpa_count = 0; + if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) { + dt_dprintf("failed to iterate objects\n"); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + + if (arg.dpa_count == 0) { + dt_dprintf("no ctf data present\n"); + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + + dmp->dm_libctfp = malloc(sizeof (ctf_file_t *) * arg.dpa_count); + if (dmp->dm_libctfp == NULL) { + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_NOMEM)); + } + bzero(dmp->dm_libctfp, sizeof (ctf_file_t *) * arg.dpa_count); + + dmp->dm_libctfn = malloc(sizeof (char *) * arg.dpa_count); + if (dmp->dm_libctfn == NULL) { + free(dmp->dm_libctfp); + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_NOMEM)); + } + bzero(dmp->dm_libctfn, sizeof (char *) * arg.dpa_count); + + dmp->dm_nctflibs = arg.dpa_count; + + arg.dpa_count = 0; + if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) { + dt_proc_unlock(dtp, p); + dt_module_unload(dtp, dmp); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + assert(arg.dpa_count == dmp->dm_nctflibs); + dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count, + (int)dmp->dm_pid); + + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + dmp->dm_flags |= DT_DM_LOADED; + + return (0); +} + int dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp) { if (dmp->dm_flags & DT_DM_LOADED) return (0); /* module is already loaded */ + if (dmp->dm_pid != 0) + return (dt_module_load_proc(dtp, dmp)); + dmp->dm_ctdata.cts_name = ".SUNW_ctf"; dmp->dm_ctdata.cts_type = SHT_PROGBITS; dmp->dm_ctdata.cts_flags = 0; @@ -645,6 +835,14 @@ dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp) return (0); } +int +dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp) +{ + if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0) + return (1); + return (dt_module_getctf(dtp, dmp) != NULL); +} + ctf_file_t * dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp) { @@ -718,6 +916,8 @@ err: void dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp) { + int i; + ctf_close(dmp->dm_ctfp); dmp->dm_ctfp = NULL; @@ -733,6 +933,17 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp) } #endif + if (dmp->dm_libctfp != NULL) { + for (i = 0; i < dmp->dm_nctflibs; i++) { + ctf_close(dmp->dm_libctfp[i]); + free(dmp->dm_libctfn[i]); + } + free(dmp->dm_libctfp); + free(dmp->dm_libctfn); + dmp->dm_libctfp = NULL; + dmp->dm_nctflibs = 0; + } + bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t)); bzero(&dmp->dm_symtab, sizeof (ctf_sect_t)); bzero(&dmp->dm_strtab, sizeof (ctf_sect_t)); @@ -778,6 +989,8 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp) (void) elf_end(dmp->dm_elf); dmp->dm_elf = NULL; + dmp->dm_pid = 0; + dmp->dm_flags &= ~DT_DM_LOADED; } @@ -866,6 +1079,34 @@ dt_module_modelname(dt_module_t *dmp) return ("32-bit"); } +/* ARGSUSED */ +int +dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp) +{ + int i; + + for (i = 0; i < dmp->dm_nctflibs; i++) { + if (dmp->dm_libctfp[i] == fp) + return (i); + } + + return (-1); +} + +/* ARGSUSED */ +ctf_file_t * +dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name) +{ + int i; + + for (i = 0; i < dmp->dm_nctflibs; i++) { + if (strcmp(dmp->dm_libctfn[i], name) == 0) + return (dmp->dm_libctfp[i]); + } + + return (NULL); +} + /* * Update our module cache by adding an entry for the specified module 'name'. * We create the dt_module_t and populate it using /system/object/<name>/. @@ -1294,8 +1535,10 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, dt_module_t *dmp; int found = 0; ctf_id_t id; - uint_t n; + uint_t n, i; int justone; + ctf_file_t *fp; + char *buf, *p, *q; uint_t mask = 0; /* mask of dt_module flags to match */ uint_t bits = 0; /* flag bits that must be present */ @@ -1310,7 +1553,6 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, return (-1); /* dt_errno is set for us */ n = 1; justone = 1; - } else { if (object == DTRACE_OBJ_KMODS) mask = bits = DT_DM_KERNEL; @@ -1334,7 +1576,7 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, * module. If our search was scoped to only one module then * return immediately leaving dt_errno unmodified. */ - if (dt_module_getctf(dtp, dmp) == NULL) { + if (dt_module_hasctf(dtp, dmp) == 0) { if (justone) return (-1); continue; @@ -1346,13 +1588,38 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, * 'tip' and keep going in the hope that we will locate the * underlying structure definition. Otherwise just return. */ - if ((id = ctf_lookup_by_name(dmp->dm_ctfp, name)) != CTF_ERR) { + if (dmp->dm_pid == 0) { + id = ctf_lookup_by_name(dmp->dm_ctfp, name); + fp = dmp->dm_ctfp; + } else { + if ((p = strchr(name, '`')) != NULL) { + buf = strdup(name); + if (buf == NULL) + return (dt_set_errno(dtp, EDT_NOMEM)); + p = strchr(buf, '`'); + if ((q = strchr(p + 1, '`')) != NULL) + p = q; + *p = '\0'; + fp = dt_module_getctflib(dtp, dmp, buf); + if (fp == NULL || (id = ctf_lookup_by_name(fp, + p + 1)) == CTF_ERR) + id = CTF_ERR; + free(buf); + } else { + for (i = 0; i < dmp->dm_nctflibs; i++) { + fp = dmp->dm_libctfp[i]; + id = ctf_lookup_by_name(fp, name); + if (id != CTF_ERR) + break; + } + } + } + if (id != CTF_ERR) { tip->dtt_object = dmp->dm_name; - tip->dtt_ctfp = dmp->dm_ctfp; + tip->dtt_ctfp = fp; tip->dtt_type = id; - - if (ctf_type_kind(dmp->dm_ctfp, ctf_type_resolve( - dmp->dm_ctfp, id)) != CTF_K_FORWARD) + if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) != + CTF_K_FORWARD) return (0); found++; @@ -1374,6 +1641,7 @@ dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp, tip->dtt_object = NULL; tip->dtt_ctfp = NULL; tip->dtt_type = CTF_ERR; + tip->dtt_flags = 0; if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL) return (dt_set_errno(dtp, EDT_NOMOD)); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h index 8334a2b..d103e02 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h @@ -23,12 +23,13 @@ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #ifndef _DT_MODULE_H #define _DT_MODULE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <dt_impl.h> #ifdef __cplusplus @@ -43,11 +44,16 @@ extern void dt_module_destroy(dtrace_hdl_t *, dt_module_t *); extern dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *, const char *); extern dt_module_t *dt_module_lookup_by_ctf(dtrace_hdl_t *, ctf_file_t *); +extern int dt_module_hasctf(dtrace_hdl_t *, dt_module_t *); extern ctf_file_t *dt_module_getctf(dtrace_hdl_t *, dt_module_t *); extern dt_ident_t *dt_module_extern(dtrace_hdl_t *, dt_module_t *, const char *, const dtrace_typeinfo_t *); extern const char *dt_module_modelname(dt_module_t *); +extern int dt_module_getlibid(dtrace_hdl_t *, dt_module_t *, + const ctf_file_t *); +extern ctf_file_t *dt_module_getctflib(dtrace_hdl_t *, dt_module_t *, + const char *); #ifdef __cplusplus } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index 92251d5..f6c140b 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ @@ -122,8 +122,12 @@ #define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1) #define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0) #define DT_VERS_1_9_1 DT_VERSION_NUMBER(1, 9, 1) -#define DT_VERS_LATEST DT_VERS_1_9_1 -#define DT_VERS_STRING "Sun D 1.9.1" +#define DT_VERS_1_10 DT_VERSION_NUMBER(1, 10, 0) +#define DT_VERS_1_11 DT_VERSION_NUMBER(1, 11, 0) +#define DT_VERS_1_12 DT_VERSION_NUMBER(1, 12, 0) +#define DT_VERS_1_12_1 DT_VERSION_NUMBER(1, 12, 1) +#define DT_VERS_LATEST DT_VERS_1_12_1 +#define DT_VERS_STRING "Sun D 1.12.1" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ @@ -145,6 +149,10 @@ const dt_version_t _dtrace_versions[] = { DT_VERS_1_8_1, /* D API 1.8.1 */ DT_VERS_1_9, /* D API 1.9 */ DT_VERS_1_9_1, /* D API 1.9.1 */ + DT_VERS_1_10, /* D API 1.10 */ + DT_VERS_1_11, /* D API 1.11 */ + DT_VERS_1_12, /* D API 1.12 */ + DT_VERS_1_12_1, /* D API 1.12.1 */ 0 }; @@ -275,6 +283,8 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_func, "uint64_t(uint64_t)" }, { "htons", DT_IDENT_FUNC, 0, DIF_SUBR_HTONS, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint16_t(uint16_t)" }, +{ "getf", DT_IDENT_FUNC, 0, DIF_SUBR_GETF, DT_ATTR_STABCMN, DT_VERS_1_10, + &dt_idops_func, "file_t *(int)" }, { "gid", DT_IDENT_SCALAR, 0, DIF_VAR_GID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "gid_t" }, { "id", DT_IDENT_SCALAR, 0, DIF_VAR_ID, DT_ATTR_STABCMN, DT_VERS_1_0, @@ -297,6 +307,8 @@ static const dt_ident_t _dtrace_globals[] = { DT_VERS_1_5, &dt_idops_func, "string(int, void *)" }, { "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, +{ "json", DT_IDENT_FUNC, 0, DIF_SUBR_JSON, DT_ATTR_STABCMN, DT_VERS_1_11, + &dt_idops_func, "string(const char *, const char *)" }, { "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0, @@ -448,6 +460,8 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_func, "string(const char *, const char *)" }, { "strtok", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOK, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, const char *)" }, +{ "strtoll", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOLL, DT_ATTR_STABCMN, DT_VERS_1_11, + &dt_idops_func, "int64_t(const char *, [int])" }, { "substr", DT_IDENT_FUNC, 0, DIF_SUBR_SUBSTR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, int, [int])" }, { "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0, @@ -1144,6 +1158,7 @@ alloc: dtp->dt_linktype = DT_LTYP_ELF; dtp->dt_xlatemode = DT_XL_STATIC; dtp->dt_stdcmode = DT_STDC_XA; + dtp->dt_encoding = DT_ENCODING_UNSET; dtp->dt_version = version; dtp->dt_fd = dtfd; dtp->dt_ftfd = ftfd; diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c index c20d250..832af88 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c @@ -25,6 +25,7 @@ */ /* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ @@ -338,6 +339,23 @@ dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) /*ARGSUSED*/ static int +dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ + if (arg == NULL) + return (dt_set_errno(dtp, EDT_BADOPTVAL)); + + if (strcmp(arg, "ascii") == 0) + dtp->dt_encoding = DT_ENCODING_ASCII; + else if (strcmp(arg, "utf8") == 0) + dtp->dt_encoding = DT_ENCODING_UTF8; + else + return (dt_set_errno(dtp, EDT_BADOPTVAL)); + + return (0); +} + +/*ARGSUSED*/ +static int dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) { if (arg == NULL) @@ -928,6 +946,7 @@ static const dt_option_t _dtrace_ctoptions[] = { { "define", dt_opt_cpp_opts, (uintptr_t)"-D" }, { "droptags", dt_opt_droptags }, { "empty", dt_opt_cflags, DTRACE_C_EMPTY }, + { "encoding", dt_opt_encoding }, { "errtags", dt_opt_cflags, DTRACE_C_ETAGS }, { "evaltime", dt_opt_evaltime }, { "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" }, @@ -988,11 +1007,14 @@ static const dt_option_t _dtrace_rtoptions[] = { * Dynamic run-time options. */ static const dt_option_t _dtrace_drtoptions[] = { + { "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST }, + { "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK }, { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE }, { "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY }, { "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS }, { "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS }, { "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV }, + { "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM }, { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT }, { "quiet", dt_opt_runtime, DTRACEOPT_QUIET }, { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES }, diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c index 5b3be7d..6ce3dad 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c @@ -22,8 +22,8 @@ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2011, Joyent Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013, Joyent Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -197,7 +197,7 @@ dt_type_lookup(const char *s, dtrace_typeinfo_t *tip) { static const char delimiters[] = " \t\n\r\v\f*`"; dtrace_hdl_t *dtp = yypcb->pcb_hdl; - const char *p, *q, *end, *obj; + const char *p, *q, *r, *end, *obj; for (p = s, end = s + strlen(s); *p != '\0'; p = q) { while (isspace(*p)) @@ -225,8 +225,23 @@ dt_type_lookup(const char *s, dtrace_typeinfo_t *tip) bcopy(s, type, (size_t)(p - s)); bcopy(q + 1, type + (size_t)(p - s), strlen(q + 1) + 1); - if (strchr(q + 1, '`') != NULL) - return (dt_set_errno(dtp, EDT_BADSCOPE)); + /* + * There may be at most three delimeters. The second + * delimeter is usually used to distinguish the type + * within a given module, however, there could be a link + * map id on the scene in which case that delimeter + * would be the third. We determine presence of the lmid + * if it rouglhly meets the from LM[0-9] + */ + if ((r = strchr(q + 1, '`')) != NULL && + ((r = strchr(r + 1, '`')) != NULL)) { + if (strchr(r + 1, '`') != NULL) + return (dt_set_errno(dtp, + EDT_BADSCOPE)); + if (q[1] != 'L' || q[2] != 'M') + return (dt_set_errno(dtp, + EDT_BADSCOPE)); + } return (dtrace_lookup_by_type(dtp, object, type, tip)); } @@ -256,6 +271,7 @@ dt_type_pointer(dtrace_typeinfo_t *tip) ctf_file_t *ctfp = tip->dtt_ctfp; ctf_id_t type = tip->dtt_type; ctf_id_t base = ctf_type_resolve(ctfp, type); + uint_t bflags = tip->dtt_flags; dt_module_t *dmp; ctf_id_t ptr; @@ -287,6 +303,7 @@ dt_type_pointer(dtrace_typeinfo_t *tip) tip->dtt_object = dmp->dm_name; tip->dtt_ctfp = dmp->dm_ctfp; tip->dtt_type = ptr; + tip->dtt_flags = bflags; return (0); } @@ -390,7 +407,7 @@ void dt_node_promote(dt_node_t *lp, dt_node_t *rp, dt_node_t *dnp) { dt_type_promote(lp, rp, &dnp->dn_ctfp, &dnp->dn_type); - dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type); + dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type, B_FALSE); dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr)); } @@ -659,7 +676,8 @@ dt_node_attr_assign(dt_node_t *dnp, dtrace_attribute_t attr) } void -dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type) +dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type, + boolean_t user) { ctf_id_t base = ctf_type_resolve(fp, type); uint_t kind = ctf_type_kind(fp, base); @@ -691,6 +709,9 @@ dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type) type == DT_DYN_TYPE(yypcb->pcb_hdl)) dnp->dn_flags |= DT_NF_REF; + if (user) + dnp->dn_flags |= DT_NF_USERLAND; + dnp->dn_flags |= DT_NF_COOKED; dnp->dn_ctfp = fp; dnp->dn_type = type; @@ -728,6 +749,7 @@ size_t dt_node_type_size(const dt_node_t *dnp) { ctf_id_t base; + dtrace_hdl_t *dtp = yypcb->pcb_hdl; if (dnp->dn_kind == DT_NODE_STRING) return (strlen(dnp->dn_string) + 1); @@ -740,6 +762,20 @@ dt_node_type_size(const dt_node_t *dnp) if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_FORWARD) return (0); + /* + * Here we have a 32-bit user pointer that is being used with a 64-bit + * kernel. When we're using it and its tagged as a userland reference -- + * then we need to keep it as a 32-bit pointer. However, if we are + * referring to it as a kernel address, eg. being used after a copyin() + * then we need to make sure that we actually return the kernel's size + * of a pointer, 8 bytes. + */ + if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_POINTER && + ctf_getmodel(dnp->dn_ctfp) == CTF_MODEL_ILP32 && + !(dnp->dn_flags & DT_NF_USERLAND) && + dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) + return (8); + return (ctf_type_size(dnp->dn_ctfp, dnp->dn_type)); } @@ -1226,7 +1262,7 @@ dt_node_int(uintmax_t value) if (value <= dtp->dt_ints[i].did_limit) { dt_node_type_assign(dnp, dtp->dt_ints[i].did_ctfp, - dtp->dt_ints[i].did_type); + dtp->dt_ints[i].did_type, B_FALSE); /* * If a prefix character is present in macro text, add @@ -1261,7 +1297,7 @@ dt_node_string(char *string) dnp = dt_node_alloc(DT_NODE_STRING); dnp->dn_op = DT_TOK_STRING; dnp->dn_string = string; - dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp)); + dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp), B_FALSE); return (dnp); } @@ -1337,7 +1373,8 @@ dt_node_type(dt_decl_t *ddp) dnp = dt_node_alloc(DT_NODE_TYPE); dnp->dn_op = DT_TOK_IDENT; dnp->dn_string = name; - dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type); + + dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags); if (dtt.dtt_ctfp == dtp->dt_cdefs->dm_ctfp || dtt.dtt_ctfp == dtp->dt_ddefs->dm_ctfp) @@ -1581,7 +1618,8 @@ dt_node_decl(void) bzero(&idn, sizeof (dt_node_t)); if (idp != NULL && idp->di_type != CTF_ERR) - dt_node_type_assign(&idn, idp->di_ctfp, idp->di_type); + dt_node_type_assign(&idn, idp->di_ctfp, idp->di_type, + B_FALSE); else if (idp != NULL) (void) dt_ident_cook(&idn, idp, NULL); @@ -1791,7 +1829,7 @@ dt_node_offsetof(dt_decl_t *ddp, char *s) } bzero(&dn, sizeof (dn)); - dt_node_type_assign(&dn, dtt.dtt_ctfp, ctm.ctm_type); + dt_node_type_assign(&dn, dtt.dtt_ctfp, ctm.ctm_type, B_FALSE); if (dn.dn_flags & DT_NF_BITFIELD) { xyerror(D_OFFSETOF_BITFIELD, @@ -1847,7 +1885,8 @@ dt_node_op1(int op, dt_node_t *cp) } dt_node_type_assign(cp, dtp->dt_ddefs->dm_ctfp, - ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t")); + ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"), + B_FALSE); cp->dn_kind = DT_NODE_INT; cp->dn_op = DT_TOK_INT; @@ -1925,17 +1964,17 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) case DT_TOK_LOR: dnp->dn_value = l || r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_LXOR: dnp->dn_value = (l != 0) ^ (r != 0); dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_LAND: dnp->dn_value = l && r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_BOR: dnp->dn_value = l | r; @@ -1952,12 +1991,12 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) case DT_TOK_EQU: dnp->dn_value = l == r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_NEQ: dnp->dn_value = l != r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_LT: dt_node_promote(lp, rp, dnp); @@ -1966,7 +2005,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) else dnp->dn_value = l < r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_LE: dt_node_promote(lp, rp, dnp); @@ -1975,7 +2014,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) else dnp->dn_value = l <= r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_GT: dt_node_promote(lp, rp, dnp); @@ -1984,7 +2023,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) else dnp->dn_value = l > r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_GE: dt_node_promote(lp, rp, dnp); @@ -1993,7 +2032,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) else dnp->dn_value = l >= r; dt_node_type_assign(dnp, - DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE); break; case DT_TOK_LSH: dnp->dn_value = l << r; @@ -2234,7 +2273,7 @@ dt_node_inline(dt_node_t *expr) * until we have successfully cooked the right-hand expression, below. */ dnp = dt_node_alloc(DT_NODE_INLINE); - dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type); + dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); dt_node_attr_assign(dnp, _dtrace_defattr); if (dt_node_is_void(dnp)) { @@ -2389,7 +2428,8 @@ dt_node_member(dt_decl_t *ddp, char *name, dt_node_t *expr) dnp->dn_membexpr = expr; if (ddp != NULL) - dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type); + dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, + dtt.dtt_flags); return (dnp); } @@ -2420,10 +2460,10 @@ dt_node_xlator(dt_decl_t *ddp, dt_decl_t *sdp, char *name, dt_node_t *members) } bzero(&sn, sizeof (sn)); - dt_node_type_assign(&sn, src.dtt_ctfp, src.dtt_type); + dt_node_type_assign(&sn, src.dtt_ctfp, src.dtt_type, B_FALSE); bzero(&dn, sizeof (dn)); - dt_node_type_assign(&dn, dst.dtt_ctfp, dst.dtt_type); + dt_node_type_assign(&dn, dst.dtt_ctfp, dst.dtt_type, B_FALSE); if (dt_xlator_lookup(dtp, &sn, &dn, DT_XLATE_EXACT) != NULL) { xyerror(D_XLATE_REDECL, @@ -2669,7 +2709,7 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create) attr = dt_ident_cook(dnp, idp, NULL); else { dt_node_type_assign(dnp, - DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); + DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE); attr = idp->di_attr; } @@ -2745,7 +2785,8 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create) dnp->dn_ident = idp; dnp->dn_flags |= DT_NF_LVALUE; - dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type); + dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, + dtt.dtt_flags); dt_node_attr_assign(dnp, _dtrace_symattr); if (uref) { @@ -2793,7 +2834,7 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create) attr = dt_ident_cook(dnp, idp, NULL); else { dt_node_type_assign(dnp, - DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); + DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE); attr = idp->di_attr; } @@ -2896,7 +2937,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) xyerror(D_TYPE_ERR, "failed to lookup int64_t\n"); dt_ident_type_assign(cp->dn_ident, dtt.dtt_ctfp, dtt.dtt_type); - dt_node_type_assign(cp, dtt.dtt_ctfp, dtt.dtt_type); + dt_node_type_assign(cp, dtt.dtt_ctfp, dtt.dtt_type, + dtt.dtt_flags); } if (cp->dn_kind == DT_NODE_VAR) @@ -2913,7 +2955,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) dnp->dn_ident = &dxp->dx_souid; dt_node_type_assign(dnp, - dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type); + dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type, + cp->dn_flags & DT_NF_USERLAND); break; } @@ -2933,7 +2976,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) "cannot dereference non-pointer type\n"); } - dt_node_type_assign(dnp, cp->dn_ctfp, type); + dt_node_type_assign(dnp, cp->dn_ctfp, type, + cp->dn_flags & DT_NF_USERLAND); base = ctf_type_resolve(cp->dn_ctfp, type); kind = ctf_type_kind(cp->dn_ctfp, base); @@ -2990,7 +3034,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) xyerror(D_OP_SCALAR, "operator %s requires an operand " "of scalar type\n", opstr(dnp->dn_op)); } - dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), + B_FALSE); break; case DT_TOK_ADDROF: @@ -3023,10 +3068,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) dt_node_type_name(cp, n, sizeof (n))); } - dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type); - - if (cp->dn_flags & DT_NF_USERLAND) - dnp->dn_flags |= DT_NF_USERLAND; + dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, + cp->dn_flags & DT_NF_USERLAND); break; case DT_TOK_SIZEOF: @@ -3041,7 +3084,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) } dt_node_type_assign(dnp, dtp->dt_ddefs->dm_ctfp, - ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t")); + ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"), + B_FALSE); break; case DT_TOK_STRINGOF: @@ -3051,7 +3095,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) "cannot apply stringof to a value of type %s\n", dt_node_type_name(cp, n, sizeof (n))); } - dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp)); + dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp), + cp->dn_flags & DT_NF_USERLAND); break; case DT_TOK_PREINC: @@ -3244,7 +3289,8 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags) "of scalar type\n", opstr(op)); } - dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), + B_FALSE); dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr)); break; @@ -3288,7 +3334,8 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags) rp->dn_op = DT_TOK_INT; rp->dn_value = (intmax_t)val; - dt_node_type_assign(rp, lp->dn_ctfp, lp->dn_type); + dt_node_type_assign(rp, lp->dn_ctfp, lp->dn_type, + B_FALSE); dt_node_attr_assign(rp, _dtrace_symattr); } @@ -3320,7 +3367,8 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags) dt_node_type_name(rp, n2, sizeof (n2))); } - dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp)); + dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), + B_FALSE); dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr)); break; @@ -3368,7 +3416,7 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags) dt_node_type_name(rp, n2, sizeof (n2))); } - dt_node_type_assign(dnp, ctfp, type); + dt_node_type_assign(dnp, ctfp, type, B_FALSE); dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr)); if (uref) @@ -3509,7 +3557,7 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags) */ if (lp->dn_kind == DT_NODE_VAR && dt_ident_unref(lp->dn_ident)) { - dt_node_type_assign(lp, ctfp, type); + dt_node_type_assign(lp, ctfp, type, B_FALSE); dt_ident_type_assign(lp->dn_ident, ctfp, type); if (uref) { @@ -3723,7 +3771,7 @@ asgn_common: type = ctf_type_resolve(ctfp, m.ctm_type); kind = ctf_type_kind(ctfp, type); - dt_node_type_assign(dnp, ctfp, m.ctm_type); + dt_node_type_assign(dnp, ctfp, m.ctm_type, B_FALSE); dt_node_attr_assign(dnp, lp->dn_attr); if (op == DT_TOK_PTR && (kind != CTF_K_ARRAY || @@ -3849,7 +3897,8 @@ asgn_common: } dnp->dn_ident = dt_xlator_ident(dxp, lp->dn_ctfp, lp->dn_type); - dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); + dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), + B_FALSE); dt_node_attr_assign(dnp, dt_attr_min(rp->dn_attr, dnp->dn_ident->di_attr)); break; @@ -4014,7 +4063,7 @@ dt_cook_op3(dt_node_t *dnp, uint_t idflags) "used in a conditional context\n"); } - dt_node_type_assign(dnp, ctfp, type); + dt_node_type_assign(dnp, ctfp, type, B_FALSE); dt_node_attr_assign(dnp, dt_attr_min(dnp->dn_expr->dn_attr, dt_attr_min(lp->dn_attr, rp->dn_attr))); @@ -4047,7 +4096,8 @@ dt_cook_aggregation(dt_node_t *dnp, uint_t idflags) dt_node_attr_assign(dnp, dt_ident_cook(dnp, dnp->dn_ident, &dnp->dn_aggtup)); } else { - dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); + dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), + B_FALSE); dt_node_attr_assign(dnp, dnp->dn_ident->di_attr); } @@ -4249,7 +4299,8 @@ dt_cook_xlator(dt_node_t *dnp, uint_t idflags) } (void) dt_node_cook(mnp, DT_IDFLG_REF); - dt_node_type_assign(mnp, dxp->dx_dst_ctfp, ctm.ctm_type); + dt_node_type_assign(mnp, dxp->dx_dst_ctfp, ctm.ctm_type, + B_FALSE); attr = dt_attr_min(attr, mnp->dn_attr); if (dt_node_is_argcompat(mnp, mnp->dn_membexpr) == 0) { @@ -4268,7 +4319,7 @@ dt_cook_xlator(dt_node_t *dnp, uint_t idflags) dxp->dx_souid.di_attr = attr; dxp->dx_ptrid.di_attr = attr; - dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); + dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE); dt_node_attr_assign(dnp, _dtrace_defattr); return (dnp); @@ -4561,7 +4612,9 @@ dt_node_diftype(dtrace_hdl_t *dtp, const dt_node_t *dnp, dtrace_diftype_t *tp) ctf_type_resolve(dnp->dn_ctfp, dnp->dn_type)); } - tp->dtdt_flags = (dnp->dn_flags & DT_NF_REF) ? DIF_TF_BYREF : 0; + tp->dtdt_flags = (dnp->dn_flags & DT_NF_REF) ? + (dnp->dn_flags & DT_NF_USERLAND) ? DIF_TF_BYUREF : + DIF_TF_BYREF : 0; tp->dtdt_pad = 0; tp->dtdt_size = ctf_type_size(dnp->dn_ctfp, dnp->dn_type); } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h index 6064efb..38f21c9 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h @@ -22,12 +22,14 @@ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013 Joyent, Inc. All rights reserved. + */ #ifndef _DT_PARSER_H #define _DT_PARSER_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/dtrace.h> @@ -223,7 +225,7 @@ extern void dt_node_list_free(dt_node_t **); extern void dt_node_link_free(dt_node_t **); extern void dt_node_attr_assign(dt_node_t *, dtrace_attribute_t); -extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t); +extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t, boolean_t); extern void dt_node_type_propagate(const dt_node_t *, dt_node_t *); extern const char *dt_node_type_name(const dt_node_t *, char *, size_t); extern size_t dt_node_type_size(const dt_node_t *); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c index b145818..c865a2d 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c @@ -23,6 +23,9 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <assert.h> #include <strings.h> @@ -35,6 +38,7 @@ #endif #include <libgen.h> #include <stddef.h> +#include <sys/sysmacros.h> #include <dt_impl.h> #include <dt_program.h> @@ -43,6 +47,7 @@ #if !defined(sun) #include <libproc_compat.h> #endif +#include <dt_module.h> typedef struct dt_pid_probe { dtrace_hdl_t *dpp_dtp; @@ -827,3 +832,170 @@ dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr) return (ret); } + +/* + * libdtrace has a backroom deal with us to ask us for type information on + * behalf of pid provider probes when fasttrap doesn't return any type + * information. Instead we'll look up the module and see if there is type + * information available. However, if there is no type information available due + * to a lack of CTF data, then we want to make sure that DTrace still carries on + * in face of that. As such we don't have a meaningful exit code about failure. + * We emit information about why we failed to the dtrace debug log so someone + * can figure it out by asking nicely for DTRACE_DEBUG. + */ +void +dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, + dtrace_argdesc_t *adp, int *nargs) +{ + dt_module_t *dmp; + ctf_file_t *fp; + ctf_funcinfo_t f; + ctf_id_t argv[32]; + GElf_Sym sym; +#if defined(sun) + prsyminfo_t si; +#else + void *si; +#endif + struct ps_prochandle *p; + int i, args; + char buf[DTRACE_ARGTYPELEN]; + const char *mptr; + char *eptr; + int ret = 0; + int argc = sizeof (argv) / sizeof (ctf_id_t); + Lmid_t lmid; + + /* Set up a potential outcome */ + args = *nargs; + *nargs = 0; + + /* + * If we don't have an entry or return probe then we can just stop right + * now as we don't have arguments for offset probes. + */ + if (strcmp(pdp->dtpd_name, "entry") != 0 && + strcmp(pdp->dtpd_name, "return") != 0) + return; + + dmp = dt_module_create(dtp, pdp->dtpd_provider); + if (dmp == NULL) { + dt_dprintf("failed to find module for %s\n", + pdp->dtpd_provider); + return; + } + if (dt_module_load(dtp, dmp) != 0) { + dt_dprintf("failed to load module for %s\n", + pdp->dtpd_provider); + return; + } + + /* + * We may be working with a module that doesn't have ctf. If that's the + * case then we just return now and move on with life. + */ + fp = dt_module_getctflib(dtp, dmp, pdp->dtpd_mod); + if (fp == NULL) { + dt_dprintf("no ctf container for %s\n", + pdp->dtpd_mod); + return; + } + p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE); + if (p == NULL) { + dt_dprintf("failed to grab pid\n"); + return; + } + dt_proc_lock(dtp, p); + + /* + * Check to see if the D module has a link map ID and separate that out + * for properly interrogating libproc. + */ + if ((mptr = strchr(pdp->dtpd_mod, '`')) != NULL) { + if (strlen(pdp->dtpd_mod) < 3) { + dt_dprintf("found weird modname with linkmap, " + "aborting: %s\n", pdp->dtpd_mod); + goto out; + } + if (pdp->dtpd_mod[0] != 'L' || pdp->dtpd_mod[1] != 'M') { + dt_dprintf("missing leading 'LM', " + "aborting: %s\n", pdp->dtpd_mod); + goto out; + } + errno = 0; + lmid = strtol(pdp->dtpd_mod + 2, &eptr, 16); + if (errno == ERANGE || eptr != mptr) { + dt_dprintf("failed to parse out lmid, aborting: %s\n", + pdp->dtpd_mod); + goto out; + } + mptr++; + } else { + mptr = pdp->dtpd_mod; + lmid = 0; + } + + if (Pxlookup_by_name(p, lmid, mptr, pdp->dtpd_func, + &sym, &si) != 0) { + dt_dprintf("failed to find function %s in %s`%s\n", + pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod); + goto out; + } +#if defined(sun) + if (ctf_func_info(fp, si.prs_id, &f) == CTF_ERR) { + dt_dprintf("failed to get ctf information for %s in %s`%s\n", + pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod); + goto out; + } +#endif + + (void) snprintf(buf, sizeof (buf), "%s`%s", pdp->dtpd_provider, + pdp->dtpd_mod); + + if (strcmp(pdp->dtpd_name, "return") == 0) { + if (args < 2) + goto out; + + bzero(adp, sizeof (dtrace_argdesc_t)); + adp->dtargd_ndx = 0; + adp->dtargd_id = pdp->dtpd_id; + adp->dtargd_mapping = adp->dtargd_ndx; + /* + * We explicitly leave out the library here, we only care that + * it is some int. We are assuming that there is no ctf + * container in here that is lying about what an int is. + */ + (void) snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN, + "user %s`%s", pdp->dtpd_provider, "int"); + adp++; + bzero(adp, sizeof (dtrace_argdesc_t)); + adp->dtargd_ndx = 1; + adp->dtargd_id = pdp->dtpd_id; + adp->dtargd_mapping = adp->dtargd_ndx; + ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN, + "userland "); + (void) ctf_type_qname(fp, f.ctc_return, adp->dtargd_native + + ret, DTRACE_ARGTYPELEN - ret, buf); + *nargs = 2; +#if defined(sun) + } else { + if (ctf_func_args(fp, si.prs_id, argc, argv) == CTF_ERR) + goto out; + + *nargs = MIN(args, f.ctc_argc); + for (i = 0; i < *nargs; i++, adp++) { + bzero(adp, sizeof (dtrace_argdesc_t)); + adp->dtargd_ndx = i; + adp->dtargd_id = pdp->dtpd_id; + adp->dtargd_mapping = adp->dtargd_ndx; + ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN, + "userland "); + (void) ctf_type_qname(fp, argv[i], adp->dtargd_native + + ret, DTRACE_ARGTYPELEN - ret, buf); + } +#endif + } +out: + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); +} diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h index 886e33d..4bf39c8 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h @@ -24,12 +24,13 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #ifndef _DT_PID_H #define _DT_PID_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <libproc.h> #include <sys/fasttrap.h> #include <dt_impl.h> @@ -57,6 +58,9 @@ extern int dt_pid_create_offset_probe(struct ps_prochandle *, dtrace_hdl_t *, extern int dt_pid_create_glob_offset_probes(struct ps_prochandle *, dtrace_hdl_t *, fasttrap_probe_spec_t *, const GElf_Sym *, const char *); +extern void dt_pid_get_types(dtrace_hdl_t *, const dtrace_probedesc_t *, + dtrace_argdesc_t *, int *); + #ifdef __cplusplus } #endif diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c index ccfa3da..fb8ea16 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c @@ -647,12 +647,16 @@ dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename, dt_printarg_t pa; ctf_id_t id; dt_module_t *dmp; + ctf_file_t *ctfp; + int libid; /* * Split the fully-qualified type ID (module`id). This should * always be the format, but if for some reason we don't find the * expected value, return 0 to fall back to the generic trace() - * behavior. + * behavior. In the case of userland CTF modules this will actually be + * of the format (module`lib`id). This is due to the fact that those + * modules have multiple CTF containers which `lib` identifies. */ for (s = typename; *s != '\0' && *s != '`'; s++) ; @@ -663,6 +667,20 @@ dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename, object = alloca(s - typename + 1); bcopy(typename, object, s - typename); object[s - typename] = '\0'; + dmp = dt_module_lookup_by_name(dtp, object); + if (dmp == NULL) + return (0); + + if (dmp->dm_pid != 0) { + libid = atoi(s + 1); + s = strchr(s + 1, '`'); + if (s == NULL || libid > dmp->dm_nctflibs) + return (0); + ctfp = dmp->dm_libctfp[libid]; + } else { + ctfp = dt_module_getctf(dtp, dmp); + } + id = atoi(s + 1); /* @@ -670,16 +688,13 @@ dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename, * wrong and we can't resolve the ID, bail out and let trace() do the * work. */ - dmp = dt_module_lookup_by_name(dtp, object); - if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp), - id) == CTF_ERR) { + if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR) return (0); - } /* setup the print structure and kick off the main print routine */ pa.pa_dtp = dtp; pa.pa_addr = addr; - pa.pa_ctfp = dt_module_getctf(dtp, dmp); + pa.pa_ctfp = ctfp; pa.pa_nest = 0; pa.pa_depth = 0; pa.pa_file = fp; diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c index e4cbd21..eeb8735 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c @@ -21,8 +21,8 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #if defined(sun) @@ -1075,7 +1075,7 @@ dt_printf_validate(dt_pfargv_t *pfv, uint_t flags, xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype); bzero(&aggnode, sizeof (aggnode)); - dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type); + dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { const dt_pfconv_t *pfc = pfd->pfd_conv; diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c index 188ce0e..0f1bfe0 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c @@ -23,8 +23,9 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <sys/types.h> #if defined(sun) @@ -45,6 +46,8 @@ #include <dt_module.h> #include <dt_string.h> #include <dt_list.h> +#include <dt_pid.h> +#include <dtrace.h> static dt_provider_t * dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h) @@ -273,6 +276,21 @@ dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp) nc++; /* + * The pid provider believes in giving the kernel a break. No reason to + * give the kernel all the ctf containers that we're keeping ourselves + * just to get it back from it. So if we're coming from a pid provider + * probe and the kernel gave us no argument information we'll get some + * here. If for some crazy reason the kernel knows about our userland + * types then we just ignore this. + */ + if (xc == 0 && nc == 0 && + strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) { + nc = adc; + dt_pid_get_types(dtp, pdp, adv, &nc); + xc = nc; + } + + /* * Now that we have discovered the number of native and translated * arguments from the argument descriptions, allocate a new probe ident * and corresponding dt_probe_t and hash it into the provider. @@ -318,7 +336,8 @@ dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp) dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping], - dtt.dtt_ctfp, dtt.dtt_type); + dtt.dtt_ctfp, dtt.dtt_type, + dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE); } if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' || @@ -337,7 +356,7 @@ dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp) dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_xargv[i], - dtt.dtt_ctfp, dtt.dtt_type); + dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); } prp->pr_mapping[i] = adp->dtargd_mapping; @@ -638,7 +657,7 @@ dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp) bzero(dnp, sizeof (dt_node_t)); dnp->dn_kind = DT_NODE_TYPE; - dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type); + dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); dt_node_attr_assign(dnp, _dtrace_defattr); return (dnp); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c index 7ac0cc4..74bd487 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c @@ -23,8 +23,10 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013 Joyent, Inc. All rights reserved. + */ #include <strings.h> #include <assert.h> @@ -69,7 +71,7 @@ dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg) enp->dn_op = DT_TOK_XLATE; enp->dn_xlator = dxp; enp->dn_xmember = mnp; - dt_node_type_assign(enp, dxp->dx_dst_ctfp, type); + dt_node_type_assign(enp, dxp->dx_dst_ctfp, type, B_FALSE); /* * For the member itself, we use a DT_NODE_MEMBER as usual with the @@ -83,7 +85,7 @@ dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg) mnp->dn_membname = strdup(name); mnp->dn_membexpr = enp; - dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type); + dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type, B_FALSE); if (mnp->dn_membname == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); @@ -318,7 +320,8 @@ dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags) for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = dt_list_next(dxp)) { - dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type); + dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type, + B_FALSE); if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base, dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn)) goto out; diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h index b2e3108..6f88e6d 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h @@ -25,7 +25,8 @@ */ /* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #ifndef _DTRACE_H @@ -356,6 +357,12 @@ extern int dtrace_handle_setopt(dtrace_hdl_t *, #define DTRACE_A_PERCPU 0x0001 #define DTRACE_A_KEEPDELTA 0x0002 #define DTRACE_A_ANONYMOUS 0x0004 +#define DTRACE_A_TOTAL 0x0008 +#define DTRACE_A_MINMAXBIN 0x0010 +#define DTRACE_A_HASNEGATIVES 0x0020 +#define DTRACE_A_HASPOSITIVES 0x0040 + +#define DTRACE_AGGZOOM_MAX 0.95 /* height of max bar */ #define DTRACE_AGGWALK_ERROR -1 /* error while processing */ #define DTRACE_AGGWALK_NEXT 0 /* proceed to next element */ @@ -376,6 +383,10 @@ struct dtrace_aggdata { caddr_t dtada_delta; /* delta data, if available */ caddr_t *dtada_percpu; /* per CPU data, if avail */ caddr_t *dtada_percpu_delta; /* per CPU delta, if avail */ + int64_t dtada_total; /* per agg total, if avail */ + uint16_t dtada_minbin; /* minimum bin, if avail */ + uint16_t dtada_maxbin; /* maximum bin, if avail */ + uint32_t dtada_flags; /* flags */ }; typedef int dtrace_aggregate_f(const dtrace_aggdata_t *, void *); @@ -495,8 +506,11 @@ typedef struct dtrace_typeinfo { const char *dtt_object; /* object containing type */ ctf_file_t *dtt_ctfp; /* CTF container handle */ ctf_id_t dtt_type; /* CTF type identifier */ + uint_t dtt_flags; /* Misc. flags */ } dtrace_typeinfo_t; +#define DTT_FL_USER 0x1 /* user type */ + extern int dtrace_lookup_by_type(dtrace_hdl_t *, const char *, const char *, dtrace_typeinfo_t *); diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h index 24131d6..ef18b45 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h @@ -42,6 +42,7 @@ #include <sys/fs/zfs.h> #include <sys/avl.h> #include <sys/zfs_ioctl.h> +#include <libzfs_core.h> #ifdef __cplusplus extern "C" { @@ -607,13 +608,16 @@ typedef struct sendflags { /* show progress (ie. -v) */ boolean_t progress; + + /* WRITE_EMBEDDED records of type DATA are permitted */ + boolean_t embed_data; } sendflags_t; typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *); extern int zfs_send(zfs_handle_t *, const char *, const char *, sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **); -extern int zfs_send_one(zfs_handle_t *, const char *, int); +extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags); extern int zfs_promote(zfs_handle_t *); extern int zfs_hold(zfs_handle_t *, const char *, const char *, diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c index 3c8119d..a3f6129 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c @@ -72,16 +72,23 @@ zcmd_ioctl(int fd, int request, zfs_cmd_t *zc) if (zfs_ioctl_version == ZFS_IOCVER_UNDEF) zfs_ioctl_version = get_zfs_ioctl_version(); - if (zfs_ioctl_version == ZFS_IOCVER_LZC) - cflag = ZFS_CMD_COMPAT_LZC; - else if (zfs_ioctl_version == ZFS_IOCVER_DEADMAN) - cflag = ZFS_CMD_COMPAT_DEADMAN; - - /* - * If vfs.zfs.version.ioctl is not defined, assume we have v28 - * compatible binaries and use vfs.zfs.version.spa to test for v15 - */ - if (zfs_ioctl_version < ZFS_IOCVER_DEADMAN) { + if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) { + switch (zfs_ioctl_version) { + case ZFS_IOCVER_ZCMD: + cflag = ZFS_CMD_COMPAT_ZCMD; + break; + case ZFS_IOCVER_LZC: + cflag = ZFS_CMD_COMPAT_LZC; + break; + case ZFS_IOCVER_DEADMAN: + cflag = ZFS_CMD_COMPAT_DEADMAN; + break; + } + } else { + /* + * If vfs.zfs.version.ioctl is not defined, assume we have v28 + * compatible binaries and use vfs.zfs.version.spa to test for v15 + */ cflag = ZFS_CMD_COMPAT_V28; if (zfs_spa_version < 0) diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c index 11378a2..d7126bf 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c @@ -22,7 +22,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. - * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>. * All rights reserved. @@ -3873,7 +3873,6 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target, strcmp(property, "none") == 0)) { flags.nounmount = B_TRUE; } - if (flags.recurse) { parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); @@ -3888,8 +3887,7 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target, ret = -1; goto error; } - - } else { + } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) { if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, flags.forceunmount ? MS_FORCE : 0)) == NULL) { @@ -3941,23 +3939,23 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target, * On failure, we still want to remount any filesystems that * were previously mounted, so we don't alter the system state. */ - if (!flags.recurse) + if (cl != NULL) (void) changelist_postfix(cl); } else { - if (!flags.recurse) { + if (cl != NULL) { changelist_rename(cl, zfs_get_name(zhp), target); ret = changelist_postfix(cl); } } error: - if (parentname) { + if (parentname != NULL) { free(parentname); } - if (zhrp) { + if (zhrp != NULL) { zfs_close(zhrp); } - if (cl) { + if (cl != NULL) { changelist_free(cl); } return (ret); diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c index e53a8cd..868961d 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c @@ -94,6 +94,7 @@ typedef struct pool_list { static char * get_devid(const char *path) { +#ifdef have_devid int fd; ddi_devid_t devid; char *minor, *ret; @@ -113,6 +114,9 @@ get_devid(const char *path) (void) close(fd); return (ret); +#else + return (NULL); +#endif } diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c index b2959dd..f8596ed 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014 by Delphix. All rights reserved. */ /* @@ -736,16 +737,6 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) return (0); -#ifdef sun - if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { - (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, - dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), - zfs_get_name(zhp), _sa_errorstr != NULL ? - _sa_errorstr(ret) : ""); - return (-1); - } -#endif - for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { /* * Return success if there are no share options. @@ -756,6 +747,17 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) strcmp(shareopts, "off") == 0) continue; +#ifdef illumos + ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API); + if (ret != SA_OK) { + (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, + dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), + zfs_get_name(zhp), _sa_errorstr != NULL ? + _sa_errorstr(ret) : ""); + return (-1); + } +#endif + /* * If the 'zoned' property is set, then zfs_is_mountable() * will have already bailed out if we are in the global zone. diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c index 8dd24a7..30b2d87 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c @@ -22,7 +22,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2012, 2014 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ @@ -303,6 +303,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, case ZPOOL_PROP_ALLOCATED: case ZPOOL_PROP_FREE: case ZPOOL_PROP_FREEING: + case ZPOOL_PROP_LEAKED: case ZPOOL_PROP_EXPANDSZ: if (literal) { (void) snprintf(buf, len, "%llu", @@ -321,6 +322,14 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, (u_longlong_t)intval); } break; + case ZPOOL_PROP_FRAGMENTATION: + if (intval == UINT64_MAX) { + (void) strlcpy(buf, "-", len); + } else { + (void) snprintf(buf, len, "%llu%%", + (u_longlong_t)intval); + } + break; case ZPOOL_PROP_DEDUPRATIO: (void) snprintf(buf, len, "%llu.%02llux", @@ -3324,6 +3333,7 @@ devid_to_path(char *devid_str) static char * path_to_devid(const char *path) { +#ifdef have_devid int fd; ddi_devid_t devid; char *minor, *ret; @@ -3343,6 +3353,9 @@ path_to_devid(const char *path) (void) close(fd); return (ret); +#else + return (NULL); +#endif } /* @@ -3508,7 +3521,7 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, static int zbookmark_compare(const void *a, const void *b) { - return (memcmp(a, b, sizeof (zbookmark_t))); + return (memcmp(a, b, sizeof (zbookmark_phys_t))); } /* @@ -3520,7 +3533,7 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) { zfs_cmd_t zc = { 0 }; uint64_t count; - zbookmark_t *zb = NULL; + zbookmark_phys_t *zb = NULL; int i; /* @@ -3533,7 +3546,7 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) if (count == 0) return (0); if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, - count * sizeof (zbookmark_t))) == (uintptr_t)NULL) + count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL) return (-1); zc.zc_nvlist_dst_size = count; (void) strcpy(zc.zc_name, zhp->zpool_name); @@ -3542,11 +3555,14 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) &zc) != 0) { free((void *)(uintptr_t)zc.zc_nvlist_dst); if (errno == ENOMEM) { + void *dst; + count = zc.zc_nvlist_dst_size; - if ((zc.zc_nvlist_dst = (uintptr_t) - zfs_alloc(zhp->zpool_hdl, count * - sizeof (zbookmark_t))) == (uintptr_t)NULL) + dst = zfs_alloc(zhp->zpool_hdl, count * + sizeof (zbookmark_phys_t)); + if (dst == NULL) return (-1); + zc.zc_nvlist_dst = (uintptr_t)dst; } else { return (-1); } @@ -3562,11 +3578,11 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) * _not_ copied as part of the process. So we point the start of our * array appropriate and decrement the total number of elements. */ - zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + + zb = ((zbookmark_phys_t *)(uintptr_t)zc.zc_nvlist_dst) + zc.zc_nvlist_dst_size; count -= zc.zc_nvlist_dst_size; - qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); + qsort(zb, count, sizeof (zbookmark_phys_t), zbookmark_compare); verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c index feddb69..97f18d7 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>. * All rights reserved. @@ -45,6 +45,7 @@ #include <time.h> #include <libzfs.h> +#include <libzfs_core.h> #include "zfs_namecheck.h" #include "zfs_prop.h" @@ -222,6 +223,7 @@ cksummer(void *arg) struct drr_object *drro = &thedrr.drr_u.drr_object; struct drr_write *drrw = &thedrr.drr_u.drr_write; struct drr_spill *drrs = &thedrr.drr_u.drr_spill; + struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded; FILE *ofp; int outfd; dmu_replay_record_t wbr_drr = {0}; @@ -418,6 +420,20 @@ cksummer(void *arg) break; } + case DRR_WRITE_EMBEDDED: + { + if (cksum_and_write(drr, sizeof (dmu_replay_record_t), + &stream_cksum, outfd) == -1) + goto out; + (void) ssread(buf, + P2ROUNDUP((uint64_t)drrwe->drr_psize, 8), ofp); + if (cksum_and_write(buf, + P2ROUNDUP((uint64_t)drrwe->drr_psize, 8), + &stream_cksum, outfd) == -1) + goto out; + break; + } + case DRR_FREE: { if (cksum_and_write(drr, sizeof (dmu_replay_record_t), @@ -799,7 +815,7 @@ typedef struct send_dump_data { char prevsnap[ZFS_MAXNAMELEN]; uint64_t prevsnap_obj; boolean_t seenfrom, seento, replicate, doall, fromorigin; - boolean_t verbose, dryrun, parsable, progress; + boolean_t verbose, dryrun, parsable, progress, embed_data; int outfd; boolean_t err; nvlist_t *fss; @@ -878,7 +894,8 @@ estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj, */ static int dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj, - boolean_t fromorigin, int outfd, nvlist_t *debugnv) + boolean_t fromorigin, int outfd, enum lzc_send_flags flags, + nvlist_t *debugnv) { zfs_cmd_t zc = { 0 }; libzfs_handle_t *hdl = zhp->zfs_hdl; @@ -892,6 +909,7 @@ dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj, zc.zc_obj = fromorigin; zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); zc.zc_fromobj = fromsnap_obj; + zc.zc_flags = flags; VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0)); if (fromsnap && fromsnap[0] != '\0') { @@ -1144,8 +1162,12 @@ dump_snapshot(zfs_handle_t *zhp, void *arg) } } + enum lzc_send_flags flags = 0; + if (sdd->embed_data) + flags |= LZC_SEND_FLAG_EMBED_DATA; + err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj, - fromorigin, sdd->outfd, sdd->debugnv); + fromorigin, sdd->outfd, flags, sdd->debugnv); if (sdd->progress) { (void) pthread_cancel(tid); @@ -1489,6 +1511,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, sdd.parsable = flags->parsable; sdd.progress = flags->progress; sdd.dryrun = flags->dryrun; + sdd.embed_data = flags->embed_data; sdd.filter_cb = filter_func; sdd.filter_cb_arg = cb_arg; if (debugnvp) @@ -1620,7 +1643,8 @@ err_out: } int -zfs_send_one(zfs_handle_t *zhp, const char *from, int fd) +zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, + enum lzc_send_flags flags) { int err; libzfs_handle_t *hdl = zhp->zfs_hdl; @@ -1629,7 +1653,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd) (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "warning: cannot send '%s'"), zhp->zfs_name); - err = lzc_send(zhp->zfs_name, from, fd); + err = lzc_send(zhp->zfs_name, from, fd, flags); if (err != 0) { switch (errno) { case EXDEV: @@ -2576,6 +2600,16 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap) (void) recv_read(hdl, fd, buf, drr->drr_u.drr_spill.drr_length, B_FALSE, NULL); break; + case DRR_WRITE_EMBEDDED: + if (byteswap) { + drr->drr_u.drr_write_embedded.drr_psize = + BSWAP_32(drr->drr_u.drr_write_embedded. + drr_psize); + } + (void) recv_read(hdl, fd, buf, + P2ROUNDUP(drr->drr_u.drr_write_embedded.drr_psize, + 8), B_FALSE, NULL); + break; case DRR_WRITE_BYREF: case DRR_FREEOBJECTS: case DRR_FREE: diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c index 1c87223..cb38dc2 100644 --- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c +++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c @@ -486,6 +486,8 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp) } /* + * Generate a zfs send stream for the specified snapshot and write it to + * the specified file descriptor. * * "snapname" is the full name of the snapshot to send (e.g. "pool/fs@snap") * @@ -499,9 +501,15 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp) * snapshot in the origin, etc. * * "fd" is the file descriptor to write the send stream to. + * + * If "flags" contains LZC_SEND_FLAG_EMBED_DATA, the stream is permitted + * to contain DRR_WRITE_EMBEDDED records with drr_etype==BP_EMBEDDED_TYPE_DATA, + * which the receiving system must support (as indicated by support + * for the "embedded_data" feature). */ int -lzc_send(const char *snapname, const char *from, int fd) +lzc_send(const char *snapname, const char *from, int fd, + enum lzc_send_flags flags) { nvlist_t *args; int err; @@ -510,6 +518,8 @@ lzc_send(const char *snapname, const char *from, int fd) fnvlist_add_int32(args, "fd", fd); if (from != NULL) fnvlist_add_string(args, "fromsnap", from); + if (flags & LZC_SEND_FLAG_EMBED_DATA) + fnvlist_add_boolean(args, "embedok"); err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL); nvlist_free(args); return (err); diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h index 380560f..99883fe 100644 --- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h +++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h @@ -53,7 +53,11 @@ int lzc_hold(nvlist_t *, int, nvlist_t **); int lzc_release(nvlist_t *, nvlist_t **); int lzc_get_holds(const char *, nvlist_t **); -int lzc_send(const char *, const char *, int); +enum lzc_send_flags { + LZC_SEND_FLAG_EMBED_DATA = 1 << 0 +}; + +int lzc_send(const char *, const char *, int, enum lzc_send_flags); int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int); int lzc_send_space(const char *, const char *, uint64_t *); diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c index 2b174f9..c61c5c2 100644 --- a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c +++ b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c @@ -31,6 +31,7 @@ #include <stdlib.h> #include <string.h> #include <zlib.h> +#include <libgen.h> #include <sys/spa.h> #include <sys/stat.h> #include <sys/processor.h> @@ -52,6 +53,9 @@ char hw_serial[HW_HOSTID_LEN]; kmutex_t cpu_lock; #endif +/* If set, all blocks read will be copied to the specified directory. */ +char *vn_dumpdir = NULL; + struct utsname utsname = { "userland", "libzpool", "1", "1", "na" }; @@ -415,6 +419,7 @@ int vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3) { int fd; + int dump_fd; vnode_t *vp; int old_umask; char realpath[MAXPATHLEN]; @@ -463,6 +468,17 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3) if (flags & FCREAT) (void) umask(old_umask); + if (vn_dumpdir != NULL) { + char dumppath[MAXPATHLEN]; + (void) snprintf(dumppath, sizeof (dumppath), + "%s/%s", vn_dumpdir, basename(realpath)); + dump_fd = open64(dumppath, O_CREAT | O_WRONLY, 0666); + if (dump_fd == -1) + return (errno); + } else { + dump_fd = -1; + } + if (fd == -1) return (errno); @@ -478,6 +494,7 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3) vp->v_fd = fd; vp->v_size = st.st_size; vp->v_path = spa_strdup(path); + vp->v_dump_fd = dump_fd; return (0); } @@ -510,6 +527,11 @@ vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset, if (uio == UIO_READ) { iolen = pread64(vp->v_fd, addr, len, offset); + if (vp->v_dump_fd != -1) { + int status = + pwrite64(vp->v_dump_fd, addr, iolen, offset); + ASSERT(status != -1); + } } else { /* * To simulate partial disk writes, we split writes into two @@ -536,6 +558,8 @@ void vn_close(vnode_t *vp, int openflag, cred_t *cr, kthread_t *td) { close(vp->v_fd); + if (vp->v_dump_fd != -1) + close(vp->v_dump_fd); spa_strfree(vp->v_path); umem_free(vp, sizeof (vnode_t)); } diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h index cc8285d..03027c3 100644 --- a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h +++ b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h @@ -424,8 +424,10 @@ typedef struct vnode { uint64_t v_size; int v_fd; char *v_path; + int v_dump_fd; } vnode_t; +extern char *vn_dumpdir; #define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */ typedef struct xoptattr { |