dt_consume.c revision 249367
138889Sjdp/* 2218822Sdim * CDDL HEADER START 385815Sobrien * 438889Sjdp * The contents of this file are subject to the terms of the 585815Sobrien * Common Development and Distribution License (the "License"). 638889Sjdp * You may not use this file except in compliance with the License. 738889Sjdp * 838889Sjdp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 938889Sjdp * or http://www.opensolaris.org/os/licensing. 1038889Sjdp * See the License for the specific language governing permissions 1138889Sjdp * and limitations under the License. 1238889Sjdp * 1338889Sjdp * When distributing Covered Code, include this CDDL HEADER in each 1438889Sjdp * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1538889Sjdp * If applicable, add the following below this CDDL HEADER, with the 1638889Sjdp * fields enclosed by brackets "[]" replaced with your own identifying 1785815Sobrien * information: Portions Copyright [yyyy] [name of copyright owner] 18218822Sdim * 1938889Sjdp * CDDL HEADER END 2089857Sobrien */ 2138889Sjdp/* 2285815Sobrien * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23130561Sobrien * Use is subject to license terms. 2438889Sjdp */ 25218822Sdim 2638889Sjdp/* 27218822Sdim * Copyright (c) 2011, Joyent, Inc. All rights reserved. 28218822Sdim * Copyright (c) 2012 by Delphix. All rights reserved. 29218822Sdim */ 30218822Sdim 31218822Sdim#include <stdlib.h> 32218822Sdim#include <strings.h> 33218822Sdim#include <errno.h> 34218822Sdim#include <unistd.h> 35218822Sdim#include <limits.h> 36218822Sdim#include <assert.h> 37218822Sdim#include <ctype.h> 38218822Sdim#if defined(sun) 39218822Sdim#include <alloca.h> 40218822Sdim#endif 41218822Sdim#include <dt_impl.h> 42218822Sdim#include <dt_pq.h> 43218822Sdim#if !defined(sun) 44218822Sdim#include <libproc_compat.h> 45218822Sdim#endif 46218822Sdim 47218822Sdim#define DT_MASK_LO 0x00000000FFFFFFFFULL 48218822Sdim 49218822Sdim/* 50218822Sdim * We declare this here because (1) we need it and (2) we want to avoid a 51218822Sdim * dependency on libm in libdtrace. 52218822Sdim */ 53218822Sdimstatic long double 54218822Sdimdt_fabsl(long double x) 55218822Sdim{ 56218822Sdim if (x < 0) 57218822Sdim return (-x); 58218822Sdim 59218822Sdim return (x); 60218822Sdim} 61218822Sdim 62218822Sdim/* 63218822Sdim * 128-bit arithmetic functions needed to support the stddev() aggregating 64218822Sdim * action. 65218822Sdim */ 66218822Sdimstatic int 67218822Sdimdt_gt_128(uint64_t *a, uint64_t *b) 68218822Sdim{ 69218822Sdim return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0])); 70218822Sdim} 71218822Sdim 72218822Sdimstatic int 73218822Sdimdt_ge_128(uint64_t *a, uint64_t *b) 74218822Sdim{ 75218822Sdim return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0])); 76218822Sdim} 77218822Sdim 78218822Sdimstatic int 79218822Sdimdt_le_128(uint64_t *a, uint64_t *b) 80218822Sdim{ 8138889Sjdp return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0])); 82218822Sdim} 83218822Sdim 84218822Sdim/* 85218822Sdim * Shift the 128-bit value in a by b. If b is positive, shift left. 8638889Sjdp * If b is negative, shift right. 87218822Sdim */ 88218822Sdimstatic void 8938889Sjdpdt_shift_128(uint64_t *a, int b) 9038889Sjdp{ 9138889Sjdp uint64_t mask; 9238889Sjdp 9385815Sobrien if (b == 0) 9485815Sobrien return; 9585815Sobrien 9685815Sobrien if (b < 0) { 9785815Sobrien b = -b; 9838889Sjdp if (b >= 64) { 9985815Sobrien a[0] = a[1] >> (b - 64); 10038889Sjdp a[1] = 0; 10138889Sjdp } else { 10238889Sjdp a[0] >>= b; 10338889Sjdp mask = 1LL << (64 - b); 10438889Sjdp mask -= 1; 10585815Sobrien a[0] |= ((a[1] & mask) << (64 - b)); 10638889Sjdp a[1] >>= b; 10738889Sjdp } 10838889Sjdp } else { 10985815Sobrien if (b >= 64) { 11085815Sobrien a[1] = a[0] << (b - 64); 11185815Sobrien a[0] = 0; 11285815Sobrien } else { 11338889Sjdp a[1] <<= b; 11438889Sjdp mask = a[0] >> (64 - b); 11538889Sjdp a[1] |= mask; 11685815Sobrien a[0] <<= b; 11738889Sjdp } 11838889Sjdp } 11938889Sjdp} 12038889Sjdp 12138889Sjdpstatic int 12238889Sjdpdt_nbits_128(uint64_t *a) 12338889Sjdp{ 12438889Sjdp int nbits = 0; 12538889Sjdp uint64_t tmp[2]; 12638889Sjdp uint64_t zero[2] = { 0, 0 }; 12738889Sjdp 12885815Sobrien tmp[0] = a[0]; 12985815Sobrien tmp[1] = a[1]; 13085815Sobrien 13185815Sobrien dt_shift_128(tmp, -1); 13285815Sobrien while (dt_gt_128(tmp, zero)) { 13385815Sobrien dt_shift_128(tmp, -1); 13485815Sobrien nbits++; 13538889Sjdp } 13638889Sjdp 13738889Sjdp return (nbits); 13838889Sjdp} 13938889Sjdp 14038889Sjdpstatic void 14138889Sjdpdt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference) 14238889Sjdp{ 14385815Sobrien uint64_t result[2]; 14438889Sjdp 14538889Sjdp result[0] = minuend[0] - subtrahend[0]; 14638889Sjdp result[1] = minuend[1] - subtrahend[1] - 14738889Sjdp (minuend[0] < subtrahend[0] ? 1 : 0); 14838889Sjdp 14938889Sjdp difference[0] = result[0]; 15038889Sjdp difference[1] = result[1]; 15138889Sjdp} 15238889Sjdp 15338889Sjdpstatic void 15438889Sjdpdt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) 15538889Sjdp{ 15638889Sjdp uint64_t result[2]; 15738889Sjdp 15838889Sjdp result[0] = addend1[0] + addend2[0]; 15938889Sjdp result[1] = addend1[1] + addend2[1] + 16038889Sjdp (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); 16138889Sjdp 16238889Sjdp sum[0] = result[0]; 16338889Sjdp sum[1] = result[1]; 16438889Sjdp} 16585815Sobrien 16638889Sjdp/* 16738889Sjdp * The basic idea is to break the 2 64-bit values into 4 32-bit values, 16838889Sjdp * use native multiplication on those, and then re-combine into the 169218822Sdim * resulting 128-bit value. 17038889Sjdp * 17185815Sobrien * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) = 17238889Sjdp * hi1 * hi2 << 64 + 173218822Sdim * hi1 * lo2 << 32 + 17438889Sjdp * hi2 * lo1 << 32 + 17585815Sobrien * lo1 * lo2 17638889Sjdp */ 177218822Sdimstatic void 17838889Sjdpdt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product) 17985815Sobrien{ 18038889Sjdp uint64_t hi1, hi2, lo1, lo2; 181218822Sdim uint64_t tmp[2]; 18238889Sjdp 18385815Sobrien hi1 = factor1 >> 32; 18438889Sjdp hi2 = factor2 >> 32; 185218822Sdim 18638889Sjdp lo1 = factor1 & DT_MASK_LO; 18738889Sjdp lo2 = factor2 & DT_MASK_LO; 18838889Sjdp 189218822Sdim product[0] = lo1 * lo2; 19038889Sjdp product[1] = hi1 * hi2; 19138889Sjdp 19238889Sjdp tmp[0] = hi1 * lo2; 193218822Sdim tmp[1] = 0; 19485815Sobrien dt_shift_128(tmp, 32); 19585815Sobrien dt_add_128(product, tmp, product); 19638889Sjdp 197218822Sdim tmp[0] = hi2 * lo1; 19885815Sobrien tmp[1] = 0; 19985815Sobrien dt_shift_128(tmp, 32); 20038889Sjdp dt_add_128(product, tmp, product); 201218822Sdim} 20285815Sobrien 20385815Sobrien/* 20485815Sobrien * This is long-hand division. 20585815Sobrien * 20685815Sobrien * We initialize subtrahend by shifting divisor left as far as possible. We 20785815Sobrien * loop, comparing subtrahend to dividend: if subtrahend is smaller, we 20885815Sobrien * subtract and set the appropriate bit in the result. We then shift 20985815Sobrien * subtrahend right by one bit for the next comparison. 21085815Sobrien */ 21185815Sobrienstatic void 21285815Sobriendt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient) 21385815Sobrien{ 21485815Sobrien uint64_t result[2] = { 0, 0 }; 21585815Sobrien uint64_t remainder[2]; 21685815Sobrien uint64_t subtrahend[2]; 21785815Sobrien uint64_t divisor_128[2]; 21885815Sobrien uint64_t mask[2] = { 1, 0 }; 21985815Sobrien int log = 0; 22085815Sobrien 221218822Sdim assert(divisor != 0); 22285815Sobrien 22338889Sjdp divisor_128[0] = divisor; 22438889Sjdp divisor_128[1] = 0; 225218822Sdim 22638889Sjdp remainder[0] = dividend[0]; 22738889Sjdp remainder[1] = dividend[1]; 22838889Sjdp 229218822Sdim subtrahend[0] = divisor; 23038889Sjdp subtrahend[1] = 0; 23138889Sjdp 23238889Sjdp while (divisor > 0) { 233218822Sdim log++; 23438889Sjdp divisor >>= 1; 23585815Sobrien } 23638889Sjdp 237218822Sdim dt_shift_128(subtrahend, 128 - log); 23838889Sjdp dt_shift_128(mask, 128 - log); 23938889Sjdp 24038889Sjdp while (dt_ge_128(remainder, divisor_128)) { 241218822Sdim if (dt_ge_128(remainder, subtrahend)) { 24238889Sjdp dt_subtract_128(remainder, subtrahend, remainder); 24385815Sobrien result[0] |= mask[0]; 24438889Sjdp result[1] |= mask[1]; 245218822Sdim } 24638889Sjdp 24785815Sobrien dt_shift_128(subtrahend, -1); 24838889Sjdp dt_shift_128(mask, -1); 249218822Sdim } 25085815Sobrien 25138889Sjdp quotient[0] = result[0]; 25285815Sobrien quotient[1] = result[1]; 25338889Sjdp} 254218822Sdim 25585815Sobrien/* 25685815Sobrien * This is the long-hand method of calculating a square root. 25738889Sjdp * The algorithm is as follows: 258218822Sdim * 25985815Sobrien * 1. Group the digits by 2 from the right. 26085815Sobrien * 2. Over the leftmost group, find the largest single-digit number 26185815Sobrien * whose square is less than that group. 262218822Sdim * 3. Subtract the result of the previous step (2 or 4, depending) and 26338889Sjdp * bring down the next two-digit group. 26485815Sobrien * 4. For the result R we have so far, find the largest single-digit number 26538889Sjdp * x such that 2 * R * 10 * x + x^2 is less than the result from step 3. 266218822Sdim * (Note that this is doubling R and performing a decimal left-shift by 1 26738889Sjdp * and searching for the appropriate decimal to fill the one's place.) 26885815Sobrien * The value x is the next digit in the square root. 26938889Sjdp * Repeat steps 3 and 4 until the desired precision is reached. (We're 270218822Sdim * dealing with integers, so the above is sufficient.) 27138889Sjdp * 27285815Sobrien * In decimal, the square root of 582,734 would be calculated as so: 27338889Sjdp * 274218822Sdim * __7__6__3 27538889Sjdp * | 58 27 34 27685815Sobrien * -49 (7^2 == 49 => 7 is the first digit in the square root) 27738889Sjdp * -- 278218822Sdim * 9 27 (Subtract and bring down the next group.) 27938889Sjdp * 146 8 76 (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in 28085815Sobrien * ----- the square root) 28138889Sjdp * 51 34 (Subtract and bring down the next group.) 282218822Sdim * 1523 45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in 28338889Sjdp * ----- the square root) 28485815Sobrien * 5 65 (remainder) 28538889Sjdp * 286218822Sdim * The above algorithm applies similarly in binary, but note that the 28738889Sjdp * only possible non-zero value for x in step 4 is 1, so step 4 becomes a 28885815Sobrien * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the 28938889Sjdp * preceding difference? 290218822Sdim * 29138889Sjdp * In binary, the square root of 11011011 would be calculated as so: 29285815Sobrien * 29338889Sjdp * __1__1__1__0 294218822Sdim * | 11 01 10 11 29538889Sjdp * 01 (0 << 2 + 1 == 1 < 11 => this bit is 1) 29685815Sobrien * -- 29738889Sjdp * 10 01 10 11 298218822Sdim * 101 1 01 (1 << 2 + 1 == 101 < 1001 => next bit is 1) 29938889Sjdp * ----- 30085815Sobrien * 1 00 10 11 30138889Sjdp * 1101 11 01 (11 << 2 + 1 == 1101 < 10010 => next bit is 1) 302218822Sdim * ------- 30338889Sjdp * 1 01 11 30438889Sjdp * 11101 1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0) 30538889Sjdp * 30638889Sjdp */ 30738889Sjdpstatic uint64_t 30885815Sobriendt_sqrt_128(uint64_t *square) 30938889Sjdp{ 31038889Sjdp uint64_t result[2] = { 0, 0 }; 31138889Sjdp uint64_t diff[2] = { 0, 0 }; 31238889Sjdp uint64_t one[2] = { 1, 0 }; 31338889Sjdp uint64_t next_pair[2]; 31485815Sobrien uint64_t next_try[2]; 31538889Sjdp uint64_t bit_pairs, pair_shift; 31638889Sjdp int i; 31738889Sjdp 31885815Sobrien bit_pairs = dt_nbits_128(square) / 2; 31938889Sjdp pair_shift = bit_pairs * 2; 320218822Sdim 32185815Sobrien for (i = 0; i <= bit_pairs; i++) { 32238889Sjdp /* 32338889Sjdp * Bring down the next pair of bits. 32438889Sjdp */ 32538889Sjdp next_pair[0] = square[0]; 32638889Sjdp next_pair[1] = square[1]; 32738889Sjdp dt_shift_128(next_pair, -pair_shift); 32838889Sjdp next_pair[0] &= 0x3; 32938889Sjdp next_pair[1] = 0; 330218822Sdim 331218822Sdim dt_shift_128(diff, 2); 332218822Sdim dt_add_128(diff, next_pair, diff); 333218822Sdim 334218822Sdim /* 335218822Sdim * next_try = R << 2 + 1 33638889Sjdp */ 33738889Sjdp next_try[0] = result[0]; 33885815Sobrien next_try[1] = result[1]; 33938889Sjdp dt_shift_128(next_try, 2); 34038889Sjdp dt_add_128(next_try, one, next_try); 34138889Sjdp 34238889Sjdp if (dt_le_128(next_try, diff)) { 34338889Sjdp dt_subtract_128(diff, next_try, diff); 34438889Sjdp dt_shift_128(result, 1); 34538889Sjdp dt_add_128(result, one, result); 34638889Sjdp } else { 34738889Sjdp dt_shift_128(result, 1); 34838889Sjdp } 34938889Sjdp 35038889Sjdp pair_shift -= 2; 35138889Sjdp } 35238889Sjdp 35338889Sjdp assert(result[1] == 0); 35485815Sobrien 35585815Sobrien return (result[0]); 35685815Sobrien} 357218822Sdim 35885815Sobrienuint64_t 35985815Sobriendt_stddev(uint64_t *data, uint64_t normal) 36085815Sobrien{ 36185815Sobrien uint64_t avg_of_squares[2]; 36285815Sobrien uint64_t square_of_avg[2]; 36385815Sobrien int64_t norm_avg; 36485815Sobrien uint64_t diff[2]; 36585815Sobrien 36685815Sobrien /* 36785815Sobrien * The standard approximation for standard deviation is 368218822Sdim * sqrt(average(x**2) - average(x)**2), i.e. the square root 36985815Sobrien * of the average of the squares minus the square of the average. 37085815Sobrien */ 37138889Sjdp dt_divide_128(data + 2, normal, avg_of_squares); 37285815Sobrien dt_divide_128(avg_of_squares, data[0], avg_of_squares); 37338889Sjdp 37438889Sjdp norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0]; 37538889Sjdp 37638889Sjdp if (norm_avg < 0) 37785815Sobrien norm_avg = -norm_avg; 37838889Sjdp 37938889Sjdp dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg); 38038889Sjdp 38138889Sjdp dt_subtract_128(avg_of_squares, square_of_avg, diff); 38238889Sjdp 38338889Sjdp return (dt_sqrt_128(diff)); 384218822Sdim} 38538889Sjdp 38638889Sjdpstatic int 38738889Sjdpdt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, 38838889Sjdp dtrace_bufdesc_t *buf, size_t offs) 38938889Sjdp{ 39038889Sjdp dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; 39138889Sjdp dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; 39238889Sjdp char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub; 393218822Sdim dtrace_flowkind_t flow = DTRACEFLOW_NONE; 39438889Sjdp const char *str = NULL; 39538889Sjdp static const char *e_str[2] = { " -> ", " => " }; 396218822Sdim static const char *r_str[2] = { " <- ", " <= " }; 39785815Sobrien static const char *ent = "entry", *ret = "return"; 39885815Sobrien static int entlen = 0, retlen = 0; 399218822Sdim dtrace_epid_t next, id = epd->dtepd_epid; 40085815Sobrien int rval; 40185815Sobrien 40285815Sobrien if (entlen == 0) { 40385815Sobrien assert(retlen == 0); 404218822Sdim entlen = strlen(ent); 40585815Sobrien retlen = strlen(ret); 40638889Sjdp } 40738889Sjdp 40838889Sjdp /* 40938889Sjdp * If the name of the probe is "entry" or ends with "-entry", we 41038889Sjdp * treat it as an entry; if it is "return" or ends with "-return", 41138889Sjdp * we treat it as a return. (This allows application-provided probes 41285815Sobrien * like "method-entry" or "function-entry" to participate in flow 41385815Sobrien * indentation -- without accidentally misinterpreting popular probe 41485815Sobrien * names like "carpentry", "gentry" or "Coventry".) 41585815Sobrien */ 416218822Sdim if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' && 41785815Sobrien (sub == n || sub[-1] == '-')) { 41885815Sobrien flow = DTRACEFLOW_ENTRY; 41985815Sobrien str = e_str[strcmp(p, "syscall") == 0]; 42085815Sobrien } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' && 421218822Sdim (sub == n || sub[-1] == '-')) { 42285815Sobrien flow = DTRACEFLOW_RETURN; 42338889Sjdp str = r_str[strcmp(p, "syscall") == 0]; 42438889Sjdp } 42538889Sjdp 426218822Sdim /* 42738889Sjdp * If we're going to indent this, we need to check the ID of our last 42838889Sjdp * call. If we're looking at the same probe ID but a different EPID, 42985815Sobrien * we _don't_ want to indent. (Yes, there are some minor holes in 43085815Sobrien * this scheme -- it's a heuristic.) 43138889Sjdp */ 43238889Sjdp if (flow == DTRACEFLOW_ENTRY) { 43338889Sjdp if ((last != DTRACE_EPIDNONE && id != last && 43485815Sobrien pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) 43585815Sobrien flow = DTRACEFLOW_NONE; 43685815Sobrien } 43785815Sobrien 43885815Sobrien /* 43985815Sobrien * If we're going to unindent this, it's more difficult to see if 44085815Sobrien * we don't actually want to unindent it -- we need to look at the 44185815Sobrien * _next_ EPID. 44285815Sobrien */ 44385815Sobrien if (flow == DTRACEFLOW_RETURN) { 44485815Sobrien offs += epd->dtepd_size; 44585815Sobrien 44685815Sobrien do { 44785815Sobrien if (offs >= buf->dtbd_size) 44885815Sobrien goto out; 44985815Sobrien 45085815Sobrien next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 45185815Sobrien 45285815Sobrien if (next == DTRACE_EPIDNONE) 45338889Sjdp offs += sizeof (id); 45438889Sjdp } while (next == DTRACE_EPIDNONE); 45538889Sjdp 45638889Sjdp if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) 45738889Sjdp return (rval); 45838889Sjdp 459218822Sdim if (next != id && npd->dtpd_id == pd->dtpd_id) 460218822Sdim flow = DTRACEFLOW_NONE; 461218822Sdim } 462218822Sdim 463218822Sdimout: 464218822Sdim if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { 46538889Sjdp data->dtpda_prefix = str; 46638889Sjdp } else { 46738889Sjdp data->dtpda_prefix = "| "; 46838889Sjdp } 46938889Sjdp 47085815Sobrien if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) 47185815Sobrien data->dtpda_indent -= 2; 47238889Sjdp 47385815Sobrien data->dtpda_flow = flow; 47485815Sobrien 47585815Sobrien return (0); 476218822Sdim} 477218822Sdim 478218822Sdimstatic int 479218822Sdimdt_nullprobe() 480218822Sdim{ 481218822Sdim return (DTRACE_CONSUME_THIS); 48285815Sobrien} 48385815Sobrien 48485815Sobrienstatic int 48585815Sobriendt_nullrec() 48638889Sjdp{ 48738889Sjdp return (DTRACE_CONSUME_NEXT); 48838889Sjdp} 48938889Sjdp 49038889Sjdpint 49138889Sjdpdt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 49238889Sjdp uint64_t normal, long double total, char positives, char negatives) 49338889Sjdp{ 494218822Sdim long double f; 495218822Sdim uint_t depth, len = 40; 496218822Sdim 497218822Sdim const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; 498218822Sdim const char *spaces = " "; 499218822Sdim 50038889Sjdp assert(strlen(ats) == len && strlen(spaces) == len); 50138889Sjdp assert(!(total == 0 && (positives || negatives))); 50238889Sjdp assert(!(val < 0 && !negatives)); 50338889Sjdp assert(!(val > 0 && !positives)); 50438889Sjdp assert(!(val != 0 && total == 0)); 50538889Sjdp 50638889Sjdp if (!negatives) { 50738889Sjdp if (positives) { 50838889Sjdp f = (dt_fabsl((long double)val) * len) / total; 50938889Sjdp depth = (uint_t)(f + 0.5); 51038889Sjdp } else { 51138889Sjdp depth = 0; 51238889Sjdp } 51338889Sjdp 514218822Sdim return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth, 515218822Sdim spaces + depth, (long long)val / normal)); 516218822Sdim } 517218822Sdim 518218822Sdim if (!positives) { 519218822Sdim f = (dt_fabsl((long double)val) * len) / total; 52038889Sjdp depth = (uint_t)(f + 0.5); 52138889Sjdp 52238889Sjdp return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth, 52338889Sjdp ats + len - depth, (long long)val / normal)); 52438889Sjdp } 52538889Sjdp 52638889Sjdp /* 52738889Sjdp * If we're here, we have both positive and negative bucket values. 52838889Sjdp * To express this graphically, we're going to generate both positive 52938889Sjdp * and negative bars separated by a centerline. These bars are half 53038889Sjdp * the size of normal quantize()/lquantize() bars, so we divide the 53138889Sjdp * length in half before calculating the bar length. 53238889Sjdp */ 533218822Sdim len /= 2; 534218822Sdim ats = &ats[len]; 535218822Sdim spaces = &spaces[len]; 536218822Sdim 537218822Sdim f = (dt_fabsl((long double)val) * len) / total; 538218822Sdim depth = (uint_t)(f + 0.5); 53985815Sobrien 54085815Sobrien if (val <= 0) { 54185815Sobrien return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth, 54285815Sobrien ats + len - depth, len, "", (long long)val / normal)); 54385815Sobrien } else { 54485815Sobrien return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "", 545218822Sdim ats + len - depth, spaces + depth, 546218822Sdim (long long)val / normal)); 547218822Sdim } 548218822Sdim} 549218822Sdim 550218822Sdimint 55185815Sobriendt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 55285815Sobrien size_t size, uint64_t normal) 55385815Sobrien{ 55485815Sobrien const int64_t *data = addr; 55585815Sobrien int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; 55685815Sobrien long double total = 0; 557218822Sdim char positives = 0, negatives = 0; 558218822Sdim 559218822Sdim if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 560218822Sdim return (dt_set_errno(dtp, EDT_DMISMATCH)); 561218822Sdim 562218822Sdim while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) 56338889Sjdp first_bin++; 56485815Sobrien 56585815Sobrien if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) { 56685815Sobrien /* 56785815Sobrien * There isn't any data. This is possible if (and only if) 56885815Sobrien * negative increment values have been used. In this case, 56985815Sobrien * we'll print the buckets around 0. 57085815Sobrien */ 57185815Sobrien first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1; 57285815Sobrien last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1; 57385815Sobrien } else { 57485815Sobrien if (first_bin > 0) 575218822Sdim first_bin--; 57685815Sobrien 57785815Sobrien while (last_bin > 0 && data[last_bin] == 0) 578218822Sdim last_bin--; 57985815Sobrien 58085815Sobrien if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) 58185815Sobrien last_bin++; 58285815Sobrien } 58385815Sobrien 58485815Sobrien for (i = first_bin; i <= last_bin; i++) { 58585815Sobrien positives |= (data[i] > 0); 586218822Sdim negatives |= (data[i] < 0); 58785815Sobrien total += dt_fabsl((long double)data[i]); 58885815Sobrien } 58985815Sobrien 59085815Sobrien if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 59185815Sobrien "------------- Distribution -------------", "count") < 0) 592218822Sdim return (-1); 59385815Sobrien 59485815Sobrien for (i = first_bin; i <= last_bin; i++) { 59585815Sobrien if (dt_printf(dtp, fp, "%16lld ", 59685815Sobrien (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0) 59785815Sobrien return (-1); 59885815Sobrien 59985815Sobrien if (dt_print_quantline(dtp, fp, data[i], normal, total, 60085815Sobrien positives, negatives) < 0) 60138889Sjdp return (-1); 60238889Sjdp } 60338889Sjdp 60485815Sobrien return (0); 60585815Sobrien} 60638889Sjdp 60738889Sjdpint 608218822Sdimdt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 609218822Sdim size_t size, uint64_t normal) 610218822Sdim{ 611218822Sdim const int64_t *data = addr; 612218822Sdim int i, first_bin, last_bin, base; 613218822Sdim uint64_t arg; 61438889Sjdp long double total = 0; 61538889Sjdp uint16_t step, levels; 61638889Sjdp char positives = 0, negatives = 0; 61738889Sjdp 61838889Sjdp if (size < sizeof (uint64_t)) 61985815Sobrien return (dt_set_errno(dtp, EDT_DMISMATCH)); 62085815Sobrien 62185815Sobrien arg = *data++; 622218822Sdim size -= sizeof (uint64_t); 623218822Sdim 624218822Sdim base = DTRACE_LQUANTIZE_BASE(arg); 62538889Sjdp step = DTRACE_LQUANTIZE_STEP(arg); 62638889Sjdp levels = DTRACE_LQUANTIZE_LEVELS(arg); 62738889Sjdp 62838889Sjdp first_bin = 0; 62938889Sjdp last_bin = levels + 1; 63038889Sjdp 63138889Sjdp if (size != sizeof (uint64_t) * (levels + 2)) 63238889Sjdp return (dt_set_errno(dtp, EDT_DMISMATCH)); 63338889Sjdp 63438889Sjdp while (first_bin <= levels + 1 && data[first_bin] == 0) 63538889Sjdp first_bin++; 63638889Sjdp 63738889Sjdp if (first_bin > levels + 1) { 63838889Sjdp first_bin = 0; 63938889Sjdp last_bin = 2; 64085815Sobrien } else { 64138889Sjdp if (first_bin > 0) 64285815Sobrien first_bin--; 643218822Sdim 644218822Sdim while (last_bin > 0 && data[last_bin] == 0) 64585815Sobrien last_bin--; 64685815Sobrien 64785815Sobrien if (last_bin < levels + 1) 64885815Sobrien last_bin++; 64985815Sobrien } 65085815Sobrien 65185815Sobrien for (i = first_bin; i <= last_bin; i++) { 65285815Sobrien positives |= (data[i] > 0); 65385815Sobrien negatives |= (data[i] < 0); 65485815Sobrien total += dt_fabsl((long double)data[i]); 65538889Sjdp } 65638889Sjdp 65785815Sobrien if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 65885815Sobrien "------------- Distribution -------------", "count") < 0) 65985815Sobrien return (-1); 66085815Sobrien 66185815Sobrien for (i = first_bin; i <= last_bin; i++) { 662218822Sdim char c[32]; 663218822Sdim int err; 66485815Sobrien 66585815Sobrien if (i == 0) { 666218822Sdim (void) snprintf(c, sizeof (c), "< %d", 66785815Sobrien base / (uint32_t)normal); 66885815Sobrien err = dt_printf(dtp, fp, "%16s ", c); 66985815Sobrien } else if (i == levels + 1) { 67085815Sobrien (void) snprintf(c, sizeof (c), ">= %d", 671218822Sdim base + (levels * step)); 67285815Sobrien err = dt_printf(dtp, fp, "%16s ", c); 67385815Sobrien } else { 674218822Sdim err = dt_printf(dtp, fp, "%16d ", 67585815Sobrien base + (i - 1) * step); 67685815Sobrien } 677218822Sdim 678218822Sdim if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal, 67985815Sobrien total, positives, negatives) < 0) 68085815Sobrien return (-1); 68185815Sobrien } 68285815Sobrien 68385815Sobrien return (0); 684218822Sdim} 685218822Sdim 68685815Sobrienint 68785815Sobriendt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 68885815Sobrien size_t size, uint64_t normal) 68985815Sobrien{ 69085815Sobrien int i, first_bin, last_bin, bin = 1, order, levels; 69185815Sobrien uint16_t factor, low, high, nsteps; 69285815Sobrien const int64_t *data = addr; 69385815Sobrien int64_t value = 1, next, step; 69485815Sobrien char positives = 0, negatives = 0; 69585815Sobrien long double total = 0; 69638889Sjdp uint64_t arg; 69785815Sobrien char c[32]; 69838889Sjdp 69938889Sjdp if (size < sizeof (uint64_t)) 70038889Sjdp return (dt_set_errno(dtp, EDT_DMISMATCH)); 70185815Sobrien 70238889Sjdp arg = *data++; 70385815Sobrien size -= sizeof (uint64_t); 704218822Sdim 705218822Sdim factor = DTRACE_LLQUANTIZE_FACTOR(arg); 706218822Sdim low = DTRACE_LLQUANTIZE_LOW(arg); 707218822Sdim high = DTRACE_LLQUANTIZE_HIGH(arg); 708218822Sdim nsteps = DTRACE_LLQUANTIZE_NSTEP(arg); 70985815Sobrien 71085815Sobrien /* 71185815Sobrien * We don't expect to be handed invalid llquantize() parameters here, 71285815Sobrien * but sanity check them (to a degree) nonetheless. 71385815Sobrien */ 71485815Sobrien if (size > INT32_MAX || factor < 2 || low >= high || 71585815Sobrien nsteps == 0 || factor > nsteps) 71685815Sobrien return (dt_set_errno(dtp, EDT_DMISMATCH)); 71785815Sobrien 71885815Sobrien levels = (int)size / sizeof (uint64_t); 71985815Sobrien 72085815Sobrien first_bin = 0; 72185815Sobrien last_bin = levels - 1; 72285815Sobrien 72385815Sobrien while (first_bin < levels && data[first_bin] == 0) 72485815Sobrien first_bin++; 72585815Sobrien 72685815Sobrien if (first_bin == levels) { 72785815Sobrien first_bin = 0; 72885815Sobrien last_bin = 1; 72985815Sobrien } else { 73085815Sobrien if (first_bin > 0) 73185815Sobrien first_bin--; 73285815Sobrien 73385815Sobrien while (last_bin > 0 && data[last_bin] == 0) 734218822Sdim last_bin--; 73585815Sobrien 73685815Sobrien if (last_bin < levels - 1) 73785815Sobrien last_bin++; 738218822Sdim } 73985815Sobrien 74085815Sobrien for (i = first_bin; i <= last_bin; i++) { 74185815Sobrien positives |= (data[i] > 0); 74285815Sobrien negatives |= (data[i] < 0); 743218822Sdim total += dt_fabsl((long double)data[i]); 74485815Sobrien } 74585815Sobrien 746218822Sdim if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 74785815Sobrien "------------- Distribution -------------", "count") < 0) 74885815Sobrien return (-1); 74985815Sobrien 75085815Sobrien for (order = 0; order < low; order++) 75138889Sjdp value *= factor; 752218822Sdim 753218822Sdim next = value * factor; 754218822Sdim step = next > nsteps ? next / nsteps : 1; 755218822Sdim 756218822Sdim if (first_bin == 0) { 757218822Sdim (void) snprintf(c, sizeof (c), "< %lld", (long long)value); 75838889Sjdp 759218822Sdim if (dt_printf(dtp, fp, "%16s ", c) < 0) 76085815Sobrien return (-1); 761218822Sdim 76285815Sobrien if (dt_print_quantline(dtp, fp, data[0], normal, 76385815Sobrien total, positives, negatives) < 0) 76485815Sobrien return (-1); 76585815Sobrien } 76685815Sobrien 76785815Sobrien while (order <= high) { 76885815Sobrien if (bin >= first_bin && bin <= last_bin) { 76985815Sobrien if (dt_printf(dtp, fp, "%16lld ", (long long)value) < 0) 77085815Sobrien return (-1); 77185815Sobrien 772218822Sdim if (dt_print_quantline(dtp, fp, data[bin], 773218822Sdim normal, total, positives, negatives) < 0) 77485815Sobrien return (-1); 775218822Sdim } 776218822Sdim 77785815Sobrien assert(value < next); 778218822Sdim bin++; 779218822Sdim 780218822Sdim if ((value += step) != next) 78185815Sobrien continue; 78285815Sobrien 78385815Sobrien next = value * factor; 78485815Sobrien step = next > nsteps ? next / nsteps : 1; 78585815Sobrien order++; 78685815Sobrien } 78785815Sobrien 78885815Sobrien if (last_bin < bin) 78985815Sobrien return (0); 79085815Sobrien 79185815Sobrien assert(last_bin == bin); 79285815Sobrien (void) snprintf(c, sizeof (c), ">= %lld", (long long)value); 79385815Sobrien 79485815Sobrien if (dt_printf(dtp, fp, "%16s ", c) < 0) 79585815Sobrien return (-1); 79685815Sobrien 79785815Sobrien return (dt_print_quantline(dtp, fp, data[bin], normal, 798218822Sdim total, positives, negatives)); 799218822Sdim} 800218822Sdim 801218822Sdim/*ARGSUSED*/ 802218822Sdimstatic int 803218822Sdimdt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 804218822Sdim size_t size, uint64_t normal) 805218822Sdim{ 806218822Sdim /* LINTED - alignment */ 807218822Sdim int64_t *data = (int64_t *)addr; 808218822Sdim 809218822Sdim return (dt_printf(dtp, fp, " %16lld", data[0] ? 810218822Sdim (long long)(data[1] / (int64_t)normal / data[0]) : 0)); 811218822Sdim} 812218822Sdim 81385815Sobrien/*ARGSUSED*/ 81485815Sobrienstatic int 81585815Sobriendt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 816218822Sdim size_t size, uint64_t normal) 81785815Sobrien{ 81885815Sobrien /* LINTED - alignment */ 81985815Sobrien uint64_t *data = (uint64_t *)addr; 820218822Sdim 82138889Sjdp return (dt_printf(dtp, fp, " %16llu", data[0] ? 82238889Sjdp (unsigned long long) dt_stddev(data, normal) : 0)); 82338889Sjdp} 82485815Sobrien 82585815Sobrien/*ARGSUSED*/ 82685815Sobrienint 827218822Sdimdt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 828218822Sdim size_t nbytes, int width, int quiet, int forceraw) 829218822Sdim{ 830218822Sdim /* 831218822Sdim * If the byte stream is a series of printable characters, followed by 832218822Sdim * a terminating byte, we print it out as a string. Otherwise, we 83385815Sobrien * assume that it's something else and just print the bytes. 834218822Sdim */ 835218822Sdim int i, j, margin = 5; 836218822Sdim char *c = (char *)addr; 837218822Sdim 83885815Sobrien if (nbytes == 0) 839218822Sdim return (0); 84085815Sobrien 841218822Sdim if (forceraw) 84285815Sobrien goto raw; 84385815Sobrien 84485815Sobrien if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) 845218822Sdim goto raw; 84685815Sobrien 84785815Sobrien for (i = 0; i < nbytes; i++) { 84885815Sobrien /* 84985815Sobrien * We define a "printable character" to be one for which 85085815Sobrien * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 85185815Sobrien * or a character which is either backspace or the bell. 85285815Sobrien * Backspace and the bell are regrettably special because 85385815Sobrien * they fail the first two tests -- and yet they are entirely 854218822Sdim * printable. These are the only two control characters that 85585815Sobrien * have meaning for the terminal and for which isprint(3C) and 85685815Sobrien * isspace(3C) return 0. 85785815Sobrien */ 858218822Sdim if (isprint(c[i]) || isspace(c[i]) || 85985815Sobrien c[i] == '\b' || c[i] == '\a') 86085815Sobrien continue; 86185815Sobrien 86285815Sobrien if (c[i] == '\0' && i > 0) { 86385815Sobrien /* 86485815Sobrien * This looks like it might be a string. Before we 86585815Sobrien * assume that it is indeed a string, check the 86685815Sobrien * remainder of the byte range; if it contains 867218822Sdim * additional non-nul characters, we'll assume that 868218822Sdim * it's a binary stream that just happens to look like 869218822Sdim * a string, and we'll print out the individual bytes. 870218822Sdim */ 871218822Sdim for (j = i + 1; j < nbytes; j++) { 87285815Sobrien if (c[j] != '\0') 87385815Sobrien break; 87485815Sobrien } 87585815Sobrien 87685815Sobrien if (j != nbytes) 87785815Sobrien break; 87885815Sobrien 87985815Sobrien if (quiet) 88085815Sobrien return (dt_printf(dtp, fp, "%s", c)); 881218822Sdim else 882218822Sdim return (dt_printf(dtp, fp, " %-*s", width, c)); 883218822Sdim } 884218822Sdim 885218822Sdim break; 886218822Sdim } 887218822Sdim 888218822Sdim if (i == nbytes) { 88985815Sobrien /* 89085815Sobrien * The byte range is all printable characters, but there is 89185815Sobrien * no trailing nul byte. We'll assume that it's a string and 89285815Sobrien * print it as such. 89338889Sjdp */ 89438889Sjdp char *s = alloca(nbytes + 1); 89538889Sjdp bcopy(c, s, nbytes); 89638889Sjdp s[nbytes] = '\0'; 897218822Sdim return (dt_printf(dtp, fp, " %-*s", width, s)); 898218822Sdim } 899218822Sdim 900218822Sdimraw: 901218822Sdim if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) 902218822Sdim return (-1); 90338889Sjdp 90438889Sjdp for (i = 0; i < 16; i++) 90538889Sjdp if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) 90638889Sjdp return (-1); 90738889Sjdp 90838889Sjdp if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) 90938889Sjdp return (-1); 91038889Sjdp 91138889Sjdp 91238889Sjdp for (i = 0; i < nbytes; i += 16) { 91338889Sjdp if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) 91438889Sjdp return (-1); 91538889Sjdp 91638889Sjdp for (j = i; j < i + 16 && j < nbytes; j++) { 91738889Sjdp if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) 91838889Sjdp return (-1); 91938889Sjdp } 92038889Sjdp 92138889Sjdp while (j++ % 16) { 922218822Sdim if (dt_printf(dtp, fp, " ") < 0) 923218822Sdim return (-1); 924218822Sdim } 925218822Sdim 926218822Sdim if (dt_printf(dtp, fp, " ") < 0) 927218822Sdim return (-1); 92885815Sobrien 92985815Sobrien for (j = i; j < i + 16 && j < nbytes; j++) { 93085815Sobrien if (dt_printf(dtp, fp, "%c", 93185815Sobrien c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) 93285815Sobrien return (-1); 933218822Sdim } 934218822Sdim 935218822Sdim if (dt_printf(dtp, fp, "\n") < 0) 936218822Sdim return (-1); 937218822Sdim } 938218822Sdim 93938889Sjdp return (0); 94085815Sobrien} 941218822Sdim 942218822Sdimint 943218822Sdimdt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 944218822Sdim caddr_t addr, int depth, int size) 945218822Sdim{ 946218822Sdim dtrace_syminfo_t dts; 947218822Sdim GElf_Sym sym; 948218822Sdim int i, indent; 949218822Sdim char c[PATH_MAX * 2]; 950218822Sdim uint64_t pc; 951218822Sdim 952218822Sdim if (dt_printf(dtp, fp, "\n") < 0) 953218822Sdim return (-1); 954218822Sdim 95585815Sobrien if (format == NULL) 95685815Sobrien format = "%s"; 95785815Sobrien 95838889Sjdp if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 95938889Sjdp indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 96038889Sjdp else 96138889Sjdp indent = _dtrace_stkindent; 96238889Sjdp 96338889Sjdp for (i = 0; i < depth; i++) { 964218822Sdim switch (size) { 965218822Sdim case sizeof (uint32_t): 966218822Sdim /* LINTED - alignment */ 967218822Sdim pc = *((uint32_t *)addr); 968218822Sdim break; 969218822Sdim 97038889Sjdp case sizeof (uint64_t): 97138889Sjdp /* LINTED - alignment */ 97238889Sjdp pc = *((uint64_t *)addr); 97338889Sjdp break; 97438889Sjdp 97538889Sjdp default: 97638889Sjdp return (dt_set_errno(dtp, EDT_BADSTACKPC)); 97738889Sjdp } 978218822Sdim 979218822Sdim if (pc == 0) 980218822Sdim break; 981218822Sdim 982218822Sdim addr += size; 983218822Sdim 98438889Sjdp if (dt_printf(dtp, fp, "%*s", indent, "") < 0) 98538889Sjdp return (-1); 986218822Sdim 98738889Sjdp if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 98838889Sjdp if (pc > sym.st_value) { 98938889Sjdp (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", 99038889Sjdp dts.dts_object, dts.dts_name, 99138889Sjdp (u_longlong_t)(pc - sym.st_value)); 99238889Sjdp } else { 99338889Sjdp (void) snprintf(c, sizeof (c), "%s`%s", 99438889Sjdp dts.dts_object, dts.dts_name); 99538889Sjdp } 99685815Sobrien } else { 99738889Sjdp /* 99838889Sjdp * We'll repeat the lookup, but this time we'll specify 99938889Sjdp * a NULL GElf_Sym -- indicating that we're only 100085815Sobrien * interested in the containing module. 100138889Sjdp */ 100285815Sobrien if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 100385815Sobrien (void) snprintf(c, sizeof (c), "%s`0x%llx", 100485815Sobrien dts.dts_object, (u_longlong_t)pc); 100538889Sjdp } else { 1006218822Sdim (void) snprintf(c, sizeof (c), "0x%llx", 1007218822Sdim (u_longlong_t)pc); 1008218822Sdim } 1009218822Sdim } 1010218822Sdim 1011218822Sdim if (dt_printf(dtp, fp, format, c) < 0) 101238889Sjdp return (-1); 101338889Sjdp 101485815Sobrien if (dt_printf(dtp, fp, "\n") < 0) 1015218822Sdim return (-1); 1016218822Sdim } 101785815Sobrien 101885815Sobrien return (0); 1019218822Sdim} 1020218822Sdim 1021218822Sdimint 1022218822Sdimdt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 102385815Sobrien caddr_t addr, uint64_t arg) 102485815Sobrien{ 102538889Sjdp /* LINTED - alignment */ 102638889Sjdp uint64_t *pc = (uint64_t *)addr; 102738889Sjdp uint32_t depth = DTRACE_USTACK_NFRAMES(arg); 102838889Sjdp uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); 102938889Sjdp const char *strbase = addr + (depth + 1) * sizeof (uint64_t); 103038889Sjdp const char *str = strsize ? strbase : NULL; 103138889Sjdp int err = 0; 103238889Sjdp 103338889Sjdp char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 103438889Sjdp struct ps_prochandle *P; 103538889Sjdp GElf_Sym sym; 103638889Sjdp int i, indent; 103738889Sjdp pid_t pid; 1038218822Sdim 103938889Sjdp if (depth == 0) 1040218822Sdim return (0); 104138889Sjdp 104238889Sjdp pid = (pid_t)*pc++; 1043218822Sdim 1044218822Sdim if (dt_printf(dtp, fp, "\n") < 0) 1045218822Sdim return (-1); 1046218822Sdim 1047218822Sdim if (format == NULL) 1048218822Sdim format = "%s"; 1049218822Sdim 1050218822Sdim if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 1051218822Sdim indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 1052218822Sdim else 1053218822Sdim indent = _dtrace_stkindent; 1054218822Sdim 1055218822Sdim /* 1056218822Sdim * Ultimately, we need to add an entry point in the library vector for 1057218822Sdim * determining <symbol, offset> from <pid, address>. For now, if 1058218822Sdim * this is a vector open, we just print the raw address or string. 1059218822Sdim */ 1060218822Sdim if (dtp->dt_vector == NULL) 1061218822Sdim P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 1062218822Sdim else 1063218822Sdim P = NULL; 1064218822Sdim 1065218822Sdim if (P != NULL) 1066218822Sdim dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 106738889Sjdp 106838889Sjdp for (i = 0; i < depth && pc[i] != 0; i++) { 106938889Sjdp const prmap_t *map; 107038889Sjdp 107138889Sjdp if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 107238889Sjdp break; 107338889Sjdp 107438889Sjdp if (P != NULL && Plookup_by_addr(P, pc[i], 1075218822Sdim name, sizeof (name), &sym) == 0) { 1076218822Sdim (void) Pobjname(P, pc[i], objname, sizeof (objname)); 1077218822Sdim 1078218822Sdim if (pc[i] > sym.st_value) { 1079218822Sdim (void) snprintf(c, sizeof (c), 108038889Sjdp "%s`%s+0x%llx", dt_basename(objname), name, 108138889Sjdp (u_longlong_t)(pc[i] - sym.st_value)); 108238889Sjdp } else { 108385815Sobrien (void) snprintf(c, sizeof (c), 108438889Sjdp "%s`%s", dt_basename(objname), name); 108538889Sjdp } 108685815Sobrien } else if (str != NULL && str[0] != '\0' && str[0] != '@' && 108738889Sjdp (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL || 108838889Sjdp (map->pr_mflags & MA_WRITE)))) { 108938889Sjdp /* 109038889Sjdp * If the current string pointer in the string table 109185815Sobrien * does not point to an empty string _and_ the program 1092218822Sdim * counter falls in a writable region, we'll use the 109385815Sobrien * string from the string table instead of the raw 109485815Sobrien * address. This last condition is necessary because 109585815Sobrien * some (broken) ustack helpers will return a string 109685815Sobrien * even for a program counter that they can't 109785815Sobrien * identify. If we have a string for a program 109885815Sobrien * counter that falls in a segment that isn't 109985815Sobrien * writable, we assume that we have fallen into this 110085815Sobrien * case and we refuse to use the string. 110185815Sobrien */ 110285815Sobrien (void) snprintf(c, sizeof (c), "%s", str); 110385815Sobrien } else { 110485815Sobrien if (P != NULL && Pobjname(P, pc[i], objname, 1105218822Sdim sizeof (objname)) != 0) { 110638889Sjdp (void) snprintf(c, sizeof (c), "%s`0x%llx", 110738889Sjdp dt_basename(objname), (u_longlong_t)pc[i]); 110838889Sjdp } else { 110985815Sobrien (void) snprintf(c, sizeof (c), "0x%llx", 111085815Sobrien (u_longlong_t)pc[i]); 1111218822Sdim } 111285815Sobrien } 111385815Sobrien 111485815Sobrien if ((err = dt_printf(dtp, fp, format, c)) < 0) 111585815Sobrien break; 111685815Sobrien 111785815Sobrien if ((err = dt_printf(dtp, fp, "\n")) < 0) 111885815Sobrien break; 1119218822Sdim 1120218822Sdim if (str != NULL && str[0] == '@') { 112138889Sjdp /* 112238889Sjdp * If the first character of the string is an "at" sign, 112338889Sjdp * then the string is inferred to be an annotation -- 112438889Sjdp * and it is printed out beneath the frame and offset 112538889Sjdp * with brackets. 112685815Sobrien */ 112738889Sjdp if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 112838889Sjdp break; 1129218822Sdim 1130218822Sdim (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]); 113185815Sobrien 1132218822Sdim if ((err = dt_printf(dtp, fp, format, c)) < 0) 113338889Sjdp break; 1134218822Sdim 113538889Sjdp if ((err = dt_printf(dtp, fp, "\n")) < 0) 113638889Sjdp break; 113738889Sjdp } 113838889Sjdp 113938889Sjdp if (str != NULL) { 1140218822Sdim str += strlen(str) + 1; 114185815Sobrien if (str - strbase >= strsize) 114238889Sjdp str = NULL; 114338889Sjdp } 114438889Sjdp } 114538889Sjdp 114638889Sjdp if (P != NULL) { 114738889Sjdp dt_proc_unlock(dtp, P); 114838889Sjdp dt_proc_release(dtp, P); 114938889Sjdp } 115038889Sjdp 115138889Sjdp return (err); 115238889Sjdp} 115338889Sjdp 115438889Sjdpstatic int 115538889Sjdpdt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act) 115638889Sjdp{ 115738889Sjdp /* LINTED - alignment */ 115838889Sjdp uint64_t pid = ((uint64_t *)addr)[0]; 115938889Sjdp /* LINTED - alignment */ 116038889Sjdp uint64_t pc = ((uint64_t *)addr)[1]; 1161218822Sdim const char *format = " %-50s"; 116285815Sobrien char *s; 116385815Sobrien int n, len = 256; 116485815Sobrien 116585815Sobrien if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) { 116685815Sobrien struct ps_prochandle *P; 116785815Sobrien 116885815Sobrien if ((P = dt_proc_grab(dtp, pid, 116985815Sobrien PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) { 117085815Sobrien GElf_Sym sym; 117185815Sobrien 117285815Sobrien dt_proc_lock(dtp, P); 117385815Sobrien 117485815Sobrien if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0) 117585815Sobrien pc = sym.st_value; 117685815Sobrien 117785815Sobrien dt_proc_unlock(dtp, P); 117885815Sobrien dt_proc_release(dtp, P); 117985815Sobrien } 118038889Sjdp } 118138889Sjdp 118238889Sjdp do { 118338889Sjdp n = len; 118438889Sjdp s = alloca(n); 118538889Sjdp } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n); 118638889Sjdp 118738889Sjdp return (dt_printf(dtp, fp, format, s)); 1188218822Sdim} 1189218822Sdim 1190218822Sdimint 1191218822Sdimdt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1192218822Sdim{ 119338889Sjdp /* LINTED - alignment */ 119438889Sjdp uint64_t pid = ((uint64_t *)addr)[0]; 119538889Sjdp /* LINTED - alignment */ 119638889Sjdp uint64_t pc = ((uint64_t *)addr)[1]; 119738889Sjdp int err = 0; 119838889Sjdp 119938889Sjdp char objname[PATH_MAX], c[PATH_MAX * 2]; 120085815Sobrien struct ps_prochandle *P; 120138889Sjdp 120238889Sjdp if (format == NULL) 120338889Sjdp format = " %-50s"; 120438889Sjdp 120585815Sobrien /* 120638889Sjdp * See the comment in dt_print_ustack() for the rationale for 120738889Sjdp * printing raw addresses in the vectored case. 120838889Sjdp */ 120938889Sjdp if (dtp->dt_vector == NULL) 121038889Sjdp P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 121138889Sjdp else 121238889Sjdp P = NULL; 121338889Sjdp 121438889Sjdp if (P != NULL) 121538889Sjdp dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 121638889Sjdp 121738889Sjdp if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) { 1218218822Sdim (void) snprintf(c, sizeof (c), "%s", dt_basename(objname)); 1219218822Sdim } else { 1220218822Sdim (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1221218822Sdim } 1222218822Sdim 122338889Sjdp err = dt_printf(dtp, fp, format, c); 122438889Sjdp 122538889Sjdp if (P != NULL) { 122638889Sjdp dt_proc_unlock(dtp, P); 122738889Sjdp dt_proc_release(dtp, P); 122838889Sjdp } 122938889Sjdp 123085815Sobrien return (err); 123138889Sjdp} 123238889Sjdp 123338889Sjdpint 123438889Sjdpdt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr) 123538889Sjdp{ 123638889Sjdp int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 123738889Sjdp size_t nbytes = *((uintptr_t *) addr); 123838889Sjdp 123938889Sjdp return (dt_print_bytes(dtp, fp, addr + sizeof(uintptr_t), 124038889Sjdp nbytes, 50, quiet, 1)); 124138889Sjdp} 124238889Sjdp 124338889Sjdptypedef struct dt_type_cbdata { 1244218822Sdim dtrace_hdl_t *dtp; 1245218822Sdim dtrace_typeinfo_t dtt; 1246218822Sdim caddr_t addr; 1247218822Sdim caddr_t addrend; 1248218822Sdim const char *name; 124938889Sjdp int f_type; 125038889Sjdp int indent; 125138889Sjdp int type_width; 125285815Sobrien int name_width; 125338889Sjdp FILE *fp; 125438889Sjdp} dt_type_cbdata_t; 125538889Sjdp 125638889Sjdpstatic int dt_print_type_data(dt_type_cbdata_t *, ctf_id_t); 125738889Sjdp 125838889Sjdpstatic int 1259218822Sdimdt_print_type_member(const char *name, ctf_id_t type, ulong_t off, void *arg) 1260218822Sdim{ 126185815Sobrien dt_type_cbdata_t cbdata; 1262218822Sdim dt_type_cbdata_t *cbdatap = arg; 1263218822Sdim ssize_t ssz; 1264218822Sdim 1265218822Sdim if ((ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type)) <= 0) 1266218822Sdim return (0); 126785815Sobrien 126885815Sobrien off /= 8; 126985815Sobrien 127085815Sobrien cbdata = *cbdatap; 127185815Sobrien cbdata.name = name; 127285815Sobrien cbdata.addr += off; 127385815Sobrien cbdata.addrend = cbdata.addr + ssz; 1274218822Sdim 127585815Sobrien return (dt_print_type_data(&cbdata, type)); 127685815Sobrien} 1277218822Sdim 1278218822Sdimstatic int 1279218822Sdimdt_print_type_width(const char *name, ctf_id_t type, ulong_t off, void *arg) 1280218822Sdim{ 1281218822Sdim char buf[DT_TYPE_NAMELEN]; 128285815Sobrien char *p; 128385815Sobrien dt_type_cbdata_t *cbdatap = arg; 128485815Sobrien size_t sz = strlen(name); 128585815Sobrien 128685815Sobrien ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf)); 128785815Sobrien 128885815Sobrien if ((p = strchr(buf, '[')) != NULL) 128985815Sobrien p[-1] = '\0'; 129085815Sobrien else 129185815Sobrien p = ""; 129285815Sobrien 129385815Sobrien sz += strlen(p); 1294218822Sdim 1295218822Sdim if (sz > cbdatap->name_width) 1296218822Sdim cbdatap->name_width = sz; 129785815Sobrien 129885815Sobrien sz = strlen(buf); 1299218822Sdim 130085815Sobrien if (sz > cbdatap->type_width) 130185815Sobrien cbdatap->type_width = sz; 1302218822Sdim 1303218822Sdim return (0); 1304218822Sdim} 1305218822Sdim 1306218822Sdimstatic int 130785815Sobriendt_print_type_data(dt_type_cbdata_t *cbdatap, ctf_id_t type) 130885815Sobrien{ 130985815Sobrien caddr_t addr = cbdatap->addr; 131085815Sobrien caddr_t addrend = cbdatap->addrend; 131185815Sobrien char buf[DT_TYPE_NAMELEN]; 131285815Sobrien char *p; 131385815Sobrien int cnt = 0; 131485815Sobrien uint_t kind = ctf_type_kind(cbdatap->dtt.dtt_ctfp, type); 131585815Sobrien ssize_t ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type); 131685815Sobrien 131785815Sobrien ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf)); 1318218822Sdim 1319218822Sdim if ((p = strchr(buf, '[')) != NULL) 132085815Sobrien p[-1] = '\0'; 1321218822Sdim else 132285815Sobrien p = ""; 132385815Sobrien 132485815Sobrien if (cbdatap->f_type) { 132585815Sobrien int type_width = roundup(cbdatap->type_width + 1, 4); 132638889Sjdp int name_width = roundup(cbdatap->name_width + 1, 4); 132738889Sjdp 132838889Sjdp name_width -= strlen(cbdatap->name); 132938889Sjdp 133038889Sjdp dt_printf(cbdatap->dtp, cbdatap->fp, "%*s%-*s%s%-*s = ",cbdatap->indent * 4,"",type_width,buf,cbdatap->name,name_width,p); 1331218822Sdim } 1332218822Sdim 1333218822Sdim while (addr < addrend) { 1334218822Sdim dt_type_cbdata_t cbdata; 1335218822Sdim ctf_arinfo_t arinfo; 133638889Sjdp ctf_encoding_t cte; 133738889Sjdp uintptr_t *up; 133838889Sjdp void *vp = addr; 133938889Sjdp cbdata = *cbdatap; 134085815Sobrien cbdata.name = ""; 134185815Sobrien cbdata.addr = addr; 134238889Sjdp cbdata.addrend = addr + ssz; 134338889Sjdp cbdata.f_type = 0; 134438889Sjdp cbdata.indent++; 134538889Sjdp cbdata.type_width = 0; 1346218822Sdim cbdata.name_width = 0; 1347218822Sdim 134838889Sjdp if (cnt > 0) 1349218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%*s", cbdatap->indent * 4,""); 1350218822Sdim 1351218822Sdim switch (kind) { 1352218822Sdim case CTF_K_INTEGER: 1353218822Sdim if (ctf_type_encoding(cbdatap->dtt.dtt_ctfp, type, &cte) != 0) 1354218822Sdim return (-1); 1355218822Sdim if ((cte.cte_format & CTF_INT_SIGNED) != 0) 1356218822Sdim switch (cte.cte_bits) { 1357218822Sdim case 8: 1358218822Sdim if (isprint(*((char *) vp))) 1359218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "'%c', ", *((char *) vp)); 1360218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((char *) vp), *((char *) vp)); 1361218822Sdim break; 1362218822Sdim case 16: 1363218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%hd (0x%hx);\n", *((short *) vp), *((u_short *) vp)); 1364218822Sdim break; 1365218822Sdim case 32: 1366218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((int *) vp), *((u_int *) vp)); 1367218822Sdim break; 1368218822Sdim case 64: 1369218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%jd (0x%jx);\n", *((long long *) vp), *((unsigned long long *) vp)); 1370218822Sdim break; 1371218822Sdim default: 1372218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_INTEGER: format %x offset %u bits %u\n",cte.cte_format,cte.cte_offset,cte.cte_bits); 1373218822Sdim break; 1374218822Sdim } 1375218822Sdim else 1376218822Sdim switch (cte.cte_bits) { 1377218822Sdim case 8: 1378218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((uint8_t *) vp) & 0xff, *((uint8_t *) vp) & 0xff); 1379218822Sdim break; 1380218822Sdim case 16: 1381218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%hu (0x%hx);\n", *((u_short *) vp), *((u_short *) vp)); 1382218822Sdim break; 1383218822Sdim case 32: 1384218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((u_int *) vp), *((u_int *) vp)); 1385218822Sdim break; 1386218822Sdim case 64: 1387218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%ju (0x%jx);\n", *((unsigned long long *) vp), *((unsigned long long *) vp)); 1388218822Sdim break; 1389218822Sdim default: 1390218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_INTEGER: format %x offset %u bits %u\n",cte.cte_format,cte.cte_offset,cte.cte_bits); 1391218822Sdim break; 1392218822Sdim } 1393218822Sdim break; 1394218822Sdim case CTF_K_FLOAT: 1395218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_FLOAT: format %x offset %u bits %u\n",cte.cte_format,cte.cte_offset,cte.cte_bits); 1396218822Sdim break; 1397218822Sdim case CTF_K_POINTER: 1398218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%p;\n", *((void **) addr)); 1399218822Sdim break; 1400218822Sdim case CTF_K_ARRAY: 1401218822Sdim if (ctf_array_info(cbdatap->dtt.dtt_ctfp, type, &arinfo) != 0) 1402218822Sdim return (-1); 1403218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "{\n%*s",cbdata.indent * 4,""); 1404218822Sdim dt_print_type_data(&cbdata, arinfo.ctr_contents); 1405218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1406218822Sdim break; 1407218822Sdim case CTF_K_FUNCTION: 1408218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_FUNCTION:\n"); 1409218822Sdim break; 1410218822Sdim case CTF_K_STRUCT: 1411218822Sdim cbdata.f_type = 1; 1412218822Sdim if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1413218822Sdim dt_print_type_width, &cbdata) != 0) 1414218822Sdim return (-1); 1415218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "{\n"); 1416218822Sdim if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1417218822Sdim dt_print_type_member, &cbdata) != 0) 1418218822Sdim return (-1); 1419218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1420218822Sdim break; 1421218822Sdim case CTF_K_UNION: 1422218822Sdim cbdata.f_type = 1; 1423218822Sdim if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1424218822Sdim dt_print_type_width, &cbdata) != 0) 1425218822Sdim return (-1); 1426218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "{\n"); 1427218822Sdim if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1428218822Sdim dt_print_type_member, &cbdata) != 0) 1429218822Sdim return (-1); 1430218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1431218822Sdim break; 1432218822Sdim case CTF_K_ENUM: 1433218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "%s;\n", ctf_enum_name(cbdatap->dtt.dtt_ctfp, type, *((int *) vp))); 1434218822Sdim break; 1435218822Sdim case CTF_K_TYPEDEF: 1436218822Sdim dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1437218822Sdim break; 1438218822Sdim case CTF_K_VOLATILE: 1439218822Sdim if (cbdatap->f_type) 1440218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "volatile "); 1441218822Sdim dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1442218822Sdim break; 1443218822Sdim case CTF_K_CONST: 1444218822Sdim if (cbdatap->f_type) 1445218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "const "); 1446218822Sdim dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1447218822Sdim break; 1448218822Sdim case CTF_K_RESTRICT: 1449218822Sdim if (cbdatap->f_type) 1450218822Sdim dt_printf(cbdatap->dtp, cbdatap->fp, "restrict "); 1451218822Sdim dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1452218822Sdim break; 1453218822Sdim default: 1454218822Sdim break; 1455218822Sdim } 1456218822Sdim 1457218822Sdim addr += ssz; 1458218822Sdim cnt++; 1459218822Sdim } 1460218822Sdim 1461218822Sdim return (0); 1462218822Sdim} 1463218822Sdim 1464218822Sdimstatic int 1465218822Sdimdt_print_type(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr) 1466218822Sdim{ 1467218822Sdim caddr_t addrend; 1468218822Sdim char *p; 1469218822Sdim dtrace_typeinfo_t dtt; 1470218822Sdim dt_type_cbdata_t cbdata; 1471218822Sdim int num = 0; 1472218822Sdim int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 1473218822Sdim ssize_t ssz; 1474218822Sdim 1475218822Sdim if (!quiet) 1476218822Sdim dt_printf(dtp, fp, "\n"); 1477218822Sdim 1478218822Sdim /* Get the total number of bytes of data buffered. */ 1479218822Sdim size_t nbytes = *((uintptr_t *) addr); 1480218822Sdim addr += sizeof(uintptr_t); 1481218822Sdim 1482218822Sdim /* 1483218822Sdim * Get the size of the type so that we can check that it matches 1484218822Sdim * the CTF data we look up and so that we can figure out how many 1485218822Sdim * type elements are buffered. 1486218822Sdim */ 1487218822Sdim size_t typs = *((uintptr_t *) addr); 1488218822Sdim addr += sizeof(uintptr_t); 1489218822Sdim 1490218822Sdim /* 1491218822Sdim * Point to the type string in the buffer. Get it's string 1492218822Sdim * length and round it up to become the offset to the start 1493218822Sdim * of the buffered type data which we would like to be aligned 1494218822Sdim * for easy access. 1495218822Sdim */ 1496218822Sdim char *strp = (char *) addr; 1497218822Sdim int offset = roundup(strlen(strp) + 1, sizeof(uintptr_t)); 1498218822Sdim 1499218822Sdim /* 1500218822Sdim * The type string might have a format such as 'int [20]'. 1501218822Sdim * Check if there is an array dimension present. 1502218822Sdim */ 1503218822Sdim if ((p = strchr(strp, '[')) != NULL) { 1504218822Sdim /* Strip off the array dimension. */ 1505218822Sdim *p++ = '\0'; 1506218822Sdim 1507218822Sdim for (; *p != '\0' && *p != ']'; p++) 1508218822Sdim num = num * 10 + *p - '0'; 1509218822Sdim } else 1510218822Sdim /* No array dimension, so default. */ 1511218822Sdim num = 1; 1512218822Sdim 1513218822Sdim /* Lookup the CTF type from the type string. */ 1514218822Sdim if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, strp, &dtt) < 0) 1515218822Sdim return (-1); 1516218822Sdim 1517218822Sdim /* Offset the buffer address to the start of the data... */ 1518218822Sdim addr += offset; 1519218822Sdim 1520218822Sdim ssz = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type); 1521218822Sdim 1522218822Sdim if (typs != ssz) { 1523218822Sdim printf("Expected type size from buffer (%lu) to match type size looked up now (%ld)\n", (u_long) typs, (long) ssz); 1524218822Sdim return (-1); 1525218822Sdim } 1526218822Sdim 1527218822Sdim cbdata.dtp = dtp; 1528218822Sdim cbdata.dtt = dtt; 1529218822Sdim cbdata.name = ""; 1530218822Sdim cbdata.addr = addr; 1531218822Sdim cbdata.addrend = addr + nbytes; 1532218822Sdim cbdata.indent = 1; 1533218822Sdim cbdata.f_type = 1; 1534218822Sdim cbdata.type_width = 0; 1535218822Sdim cbdata.name_width = 0; 1536218822Sdim cbdata.fp = fp; 1537218822Sdim 1538218822Sdim return (dt_print_type_data(&cbdata, dtt.dtt_type)); 1539218822Sdim} 1540218822Sdim 1541218822Sdimstatic int 1542218822Sdimdt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1543218822Sdim{ 1544218822Sdim /* LINTED - alignment */ 1545218822Sdim uint64_t pc = *((uint64_t *)addr); 1546218822Sdim dtrace_syminfo_t dts; 1547218822Sdim GElf_Sym sym; 1548218822Sdim char c[PATH_MAX * 2]; 1549218822Sdim 1550218822Sdim if (format == NULL) 1551218822Sdim format = " %-50s"; 1552218822Sdim 1553218822Sdim if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 1554218822Sdim (void) snprintf(c, sizeof (c), "%s`%s", 1555218822Sdim dts.dts_object, dts.dts_name); 1556218822Sdim } else { 1557218822Sdim /* 1558218822Sdim * We'll repeat the lookup, but this time we'll specify a 1559218822Sdim * NULL GElf_Sym -- indicating that we're only interested in 1560218822Sdim * the containing module. 1561218822Sdim */ 1562218822Sdim if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1563218822Sdim (void) snprintf(c, sizeof (c), "%s`0x%llx", 1564218822Sdim dts.dts_object, (u_longlong_t)pc); 1565218822Sdim } else { 1566218822Sdim (void) snprintf(c, sizeof (c), "0x%llx", 1567218822Sdim (u_longlong_t)pc); 1568218822Sdim } 1569218822Sdim } 1570218822Sdim 1571218822Sdim if (dt_printf(dtp, fp, format, c) < 0) 1572218822Sdim return (-1); 1573218822Sdim 1574218822Sdim return (0); 1575218822Sdim} 1576218822Sdim 1577218822Sdimint 1578218822Sdimdt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1579218822Sdim{ 1580218822Sdim /* LINTED - alignment */ 1581218822Sdim uint64_t pc = *((uint64_t *)addr); 1582218822Sdim dtrace_syminfo_t dts; 1583218822Sdim char c[PATH_MAX * 2]; 1584218822Sdim 1585218822Sdim if (format == NULL) 1586218822Sdim format = " %-50s"; 1587218822Sdim 1588218822Sdim if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1589218822Sdim (void) snprintf(c, sizeof (c), "%s", dts.dts_object); 1590218822Sdim } else { 1591218822Sdim (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1592218822Sdim } 1593218822Sdim 1594218822Sdim if (dt_printf(dtp, fp, format, c) < 0) 1595218822Sdim return (-1); 1596218822Sdim 1597218822Sdim return (0); 1598218822Sdim} 1599218822Sdim 1600218822Sdimtypedef struct dt_normal { 1601218822Sdim dtrace_aggvarid_t dtnd_id; 1602218822Sdim uint64_t dtnd_normal; 1603218822Sdim} dt_normal_t; 1604218822Sdim 1605218822Sdimstatic int 1606218822Sdimdt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 1607218822Sdim{ 1608218822Sdim dt_normal_t *normal = arg; 1609218822Sdim dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1610218822Sdim dtrace_aggvarid_t id = normal->dtnd_id; 1611218822Sdim 1612218822Sdim if (agg->dtagd_nrecs == 0) 1613218822Sdim return (DTRACE_AGGWALK_NEXT); 1614218822Sdim 1615218822Sdim if (agg->dtagd_varid != id) 1616218822Sdim return (DTRACE_AGGWALK_NEXT); 1617218822Sdim 1618218822Sdim ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal; 1619218822Sdim return (DTRACE_AGGWALK_NORMALIZE); 1620218822Sdim} 1621218822Sdim 1622218822Sdimstatic int 1623218822Sdimdt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 1624218822Sdim{ 1625218822Sdim dt_normal_t normal; 1626218822Sdim caddr_t addr; 1627218822Sdim 1628218822Sdim /* 1629218822Sdim * We (should) have two records: the aggregation ID followed by the 1630218822Sdim * normalization value. 1631218822Sdim */ 1632218822Sdim addr = base + rec->dtrd_offset; 1633218822Sdim 1634218822Sdim if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 1635218822Sdim return (dt_set_errno(dtp, EDT_BADNORMAL)); 1636218822Sdim 1637218822Sdim /* LINTED - alignment */ 1638218822Sdim normal.dtnd_id = *((dtrace_aggvarid_t *)addr); 1639218822Sdim rec++; 1640218822Sdim 1641218822Sdim if (rec->dtrd_action != DTRACEACT_LIBACT) 1642218822Sdim return (dt_set_errno(dtp, EDT_BADNORMAL)); 1643218822Sdim 1644218822Sdim if (rec->dtrd_arg != DT_ACT_NORMALIZE) 1645218822Sdim return (dt_set_errno(dtp, EDT_BADNORMAL)); 1646218822Sdim 1647218822Sdim addr = base + rec->dtrd_offset; 1648218822Sdim 1649218822Sdim switch (rec->dtrd_size) { 1650218822Sdim case sizeof (uint64_t): 1651218822Sdim /* LINTED - alignment */ 1652218822Sdim normal.dtnd_normal = *((uint64_t *)addr); 1653218822Sdim break; 1654218822Sdim case sizeof (uint32_t): 1655218822Sdim /* LINTED - alignment */ 1656218822Sdim normal.dtnd_normal = *((uint32_t *)addr); 1657218822Sdim break; 1658218822Sdim case sizeof (uint16_t): 1659218822Sdim /* LINTED - alignment */ 1660218822Sdim normal.dtnd_normal = *((uint16_t *)addr); 1661218822Sdim break; 1662218822Sdim case sizeof (uint8_t): 1663218822Sdim normal.dtnd_normal = *((uint8_t *)addr); 1664218822Sdim break; 1665218822Sdim default: 1666218822Sdim return (dt_set_errno(dtp, EDT_BADNORMAL)); 1667218822Sdim } 1668218822Sdim 1669218822Sdim (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal); 1670218822Sdim 1671218822Sdim return (0); 1672218822Sdim} 1673218822Sdim 1674218822Sdimstatic int 1675218822Sdimdt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 1676218822Sdim{ 1677218822Sdim dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1678218822Sdim dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 1679218822Sdim 1680218822Sdim if (agg->dtagd_nrecs == 0) 1681218822Sdim return (DTRACE_AGGWALK_NEXT); 1682218822Sdim 1683218822Sdim if (agg->dtagd_varid != id) 1684218822Sdim return (DTRACE_AGGWALK_NEXT); 1685218822Sdim 168638889Sjdp return (DTRACE_AGGWALK_DENORMALIZE); 168738889Sjdp} 168838889Sjdp 168938889Sjdpstatic int 1690218822Sdimdt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg) 169138889Sjdp{ 1692218822Sdim dtrace_aggdesc_t *agg = aggdata->dtada_desc; 169385815Sobrien dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 169438889Sjdp 169585815Sobrien if (agg->dtagd_nrecs == 0) 169685815Sobrien return (DTRACE_AGGWALK_NEXT); 169785815Sobrien 169885815Sobrien if (agg->dtagd_varid != id) 169985815Sobrien return (DTRACE_AGGWALK_NEXT); 170085815Sobrien 170185815Sobrien return (DTRACE_AGGWALK_CLEAR); 170285815Sobrien} 170338889Sjdp 170438889Sjdptypedef struct dt_trunc { 170538889Sjdp dtrace_aggvarid_t dttd_id; 170638889Sjdp uint64_t dttd_remaining; 170738889Sjdp} dt_trunc_t; 170838889Sjdp 170938889Sjdpstatic int 171038889Sjdpdt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg) 171185815Sobrien{ 1712218822Sdim dt_trunc_t *trunc = arg; 171385815Sobrien dtrace_aggdesc_t *agg = aggdata->dtada_desc; 171485815Sobrien dtrace_aggvarid_t id = trunc->dttd_id; 171585815Sobrien 171685815Sobrien if (agg->dtagd_nrecs == 0) 171785815Sobrien return (DTRACE_AGGWALK_NEXT); 1718218822Sdim 171985815Sobrien if (agg->dtagd_varid != id) 172085815Sobrien return (DTRACE_AGGWALK_NEXT); 172185815Sobrien 172285815Sobrien if (trunc->dttd_remaining == 0) 172385815Sobrien return (DTRACE_AGGWALK_REMOVE); 172485815Sobrien 1725218822Sdim trunc->dttd_remaining--; 172685815Sobrien return (DTRACE_AGGWALK_NEXT); 172785815Sobrien} 172885815Sobrien 172985815Sobrienstatic int 1730218822Sdimdt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 173185815Sobrien{ 173285815Sobrien dt_trunc_t trunc; 1733218822Sdim caddr_t addr; 173485815Sobrien int64_t remaining; 173585815Sobrien int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *); 1736218822Sdim 173785815Sobrien /* 173885815Sobrien * We (should) have two records: the aggregation ID followed by the 173985815Sobrien * number of aggregation entries after which the aggregation is to be 174085815Sobrien * truncated. 174185815Sobrien */ 174285815Sobrien addr = base + rec->dtrd_offset; 1743218822Sdim 174485815Sobrien if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 174585815Sobrien return (dt_set_errno(dtp, EDT_BADTRUNC)); 174685815Sobrien 174785815Sobrien /* LINTED - alignment */ 174885815Sobrien trunc.dttd_id = *((dtrace_aggvarid_t *)addr); 174985815Sobrien rec++; 175085815Sobrien 175185815Sobrien if (rec->dtrd_action != DTRACEACT_LIBACT) 175285815Sobrien return (dt_set_errno(dtp, EDT_BADTRUNC)); 175385815Sobrien 175485815Sobrien if (rec->dtrd_arg != DT_ACT_TRUNC) 175585815Sobrien return (dt_set_errno(dtp, EDT_BADTRUNC)); 175685815Sobrien 175785815Sobrien addr = base + rec->dtrd_offset; 1758218822Sdim 175985815Sobrien switch (rec->dtrd_size) { 176085815Sobrien case sizeof (uint64_t): 176185815Sobrien /* LINTED - alignment */ 1762 remaining = *((int64_t *)addr); 1763 break; 1764 case sizeof (uint32_t): 1765 /* LINTED - alignment */ 1766 remaining = *((int32_t *)addr); 1767 break; 1768 case sizeof (uint16_t): 1769 /* LINTED - alignment */ 1770 remaining = *((int16_t *)addr); 1771 break; 1772 case sizeof (uint8_t): 1773 remaining = *((int8_t *)addr); 1774 break; 1775 default: 1776 return (dt_set_errno(dtp, EDT_BADNORMAL)); 1777 } 1778 1779 if (remaining < 0) { 1780 func = dtrace_aggregate_walk_valsorted; 1781 remaining = -remaining; 1782 } else { 1783 func = dtrace_aggregate_walk_valrevsorted; 1784 } 1785 1786 assert(remaining >= 0); 1787 trunc.dttd_remaining = remaining; 1788 1789 (void) func(dtp, dt_trunc_agg, &trunc); 1790 1791 return (0); 1792} 1793 1794static int 1795dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, 1796 caddr_t addr, size_t size, uint64_t normal) 1797{ 1798 int err; 1799 dtrace_actkind_t act = rec->dtrd_action; 1800 1801 switch (act) { 1802 case DTRACEACT_STACK: 1803 return (dt_print_stack(dtp, fp, NULL, addr, 1804 rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg)); 1805 1806 case DTRACEACT_USTACK: 1807 case DTRACEACT_JSTACK: 1808 return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg)); 1809 1810 case DTRACEACT_USYM: 1811 case DTRACEACT_UADDR: 1812 return (dt_print_usym(dtp, fp, addr, act)); 1813 1814 case DTRACEACT_UMOD: 1815 return (dt_print_umod(dtp, fp, NULL, addr)); 1816 1817 case DTRACEACT_SYM: 1818 return (dt_print_sym(dtp, fp, NULL, addr)); 1819 1820 case DTRACEACT_MOD: 1821 return (dt_print_mod(dtp, fp, NULL, addr)); 1822 1823 case DTRACEAGG_QUANTIZE: 1824 return (dt_print_quantize(dtp, fp, addr, size, normal)); 1825 1826 case DTRACEAGG_LQUANTIZE: 1827 return (dt_print_lquantize(dtp, fp, addr, size, normal)); 1828 1829 case DTRACEAGG_LLQUANTIZE: 1830 return (dt_print_llquantize(dtp, fp, addr, size, normal)); 1831 1832 case DTRACEAGG_AVG: 1833 return (dt_print_average(dtp, fp, addr, size, normal)); 1834 1835 case DTRACEAGG_STDDEV: 1836 return (dt_print_stddev(dtp, fp, addr, size, normal)); 1837 1838 default: 1839 break; 1840 } 1841 1842 switch (size) { 1843 case sizeof (uint64_t): 1844 err = dt_printf(dtp, fp, " %16lld", 1845 /* LINTED - alignment */ 1846 (long long)*((uint64_t *)addr) / normal); 1847 break; 1848 case sizeof (uint32_t): 1849 /* LINTED - alignment */ 1850 err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) / 1851 (uint32_t)normal); 1852 break; 1853 case sizeof (uint16_t): 1854 /* LINTED - alignment */ 1855 err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) / 1856 (uint32_t)normal); 1857 break; 1858 case sizeof (uint8_t): 1859 err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) / 1860 (uint32_t)normal); 1861 break; 1862 default: 1863 err = dt_print_bytes(dtp, fp, addr, size, 50, 0, 0); 1864 break; 1865 } 1866 1867 return (err); 1868} 1869 1870int 1871dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) 1872{ 1873 int i, aggact = 0; 1874 dt_print_aggdata_t *pd = arg; 1875 const dtrace_aggdata_t *aggdata = aggsdata[0]; 1876 dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1877 FILE *fp = pd->dtpa_fp; 1878 dtrace_hdl_t *dtp = pd->dtpa_dtp; 1879 dtrace_recdesc_t *rec; 1880 dtrace_actkind_t act; 1881 caddr_t addr; 1882 size_t size; 1883 1884 /* 1885 * Iterate over each record description in the key, printing the traced 1886 * data, skipping the first datum (the tuple member created by the 1887 * compiler). 1888 */ 1889 for (i = 1; i < agg->dtagd_nrecs; i++) { 1890 rec = &agg->dtagd_rec[i]; 1891 act = rec->dtrd_action; 1892 addr = aggdata->dtada_data + rec->dtrd_offset; 1893 size = rec->dtrd_size; 1894 1895 if (DTRACEACT_ISAGG(act)) { 1896 aggact = i; 1897 break; 1898 } 1899 1900 if (dt_print_datum(dtp, fp, rec, addr, size, 1) < 0) 1901 return (-1); 1902 1903 if (dt_buffered_flush(dtp, NULL, rec, aggdata, 1904 DTRACE_BUFDATA_AGGKEY) < 0) 1905 return (-1); 1906 } 1907 1908 assert(aggact != 0); 1909 1910 for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) { 1911 uint64_t normal; 1912 1913 aggdata = aggsdata[i]; 1914 agg = aggdata->dtada_desc; 1915 rec = &agg->dtagd_rec[aggact]; 1916 act = rec->dtrd_action; 1917 addr = aggdata->dtada_data + rec->dtrd_offset; 1918 size = rec->dtrd_size; 1919 1920 assert(DTRACEACT_ISAGG(act)); 1921 normal = aggdata->dtada_normal; 1922 1923 if (dt_print_datum(dtp, fp, rec, addr, size, normal) < 0) 1924 return (-1); 1925 1926 if (dt_buffered_flush(dtp, NULL, rec, aggdata, 1927 DTRACE_BUFDATA_AGGVAL) < 0) 1928 return (-1); 1929 1930 if (!pd->dtpa_allunprint) 1931 agg->dtagd_flags |= DTRACE_AGD_PRINTED; 1932 } 1933 1934 if (dt_printf(dtp, fp, "\n") < 0) 1935 return (-1); 1936 1937 if (dt_buffered_flush(dtp, NULL, NULL, aggdata, 1938 DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) 1939 return (-1); 1940 1941 return (0); 1942} 1943 1944int 1945dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg) 1946{ 1947 dt_print_aggdata_t *pd = arg; 1948 dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1949 dtrace_aggvarid_t aggvarid = pd->dtpa_id; 1950 1951 if (pd->dtpa_allunprint) { 1952 if (agg->dtagd_flags & DTRACE_AGD_PRINTED) 1953 return (0); 1954 } else { 1955 /* 1956 * If we're not printing all unprinted aggregations, then the 1957 * aggregation variable ID denotes a specific aggregation 1958 * variable that we should print -- skip any other aggregations 1959 * that we encounter. 1960 */ 1961 if (agg->dtagd_nrecs == 0) 1962 return (0); 1963 1964 if (aggvarid != agg->dtagd_varid) 1965 return (0); 1966 } 1967 1968 return (dt_print_aggs(&aggdata, 1, arg)); 1969} 1970 1971int 1972dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, 1973 const char *option, const char *value) 1974{ 1975 int len, rval; 1976 char *msg; 1977 const char *errstr; 1978 dtrace_setoptdata_t optdata; 1979 1980 bzero(&optdata, sizeof (optdata)); 1981 (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval); 1982 1983 if (dtrace_setopt(dtp, option, value) == 0) { 1984 (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval); 1985 optdata.dtsda_probe = data; 1986 optdata.dtsda_option = option; 1987 optdata.dtsda_handle = dtp; 1988 1989 if ((rval = dt_handle_setopt(dtp, &optdata)) != 0) 1990 return (rval); 1991 1992 return (0); 1993 } 1994 1995 errstr = dtrace_errmsg(dtp, dtrace_errno(dtp)); 1996 len = strlen(option) + strlen(value) + strlen(errstr) + 80; 1997 msg = alloca(len); 1998 1999 (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n", 2000 option, value, errstr); 2001 2002 if ((rval = dt_handle_liberr(dtp, data, msg)) == 0) 2003 return (0); 2004 2005 return (rval); 2006} 2007 2008static int 2009dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, 2010 dtrace_bufdesc_t *buf, boolean_t just_one, 2011 dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) 2012{ 2013 dtrace_epid_t id; 2014 size_t offs; 2015 int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 2016 int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 2017 int rval, i, n; 2018 uint64_t tracememsize = 0; 2019 dtrace_probedata_t data; 2020 uint64_t drops; 2021 2022 bzero(&data, sizeof (data)); 2023 data.dtpda_handle = dtp; 2024 data.dtpda_cpu = cpu; 2025 data.dtpda_flow = dtp->dt_flow; 2026 data.dtpda_indent = dtp->dt_indent; 2027 data.dtpda_prefix = dtp->dt_prefix; 2028 2029 for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) { 2030 dtrace_eprobedesc_t *epd; 2031 2032 /* 2033 * We're guaranteed to have an ID. 2034 */ 2035 id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 2036 2037 if (id == DTRACE_EPIDNONE) { 2038 /* 2039 * This is filler to assure proper alignment of the 2040 * next record; we simply ignore it. 2041 */ 2042 offs += sizeof (id); 2043 continue; 2044 } 2045 2046 if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc, 2047 &data.dtpda_pdesc)) != 0) 2048 return (rval); 2049 2050 epd = data.dtpda_edesc; 2051 data.dtpda_data = buf->dtbd_data + offs; 2052 2053 if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) { 2054 rval = dt_handle(dtp, &data); 2055 2056 if (rval == DTRACE_CONSUME_NEXT) 2057 goto nextepid; 2058 2059 if (rval == DTRACE_CONSUME_ERROR) 2060 return (-1); 2061 } 2062 2063 if (flow) 2064 (void) dt_flowindent(dtp, &data, dtp->dt_last_epid, 2065 buf, offs); 2066 2067 rval = (*efunc)(&data, arg); 2068 2069 if (flow) { 2070 if (data.dtpda_flow == DTRACEFLOW_ENTRY) 2071 data.dtpda_indent += 2; 2072 } 2073 2074 if (rval == DTRACE_CONSUME_NEXT) 2075 goto nextepid; 2076 2077 if (rval == DTRACE_CONSUME_ABORT) 2078 return (dt_set_errno(dtp, EDT_DIRABORT)); 2079 2080 if (rval != DTRACE_CONSUME_THIS) 2081 return (dt_set_errno(dtp, EDT_BADRVAL)); 2082 2083 for (i = 0; i < epd->dtepd_nrecs; i++) { 2084 caddr_t addr; 2085 dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; 2086 dtrace_actkind_t act = rec->dtrd_action; 2087 2088 data.dtpda_data = buf->dtbd_data + offs + 2089 rec->dtrd_offset; 2090 addr = data.dtpda_data; 2091 2092 if (act == DTRACEACT_LIBACT) { 2093 uint64_t arg = rec->dtrd_arg; 2094 dtrace_aggvarid_t id; 2095 2096 switch (arg) { 2097 case DT_ACT_CLEAR: 2098 /* LINTED - alignment */ 2099 id = *((dtrace_aggvarid_t *)addr); 2100 (void) dtrace_aggregate_walk(dtp, 2101 dt_clear_agg, &id); 2102 continue; 2103 2104 case DT_ACT_DENORMALIZE: 2105 /* LINTED - alignment */ 2106 id = *((dtrace_aggvarid_t *)addr); 2107 (void) dtrace_aggregate_walk(dtp, 2108 dt_denormalize_agg, &id); 2109 continue; 2110 2111 case DT_ACT_FTRUNCATE: 2112 if (fp == NULL) 2113 continue; 2114 2115 (void) fflush(fp); 2116 (void) ftruncate(fileno(fp), 0); 2117 (void) fseeko(fp, 0, SEEK_SET); 2118 continue; 2119 2120 case DT_ACT_NORMALIZE: 2121 if (i == epd->dtepd_nrecs - 1) 2122 return (dt_set_errno(dtp, 2123 EDT_BADNORMAL)); 2124 2125 if (dt_normalize(dtp, 2126 buf->dtbd_data + offs, rec) != 0) 2127 return (-1); 2128 2129 i++; 2130 continue; 2131 2132 case DT_ACT_SETOPT: { 2133 uint64_t *opts = dtp->dt_options; 2134 dtrace_recdesc_t *valrec; 2135 uint32_t valsize; 2136 caddr_t val; 2137 int rv; 2138 2139 if (i == epd->dtepd_nrecs - 1) { 2140 return (dt_set_errno(dtp, 2141 EDT_BADSETOPT)); 2142 } 2143 2144 valrec = &epd->dtepd_rec[++i]; 2145 valsize = valrec->dtrd_size; 2146 2147 if (valrec->dtrd_action != act || 2148 valrec->dtrd_arg != arg) { 2149 return (dt_set_errno(dtp, 2150 EDT_BADSETOPT)); 2151 } 2152 2153 if (valsize > sizeof (uint64_t)) { 2154 val = buf->dtbd_data + offs + 2155 valrec->dtrd_offset; 2156 } else { 2157 val = "1"; 2158 } 2159 2160 rv = dt_setopt(dtp, &data, addr, val); 2161 2162 if (rv != 0) 2163 return (-1); 2164 2165 flow = (opts[DTRACEOPT_FLOWINDENT] != 2166 DTRACEOPT_UNSET); 2167 quiet = (opts[DTRACEOPT_QUIET] != 2168 DTRACEOPT_UNSET); 2169 2170 continue; 2171 } 2172 2173 case DT_ACT_TRUNC: 2174 if (i == epd->dtepd_nrecs - 1) 2175 return (dt_set_errno(dtp, 2176 EDT_BADTRUNC)); 2177 2178 if (dt_trunc(dtp, 2179 buf->dtbd_data + offs, rec) != 0) 2180 return (-1); 2181 2182 i++; 2183 continue; 2184 2185 default: 2186 continue; 2187 } 2188 } 2189 2190 if (act == DTRACEACT_TRACEMEM_DYNSIZE && 2191 rec->dtrd_size == sizeof (uint64_t)) { 2192 /* LINTED - alignment */ 2193 tracememsize = *((unsigned long long *)addr); 2194 continue; 2195 } 2196 2197 rval = (*rfunc)(&data, rec, arg); 2198 2199 if (rval == DTRACE_CONSUME_NEXT) 2200 continue; 2201 2202 if (rval == DTRACE_CONSUME_ABORT) 2203 return (dt_set_errno(dtp, EDT_DIRABORT)); 2204 2205 if (rval != DTRACE_CONSUME_THIS) 2206 return (dt_set_errno(dtp, EDT_BADRVAL)); 2207 2208 if (act == DTRACEACT_STACK) { 2209 int depth = rec->dtrd_arg; 2210 2211 if (dt_print_stack(dtp, fp, NULL, addr, depth, 2212 rec->dtrd_size / depth) < 0) 2213 return (-1); 2214 goto nextrec; 2215 } 2216 2217 if (act == DTRACEACT_USTACK || 2218 act == DTRACEACT_JSTACK) { 2219 if (dt_print_ustack(dtp, fp, NULL, 2220 addr, rec->dtrd_arg) < 0) 2221 return (-1); 2222 goto nextrec; 2223 } 2224 2225 if (act == DTRACEACT_SYM) { 2226 if (dt_print_sym(dtp, fp, NULL, addr) < 0) 2227 return (-1); 2228 goto nextrec; 2229 } 2230 2231 if (act == DTRACEACT_MOD) { 2232 if (dt_print_mod(dtp, fp, NULL, addr) < 0) 2233 return (-1); 2234 goto nextrec; 2235 } 2236 2237 if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) { 2238 if (dt_print_usym(dtp, fp, addr, act) < 0) 2239 return (-1); 2240 goto nextrec; 2241 } 2242 2243 if (act == DTRACEACT_UMOD) { 2244 if (dt_print_umod(dtp, fp, NULL, addr) < 0) 2245 return (-1); 2246 goto nextrec; 2247 } 2248 2249 if (act == DTRACEACT_PRINTM) { 2250 if (dt_print_memory(dtp, fp, addr) < 0) 2251 return (-1); 2252 goto nextrec; 2253 } 2254 2255 if (act == DTRACEACT_PRINTT) { 2256 if (dt_print_type(dtp, fp, addr) < 0) 2257 return (-1); 2258 goto nextrec; 2259 } 2260 2261 if (DTRACEACT_ISPRINTFLIKE(act)) { 2262 void *fmtdata; 2263 int (*func)(dtrace_hdl_t *, FILE *, void *, 2264 const dtrace_probedata_t *, 2265 const dtrace_recdesc_t *, uint_t, 2266 const void *buf, size_t); 2267 2268 if ((fmtdata = dt_format_lookup(dtp, 2269 rec->dtrd_format)) == NULL) 2270 goto nofmt; 2271 2272 switch (act) { 2273 case DTRACEACT_PRINTF: 2274 func = dtrace_fprintf; 2275 break; 2276 case DTRACEACT_PRINTA: 2277 func = dtrace_fprinta; 2278 break; 2279 case DTRACEACT_SYSTEM: 2280 func = dtrace_system; 2281 break; 2282 case DTRACEACT_FREOPEN: 2283 func = dtrace_freopen; 2284 break; 2285 } 2286 2287 n = (*func)(dtp, fp, fmtdata, &data, 2288 rec, epd->dtepd_nrecs - i, 2289 (uchar_t *)buf->dtbd_data + offs, 2290 buf->dtbd_size - offs); 2291 2292 if (n < 0) 2293 return (-1); /* errno is set for us */ 2294 2295 if (n > 0) 2296 i += n - 1; 2297 goto nextrec; 2298 } 2299 2300 /* 2301 * If this is a DIF expression, and the record has a 2302 * format set, this indicates we have a CTF type name 2303 * associated with the data and we should try to print 2304 * it out by type. 2305 */ 2306 if (act == DTRACEACT_DIFEXPR) { 2307 const char *strdata = dt_strdata_lookup(dtp, 2308 rec->dtrd_format); 2309 if (strdata != NULL) { 2310 n = dtrace_print(dtp, fp, strdata, 2311 addr, rec->dtrd_size); 2312 2313 /* 2314 * dtrace_print() will return -1 on 2315 * error, or return the number of bytes 2316 * consumed. It will return 0 if the 2317 * type couldn't be determined, and we 2318 * should fall through to the normal 2319 * trace method. 2320 */ 2321 if (n < 0) 2322 return (-1); 2323 2324 if (n > 0) 2325 goto nextrec; 2326 } 2327 } 2328 2329nofmt: 2330 if (act == DTRACEACT_PRINTA) { 2331 dt_print_aggdata_t pd; 2332 dtrace_aggvarid_t *aggvars; 2333 int j, naggvars = 0; 2334 size_t size = ((epd->dtepd_nrecs - i) * 2335 sizeof (dtrace_aggvarid_t)); 2336 2337 if ((aggvars = dt_alloc(dtp, size)) == NULL) 2338 return (-1); 2339 2340 /* 2341 * This might be a printa() with multiple 2342 * aggregation variables. We need to scan 2343 * forward through the records until we find 2344 * a record from a different statement. 2345 */ 2346 for (j = i; j < epd->dtepd_nrecs; j++) { 2347 dtrace_recdesc_t *nrec; 2348 caddr_t naddr; 2349 2350 nrec = &epd->dtepd_rec[j]; 2351 2352 if (nrec->dtrd_uarg != rec->dtrd_uarg) 2353 break; 2354 2355 if (nrec->dtrd_action != act) { 2356 return (dt_set_errno(dtp, 2357 EDT_BADAGG)); 2358 } 2359 2360 naddr = buf->dtbd_data + offs + 2361 nrec->dtrd_offset; 2362 2363 aggvars[naggvars++] = 2364 /* LINTED - alignment */ 2365 *((dtrace_aggvarid_t *)naddr); 2366 } 2367 2368 i = j - 1; 2369 bzero(&pd, sizeof (pd)); 2370 pd.dtpa_dtp = dtp; 2371 pd.dtpa_fp = fp; 2372 2373 assert(naggvars >= 1); 2374 2375 if (naggvars == 1) { 2376 pd.dtpa_id = aggvars[0]; 2377 dt_free(dtp, aggvars); 2378 2379 if (dt_printf(dtp, fp, "\n") < 0 || 2380 dtrace_aggregate_walk_sorted(dtp, 2381 dt_print_agg, &pd) < 0) 2382 return (-1); 2383 goto nextrec; 2384 } 2385 2386 if (dt_printf(dtp, fp, "\n") < 0 || 2387 dtrace_aggregate_walk_joined(dtp, aggvars, 2388 naggvars, dt_print_aggs, &pd) < 0) { 2389 dt_free(dtp, aggvars); 2390 return (-1); 2391 } 2392 2393 dt_free(dtp, aggvars); 2394 goto nextrec; 2395 } 2396 2397 if (act == DTRACEACT_TRACEMEM) { 2398 if (tracememsize == 0 || 2399 tracememsize > rec->dtrd_size) { 2400 tracememsize = rec->dtrd_size; 2401 } 2402 2403 n = dt_print_bytes(dtp, fp, addr, 2404 tracememsize, 33, quiet, 1); 2405 2406 tracememsize = 0; 2407 2408 if (n < 0) 2409 return (-1); 2410 2411 goto nextrec; 2412 } 2413 2414 switch (rec->dtrd_size) { 2415 case sizeof (uint64_t): 2416 n = dt_printf(dtp, fp, 2417 quiet ? "%lld" : " %16lld", 2418 /* LINTED - alignment */ 2419 *((unsigned long long *)addr)); 2420 break; 2421 case sizeof (uint32_t): 2422 n = dt_printf(dtp, fp, quiet ? "%d" : " %8d", 2423 /* LINTED - alignment */ 2424 *((uint32_t *)addr)); 2425 break; 2426 case sizeof (uint16_t): 2427 n = dt_printf(dtp, fp, quiet ? "%d" : " %5d", 2428 /* LINTED - alignment */ 2429 *((uint16_t *)addr)); 2430 break; 2431 case sizeof (uint8_t): 2432 n = dt_printf(dtp, fp, quiet ? "%d" : " %3d", 2433 *((uint8_t *)addr)); 2434 break; 2435 default: 2436 n = dt_print_bytes(dtp, fp, addr, 2437 rec->dtrd_size, 33, quiet, 0); 2438 break; 2439 } 2440 2441 if (n < 0) 2442 return (-1); /* errno is set for us */ 2443 2444nextrec: 2445 if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0) 2446 return (-1); /* errno is set for us */ 2447 } 2448 2449 /* 2450 * Call the record callback with a NULL record to indicate 2451 * that we're done processing this EPID. 2452 */ 2453 rval = (*rfunc)(&data, NULL, arg); 2454nextepid: 2455 offs += epd->dtepd_size; 2456 dtp->dt_last_epid = id; 2457 if (just_one) { 2458 buf->dtbd_oldest = offs; 2459 break; 2460 } 2461 } 2462 2463 dtp->dt_flow = data.dtpda_flow; 2464 dtp->dt_indent = data.dtpda_indent; 2465 dtp->dt_prefix = data.dtpda_prefix; 2466 2467 if ((drops = buf->dtbd_drops) == 0) 2468 return (0); 2469 2470 /* 2471 * Explicitly zero the drops to prevent us from processing them again. 2472 */ 2473 buf->dtbd_drops = 0; 2474 2475 return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); 2476} 2477 2478/* 2479 * Reduce memory usage by shrinking the buffer if it's no more than half full. 2480 * Note, we need to preserve the alignment of the data at dtbd_oldest, which is 2481 * only 4-byte aligned. 2482 */ 2483static void 2484dt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize) 2485{ 2486 uint64_t used = buf->dtbd_size - buf->dtbd_oldest; 2487 if (used < cursize / 2) { 2488 int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2489 char *newdata = dt_alloc(dtp, used + misalign); 2490 if (newdata == NULL) 2491 return; 2492 bzero(newdata, misalign); 2493 bcopy(buf->dtbd_data + buf->dtbd_oldest, 2494 newdata + misalign, used); 2495 dt_free(dtp, buf->dtbd_data); 2496 buf->dtbd_oldest = misalign; 2497 buf->dtbd_size = used + misalign; 2498 buf->dtbd_data = newdata; 2499 } 2500} 2501 2502/* 2503 * If the ring buffer has wrapped, the data is not in order. Rearrange it 2504 * so that it is. Note, we need to preserve the alignment of the data at 2505 * dtbd_oldest, which is only 4-byte aligned. 2506 */ 2507static int 2508dt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2509{ 2510 int misalign; 2511 char *newdata, *ndp; 2512 2513 if (buf->dtbd_oldest == 0) 2514 return (0); 2515 2516 misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2517 newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign); 2518 2519 if (newdata == NULL) 2520 return (-1); 2521 2522 assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1))); 2523 2524 bzero(ndp, misalign); 2525 ndp += misalign; 2526 2527 bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp, 2528 buf->dtbd_size - buf->dtbd_oldest); 2529 ndp += buf->dtbd_size - buf->dtbd_oldest; 2530 2531 bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest); 2532 2533 dt_free(dtp, buf->dtbd_data); 2534 buf->dtbd_oldest = 0; 2535 buf->dtbd_data = newdata; 2536 buf->dtbd_size += misalign; 2537 2538 return (0); 2539} 2540 2541static void 2542dt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2543{ 2544 dt_free(dtp, buf->dtbd_data); 2545 dt_free(dtp, buf); 2546} 2547 2548/* 2549 * Returns 0 on success, in which case *cbp will be filled in if we retrieved 2550 * data, or NULL if there is no data for this CPU. 2551 * Returns -1 on failure and sets dt_errno. 2552 */ 2553static int 2554dt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp) 2555{ 2556 dtrace_optval_t size; 2557 dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf)); 2558 int error; 2559 2560 if (buf == NULL) 2561 return (-1); 2562 2563 (void) dtrace_getopt(dtp, "bufsize", &size); 2564 buf->dtbd_data = dt_alloc(dtp, size); 2565 if (buf->dtbd_data == NULL) { 2566 dt_free(dtp, buf); 2567 return (-1); 2568 } 2569 buf->dtbd_size = size; 2570 buf->dtbd_cpu = cpu; 2571 2572#if defined(sun) 2573 if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 2574#else 2575 if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) { 2576#endif 2577 dt_put_buf(dtp, buf); 2578 /* 2579 * If we failed with ENOENT, it may be because the 2580 * CPU was unconfigured -- this is okay. Any other 2581 * error, however, is unexpected. 2582 */ 2583 if (errno == ENOENT) { 2584 *bufp = NULL; 2585 return (0); 2586 } 2587 2588 return (dt_set_errno(dtp, errno)); 2589 } 2590 2591 error = dt_unring_buf(dtp, buf); 2592 if (error != 0) { 2593 dt_put_buf(dtp, buf); 2594 return (error); 2595 } 2596 dt_realloc_buf(dtp, buf, size); 2597 2598 *bufp = buf; 2599 return (0); 2600} 2601 2602typedef struct dt_begin { 2603 dtrace_consume_probe_f *dtbgn_probefunc; 2604 dtrace_consume_rec_f *dtbgn_recfunc; 2605 void *dtbgn_arg; 2606 dtrace_handle_err_f *dtbgn_errhdlr; 2607 void *dtbgn_errarg; 2608 int dtbgn_beginonly; 2609} dt_begin_t; 2610 2611static int 2612dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) 2613{ 2614 dt_begin_t *begin = arg; 2615 dtrace_probedesc_t *pd = data->dtpda_pdesc; 2616 2617 int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 2618 int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 2619 2620 if (begin->dtbgn_beginonly) { 2621 if (!(r1 && r2)) 2622 return (DTRACE_CONSUME_NEXT); 2623 } else { 2624 if (r1 && r2) 2625 return (DTRACE_CONSUME_NEXT); 2626 } 2627 2628 /* 2629 * We have a record that we're interested in. Now call the underlying 2630 * probe function... 2631 */ 2632 return (begin->dtbgn_probefunc(data, begin->dtbgn_arg)); 2633} 2634 2635static int 2636dt_consume_begin_record(const dtrace_probedata_t *data, 2637 const dtrace_recdesc_t *rec, void *arg) 2638{ 2639 dt_begin_t *begin = arg; 2640 2641 return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); 2642} 2643 2644static int 2645dt_consume_begin_error(const dtrace_errdata_t *data, void *arg) 2646{ 2647 dt_begin_t *begin = (dt_begin_t *)arg; 2648 dtrace_probedesc_t *pd = data->dteda_pdesc; 2649 2650 int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 2651 int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 2652 2653 if (begin->dtbgn_beginonly) { 2654 if (!(r1 && r2)) 2655 return (DTRACE_HANDLE_OK); 2656 } else { 2657 if (r1 && r2) 2658 return (DTRACE_HANDLE_OK); 2659 } 2660 2661 return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg)); 2662} 2663 2664static int 2665dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, 2666 dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 2667{ 2668 /* 2669 * There's this idea that the BEGIN probe should be processed before 2670 * everything else, and that the END probe should be processed after 2671 * anything else. In the common case, this is pretty easy to deal 2672 * with. However, a situation may arise where the BEGIN enabling and 2673 * END enabling are on the same CPU, and some enabling in the middle 2674 * occurred on a different CPU. To deal with this (blech!) we need to 2675 * consume the BEGIN buffer up until the end of the BEGIN probe, and 2676 * then set it aside. We will then process every other CPU, and then 2677 * we'll return to the BEGIN CPU and process the rest of the data 2678 * (which will inevitably include the END probe, if any). Making this 2679 * even more complicated (!) is the library's ERROR enabling. Because 2680 * this enabling is processed before we even get into the consume call 2681 * back, any ERROR firing would result in the library's ERROR enabling 2682 * being processed twice -- once in our first pass (for BEGIN probes), 2683 * and again in our second pass (for everything but BEGIN probes). To 2684 * deal with this, we interpose on the ERROR handler to assure that we 2685 * only process ERROR enablings induced by BEGIN enablings in the 2686 * first pass, and that we only process ERROR enablings _not_ induced 2687 * by BEGIN enablings in the second pass. 2688 */ 2689 2690 dt_begin_t begin; 2691 processorid_t cpu = dtp->dt_beganon; 2692 int rval, i; 2693 static int max_ncpus; 2694 dtrace_bufdesc_t *buf; 2695 2696 dtp->dt_beganon = -1; 2697 2698 if (dt_get_buf(dtp, cpu, &buf) != 0) 2699 return (-1); 2700 if (buf == NULL) 2701 return (0); 2702 2703 if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { 2704 /* 2705 * This is the simple case. We're either not stopped, or if 2706 * we are, we actually processed any END probes on another 2707 * CPU. We can simply consume this buffer and return. 2708 */ 2709 rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2710 pf, rf, arg); 2711 dt_put_buf(dtp, buf); 2712 return (rval); 2713 } 2714 2715 begin.dtbgn_probefunc = pf; 2716 begin.dtbgn_recfunc = rf; 2717 begin.dtbgn_arg = arg; 2718 begin.dtbgn_beginonly = 1; 2719 2720 /* 2721 * We need to interpose on the ERROR handler to be sure that we 2722 * only process ERRORs induced by BEGIN. 2723 */ 2724 begin.dtbgn_errhdlr = dtp->dt_errhdlr; 2725 begin.dtbgn_errarg = dtp->dt_errarg; 2726 dtp->dt_errhdlr = dt_consume_begin_error; 2727 dtp->dt_errarg = &begin; 2728 2729 rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2730 dt_consume_begin_probe, dt_consume_begin_record, &begin); 2731 2732 dtp->dt_errhdlr = begin.dtbgn_errhdlr; 2733 dtp->dt_errarg = begin.dtbgn_errarg; 2734 2735 if (rval != 0) { 2736 dt_put_buf(dtp, buf); 2737 return (rval); 2738 } 2739 2740 if (max_ncpus == 0) 2741 max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 2742 2743 for (i = 0; i < max_ncpus; i++) { 2744 dtrace_bufdesc_t *nbuf; 2745 if (i == cpu) 2746 continue; 2747 2748 if (dt_get_buf(dtp, i, &nbuf) != 0) { 2749 dt_put_buf(dtp, buf); 2750 return (-1); 2751 } 2752 if (nbuf == NULL) 2753 continue; 2754 2755 rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE, 2756 pf, rf, arg); 2757 dt_put_buf(dtp, nbuf); 2758 if (rval != 0) { 2759 dt_put_buf(dtp, buf); 2760 return (rval); 2761 } 2762 } 2763 2764 /* 2765 * Okay -- we're done with the other buffers. Now we want to 2766 * reconsume the first buffer -- but this time we're looking for 2767 * everything _but_ BEGIN. And of course, in order to only consume 2768 * those ERRORs _not_ associated with BEGIN, we need to reinstall our 2769 * ERROR interposition function... 2770 */ 2771 begin.dtbgn_beginonly = 0; 2772 2773 assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr); 2774 assert(begin.dtbgn_errarg == dtp->dt_errarg); 2775 dtp->dt_errhdlr = dt_consume_begin_error; 2776 dtp->dt_errarg = &begin; 2777 2778 rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2779 dt_consume_begin_probe, dt_consume_begin_record, &begin); 2780 2781 dtp->dt_errhdlr = begin.dtbgn_errhdlr; 2782 dtp->dt_errarg = begin.dtbgn_errarg; 2783 2784 return (rval); 2785} 2786 2787/* ARGSUSED */ 2788static uint64_t 2789dt_buf_oldest(void *elem, void *arg) 2790{ 2791 dtrace_bufdesc_t *buf = elem; 2792 size_t offs = buf->dtbd_oldest; 2793 2794 while (offs < buf->dtbd_size) { 2795 dtrace_rechdr_t *dtrh = 2796 /* LINTED - alignment */ 2797 (dtrace_rechdr_t *)(buf->dtbd_data + offs); 2798 if (dtrh->dtrh_epid == DTRACE_EPIDNONE) { 2799 offs += sizeof (dtrace_epid_t); 2800 } else { 2801 return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh)); 2802 } 2803 } 2804 2805 /* There are no records left; use the time the buffer was retrieved. */ 2806 return (buf->dtbd_timestamp); 2807} 2808 2809int 2810dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, 2811 dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 2812{ 2813 dtrace_optval_t size; 2814 static int max_ncpus; 2815 int i, rval; 2816 dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE]; 2817 hrtime_t now = gethrtime(); 2818 2819 if (dtp->dt_lastswitch != 0) { 2820 if (now - dtp->dt_lastswitch < interval) 2821 return (0); 2822 2823 dtp->dt_lastswitch += interval; 2824 } else { 2825 dtp->dt_lastswitch = now; 2826 } 2827 2828 if (!dtp->dt_active) 2829 return (dt_set_errno(dtp, EINVAL)); 2830 2831 if (max_ncpus == 0) 2832 max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 2833 2834 if (pf == NULL) 2835 pf = (dtrace_consume_probe_f *)dt_nullprobe; 2836 2837 if (rf == NULL) 2838 rf = (dtrace_consume_rec_f *)dt_nullrec; 2839 2840 if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) { 2841 /* 2842 * The output will not be in the order it was traced. Rather, 2843 * we will consume all of the data from each CPU's buffer in 2844 * turn. We apply special handling for the records from BEGIN 2845 * and END probes so that they are consumed first and last, 2846 * respectively. 2847 * 2848 * If we have just begun, we want to first process the CPU that 2849 * executed the BEGIN probe (if any). 2850 */ 2851 if (dtp->dt_active && dtp->dt_beganon != -1 && 2852 (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0) 2853 return (rval); 2854 2855 for (i = 0; i < max_ncpus; i++) { 2856 dtrace_bufdesc_t *buf; 2857 2858 /* 2859 * If we have stopped, we want to process the CPU on 2860 * which the END probe was processed only _after_ we 2861 * have processed everything else. 2862 */ 2863 if (dtp->dt_stopped && (i == dtp->dt_endedon)) 2864 continue; 2865 2866 if (dt_get_buf(dtp, i, &buf) != 0) 2867 return (-1); 2868 if (buf == NULL) 2869 continue; 2870 2871 dtp->dt_flow = 0; 2872 dtp->dt_indent = 0; 2873 dtp->dt_prefix = NULL; 2874 rval = dt_consume_cpu(dtp, fp, i, 2875 buf, B_FALSE, pf, rf, arg); 2876 dt_put_buf(dtp, buf); 2877 if (rval != 0) 2878 return (rval); 2879 } 2880 if (dtp->dt_stopped) { 2881 dtrace_bufdesc_t *buf; 2882 2883 if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0) 2884 return (-1); 2885 if (buf == NULL) 2886 return (0); 2887 2888 rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon, 2889 buf, B_FALSE, pf, rf, arg); 2890 dt_put_buf(dtp, buf); 2891 return (rval); 2892 } 2893 } else { 2894 /* 2895 * The output will be in the order it was traced (or for 2896 * speculations, when it was committed). We retrieve a buffer 2897 * from each CPU and put it into a priority queue, which sorts 2898 * based on the first entry in the buffer. This is sufficient 2899 * because entries within a buffer are already sorted. 2900 * 2901 * We then consume records one at a time, always consuming the 2902 * oldest record, as determined by the priority queue. When 2903 * we reach the end of the time covered by these buffers, 2904 * we need to stop and retrieve more records on the next pass. 2905 * The kernel tells us the time covered by each buffer, in 2906 * dtbd_timestamp. The first buffer's timestamp tells us the 2907 * time covered by all buffers, as subsequently retrieved 2908 * buffers will cover to a more recent time. 2909 */ 2910 2911 uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t)); 2912 uint64_t first_timestamp = 0; 2913 uint_t cookie = 0; 2914 dtrace_bufdesc_t *buf; 2915 2916 bzero(drops, max_ncpus * sizeof (uint64_t)); 2917 2918 if (dtp->dt_bufq == NULL) { 2919 dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2, 2920 dt_buf_oldest, NULL); 2921 if (dtp->dt_bufq == NULL) /* ENOMEM */ 2922 return (-1); 2923 } 2924 2925 /* Retrieve data from each CPU. */ 2926 (void) dtrace_getopt(dtp, "bufsize", &size); 2927 for (i = 0; i < max_ncpus; i++) { 2928 dtrace_bufdesc_t *buf; 2929 2930 if (dt_get_buf(dtp, i, &buf) != 0) 2931 return (-1); 2932 if (buf != NULL) { 2933 if (first_timestamp == 0) 2934 first_timestamp = buf->dtbd_timestamp; 2935 assert(buf->dtbd_timestamp >= first_timestamp); 2936 2937 dt_pq_insert(dtp->dt_bufq, buf); 2938 drops[i] = buf->dtbd_drops; 2939 buf->dtbd_drops = 0; 2940 } 2941 } 2942 2943 /* Consume records. */ 2944 for (;;) { 2945 dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq); 2946 uint64_t timestamp; 2947 2948 if (buf == NULL) 2949 break; 2950 2951 timestamp = dt_buf_oldest(buf, dtp); 2952 /* XXX: assert(timestamp >= dtp->dt_last_timestamp); */ 2953 dtp->dt_last_timestamp = timestamp; 2954 2955 if (timestamp == buf->dtbd_timestamp) { 2956 /* 2957 * We've reached the end of the time covered 2958 * by this buffer. If this is the oldest 2959 * buffer, we must do another pass 2960 * to retrieve more data. 2961 */ 2962 dt_put_buf(dtp, buf); 2963 if (timestamp == first_timestamp && 2964 !dtp->dt_stopped) 2965 break; 2966 continue; 2967 } 2968 2969 if ((rval = dt_consume_cpu(dtp, fp, 2970 buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0) 2971 return (rval); 2972 dt_pq_insert(dtp->dt_bufq, buf); 2973 } 2974 2975 /* Consume drops. */ 2976 for (i = 0; i < max_ncpus; i++) { 2977 if (drops[i] != 0) { 2978 int error = dt_handle_cpudrop(dtp, i, 2979 DTRACEDROP_PRINCIPAL, drops[i]); 2980 if (error != 0) 2981 return (error); 2982 } 2983 } 2984 2985 /* 2986 * Reduce memory usage by re-allocating smaller buffers 2987 * for the "remnants". 2988 */ 2989 while (buf = dt_pq_walk(dtp->dt_bufq, &cookie)) 2990 dt_realloc_buf(dtp, buf, buf->dtbd_size); 2991 } 2992 2993 return (0); 2994} 2995