10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <stdlib.h> 300Sstevel@tonic-gate #include <strings.h> 310Sstevel@tonic-gate #include <errno.h> 320Sstevel@tonic-gate #include <unistd.h> 330Sstevel@tonic-gate #include <limits.h> 340Sstevel@tonic-gate #include <assert.h> 350Sstevel@tonic-gate #include <ctype.h> 360Sstevel@tonic-gate #include <alloca.h> 37*457Sbmc #include <dt_impl.h> 380Sstevel@tonic-gate 39*457Sbmc /* 40*457Sbmc * We declare this here because (1) we need it and (2) we want to avoid a 41*457Sbmc * dependency on libm in libdtrace. 42*457Sbmc */ 43*457Sbmc static long double 44*457Sbmc dt_fabsl(long double x) 45*457Sbmc { 46*457Sbmc if (x < 0) 47*457Sbmc return (-x); 48*457Sbmc 49*457Sbmc return (x); 50*457Sbmc } 510Sstevel@tonic-gate 520Sstevel@tonic-gate static int 530Sstevel@tonic-gate dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, 540Sstevel@tonic-gate dtrace_bufdesc_t *buf, size_t offs) 550Sstevel@tonic-gate { 560Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; 570Sstevel@tonic-gate dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; 58*457Sbmc char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub; 590Sstevel@tonic-gate dtrace_flowkind_t flow = DTRACEFLOW_NONE; 600Sstevel@tonic-gate const char *str = NULL; 610Sstevel@tonic-gate static const char *e_str[2] = { " -> ", " => " }; 620Sstevel@tonic-gate static const char *r_str[2] = { " <- ", " <= " }; 63*457Sbmc static const char *ent = "entry", *ret = "return"; 64*457Sbmc static int entlen = 0, retlen = 0; 650Sstevel@tonic-gate dtrace_epid_t next, id = epd->dtepd_epid; 660Sstevel@tonic-gate int rval; 670Sstevel@tonic-gate 68*457Sbmc if (entlen == 0) { 69*457Sbmc assert(retlen == 0); 70*457Sbmc entlen = strlen(ent); 71*457Sbmc retlen = strlen(ret); 72*457Sbmc } 73*457Sbmc 74*457Sbmc /* 75*457Sbmc * If the name of the probe is "entry" or ends with "-entry", we 76*457Sbmc * treat it as an entry; if it is "return" or ends with "-return", 77*457Sbmc * we treat it as a return. (This allows application-provided probes 78*457Sbmc * like "method-entry" or "function-entry" to participate in flow 79*457Sbmc * indentation -- without accidentally misinterpreting popular probe 80*457Sbmc * names like "carpentry", "gentry" or "Coventry".) 81*457Sbmc */ 82*457Sbmc if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' && 83*457Sbmc (sub == n || sub[-1] == '-')) { 840Sstevel@tonic-gate flow = DTRACEFLOW_ENTRY; 850Sstevel@tonic-gate str = e_str[strcmp(p, "syscall") == 0]; 86*457Sbmc } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' && 87*457Sbmc (sub == n || sub[-1] == '-')) { 880Sstevel@tonic-gate flow = DTRACEFLOW_RETURN; 890Sstevel@tonic-gate str = r_str[strcmp(p, "syscall") == 0]; 900Sstevel@tonic-gate } 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * If we're going to indent this, we need to check the ID of our last 940Sstevel@tonic-gate * call. If we're looking at the same probe ID but a different EPID, 950Sstevel@tonic-gate * we _don't_ want to indent. (Yes, there are some minor holes in 960Sstevel@tonic-gate * this scheme -- it's a heuristic.) 970Sstevel@tonic-gate */ 980Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY) { 990Sstevel@tonic-gate if ((last != DTRACE_EPIDNONE && id != last && 1000Sstevel@tonic-gate pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) 1010Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /* 1050Sstevel@tonic-gate * If we're going to unindent this, it's more difficult to see if 1060Sstevel@tonic-gate * we don't actually want to unindent it -- we need to look at the 1070Sstevel@tonic-gate * _next_ EPID. 1080Sstevel@tonic-gate */ 1090Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN) { 1100Sstevel@tonic-gate offs += epd->dtepd_size; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate do { 1130Sstevel@tonic-gate if (offs >= buf->dtbd_size) { 1140Sstevel@tonic-gate /* 1150Sstevel@tonic-gate * We're at the end -- maybe. If the oldest 1160Sstevel@tonic-gate * record is non-zero, we need to wrap. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate if (buf->dtbd_oldest != 0) { 1190Sstevel@tonic-gate offs = 0; 1200Sstevel@tonic-gate } else { 1210Sstevel@tonic-gate goto out; 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if (next == DTRACE_EPIDNONE) 1280Sstevel@tonic-gate offs += sizeof (id); 1290Sstevel@tonic-gate } while (next == DTRACE_EPIDNONE); 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) 1320Sstevel@tonic-gate return (rval); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate if (next != id && npd->dtpd_id == pd->dtpd_id) 1350Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate out: 1390Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { 1400Sstevel@tonic-gate data->dtpda_prefix = str; 1410Sstevel@tonic-gate } else { 1420Sstevel@tonic-gate data->dtpda_prefix = "| "; 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) 1460Sstevel@tonic-gate data->dtpda_indent -= 2; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate data->dtpda_flow = flow; 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate return (0); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate static int 1540Sstevel@tonic-gate dt_nullprobe() 1550Sstevel@tonic-gate { 1560Sstevel@tonic-gate return (DTRACE_CONSUME_THIS); 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static int 1600Sstevel@tonic-gate dt_nullrec() 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate int 166*457Sbmc dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 167*457Sbmc uint64_t normal, long double total, char positives, char negatives) 168*457Sbmc { 169*457Sbmc long double f; 170*457Sbmc uint_t depth, len = 40; 171*457Sbmc 172*457Sbmc const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; 173*457Sbmc const char *spaces = " "; 174*457Sbmc 175*457Sbmc assert(strlen(ats) == len && strlen(spaces) == len); 176*457Sbmc assert(!(total == 0 && (positives || negatives))); 177*457Sbmc assert(!(val < 0 && !negatives)); 178*457Sbmc assert(!(val > 0 && !positives)); 179*457Sbmc assert(!(val != 0 && total == 0)); 180*457Sbmc 181*457Sbmc if (!negatives) { 182*457Sbmc if (positives) { 183*457Sbmc f = (dt_fabsl((long double)val) * len) / total; 184*457Sbmc depth = (uint_t)(f + 0.5); 185*457Sbmc } else { 186*457Sbmc depth = 0; 187*457Sbmc } 188*457Sbmc 189*457Sbmc return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth, 190*457Sbmc spaces + depth, (long long)val / normal)); 191*457Sbmc } 192*457Sbmc 193*457Sbmc if (!positives) { 194*457Sbmc f = (dt_fabsl((long double)val) * len) / total; 195*457Sbmc depth = (uint_t)(f + 0.5); 196*457Sbmc 197*457Sbmc return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth, 198*457Sbmc ats + len - depth, (long long)val / normal)); 199*457Sbmc } 200*457Sbmc 201*457Sbmc /* 202*457Sbmc * If we're here, we have both positive and negative bucket values. 203*457Sbmc * To express this graphically, we're going to generate both positive 204*457Sbmc * and negative bars separated by a centerline. These bars are half 205*457Sbmc * the size of normal quantize()/lquantize() bars, so we divide the 206*457Sbmc * length in half before calculating the bar length. 207*457Sbmc */ 208*457Sbmc len /= 2; 209*457Sbmc ats = &ats[len]; 210*457Sbmc spaces = &spaces[len]; 211*457Sbmc 212*457Sbmc f = (dt_fabsl((long double)val) * len) / total; 213*457Sbmc depth = (uint_t)(f + 0.5); 214*457Sbmc 215*457Sbmc if (val <= 0) { 216*457Sbmc return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth, 217*457Sbmc ats + len - depth, len, "", (long long)val / normal)); 218*457Sbmc } else { 219*457Sbmc return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "", 220*457Sbmc ats + len - depth, spaces + depth, 221*457Sbmc (long long)val / normal)); 222*457Sbmc } 223*457Sbmc } 224*457Sbmc 225*457Sbmc int 2260Sstevel@tonic-gate dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 2270Sstevel@tonic-gate size_t size, uint64_t normal) 2280Sstevel@tonic-gate { 229*457Sbmc const int64_t *data = addr; 2300Sstevel@tonic-gate int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; 231*457Sbmc long double total = 0; 232*457Sbmc char positives = 0, negatives = 0; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 2350Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) 2380Sstevel@tonic-gate first_bin++; 2390Sstevel@tonic-gate 240*457Sbmc if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) { 241*457Sbmc /* 242*457Sbmc * There isn't any data. This is possible if (and only if) 243*457Sbmc * negative increment values have been used. In this case, 244*457Sbmc * we'll print the buckets around 0. 245*457Sbmc */ 246*457Sbmc first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1; 247*457Sbmc last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1; 248*457Sbmc } else { 249*457Sbmc if (first_bin > 0) 250*457Sbmc first_bin--; 2510Sstevel@tonic-gate 252*457Sbmc while (last_bin > 0 && data[last_bin] == 0) 253*457Sbmc last_bin--; 2540Sstevel@tonic-gate 255*457Sbmc if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) 256*457Sbmc last_bin++; 257*457Sbmc } 258*457Sbmc 259*457Sbmc for (i = first_bin; i <= last_bin; i++) { 260*457Sbmc positives |= (data[i] > 0); 261*457Sbmc negatives |= (data[i] < 0); 262*457Sbmc total += dt_fabsl((long double)data[i]); 263*457Sbmc } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 2660Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0) 2670Sstevel@tonic-gate return (-1); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 270*457Sbmc if (dt_printf(dtp, fp, "%16lld ", 271*457Sbmc (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0) 272*457Sbmc return (-1); 2730Sstevel@tonic-gate 274*457Sbmc if (dt_print_quantline(dtp, fp, data[i], normal, total, 275*457Sbmc positives, negatives) < 0) 2760Sstevel@tonic-gate return (-1); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate return (0); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate int 2830Sstevel@tonic-gate dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 2840Sstevel@tonic-gate size_t size, uint64_t normal) 2850Sstevel@tonic-gate { 286*457Sbmc const int64_t *data = addr; 2870Sstevel@tonic-gate int i, first_bin, last_bin, base; 288*457Sbmc uint64_t arg; 289*457Sbmc long double total = 0; 2900Sstevel@tonic-gate uint16_t step, levels; 291*457Sbmc char positives = 0, negatives = 0; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate if (size < sizeof (uint64_t)) 2940Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate arg = *data++; 2970Sstevel@tonic-gate size -= sizeof (uint64_t); 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate base = DTRACE_LQUANTIZE_BASE(arg); 3000Sstevel@tonic-gate step = DTRACE_LQUANTIZE_STEP(arg); 3010Sstevel@tonic-gate levels = DTRACE_LQUANTIZE_LEVELS(arg); 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate first_bin = 0; 3040Sstevel@tonic-gate last_bin = levels + 1; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if (size != sizeof (uint64_t) * (levels + 2)) 3070Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate while (first_bin < levels + 1 && data[first_bin] == 0) 3100Sstevel@tonic-gate first_bin++; 3110Sstevel@tonic-gate 312*457Sbmc if (first_bin == levels + 1) { 313*457Sbmc first_bin = 0; 314*457Sbmc last_bin = 2; 315*457Sbmc } else { 316*457Sbmc if (first_bin > 0) 317*457Sbmc first_bin--; 3180Sstevel@tonic-gate 319*457Sbmc while (last_bin > 0 && data[last_bin] == 0) 320*457Sbmc last_bin--; 3210Sstevel@tonic-gate 322*457Sbmc if (last_bin < levels + 1) 323*457Sbmc last_bin++; 324*457Sbmc } 3250Sstevel@tonic-gate 326*457Sbmc for (i = first_bin; i <= last_bin; i++) { 327*457Sbmc positives |= (data[i] > 0); 328*457Sbmc negatives |= (data[i] < 0); 329*457Sbmc total += dt_fabsl((long double)data[i]); 330*457Sbmc } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 3330Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0) 3340Sstevel@tonic-gate return (-1); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 3370Sstevel@tonic-gate char c[32]; 3380Sstevel@tonic-gate int err; 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if (i == 0) { 3410Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "< %d", 3420Sstevel@tonic-gate base / (uint32_t)normal); 3430Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 3440Sstevel@tonic-gate } else if (i == levels + 1) { 3450Sstevel@tonic-gate (void) snprintf(c, sizeof (c), ">= %d", 3460Sstevel@tonic-gate base + (levels * step)); 3470Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 3480Sstevel@tonic-gate } else { 3490Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16d ", 3500Sstevel@tonic-gate base + (i - 1) * step); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 353*457Sbmc if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal, 354*457Sbmc total, positives, negatives) < 0) 3550Sstevel@tonic-gate return (-1); 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate return (0); 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate /*ARGSUSED*/ 3620Sstevel@tonic-gate static int 3630Sstevel@tonic-gate dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 3640Sstevel@tonic-gate size_t size, uint64_t normal) 3650Sstevel@tonic-gate { 3660Sstevel@tonic-gate /* LINTED - alignment */ 3670Sstevel@tonic-gate uint64_t *data = (uint64_t *)addr; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate return (dt_printf(dtp, fp, " %16lld", data[0] ? 3700Sstevel@tonic-gate (long long)(data[1] / normal / data[0]) : 0)); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /*ARGSUSED*/ 3740Sstevel@tonic-gate int 3750Sstevel@tonic-gate dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 3760Sstevel@tonic-gate size_t nbytes, int width, int quiet) 3770Sstevel@tonic-gate { 3780Sstevel@tonic-gate /* 3790Sstevel@tonic-gate * If the byte stream is a series of printable characters, followed by 3800Sstevel@tonic-gate * a terminating byte, we print it out as a string. Otherwise, we 3810Sstevel@tonic-gate * assume that it's something else and just print the bytes. 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate int i, j, margin = 5; 3840Sstevel@tonic-gate char *c = (char *)addr; 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate if (nbytes == 0) 3870Sstevel@tonic-gate return (0); 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) 3900Sstevel@tonic-gate goto raw; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate for (i = 0; i < nbytes; i++) { 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * We define a "printable character" to be one for which 3950Sstevel@tonic-gate * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 3960Sstevel@tonic-gate * or a character which is either backspace or the bell. 3970Sstevel@tonic-gate * Backspace and the bell are regrettably special because 3980Sstevel@tonic-gate * they fail the first two tests -- and yet they are entirely 3990Sstevel@tonic-gate * printable. These are the only two control characters that 4000Sstevel@tonic-gate * have meaning for the terminal and for which isprint(3C) and 4010Sstevel@tonic-gate * isspace(3C) return 0. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate if (isprint(c[i]) || isspace(c[i]) || 4040Sstevel@tonic-gate c[i] == '\b' || c[i] == '\a') 4050Sstevel@tonic-gate continue; 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate if (c[i] == '\0' && i > 0) { 4080Sstevel@tonic-gate /* 4090Sstevel@tonic-gate * This looks like it might be a string. Before we 4100Sstevel@tonic-gate * assume that it is indeed a string, check the 4110Sstevel@tonic-gate * remainder of the byte range; if it contains 4120Sstevel@tonic-gate * additional non-nul characters, we'll assume that 4130Sstevel@tonic-gate * it's a binary stream that just happens to look like 4140Sstevel@tonic-gate * a string, and we'll print out the individual bytes. 4150Sstevel@tonic-gate */ 4160Sstevel@tonic-gate for (j = i + 1; j < nbytes; j++) { 4170Sstevel@tonic-gate if (c[j] != '\0') 4180Sstevel@tonic-gate break; 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate if (j != nbytes) 4220Sstevel@tonic-gate break; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (quiet) 4250Sstevel@tonic-gate return (dt_printf(dtp, fp, "%s", c)); 4260Sstevel@tonic-gate else 4270Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, c)); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate break; 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate if (i == nbytes) { 4340Sstevel@tonic-gate /* 4350Sstevel@tonic-gate * The byte range is all printable characters, but there is 4360Sstevel@tonic-gate * no trailing nul byte. We'll assume that it's a string and 4370Sstevel@tonic-gate * print it as such. 4380Sstevel@tonic-gate */ 4390Sstevel@tonic-gate char *s = alloca(nbytes + 1); 4400Sstevel@tonic-gate bcopy(c, s, nbytes); 4410Sstevel@tonic-gate s[nbytes] = '\0'; 4420Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, s)); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate raw: 4460Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) 4470Sstevel@tonic-gate return (-1); 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate for (i = 0; i < 16; i++) 4500Sstevel@tonic-gate if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) 4510Sstevel@tonic-gate return (-1); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) 4540Sstevel@tonic-gate return (-1); 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate for (i = 0; i < nbytes; i += 16) { 4580Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) 4590Sstevel@tonic-gate return (-1); 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 4620Sstevel@tonic-gate if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) 4630Sstevel@tonic-gate return (-1); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate while (j++ % 16) { 4670Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 4680Sstevel@tonic-gate return (-1); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 4720Sstevel@tonic-gate return (-1); 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 4750Sstevel@tonic-gate if (dt_printf(dtp, fp, "%c", 4760Sstevel@tonic-gate c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) 4770Sstevel@tonic-gate return (-1); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 4810Sstevel@tonic-gate return (-1); 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate return (0); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate int 4880Sstevel@tonic-gate dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 489*457Sbmc caddr_t addr, int depth, int size) 4900Sstevel@tonic-gate { 4910Sstevel@tonic-gate dtrace_syminfo_t dts; 4920Sstevel@tonic-gate GElf_Sym sym; 4930Sstevel@tonic-gate int i, indent; 4940Sstevel@tonic-gate char c[PATH_MAX * 2]; 495*457Sbmc uint64_t pc; 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 4980Sstevel@tonic-gate return (-1); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate if (format == NULL) 5010Sstevel@tonic-gate format = "%s"; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 5040Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 5050Sstevel@tonic-gate else 5060Sstevel@tonic-gate indent = _dtrace_stkindent; 5070Sstevel@tonic-gate 508*457Sbmc for (i = 0; i < depth; i++) { 509*457Sbmc switch (size) { 510*457Sbmc case sizeof (uint32_t): 511*457Sbmc /* LINTED - alignment */ 512*457Sbmc pc = *((uint32_t *)addr); 513*457Sbmc break; 514*457Sbmc 515*457Sbmc case sizeof (uint64_t): 516*457Sbmc /* LINTED - alignment */ 517*457Sbmc pc = *((uint64_t *)addr); 518*457Sbmc break; 519*457Sbmc 520*457Sbmc default: 521*457Sbmc return (dt_set_errno(dtp, EDT_BADSTACKPC)); 522*457Sbmc } 523*457Sbmc 524*457Sbmc if (pc == NULL) 525*457Sbmc break; 526*457Sbmc 527*457Sbmc addr += size; 528*457Sbmc 5290Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s", indent, "") < 0) 5300Sstevel@tonic-gate return (-1); 5310Sstevel@tonic-gate 532*457Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 533*457Sbmc if (pc > sym.st_value) { 5340Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", 5350Sstevel@tonic-gate dts.dts_object, dts.dts_name, 536*457Sbmc pc - sym.st_value); 5370Sstevel@tonic-gate } else { 5380Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s", 5390Sstevel@tonic-gate dts.dts_object, dts.dts_name); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate } else { 5420Sstevel@tonic-gate /* 5430Sstevel@tonic-gate * We'll repeat the lookup, but this time we'll specify 5440Sstevel@tonic-gate * a NULL GElf_Sym -- indicating that we're only 5450Sstevel@tonic-gate * interested in the containing module. 5460Sstevel@tonic-gate */ 547*457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 5480Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 549*457Sbmc dts.dts_object, pc); 5500Sstevel@tonic-gate } else { 551*457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", pc); 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate if (dt_printf(dtp, fp, format, c) < 0) 5560Sstevel@tonic-gate return (-1); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 5590Sstevel@tonic-gate return (-1); 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate return (0); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate int 5660Sstevel@tonic-gate dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 5670Sstevel@tonic-gate caddr_t addr, uint64_t arg) 5680Sstevel@tonic-gate { 569*457Sbmc /* LINTED - alignment */ 570*457Sbmc uint64_t *pc = (uint64_t *)addr; 5710Sstevel@tonic-gate uint32_t depth = DTRACE_USTACK_NFRAMES(arg); 5720Sstevel@tonic-gate uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); 5730Sstevel@tonic-gate const char *strbase = addr + (depth + 1) * sizeof (uint64_t); 5740Sstevel@tonic-gate const char *str = strsize ? strbase : NULL; 5750Sstevel@tonic-gate int err = 0; 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 5780Sstevel@tonic-gate struct ps_prochandle *P; 5790Sstevel@tonic-gate GElf_Sym sym; 5800Sstevel@tonic-gate int i, indent; 5810Sstevel@tonic-gate pid_t pid; 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (depth == 0) 5840Sstevel@tonic-gate return (0); 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate pid = (pid_t)*pc++; 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 5890Sstevel@tonic-gate return (-1); 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate if (format == NULL) 5920Sstevel@tonic-gate format = "%s"; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 5950Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 5960Sstevel@tonic-gate else 5970Sstevel@tonic-gate indent = _dtrace_stkindent; 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * Ultimately, we need to add an entry point in the library vector for 6010Sstevel@tonic-gate * determining <symbol, offset> from <pid, address>. For now, if 6020Sstevel@tonic-gate * this is a vector open, we just print the raw address or string. 6030Sstevel@tonic-gate */ 6040Sstevel@tonic-gate if (dtp->dt_vector == NULL) 6050Sstevel@tonic-gate P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 6060Sstevel@tonic-gate else 6070Sstevel@tonic-gate P = NULL; 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate if (P != NULL) 6100Sstevel@tonic-gate dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate for (i = 0; i < depth && pc[i] != NULL; i++) { 613*457Sbmc const prmap_t *map; 614*457Sbmc 6150Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 6160Sstevel@tonic-gate break; 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (P != NULL && Plookup_by_addr(P, pc[i], 6190Sstevel@tonic-gate name, sizeof (name), &sym) == 0) { 6200Sstevel@tonic-gate (void) Pobjname(P, pc[i], objname, sizeof (objname)); 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate if (pc[i] > sym.st_value) { 6230Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 6240Sstevel@tonic-gate "%s`%s+0x%llx", dt_basename(objname), name, 6250Sstevel@tonic-gate (u_longlong_t)(pc[i] - sym.st_value)); 6260Sstevel@tonic-gate } else { 6270Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 6280Sstevel@tonic-gate "%s`%s", dt_basename(objname), name); 6290Sstevel@tonic-gate } 630*457Sbmc } else if (str != NULL && str[0] != '\0' && 631*457Sbmc (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL || 632*457Sbmc (map->pr_mflags & MA_WRITE)))) { 633*457Sbmc /* 634*457Sbmc * If the current string pointer in the string table 635*457Sbmc * does not point to an empty string _and_ the program 636*457Sbmc * counter falls in a writable region, we'll use the 637*457Sbmc * string from the string table instead of the raw 638*457Sbmc * address. This last condition is necessary because 639*457Sbmc * some (broken) ustack helpers will return a string 640*457Sbmc * even for a program counter that they can't 641*457Sbmc * identify. If we have a string for a program 642*457Sbmc * counter that falls in a segment that isn't 643*457Sbmc * writable, we assume that we have fallen into this 644*457Sbmc * case and we refuse to use the string. 645*457Sbmc */ 6460Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s", str); 6470Sstevel@tonic-gate } else { 6480Sstevel@tonic-gate if (P != NULL && Pobjname(P, pc[i], objname, 6490Sstevel@tonic-gate sizeof (objname)) != NULL) { 6500Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 6510Sstevel@tonic-gate dt_basename(objname), (u_longlong_t)pc[i]); 6520Sstevel@tonic-gate } else { 6530Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "0x%llx", 6540Sstevel@tonic-gate (u_longlong_t)pc[i]); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, format, c)) < 0) 6590Sstevel@tonic-gate break; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "\n")) < 0) 6620Sstevel@tonic-gate break; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate if (str != NULL) { 6650Sstevel@tonic-gate str += strlen(str) + 1; 6660Sstevel@tonic-gate if (str - strbase >= strsize) 6670Sstevel@tonic-gate str = NULL; 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate if (P != NULL) { 6720Sstevel@tonic-gate dt_proc_unlock(dtp, P); 6730Sstevel@tonic-gate dt_proc_release(dtp, P); 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate return (err); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 679*457Sbmc static int 680*457Sbmc dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act) 681*457Sbmc { 682*457Sbmc /* LINTED - alignment */ 683*457Sbmc uint64_t pid = ((uint64_t *)addr)[0]; 684*457Sbmc /* LINTED - alignment */ 685*457Sbmc uint64_t pc = ((uint64_t *)addr)[1]; 686*457Sbmc const char *format = " %-50s"; 687*457Sbmc char *s; 688*457Sbmc int n, len = 256; 689*457Sbmc 690*457Sbmc if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) { 691*457Sbmc struct ps_prochandle *P; 692*457Sbmc 693*457Sbmc if ((P = dt_proc_grab(dtp, pid, 694*457Sbmc PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) { 695*457Sbmc GElf_Sym sym; 696*457Sbmc 697*457Sbmc dt_proc_lock(dtp, P); 698*457Sbmc 699*457Sbmc if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0) 700*457Sbmc pc = sym.st_value; 701*457Sbmc 702*457Sbmc dt_proc_unlock(dtp, P); 703*457Sbmc dt_proc_release(dtp, P); 704*457Sbmc } 705*457Sbmc } 706*457Sbmc 707*457Sbmc do { 708*457Sbmc n = len; 709*457Sbmc s = alloca(n); 710*457Sbmc } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) >= n); 711*457Sbmc 712*457Sbmc return (dt_printf(dtp, fp, format, s)); 713*457Sbmc } 714*457Sbmc 715*457Sbmc int 716*457Sbmc dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 717*457Sbmc { 718*457Sbmc /* LINTED - alignment */ 719*457Sbmc uint64_t pid = ((uint64_t *)addr)[0]; 720*457Sbmc /* LINTED - alignment */ 721*457Sbmc uint64_t pc = ((uint64_t *)addr)[1]; 722*457Sbmc int err = 0; 723*457Sbmc 724*457Sbmc char objname[PATH_MAX], c[PATH_MAX * 2]; 725*457Sbmc struct ps_prochandle *P; 726*457Sbmc 727*457Sbmc if (format == NULL) 728*457Sbmc format = " %-50s"; 729*457Sbmc 730*457Sbmc /* 731*457Sbmc * See the comment in dt_print_ustack() for the rationale for 732*457Sbmc * printing raw addresses in the vectored case. 733*457Sbmc */ 734*457Sbmc if (dtp->dt_vector == NULL) 735*457Sbmc P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 736*457Sbmc else 737*457Sbmc P = NULL; 738*457Sbmc 739*457Sbmc if (P != NULL) 740*457Sbmc dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 741*457Sbmc 742*457Sbmc if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != NULL) { 743*457Sbmc (void) snprintf(c, sizeof (c), "%s", dt_basename(objname)); 744*457Sbmc } else { 745*457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 746*457Sbmc } 747*457Sbmc 748*457Sbmc err = dt_printf(dtp, fp, format, c); 749*457Sbmc 750*457Sbmc if (P != NULL) { 751*457Sbmc dt_proc_unlock(dtp, P); 752*457Sbmc dt_proc_release(dtp, P); 753*457Sbmc } 754*457Sbmc 755*457Sbmc return (err); 756*457Sbmc } 757*457Sbmc 758*457Sbmc static int 759*457Sbmc dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 760*457Sbmc { 761*457Sbmc /* LINTED - alignment */ 762*457Sbmc uint64_t pc = *((uint64_t *)addr); 763*457Sbmc dtrace_syminfo_t dts; 764*457Sbmc GElf_Sym sym; 765*457Sbmc char c[PATH_MAX * 2]; 766*457Sbmc 767*457Sbmc if (format == NULL) 768*457Sbmc format = " %-50s"; 769*457Sbmc 770*457Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 771*457Sbmc (void) snprintf(c, sizeof (c), "%s`%s", 772*457Sbmc dts.dts_object, dts.dts_name); 773*457Sbmc } else { 774*457Sbmc /* 775*457Sbmc * We'll repeat the lookup, but this time we'll specify a 776*457Sbmc * NULL GElf_Sym -- indicating that we're only interested in 777*457Sbmc * the containing module. 778*457Sbmc */ 779*457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 780*457Sbmc (void) snprintf(c, sizeof (c), "%s`0x%llx", 781*457Sbmc dts.dts_object, (u_longlong_t)pc); 782*457Sbmc } else { 783*457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", 784*457Sbmc (u_longlong_t)pc); 785*457Sbmc } 786*457Sbmc } 787*457Sbmc 788*457Sbmc if (dt_printf(dtp, fp, format, c) < 0) 789*457Sbmc return (-1); 790*457Sbmc 791*457Sbmc return (0); 792*457Sbmc } 793*457Sbmc 794*457Sbmc int 795*457Sbmc dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 796*457Sbmc { 797*457Sbmc /* LINTED - alignment */ 798*457Sbmc uint64_t pc = *((uint64_t *)addr); 799*457Sbmc dtrace_syminfo_t dts; 800*457Sbmc char c[PATH_MAX * 2]; 801*457Sbmc 802*457Sbmc if (format == NULL) 803*457Sbmc format = " %-50s"; 804*457Sbmc 805*457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 806*457Sbmc (void) snprintf(c, sizeof (c), "%s", dts.dts_object); 807*457Sbmc } else { 808*457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 809*457Sbmc } 810*457Sbmc 811*457Sbmc if (dt_printf(dtp, fp, format, c) < 0) 812*457Sbmc return (-1); 813*457Sbmc 814*457Sbmc return (0); 815*457Sbmc } 816*457Sbmc 8170Sstevel@tonic-gate typedef struct dt_normal { 8180Sstevel@tonic-gate dtrace_aggvarid_t dtnd_id; 8190Sstevel@tonic-gate uint64_t dtnd_normal; 8200Sstevel@tonic-gate } dt_normal_t; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate static int 823*457Sbmc dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 8240Sstevel@tonic-gate { 8250Sstevel@tonic-gate dt_normal_t *normal = arg; 8260Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 8270Sstevel@tonic-gate dtrace_aggvarid_t id = normal->dtnd_id; 8280Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 8310Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 8340Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 8350Sstevel@tonic-gate 836*457Sbmc ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal; 8370Sstevel@tonic-gate return (DTRACE_AGGWALK_NORMALIZE); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate static int 8410Sstevel@tonic-gate dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 8420Sstevel@tonic-gate { 8430Sstevel@tonic-gate dt_normal_t normal; 8440Sstevel@tonic-gate caddr_t addr; 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 8480Sstevel@tonic-gate * normalization value. 8490Sstevel@tonic-gate */ 8500Sstevel@tonic-gate addr = base + rec->dtrd_offset; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 8530Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate /* LINTED - alignment */ 8560Sstevel@tonic-gate normal.dtnd_id = *((dtrace_aggvarid_t *)addr); 8570Sstevel@tonic-gate rec++; 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 8600Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_NORMALIZE) 8630Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate addr = base + rec->dtrd_offset; 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate switch (rec->dtrd_size) { 8680Sstevel@tonic-gate case sizeof (uint64_t): 8690Sstevel@tonic-gate /* LINTED - alignment */ 8700Sstevel@tonic-gate normal.dtnd_normal = *((uint64_t *)addr); 8710Sstevel@tonic-gate break; 8720Sstevel@tonic-gate case sizeof (uint32_t): 8730Sstevel@tonic-gate /* LINTED - alignment */ 8740Sstevel@tonic-gate normal.dtnd_normal = *((uint32_t *)addr); 8750Sstevel@tonic-gate break; 8760Sstevel@tonic-gate case sizeof (uint16_t): 8770Sstevel@tonic-gate /* LINTED - alignment */ 8780Sstevel@tonic-gate normal.dtnd_normal = *((uint16_t *)addr); 8790Sstevel@tonic-gate break; 8800Sstevel@tonic-gate case sizeof (uint8_t): 8810Sstevel@tonic-gate normal.dtnd_normal = *((uint8_t *)addr); 8820Sstevel@tonic-gate break; 8830Sstevel@tonic-gate default: 8840Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal); 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate return (0); 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate static int 893*457Sbmc dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 8940Sstevel@tonic-gate { 8950Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 8960Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 8970Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 9000Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 9030Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate return (DTRACE_AGGWALK_DENORMALIZE); 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate static int 909*457Sbmc dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg) 9100Sstevel@tonic-gate { 9110Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 9120Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 9130Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 9160Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 9190Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate return (DTRACE_AGGWALK_CLEAR); 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate typedef struct dt_trunc { 9250Sstevel@tonic-gate dtrace_aggvarid_t dttd_id; 9260Sstevel@tonic-gate uint64_t dttd_remaining; 9270Sstevel@tonic-gate } dt_trunc_t; 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate static int 930*457Sbmc dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg) 9310Sstevel@tonic-gate { 9320Sstevel@tonic-gate dt_trunc_t *trunc = arg; 9330Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 9340Sstevel@tonic-gate dtrace_aggvarid_t id = trunc->dttd_id; 9350Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 9380Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 9410Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate if (trunc->dttd_remaining == 0) 9440Sstevel@tonic-gate return (DTRACE_AGGWALK_REMOVE); 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate trunc->dttd_remaining--; 9470Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 9480Sstevel@tonic-gate } 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate static int 9510Sstevel@tonic-gate dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 9520Sstevel@tonic-gate { 9530Sstevel@tonic-gate dt_trunc_t trunc; 9540Sstevel@tonic-gate caddr_t addr; 9550Sstevel@tonic-gate int64_t remaining; 9560Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *); 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /* 9590Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 9600Sstevel@tonic-gate * number of aggregation entries after which the aggregation is to be 9610Sstevel@tonic-gate * truncated. 9620Sstevel@tonic-gate */ 9630Sstevel@tonic-gate addr = base + rec->dtrd_offset; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 9660Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate /* LINTED - alignment */ 9690Sstevel@tonic-gate trunc.dttd_id = *((dtrace_aggvarid_t *)addr); 9700Sstevel@tonic-gate rec++; 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 9730Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_TRUNC) 9760Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate addr = base + rec->dtrd_offset; 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate switch (rec->dtrd_size) { 9810Sstevel@tonic-gate case sizeof (uint64_t): 9820Sstevel@tonic-gate /* LINTED - alignment */ 9830Sstevel@tonic-gate remaining = *((int64_t *)addr); 9840Sstevel@tonic-gate break; 9850Sstevel@tonic-gate case sizeof (uint32_t): 9860Sstevel@tonic-gate /* LINTED - alignment */ 9870Sstevel@tonic-gate remaining = *((int32_t *)addr); 9880Sstevel@tonic-gate break; 9890Sstevel@tonic-gate case sizeof (uint16_t): 9900Sstevel@tonic-gate /* LINTED - alignment */ 9910Sstevel@tonic-gate remaining = *((int16_t *)addr); 9920Sstevel@tonic-gate break; 9930Sstevel@tonic-gate case sizeof (uint8_t): 9940Sstevel@tonic-gate remaining = *((int8_t *)addr); 9950Sstevel@tonic-gate break; 9960Sstevel@tonic-gate default: 9970Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate if (remaining < 0) { 10010Sstevel@tonic-gate func = dtrace_aggregate_walk_valsorted; 10020Sstevel@tonic-gate remaining = -remaining; 10030Sstevel@tonic-gate } else { 10040Sstevel@tonic-gate func = dtrace_aggregate_walk_valrevsorted; 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate assert(remaining >= 0); 10080Sstevel@tonic-gate trunc.dttd_remaining = remaining; 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate (void) func(dtp, dt_trunc_agg, &trunc); 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate return (0); 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate int 1016*457Sbmc dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg) 10170Sstevel@tonic-gate { 10180Sstevel@tonic-gate int i, err = 0; 10190Sstevel@tonic-gate dt_print_aggdata_t *pd = arg; 10200Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 10210Sstevel@tonic-gate FILE *fp = pd->dtpa_fp; 10220Sstevel@tonic-gate dtrace_hdl_t *dtp = pd->dtpa_dtp; 10230Sstevel@tonic-gate dtrace_aggvarid_t aggvarid = pd->dtpa_id; 10240Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate if (pd->dtpa_allunprint) { 10270Sstevel@tonic-gate if (agg->dtagd_flags & DTRACE_AGD_PRINTED) 10280Sstevel@tonic-gate return (0); 10290Sstevel@tonic-gate } else { 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * If we're not printing all unprinted aggregations, then the 10320Sstevel@tonic-gate * aggregation variable ID denotes a specific aggregation 10330Sstevel@tonic-gate * variable that we should print -- skip any other aggregations 10340Sstevel@tonic-gate * that we encounter. 10350Sstevel@tonic-gate */ 10360Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 10370Sstevel@tonic-gate return (0); 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate if (aggvarid != *(dtrace_aggvarid_t *)(data + 10400Sstevel@tonic-gate agg->dtagd_rec[0].dtrd_offset)) 10410Sstevel@tonic-gate return (0); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate /* 10450Sstevel@tonic-gate * Iterate over each record description, printing the traced data, 10460Sstevel@tonic-gate * skipping the first datum (the tuple member created by the compiler). 10470Sstevel@tonic-gate */ 10480Sstevel@tonic-gate for (i = 1; err >= 0 && i < agg->dtagd_nrecs; i++) { 10490Sstevel@tonic-gate dtrace_recdesc_t *rec = &agg->dtagd_rec[i]; 10500Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action; 10510Sstevel@tonic-gate caddr_t addr = aggdata->dtada_data + rec->dtrd_offset; 10520Sstevel@tonic-gate size_t size = rec->dtrd_size; 10530Sstevel@tonic-gate uint64_t normal; 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate normal = DTRACEACT_ISAGG(act) ? aggdata->dtada_normal : 1; 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate if (act == DTRACEACT_STACK) { 1058*457Sbmc err = dt_print_stack(dtp, fp, NULL, addr, 1059*457Sbmc rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg); 10600Sstevel@tonic-gate goto nextrec; 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate if (act == DTRACEACT_USTACK || act == DTRACEACT_JSTACK) { 10640Sstevel@tonic-gate err = dt_print_ustack(dtp, fp, NULL, addr, 10650Sstevel@tonic-gate rec->dtrd_arg); 10660Sstevel@tonic-gate goto nextrec; 10670Sstevel@tonic-gate } 10680Sstevel@tonic-gate 1069*457Sbmc if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) { 1070*457Sbmc err = dt_print_usym(dtp, fp, addr, act); 1071*457Sbmc goto nextrec; 1072*457Sbmc } 1073*457Sbmc 1074*457Sbmc if (act == DTRACEACT_UMOD) { 1075*457Sbmc err = dt_print_umod(dtp, fp, NULL, addr); 1076*457Sbmc goto nextrec; 1077*457Sbmc } 1078*457Sbmc 1079*457Sbmc if (act == DTRACEACT_SYM) { 1080*457Sbmc err = dt_print_sym(dtp, fp, NULL, addr); 1081*457Sbmc goto nextrec; 1082*457Sbmc } 1083*457Sbmc 1084*457Sbmc if (act == DTRACEACT_MOD) { 1085*457Sbmc err = dt_print_mod(dtp, fp, NULL, addr); 1086*457Sbmc goto nextrec; 1087*457Sbmc } 1088*457Sbmc 10890Sstevel@tonic-gate if (act == DTRACEAGG_QUANTIZE) { 10900Sstevel@tonic-gate err = dt_print_quantize(dtp, fp, addr, size, normal); 10910Sstevel@tonic-gate goto nextrec; 10920Sstevel@tonic-gate } 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate if (act == DTRACEAGG_LQUANTIZE) { 10950Sstevel@tonic-gate err = dt_print_lquantize(dtp, fp, addr, size, normal); 10960Sstevel@tonic-gate goto nextrec; 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate if (act == DTRACEAGG_AVG) { 11000Sstevel@tonic-gate err = dt_print_average(dtp, fp, addr, size, normal); 11010Sstevel@tonic-gate goto nextrec; 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate switch (size) { 11050Sstevel@tonic-gate case sizeof (uint64_t): 11060Sstevel@tonic-gate err = dt_printf(dtp, fp, " %16lld", 11070Sstevel@tonic-gate /* LINTED - alignment */ 11080Sstevel@tonic-gate (long long)*((uint64_t *)addr) / normal); 11090Sstevel@tonic-gate break; 11100Sstevel@tonic-gate case sizeof (uint32_t): 11110Sstevel@tonic-gate /* LINTED - alignment */ 11120Sstevel@tonic-gate err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) / 11130Sstevel@tonic-gate (uint32_t)normal); 11140Sstevel@tonic-gate break; 11150Sstevel@tonic-gate case sizeof (uint16_t): 11160Sstevel@tonic-gate /* LINTED - alignment */ 11170Sstevel@tonic-gate err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) / 11180Sstevel@tonic-gate (uint32_t)normal); 11190Sstevel@tonic-gate break; 11200Sstevel@tonic-gate case sizeof (uint8_t): 11210Sstevel@tonic-gate err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) / 11220Sstevel@tonic-gate (uint32_t)normal); 11230Sstevel@tonic-gate break; 11240Sstevel@tonic-gate default: 11250Sstevel@tonic-gate err = dt_print_bytes(dtp, fp, addr, size, 50, 0); 11260Sstevel@tonic-gate break; 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate nextrec: 11300Sstevel@tonic-gate if (dt_buffered_flush(dtp, NULL, rec, aggdata) < 0) 11310Sstevel@tonic-gate return (-1); 11320Sstevel@tonic-gate } 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate if (err >= 0) 11350Sstevel@tonic-gate err = dt_printf(dtp, fp, "\n"); 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate if (dt_buffered_flush(dtp, NULL, NULL, aggdata) < 0) 11380Sstevel@tonic-gate return (-1); 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate if (!pd->dtpa_allunprint) 11410Sstevel@tonic-gate agg->dtagd_flags |= DTRACE_AGD_PRINTED; 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate return (err < 0 ? -1 : 0); 11440Sstevel@tonic-gate } 11450Sstevel@tonic-gate 1146*457Sbmc 1147*457Sbmc int 1148*457Sbmc dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, 1149*457Sbmc const char *option, const char *value) 1150*457Sbmc { 1151*457Sbmc int len, rval; 1152*457Sbmc char *msg; 1153*457Sbmc const char *errstr; 1154*457Sbmc dtrace_setoptdata_t optdata; 1155*457Sbmc 1156*457Sbmc bzero(&optdata, sizeof (optdata)); 1157*457Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval); 1158*457Sbmc 1159*457Sbmc if (dtrace_setopt(dtp, option, value) == 0) { 1160*457Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval); 1161*457Sbmc optdata.dtsda_probe = data; 1162*457Sbmc optdata.dtsda_option = option; 1163*457Sbmc optdata.dtsda_handle = dtp; 1164*457Sbmc 1165*457Sbmc if ((rval = dt_handle_setopt(dtp, &optdata)) != 0) 1166*457Sbmc return (rval); 1167*457Sbmc 1168*457Sbmc return (0); 1169*457Sbmc } 1170*457Sbmc 1171*457Sbmc errstr = dtrace_errmsg(dtp, dtrace_errno(dtp)); 1172*457Sbmc len = strlen(option) + strlen(value) + strlen(errstr) + 80; 1173*457Sbmc msg = alloca(len); 1174*457Sbmc 1175*457Sbmc (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n", 1176*457Sbmc option, value, errstr); 1177*457Sbmc 1178*457Sbmc if ((rval = dt_handle_liberr(dtp, data, msg)) == 0) 1179*457Sbmc return (0); 1180*457Sbmc 1181*457Sbmc return (rval); 1182*457Sbmc } 1183*457Sbmc 11840Sstevel@tonic-gate static int 11850Sstevel@tonic-gate dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf, 11860Sstevel@tonic-gate dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) 11870Sstevel@tonic-gate { 11880Sstevel@tonic-gate dtrace_epid_t id; 11890Sstevel@tonic-gate size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size; 11900Sstevel@tonic-gate int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 11910Sstevel@tonic-gate int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 11920Sstevel@tonic-gate int rval, i, n; 11930Sstevel@tonic-gate dtrace_epid_t last = DTRACE_EPIDNONE; 11940Sstevel@tonic-gate dtrace_probedata_t data; 11950Sstevel@tonic-gate uint64_t drops; 11960Sstevel@tonic-gate caddr_t addr; 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate bzero(&data, sizeof (data)); 11990Sstevel@tonic-gate data.dtpda_handle = dtp; 12000Sstevel@tonic-gate data.dtpda_cpu = cpu; 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate again: 12030Sstevel@tonic-gate for (offs = start; offs < end; ) { 12040Sstevel@tonic-gate dtrace_eprobedesc_t *epd; 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate /* 12070Sstevel@tonic-gate * We're guaranteed to have an ID. 12080Sstevel@tonic-gate */ 12090Sstevel@tonic-gate id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate if (id == DTRACE_EPIDNONE) { 12120Sstevel@tonic-gate /* 12130Sstevel@tonic-gate * This is filler to assure proper alignment of the 12140Sstevel@tonic-gate * next record; we simply ignore it. 12150Sstevel@tonic-gate */ 12160Sstevel@tonic-gate offs += sizeof (id); 12170Sstevel@tonic-gate continue; 12180Sstevel@tonic-gate } 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc, 12210Sstevel@tonic-gate &data.dtpda_pdesc)) != 0) 12220Sstevel@tonic-gate return (rval); 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate epd = data.dtpda_edesc; 12250Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs; 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) { 12280Sstevel@tonic-gate rval = dt_handle(dtp, &data); 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 12310Sstevel@tonic-gate goto nextepid; 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ERROR) 12340Sstevel@tonic-gate return (-1); 12350Sstevel@tonic-gate } 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate if (flow) 12380Sstevel@tonic-gate (void) dt_flowindent(dtp, &data, last, buf, offs); 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate rval = (*efunc)(&data, arg); 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate if (flow) { 12430Sstevel@tonic-gate if (data.dtpda_flow == DTRACEFLOW_ENTRY) 12440Sstevel@tonic-gate data.dtpda_indent += 2; 12450Sstevel@tonic-gate } 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 12480Sstevel@tonic-gate goto nextepid; 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 12510Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 12540Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate for (i = 0; i < epd->dtepd_nrecs; i++) { 12570Sstevel@tonic-gate dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; 12580Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action; 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs + 12610Sstevel@tonic-gate rec->dtrd_offset; 12620Sstevel@tonic-gate addr = data.dtpda_data; 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate if (act == DTRACEACT_LIBACT) { 1265*457Sbmc uint64_t arg = rec->dtrd_arg; 1266*457Sbmc dtrace_aggvarid_t id; 12670Sstevel@tonic-gate 1268*457Sbmc switch (arg) { 1269*457Sbmc case DT_ACT_CLEAR: 12700Sstevel@tonic-gate /* LINTED - alignment */ 12710Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 12720Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 12730Sstevel@tonic-gate dt_clear_agg, &id); 12740Sstevel@tonic-gate continue; 12750Sstevel@tonic-gate 1276*457Sbmc case DT_ACT_DENORMALIZE: 12770Sstevel@tonic-gate /* LINTED - alignment */ 12780Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 12790Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 12800Sstevel@tonic-gate dt_denormalize_agg, &id); 12810Sstevel@tonic-gate continue; 1282*457Sbmc 1283*457Sbmc case DT_ACT_FTRUNCATE: 1284*457Sbmc if (fp == NULL) 1285*457Sbmc continue; 12860Sstevel@tonic-gate 1287*457Sbmc (void) fflush(fp); 1288*457Sbmc (void) ftruncate(fileno(fp), 0); 1289*457Sbmc (void) fseeko(fp, 0, SEEK_SET); 1290*457Sbmc continue; 1291*457Sbmc 1292*457Sbmc case DT_ACT_NORMALIZE: 12930Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 12940Sstevel@tonic-gate return (dt_set_errno(dtp, 12950Sstevel@tonic-gate EDT_BADNORMAL)); 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate if (dt_normalize(dtp, 12980Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 12990Sstevel@tonic-gate return (-1); 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate i++; 13020Sstevel@tonic-gate continue; 1303*457Sbmc 1304*457Sbmc case DT_ACT_SETOPT: { 1305*457Sbmc uint64_t *opts = dtp->dt_options; 1306*457Sbmc dtrace_recdesc_t *valrec; 1307*457Sbmc uint32_t valsize; 1308*457Sbmc caddr_t val; 1309*457Sbmc int rv; 1310*457Sbmc 1311*457Sbmc if (i == epd->dtepd_nrecs - 1) { 1312*457Sbmc return (dt_set_errno(dtp, 1313*457Sbmc EDT_BADSETOPT)); 1314*457Sbmc } 1315*457Sbmc 1316*457Sbmc valrec = &epd->dtepd_rec[++i]; 1317*457Sbmc valsize = valrec->dtrd_size; 1318*457Sbmc 1319*457Sbmc if (valrec->dtrd_action != act || 1320*457Sbmc valrec->dtrd_arg != arg) { 1321*457Sbmc return (dt_set_errno(dtp, 1322*457Sbmc EDT_BADSETOPT)); 1323*457Sbmc } 1324*457Sbmc 1325*457Sbmc if (valsize > sizeof (uint64_t)) { 1326*457Sbmc val = buf->dtbd_data + offs + 1327*457Sbmc valrec->dtrd_offset; 1328*457Sbmc } else { 1329*457Sbmc val = "1"; 1330*457Sbmc } 1331*457Sbmc 1332*457Sbmc rv = dt_setopt(dtp, &data, addr, val); 1333*457Sbmc 1334*457Sbmc if (rv != 0) 1335*457Sbmc return (-1); 1336*457Sbmc 1337*457Sbmc flow = (opts[DTRACEOPT_FLOWINDENT] != 1338*457Sbmc DTRACEOPT_UNSET); 1339*457Sbmc quiet = (opts[DTRACEOPT_QUIET] != 1340*457Sbmc DTRACEOPT_UNSET); 1341*457Sbmc 1342*457Sbmc continue; 13430Sstevel@tonic-gate } 13440Sstevel@tonic-gate 1345*457Sbmc case DT_ACT_TRUNC: 13460Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 13470Sstevel@tonic-gate return (dt_set_errno(dtp, 13480Sstevel@tonic-gate EDT_BADTRUNC)); 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate if (dt_trunc(dtp, 13510Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 13520Sstevel@tonic-gate return (-1); 13530Sstevel@tonic-gate 13540Sstevel@tonic-gate i++; 13550Sstevel@tonic-gate continue; 13560Sstevel@tonic-gate 1357*457Sbmc default: 13580Sstevel@tonic-gate continue; 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate rval = (*rfunc)(&data, rec, arg); 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 13650Sstevel@tonic-gate continue; 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 13680Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 13710Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate if (act == DTRACEACT_STACK) { 1374*457Sbmc int depth = rec->dtrd_arg; 1375*457Sbmc 1376*457Sbmc if (dt_print_stack(dtp, fp, NULL, addr, depth, 1377*457Sbmc rec->dtrd_size / depth) < 0) 13780Sstevel@tonic-gate return (-1); 13790Sstevel@tonic-gate goto nextrec; 13800Sstevel@tonic-gate } 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate if (act == DTRACEACT_USTACK || 13830Sstevel@tonic-gate act == DTRACEACT_JSTACK) { 13840Sstevel@tonic-gate if (dt_print_ustack(dtp, fp, NULL, 13850Sstevel@tonic-gate addr, rec->dtrd_arg) < 0) 13860Sstevel@tonic-gate return (-1); 13870Sstevel@tonic-gate goto nextrec; 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate 1390*457Sbmc if (act == DTRACEACT_SYM) { 1391*457Sbmc if (dt_print_sym(dtp, fp, NULL, addr) < 0) 1392*457Sbmc return (-1); 1393*457Sbmc goto nextrec; 1394*457Sbmc } 1395*457Sbmc 1396*457Sbmc if (act == DTRACEACT_MOD) { 1397*457Sbmc if (dt_print_mod(dtp, fp, NULL, addr) < 0) 1398*457Sbmc return (-1); 1399*457Sbmc goto nextrec; 1400*457Sbmc } 1401*457Sbmc 1402*457Sbmc if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) { 1403*457Sbmc if (dt_print_usym(dtp, fp, addr, act) < 0) 1404*457Sbmc return (-1); 1405*457Sbmc goto nextrec; 1406*457Sbmc } 1407*457Sbmc 1408*457Sbmc if (act == DTRACEACT_UMOD) { 1409*457Sbmc if (dt_print_umod(dtp, fp, NULL, addr) < 0) 1410*457Sbmc return (-1); 1411*457Sbmc goto nextrec; 1412*457Sbmc } 1413*457Sbmc 14140Sstevel@tonic-gate if (DTRACEACT_ISPRINTFLIKE(act)) { 14150Sstevel@tonic-gate void *fmtdata; 14160Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, FILE *, void *, 14170Sstevel@tonic-gate const dtrace_probedata_t *, 14180Sstevel@tonic-gate const dtrace_recdesc_t *, uint_t, 14190Sstevel@tonic-gate const void *buf, size_t); 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate if ((fmtdata = dt_format_lookup(dtp, 14220Sstevel@tonic-gate rec->dtrd_format)) == NULL) 14230Sstevel@tonic-gate goto nofmt; 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate switch (act) { 14260Sstevel@tonic-gate case DTRACEACT_PRINTF: 14270Sstevel@tonic-gate func = dtrace_fprintf; 14280Sstevel@tonic-gate break; 14290Sstevel@tonic-gate case DTRACEACT_PRINTA: 14300Sstevel@tonic-gate func = dtrace_fprinta; 14310Sstevel@tonic-gate break; 14320Sstevel@tonic-gate case DTRACEACT_SYSTEM: 14330Sstevel@tonic-gate func = dtrace_system; 14340Sstevel@tonic-gate break; 14350Sstevel@tonic-gate case DTRACEACT_FREOPEN: 14360Sstevel@tonic-gate func = dtrace_freopen; 14370Sstevel@tonic-gate break; 14380Sstevel@tonic-gate } 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate n = (*func)(dtp, fp, fmtdata, &data, 14410Sstevel@tonic-gate rec, epd->dtepd_nrecs - i, 14420Sstevel@tonic-gate (uchar_t *)buf->dtbd_data + offs, 14430Sstevel@tonic-gate buf->dtbd_size - offs); 14440Sstevel@tonic-gate 14450Sstevel@tonic-gate if (n < 0) 14460Sstevel@tonic-gate return (-1); /* errno is set for us */ 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate if (n > 0) 14490Sstevel@tonic-gate i += n - 1; 14500Sstevel@tonic-gate goto nextrec; 14510Sstevel@tonic-gate } 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate nofmt: 14540Sstevel@tonic-gate if (act == DTRACEACT_PRINTA) { 14550Sstevel@tonic-gate dt_print_aggdata_t pd; 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate bzero(&pd, sizeof (pd)); 14580Sstevel@tonic-gate pd.dtpa_dtp = dtp; 14590Sstevel@tonic-gate pd.dtpa_fp = fp; 14600Sstevel@tonic-gate /* LINTED - alignment */ 14610Sstevel@tonic-gate pd.dtpa_id = *((dtrace_aggvarid_t *)addr); 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0 || 14640Sstevel@tonic-gate dtrace_aggregate_walk_valsorted(dtp, 14650Sstevel@tonic-gate dt_print_agg, &pd) < 0) 14660Sstevel@tonic-gate return (-1); 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate goto nextrec; 14690Sstevel@tonic-gate } 14700Sstevel@tonic-gate 14710Sstevel@tonic-gate switch (rec->dtrd_size) { 14720Sstevel@tonic-gate case sizeof (uint64_t): 14730Sstevel@tonic-gate n = dt_printf(dtp, fp, 14740Sstevel@tonic-gate quiet ? "%lld" : " %16lld", 14750Sstevel@tonic-gate /* LINTED - alignment */ 14760Sstevel@tonic-gate *((unsigned long long *)addr)); 14770Sstevel@tonic-gate break; 14780Sstevel@tonic-gate case sizeof (uint32_t): 14790Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %8d", 14800Sstevel@tonic-gate /* LINTED - alignment */ 14810Sstevel@tonic-gate *((uint32_t *)addr)); 14820Sstevel@tonic-gate break; 14830Sstevel@tonic-gate case sizeof (uint16_t): 14840Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %5d", 14850Sstevel@tonic-gate /* LINTED - alignment */ 14860Sstevel@tonic-gate *((uint16_t *)addr)); 14870Sstevel@tonic-gate break; 14880Sstevel@tonic-gate case sizeof (uint8_t): 14890Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %3d", 14900Sstevel@tonic-gate *((uint8_t *)addr)); 14910Sstevel@tonic-gate break; 14920Sstevel@tonic-gate default: 14930Sstevel@tonic-gate n = dt_print_bytes(dtp, fp, addr, 14940Sstevel@tonic-gate rec->dtrd_size, 33, quiet); 14950Sstevel@tonic-gate break; 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate if (n < 0) 14990Sstevel@tonic-gate return (-1); /* errno is set for us */ 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate nextrec: 15020Sstevel@tonic-gate if (dt_buffered_flush(dtp, &data, rec, NULL) < 0) 15030Sstevel@tonic-gate return (-1); /* errno is set for us */ 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate /* 15070Sstevel@tonic-gate * Call the record callback with a NULL record to indicate 15080Sstevel@tonic-gate * that we're done processing this EPID. 15090Sstevel@tonic-gate */ 15100Sstevel@tonic-gate rval = (*rfunc)(&data, NULL, arg); 15110Sstevel@tonic-gate nextepid: 15120Sstevel@tonic-gate offs += epd->dtepd_size; 15130Sstevel@tonic-gate last = id; 15140Sstevel@tonic-gate } 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) { 15170Sstevel@tonic-gate end = buf->dtbd_oldest; 15180Sstevel@tonic-gate start = 0; 15190Sstevel@tonic-gate goto again; 15200Sstevel@tonic-gate } 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate if ((drops = buf->dtbd_drops) == 0) 15230Sstevel@tonic-gate return (0); 15240Sstevel@tonic-gate 15250Sstevel@tonic-gate /* 15260Sstevel@tonic-gate * Explicitly zero the drops to prevent us from processing them again. 15270Sstevel@tonic-gate */ 15280Sstevel@tonic-gate buf->dtbd_drops = 0; 15290Sstevel@tonic-gate 15300Sstevel@tonic-gate return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); 15310Sstevel@tonic-gate } 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate typedef struct dt_begin { 15340Sstevel@tonic-gate dtrace_consume_probe_f *dtbgn_probefunc; 15350Sstevel@tonic-gate dtrace_consume_rec_f *dtbgn_recfunc; 15360Sstevel@tonic-gate void *dtbgn_arg; 15370Sstevel@tonic-gate dtrace_handle_err_f *dtbgn_errhdlr; 15380Sstevel@tonic-gate void *dtbgn_errarg; 15390Sstevel@tonic-gate int dtbgn_beginonly; 15400Sstevel@tonic-gate } dt_begin_t; 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate static int 15430Sstevel@tonic-gate dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) 15440Sstevel@tonic-gate { 15450Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 15460Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc; 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 15490Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 15520Sstevel@tonic-gate if (!(r1 && r2)) 15530Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 15540Sstevel@tonic-gate } else { 15550Sstevel@tonic-gate if (r1 && r2) 15560Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 15570Sstevel@tonic-gate } 15580Sstevel@tonic-gate 15590Sstevel@tonic-gate /* 15600Sstevel@tonic-gate * We have a record that we're interested in. Now call the underlying 15610Sstevel@tonic-gate * probe function... 15620Sstevel@tonic-gate */ 15630Sstevel@tonic-gate return (begin->dtbgn_probefunc(data, begin->dtbgn_arg)); 15640Sstevel@tonic-gate } 15650Sstevel@tonic-gate 15660Sstevel@tonic-gate static int 15670Sstevel@tonic-gate dt_consume_begin_record(const dtrace_probedata_t *data, 15680Sstevel@tonic-gate const dtrace_recdesc_t *rec, void *arg) 15690Sstevel@tonic-gate { 15700Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); 15730Sstevel@tonic-gate } 15740Sstevel@tonic-gate 15750Sstevel@tonic-gate static int 1576*457Sbmc dt_consume_begin_error(const dtrace_errdata_t *data, void *arg) 15770Sstevel@tonic-gate { 15780Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 15790Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dteda_pdesc; 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 15820Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 15850Sstevel@tonic-gate if (!(r1 && r2)) 15860Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 15870Sstevel@tonic-gate } else { 15880Sstevel@tonic-gate if (r1 && r2) 15890Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 15900Sstevel@tonic-gate } 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg)); 15930Sstevel@tonic-gate } 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate static int 15960Sstevel@tonic-gate dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, 15970Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 15980Sstevel@tonic-gate { 15990Sstevel@tonic-gate /* 16000Sstevel@tonic-gate * There's this idea that the BEGIN probe should be processed before 16010Sstevel@tonic-gate * everything else, and that the END probe should be processed after 16020Sstevel@tonic-gate * anything else. In the common case, this is pretty easy to deal 16030Sstevel@tonic-gate * with. However, a situation may arise where the BEGIN enabling and 16040Sstevel@tonic-gate * END enabling are on the same CPU, and some enabling in the middle 16050Sstevel@tonic-gate * occurred on a different CPU. To deal with this (blech!) we need to 16060Sstevel@tonic-gate * consume the BEGIN buffer up until the end of the BEGIN probe, and 16070Sstevel@tonic-gate * then set it aside. We will then process every other CPU, and then 16080Sstevel@tonic-gate * we'll return to the BEGIN CPU and process the rest of the data 16090Sstevel@tonic-gate * (which will inevitably include the END probe, if any). Making this 16100Sstevel@tonic-gate * even more complicated (!) is the library's ERROR enabling. Because 16110Sstevel@tonic-gate * this enabling is processed before we even get into the consume call 16120Sstevel@tonic-gate * back, any ERROR firing would result in the library's ERROR enabling 16130Sstevel@tonic-gate * being processed twice -- once in our first pass (for BEGIN probes), 16140Sstevel@tonic-gate * and again in our second pass (for everything but BEGIN probes). To 16150Sstevel@tonic-gate * deal with this, we interpose on the ERROR handler to assure that we 16160Sstevel@tonic-gate * only process ERROR enablings induced by BEGIN enablings in the 16170Sstevel@tonic-gate * first pass, and that we only process ERROR enablings _not_ induced 16180Sstevel@tonic-gate * by BEGIN enablings in the second pass. 16190Sstevel@tonic-gate */ 16200Sstevel@tonic-gate dt_begin_t begin; 16210Sstevel@tonic-gate processorid_t cpu = dtp->dt_beganon; 16220Sstevel@tonic-gate dtrace_bufdesc_t nbuf; 16230Sstevel@tonic-gate int rval, i; 16240Sstevel@tonic-gate static int max_ncpus; 16250Sstevel@tonic-gate dtrace_optval_t size; 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate dtp->dt_beganon = -1; 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 16300Sstevel@tonic-gate /* 16310Sstevel@tonic-gate * We really don't expect this to fail, but it is at least 16320Sstevel@tonic-gate * technically possible for this to fail with ENOENT. In this 16330Sstevel@tonic-gate * case, we just drive on... 16340Sstevel@tonic-gate */ 16350Sstevel@tonic-gate if (errno == ENOENT) 16360Sstevel@tonic-gate return (0); 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 16390Sstevel@tonic-gate } 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { 16420Sstevel@tonic-gate /* 16430Sstevel@tonic-gate * This is the simple case. We're either not stopped, or if 16440Sstevel@tonic-gate * we are, we actually processed any END probes on another 16450Sstevel@tonic-gate * CPU. We can simply consume this buffer and return. 16460Sstevel@tonic-gate */ 16470Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg)); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate begin.dtbgn_probefunc = pf; 16510Sstevel@tonic-gate begin.dtbgn_recfunc = rf; 16520Sstevel@tonic-gate begin.dtbgn_arg = arg; 16530Sstevel@tonic-gate begin.dtbgn_beginonly = 1; 16540Sstevel@tonic-gate 16550Sstevel@tonic-gate /* 16560Sstevel@tonic-gate * We need to interpose on the ERROR handler to be sure that we 16570Sstevel@tonic-gate * only process ERRORs induced by BEGIN. 16580Sstevel@tonic-gate */ 16590Sstevel@tonic-gate begin.dtbgn_errhdlr = dtp->dt_errhdlr; 16600Sstevel@tonic-gate begin.dtbgn_errarg = dtp->dt_errarg; 16610Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 16620Sstevel@tonic-gate dtp->dt_errarg = &begin; 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, 16650Sstevel@tonic-gate dt_consume_begin_record, &begin); 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 16680Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate if (rval != 0) 16710Sstevel@tonic-gate return (rval); 16720Sstevel@tonic-gate 16730Sstevel@tonic-gate /* 16740Sstevel@tonic-gate * Now allocate a new buffer. We'll use this to deal with every other 16750Sstevel@tonic-gate * CPU. 16760Sstevel@tonic-gate */ 16770Sstevel@tonic-gate bzero(&nbuf, sizeof (dtrace_bufdesc_t)); 16780Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size); 16790Sstevel@tonic-gate if ((nbuf.dtbd_data = malloc(size)) == NULL) 16800Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate if (max_ncpus == 0) 16830Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 16840Sstevel@tonic-gate 16850Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 16860Sstevel@tonic-gate nbuf.dtbd_cpu = i; 16870Sstevel@tonic-gate 16880Sstevel@tonic-gate if (i == cpu) 16890Sstevel@tonic-gate continue; 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) { 16920Sstevel@tonic-gate /* 16930Sstevel@tonic-gate * If we failed with ENOENT, it may be because the 16940Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other 16950Sstevel@tonic-gate * error, however, is unexpected. 16960Sstevel@tonic-gate */ 16970Sstevel@tonic-gate if (errno == ENOENT) 16980Sstevel@tonic-gate continue; 16990Sstevel@tonic-gate 17000Sstevel@tonic-gate free(nbuf.dtbd_data); 17010Sstevel@tonic-gate 17020Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate 17050Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp, 17060Sstevel@tonic-gate i, &nbuf, pf, rf, arg)) != 0) { 17070Sstevel@tonic-gate free(nbuf.dtbd_data); 17080Sstevel@tonic-gate return (rval); 17090Sstevel@tonic-gate } 17100Sstevel@tonic-gate } 17110Sstevel@tonic-gate 17120Sstevel@tonic-gate free(nbuf.dtbd_data); 17130Sstevel@tonic-gate 17140Sstevel@tonic-gate /* 17150Sstevel@tonic-gate * Okay -- we're done with the other buffers. Now we want to 17160Sstevel@tonic-gate * reconsume the first buffer -- but this time we're looking for 17170Sstevel@tonic-gate * everything _but_ BEGIN. And of course, in order to only consume 17180Sstevel@tonic-gate * those ERRORs _not_ associated with BEGIN, we need to reinstall our 17190Sstevel@tonic-gate * ERROR interposition function... 17200Sstevel@tonic-gate */ 17210Sstevel@tonic-gate begin.dtbgn_beginonly = 0; 17220Sstevel@tonic-gate 17230Sstevel@tonic-gate assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr); 17240Sstevel@tonic-gate assert(begin.dtbgn_errarg == dtp->dt_errarg); 17250Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 17260Sstevel@tonic-gate dtp->dt_errarg = &begin; 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, 17290Sstevel@tonic-gate dt_consume_begin_record, &begin); 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 17320Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate return (rval); 17350Sstevel@tonic-gate } 17360Sstevel@tonic-gate 17370Sstevel@tonic-gate int 17380Sstevel@tonic-gate dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, 17390Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 17400Sstevel@tonic-gate { 17410Sstevel@tonic-gate dtrace_bufdesc_t *buf = &dtp->dt_buf; 17420Sstevel@tonic-gate dtrace_optval_t size; 17430Sstevel@tonic-gate static int max_ncpus; 17440Sstevel@tonic-gate int i, rval; 17450Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE]; 17460Sstevel@tonic-gate hrtime_t now = gethrtime(); 17470Sstevel@tonic-gate 17480Sstevel@tonic-gate if (dtp->dt_lastswitch != 0) { 17490Sstevel@tonic-gate if (now - dtp->dt_lastswitch < interval) 17500Sstevel@tonic-gate return (0); 17510Sstevel@tonic-gate 17520Sstevel@tonic-gate dtp->dt_lastswitch += interval; 17530Sstevel@tonic-gate } else { 17540Sstevel@tonic-gate dtp->dt_lastswitch = now; 17550Sstevel@tonic-gate } 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate if (!dtp->dt_active) 17580Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL)); 17590Sstevel@tonic-gate 17600Sstevel@tonic-gate if (max_ncpus == 0) 17610Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate if (pf == NULL) 17640Sstevel@tonic-gate pf = (dtrace_consume_probe_f *)dt_nullprobe; 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate if (rf == NULL) 17670Sstevel@tonic-gate rf = (dtrace_consume_rec_f *)dt_nullrec; 17680Sstevel@tonic-gate 17690Sstevel@tonic-gate if (buf->dtbd_data == NULL) { 17700Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size); 17710Sstevel@tonic-gate if ((buf->dtbd_data = malloc(size)) == NULL) 17720Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate buf->dtbd_size = size; 17750Sstevel@tonic-gate } 17760Sstevel@tonic-gate 17770Sstevel@tonic-gate /* 17780Sstevel@tonic-gate * If we have just begun, we want to first process the CPU that 17790Sstevel@tonic-gate * executed the BEGIN probe (if any). 17800Sstevel@tonic-gate */ 17810Sstevel@tonic-gate if (dtp->dt_active && dtp->dt_beganon != -1) { 17820Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_beganon; 17830Sstevel@tonic-gate if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0) 17840Sstevel@tonic-gate return (rval); 17850Sstevel@tonic-gate } 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 17880Sstevel@tonic-gate buf->dtbd_cpu = i; 17890Sstevel@tonic-gate 17900Sstevel@tonic-gate /* 17910Sstevel@tonic-gate * If we have stopped, we want to process the CPU on which the 17920Sstevel@tonic-gate * END probe was processed only _after_ we have processed 17930Sstevel@tonic-gate * everything else. 17940Sstevel@tonic-gate */ 17950Sstevel@tonic-gate if (dtp->dt_stopped && (i == dtp->dt_endedon)) 17960Sstevel@tonic-gate continue; 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 17990Sstevel@tonic-gate /* 18000Sstevel@tonic-gate * If we failed with ENOENT, it may be because the 18010Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other 18020Sstevel@tonic-gate * error, however, is unexpected. 18030Sstevel@tonic-gate */ 18040Sstevel@tonic-gate if (errno == ENOENT) 18050Sstevel@tonic-gate continue; 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 18080Sstevel@tonic-gate } 18090Sstevel@tonic-gate 18100Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0) 18110Sstevel@tonic-gate return (rval); 18120Sstevel@tonic-gate } 18130Sstevel@tonic-gate 18140Sstevel@tonic-gate if (!dtp->dt_stopped) 18150Sstevel@tonic-gate return (0); 18160Sstevel@tonic-gate 18170Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_endedon; 18180Sstevel@tonic-gate 18190Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 18200Sstevel@tonic-gate /* 18210Sstevel@tonic-gate * This _really_ shouldn't fail, but it is strictly speaking 18220Sstevel@tonic-gate * possible for this to return ENOENT if the CPU that called 18230Sstevel@tonic-gate * the END enabling somehow managed to become unconfigured. 18240Sstevel@tonic-gate * It's unclear how the user can possibly expect anything 18250Sstevel@tonic-gate * rational to happen in this case -- the state has been thrown 18260Sstevel@tonic-gate * out along with the unconfigured CPU -- so we'll just drive 18270Sstevel@tonic-gate * on... 18280Sstevel@tonic-gate */ 18290Sstevel@tonic-gate if (errno == ENOENT) 18300Sstevel@tonic-gate return (0); 18310Sstevel@tonic-gate 18320Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg)); 18360Sstevel@tonic-gate } 1837