1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdlib.h> 30*0Sstevel@tonic-gate #include <strings.h> 31*0Sstevel@tonic-gate #include <errno.h> 32*0Sstevel@tonic-gate #include <unistd.h> 33*0Sstevel@tonic-gate #include <limits.h> 34*0Sstevel@tonic-gate #include <assert.h> 35*0Sstevel@tonic-gate #include <ctype.h> 36*0Sstevel@tonic-gate #include <alloca.h> 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #include <dt_impl.h> 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate static int 41*0Sstevel@tonic-gate dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, 42*0Sstevel@tonic-gate dtrace_bufdesc_t *buf, size_t offs) 43*0Sstevel@tonic-gate { 44*0Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; 45*0Sstevel@tonic-gate dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; 46*0Sstevel@tonic-gate char *p = pd->dtpd_provider, *n = pd->dtpd_name; 47*0Sstevel@tonic-gate dtrace_flowkind_t flow = DTRACEFLOW_NONE; 48*0Sstevel@tonic-gate const char *str = NULL; 49*0Sstevel@tonic-gate static const char *e_str[2] = { " -> ", " => " }; 50*0Sstevel@tonic-gate static const char *r_str[2] = { " <- ", " <= " }; 51*0Sstevel@tonic-gate dtrace_epid_t next, id = epd->dtepd_epid; 52*0Sstevel@tonic-gate int rval; 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate if (strcmp(n, "entry") == 0) { 55*0Sstevel@tonic-gate flow = DTRACEFLOW_ENTRY; 56*0Sstevel@tonic-gate str = e_str[strcmp(p, "syscall") == 0]; 57*0Sstevel@tonic-gate } else if (strcmp(n, "return") == 0 || 58*0Sstevel@tonic-gate strcmp(n, "exit") == 0) { 59*0Sstevel@tonic-gate flow = DTRACEFLOW_RETURN; 60*0Sstevel@tonic-gate str = r_str[strcmp(p, "syscall") == 0]; 61*0Sstevel@tonic-gate } 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * If we're going to indent this, we need to check the ID of our last 65*0Sstevel@tonic-gate * call. If we're looking at the same probe ID but a different EPID, 66*0Sstevel@tonic-gate * we _don't_ want to indent. (Yes, there are some minor holes in 67*0Sstevel@tonic-gate * this scheme -- it's a heuristic.) 68*0Sstevel@tonic-gate */ 69*0Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY) { 70*0Sstevel@tonic-gate if ((last != DTRACE_EPIDNONE && id != last && 71*0Sstevel@tonic-gate pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) 72*0Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 73*0Sstevel@tonic-gate } 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* 76*0Sstevel@tonic-gate * If we're going to unindent this, it's more difficult to see if 77*0Sstevel@tonic-gate * we don't actually want to unindent it -- we need to look at the 78*0Sstevel@tonic-gate * _next_ EPID. 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN) { 81*0Sstevel@tonic-gate offs += epd->dtepd_size; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate do { 84*0Sstevel@tonic-gate if (offs >= buf->dtbd_size) { 85*0Sstevel@tonic-gate /* 86*0Sstevel@tonic-gate * We're at the end -- maybe. If the oldest 87*0Sstevel@tonic-gate * record is non-zero, we need to wrap. 88*0Sstevel@tonic-gate */ 89*0Sstevel@tonic-gate if (buf->dtbd_oldest != 0) { 90*0Sstevel@tonic-gate offs = 0; 91*0Sstevel@tonic-gate } else { 92*0Sstevel@tonic-gate goto out; 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate if (next == DTRACE_EPIDNONE) 99*0Sstevel@tonic-gate offs += sizeof (id); 100*0Sstevel@tonic-gate } while (next == DTRACE_EPIDNONE); 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) 103*0Sstevel@tonic-gate return (rval); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate if (next != id && npd->dtpd_id == pd->dtpd_id) 106*0Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate out: 110*0Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { 111*0Sstevel@tonic-gate data->dtpda_prefix = str; 112*0Sstevel@tonic-gate } else { 113*0Sstevel@tonic-gate data->dtpda_prefix = "| "; 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) 117*0Sstevel@tonic-gate data->dtpda_indent -= 2; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate data->dtpda_flow = flow; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate return (0); 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate static int 125*0Sstevel@tonic-gate dt_nullprobe() 126*0Sstevel@tonic-gate { 127*0Sstevel@tonic-gate return (DTRACE_CONSUME_THIS); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate static int 131*0Sstevel@tonic-gate dt_nullrec() 132*0Sstevel@tonic-gate { 133*0Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate int 137*0Sstevel@tonic-gate dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 138*0Sstevel@tonic-gate size_t size, uint64_t normal) 139*0Sstevel@tonic-gate { 140*0Sstevel@tonic-gate const uint64_t *data = addr; 141*0Sstevel@tonic-gate int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; 142*0Sstevel@tonic-gate uint64_t total_bin_count = 0; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 145*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) 148*0Sstevel@tonic-gate first_bin++; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate if (first_bin > 0) 151*0Sstevel@tonic-gate first_bin--; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate while (last_bin > 0 && data[last_bin] == 0) 154*0Sstevel@tonic-gate last_bin--; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) 157*0Sstevel@tonic-gate last_bin++; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) 160*0Sstevel@tonic-gate total_bin_count += data[i]; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 163*0Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0) 164*0Sstevel@tonic-gate return (-1); 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 167*0Sstevel@tonic-gate float f = ((float)data[i] * 40.0) / (float)total_bin_count; 168*0Sstevel@tonic-gate uint_t depth = (uint_t)(f + 0.5); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "%16lld |%s%s %-9llu\n", 171*0Sstevel@tonic-gate (long long)DTRACE_QUANTIZE_BUCKETVAL(i), 172*0Sstevel@tonic-gate "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth, 173*0Sstevel@tonic-gate " " + depth, 174*0Sstevel@tonic-gate (u_longlong_t)data[i] / normal) < 0) 175*0Sstevel@tonic-gate return (-1); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate return (0); 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate int 182*0Sstevel@tonic-gate dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 183*0Sstevel@tonic-gate size_t size, uint64_t normal) 184*0Sstevel@tonic-gate { 185*0Sstevel@tonic-gate const uint64_t *data = addr; 186*0Sstevel@tonic-gate int i, first_bin, last_bin, base; 187*0Sstevel@tonic-gate uint64_t arg, total_bin_count = 0; 188*0Sstevel@tonic-gate uint16_t step, levels; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate if (size < sizeof (uint64_t)) 191*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate arg = *data++; 194*0Sstevel@tonic-gate size -= sizeof (uint64_t); 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate base = DTRACE_LQUANTIZE_BASE(arg); 197*0Sstevel@tonic-gate step = DTRACE_LQUANTIZE_STEP(arg); 198*0Sstevel@tonic-gate levels = DTRACE_LQUANTIZE_LEVELS(arg); 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate first_bin = 0; 201*0Sstevel@tonic-gate last_bin = levels + 1; 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate if (size != sizeof (uint64_t) * (levels + 2)) 204*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate while (first_bin < levels + 1 && data[first_bin] == 0) 207*0Sstevel@tonic-gate first_bin++; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate if (first_bin > 0) 210*0Sstevel@tonic-gate first_bin--; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate while (last_bin > 0 && data[last_bin] == 0) 213*0Sstevel@tonic-gate last_bin--; 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate if (last_bin < levels + 1) 216*0Sstevel@tonic-gate last_bin++; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) 219*0Sstevel@tonic-gate total_bin_count += data[i]; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 222*0Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0) 223*0Sstevel@tonic-gate return (-1); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 226*0Sstevel@tonic-gate float f = ((float)data[i] * 40.0) / (float)total_bin_count; 227*0Sstevel@tonic-gate uint_t depth = (uint_t)(f + 0.5); 228*0Sstevel@tonic-gate char c[32]; 229*0Sstevel@tonic-gate int err; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate if (i == 0) { 232*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "< %d", 233*0Sstevel@tonic-gate base / (uint32_t)normal); 234*0Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 235*0Sstevel@tonic-gate } else if (i == levels + 1) { 236*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), ">= %d", 237*0Sstevel@tonic-gate base + (levels * step)); 238*0Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 239*0Sstevel@tonic-gate } else { 240*0Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16d ", 241*0Sstevel@tonic-gate base + (i - 1) * step); 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if (err < 0 || dt_printf(dtp, fp, "|%s%s %-9llu\n", 245*0Sstevel@tonic-gate "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth, 246*0Sstevel@tonic-gate " " + depth, 247*0Sstevel@tonic-gate (u_longlong_t)data[i] / normal) < 0) 248*0Sstevel@tonic-gate return (-1); 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate return (0); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /*ARGSUSED*/ 255*0Sstevel@tonic-gate static int 256*0Sstevel@tonic-gate dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 257*0Sstevel@tonic-gate size_t size, uint64_t normal) 258*0Sstevel@tonic-gate { 259*0Sstevel@tonic-gate /* LINTED - alignment */ 260*0Sstevel@tonic-gate uint64_t *data = (uint64_t *)addr; 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate return (dt_printf(dtp, fp, " %16lld", data[0] ? 263*0Sstevel@tonic-gate (long long)(data[1] / normal / data[0]) : 0)); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /*ARGSUSED*/ 267*0Sstevel@tonic-gate int 268*0Sstevel@tonic-gate dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 269*0Sstevel@tonic-gate size_t nbytes, int width, int quiet) 270*0Sstevel@tonic-gate { 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * If the byte stream is a series of printable characters, followed by 273*0Sstevel@tonic-gate * a terminating byte, we print it out as a string. Otherwise, we 274*0Sstevel@tonic-gate * assume that it's something else and just print the bytes. 275*0Sstevel@tonic-gate */ 276*0Sstevel@tonic-gate int i, j, margin = 5; 277*0Sstevel@tonic-gate char *c = (char *)addr; 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate if (nbytes == 0) 280*0Sstevel@tonic-gate return (0); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) 283*0Sstevel@tonic-gate goto raw; 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate for (i = 0; i < nbytes; i++) { 286*0Sstevel@tonic-gate /* 287*0Sstevel@tonic-gate * We define a "printable character" to be one for which 288*0Sstevel@tonic-gate * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 289*0Sstevel@tonic-gate * or a character which is either backspace or the bell. 290*0Sstevel@tonic-gate * Backspace and the bell are regrettably special because 291*0Sstevel@tonic-gate * they fail the first two tests -- and yet they are entirely 292*0Sstevel@tonic-gate * printable. These are the only two control characters that 293*0Sstevel@tonic-gate * have meaning for the terminal and for which isprint(3C) and 294*0Sstevel@tonic-gate * isspace(3C) return 0. 295*0Sstevel@tonic-gate */ 296*0Sstevel@tonic-gate if (isprint(c[i]) || isspace(c[i]) || 297*0Sstevel@tonic-gate c[i] == '\b' || c[i] == '\a') 298*0Sstevel@tonic-gate continue; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate if (c[i] == '\0' && i > 0) { 301*0Sstevel@tonic-gate /* 302*0Sstevel@tonic-gate * This looks like it might be a string. Before we 303*0Sstevel@tonic-gate * assume that it is indeed a string, check the 304*0Sstevel@tonic-gate * remainder of the byte range; if it contains 305*0Sstevel@tonic-gate * additional non-nul characters, we'll assume that 306*0Sstevel@tonic-gate * it's a binary stream that just happens to look like 307*0Sstevel@tonic-gate * a string, and we'll print out the individual bytes. 308*0Sstevel@tonic-gate */ 309*0Sstevel@tonic-gate for (j = i + 1; j < nbytes; j++) { 310*0Sstevel@tonic-gate if (c[j] != '\0') 311*0Sstevel@tonic-gate break; 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate if (j != nbytes) 315*0Sstevel@tonic-gate break; 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate if (quiet) 318*0Sstevel@tonic-gate return (dt_printf(dtp, fp, "%s", c)); 319*0Sstevel@tonic-gate else 320*0Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, c)); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate break; 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if (i == nbytes) { 327*0Sstevel@tonic-gate /* 328*0Sstevel@tonic-gate * The byte range is all printable characters, but there is 329*0Sstevel@tonic-gate * no trailing nul byte. We'll assume that it's a string and 330*0Sstevel@tonic-gate * print it as such. 331*0Sstevel@tonic-gate */ 332*0Sstevel@tonic-gate char *s = alloca(nbytes + 1); 333*0Sstevel@tonic-gate bcopy(c, s, nbytes); 334*0Sstevel@tonic-gate s[nbytes] = '\0'; 335*0Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, s)); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate raw: 339*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) 340*0Sstevel@tonic-gate return (-1); 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate for (i = 0; i < 16; i++) 343*0Sstevel@tonic-gate if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) 344*0Sstevel@tonic-gate return (-1); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) 347*0Sstevel@tonic-gate return (-1); 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate for (i = 0; i < nbytes; i += 16) { 351*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) 352*0Sstevel@tonic-gate return (-1); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 355*0Sstevel@tonic-gate if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) 356*0Sstevel@tonic-gate return (-1); 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate while (j++ % 16) { 360*0Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 361*0Sstevel@tonic-gate return (-1); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 365*0Sstevel@tonic-gate return (-1); 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 368*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "%c", 369*0Sstevel@tonic-gate c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) 370*0Sstevel@tonic-gate return (-1); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 374*0Sstevel@tonic-gate return (-1); 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate return (0); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate int 381*0Sstevel@tonic-gate dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 382*0Sstevel@tonic-gate caddr_t addr, int depth) 383*0Sstevel@tonic-gate { 384*0Sstevel@tonic-gate pc_t *pc = (pc_t *)(uintptr_t)addr; 385*0Sstevel@tonic-gate dtrace_syminfo_t dts; 386*0Sstevel@tonic-gate GElf_Sym sym; 387*0Sstevel@tonic-gate int i, indent; 388*0Sstevel@tonic-gate char c[PATH_MAX * 2]; 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 391*0Sstevel@tonic-gate return (-1); 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate if (format == NULL) 394*0Sstevel@tonic-gate format = "%s"; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 397*0Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 398*0Sstevel@tonic-gate else 399*0Sstevel@tonic-gate indent = _dtrace_stkindent; 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate for (i = 0; i < depth && pc[i] != NULL; i++) { 402*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s", indent, "") < 0) 403*0Sstevel@tonic-gate return (-1); 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate if (dtrace_lookup_by_addr(dtp, pc[i], &sym, &dts) == 0) { 406*0Sstevel@tonic-gate if (pc[i] > sym.st_value) { 407*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", 408*0Sstevel@tonic-gate dts.dts_object, dts.dts_name, 409*0Sstevel@tonic-gate (u_longlong_t)pc[i] - sym.st_value); 410*0Sstevel@tonic-gate } else { 411*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s", 412*0Sstevel@tonic-gate dts.dts_object, dts.dts_name); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate } else { 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * We'll repeat the lookup, but this time we'll specify 417*0Sstevel@tonic-gate * a NULL GElf_Sym -- indicating that we're only 418*0Sstevel@tonic-gate * interested in the containing module. 419*0Sstevel@tonic-gate */ 420*0Sstevel@tonic-gate if (dtrace_lookup_by_addr(dtp, pc[i], 421*0Sstevel@tonic-gate NULL, &dts) == 0) { 422*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 423*0Sstevel@tonic-gate dts.dts_object, (u_longlong_t)pc[i]); 424*0Sstevel@tonic-gate } else { 425*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "0x%llx", 426*0Sstevel@tonic-gate (u_longlong_t)pc[i]); 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate } 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate if (dt_printf(dtp, fp, format, c) < 0) 431*0Sstevel@tonic-gate return (-1); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 434*0Sstevel@tonic-gate return (-1); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate return (0); 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate int 441*0Sstevel@tonic-gate dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 442*0Sstevel@tonic-gate caddr_t addr, uint64_t arg) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate uint64_t *pc = (uint64_t *)(uintptr_t)addr; 445*0Sstevel@tonic-gate uint32_t depth = DTRACE_USTACK_NFRAMES(arg); 446*0Sstevel@tonic-gate uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); 447*0Sstevel@tonic-gate const char *strbase = addr + (depth + 1) * sizeof (uint64_t); 448*0Sstevel@tonic-gate const char *str = strsize ? strbase : NULL; 449*0Sstevel@tonic-gate int err = 0; 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 452*0Sstevel@tonic-gate struct ps_prochandle *P; 453*0Sstevel@tonic-gate GElf_Sym sym; 454*0Sstevel@tonic-gate int i, indent; 455*0Sstevel@tonic-gate pid_t pid; 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate if (depth == 0) 458*0Sstevel@tonic-gate return (0); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate pid = (pid_t)*pc++; 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 463*0Sstevel@tonic-gate return (-1); 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate if (format == NULL) 466*0Sstevel@tonic-gate format = "%s"; 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 469*0Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 470*0Sstevel@tonic-gate else 471*0Sstevel@tonic-gate indent = _dtrace_stkindent; 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate /* 474*0Sstevel@tonic-gate * Ultimately, we need to add an entry point in the library vector for 475*0Sstevel@tonic-gate * determining <symbol, offset> from <pid, address>. For now, if 476*0Sstevel@tonic-gate * this is a vector open, we just print the raw address or string. 477*0Sstevel@tonic-gate */ 478*0Sstevel@tonic-gate if (dtp->dt_vector == NULL) 479*0Sstevel@tonic-gate P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 480*0Sstevel@tonic-gate else 481*0Sstevel@tonic-gate P = NULL; 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate if (P != NULL) 484*0Sstevel@tonic-gate dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate for (i = 0; i < depth && pc[i] != NULL; i++) { 487*0Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 488*0Sstevel@tonic-gate break; 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate if (P != NULL && Plookup_by_addr(P, pc[i], 491*0Sstevel@tonic-gate name, sizeof (name), &sym) == 0) { 492*0Sstevel@tonic-gate (void) Pobjname(P, pc[i], objname, sizeof (objname)); 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate if (pc[i] > sym.st_value) { 495*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 496*0Sstevel@tonic-gate "%s`%s+0x%llx", dt_basename(objname), name, 497*0Sstevel@tonic-gate (u_longlong_t)(pc[i] - sym.st_value)); 498*0Sstevel@tonic-gate } else { 499*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 500*0Sstevel@tonic-gate "%s`%s", dt_basename(objname), name); 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate } else if (str != NULL && str[0] != '\0') { 503*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s", str); 504*0Sstevel@tonic-gate } else { 505*0Sstevel@tonic-gate if (P != NULL && Pobjname(P, pc[i], objname, 506*0Sstevel@tonic-gate sizeof (objname)) != NULL) { 507*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 508*0Sstevel@tonic-gate dt_basename(objname), (u_longlong_t)pc[i]); 509*0Sstevel@tonic-gate } else { 510*0Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "0x%llx", 511*0Sstevel@tonic-gate (u_longlong_t)pc[i]); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate } 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, format, c)) < 0) 516*0Sstevel@tonic-gate break; 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "\n")) < 0) 519*0Sstevel@tonic-gate break; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate if (str != NULL) { 522*0Sstevel@tonic-gate str += strlen(str) + 1; 523*0Sstevel@tonic-gate if (str - strbase >= strsize) 524*0Sstevel@tonic-gate str = NULL; 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate if (P != NULL) { 529*0Sstevel@tonic-gate dt_proc_unlock(dtp, P); 530*0Sstevel@tonic-gate dt_proc_release(dtp, P); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate return (err); 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate typedef struct dt_normal { 537*0Sstevel@tonic-gate dtrace_aggvarid_t dtnd_id; 538*0Sstevel@tonic-gate uint64_t dtnd_normal; 539*0Sstevel@tonic-gate } dt_normal_t; 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate static int 542*0Sstevel@tonic-gate dt_normalize_agg(dtrace_aggdata_t *aggdata, void *arg) 543*0Sstevel@tonic-gate { 544*0Sstevel@tonic-gate dt_normal_t *normal = arg; 545*0Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 546*0Sstevel@tonic-gate dtrace_aggvarid_t id = normal->dtnd_id; 547*0Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 550*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 553*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate aggdata->dtada_normal = normal->dtnd_normal; 556*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NORMALIZE); 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate static int 560*0Sstevel@tonic-gate dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 561*0Sstevel@tonic-gate { 562*0Sstevel@tonic-gate dt_normal_t normal; 563*0Sstevel@tonic-gate caddr_t addr; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 567*0Sstevel@tonic-gate * normalization value. 568*0Sstevel@tonic-gate */ 569*0Sstevel@tonic-gate addr = base + rec->dtrd_offset; 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 572*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate /* LINTED - alignment */ 575*0Sstevel@tonic-gate normal.dtnd_id = *((dtrace_aggvarid_t *)addr); 576*0Sstevel@tonic-gate rec++; 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 579*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_NORMALIZE) 582*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate addr = base + rec->dtrd_offset; 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate switch (rec->dtrd_size) { 587*0Sstevel@tonic-gate case sizeof (uint64_t): 588*0Sstevel@tonic-gate /* LINTED - alignment */ 589*0Sstevel@tonic-gate normal.dtnd_normal = *((uint64_t *)addr); 590*0Sstevel@tonic-gate break; 591*0Sstevel@tonic-gate case sizeof (uint32_t): 592*0Sstevel@tonic-gate /* LINTED - alignment */ 593*0Sstevel@tonic-gate normal.dtnd_normal = *((uint32_t *)addr); 594*0Sstevel@tonic-gate break; 595*0Sstevel@tonic-gate case sizeof (uint16_t): 596*0Sstevel@tonic-gate /* LINTED - alignment */ 597*0Sstevel@tonic-gate normal.dtnd_normal = *((uint16_t *)addr); 598*0Sstevel@tonic-gate break; 599*0Sstevel@tonic-gate case sizeof (uint8_t): 600*0Sstevel@tonic-gate normal.dtnd_normal = *((uint8_t *)addr); 601*0Sstevel@tonic-gate break; 602*0Sstevel@tonic-gate default: 603*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal); 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate return (0); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate static int 612*0Sstevel@tonic-gate dt_denormalize_agg(dtrace_aggdata_t *aggdata, void *arg) 613*0Sstevel@tonic-gate { 614*0Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 615*0Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 616*0Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 619*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 622*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate return (DTRACE_AGGWALK_DENORMALIZE); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate static int 628*0Sstevel@tonic-gate dt_clear_agg(dtrace_aggdata_t *aggdata, void *arg) 629*0Sstevel@tonic-gate { 630*0Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 631*0Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 632*0Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 635*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 638*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate return (DTRACE_AGGWALK_CLEAR); 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate typedef struct dt_trunc { 644*0Sstevel@tonic-gate dtrace_aggvarid_t dttd_id; 645*0Sstevel@tonic-gate uint64_t dttd_remaining; 646*0Sstevel@tonic-gate } dt_trunc_t; 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate static int 649*0Sstevel@tonic-gate dt_trunc_agg(dtrace_aggdata_t *aggdata, void *arg) 650*0Sstevel@tonic-gate { 651*0Sstevel@tonic-gate dt_trunc_t *trunc = arg; 652*0Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 653*0Sstevel@tonic-gate dtrace_aggvarid_t id = trunc->dttd_id; 654*0Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 657*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset)) 660*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate if (trunc->dttd_remaining == 0) 663*0Sstevel@tonic-gate return (DTRACE_AGGWALK_REMOVE); 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate trunc->dttd_remaining--; 666*0Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 667*0Sstevel@tonic-gate } 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate static int 670*0Sstevel@tonic-gate dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 671*0Sstevel@tonic-gate { 672*0Sstevel@tonic-gate dt_trunc_t trunc; 673*0Sstevel@tonic-gate caddr_t addr; 674*0Sstevel@tonic-gate int64_t remaining; 675*0Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *); 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate /* 678*0Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 679*0Sstevel@tonic-gate * number of aggregation entries after which the aggregation is to be 680*0Sstevel@tonic-gate * truncated. 681*0Sstevel@tonic-gate */ 682*0Sstevel@tonic-gate addr = base + rec->dtrd_offset; 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 685*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate /* LINTED - alignment */ 688*0Sstevel@tonic-gate trunc.dttd_id = *((dtrace_aggvarid_t *)addr); 689*0Sstevel@tonic-gate rec++; 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 692*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_TRUNC) 695*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate addr = base + rec->dtrd_offset; 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate switch (rec->dtrd_size) { 700*0Sstevel@tonic-gate case sizeof (uint64_t): 701*0Sstevel@tonic-gate /* LINTED - alignment */ 702*0Sstevel@tonic-gate remaining = *((int64_t *)addr); 703*0Sstevel@tonic-gate break; 704*0Sstevel@tonic-gate case sizeof (uint32_t): 705*0Sstevel@tonic-gate /* LINTED - alignment */ 706*0Sstevel@tonic-gate remaining = *((int32_t *)addr); 707*0Sstevel@tonic-gate break; 708*0Sstevel@tonic-gate case sizeof (uint16_t): 709*0Sstevel@tonic-gate /* LINTED - alignment */ 710*0Sstevel@tonic-gate remaining = *((int16_t *)addr); 711*0Sstevel@tonic-gate break; 712*0Sstevel@tonic-gate case sizeof (uint8_t): 713*0Sstevel@tonic-gate remaining = *((int8_t *)addr); 714*0Sstevel@tonic-gate break; 715*0Sstevel@tonic-gate default: 716*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate if (remaining < 0) { 720*0Sstevel@tonic-gate func = dtrace_aggregate_walk_valsorted; 721*0Sstevel@tonic-gate remaining = -remaining; 722*0Sstevel@tonic-gate } else { 723*0Sstevel@tonic-gate func = dtrace_aggregate_walk_valrevsorted; 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate assert(remaining >= 0); 727*0Sstevel@tonic-gate trunc.dttd_remaining = remaining; 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate (void) func(dtp, dt_trunc_agg, &trunc); 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate return (0); 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate int 735*0Sstevel@tonic-gate dt_print_agg(dtrace_aggdata_t *aggdata, void *arg) 736*0Sstevel@tonic-gate { 737*0Sstevel@tonic-gate int i, err = 0; 738*0Sstevel@tonic-gate dt_print_aggdata_t *pd = arg; 739*0Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 740*0Sstevel@tonic-gate FILE *fp = pd->dtpa_fp; 741*0Sstevel@tonic-gate dtrace_hdl_t *dtp = pd->dtpa_dtp; 742*0Sstevel@tonic-gate dtrace_aggvarid_t aggvarid = pd->dtpa_id; 743*0Sstevel@tonic-gate uintptr_t data = (uintptr_t)aggdata->dtada_data; 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate if (pd->dtpa_allunprint) { 746*0Sstevel@tonic-gate if (agg->dtagd_flags & DTRACE_AGD_PRINTED) 747*0Sstevel@tonic-gate return (0); 748*0Sstevel@tonic-gate } else { 749*0Sstevel@tonic-gate /* 750*0Sstevel@tonic-gate * If we're not printing all unprinted aggregations, then the 751*0Sstevel@tonic-gate * aggregation variable ID denotes a specific aggregation 752*0Sstevel@tonic-gate * variable that we should print -- skip any other aggregations 753*0Sstevel@tonic-gate * that we encounter. 754*0Sstevel@tonic-gate */ 755*0Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 756*0Sstevel@tonic-gate return (0); 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate if (aggvarid != *(dtrace_aggvarid_t *)(data + 759*0Sstevel@tonic-gate agg->dtagd_rec[0].dtrd_offset)) 760*0Sstevel@tonic-gate return (0); 761*0Sstevel@tonic-gate } 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate /* 764*0Sstevel@tonic-gate * Iterate over each record description, printing the traced data, 765*0Sstevel@tonic-gate * skipping the first datum (the tuple member created by the compiler). 766*0Sstevel@tonic-gate */ 767*0Sstevel@tonic-gate for (i = 1; err >= 0 && i < agg->dtagd_nrecs; i++) { 768*0Sstevel@tonic-gate dtrace_recdesc_t *rec = &agg->dtagd_rec[i]; 769*0Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action; 770*0Sstevel@tonic-gate caddr_t addr = aggdata->dtada_data + rec->dtrd_offset; 771*0Sstevel@tonic-gate size_t size = rec->dtrd_size; 772*0Sstevel@tonic-gate uint64_t normal; 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate normal = DTRACEACT_ISAGG(act) ? aggdata->dtada_normal : 1; 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate if (act == DTRACEACT_STACK) { 777*0Sstevel@tonic-gate int depth = rec->dtrd_size / sizeof (pc_t); 778*0Sstevel@tonic-gate err = dt_print_stack(dtp, fp, NULL, addr, depth); 779*0Sstevel@tonic-gate goto nextrec; 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate 782*0Sstevel@tonic-gate if (act == DTRACEACT_USTACK || act == DTRACEACT_JSTACK) { 783*0Sstevel@tonic-gate err = dt_print_ustack(dtp, fp, NULL, addr, 784*0Sstevel@tonic-gate rec->dtrd_arg); 785*0Sstevel@tonic-gate goto nextrec; 786*0Sstevel@tonic-gate } 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate if (act == DTRACEAGG_QUANTIZE) { 789*0Sstevel@tonic-gate err = dt_print_quantize(dtp, fp, addr, size, normal); 790*0Sstevel@tonic-gate goto nextrec; 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate if (act == DTRACEAGG_LQUANTIZE) { 794*0Sstevel@tonic-gate err = dt_print_lquantize(dtp, fp, addr, size, normal); 795*0Sstevel@tonic-gate goto nextrec; 796*0Sstevel@tonic-gate } 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate if (act == DTRACEAGG_AVG) { 799*0Sstevel@tonic-gate err = dt_print_average(dtp, fp, addr, size, normal); 800*0Sstevel@tonic-gate goto nextrec; 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate switch (size) { 804*0Sstevel@tonic-gate case sizeof (uint64_t): 805*0Sstevel@tonic-gate err = dt_printf(dtp, fp, " %16lld", 806*0Sstevel@tonic-gate /* LINTED - alignment */ 807*0Sstevel@tonic-gate (long long)*((uint64_t *)addr) / normal); 808*0Sstevel@tonic-gate break; 809*0Sstevel@tonic-gate case sizeof (uint32_t): 810*0Sstevel@tonic-gate /* LINTED - alignment */ 811*0Sstevel@tonic-gate err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) / 812*0Sstevel@tonic-gate (uint32_t)normal); 813*0Sstevel@tonic-gate break; 814*0Sstevel@tonic-gate case sizeof (uint16_t): 815*0Sstevel@tonic-gate /* LINTED - alignment */ 816*0Sstevel@tonic-gate err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) / 817*0Sstevel@tonic-gate (uint32_t)normal); 818*0Sstevel@tonic-gate break; 819*0Sstevel@tonic-gate case sizeof (uint8_t): 820*0Sstevel@tonic-gate err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) / 821*0Sstevel@tonic-gate (uint32_t)normal); 822*0Sstevel@tonic-gate break; 823*0Sstevel@tonic-gate default: 824*0Sstevel@tonic-gate err = dt_print_bytes(dtp, fp, addr, size, 50, 0); 825*0Sstevel@tonic-gate break; 826*0Sstevel@tonic-gate } 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate nextrec: 829*0Sstevel@tonic-gate if (dt_buffered_flush(dtp, NULL, rec, aggdata) < 0) 830*0Sstevel@tonic-gate return (-1); 831*0Sstevel@tonic-gate } 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate if (err >= 0) 834*0Sstevel@tonic-gate err = dt_printf(dtp, fp, "\n"); 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate if (dt_buffered_flush(dtp, NULL, NULL, aggdata) < 0) 837*0Sstevel@tonic-gate return (-1); 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate if (!pd->dtpa_allunprint) 840*0Sstevel@tonic-gate agg->dtagd_flags |= DTRACE_AGD_PRINTED; 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate return (err < 0 ? -1 : 0); 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate static int 846*0Sstevel@tonic-gate dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf, 847*0Sstevel@tonic-gate dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) 848*0Sstevel@tonic-gate { 849*0Sstevel@tonic-gate dtrace_epid_t id; 850*0Sstevel@tonic-gate size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size; 851*0Sstevel@tonic-gate int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 852*0Sstevel@tonic-gate int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 853*0Sstevel@tonic-gate int rval, i, n; 854*0Sstevel@tonic-gate dtrace_epid_t last = DTRACE_EPIDNONE; 855*0Sstevel@tonic-gate dtrace_probedata_t data; 856*0Sstevel@tonic-gate uint64_t drops; 857*0Sstevel@tonic-gate caddr_t addr; 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate bzero(&data, sizeof (data)); 860*0Sstevel@tonic-gate data.dtpda_handle = dtp; 861*0Sstevel@tonic-gate data.dtpda_cpu = cpu; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate again: 864*0Sstevel@tonic-gate for (offs = start; offs < end; ) { 865*0Sstevel@tonic-gate dtrace_eprobedesc_t *epd; 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate /* 868*0Sstevel@tonic-gate * We're guaranteed to have an ID. 869*0Sstevel@tonic-gate */ 870*0Sstevel@tonic-gate id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate if (id == DTRACE_EPIDNONE) { 873*0Sstevel@tonic-gate /* 874*0Sstevel@tonic-gate * This is filler to assure proper alignment of the 875*0Sstevel@tonic-gate * next record; we simply ignore it. 876*0Sstevel@tonic-gate */ 877*0Sstevel@tonic-gate offs += sizeof (id); 878*0Sstevel@tonic-gate continue; 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc, 882*0Sstevel@tonic-gate &data.dtpda_pdesc)) != 0) 883*0Sstevel@tonic-gate return (rval); 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate epd = data.dtpda_edesc; 886*0Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs; 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) { 889*0Sstevel@tonic-gate rval = dt_handle(dtp, &data); 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 892*0Sstevel@tonic-gate goto nextepid; 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ERROR) 895*0Sstevel@tonic-gate return (-1); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate if (flow) 899*0Sstevel@tonic-gate (void) dt_flowindent(dtp, &data, last, buf, offs); 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate rval = (*efunc)(&data, arg); 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate if (flow) { 904*0Sstevel@tonic-gate if (data.dtpda_flow == DTRACEFLOW_ENTRY) 905*0Sstevel@tonic-gate data.dtpda_indent += 2; 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 909*0Sstevel@tonic-gate goto nextepid; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 912*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 915*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate for (i = 0; i < epd->dtepd_nrecs; i++) { 918*0Sstevel@tonic-gate dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; 919*0Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action; 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs + 922*0Sstevel@tonic-gate rec->dtrd_offset; 923*0Sstevel@tonic-gate addr = data.dtpda_data; 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate if (act == DTRACEACT_LIBACT) { 926*0Sstevel@tonic-gate if (rec->dtrd_arg == DT_ACT_CLEAR) { 927*0Sstevel@tonic-gate dtrace_aggvarid_t id; 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate /* LINTED - alignment */ 930*0Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 931*0Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 932*0Sstevel@tonic-gate dt_clear_agg, &id); 933*0Sstevel@tonic-gate continue; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate if (rec->dtrd_arg == DT_ACT_DENORMALIZE) { 937*0Sstevel@tonic-gate dtrace_aggvarid_t id; 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate /* LINTED - alignment */ 940*0Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 941*0Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 942*0Sstevel@tonic-gate dt_denormalize_agg, &id); 943*0Sstevel@tonic-gate continue; 944*0Sstevel@tonic-gate } 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate if (rec->dtrd_arg == DT_ACT_NORMALIZE) { 947*0Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 948*0Sstevel@tonic-gate return (dt_set_errno(dtp, 949*0Sstevel@tonic-gate EDT_BADNORMAL)); 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate if (dt_normalize(dtp, 952*0Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 953*0Sstevel@tonic-gate return (-1); 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate i++; 956*0Sstevel@tonic-gate continue; 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate if (rec->dtrd_arg == DT_ACT_TRUNC) { 960*0Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 961*0Sstevel@tonic-gate return (dt_set_errno(dtp, 962*0Sstevel@tonic-gate EDT_BADTRUNC)); 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate if (dt_trunc(dtp, 965*0Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 966*0Sstevel@tonic-gate return (-1); 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate i++; 969*0Sstevel@tonic-gate continue; 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate if (rec->dtrd_arg == DT_ACT_FTRUNCATE) { 973*0Sstevel@tonic-gate if (fp == NULL) 974*0Sstevel@tonic-gate continue; 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate (void) fflush(fp); 977*0Sstevel@tonic-gate (void) ftruncate(fileno(fp), 0); 978*0Sstevel@tonic-gate (void) fseeko(fp, 0, SEEK_SET); 979*0Sstevel@tonic-gate continue; 980*0Sstevel@tonic-gate } 981*0Sstevel@tonic-gate } 982*0Sstevel@tonic-gate 983*0Sstevel@tonic-gate rval = (*rfunc)(&data, rec, arg); 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 986*0Sstevel@tonic-gate continue; 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 989*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 992*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate if (act == DTRACEACT_STACK) { 995*0Sstevel@tonic-gate int depth = rec->dtrd_size / sizeof (pc_t); 996*0Sstevel@tonic-gate if (dt_print_stack(dtp, fp, NULL, 997*0Sstevel@tonic-gate addr, depth) < 0) 998*0Sstevel@tonic-gate return (-1); 999*0Sstevel@tonic-gate goto nextrec; 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate if (act == DTRACEACT_USTACK || 1003*0Sstevel@tonic-gate act == DTRACEACT_JSTACK) { 1004*0Sstevel@tonic-gate if (dt_print_ustack(dtp, fp, NULL, 1005*0Sstevel@tonic-gate addr, rec->dtrd_arg) < 0) 1006*0Sstevel@tonic-gate return (-1); 1007*0Sstevel@tonic-gate goto nextrec; 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate if (DTRACEACT_ISPRINTFLIKE(act)) { 1011*0Sstevel@tonic-gate void *fmtdata; 1012*0Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, FILE *, void *, 1013*0Sstevel@tonic-gate const dtrace_probedata_t *, 1014*0Sstevel@tonic-gate const dtrace_recdesc_t *, uint_t, 1015*0Sstevel@tonic-gate const void *buf, size_t); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate if ((fmtdata = dt_format_lookup(dtp, 1018*0Sstevel@tonic-gate rec->dtrd_format)) == NULL) 1019*0Sstevel@tonic-gate goto nofmt; 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate switch (act) { 1022*0Sstevel@tonic-gate case DTRACEACT_PRINTF: 1023*0Sstevel@tonic-gate func = dtrace_fprintf; 1024*0Sstevel@tonic-gate break; 1025*0Sstevel@tonic-gate case DTRACEACT_PRINTA: 1026*0Sstevel@tonic-gate func = dtrace_fprinta; 1027*0Sstevel@tonic-gate break; 1028*0Sstevel@tonic-gate case DTRACEACT_SYSTEM: 1029*0Sstevel@tonic-gate func = dtrace_system; 1030*0Sstevel@tonic-gate break; 1031*0Sstevel@tonic-gate case DTRACEACT_FREOPEN: 1032*0Sstevel@tonic-gate func = dtrace_freopen; 1033*0Sstevel@tonic-gate break; 1034*0Sstevel@tonic-gate } 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate n = (*func)(dtp, fp, fmtdata, &data, 1037*0Sstevel@tonic-gate rec, epd->dtepd_nrecs - i, 1038*0Sstevel@tonic-gate (uchar_t *)buf->dtbd_data + offs, 1039*0Sstevel@tonic-gate buf->dtbd_size - offs); 1040*0Sstevel@tonic-gate 1041*0Sstevel@tonic-gate if (n < 0) 1042*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate if (n > 0) 1045*0Sstevel@tonic-gate i += n - 1; 1046*0Sstevel@tonic-gate goto nextrec; 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate nofmt: 1050*0Sstevel@tonic-gate if (act == DTRACEACT_PRINTA) { 1051*0Sstevel@tonic-gate dt_print_aggdata_t pd; 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate bzero(&pd, sizeof (pd)); 1054*0Sstevel@tonic-gate pd.dtpa_dtp = dtp; 1055*0Sstevel@tonic-gate pd.dtpa_fp = fp; 1056*0Sstevel@tonic-gate /* LINTED - alignment */ 1057*0Sstevel@tonic-gate pd.dtpa_id = *((dtrace_aggvarid_t *)addr); 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0 || 1060*0Sstevel@tonic-gate dtrace_aggregate_walk_valsorted(dtp, 1061*0Sstevel@tonic-gate dt_print_agg, &pd) < 0) 1062*0Sstevel@tonic-gate return (-1); 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate goto nextrec; 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate switch (rec->dtrd_size) { 1068*0Sstevel@tonic-gate case sizeof (uint64_t): 1069*0Sstevel@tonic-gate n = dt_printf(dtp, fp, 1070*0Sstevel@tonic-gate quiet ? "%lld" : " %16lld", 1071*0Sstevel@tonic-gate /* LINTED - alignment */ 1072*0Sstevel@tonic-gate *((unsigned long long *)addr)); 1073*0Sstevel@tonic-gate break; 1074*0Sstevel@tonic-gate case sizeof (uint32_t): 1075*0Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %8d", 1076*0Sstevel@tonic-gate /* LINTED - alignment */ 1077*0Sstevel@tonic-gate *((uint32_t *)addr)); 1078*0Sstevel@tonic-gate break; 1079*0Sstevel@tonic-gate case sizeof (uint16_t): 1080*0Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %5d", 1081*0Sstevel@tonic-gate /* LINTED - alignment */ 1082*0Sstevel@tonic-gate *((uint16_t *)addr)); 1083*0Sstevel@tonic-gate break; 1084*0Sstevel@tonic-gate case sizeof (uint8_t): 1085*0Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %3d", 1086*0Sstevel@tonic-gate *((uint8_t *)addr)); 1087*0Sstevel@tonic-gate break; 1088*0Sstevel@tonic-gate default: 1089*0Sstevel@tonic-gate n = dt_print_bytes(dtp, fp, addr, 1090*0Sstevel@tonic-gate rec->dtrd_size, 33, quiet); 1091*0Sstevel@tonic-gate break; 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate if (n < 0) 1095*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate nextrec: 1098*0Sstevel@tonic-gate if (dt_buffered_flush(dtp, &data, rec, NULL) < 0) 1099*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate /* 1103*0Sstevel@tonic-gate * Call the record callback with a NULL record to indicate 1104*0Sstevel@tonic-gate * that we're done processing this EPID. 1105*0Sstevel@tonic-gate */ 1106*0Sstevel@tonic-gate rval = (*rfunc)(&data, NULL, arg); 1107*0Sstevel@tonic-gate nextepid: 1108*0Sstevel@tonic-gate offs += epd->dtepd_size; 1109*0Sstevel@tonic-gate last = id; 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) { 1113*0Sstevel@tonic-gate end = buf->dtbd_oldest; 1114*0Sstevel@tonic-gate start = 0; 1115*0Sstevel@tonic-gate goto again; 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate if ((drops = buf->dtbd_drops) == 0) 1119*0Sstevel@tonic-gate return (0); 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate /* 1122*0Sstevel@tonic-gate * Explicitly zero the drops to prevent us from processing them again. 1123*0Sstevel@tonic-gate */ 1124*0Sstevel@tonic-gate buf->dtbd_drops = 0; 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); 1127*0Sstevel@tonic-gate } 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate typedef struct dt_begin { 1130*0Sstevel@tonic-gate dtrace_consume_probe_f *dtbgn_probefunc; 1131*0Sstevel@tonic-gate dtrace_consume_rec_f *dtbgn_recfunc; 1132*0Sstevel@tonic-gate void *dtbgn_arg; 1133*0Sstevel@tonic-gate dtrace_handle_err_f *dtbgn_errhdlr; 1134*0Sstevel@tonic-gate void *dtbgn_errarg; 1135*0Sstevel@tonic-gate int dtbgn_beginonly; 1136*0Sstevel@tonic-gate } dt_begin_t; 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate static int 1139*0Sstevel@tonic-gate dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) 1140*0Sstevel@tonic-gate { 1141*0Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 1142*0Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc; 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 1145*0Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 1148*0Sstevel@tonic-gate if (!(r1 && r2)) 1149*0Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 1150*0Sstevel@tonic-gate } else { 1151*0Sstevel@tonic-gate if (r1 && r2) 1152*0Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 1153*0Sstevel@tonic-gate } 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate /* 1156*0Sstevel@tonic-gate * We have a record that we're interested in. Now call the underlying 1157*0Sstevel@tonic-gate * probe function... 1158*0Sstevel@tonic-gate */ 1159*0Sstevel@tonic-gate return (begin->dtbgn_probefunc(data, begin->dtbgn_arg)); 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate static int 1163*0Sstevel@tonic-gate dt_consume_begin_record(const dtrace_probedata_t *data, 1164*0Sstevel@tonic-gate const dtrace_recdesc_t *rec, void *arg) 1165*0Sstevel@tonic-gate { 1166*0Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate static int 1172*0Sstevel@tonic-gate dt_consume_begin_error(dtrace_errdata_t *data, void *arg) 1173*0Sstevel@tonic-gate { 1174*0Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 1175*0Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dteda_pdesc; 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 1178*0Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 1181*0Sstevel@tonic-gate if (!(r1 && r2)) 1182*0Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 1183*0Sstevel@tonic-gate } else { 1184*0Sstevel@tonic-gate if (r1 && r2) 1185*0Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 1186*0Sstevel@tonic-gate } 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg)); 1189*0Sstevel@tonic-gate } 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate static int 1192*0Sstevel@tonic-gate dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, 1193*0Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 1194*0Sstevel@tonic-gate { 1195*0Sstevel@tonic-gate /* 1196*0Sstevel@tonic-gate * There's this idea that the BEGIN probe should be processed before 1197*0Sstevel@tonic-gate * everything else, and that the END probe should be processed after 1198*0Sstevel@tonic-gate * anything else. In the common case, this is pretty easy to deal 1199*0Sstevel@tonic-gate * with. However, a situation may arise where the BEGIN enabling and 1200*0Sstevel@tonic-gate * END enabling are on the same CPU, and some enabling in the middle 1201*0Sstevel@tonic-gate * occurred on a different CPU. To deal with this (blech!) we need to 1202*0Sstevel@tonic-gate * consume the BEGIN buffer up until the end of the BEGIN probe, and 1203*0Sstevel@tonic-gate * then set it aside. We will then process every other CPU, and then 1204*0Sstevel@tonic-gate * we'll return to the BEGIN CPU and process the rest of the data 1205*0Sstevel@tonic-gate * (which will inevitably include the END probe, if any). Making this 1206*0Sstevel@tonic-gate * even more complicated (!) is the library's ERROR enabling. Because 1207*0Sstevel@tonic-gate * this enabling is processed before we even get into the consume call 1208*0Sstevel@tonic-gate * back, any ERROR firing would result in the library's ERROR enabling 1209*0Sstevel@tonic-gate * being processed twice -- once in our first pass (for BEGIN probes), 1210*0Sstevel@tonic-gate * and again in our second pass (for everything but BEGIN probes). To 1211*0Sstevel@tonic-gate * deal with this, we interpose on the ERROR handler to assure that we 1212*0Sstevel@tonic-gate * only process ERROR enablings induced by BEGIN enablings in the 1213*0Sstevel@tonic-gate * first pass, and that we only process ERROR enablings _not_ induced 1214*0Sstevel@tonic-gate * by BEGIN enablings in the second pass. 1215*0Sstevel@tonic-gate */ 1216*0Sstevel@tonic-gate dt_begin_t begin; 1217*0Sstevel@tonic-gate processorid_t cpu = dtp->dt_beganon; 1218*0Sstevel@tonic-gate dtrace_bufdesc_t nbuf; 1219*0Sstevel@tonic-gate int rval, i; 1220*0Sstevel@tonic-gate static int max_ncpus; 1221*0Sstevel@tonic-gate dtrace_optval_t size; 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate dtp->dt_beganon = -1; 1224*0Sstevel@tonic-gate 1225*0Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 1226*0Sstevel@tonic-gate /* 1227*0Sstevel@tonic-gate * We really don't expect this to fail, but it is at least 1228*0Sstevel@tonic-gate * technically possible for this to fail with ENOENT. In this 1229*0Sstevel@tonic-gate * case, we just drive on... 1230*0Sstevel@tonic-gate */ 1231*0Sstevel@tonic-gate if (errno == ENOENT) 1232*0Sstevel@tonic-gate return (0); 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 1235*0Sstevel@tonic-gate } 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { 1238*0Sstevel@tonic-gate /* 1239*0Sstevel@tonic-gate * This is the simple case. We're either not stopped, or if 1240*0Sstevel@tonic-gate * we are, we actually processed any END probes on another 1241*0Sstevel@tonic-gate * CPU. We can simply consume this buffer and return. 1242*0Sstevel@tonic-gate */ 1243*0Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg)); 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate begin.dtbgn_probefunc = pf; 1247*0Sstevel@tonic-gate begin.dtbgn_recfunc = rf; 1248*0Sstevel@tonic-gate begin.dtbgn_arg = arg; 1249*0Sstevel@tonic-gate begin.dtbgn_beginonly = 1; 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate /* 1252*0Sstevel@tonic-gate * We need to interpose on the ERROR handler to be sure that we 1253*0Sstevel@tonic-gate * only process ERRORs induced by BEGIN. 1254*0Sstevel@tonic-gate */ 1255*0Sstevel@tonic-gate begin.dtbgn_errhdlr = dtp->dt_errhdlr; 1256*0Sstevel@tonic-gate begin.dtbgn_errarg = dtp->dt_errarg; 1257*0Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 1258*0Sstevel@tonic-gate dtp->dt_errarg = &begin; 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, 1261*0Sstevel@tonic-gate dt_consume_begin_record, &begin); 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 1264*0Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate if (rval != 0) 1267*0Sstevel@tonic-gate return (rval); 1268*0Sstevel@tonic-gate 1269*0Sstevel@tonic-gate /* 1270*0Sstevel@tonic-gate * Now allocate a new buffer. We'll use this to deal with every other 1271*0Sstevel@tonic-gate * CPU. 1272*0Sstevel@tonic-gate */ 1273*0Sstevel@tonic-gate bzero(&nbuf, sizeof (dtrace_bufdesc_t)); 1274*0Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size); 1275*0Sstevel@tonic-gate if ((nbuf.dtbd_data = malloc(size)) == NULL) 1276*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1277*0Sstevel@tonic-gate 1278*0Sstevel@tonic-gate if (max_ncpus == 0) 1279*0Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 1282*0Sstevel@tonic-gate nbuf.dtbd_cpu = i; 1283*0Sstevel@tonic-gate 1284*0Sstevel@tonic-gate if (i == cpu) 1285*0Sstevel@tonic-gate continue; 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) { 1288*0Sstevel@tonic-gate /* 1289*0Sstevel@tonic-gate * If we failed with ENOENT, it may be because the 1290*0Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other 1291*0Sstevel@tonic-gate * error, however, is unexpected. 1292*0Sstevel@tonic-gate */ 1293*0Sstevel@tonic-gate if (errno == ENOENT) 1294*0Sstevel@tonic-gate continue; 1295*0Sstevel@tonic-gate 1296*0Sstevel@tonic-gate free(nbuf.dtbd_data); 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp, 1302*0Sstevel@tonic-gate i, &nbuf, pf, rf, arg)) != 0) { 1303*0Sstevel@tonic-gate free(nbuf.dtbd_data); 1304*0Sstevel@tonic-gate return (rval); 1305*0Sstevel@tonic-gate } 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate free(nbuf.dtbd_data); 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate /* 1311*0Sstevel@tonic-gate * Okay -- we're done with the other buffers. Now we want to 1312*0Sstevel@tonic-gate * reconsume the first buffer -- but this time we're looking for 1313*0Sstevel@tonic-gate * everything _but_ BEGIN. And of course, in order to only consume 1314*0Sstevel@tonic-gate * those ERRORs _not_ associated with BEGIN, we need to reinstall our 1315*0Sstevel@tonic-gate * ERROR interposition function... 1316*0Sstevel@tonic-gate */ 1317*0Sstevel@tonic-gate begin.dtbgn_beginonly = 0; 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr); 1320*0Sstevel@tonic-gate assert(begin.dtbgn_errarg == dtp->dt_errarg); 1321*0Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 1322*0Sstevel@tonic-gate dtp->dt_errarg = &begin; 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, 1325*0Sstevel@tonic-gate dt_consume_begin_record, &begin); 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 1328*0Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate return (rval); 1331*0Sstevel@tonic-gate } 1332*0Sstevel@tonic-gate 1333*0Sstevel@tonic-gate int 1334*0Sstevel@tonic-gate dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, 1335*0Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 1336*0Sstevel@tonic-gate { 1337*0Sstevel@tonic-gate dtrace_bufdesc_t *buf = &dtp->dt_buf; 1338*0Sstevel@tonic-gate dtrace_optval_t size; 1339*0Sstevel@tonic-gate static int max_ncpus; 1340*0Sstevel@tonic-gate int i, rval; 1341*0Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE]; 1342*0Sstevel@tonic-gate hrtime_t now = gethrtime(); 1343*0Sstevel@tonic-gate 1344*0Sstevel@tonic-gate if (dtp->dt_lastswitch != 0) { 1345*0Sstevel@tonic-gate if (now - dtp->dt_lastswitch < interval) 1346*0Sstevel@tonic-gate return (0); 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate dtp->dt_lastswitch += interval; 1349*0Sstevel@tonic-gate } else { 1350*0Sstevel@tonic-gate dtp->dt_lastswitch = now; 1351*0Sstevel@tonic-gate } 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate if (!dtp->dt_active) 1354*0Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL)); 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate if (max_ncpus == 0) 1357*0Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 1358*0Sstevel@tonic-gate 1359*0Sstevel@tonic-gate if (pf == NULL) 1360*0Sstevel@tonic-gate pf = (dtrace_consume_probe_f *)dt_nullprobe; 1361*0Sstevel@tonic-gate 1362*0Sstevel@tonic-gate if (rf == NULL) 1363*0Sstevel@tonic-gate rf = (dtrace_consume_rec_f *)dt_nullrec; 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate if (buf->dtbd_data == NULL) { 1366*0Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size); 1367*0Sstevel@tonic-gate if ((buf->dtbd_data = malloc(size)) == NULL) 1368*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate buf->dtbd_size = size; 1371*0Sstevel@tonic-gate } 1372*0Sstevel@tonic-gate 1373*0Sstevel@tonic-gate /* 1374*0Sstevel@tonic-gate * If we have just begun, we want to first process the CPU that 1375*0Sstevel@tonic-gate * executed the BEGIN probe (if any). 1376*0Sstevel@tonic-gate */ 1377*0Sstevel@tonic-gate if (dtp->dt_active && dtp->dt_beganon != -1) { 1378*0Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_beganon; 1379*0Sstevel@tonic-gate if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0) 1380*0Sstevel@tonic-gate return (rval); 1381*0Sstevel@tonic-gate } 1382*0Sstevel@tonic-gate 1383*0Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 1384*0Sstevel@tonic-gate buf->dtbd_cpu = i; 1385*0Sstevel@tonic-gate 1386*0Sstevel@tonic-gate /* 1387*0Sstevel@tonic-gate * If we have stopped, we want to process the CPU on which the 1388*0Sstevel@tonic-gate * END probe was processed only _after_ we have processed 1389*0Sstevel@tonic-gate * everything else. 1390*0Sstevel@tonic-gate */ 1391*0Sstevel@tonic-gate if (dtp->dt_stopped && (i == dtp->dt_endedon)) 1392*0Sstevel@tonic-gate continue; 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 1395*0Sstevel@tonic-gate /* 1396*0Sstevel@tonic-gate * If we failed with ENOENT, it may be because the 1397*0Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other 1398*0Sstevel@tonic-gate * error, however, is unexpected. 1399*0Sstevel@tonic-gate */ 1400*0Sstevel@tonic-gate if (errno == ENOENT) 1401*0Sstevel@tonic-gate continue; 1402*0Sstevel@tonic-gate 1403*0Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 1404*0Sstevel@tonic-gate } 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0) 1407*0Sstevel@tonic-gate return (rval); 1408*0Sstevel@tonic-gate } 1409*0Sstevel@tonic-gate 1410*0Sstevel@tonic-gate if (!dtp->dt_stopped) 1411*0Sstevel@tonic-gate return (0); 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_endedon; 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 1416*0Sstevel@tonic-gate /* 1417*0Sstevel@tonic-gate * This _really_ shouldn't fail, but it is strictly speaking 1418*0Sstevel@tonic-gate * possible for this to return ENOENT if the CPU that called 1419*0Sstevel@tonic-gate * the END enabling somehow managed to become unconfigured. 1420*0Sstevel@tonic-gate * It's unclear how the user can possibly expect anything 1421*0Sstevel@tonic-gate * rational to happen in this case -- the state has been thrown 1422*0Sstevel@tonic-gate * out along with the unconfigured CPU -- so we'll just drive 1423*0Sstevel@tonic-gate * on... 1424*0Sstevel@tonic-gate */ 1425*0Sstevel@tonic-gate if (errno == ENOENT) 1426*0Sstevel@tonic-gate return (0); 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 1429*0Sstevel@tonic-gate } 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg)); 1432*0Sstevel@tonic-gate } 1433