1178479Sjb/* 2178479Sjb * CDDL HEADER START 3178479Sjb * 4178479Sjb * The contents of this file are subject to the terms of the 5178479Sjb * Common Development and Distribution License (the "License"). 6178479Sjb * You may not use this file except in compliance with the License. 7178479Sjb * 8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9178479Sjb * or http://www.opensolaris.org/os/licensing. 10178479Sjb * See the License for the specific language governing permissions 11178479Sjb * and limitations under the License. 12178479Sjb * 13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each 14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15178479Sjb * If applicable, add the following below this CDDL HEADER, with the 16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying 17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 18178479Sjb * 19178479Sjb * CDDL HEADER END 20178479Sjb */ 21178479Sjb/* 22210767Srpaulo * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23178479Sjb * Use is subject to license terms. 24178479Sjb */ 25178479Sjb 26237624Spfg/* 27237624Spfg * Copyright (c) 2011, Joyent, Inc. All rights reserved. 28250574Smarkj * Copyright (c) 2012 by Delphix. All rights reserved. 29237624Spfg */ 30237624Spfg 31178479Sjb#include <stdlib.h> 32178479Sjb#include <strings.h> 33178479Sjb#include <errno.h> 34178479Sjb#include <unistd.h> 35178479Sjb#include <limits.h> 36178479Sjb#include <assert.h> 37178479Sjb#include <ctype.h> 38178576Sjb#if defined(sun) 39178479Sjb#include <alloca.h> 40178576Sjb#endif 41178479Sjb#include <dt_impl.h> 42250574Smarkj#include <dt_pq.h> 43211554Srpaulo#if !defined(sun) 44211554Srpaulo#include <libproc_compat.h> 45211554Srpaulo#endif 46178479Sjb 47178479Sjb#define DT_MASK_LO 0x00000000FFFFFFFFULL 48178479Sjb 49178479Sjb/* 50178479Sjb * We declare this here because (1) we need it and (2) we want to avoid a 51178479Sjb * dependency on libm in libdtrace. 52178479Sjb */ 53178479Sjbstatic long double 54178479Sjbdt_fabsl(long double x) 55178479Sjb{ 56178479Sjb if (x < 0) 57178479Sjb return (-x); 58178479Sjb 59178479Sjb return (x); 60178479Sjb} 61178479Sjb 62178479Sjb/* 63178479Sjb * 128-bit arithmetic functions needed to support the stddev() aggregating 64178479Sjb * action. 65178479Sjb */ 66178479Sjbstatic int 67178479Sjbdt_gt_128(uint64_t *a, uint64_t *b) 68178479Sjb{ 69178479Sjb return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0])); 70178479Sjb} 71178479Sjb 72178479Sjbstatic int 73178479Sjbdt_ge_128(uint64_t *a, uint64_t *b) 74178479Sjb{ 75178479Sjb return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0])); 76178479Sjb} 77178479Sjb 78178479Sjbstatic int 79178479Sjbdt_le_128(uint64_t *a, uint64_t *b) 80178479Sjb{ 81178479Sjb return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0])); 82178479Sjb} 83178479Sjb 84178479Sjb/* 85178479Sjb * Shift the 128-bit value in a by b. If b is positive, shift left. 86178479Sjb * If b is negative, shift right. 87178479Sjb */ 88178479Sjbstatic void 89178479Sjbdt_shift_128(uint64_t *a, int b) 90178479Sjb{ 91178479Sjb uint64_t mask; 92178479Sjb 93178479Sjb if (b == 0) 94178479Sjb return; 95178479Sjb 96178479Sjb if (b < 0) { 97178479Sjb b = -b; 98178479Sjb if (b >= 64) { 99178479Sjb a[0] = a[1] >> (b - 64); 100178479Sjb a[1] = 0; 101178479Sjb } else { 102178479Sjb a[0] >>= b; 103178479Sjb mask = 1LL << (64 - b); 104178479Sjb mask -= 1; 105178479Sjb a[0] |= ((a[1] & mask) << (64 - b)); 106178479Sjb a[1] >>= b; 107178479Sjb } 108178479Sjb } else { 109178479Sjb if (b >= 64) { 110178479Sjb a[1] = a[0] << (b - 64); 111178479Sjb a[0] = 0; 112178479Sjb } else { 113178479Sjb a[1] <<= b; 114178479Sjb mask = a[0] >> (64 - b); 115178479Sjb a[1] |= mask; 116178479Sjb a[0] <<= b; 117178479Sjb } 118178479Sjb } 119178479Sjb} 120178479Sjb 121178479Sjbstatic int 122178479Sjbdt_nbits_128(uint64_t *a) 123178479Sjb{ 124178479Sjb int nbits = 0; 125178479Sjb uint64_t tmp[2]; 126178479Sjb uint64_t zero[2] = { 0, 0 }; 127178479Sjb 128178479Sjb tmp[0] = a[0]; 129178479Sjb tmp[1] = a[1]; 130178479Sjb 131178479Sjb dt_shift_128(tmp, -1); 132178479Sjb while (dt_gt_128(tmp, zero)) { 133178479Sjb dt_shift_128(tmp, -1); 134178479Sjb nbits++; 135178479Sjb } 136178479Sjb 137178479Sjb return (nbits); 138178479Sjb} 139178479Sjb 140178479Sjbstatic void 141178479Sjbdt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference) 142178479Sjb{ 143178479Sjb uint64_t result[2]; 144178479Sjb 145178479Sjb result[0] = minuend[0] - subtrahend[0]; 146178479Sjb result[1] = minuend[1] - subtrahend[1] - 147178479Sjb (minuend[0] < subtrahend[0] ? 1 : 0); 148178479Sjb 149178479Sjb difference[0] = result[0]; 150178479Sjb difference[1] = result[1]; 151178479Sjb} 152178479Sjb 153178479Sjbstatic void 154178479Sjbdt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) 155178479Sjb{ 156178479Sjb uint64_t result[2]; 157178479Sjb 158178479Sjb result[0] = addend1[0] + addend2[0]; 159178479Sjb result[1] = addend1[1] + addend2[1] + 160178479Sjb (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); 161178479Sjb 162178479Sjb sum[0] = result[0]; 163178479Sjb sum[1] = result[1]; 164178479Sjb} 165178479Sjb 166178479Sjb/* 167178479Sjb * The basic idea is to break the 2 64-bit values into 4 32-bit values, 168178479Sjb * use native multiplication on those, and then re-combine into the 169178479Sjb * resulting 128-bit value. 170178479Sjb * 171178479Sjb * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) = 172178479Sjb * hi1 * hi2 << 64 + 173178479Sjb * hi1 * lo2 << 32 + 174178479Sjb * hi2 * lo1 << 32 + 175178479Sjb * lo1 * lo2 176178479Sjb */ 177178479Sjbstatic void 178178479Sjbdt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product) 179178479Sjb{ 180178479Sjb uint64_t hi1, hi2, lo1, lo2; 181178479Sjb uint64_t tmp[2]; 182178479Sjb 183178479Sjb hi1 = factor1 >> 32; 184178479Sjb hi2 = factor2 >> 32; 185178479Sjb 186178479Sjb lo1 = factor1 & DT_MASK_LO; 187178479Sjb lo2 = factor2 & DT_MASK_LO; 188178479Sjb 189178479Sjb product[0] = lo1 * lo2; 190178479Sjb product[1] = hi1 * hi2; 191178479Sjb 192178479Sjb tmp[0] = hi1 * lo2; 193178479Sjb tmp[1] = 0; 194178479Sjb dt_shift_128(tmp, 32); 195178479Sjb dt_add_128(product, tmp, product); 196178479Sjb 197178479Sjb tmp[0] = hi2 * lo1; 198178479Sjb tmp[1] = 0; 199178479Sjb dt_shift_128(tmp, 32); 200178479Sjb dt_add_128(product, tmp, product); 201178479Sjb} 202178479Sjb 203178479Sjb/* 204178479Sjb * This is long-hand division. 205178479Sjb * 206178479Sjb * We initialize subtrahend by shifting divisor left as far as possible. We 207178479Sjb * loop, comparing subtrahend to dividend: if subtrahend is smaller, we 208178479Sjb * subtract and set the appropriate bit in the result. We then shift 209178479Sjb * subtrahend right by one bit for the next comparison. 210178479Sjb */ 211178479Sjbstatic void 212178479Sjbdt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient) 213178479Sjb{ 214178479Sjb uint64_t result[2] = { 0, 0 }; 215178479Sjb uint64_t remainder[2]; 216178479Sjb uint64_t subtrahend[2]; 217178479Sjb uint64_t divisor_128[2]; 218178479Sjb uint64_t mask[2] = { 1, 0 }; 219178479Sjb int log = 0; 220178479Sjb 221178479Sjb assert(divisor != 0); 222178479Sjb 223178479Sjb divisor_128[0] = divisor; 224178479Sjb divisor_128[1] = 0; 225178479Sjb 226178479Sjb remainder[0] = dividend[0]; 227178479Sjb remainder[1] = dividend[1]; 228178479Sjb 229178479Sjb subtrahend[0] = divisor; 230178479Sjb subtrahend[1] = 0; 231178479Sjb 232178479Sjb while (divisor > 0) { 233178479Sjb log++; 234178479Sjb divisor >>= 1; 235178479Sjb } 236178479Sjb 237178479Sjb dt_shift_128(subtrahend, 128 - log); 238178479Sjb dt_shift_128(mask, 128 - log); 239178479Sjb 240178479Sjb while (dt_ge_128(remainder, divisor_128)) { 241178479Sjb if (dt_ge_128(remainder, subtrahend)) { 242178479Sjb dt_subtract_128(remainder, subtrahend, remainder); 243178479Sjb result[0] |= mask[0]; 244178479Sjb result[1] |= mask[1]; 245178479Sjb } 246178479Sjb 247178479Sjb dt_shift_128(subtrahend, -1); 248178479Sjb dt_shift_128(mask, -1); 249178479Sjb } 250178479Sjb 251178479Sjb quotient[0] = result[0]; 252178479Sjb quotient[1] = result[1]; 253178479Sjb} 254178479Sjb 255178479Sjb/* 256178479Sjb * This is the long-hand method of calculating a square root. 257178479Sjb * The algorithm is as follows: 258178479Sjb * 259178479Sjb * 1. Group the digits by 2 from the right. 260178479Sjb * 2. Over the leftmost group, find the largest single-digit number 261178479Sjb * whose square is less than that group. 262178479Sjb * 3. Subtract the result of the previous step (2 or 4, depending) and 263178479Sjb * bring down the next two-digit group. 264178479Sjb * 4. For the result R we have so far, find the largest single-digit number 265178479Sjb * x such that 2 * R * 10 * x + x^2 is less than the result from step 3. 266178479Sjb * (Note that this is doubling R and performing a decimal left-shift by 1 267178479Sjb * and searching for the appropriate decimal to fill the one's place.) 268178479Sjb * The value x is the next digit in the square root. 269178479Sjb * Repeat steps 3 and 4 until the desired precision is reached. (We're 270178479Sjb * dealing with integers, so the above is sufficient.) 271178479Sjb * 272178479Sjb * In decimal, the square root of 582,734 would be calculated as so: 273178479Sjb * 274178479Sjb * __7__6__3 275178479Sjb * | 58 27 34 276178479Sjb * -49 (7^2 == 49 => 7 is the first digit in the square root) 277178479Sjb * -- 278178479Sjb * 9 27 (Subtract and bring down the next group.) 279178479Sjb * 146 8 76 (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in 280178479Sjb * ----- the square root) 281178479Sjb * 51 34 (Subtract and bring down the next group.) 282178479Sjb * 1523 45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in 283178479Sjb * ----- the square root) 284178479Sjb * 5 65 (remainder) 285178479Sjb * 286178479Sjb * The above algorithm applies similarly in binary, but note that the 287178479Sjb * only possible non-zero value for x in step 4 is 1, so step 4 becomes a 288178479Sjb * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the 289178479Sjb * preceding difference? 290178479Sjb * 291178479Sjb * In binary, the square root of 11011011 would be calculated as so: 292178479Sjb * 293178479Sjb * __1__1__1__0 294178479Sjb * | 11 01 10 11 295178479Sjb * 01 (0 << 2 + 1 == 1 < 11 => this bit is 1) 296178479Sjb * -- 297178479Sjb * 10 01 10 11 298178479Sjb * 101 1 01 (1 << 2 + 1 == 101 < 1001 => next bit is 1) 299178479Sjb * ----- 300178479Sjb * 1 00 10 11 301178479Sjb * 1101 11 01 (11 << 2 + 1 == 1101 < 10010 => next bit is 1) 302178479Sjb * ------- 303178479Sjb * 1 01 11 304178479Sjb * 11101 1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0) 305178479Sjb * 306178479Sjb */ 307178479Sjbstatic uint64_t 308178479Sjbdt_sqrt_128(uint64_t *square) 309178479Sjb{ 310178479Sjb uint64_t result[2] = { 0, 0 }; 311178479Sjb uint64_t diff[2] = { 0, 0 }; 312178479Sjb uint64_t one[2] = { 1, 0 }; 313178479Sjb uint64_t next_pair[2]; 314178479Sjb uint64_t next_try[2]; 315178479Sjb uint64_t bit_pairs, pair_shift; 316178479Sjb int i; 317178479Sjb 318178479Sjb bit_pairs = dt_nbits_128(square) / 2; 319178479Sjb pair_shift = bit_pairs * 2; 320178479Sjb 321178479Sjb for (i = 0; i <= bit_pairs; i++) { 322178479Sjb /* 323178479Sjb * Bring down the next pair of bits. 324178479Sjb */ 325178479Sjb next_pair[0] = square[0]; 326178479Sjb next_pair[1] = square[1]; 327178479Sjb dt_shift_128(next_pair, -pair_shift); 328178479Sjb next_pair[0] &= 0x3; 329178479Sjb next_pair[1] = 0; 330178479Sjb 331178479Sjb dt_shift_128(diff, 2); 332178479Sjb dt_add_128(diff, next_pair, diff); 333178479Sjb 334178479Sjb /* 335178479Sjb * next_try = R << 2 + 1 336178479Sjb */ 337178479Sjb next_try[0] = result[0]; 338178479Sjb next_try[1] = result[1]; 339178479Sjb dt_shift_128(next_try, 2); 340178479Sjb dt_add_128(next_try, one, next_try); 341178479Sjb 342178479Sjb if (dt_le_128(next_try, diff)) { 343178479Sjb dt_subtract_128(diff, next_try, diff); 344178479Sjb dt_shift_128(result, 1); 345178479Sjb dt_add_128(result, one, result); 346178479Sjb } else { 347178479Sjb dt_shift_128(result, 1); 348178479Sjb } 349178479Sjb 350178479Sjb pair_shift -= 2; 351178479Sjb } 352178479Sjb 353178479Sjb assert(result[1] == 0); 354178479Sjb 355178479Sjb return (result[0]); 356178479Sjb} 357178479Sjb 358178479Sjbuint64_t 359178479Sjbdt_stddev(uint64_t *data, uint64_t normal) 360178479Sjb{ 361178479Sjb uint64_t avg_of_squares[2]; 362178479Sjb uint64_t square_of_avg[2]; 363178479Sjb int64_t norm_avg; 364178479Sjb uint64_t diff[2]; 365178479Sjb 366178479Sjb /* 367178479Sjb * The standard approximation for standard deviation is 368178479Sjb * sqrt(average(x**2) - average(x)**2), i.e. the square root 369178479Sjb * of the average of the squares minus the square of the average. 370178479Sjb */ 371178479Sjb dt_divide_128(data + 2, normal, avg_of_squares); 372178479Sjb dt_divide_128(avg_of_squares, data[0], avg_of_squares); 373178479Sjb 374178479Sjb norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0]; 375178479Sjb 376178479Sjb if (norm_avg < 0) 377178479Sjb norm_avg = -norm_avg; 378178479Sjb 379178479Sjb dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg); 380178479Sjb 381178479Sjb dt_subtract_128(avg_of_squares, square_of_avg, diff); 382178479Sjb 383178479Sjb return (dt_sqrt_128(diff)); 384178479Sjb} 385178479Sjb 386178479Sjbstatic int 387178479Sjbdt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, 388178479Sjb dtrace_bufdesc_t *buf, size_t offs) 389178479Sjb{ 390178479Sjb dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; 391178479Sjb dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; 392178479Sjb char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub; 393178479Sjb dtrace_flowkind_t flow = DTRACEFLOW_NONE; 394178479Sjb const char *str = NULL; 395178479Sjb static const char *e_str[2] = { " -> ", " => " }; 396178479Sjb static const char *r_str[2] = { " <- ", " <= " }; 397178479Sjb static const char *ent = "entry", *ret = "return"; 398178479Sjb static int entlen = 0, retlen = 0; 399178479Sjb dtrace_epid_t next, id = epd->dtepd_epid; 400178479Sjb int rval; 401178479Sjb 402178479Sjb if (entlen == 0) { 403178479Sjb assert(retlen == 0); 404178479Sjb entlen = strlen(ent); 405178479Sjb retlen = strlen(ret); 406178479Sjb } 407178479Sjb 408178479Sjb /* 409178479Sjb * If the name of the probe is "entry" or ends with "-entry", we 410178479Sjb * treat it as an entry; if it is "return" or ends with "-return", 411178479Sjb * we treat it as a return. (This allows application-provided probes 412178479Sjb * like "method-entry" or "function-entry" to participate in flow 413178479Sjb * indentation -- without accidentally misinterpreting popular probe 414178479Sjb * names like "carpentry", "gentry" or "Coventry".) 415178479Sjb */ 416178479Sjb if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' && 417178479Sjb (sub == n || sub[-1] == '-')) { 418178479Sjb flow = DTRACEFLOW_ENTRY; 419178479Sjb str = e_str[strcmp(p, "syscall") == 0]; 420178479Sjb } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' && 421178479Sjb (sub == n || sub[-1] == '-')) { 422178479Sjb flow = DTRACEFLOW_RETURN; 423178479Sjb str = r_str[strcmp(p, "syscall") == 0]; 424178479Sjb } 425178479Sjb 426178479Sjb /* 427178479Sjb * If we're going to indent this, we need to check the ID of our last 428178479Sjb * call. If we're looking at the same probe ID but a different EPID, 429178479Sjb * we _don't_ want to indent. (Yes, there are some minor holes in 430178479Sjb * this scheme -- it's a heuristic.) 431178479Sjb */ 432178479Sjb if (flow == DTRACEFLOW_ENTRY) { 433178479Sjb if ((last != DTRACE_EPIDNONE && id != last && 434178479Sjb pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) 435178479Sjb flow = DTRACEFLOW_NONE; 436178479Sjb } 437178479Sjb 438178479Sjb /* 439178479Sjb * If we're going to unindent this, it's more difficult to see if 440178479Sjb * we don't actually want to unindent it -- we need to look at the 441178479Sjb * _next_ EPID. 442178479Sjb */ 443178479Sjb if (flow == DTRACEFLOW_RETURN) { 444178479Sjb offs += epd->dtepd_size; 445178479Sjb 446178479Sjb do { 447250574Smarkj if (offs >= buf->dtbd_size) 448250574Smarkj goto out; 449178479Sjb 450178479Sjb next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 451178479Sjb 452178479Sjb if (next == DTRACE_EPIDNONE) 453178479Sjb offs += sizeof (id); 454178479Sjb } while (next == DTRACE_EPIDNONE); 455178479Sjb 456178479Sjb if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) 457178479Sjb return (rval); 458178479Sjb 459178479Sjb if (next != id && npd->dtpd_id == pd->dtpd_id) 460178479Sjb flow = DTRACEFLOW_NONE; 461178479Sjb } 462178479Sjb 463178479Sjbout: 464178479Sjb if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { 465178479Sjb data->dtpda_prefix = str; 466178479Sjb } else { 467178479Sjb data->dtpda_prefix = "| "; 468178479Sjb } 469178479Sjb 470178479Sjb if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) 471178479Sjb data->dtpda_indent -= 2; 472178479Sjb 473178479Sjb data->dtpda_flow = flow; 474178479Sjb 475178479Sjb return (0); 476178479Sjb} 477178479Sjb 478178479Sjbstatic int 479178479Sjbdt_nullprobe() 480178479Sjb{ 481178479Sjb return (DTRACE_CONSUME_THIS); 482178479Sjb} 483178479Sjb 484178479Sjbstatic int 485178479Sjbdt_nullrec() 486178479Sjb{ 487178479Sjb return (DTRACE_CONSUME_NEXT); 488178479Sjb} 489178479Sjb 490178479Sjbint 491178479Sjbdt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 492178479Sjb uint64_t normal, long double total, char positives, char negatives) 493178479Sjb{ 494178479Sjb long double f; 495178479Sjb uint_t depth, len = 40; 496178479Sjb 497178479Sjb const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; 498178479Sjb const char *spaces = " "; 499178479Sjb 500178479Sjb assert(strlen(ats) == len && strlen(spaces) == len); 501178479Sjb assert(!(total == 0 && (positives || negatives))); 502178479Sjb assert(!(val < 0 && !negatives)); 503178479Sjb assert(!(val > 0 && !positives)); 504178479Sjb assert(!(val != 0 && total == 0)); 505178479Sjb 506178479Sjb if (!negatives) { 507178479Sjb if (positives) { 508178479Sjb f = (dt_fabsl((long double)val) * len) / total; 509178479Sjb depth = (uint_t)(f + 0.5); 510178479Sjb } else { 511178479Sjb depth = 0; 512178479Sjb } 513178479Sjb 514178479Sjb return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth, 515178479Sjb spaces + depth, (long long)val / normal)); 516178479Sjb } 517178479Sjb 518178479Sjb if (!positives) { 519178479Sjb f = (dt_fabsl((long double)val) * len) / total; 520178479Sjb depth = (uint_t)(f + 0.5); 521178479Sjb 522178479Sjb return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth, 523178479Sjb ats + len - depth, (long long)val / normal)); 524178479Sjb } 525178479Sjb 526178479Sjb /* 527178479Sjb * If we're here, we have both positive and negative bucket values. 528178479Sjb * To express this graphically, we're going to generate both positive 529178479Sjb * and negative bars separated by a centerline. These bars are half 530178479Sjb * the size of normal quantize()/lquantize() bars, so we divide the 531178479Sjb * length in half before calculating the bar length. 532178479Sjb */ 533178479Sjb len /= 2; 534178479Sjb ats = &ats[len]; 535178479Sjb spaces = &spaces[len]; 536178479Sjb 537178479Sjb f = (dt_fabsl((long double)val) * len) / total; 538178479Sjb depth = (uint_t)(f + 0.5); 539178479Sjb 540178479Sjb if (val <= 0) { 541178479Sjb return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth, 542178479Sjb ats + len - depth, len, "", (long long)val / normal)); 543178479Sjb } else { 544178479Sjb return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "", 545178479Sjb ats + len - depth, spaces + depth, 546178479Sjb (long long)val / normal)); 547178479Sjb } 548178479Sjb} 549178479Sjb 550178479Sjbint 551178479Sjbdt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 552178479Sjb size_t size, uint64_t normal) 553178479Sjb{ 554178479Sjb const int64_t *data = addr; 555178479Sjb int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; 556178479Sjb long double total = 0; 557178479Sjb char positives = 0, negatives = 0; 558178479Sjb 559178479Sjb if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 560178479Sjb return (dt_set_errno(dtp, EDT_DMISMATCH)); 561178479Sjb 562178479Sjb while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) 563178479Sjb first_bin++; 564178479Sjb 565178479Sjb if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) { 566178479Sjb /* 567178479Sjb * There isn't any data. This is possible if (and only if) 568178479Sjb * negative increment values have been used. In this case, 569178479Sjb * we'll print the buckets around 0. 570178479Sjb */ 571178479Sjb first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1; 572178479Sjb last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1; 573178479Sjb } else { 574178479Sjb if (first_bin > 0) 575178479Sjb first_bin--; 576178479Sjb 577178479Sjb while (last_bin > 0 && data[last_bin] == 0) 578178479Sjb last_bin--; 579178479Sjb 580178479Sjb if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) 581178479Sjb last_bin++; 582178479Sjb } 583178479Sjb 584178479Sjb for (i = first_bin; i <= last_bin; i++) { 585178479Sjb positives |= (data[i] > 0); 586178479Sjb negatives |= (data[i] < 0); 587178479Sjb total += dt_fabsl((long double)data[i]); 588178479Sjb } 589178479Sjb 590178479Sjb if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 591178479Sjb "------------- Distribution -------------", "count") < 0) 592178479Sjb return (-1); 593178479Sjb 594178479Sjb for (i = first_bin; i <= last_bin; i++) { 595178479Sjb if (dt_printf(dtp, fp, "%16lld ", 596178479Sjb (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0) 597178479Sjb return (-1); 598178479Sjb 599178479Sjb if (dt_print_quantline(dtp, fp, data[i], normal, total, 600178479Sjb positives, negatives) < 0) 601178479Sjb return (-1); 602178479Sjb } 603178479Sjb 604178479Sjb return (0); 605178479Sjb} 606178479Sjb 607178479Sjbint 608178479Sjbdt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 609178479Sjb size_t size, uint64_t normal) 610178479Sjb{ 611178479Sjb const int64_t *data = addr; 612178479Sjb int i, first_bin, last_bin, base; 613178479Sjb uint64_t arg; 614178479Sjb long double total = 0; 615178479Sjb uint16_t step, levels; 616178479Sjb char positives = 0, negatives = 0; 617178479Sjb 618178479Sjb if (size < sizeof (uint64_t)) 619178479Sjb return (dt_set_errno(dtp, EDT_DMISMATCH)); 620178479Sjb 621178479Sjb arg = *data++; 622178479Sjb size -= sizeof (uint64_t); 623178479Sjb 624178479Sjb base = DTRACE_LQUANTIZE_BASE(arg); 625178479Sjb step = DTRACE_LQUANTIZE_STEP(arg); 626178479Sjb levels = DTRACE_LQUANTIZE_LEVELS(arg); 627178479Sjb 628178479Sjb first_bin = 0; 629178479Sjb last_bin = levels + 1; 630178479Sjb 631178479Sjb if (size != sizeof (uint64_t) * (levels + 2)) 632178479Sjb return (dt_set_errno(dtp, EDT_DMISMATCH)); 633178479Sjb 634178479Sjb while (first_bin <= levels + 1 && data[first_bin] == 0) 635178479Sjb first_bin++; 636178479Sjb 637178479Sjb if (first_bin > levels + 1) { 638178479Sjb first_bin = 0; 639178479Sjb last_bin = 2; 640178479Sjb } else { 641178479Sjb if (first_bin > 0) 642178479Sjb first_bin--; 643178479Sjb 644178479Sjb while (last_bin > 0 && data[last_bin] == 0) 645178479Sjb last_bin--; 646178479Sjb 647178479Sjb if (last_bin < levels + 1) 648178479Sjb last_bin++; 649178479Sjb } 650178479Sjb 651178479Sjb for (i = first_bin; i <= last_bin; i++) { 652178479Sjb positives |= (data[i] > 0); 653178479Sjb negatives |= (data[i] < 0); 654178479Sjb total += dt_fabsl((long double)data[i]); 655178479Sjb } 656178479Sjb 657178479Sjb if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 658178479Sjb "------------- Distribution -------------", "count") < 0) 659178479Sjb return (-1); 660178479Sjb 661178479Sjb for (i = first_bin; i <= last_bin; i++) { 662178479Sjb char c[32]; 663178479Sjb int err; 664178479Sjb 665178479Sjb if (i == 0) { 666178479Sjb (void) snprintf(c, sizeof (c), "< %d", 667178479Sjb base / (uint32_t)normal); 668178479Sjb err = dt_printf(dtp, fp, "%16s ", c); 669178479Sjb } else if (i == levels + 1) { 670178479Sjb (void) snprintf(c, sizeof (c), ">= %d", 671178479Sjb base + (levels * step)); 672178479Sjb err = dt_printf(dtp, fp, "%16s ", c); 673178479Sjb } else { 674178479Sjb err = dt_printf(dtp, fp, "%16d ", 675178479Sjb base + (i - 1) * step); 676178479Sjb } 677178479Sjb 678178479Sjb if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal, 679178479Sjb total, positives, negatives) < 0) 680178479Sjb return (-1); 681178479Sjb } 682178479Sjb 683178479Sjb return (0); 684178479Sjb} 685178479Sjb 686237624Spfgint 687237624Spfgdt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 688237624Spfg size_t size, uint64_t normal) 689237624Spfg{ 690237624Spfg int i, first_bin, last_bin, bin = 1, order, levels; 691237624Spfg uint16_t factor, low, high, nsteps; 692237624Spfg const int64_t *data = addr; 693237624Spfg int64_t value = 1, next, step; 694237624Spfg char positives = 0, negatives = 0; 695237624Spfg long double total = 0; 696237624Spfg uint64_t arg; 697237624Spfg char c[32]; 698237624Spfg 699237624Spfg if (size < sizeof (uint64_t)) 700237624Spfg return (dt_set_errno(dtp, EDT_DMISMATCH)); 701237624Spfg 702237624Spfg arg = *data++; 703237624Spfg size -= sizeof (uint64_t); 704237624Spfg 705237624Spfg factor = DTRACE_LLQUANTIZE_FACTOR(arg); 706237624Spfg low = DTRACE_LLQUANTIZE_LOW(arg); 707237624Spfg high = DTRACE_LLQUANTIZE_HIGH(arg); 708237624Spfg nsteps = DTRACE_LLQUANTIZE_NSTEP(arg); 709237624Spfg 710237624Spfg /* 711237624Spfg * We don't expect to be handed invalid llquantize() parameters here, 712237624Spfg * but sanity check them (to a degree) nonetheless. 713237624Spfg */ 714237624Spfg if (size > INT32_MAX || factor < 2 || low >= high || 715237624Spfg nsteps == 0 || factor > nsteps) 716237624Spfg return (dt_set_errno(dtp, EDT_DMISMATCH)); 717237624Spfg 718237624Spfg levels = (int)size / sizeof (uint64_t); 719237624Spfg 720237624Spfg first_bin = 0; 721237624Spfg last_bin = levels - 1; 722237624Spfg 723237624Spfg while (first_bin < levels && data[first_bin] == 0) 724237624Spfg first_bin++; 725237624Spfg 726237624Spfg if (first_bin == levels) { 727237624Spfg first_bin = 0; 728237624Spfg last_bin = 1; 729237624Spfg } else { 730237624Spfg if (first_bin > 0) 731237624Spfg first_bin--; 732237624Spfg 733237624Spfg while (last_bin > 0 && data[last_bin] == 0) 734237624Spfg last_bin--; 735237624Spfg 736237624Spfg if (last_bin < levels - 1) 737237624Spfg last_bin++; 738237624Spfg } 739237624Spfg 740237624Spfg for (i = first_bin; i <= last_bin; i++) { 741237624Spfg positives |= (data[i] > 0); 742237624Spfg negatives |= (data[i] < 0); 743237624Spfg total += dt_fabsl((long double)data[i]); 744237624Spfg } 745237624Spfg 746237624Spfg if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 747237624Spfg "------------- Distribution -------------", "count") < 0) 748237624Spfg return (-1); 749237624Spfg 750237624Spfg for (order = 0; order < low; order++) 751237624Spfg value *= factor; 752237624Spfg 753237624Spfg next = value * factor; 754237624Spfg step = next > nsteps ? next / nsteps : 1; 755237624Spfg 756237624Spfg if (first_bin == 0) { 757237716Spfg (void) snprintf(c, sizeof (c), "< %lld", (long long)value); 758237624Spfg 759237624Spfg if (dt_printf(dtp, fp, "%16s ", c) < 0) 760237624Spfg return (-1); 761237624Spfg 762237624Spfg if (dt_print_quantline(dtp, fp, data[0], normal, 763237624Spfg total, positives, negatives) < 0) 764237624Spfg return (-1); 765237624Spfg } 766237624Spfg 767237624Spfg while (order <= high) { 768237624Spfg if (bin >= first_bin && bin <= last_bin) { 769237624Spfg if (dt_printf(dtp, fp, "%16lld ", (long long)value) < 0) 770237624Spfg return (-1); 771237624Spfg 772237624Spfg if (dt_print_quantline(dtp, fp, data[bin], 773237624Spfg normal, total, positives, negatives) < 0) 774237624Spfg return (-1); 775237624Spfg } 776237624Spfg 777237624Spfg assert(value < next); 778237624Spfg bin++; 779237624Spfg 780237624Spfg if ((value += step) != next) 781237624Spfg continue; 782237624Spfg 783237624Spfg next = value * factor; 784237624Spfg step = next > nsteps ? next / nsteps : 1; 785237624Spfg order++; 786237624Spfg } 787237624Spfg 788237624Spfg if (last_bin < bin) 789237624Spfg return (0); 790237624Spfg 791237624Spfg assert(last_bin == bin); 792238071Sdim (void) snprintf(c, sizeof (c), ">= %lld", (long long)value); 793237624Spfg 794237624Spfg if (dt_printf(dtp, fp, "%16s ", c) < 0) 795237624Spfg return (-1); 796237624Spfg 797237624Spfg return (dt_print_quantline(dtp, fp, data[bin], normal, 798237624Spfg total, positives, negatives)); 799237624Spfg} 800237624Spfg 801178479Sjb/*ARGSUSED*/ 802178479Sjbstatic int 803178479Sjbdt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 804178479Sjb size_t size, uint64_t normal) 805178479Sjb{ 806178479Sjb /* LINTED - alignment */ 807178479Sjb int64_t *data = (int64_t *)addr; 808178479Sjb 809178479Sjb return (dt_printf(dtp, fp, " %16lld", data[0] ? 810178479Sjb (long long)(data[1] / (int64_t)normal / data[0]) : 0)); 811178479Sjb} 812178479Sjb 813178479Sjb/*ARGSUSED*/ 814178479Sjbstatic int 815178479Sjbdt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 816178479Sjb size_t size, uint64_t normal) 817178479Sjb{ 818178479Sjb /* LINTED - alignment */ 819178479Sjb uint64_t *data = (uint64_t *)addr; 820178479Sjb 821178479Sjb return (dt_printf(dtp, fp, " %16llu", data[0] ? 822178479Sjb (unsigned long long) dt_stddev(data, normal) : 0)); 823178479Sjb} 824178479Sjb 825178479Sjb/*ARGSUSED*/ 826178479Sjbint 827178479Sjbdt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 828248690Spfg size_t nbytes, int width, int quiet, int forceraw) 829178479Sjb{ 830178479Sjb /* 831178479Sjb * If the byte stream is a series of printable characters, followed by 832178479Sjb * a terminating byte, we print it out as a string. Otherwise, we 833178479Sjb * assume that it's something else and just print the bytes. 834178479Sjb */ 835178479Sjb int i, j, margin = 5; 836178479Sjb char *c = (char *)addr; 837178479Sjb 838178479Sjb if (nbytes == 0) 839178479Sjb return (0); 840178479Sjb 841248690Spfg if (forceraw) 842178479Sjb goto raw; 843178479Sjb 844248690Spfg if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) 845248690Spfg goto raw; 846248690Spfg 847178479Sjb for (i = 0; i < nbytes; i++) { 848178479Sjb /* 849178479Sjb * We define a "printable character" to be one for which 850178479Sjb * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 851178479Sjb * or a character which is either backspace or the bell. 852178479Sjb * Backspace and the bell are regrettably special because 853178479Sjb * they fail the first two tests -- and yet they are entirely 854178479Sjb * printable. These are the only two control characters that 855178479Sjb * have meaning for the terminal and for which isprint(3C) and 856178479Sjb * isspace(3C) return 0. 857178479Sjb */ 858178479Sjb if (isprint(c[i]) || isspace(c[i]) || 859178479Sjb c[i] == '\b' || c[i] == '\a') 860178479Sjb continue; 861178479Sjb 862178479Sjb if (c[i] == '\0' && i > 0) { 863178479Sjb /* 864178479Sjb * This looks like it might be a string. Before we 865178479Sjb * assume that it is indeed a string, check the 866178479Sjb * remainder of the byte range; if it contains 867178479Sjb * additional non-nul characters, we'll assume that 868178479Sjb * it's a binary stream that just happens to look like 869178479Sjb * a string, and we'll print out the individual bytes. 870178479Sjb */ 871178479Sjb for (j = i + 1; j < nbytes; j++) { 872178479Sjb if (c[j] != '\0') 873178479Sjb break; 874178479Sjb } 875178479Sjb 876178479Sjb if (j != nbytes) 877178479Sjb break; 878178479Sjb 879178479Sjb if (quiet) 880178479Sjb return (dt_printf(dtp, fp, "%s", c)); 881178479Sjb else 882178479Sjb return (dt_printf(dtp, fp, " %-*s", width, c)); 883178479Sjb } 884178479Sjb 885178479Sjb break; 886178479Sjb } 887178479Sjb 888178479Sjb if (i == nbytes) { 889178479Sjb /* 890178479Sjb * The byte range is all printable characters, but there is 891178479Sjb * no trailing nul byte. We'll assume that it's a string and 892178479Sjb * print it as such. 893178479Sjb */ 894178479Sjb char *s = alloca(nbytes + 1); 895178479Sjb bcopy(c, s, nbytes); 896178479Sjb s[nbytes] = '\0'; 897178479Sjb return (dt_printf(dtp, fp, " %-*s", width, s)); 898178479Sjb } 899178479Sjb 900178479Sjbraw: 901178479Sjb if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) 902178479Sjb return (-1); 903178479Sjb 904178479Sjb for (i = 0; i < 16; i++) 905178479Sjb if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) 906178479Sjb return (-1); 907178479Sjb 908178479Sjb if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) 909178479Sjb return (-1); 910178479Sjb 911178479Sjb 912178479Sjb for (i = 0; i < nbytes; i += 16) { 913178479Sjb if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) 914178479Sjb return (-1); 915178479Sjb 916178479Sjb for (j = i; j < i + 16 && j < nbytes; j++) { 917178479Sjb if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) 918178479Sjb return (-1); 919178479Sjb } 920178479Sjb 921178479Sjb while (j++ % 16) { 922178479Sjb if (dt_printf(dtp, fp, " ") < 0) 923178479Sjb return (-1); 924178479Sjb } 925178479Sjb 926178479Sjb if (dt_printf(dtp, fp, " ") < 0) 927178479Sjb return (-1); 928178479Sjb 929178479Sjb for (j = i; j < i + 16 && j < nbytes; j++) { 930178479Sjb if (dt_printf(dtp, fp, "%c", 931178479Sjb c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) 932178479Sjb return (-1); 933178479Sjb } 934178479Sjb 935178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 936178479Sjb return (-1); 937178479Sjb } 938178479Sjb 939178479Sjb return (0); 940178479Sjb} 941178479Sjb 942178479Sjbint 943178479Sjbdt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 944178479Sjb caddr_t addr, int depth, int size) 945178479Sjb{ 946178479Sjb dtrace_syminfo_t dts; 947178479Sjb GElf_Sym sym; 948178479Sjb int i, indent; 949178479Sjb char c[PATH_MAX * 2]; 950178479Sjb uint64_t pc; 951178479Sjb 952178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 953178479Sjb return (-1); 954178479Sjb 955178479Sjb if (format == NULL) 956178479Sjb format = "%s"; 957178479Sjb 958178479Sjb if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 959178479Sjb indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 960178479Sjb else 961178479Sjb indent = _dtrace_stkindent; 962178479Sjb 963178479Sjb for (i = 0; i < depth; i++) { 964178479Sjb switch (size) { 965178479Sjb case sizeof (uint32_t): 966178479Sjb /* LINTED - alignment */ 967178479Sjb pc = *((uint32_t *)addr); 968178479Sjb break; 969178479Sjb 970178479Sjb case sizeof (uint64_t): 971178479Sjb /* LINTED - alignment */ 972178479Sjb pc = *((uint64_t *)addr); 973178479Sjb break; 974178479Sjb 975178479Sjb default: 976178479Sjb return (dt_set_errno(dtp, EDT_BADSTACKPC)); 977178479Sjb } 978178479Sjb 979178576Sjb if (pc == 0) 980178479Sjb break; 981178479Sjb 982178479Sjb addr += size; 983178479Sjb 984178479Sjb if (dt_printf(dtp, fp, "%*s", indent, "") < 0) 985178479Sjb return (-1); 986178479Sjb 987178479Sjb if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 988178479Sjb if (pc > sym.st_value) { 989178479Sjb (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", 990178479Sjb dts.dts_object, dts.dts_name, 991228579Sdim (u_longlong_t)(pc - sym.st_value)); 992178479Sjb } else { 993178479Sjb (void) snprintf(c, sizeof (c), "%s`%s", 994178479Sjb dts.dts_object, dts.dts_name); 995178479Sjb } 996178479Sjb } else { 997178479Sjb /* 998178479Sjb * We'll repeat the lookup, but this time we'll specify 999178479Sjb * a NULL GElf_Sym -- indicating that we're only 1000178479Sjb * interested in the containing module. 1001178479Sjb */ 1002178479Sjb if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1003178479Sjb (void) snprintf(c, sizeof (c), "%s`0x%llx", 1004228579Sdim dts.dts_object, (u_longlong_t)pc); 1005178479Sjb } else { 1006228579Sdim (void) snprintf(c, sizeof (c), "0x%llx", 1007228579Sdim (u_longlong_t)pc); 1008178479Sjb } 1009178479Sjb } 1010178479Sjb 1011178479Sjb if (dt_printf(dtp, fp, format, c) < 0) 1012178479Sjb return (-1); 1013178479Sjb 1014178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 1015178479Sjb return (-1); 1016178479Sjb } 1017178479Sjb 1018178479Sjb return (0); 1019178479Sjb} 1020178479Sjb 1021178479Sjbint 1022178479Sjbdt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1023178479Sjb caddr_t addr, uint64_t arg) 1024178479Sjb{ 1025178479Sjb /* LINTED - alignment */ 1026178479Sjb uint64_t *pc = (uint64_t *)addr; 1027178479Sjb uint32_t depth = DTRACE_USTACK_NFRAMES(arg); 1028178479Sjb uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); 1029178479Sjb const char *strbase = addr + (depth + 1) * sizeof (uint64_t); 1030178479Sjb const char *str = strsize ? strbase : NULL; 1031178479Sjb int err = 0; 1032178479Sjb 1033178479Sjb char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 1034178479Sjb struct ps_prochandle *P; 1035178479Sjb GElf_Sym sym; 1036178479Sjb int i, indent; 1037178479Sjb pid_t pid; 1038178479Sjb 1039178479Sjb if (depth == 0) 1040178479Sjb return (0); 1041178479Sjb 1042178479Sjb pid = (pid_t)*pc++; 1043178479Sjb 1044178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 1045178479Sjb return (-1); 1046178479Sjb 1047178479Sjb if (format == NULL) 1048178479Sjb format = "%s"; 1049178479Sjb 1050178479Sjb if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 1051178479Sjb indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 1052178479Sjb else 1053178479Sjb indent = _dtrace_stkindent; 1054178479Sjb 1055178479Sjb /* 1056178479Sjb * Ultimately, we need to add an entry point in the library vector for 1057178479Sjb * determining <symbol, offset> from <pid, address>. For now, if 1058178479Sjb * this is a vector open, we just print the raw address or string. 1059178479Sjb */ 1060178479Sjb if (dtp->dt_vector == NULL) 1061178479Sjb P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 1062178479Sjb else 1063178479Sjb P = NULL; 1064178479Sjb 1065178479Sjb if (P != NULL) 1066178479Sjb dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 1067178479Sjb 1068178576Sjb for (i = 0; i < depth && pc[i] != 0; i++) { 1069178479Sjb const prmap_t *map; 1070178479Sjb 1071178479Sjb if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 1072178479Sjb break; 1073178479Sjb 1074178479Sjb if (P != NULL && Plookup_by_addr(P, pc[i], 1075178479Sjb name, sizeof (name), &sym) == 0) { 1076178479Sjb (void) Pobjname(P, pc[i], objname, sizeof (objname)); 1077178479Sjb 1078178479Sjb if (pc[i] > sym.st_value) { 1079178479Sjb (void) snprintf(c, sizeof (c), 1080178479Sjb "%s`%s+0x%llx", dt_basename(objname), name, 1081178479Sjb (u_longlong_t)(pc[i] - sym.st_value)); 1082178479Sjb } else { 1083178479Sjb (void) snprintf(c, sizeof (c), 1084178479Sjb "%s`%s", dt_basename(objname), name); 1085178479Sjb } 1086178479Sjb } else if (str != NULL && str[0] != '\0' && str[0] != '@' && 1087178479Sjb (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL || 1088178479Sjb (map->pr_mflags & MA_WRITE)))) { 1089178479Sjb /* 1090178479Sjb * If the current string pointer in the string table 1091178479Sjb * does not point to an empty string _and_ the program 1092178479Sjb * counter falls in a writable region, we'll use the 1093178479Sjb * string from the string table instead of the raw 1094178479Sjb * address. This last condition is necessary because 1095178479Sjb * some (broken) ustack helpers will return a string 1096178479Sjb * even for a program counter that they can't 1097178479Sjb * identify. If we have a string for a program 1098178479Sjb * counter that falls in a segment that isn't 1099178479Sjb * writable, we assume that we have fallen into this 1100178479Sjb * case and we refuse to use the string. 1101178479Sjb */ 1102178479Sjb (void) snprintf(c, sizeof (c), "%s", str); 1103178479Sjb } else { 1104178479Sjb if (P != NULL && Pobjname(P, pc[i], objname, 1105178576Sjb sizeof (objname)) != 0) { 1106178479Sjb (void) snprintf(c, sizeof (c), "%s`0x%llx", 1107178479Sjb dt_basename(objname), (u_longlong_t)pc[i]); 1108178479Sjb } else { 1109178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", 1110178479Sjb (u_longlong_t)pc[i]); 1111178479Sjb } 1112178479Sjb } 1113178479Sjb 1114178479Sjb if ((err = dt_printf(dtp, fp, format, c)) < 0) 1115178479Sjb break; 1116178479Sjb 1117178479Sjb if ((err = dt_printf(dtp, fp, "\n")) < 0) 1118178479Sjb break; 1119178479Sjb 1120178479Sjb if (str != NULL && str[0] == '@') { 1121178479Sjb /* 1122178479Sjb * If the first character of the string is an "at" sign, 1123178479Sjb * then the string is inferred to be an annotation -- 1124178479Sjb * and it is printed out beneath the frame and offset 1125178479Sjb * with brackets. 1126178479Sjb */ 1127178479Sjb if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 1128178479Sjb break; 1129178479Sjb 1130178479Sjb (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]); 1131178479Sjb 1132178479Sjb if ((err = dt_printf(dtp, fp, format, c)) < 0) 1133178479Sjb break; 1134178479Sjb 1135178479Sjb if ((err = dt_printf(dtp, fp, "\n")) < 0) 1136178479Sjb break; 1137178479Sjb } 1138178479Sjb 1139178479Sjb if (str != NULL) { 1140178479Sjb str += strlen(str) + 1; 1141178479Sjb if (str - strbase >= strsize) 1142178479Sjb str = NULL; 1143178479Sjb } 1144178479Sjb } 1145178479Sjb 1146178479Sjb if (P != NULL) { 1147178479Sjb dt_proc_unlock(dtp, P); 1148178479Sjb dt_proc_release(dtp, P); 1149178479Sjb } 1150178479Sjb 1151178479Sjb return (err); 1152178479Sjb} 1153178479Sjb 1154178479Sjbstatic int 1155178479Sjbdt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act) 1156178479Sjb{ 1157178479Sjb /* LINTED - alignment */ 1158178479Sjb uint64_t pid = ((uint64_t *)addr)[0]; 1159178479Sjb /* LINTED - alignment */ 1160178479Sjb uint64_t pc = ((uint64_t *)addr)[1]; 1161178479Sjb const char *format = " %-50s"; 1162178479Sjb char *s; 1163178479Sjb int n, len = 256; 1164178479Sjb 1165178479Sjb if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) { 1166178479Sjb struct ps_prochandle *P; 1167178479Sjb 1168178479Sjb if ((P = dt_proc_grab(dtp, pid, 1169178479Sjb PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) { 1170178479Sjb GElf_Sym sym; 1171178479Sjb 1172178479Sjb dt_proc_lock(dtp, P); 1173178479Sjb 1174178479Sjb if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0) 1175178479Sjb pc = sym.st_value; 1176178479Sjb 1177178479Sjb dt_proc_unlock(dtp, P); 1178178479Sjb dt_proc_release(dtp, P); 1179178479Sjb } 1180178479Sjb } 1181178479Sjb 1182178479Sjb do { 1183178479Sjb n = len; 1184178479Sjb s = alloca(n); 1185210767Srpaulo } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n); 1186178479Sjb 1187178479Sjb return (dt_printf(dtp, fp, format, s)); 1188178479Sjb} 1189178479Sjb 1190178479Sjbint 1191178479Sjbdt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1192178479Sjb{ 1193178479Sjb /* LINTED - alignment */ 1194178479Sjb uint64_t pid = ((uint64_t *)addr)[0]; 1195178479Sjb /* LINTED - alignment */ 1196178479Sjb uint64_t pc = ((uint64_t *)addr)[1]; 1197178479Sjb int err = 0; 1198178479Sjb 1199178479Sjb char objname[PATH_MAX], c[PATH_MAX * 2]; 1200178479Sjb struct ps_prochandle *P; 1201178479Sjb 1202178479Sjb if (format == NULL) 1203178479Sjb format = " %-50s"; 1204178479Sjb 1205178479Sjb /* 1206178479Sjb * See the comment in dt_print_ustack() for the rationale for 1207178479Sjb * printing raw addresses in the vectored case. 1208178479Sjb */ 1209178479Sjb if (dtp->dt_vector == NULL) 1210178479Sjb P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 1211178479Sjb else 1212178479Sjb P = NULL; 1213178479Sjb 1214178479Sjb if (P != NULL) 1215178479Sjb dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 1216178479Sjb 1217178576Sjb if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) { 1218178479Sjb (void) snprintf(c, sizeof (c), "%s", dt_basename(objname)); 1219178479Sjb } else { 1220178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1221178479Sjb } 1222178479Sjb 1223178479Sjb err = dt_printf(dtp, fp, format, c); 1224178479Sjb 1225178479Sjb if (P != NULL) { 1226178479Sjb dt_proc_unlock(dtp, P); 1227178479Sjb dt_proc_release(dtp, P); 1228178479Sjb } 1229178479Sjb 1230178479Sjb return (err); 1231178479Sjb} 1232178479Sjb 1233178576Sjbint 1234178576Sjbdt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr) 1235178576Sjb{ 1236178576Sjb int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 1237178576Sjb size_t nbytes = *((uintptr_t *) addr); 1238178576Sjb 1239178576Sjb return (dt_print_bytes(dtp, fp, addr + sizeof(uintptr_t), 1240178576Sjb nbytes, 50, quiet, 1)); 1241178576Sjb} 1242178576Sjb 1243178576Sjbtypedef struct dt_type_cbdata { 1244178576Sjb dtrace_hdl_t *dtp; 1245178576Sjb dtrace_typeinfo_t dtt; 1246178576Sjb caddr_t addr; 1247178576Sjb caddr_t addrend; 1248178576Sjb const char *name; 1249178576Sjb int f_type; 1250178576Sjb int indent; 1251178576Sjb int type_width; 1252178576Sjb int name_width; 1253178576Sjb FILE *fp; 1254178576Sjb} dt_type_cbdata_t; 1255178576Sjb 1256178576Sjbstatic int dt_print_type_data(dt_type_cbdata_t *, ctf_id_t); 1257178576Sjb 1258178479Sjbstatic int 1259178576Sjbdt_print_type_member(const char *name, ctf_id_t type, ulong_t off, void *arg) 1260178576Sjb{ 1261178576Sjb dt_type_cbdata_t cbdata; 1262178576Sjb dt_type_cbdata_t *cbdatap = arg; 1263178576Sjb ssize_t ssz; 1264178576Sjb 1265178576Sjb if ((ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type)) <= 0) 1266178576Sjb return (0); 1267178576Sjb 1268178576Sjb off /= 8; 1269178576Sjb 1270178576Sjb cbdata = *cbdatap; 1271178576Sjb cbdata.name = name; 1272178576Sjb cbdata.addr += off; 1273178576Sjb cbdata.addrend = cbdata.addr + ssz; 1274178576Sjb 1275178576Sjb return (dt_print_type_data(&cbdata, type)); 1276178576Sjb} 1277178576Sjb 1278178576Sjbstatic int 1279178576Sjbdt_print_type_width(const char *name, ctf_id_t type, ulong_t off, void *arg) 1280178576Sjb{ 1281178576Sjb char buf[DT_TYPE_NAMELEN]; 1282178576Sjb char *p; 1283178576Sjb dt_type_cbdata_t *cbdatap = arg; 1284178576Sjb size_t sz = strlen(name); 1285178576Sjb 1286178576Sjb ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf)); 1287178576Sjb 1288178576Sjb if ((p = strchr(buf, '[')) != NULL) 1289178576Sjb p[-1] = '\0'; 1290178576Sjb else 1291178576Sjb p = ""; 1292178576Sjb 1293178576Sjb sz += strlen(p); 1294178576Sjb 1295178576Sjb if (sz > cbdatap->name_width) 1296178576Sjb cbdatap->name_width = sz; 1297178576Sjb 1298178576Sjb sz = strlen(buf); 1299178576Sjb 1300178576Sjb if (sz > cbdatap->type_width) 1301178576Sjb cbdatap->type_width = sz; 1302178576Sjb 1303178576Sjb return (0); 1304178576Sjb} 1305178576Sjb 1306178576Sjbstatic int 1307178576Sjbdt_print_type_data(dt_type_cbdata_t *cbdatap, ctf_id_t type) 1308178576Sjb{ 1309178576Sjb caddr_t addr = cbdatap->addr; 1310178576Sjb caddr_t addrend = cbdatap->addrend; 1311178576Sjb char buf[DT_TYPE_NAMELEN]; 1312178576Sjb char *p; 1313178576Sjb int cnt = 0; 1314178576Sjb uint_t kind = ctf_type_kind(cbdatap->dtt.dtt_ctfp, type); 1315178576Sjb ssize_t ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type); 1316178576Sjb 1317178576Sjb ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf)); 1318178576Sjb 1319178576Sjb if ((p = strchr(buf, '[')) != NULL) 1320178576Sjb p[-1] = '\0'; 1321178576Sjb else 1322178576Sjb p = ""; 1323178576Sjb 1324178576Sjb if (cbdatap->f_type) { 1325178576Sjb int type_width = roundup(cbdatap->type_width + 1, 4); 1326178576Sjb int name_width = roundup(cbdatap->name_width + 1, 4); 1327178576Sjb 1328178576Sjb name_width -= strlen(cbdatap->name); 1329178576Sjb 1330178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s%-*s%s%-*s = ",cbdatap->indent * 4,"",type_width,buf,cbdatap->name,name_width,p); 1331178576Sjb } 1332178576Sjb 1333178576Sjb while (addr < addrend) { 1334178576Sjb dt_type_cbdata_t cbdata; 1335178576Sjb ctf_arinfo_t arinfo; 1336178576Sjb ctf_encoding_t cte; 1337178576Sjb uintptr_t *up; 1338178576Sjb void *vp = addr; 1339178576Sjb cbdata = *cbdatap; 1340178576Sjb cbdata.name = ""; 1341178576Sjb cbdata.addr = addr; 1342178576Sjb cbdata.addrend = addr + ssz; 1343178576Sjb cbdata.f_type = 0; 1344178576Sjb cbdata.indent++; 1345178576Sjb cbdata.type_width = 0; 1346178576Sjb cbdata.name_width = 0; 1347178576Sjb 1348178576Sjb if (cnt > 0) 1349178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s", cbdatap->indent * 4,""); 1350178576Sjb 1351178576Sjb switch (kind) { 1352178576Sjb case CTF_K_INTEGER: 1353178576Sjb if (ctf_type_encoding(cbdatap->dtt.dtt_ctfp, type, &cte) != 0) 1354178576Sjb return (-1); 1355178576Sjb if ((cte.cte_format & CTF_INT_SIGNED) != 0) 1356178576Sjb switch (cte.cte_bits) { 1357178576Sjb case 8: 1358178576Sjb if (isprint(*((char *) vp))) 1359178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "'%c', ", *((char *) vp)); 1360178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((char *) vp), *((char *) vp)); 1361178576Sjb break; 1362178576Sjb case 16: 1363178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%hd (0x%hx);\n", *((short *) vp), *((u_short *) vp)); 1364178576Sjb break; 1365178576Sjb case 32: 1366178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((int *) vp), *((u_int *) vp)); 1367178576Sjb break; 1368178576Sjb case 64: 1369178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%jd (0x%jx);\n", *((long long *) vp), *((unsigned long long *) vp)); 1370178576Sjb break; 1371178576Sjb default: 1372178576Sjb 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); 1373178576Sjb break; 1374178576Sjb } 1375178576Sjb else 1376178576Sjb switch (cte.cte_bits) { 1377178576Sjb case 8: 1378178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((uint8_t *) vp) & 0xff, *((uint8_t *) vp) & 0xff); 1379178576Sjb break; 1380178576Sjb case 16: 1381178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%hu (0x%hx);\n", *((u_short *) vp), *((u_short *) vp)); 1382178576Sjb break; 1383178576Sjb case 32: 1384178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((u_int *) vp), *((u_int *) vp)); 1385178576Sjb break; 1386178576Sjb case 64: 1387178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%ju (0x%jx);\n", *((unsigned long long *) vp), *((unsigned long long *) vp)); 1388178576Sjb break; 1389178576Sjb default: 1390178576Sjb 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); 1391178576Sjb break; 1392178576Sjb } 1393178576Sjb break; 1394178576Sjb case CTF_K_FLOAT: 1395178576Sjb 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); 1396178576Sjb break; 1397178576Sjb case CTF_K_POINTER: 1398178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%p;\n", *((void **) addr)); 1399178576Sjb break; 1400178576Sjb case CTF_K_ARRAY: 1401178576Sjb if (ctf_array_info(cbdatap->dtt.dtt_ctfp, type, &arinfo) != 0) 1402178576Sjb return (-1); 1403178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "{\n%*s",cbdata.indent * 4,""); 1404178576Sjb dt_print_type_data(&cbdata, arinfo.ctr_contents); 1405178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1406178576Sjb break; 1407178576Sjb case CTF_K_FUNCTION: 1408178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_FUNCTION:\n"); 1409178576Sjb break; 1410178576Sjb case CTF_K_STRUCT: 1411178576Sjb cbdata.f_type = 1; 1412178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1413178576Sjb dt_print_type_width, &cbdata) != 0) 1414178576Sjb return (-1); 1415178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "{\n"); 1416178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1417178576Sjb dt_print_type_member, &cbdata) != 0) 1418178576Sjb return (-1); 1419178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1420178576Sjb break; 1421178576Sjb case CTF_K_UNION: 1422178576Sjb cbdata.f_type = 1; 1423178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1424178576Sjb dt_print_type_width, &cbdata) != 0) 1425178576Sjb return (-1); 1426178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "{\n"); 1427178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1428178576Sjb dt_print_type_member, &cbdata) != 0) 1429178576Sjb return (-1); 1430178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1431178576Sjb break; 1432178576Sjb case CTF_K_ENUM: 1433178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%s;\n", ctf_enum_name(cbdatap->dtt.dtt_ctfp, type, *((int *) vp))); 1434178576Sjb break; 1435178576Sjb case CTF_K_TYPEDEF: 1436178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1437178576Sjb break; 1438178576Sjb case CTF_K_VOLATILE: 1439178576Sjb if (cbdatap->f_type) 1440178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "volatile "); 1441178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1442178576Sjb break; 1443178576Sjb case CTF_K_CONST: 1444178576Sjb if (cbdatap->f_type) 1445178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "const "); 1446178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1447178576Sjb break; 1448178576Sjb case CTF_K_RESTRICT: 1449178576Sjb if (cbdatap->f_type) 1450178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "restrict "); 1451178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1452178576Sjb break; 1453178576Sjb default: 1454178576Sjb break; 1455178576Sjb } 1456178576Sjb 1457178576Sjb addr += ssz; 1458178576Sjb cnt++; 1459178576Sjb } 1460178576Sjb 1461178576Sjb return (0); 1462178576Sjb} 1463178576Sjb 1464178576Sjbstatic int 1465178576Sjbdt_print_type(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr) 1466178576Sjb{ 1467178576Sjb caddr_t addrend; 1468178576Sjb char *p; 1469178576Sjb dtrace_typeinfo_t dtt; 1470178576Sjb dt_type_cbdata_t cbdata; 1471178576Sjb int num = 0; 1472178576Sjb int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 1473178576Sjb ssize_t ssz; 1474178576Sjb 1475178576Sjb if (!quiet) 1476178576Sjb dt_printf(dtp, fp, "\n"); 1477178576Sjb 1478178576Sjb /* Get the total number of bytes of data buffered. */ 1479178576Sjb size_t nbytes = *((uintptr_t *) addr); 1480178576Sjb addr += sizeof(uintptr_t); 1481178576Sjb 1482178576Sjb /* 1483178576Sjb * Get the size of the type so that we can check that it matches 1484178576Sjb * the CTF data we look up and so that we can figure out how many 1485178576Sjb * type elements are buffered. 1486178576Sjb */ 1487178576Sjb size_t typs = *((uintptr_t *) addr); 1488178576Sjb addr += sizeof(uintptr_t); 1489178576Sjb 1490178576Sjb /* 1491178576Sjb * Point to the type string in the buffer. Get it's string 1492178576Sjb * length and round it up to become the offset to the start 1493178576Sjb * of the buffered type data which we would like to be aligned 1494178576Sjb * for easy access. 1495178576Sjb */ 1496178576Sjb char *strp = (char *) addr; 1497178576Sjb int offset = roundup(strlen(strp) + 1, sizeof(uintptr_t)); 1498178576Sjb 1499178576Sjb /* 1500178576Sjb * The type string might have a format such as 'int [20]'. 1501178576Sjb * Check if there is an array dimension present. 1502178576Sjb */ 1503178576Sjb if ((p = strchr(strp, '[')) != NULL) { 1504178576Sjb /* Strip off the array dimension. */ 1505178576Sjb *p++ = '\0'; 1506178576Sjb 1507178576Sjb for (; *p != '\0' && *p != ']'; p++) 1508178576Sjb num = num * 10 + *p - '0'; 1509178576Sjb } else 1510178576Sjb /* No array dimension, so default. */ 1511178576Sjb num = 1; 1512178576Sjb 1513178576Sjb /* Lookup the CTF type from the type string. */ 1514178576Sjb if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, strp, &dtt) < 0) 1515178576Sjb return (-1); 1516178576Sjb 1517178576Sjb /* Offset the buffer address to the start of the data... */ 1518178576Sjb addr += offset; 1519178576Sjb 1520178576Sjb ssz = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type); 1521178576Sjb 1522178576Sjb if (typs != ssz) { 1523178576Sjb printf("Expected type size from buffer (%lu) to match type size looked up now (%ld)\n", (u_long) typs, (long) ssz); 1524178576Sjb return (-1); 1525178576Sjb } 1526178576Sjb 1527178576Sjb cbdata.dtp = dtp; 1528178576Sjb cbdata.dtt = dtt; 1529178576Sjb cbdata.name = ""; 1530178576Sjb cbdata.addr = addr; 1531178576Sjb cbdata.addrend = addr + nbytes; 1532178576Sjb cbdata.indent = 1; 1533178576Sjb cbdata.f_type = 1; 1534178576Sjb cbdata.type_width = 0; 1535178576Sjb cbdata.name_width = 0; 1536178576Sjb cbdata.fp = fp; 1537178576Sjb 1538178576Sjb return (dt_print_type_data(&cbdata, dtt.dtt_type)); 1539178576Sjb} 1540178576Sjb 1541178576Sjbstatic int 1542178479Sjbdt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1543178479Sjb{ 1544178479Sjb /* LINTED - alignment */ 1545178479Sjb uint64_t pc = *((uint64_t *)addr); 1546178479Sjb dtrace_syminfo_t dts; 1547178479Sjb GElf_Sym sym; 1548178479Sjb char c[PATH_MAX * 2]; 1549178479Sjb 1550178479Sjb if (format == NULL) 1551178479Sjb format = " %-50s"; 1552178479Sjb 1553178479Sjb if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 1554178479Sjb (void) snprintf(c, sizeof (c), "%s`%s", 1555178479Sjb dts.dts_object, dts.dts_name); 1556178479Sjb } else { 1557178479Sjb /* 1558178479Sjb * We'll repeat the lookup, but this time we'll specify a 1559178479Sjb * NULL GElf_Sym -- indicating that we're only interested in 1560178479Sjb * the containing module. 1561178479Sjb */ 1562178479Sjb if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1563178479Sjb (void) snprintf(c, sizeof (c), "%s`0x%llx", 1564178479Sjb dts.dts_object, (u_longlong_t)pc); 1565178479Sjb } else { 1566178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", 1567178479Sjb (u_longlong_t)pc); 1568178479Sjb } 1569178479Sjb } 1570178479Sjb 1571178479Sjb if (dt_printf(dtp, fp, format, c) < 0) 1572178479Sjb return (-1); 1573178479Sjb 1574178479Sjb return (0); 1575178479Sjb} 1576178479Sjb 1577178479Sjbint 1578178479Sjbdt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1579178479Sjb{ 1580178479Sjb /* LINTED - alignment */ 1581178479Sjb uint64_t pc = *((uint64_t *)addr); 1582178479Sjb dtrace_syminfo_t dts; 1583178479Sjb char c[PATH_MAX * 2]; 1584178479Sjb 1585178479Sjb if (format == NULL) 1586178479Sjb format = " %-50s"; 1587178479Sjb 1588178479Sjb if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1589178479Sjb (void) snprintf(c, sizeof (c), "%s", dts.dts_object); 1590178479Sjb } else { 1591178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1592178479Sjb } 1593178479Sjb 1594178479Sjb if (dt_printf(dtp, fp, format, c) < 0) 1595178479Sjb return (-1); 1596178479Sjb 1597178479Sjb return (0); 1598178479Sjb} 1599178479Sjb 1600178479Sjbtypedef struct dt_normal { 1601178479Sjb dtrace_aggvarid_t dtnd_id; 1602178479Sjb uint64_t dtnd_normal; 1603178479Sjb} dt_normal_t; 1604178479Sjb 1605178479Sjbstatic int 1606178479Sjbdt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 1607178479Sjb{ 1608178479Sjb dt_normal_t *normal = arg; 1609178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1610178479Sjb dtrace_aggvarid_t id = normal->dtnd_id; 1611178479Sjb 1612178479Sjb if (agg->dtagd_nrecs == 0) 1613178479Sjb return (DTRACE_AGGWALK_NEXT); 1614178479Sjb 1615178479Sjb if (agg->dtagd_varid != id) 1616178479Sjb return (DTRACE_AGGWALK_NEXT); 1617178479Sjb 1618178479Sjb ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal; 1619178479Sjb return (DTRACE_AGGWALK_NORMALIZE); 1620178479Sjb} 1621178479Sjb 1622178479Sjbstatic int 1623178479Sjbdt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 1624178479Sjb{ 1625178479Sjb dt_normal_t normal; 1626178479Sjb caddr_t addr; 1627178479Sjb 1628178479Sjb /* 1629178479Sjb * We (should) have two records: the aggregation ID followed by the 1630178479Sjb * normalization value. 1631178479Sjb */ 1632178479Sjb addr = base + rec->dtrd_offset; 1633178479Sjb 1634178479Sjb if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 1635178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1636178479Sjb 1637178479Sjb /* LINTED - alignment */ 1638178479Sjb normal.dtnd_id = *((dtrace_aggvarid_t *)addr); 1639178479Sjb rec++; 1640178479Sjb 1641178479Sjb if (rec->dtrd_action != DTRACEACT_LIBACT) 1642178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1643178479Sjb 1644178479Sjb if (rec->dtrd_arg != DT_ACT_NORMALIZE) 1645178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1646178479Sjb 1647178479Sjb addr = base + rec->dtrd_offset; 1648178479Sjb 1649178479Sjb switch (rec->dtrd_size) { 1650178479Sjb case sizeof (uint64_t): 1651178479Sjb /* LINTED - alignment */ 1652178479Sjb normal.dtnd_normal = *((uint64_t *)addr); 1653178479Sjb break; 1654178479Sjb case sizeof (uint32_t): 1655178479Sjb /* LINTED - alignment */ 1656178479Sjb normal.dtnd_normal = *((uint32_t *)addr); 1657178479Sjb break; 1658178479Sjb case sizeof (uint16_t): 1659178479Sjb /* LINTED - alignment */ 1660178479Sjb normal.dtnd_normal = *((uint16_t *)addr); 1661178479Sjb break; 1662178479Sjb case sizeof (uint8_t): 1663178479Sjb normal.dtnd_normal = *((uint8_t *)addr); 1664178479Sjb break; 1665178479Sjb default: 1666178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1667178479Sjb } 1668178479Sjb 1669178479Sjb (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal); 1670178479Sjb 1671178479Sjb return (0); 1672178479Sjb} 1673178479Sjb 1674178479Sjbstatic int 1675178479Sjbdt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 1676178479Sjb{ 1677178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1678178479Sjb dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 1679178479Sjb 1680178479Sjb if (agg->dtagd_nrecs == 0) 1681178479Sjb return (DTRACE_AGGWALK_NEXT); 1682178479Sjb 1683178479Sjb if (agg->dtagd_varid != id) 1684178479Sjb return (DTRACE_AGGWALK_NEXT); 1685178479Sjb 1686178479Sjb return (DTRACE_AGGWALK_DENORMALIZE); 1687178479Sjb} 1688178479Sjb 1689178479Sjbstatic int 1690178479Sjbdt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg) 1691178479Sjb{ 1692178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1693178479Sjb dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 1694178479Sjb 1695178479Sjb if (agg->dtagd_nrecs == 0) 1696178479Sjb return (DTRACE_AGGWALK_NEXT); 1697178479Sjb 1698178479Sjb if (agg->dtagd_varid != id) 1699178479Sjb return (DTRACE_AGGWALK_NEXT); 1700178479Sjb 1701178479Sjb return (DTRACE_AGGWALK_CLEAR); 1702178479Sjb} 1703178479Sjb 1704178479Sjbtypedef struct dt_trunc { 1705178479Sjb dtrace_aggvarid_t dttd_id; 1706178479Sjb uint64_t dttd_remaining; 1707178479Sjb} dt_trunc_t; 1708178479Sjb 1709178479Sjbstatic int 1710178479Sjbdt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg) 1711178479Sjb{ 1712178479Sjb dt_trunc_t *trunc = arg; 1713178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1714178479Sjb dtrace_aggvarid_t id = trunc->dttd_id; 1715178479Sjb 1716178479Sjb if (agg->dtagd_nrecs == 0) 1717178479Sjb return (DTRACE_AGGWALK_NEXT); 1718178479Sjb 1719178479Sjb if (agg->dtagd_varid != id) 1720178479Sjb return (DTRACE_AGGWALK_NEXT); 1721178479Sjb 1722178479Sjb if (trunc->dttd_remaining == 0) 1723178479Sjb return (DTRACE_AGGWALK_REMOVE); 1724178479Sjb 1725178479Sjb trunc->dttd_remaining--; 1726178479Sjb return (DTRACE_AGGWALK_NEXT); 1727178479Sjb} 1728178479Sjb 1729178479Sjbstatic int 1730178479Sjbdt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 1731178479Sjb{ 1732178479Sjb dt_trunc_t trunc; 1733178479Sjb caddr_t addr; 1734178479Sjb int64_t remaining; 1735178479Sjb int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *); 1736178479Sjb 1737178479Sjb /* 1738178479Sjb * We (should) have two records: the aggregation ID followed by the 1739178479Sjb * number of aggregation entries after which the aggregation is to be 1740178479Sjb * truncated. 1741178479Sjb */ 1742178479Sjb addr = base + rec->dtrd_offset; 1743178479Sjb 1744178479Sjb if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 1745178479Sjb return (dt_set_errno(dtp, EDT_BADTRUNC)); 1746178479Sjb 1747178479Sjb /* LINTED - alignment */ 1748178479Sjb trunc.dttd_id = *((dtrace_aggvarid_t *)addr); 1749178479Sjb rec++; 1750178479Sjb 1751178479Sjb if (rec->dtrd_action != DTRACEACT_LIBACT) 1752178479Sjb return (dt_set_errno(dtp, EDT_BADTRUNC)); 1753178479Sjb 1754178479Sjb if (rec->dtrd_arg != DT_ACT_TRUNC) 1755178479Sjb return (dt_set_errno(dtp, EDT_BADTRUNC)); 1756178479Sjb 1757178479Sjb addr = base + rec->dtrd_offset; 1758178479Sjb 1759178479Sjb switch (rec->dtrd_size) { 1760178479Sjb case sizeof (uint64_t): 1761178479Sjb /* LINTED - alignment */ 1762178479Sjb remaining = *((int64_t *)addr); 1763178479Sjb break; 1764178479Sjb case sizeof (uint32_t): 1765178479Sjb /* LINTED - alignment */ 1766178479Sjb remaining = *((int32_t *)addr); 1767178479Sjb break; 1768178479Sjb case sizeof (uint16_t): 1769178479Sjb /* LINTED - alignment */ 1770178479Sjb remaining = *((int16_t *)addr); 1771178479Sjb break; 1772178479Sjb case sizeof (uint8_t): 1773178479Sjb remaining = *((int8_t *)addr); 1774178479Sjb break; 1775178479Sjb default: 1776178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1777178479Sjb } 1778178479Sjb 1779178479Sjb if (remaining < 0) { 1780178479Sjb func = dtrace_aggregate_walk_valsorted; 1781178479Sjb remaining = -remaining; 1782178479Sjb } else { 1783178479Sjb func = dtrace_aggregate_walk_valrevsorted; 1784178479Sjb } 1785178479Sjb 1786178479Sjb assert(remaining >= 0); 1787178479Sjb trunc.dttd_remaining = remaining; 1788178479Sjb 1789178479Sjb (void) func(dtp, dt_trunc_agg, &trunc); 1790178479Sjb 1791178479Sjb return (0); 1792178479Sjb} 1793178479Sjb 1794178479Sjbstatic int 1795178479Sjbdt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, 1796178479Sjb caddr_t addr, size_t size, uint64_t normal) 1797178479Sjb{ 1798178479Sjb int err; 1799178479Sjb dtrace_actkind_t act = rec->dtrd_action; 1800178479Sjb 1801178479Sjb switch (act) { 1802178479Sjb case DTRACEACT_STACK: 1803178479Sjb return (dt_print_stack(dtp, fp, NULL, addr, 1804178479Sjb rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg)); 1805178479Sjb 1806178479Sjb case DTRACEACT_USTACK: 1807178479Sjb case DTRACEACT_JSTACK: 1808178479Sjb return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg)); 1809178479Sjb 1810178479Sjb case DTRACEACT_USYM: 1811178479Sjb case DTRACEACT_UADDR: 1812178479Sjb return (dt_print_usym(dtp, fp, addr, act)); 1813178479Sjb 1814178479Sjb case DTRACEACT_UMOD: 1815178479Sjb return (dt_print_umod(dtp, fp, NULL, addr)); 1816178479Sjb 1817178479Sjb case DTRACEACT_SYM: 1818178479Sjb return (dt_print_sym(dtp, fp, NULL, addr)); 1819178479Sjb 1820178479Sjb case DTRACEACT_MOD: 1821178479Sjb return (dt_print_mod(dtp, fp, NULL, addr)); 1822178479Sjb 1823178479Sjb case DTRACEAGG_QUANTIZE: 1824178479Sjb return (dt_print_quantize(dtp, fp, addr, size, normal)); 1825178479Sjb 1826178479Sjb case DTRACEAGG_LQUANTIZE: 1827178479Sjb return (dt_print_lquantize(dtp, fp, addr, size, normal)); 1828178479Sjb 1829237624Spfg case DTRACEAGG_LLQUANTIZE: 1830237624Spfg return (dt_print_llquantize(dtp, fp, addr, size, normal)); 1831237624Spfg 1832178479Sjb case DTRACEAGG_AVG: 1833178479Sjb return (dt_print_average(dtp, fp, addr, size, normal)); 1834178479Sjb 1835178479Sjb case DTRACEAGG_STDDEV: 1836178479Sjb return (dt_print_stddev(dtp, fp, addr, size, normal)); 1837178479Sjb 1838178479Sjb default: 1839178479Sjb break; 1840178479Sjb } 1841178479Sjb 1842178479Sjb switch (size) { 1843178479Sjb case sizeof (uint64_t): 1844178479Sjb err = dt_printf(dtp, fp, " %16lld", 1845178479Sjb /* LINTED - alignment */ 1846178479Sjb (long long)*((uint64_t *)addr) / normal); 1847178479Sjb break; 1848178479Sjb case sizeof (uint32_t): 1849178479Sjb /* LINTED - alignment */ 1850178479Sjb err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) / 1851178479Sjb (uint32_t)normal); 1852178479Sjb break; 1853178479Sjb case sizeof (uint16_t): 1854178479Sjb /* LINTED - alignment */ 1855178479Sjb err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) / 1856178479Sjb (uint32_t)normal); 1857178479Sjb break; 1858178479Sjb case sizeof (uint8_t): 1859178479Sjb err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) / 1860178479Sjb (uint32_t)normal); 1861178479Sjb break; 1862178479Sjb default: 1863178576Sjb err = dt_print_bytes(dtp, fp, addr, size, 50, 0, 0); 1864178479Sjb break; 1865178479Sjb } 1866178479Sjb 1867178479Sjb return (err); 1868178479Sjb} 1869178479Sjb 1870178479Sjbint 1871178479Sjbdt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) 1872178479Sjb{ 1873178479Sjb int i, aggact = 0; 1874178479Sjb dt_print_aggdata_t *pd = arg; 1875178479Sjb const dtrace_aggdata_t *aggdata = aggsdata[0]; 1876178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1877178479Sjb FILE *fp = pd->dtpa_fp; 1878178479Sjb dtrace_hdl_t *dtp = pd->dtpa_dtp; 1879178479Sjb dtrace_recdesc_t *rec; 1880178479Sjb dtrace_actkind_t act; 1881178479Sjb caddr_t addr; 1882178479Sjb size_t size; 1883178479Sjb 1884178479Sjb /* 1885178479Sjb * Iterate over each record description in the key, printing the traced 1886178479Sjb * data, skipping the first datum (the tuple member created by the 1887178479Sjb * compiler). 1888178479Sjb */ 1889178479Sjb for (i = 1; i < agg->dtagd_nrecs; i++) { 1890178479Sjb rec = &agg->dtagd_rec[i]; 1891178479Sjb act = rec->dtrd_action; 1892178479Sjb addr = aggdata->dtada_data + rec->dtrd_offset; 1893178479Sjb size = rec->dtrd_size; 1894178479Sjb 1895178479Sjb if (DTRACEACT_ISAGG(act)) { 1896178479Sjb aggact = i; 1897178479Sjb break; 1898178479Sjb } 1899178479Sjb 1900178479Sjb if (dt_print_datum(dtp, fp, rec, addr, size, 1) < 0) 1901178479Sjb return (-1); 1902178479Sjb 1903178479Sjb if (dt_buffered_flush(dtp, NULL, rec, aggdata, 1904178479Sjb DTRACE_BUFDATA_AGGKEY) < 0) 1905178479Sjb return (-1); 1906178479Sjb } 1907178479Sjb 1908178479Sjb assert(aggact != 0); 1909178479Sjb 1910178479Sjb for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) { 1911178479Sjb uint64_t normal; 1912178479Sjb 1913178479Sjb aggdata = aggsdata[i]; 1914178479Sjb agg = aggdata->dtada_desc; 1915178479Sjb rec = &agg->dtagd_rec[aggact]; 1916178479Sjb act = rec->dtrd_action; 1917178479Sjb addr = aggdata->dtada_data + rec->dtrd_offset; 1918178479Sjb size = rec->dtrd_size; 1919178479Sjb 1920178479Sjb assert(DTRACEACT_ISAGG(act)); 1921178479Sjb normal = aggdata->dtada_normal; 1922178479Sjb 1923178479Sjb if (dt_print_datum(dtp, fp, rec, addr, size, normal) < 0) 1924178479Sjb return (-1); 1925178479Sjb 1926178479Sjb if (dt_buffered_flush(dtp, NULL, rec, aggdata, 1927178479Sjb DTRACE_BUFDATA_AGGVAL) < 0) 1928178479Sjb return (-1); 1929178479Sjb 1930178479Sjb if (!pd->dtpa_allunprint) 1931178479Sjb agg->dtagd_flags |= DTRACE_AGD_PRINTED; 1932178479Sjb } 1933178479Sjb 1934178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 1935178479Sjb return (-1); 1936178479Sjb 1937178479Sjb if (dt_buffered_flush(dtp, NULL, NULL, aggdata, 1938178479Sjb DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) 1939178479Sjb return (-1); 1940178479Sjb 1941178479Sjb return (0); 1942178479Sjb} 1943178479Sjb 1944178479Sjbint 1945178479Sjbdt_print_agg(const dtrace_aggdata_t *aggdata, void *arg) 1946178479Sjb{ 1947178479Sjb dt_print_aggdata_t *pd = arg; 1948178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1949178479Sjb dtrace_aggvarid_t aggvarid = pd->dtpa_id; 1950178479Sjb 1951178479Sjb if (pd->dtpa_allunprint) { 1952178479Sjb if (agg->dtagd_flags & DTRACE_AGD_PRINTED) 1953178479Sjb return (0); 1954178479Sjb } else { 1955178479Sjb /* 1956178479Sjb * If we're not printing all unprinted aggregations, then the 1957178479Sjb * aggregation variable ID denotes a specific aggregation 1958178479Sjb * variable that we should print -- skip any other aggregations 1959178479Sjb * that we encounter. 1960178479Sjb */ 1961178479Sjb if (agg->dtagd_nrecs == 0) 1962178479Sjb return (0); 1963178479Sjb 1964178479Sjb if (aggvarid != agg->dtagd_varid) 1965178479Sjb return (0); 1966178479Sjb } 1967178479Sjb 1968178479Sjb return (dt_print_aggs(&aggdata, 1, arg)); 1969178479Sjb} 1970178479Sjb 1971178479Sjbint 1972178479Sjbdt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, 1973178479Sjb const char *option, const char *value) 1974178479Sjb{ 1975178479Sjb int len, rval; 1976178479Sjb char *msg; 1977178479Sjb const char *errstr; 1978178479Sjb dtrace_setoptdata_t optdata; 1979178479Sjb 1980178479Sjb bzero(&optdata, sizeof (optdata)); 1981178479Sjb (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval); 1982178479Sjb 1983178479Sjb if (dtrace_setopt(dtp, option, value) == 0) { 1984178479Sjb (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval); 1985178479Sjb optdata.dtsda_probe = data; 1986178479Sjb optdata.dtsda_option = option; 1987178479Sjb optdata.dtsda_handle = dtp; 1988178479Sjb 1989178479Sjb if ((rval = dt_handle_setopt(dtp, &optdata)) != 0) 1990178479Sjb return (rval); 1991178479Sjb 1992178479Sjb return (0); 1993178479Sjb } 1994178479Sjb 1995178479Sjb errstr = dtrace_errmsg(dtp, dtrace_errno(dtp)); 1996178479Sjb len = strlen(option) + strlen(value) + strlen(errstr) + 80; 1997178479Sjb msg = alloca(len); 1998178479Sjb 1999178479Sjb (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n", 2000178479Sjb option, value, errstr); 2001178479Sjb 2002178479Sjb if ((rval = dt_handle_liberr(dtp, data, msg)) == 0) 2003178479Sjb return (0); 2004178479Sjb 2005178479Sjb return (rval); 2006178479Sjb} 2007178479Sjb 2008178479Sjbstatic int 2009250574Smarkjdt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, 2010250574Smarkj dtrace_bufdesc_t *buf, boolean_t just_one, 2011178479Sjb dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) 2012178479Sjb{ 2013178479Sjb dtrace_epid_t id; 2014250574Smarkj size_t offs; 2015178479Sjb int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 2016178479Sjb int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 2017178479Sjb int rval, i, n; 2018248690Spfg uint64_t tracememsize = 0; 2019178479Sjb dtrace_probedata_t data; 2020178479Sjb uint64_t drops; 2021178479Sjb 2022178479Sjb bzero(&data, sizeof (data)); 2023178479Sjb data.dtpda_handle = dtp; 2024178479Sjb data.dtpda_cpu = cpu; 2025253725Spfg data.dtpda_flow = dtp->dt_flow; 2026253725Spfg data.dtpda_indent = dtp->dt_indent; 2027253725Spfg data.dtpda_prefix = dtp->dt_prefix; 2028178479Sjb 2029250574Smarkj for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) { 2030178479Sjb dtrace_eprobedesc_t *epd; 2031178479Sjb 2032178479Sjb /* 2033178479Sjb * We're guaranteed to have an ID. 2034178479Sjb */ 2035178479Sjb id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 2036178479Sjb 2037178479Sjb if (id == DTRACE_EPIDNONE) { 2038178479Sjb /* 2039178479Sjb * This is filler to assure proper alignment of the 2040178479Sjb * next record; we simply ignore it. 2041178479Sjb */ 2042178479Sjb offs += sizeof (id); 2043178479Sjb continue; 2044178479Sjb } 2045178479Sjb 2046178479Sjb if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc, 2047178479Sjb &data.dtpda_pdesc)) != 0) 2048178479Sjb return (rval); 2049178479Sjb 2050178479Sjb epd = data.dtpda_edesc; 2051178479Sjb data.dtpda_data = buf->dtbd_data + offs; 2052178479Sjb 2053178479Sjb if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) { 2054178479Sjb rval = dt_handle(dtp, &data); 2055178479Sjb 2056178479Sjb if (rval == DTRACE_CONSUME_NEXT) 2057178479Sjb goto nextepid; 2058178479Sjb 2059178479Sjb if (rval == DTRACE_CONSUME_ERROR) 2060178479Sjb return (-1); 2061178479Sjb } 2062178479Sjb 2063178479Sjb if (flow) 2064250574Smarkj (void) dt_flowindent(dtp, &data, dtp->dt_last_epid, 2065250574Smarkj buf, offs); 2066178479Sjb 2067178479Sjb rval = (*efunc)(&data, arg); 2068178479Sjb 2069178479Sjb if (flow) { 2070178479Sjb if (data.dtpda_flow == DTRACEFLOW_ENTRY) 2071178479Sjb data.dtpda_indent += 2; 2072178479Sjb } 2073178479Sjb 2074178479Sjb if (rval == DTRACE_CONSUME_NEXT) 2075178479Sjb goto nextepid; 2076178479Sjb 2077178479Sjb if (rval == DTRACE_CONSUME_ABORT) 2078178479Sjb return (dt_set_errno(dtp, EDT_DIRABORT)); 2079178479Sjb 2080178479Sjb if (rval != DTRACE_CONSUME_THIS) 2081178479Sjb return (dt_set_errno(dtp, EDT_BADRVAL)); 2082178479Sjb 2083178479Sjb for (i = 0; i < epd->dtepd_nrecs; i++) { 2084250574Smarkj caddr_t addr; 2085178479Sjb dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; 2086178479Sjb dtrace_actkind_t act = rec->dtrd_action; 2087178479Sjb 2088178479Sjb data.dtpda_data = buf->dtbd_data + offs + 2089178479Sjb rec->dtrd_offset; 2090178479Sjb addr = data.dtpda_data; 2091178479Sjb 2092178479Sjb if (act == DTRACEACT_LIBACT) { 2093178479Sjb uint64_t arg = rec->dtrd_arg; 2094178479Sjb dtrace_aggvarid_t id; 2095178479Sjb 2096178479Sjb switch (arg) { 2097178479Sjb case DT_ACT_CLEAR: 2098178479Sjb /* LINTED - alignment */ 2099178479Sjb id = *((dtrace_aggvarid_t *)addr); 2100178479Sjb (void) dtrace_aggregate_walk(dtp, 2101178479Sjb dt_clear_agg, &id); 2102178479Sjb continue; 2103178479Sjb 2104178479Sjb case DT_ACT_DENORMALIZE: 2105178479Sjb /* LINTED - alignment */ 2106178479Sjb id = *((dtrace_aggvarid_t *)addr); 2107178479Sjb (void) dtrace_aggregate_walk(dtp, 2108178479Sjb dt_denormalize_agg, &id); 2109178479Sjb continue; 2110178479Sjb 2111178479Sjb case DT_ACT_FTRUNCATE: 2112178479Sjb if (fp == NULL) 2113178479Sjb continue; 2114178479Sjb 2115178479Sjb (void) fflush(fp); 2116178479Sjb (void) ftruncate(fileno(fp), 0); 2117178479Sjb (void) fseeko(fp, 0, SEEK_SET); 2118178479Sjb continue; 2119178479Sjb 2120178479Sjb case DT_ACT_NORMALIZE: 2121178479Sjb if (i == epd->dtepd_nrecs - 1) 2122178479Sjb return (dt_set_errno(dtp, 2123178479Sjb EDT_BADNORMAL)); 2124178479Sjb 2125178479Sjb if (dt_normalize(dtp, 2126178479Sjb buf->dtbd_data + offs, rec) != 0) 2127178479Sjb return (-1); 2128178479Sjb 2129178479Sjb i++; 2130178479Sjb continue; 2131178479Sjb 2132178479Sjb case DT_ACT_SETOPT: { 2133178479Sjb uint64_t *opts = dtp->dt_options; 2134178479Sjb dtrace_recdesc_t *valrec; 2135178479Sjb uint32_t valsize; 2136178479Sjb caddr_t val; 2137178479Sjb int rv; 2138178479Sjb 2139178479Sjb if (i == epd->dtepd_nrecs - 1) { 2140178479Sjb return (dt_set_errno(dtp, 2141178479Sjb EDT_BADSETOPT)); 2142178479Sjb } 2143178479Sjb 2144178479Sjb valrec = &epd->dtepd_rec[++i]; 2145178479Sjb valsize = valrec->dtrd_size; 2146178479Sjb 2147178479Sjb if (valrec->dtrd_action != act || 2148178479Sjb valrec->dtrd_arg != arg) { 2149178479Sjb return (dt_set_errno(dtp, 2150178479Sjb EDT_BADSETOPT)); 2151178479Sjb } 2152178479Sjb 2153178479Sjb if (valsize > sizeof (uint64_t)) { 2154178479Sjb val = buf->dtbd_data + offs + 2155178479Sjb valrec->dtrd_offset; 2156178479Sjb } else { 2157178479Sjb val = "1"; 2158178479Sjb } 2159178479Sjb 2160178479Sjb rv = dt_setopt(dtp, &data, addr, val); 2161178479Sjb 2162178479Sjb if (rv != 0) 2163178479Sjb return (-1); 2164178479Sjb 2165178479Sjb flow = (opts[DTRACEOPT_FLOWINDENT] != 2166178479Sjb DTRACEOPT_UNSET); 2167178479Sjb quiet = (opts[DTRACEOPT_QUIET] != 2168178479Sjb DTRACEOPT_UNSET); 2169178479Sjb 2170178479Sjb continue; 2171178479Sjb } 2172178479Sjb 2173178479Sjb case DT_ACT_TRUNC: 2174178479Sjb if (i == epd->dtepd_nrecs - 1) 2175178479Sjb return (dt_set_errno(dtp, 2176178479Sjb EDT_BADTRUNC)); 2177178479Sjb 2178178479Sjb if (dt_trunc(dtp, 2179178479Sjb buf->dtbd_data + offs, rec) != 0) 2180178479Sjb return (-1); 2181178479Sjb 2182178479Sjb i++; 2183178479Sjb continue; 2184178479Sjb 2185178479Sjb default: 2186178479Sjb continue; 2187178479Sjb } 2188178479Sjb } 2189178479Sjb 2190248690Spfg if (act == DTRACEACT_TRACEMEM_DYNSIZE && 2191248690Spfg rec->dtrd_size == sizeof (uint64_t)) { 2192248708Spfg /* LINTED - alignment */ 2193248690Spfg tracememsize = *((unsigned long long *)addr); 2194248690Spfg continue; 2195248690Spfg } 2196248690Spfg 2197178479Sjb rval = (*rfunc)(&data, rec, arg); 2198178479Sjb 2199178479Sjb if (rval == DTRACE_CONSUME_NEXT) 2200178479Sjb continue; 2201178479Sjb 2202178479Sjb if (rval == DTRACE_CONSUME_ABORT) 2203178479Sjb return (dt_set_errno(dtp, EDT_DIRABORT)); 2204178479Sjb 2205178479Sjb if (rval != DTRACE_CONSUME_THIS) 2206178479Sjb return (dt_set_errno(dtp, EDT_BADRVAL)); 2207178479Sjb 2208178479Sjb if (act == DTRACEACT_STACK) { 2209178479Sjb int depth = rec->dtrd_arg; 2210178479Sjb 2211178479Sjb if (dt_print_stack(dtp, fp, NULL, addr, depth, 2212178479Sjb rec->dtrd_size / depth) < 0) 2213178479Sjb return (-1); 2214178479Sjb goto nextrec; 2215178479Sjb } 2216178479Sjb 2217178479Sjb if (act == DTRACEACT_USTACK || 2218178479Sjb act == DTRACEACT_JSTACK) { 2219178479Sjb if (dt_print_ustack(dtp, fp, NULL, 2220178479Sjb addr, rec->dtrd_arg) < 0) 2221178479Sjb return (-1); 2222178479Sjb goto nextrec; 2223178479Sjb } 2224178479Sjb 2225178479Sjb if (act == DTRACEACT_SYM) { 2226178479Sjb if (dt_print_sym(dtp, fp, NULL, addr) < 0) 2227178479Sjb return (-1); 2228178479Sjb goto nextrec; 2229178479Sjb } 2230178479Sjb 2231178479Sjb if (act == DTRACEACT_MOD) { 2232178479Sjb if (dt_print_mod(dtp, fp, NULL, addr) < 0) 2233178479Sjb return (-1); 2234178479Sjb goto nextrec; 2235178479Sjb } 2236178479Sjb 2237178479Sjb if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) { 2238178479Sjb if (dt_print_usym(dtp, fp, addr, act) < 0) 2239178479Sjb return (-1); 2240178479Sjb goto nextrec; 2241178479Sjb } 2242178479Sjb 2243178479Sjb if (act == DTRACEACT_UMOD) { 2244178479Sjb if (dt_print_umod(dtp, fp, NULL, addr) < 0) 2245178479Sjb return (-1); 2246178479Sjb goto nextrec; 2247178479Sjb } 2248178479Sjb 2249178576Sjb if (act == DTRACEACT_PRINTM) { 2250178576Sjb if (dt_print_memory(dtp, fp, addr) < 0) 2251178576Sjb return (-1); 2252178576Sjb goto nextrec; 2253178576Sjb } 2254178576Sjb 2255178576Sjb if (act == DTRACEACT_PRINTT) { 2256178576Sjb if (dt_print_type(dtp, fp, addr) < 0) 2257178576Sjb return (-1); 2258178576Sjb goto nextrec; 2259178576Sjb } 2260178576Sjb 2261178479Sjb if (DTRACEACT_ISPRINTFLIKE(act)) { 2262178479Sjb void *fmtdata; 2263178479Sjb int (*func)(dtrace_hdl_t *, FILE *, void *, 2264178479Sjb const dtrace_probedata_t *, 2265178479Sjb const dtrace_recdesc_t *, uint_t, 2266178479Sjb const void *buf, size_t); 2267178479Sjb 2268178479Sjb if ((fmtdata = dt_format_lookup(dtp, 2269178479Sjb rec->dtrd_format)) == NULL) 2270178479Sjb goto nofmt; 2271178479Sjb 2272178479Sjb switch (act) { 2273178479Sjb case DTRACEACT_PRINTF: 2274178479Sjb func = dtrace_fprintf; 2275178479Sjb break; 2276178479Sjb case DTRACEACT_PRINTA: 2277178479Sjb func = dtrace_fprinta; 2278178479Sjb break; 2279178479Sjb case DTRACEACT_SYSTEM: 2280178479Sjb func = dtrace_system; 2281178479Sjb break; 2282178479Sjb case DTRACEACT_FREOPEN: 2283178479Sjb func = dtrace_freopen; 2284178479Sjb break; 2285178479Sjb } 2286178479Sjb 2287178479Sjb n = (*func)(dtp, fp, fmtdata, &data, 2288178479Sjb rec, epd->dtepd_nrecs - i, 2289178479Sjb (uchar_t *)buf->dtbd_data + offs, 2290178479Sjb buf->dtbd_size - offs); 2291178479Sjb 2292178479Sjb if (n < 0) 2293178479Sjb return (-1); /* errno is set for us */ 2294178479Sjb 2295178479Sjb if (n > 0) 2296178479Sjb i += n - 1; 2297178479Sjb goto nextrec; 2298178479Sjb } 2299178479Sjb 2300248708Spfg /* 2301248708Spfg * If this is a DIF expression, and the record has a 2302248708Spfg * format set, this indicates we have a CTF type name 2303248708Spfg * associated with the data and we should try to print 2304248708Spfg * it out by type. 2305248708Spfg */ 2306248708Spfg if (act == DTRACEACT_DIFEXPR) { 2307248708Spfg const char *strdata = dt_strdata_lookup(dtp, 2308248708Spfg rec->dtrd_format); 2309248708Spfg if (strdata != NULL) { 2310248708Spfg n = dtrace_print(dtp, fp, strdata, 2311248708Spfg addr, rec->dtrd_size); 2312248708Spfg 2313248708Spfg /* 2314248708Spfg * dtrace_print() will return -1 on 2315248708Spfg * error, or return the number of bytes 2316248708Spfg * consumed. It will return 0 if the 2317248708Spfg * type couldn't be determined, and we 2318248708Spfg * should fall through to the normal 2319248708Spfg * trace method. 2320248708Spfg */ 2321248708Spfg if (n < 0) 2322248708Spfg return (-1); 2323248708Spfg 2324248708Spfg if (n > 0) 2325248708Spfg goto nextrec; 2326248708Spfg } 2327248708Spfg } 2328248708Spfg 2329178479Sjbnofmt: 2330178479Sjb if (act == DTRACEACT_PRINTA) { 2331178479Sjb dt_print_aggdata_t pd; 2332178479Sjb dtrace_aggvarid_t *aggvars; 2333178479Sjb int j, naggvars = 0; 2334178479Sjb size_t size = ((epd->dtepd_nrecs - i) * 2335178479Sjb sizeof (dtrace_aggvarid_t)); 2336178479Sjb 2337178479Sjb if ((aggvars = dt_alloc(dtp, size)) == NULL) 2338178479Sjb return (-1); 2339178479Sjb 2340178479Sjb /* 2341178479Sjb * This might be a printa() with multiple 2342178479Sjb * aggregation variables. We need to scan 2343178479Sjb * forward through the records until we find 2344178479Sjb * a record from a different statement. 2345178479Sjb */ 2346178479Sjb for (j = i; j < epd->dtepd_nrecs; j++) { 2347178479Sjb dtrace_recdesc_t *nrec; 2348178479Sjb caddr_t naddr; 2349178479Sjb 2350178479Sjb nrec = &epd->dtepd_rec[j]; 2351178479Sjb 2352178479Sjb if (nrec->dtrd_uarg != rec->dtrd_uarg) 2353178479Sjb break; 2354178479Sjb 2355178479Sjb if (nrec->dtrd_action != act) { 2356178479Sjb return (dt_set_errno(dtp, 2357178479Sjb EDT_BADAGG)); 2358178479Sjb } 2359178479Sjb 2360178479Sjb naddr = buf->dtbd_data + offs + 2361178479Sjb nrec->dtrd_offset; 2362178479Sjb 2363178479Sjb aggvars[naggvars++] = 2364178479Sjb /* LINTED - alignment */ 2365178479Sjb *((dtrace_aggvarid_t *)naddr); 2366178479Sjb } 2367178479Sjb 2368178479Sjb i = j - 1; 2369178479Sjb bzero(&pd, sizeof (pd)); 2370178479Sjb pd.dtpa_dtp = dtp; 2371178479Sjb pd.dtpa_fp = fp; 2372178479Sjb 2373178479Sjb assert(naggvars >= 1); 2374178479Sjb 2375178479Sjb if (naggvars == 1) { 2376178479Sjb pd.dtpa_id = aggvars[0]; 2377178479Sjb dt_free(dtp, aggvars); 2378178479Sjb 2379178479Sjb if (dt_printf(dtp, fp, "\n") < 0 || 2380178479Sjb dtrace_aggregate_walk_sorted(dtp, 2381178479Sjb dt_print_agg, &pd) < 0) 2382178479Sjb return (-1); 2383178479Sjb goto nextrec; 2384178479Sjb } 2385178479Sjb 2386178479Sjb if (dt_printf(dtp, fp, "\n") < 0 || 2387178479Sjb dtrace_aggregate_walk_joined(dtp, aggvars, 2388178479Sjb naggvars, dt_print_aggs, &pd) < 0) { 2389178479Sjb dt_free(dtp, aggvars); 2390178479Sjb return (-1); 2391178479Sjb } 2392178479Sjb 2393178479Sjb dt_free(dtp, aggvars); 2394178479Sjb goto nextrec; 2395178479Sjb } 2396178479Sjb 2397248690Spfg if (act == DTRACEACT_TRACEMEM) { 2398248690Spfg if (tracememsize == 0 || 2399248690Spfg tracememsize > rec->dtrd_size) { 2400248690Spfg tracememsize = rec->dtrd_size; 2401248690Spfg } 2402248690Spfg 2403248690Spfg n = dt_print_bytes(dtp, fp, addr, 2404248690Spfg tracememsize, 33, quiet, 1); 2405248690Spfg 2406248690Spfg tracememsize = 0; 2407248690Spfg 2408248690Spfg if (n < 0) 2409248690Spfg return (-1); 2410248690Spfg 2411248690Spfg goto nextrec; 2412248690Spfg } 2413248690Spfg 2414178479Sjb switch (rec->dtrd_size) { 2415178479Sjb case sizeof (uint64_t): 2416178479Sjb n = dt_printf(dtp, fp, 2417178479Sjb quiet ? "%lld" : " %16lld", 2418178479Sjb /* LINTED - alignment */ 2419178479Sjb *((unsigned long long *)addr)); 2420178479Sjb break; 2421178479Sjb case sizeof (uint32_t): 2422178479Sjb n = dt_printf(dtp, fp, quiet ? "%d" : " %8d", 2423178479Sjb /* LINTED - alignment */ 2424178479Sjb *((uint32_t *)addr)); 2425178479Sjb break; 2426178479Sjb case sizeof (uint16_t): 2427178479Sjb n = dt_printf(dtp, fp, quiet ? "%d" : " %5d", 2428178479Sjb /* LINTED - alignment */ 2429178479Sjb *((uint16_t *)addr)); 2430178479Sjb break; 2431178479Sjb case sizeof (uint8_t): 2432178479Sjb n = dt_printf(dtp, fp, quiet ? "%d" : " %3d", 2433178479Sjb *((uint8_t *)addr)); 2434178479Sjb break; 2435178479Sjb default: 2436178479Sjb n = dt_print_bytes(dtp, fp, addr, 2437178576Sjb rec->dtrd_size, 33, quiet, 0); 2438178479Sjb break; 2439178479Sjb } 2440178479Sjb 2441178479Sjb if (n < 0) 2442178479Sjb return (-1); /* errno is set for us */ 2443178479Sjb 2444178479Sjbnextrec: 2445178479Sjb if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0) 2446178479Sjb return (-1); /* errno is set for us */ 2447178479Sjb } 2448178479Sjb 2449178479Sjb /* 2450178479Sjb * Call the record callback with a NULL record to indicate 2451178479Sjb * that we're done processing this EPID. 2452178479Sjb */ 2453178479Sjb rval = (*rfunc)(&data, NULL, arg); 2454178479Sjbnextepid: 2455178479Sjb offs += epd->dtepd_size; 2456250574Smarkj dtp->dt_last_epid = id; 2457250574Smarkj if (just_one) { 2458250574Smarkj buf->dtbd_oldest = offs; 2459250574Smarkj break; 2460250574Smarkj } 2461178479Sjb } 2462178479Sjb 2463250574Smarkj dtp->dt_flow = data.dtpda_flow; 2464250574Smarkj dtp->dt_indent = data.dtpda_indent; 2465250574Smarkj dtp->dt_prefix = data.dtpda_prefix; 2466178479Sjb 2467178479Sjb if ((drops = buf->dtbd_drops) == 0) 2468178479Sjb return (0); 2469178479Sjb 2470178479Sjb /* 2471178479Sjb * Explicitly zero the drops to prevent us from processing them again. 2472178479Sjb */ 2473178479Sjb buf->dtbd_drops = 0; 2474178479Sjb 2475178479Sjb return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); 2476178479Sjb} 2477178479Sjb 2478250574Smarkj/* 2479250574Smarkj * Reduce memory usage by shrinking the buffer if it's no more than half full. 2480250574Smarkj * Note, we need to preserve the alignment of the data at dtbd_oldest, which is 2481250574Smarkj * only 4-byte aligned. 2482250574Smarkj */ 2483250574Smarkjstatic void 2484250574Smarkjdt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize) 2485250574Smarkj{ 2486250574Smarkj uint64_t used = buf->dtbd_size - buf->dtbd_oldest; 2487250574Smarkj if (used < cursize / 2) { 2488250574Smarkj int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2489250574Smarkj char *newdata = dt_alloc(dtp, used + misalign); 2490250574Smarkj if (newdata == NULL) 2491250574Smarkj return; 2492250574Smarkj bzero(newdata, misalign); 2493250574Smarkj bcopy(buf->dtbd_data + buf->dtbd_oldest, 2494250574Smarkj newdata + misalign, used); 2495250574Smarkj dt_free(dtp, buf->dtbd_data); 2496250574Smarkj buf->dtbd_oldest = misalign; 2497250574Smarkj buf->dtbd_size = used + misalign; 2498250574Smarkj buf->dtbd_data = newdata; 2499250574Smarkj } 2500250574Smarkj} 2501250574Smarkj 2502250574Smarkj/* 2503250574Smarkj * If the ring buffer has wrapped, the data is not in order. Rearrange it 2504250574Smarkj * so that it is. Note, we need to preserve the alignment of the data at 2505250574Smarkj * dtbd_oldest, which is only 4-byte aligned. 2506250574Smarkj */ 2507250574Smarkjstatic int 2508250574Smarkjdt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2509250574Smarkj{ 2510250574Smarkj int misalign; 2511250574Smarkj char *newdata, *ndp; 2512250574Smarkj 2513250574Smarkj if (buf->dtbd_oldest == 0) 2514250574Smarkj return (0); 2515250574Smarkj 2516250574Smarkj misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2517250574Smarkj newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign); 2518250574Smarkj 2519250574Smarkj if (newdata == NULL) 2520250574Smarkj return (-1); 2521250574Smarkj 2522250574Smarkj assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1))); 2523250574Smarkj 2524250574Smarkj bzero(ndp, misalign); 2525250574Smarkj ndp += misalign; 2526250574Smarkj 2527250574Smarkj bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp, 2528250574Smarkj buf->dtbd_size - buf->dtbd_oldest); 2529250574Smarkj ndp += buf->dtbd_size - buf->dtbd_oldest; 2530250574Smarkj 2531250574Smarkj bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest); 2532250574Smarkj 2533250574Smarkj dt_free(dtp, buf->dtbd_data); 2534250574Smarkj buf->dtbd_oldest = 0; 2535250574Smarkj buf->dtbd_data = newdata; 2536250574Smarkj buf->dtbd_size += misalign; 2537250574Smarkj 2538250574Smarkj return (0); 2539250574Smarkj} 2540250574Smarkj 2541250574Smarkjstatic void 2542250574Smarkjdt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2543250574Smarkj{ 2544250574Smarkj dt_free(dtp, buf->dtbd_data); 2545250574Smarkj dt_free(dtp, buf); 2546250574Smarkj} 2547250574Smarkj 2548250574Smarkj/* 2549250574Smarkj * Returns 0 on success, in which case *cbp will be filled in if we retrieved 2550250574Smarkj * data, or NULL if there is no data for this CPU. 2551250574Smarkj * Returns -1 on failure and sets dt_errno. 2552250574Smarkj */ 2553250574Smarkjstatic int 2554250574Smarkjdt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp) 2555250574Smarkj{ 2556250574Smarkj dtrace_optval_t size; 2557250574Smarkj dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf)); 2558250574Smarkj int error; 2559250574Smarkj 2560250574Smarkj if (buf == NULL) 2561250574Smarkj return (-1); 2562250574Smarkj 2563250574Smarkj (void) dtrace_getopt(dtp, "bufsize", &size); 2564250574Smarkj buf->dtbd_data = dt_alloc(dtp, size); 2565250574Smarkj if (buf->dtbd_data == NULL) { 2566250574Smarkj dt_free(dtp, buf); 2567250574Smarkj return (-1); 2568250574Smarkj } 2569250574Smarkj buf->dtbd_size = size; 2570250574Smarkj buf->dtbd_cpu = cpu; 2571250574Smarkj 2572250574Smarkj#if defined(sun) 2573250574Smarkj if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 2574250574Smarkj#else 2575250574Smarkj if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) { 2576250574Smarkj#endif 2577250574Smarkj dt_put_buf(dtp, buf); 2578250574Smarkj /* 2579250574Smarkj * If we failed with ENOENT, it may be because the 2580250574Smarkj * CPU was unconfigured -- this is okay. Any other 2581250574Smarkj * error, however, is unexpected. 2582250574Smarkj */ 2583250574Smarkj if (errno == ENOENT) { 2584250574Smarkj *bufp = NULL; 2585250574Smarkj return (0); 2586250574Smarkj } 2587250574Smarkj 2588250574Smarkj return (dt_set_errno(dtp, errno)); 2589250574Smarkj } 2590250574Smarkj 2591250574Smarkj error = dt_unring_buf(dtp, buf); 2592250574Smarkj if (error != 0) { 2593250574Smarkj dt_put_buf(dtp, buf); 2594250574Smarkj return (error); 2595250574Smarkj } 2596250574Smarkj dt_realloc_buf(dtp, buf, size); 2597250574Smarkj 2598250574Smarkj *bufp = buf; 2599250574Smarkj return (0); 2600250574Smarkj} 2601250574Smarkj 2602178479Sjbtypedef struct dt_begin { 2603178479Sjb dtrace_consume_probe_f *dtbgn_probefunc; 2604178479Sjb dtrace_consume_rec_f *dtbgn_recfunc; 2605178479Sjb void *dtbgn_arg; 2606178479Sjb dtrace_handle_err_f *dtbgn_errhdlr; 2607178479Sjb void *dtbgn_errarg; 2608178479Sjb int dtbgn_beginonly; 2609178479Sjb} dt_begin_t; 2610178479Sjb 2611178479Sjbstatic int 2612178479Sjbdt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) 2613178479Sjb{ 2614253725Spfg dt_begin_t *begin = arg; 2615178479Sjb dtrace_probedesc_t *pd = data->dtpda_pdesc; 2616178479Sjb 2617178479Sjb int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 2618178479Sjb int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 2619178479Sjb 2620178479Sjb if (begin->dtbgn_beginonly) { 2621178479Sjb if (!(r1 && r2)) 2622178479Sjb return (DTRACE_CONSUME_NEXT); 2623178479Sjb } else { 2624178479Sjb if (r1 && r2) 2625178479Sjb return (DTRACE_CONSUME_NEXT); 2626178479Sjb } 2627178479Sjb 2628178479Sjb /* 2629178479Sjb * We have a record that we're interested in. Now call the underlying 2630178479Sjb * probe function... 2631178479Sjb */ 2632178479Sjb return (begin->dtbgn_probefunc(data, begin->dtbgn_arg)); 2633178479Sjb} 2634178479Sjb 2635178479Sjbstatic int 2636178479Sjbdt_consume_begin_record(const dtrace_probedata_t *data, 2637178479Sjb const dtrace_recdesc_t *rec, void *arg) 2638178479Sjb{ 2639253725Spfg dt_begin_t *begin = arg; 2640178479Sjb 2641178479Sjb return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); 2642178479Sjb} 2643178479Sjb 2644178479Sjbstatic int 2645178479Sjbdt_consume_begin_error(const dtrace_errdata_t *data, void *arg) 2646178479Sjb{ 2647178479Sjb dt_begin_t *begin = (dt_begin_t *)arg; 2648178479Sjb dtrace_probedesc_t *pd = data->dteda_pdesc; 2649178479Sjb 2650178479Sjb int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 2651178479Sjb int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 2652178479Sjb 2653178479Sjb if (begin->dtbgn_beginonly) { 2654178479Sjb if (!(r1 && r2)) 2655178479Sjb return (DTRACE_HANDLE_OK); 2656178479Sjb } else { 2657178479Sjb if (r1 && r2) 2658178479Sjb return (DTRACE_HANDLE_OK); 2659178479Sjb } 2660178479Sjb 2661178479Sjb return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg)); 2662178479Sjb} 2663178479Sjb 2664178479Sjbstatic int 2665250574Smarkjdt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, 2666178479Sjb dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 2667178479Sjb{ 2668178479Sjb /* 2669178479Sjb * There's this idea that the BEGIN probe should be processed before 2670178479Sjb * everything else, and that the END probe should be processed after 2671178479Sjb * anything else. In the common case, this is pretty easy to deal 2672178479Sjb * with. However, a situation may arise where the BEGIN enabling and 2673178479Sjb * END enabling are on the same CPU, and some enabling in the middle 2674178479Sjb * occurred on a different CPU. To deal with this (blech!) we need to 2675178479Sjb * consume the BEGIN buffer up until the end of the BEGIN probe, and 2676178479Sjb * then set it aside. We will then process every other CPU, and then 2677178479Sjb * we'll return to the BEGIN CPU and process the rest of the data 2678178479Sjb * (which will inevitably include the END probe, if any). Making this 2679178479Sjb * even more complicated (!) is the library's ERROR enabling. Because 2680178479Sjb * this enabling is processed before we even get into the consume call 2681178479Sjb * back, any ERROR firing would result in the library's ERROR enabling 2682178479Sjb * being processed twice -- once in our first pass (for BEGIN probes), 2683178479Sjb * and again in our second pass (for everything but BEGIN probes). To 2684178479Sjb * deal with this, we interpose on the ERROR handler to assure that we 2685178479Sjb * only process ERROR enablings induced by BEGIN enablings in the 2686178479Sjb * first pass, and that we only process ERROR enablings _not_ induced 2687178479Sjb * by BEGIN enablings in the second pass. 2688178479Sjb */ 2689250574Smarkj 2690178479Sjb dt_begin_t begin; 2691178479Sjb processorid_t cpu = dtp->dt_beganon; 2692178479Sjb int rval, i; 2693178479Sjb static int max_ncpus; 2694250574Smarkj dtrace_bufdesc_t *buf; 2695178479Sjb 2696178479Sjb dtp->dt_beganon = -1; 2697178479Sjb 2698250574Smarkj if (dt_get_buf(dtp, cpu, &buf) != 0) 2699250574Smarkj return (-1); 2700250574Smarkj if (buf == NULL) 2701250574Smarkj return (0); 2702178479Sjb 2703178479Sjb if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { 2704178479Sjb /* 2705178479Sjb * This is the simple case. We're either not stopped, or if 2706178479Sjb * we are, we actually processed any END probes on another 2707178479Sjb * CPU. We can simply consume this buffer and return. 2708178479Sjb */ 2709250574Smarkj rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2710250574Smarkj pf, rf, arg); 2711250574Smarkj dt_put_buf(dtp, buf); 2712250574Smarkj return (rval); 2713178479Sjb } 2714178479Sjb 2715178479Sjb begin.dtbgn_probefunc = pf; 2716178479Sjb begin.dtbgn_recfunc = rf; 2717178479Sjb begin.dtbgn_arg = arg; 2718178479Sjb begin.dtbgn_beginonly = 1; 2719178479Sjb 2720178479Sjb /* 2721178479Sjb * We need to interpose on the ERROR handler to be sure that we 2722178479Sjb * only process ERRORs induced by BEGIN. 2723178479Sjb */ 2724178479Sjb begin.dtbgn_errhdlr = dtp->dt_errhdlr; 2725178479Sjb begin.dtbgn_errarg = dtp->dt_errarg; 2726178479Sjb dtp->dt_errhdlr = dt_consume_begin_error; 2727178479Sjb dtp->dt_errarg = &begin; 2728178479Sjb 2729250574Smarkj rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2730250574Smarkj dt_consume_begin_probe, dt_consume_begin_record, &begin); 2731178479Sjb 2732178479Sjb dtp->dt_errhdlr = begin.dtbgn_errhdlr; 2733178479Sjb dtp->dt_errarg = begin.dtbgn_errarg; 2734178479Sjb 2735250574Smarkj if (rval != 0) { 2736250574Smarkj dt_put_buf(dtp, buf); 2737178479Sjb return (rval); 2738250574Smarkj } 2739178479Sjb 2740178479Sjb if (max_ncpus == 0) 2741178479Sjb max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 2742178479Sjb 2743178479Sjb for (i = 0; i < max_ncpus; i++) { 2744250574Smarkj dtrace_bufdesc_t *nbuf; 2745178479Sjb if (i == cpu) 2746178479Sjb continue; 2747178479Sjb 2748250574Smarkj if (dt_get_buf(dtp, i, &nbuf) != 0) { 2749250574Smarkj dt_put_buf(dtp, buf); 2750250574Smarkj return (-1); 2751178479Sjb } 2752250574Smarkj if (nbuf == NULL) 2753250574Smarkj continue; 2754178479Sjb 2755250574Smarkj rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE, 2756250574Smarkj pf, rf, arg); 2757250574Smarkj dt_put_buf(dtp, nbuf); 2758250574Smarkj if (rval != 0) { 2759250574Smarkj dt_put_buf(dtp, buf); 2760178479Sjb return (rval); 2761178479Sjb } 2762178479Sjb } 2763178479Sjb 2764178479Sjb /* 2765178479Sjb * Okay -- we're done with the other buffers. Now we want to 2766178479Sjb * reconsume the first buffer -- but this time we're looking for 2767178479Sjb * everything _but_ BEGIN. And of course, in order to only consume 2768178479Sjb * those ERRORs _not_ associated with BEGIN, we need to reinstall our 2769178479Sjb * ERROR interposition function... 2770178479Sjb */ 2771178479Sjb begin.dtbgn_beginonly = 0; 2772178479Sjb 2773178479Sjb assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr); 2774178479Sjb assert(begin.dtbgn_errarg == dtp->dt_errarg); 2775178479Sjb dtp->dt_errhdlr = dt_consume_begin_error; 2776178479Sjb dtp->dt_errarg = &begin; 2777178479Sjb 2778250574Smarkj rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2779250574Smarkj dt_consume_begin_probe, dt_consume_begin_record, &begin); 2780178479Sjb 2781178479Sjb dtp->dt_errhdlr = begin.dtbgn_errhdlr; 2782178479Sjb dtp->dt_errarg = begin.dtbgn_errarg; 2783178479Sjb 2784178479Sjb return (rval); 2785178479Sjb} 2786178479Sjb 2787250574Smarkj/* ARGSUSED */ 2788250574Smarkjstatic uint64_t 2789250574Smarkjdt_buf_oldest(void *elem, void *arg) 2790250574Smarkj{ 2791250574Smarkj dtrace_bufdesc_t *buf = elem; 2792250574Smarkj size_t offs = buf->dtbd_oldest; 2793250574Smarkj 2794250574Smarkj while (offs < buf->dtbd_size) { 2795250574Smarkj dtrace_rechdr_t *dtrh = 2796250574Smarkj /* LINTED - alignment */ 2797250574Smarkj (dtrace_rechdr_t *)(buf->dtbd_data + offs); 2798250574Smarkj if (dtrh->dtrh_epid == DTRACE_EPIDNONE) { 2799250574Smarkj offs += sizeof (dtrace_epid_t); 2800250574Smarkj } else { 2801250574Smarkj return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh)); 2802250574Smarkj } 2803250574Smarkj } 2804250574Smarkj 2805250574Smarkj /* There are no records left; use the time the buffer was retrieved. */ 2806250574Smarkj return (buf->dtbd_timestamp); 2807250574Smarkj} 2808250574Smarkj 2809178479Sjbint 2810178479Sjbdtrace_consume(dtrace_hdl_t *dtp, FILE *fp, 2811178479Sjb dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 2812178479Sjb{ 2813178479Sjb dtrace_optval_t size; 2814178479Sjb static int max_ncpus; 2815178479Sjb int i, rval; 2816178479Sjb dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE]; 2817178479Sjb hrtime_t now = gethrtime(); 2818178479Sjb 2819178479Sjb if (dtp->dt_lastswitch != 0) { 2820178479Sjb if (now - dtp->dt_lastswitch < interval) 2821178479Sjb return (0); 2822178479Sjb 2823178479Sjb dtp->dt_lastswitch += interval; 2824178479Sjb } else { 2825178479Sjb dtp->dt_lastswitch = now; 2826178479Sjb } 2827178479Sjb 2828178479Sjb if (!dtp->dt_active) 2829178479Sjb return (dt_set_errno(dtp, EINVAL)); 2830178479Sjb 2831178479Sjb if (max_ncpus == 0) 2832178479Sjb max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 2833178479Sjb 2834178479Sjb if (pf == NULL) 2835178479Sjb pf = (dtrace_consume_probe_f *)dt_nullprobe; 2836178479Sjb 2837178479Sjb if (rf == NULL) 2838178479Sjb rf = (dtrace_consume_rec_f *)dt_nullrec; 2839178479Sjb 2840250574Smarkj if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) { 2841250574Smarkj /* 2842250574Smarkj * The output will not be in the order it was traced. Rather, 2843250574Smarkj * we will consume all of the data from each CPU's buffer in 2844250574Smarkj * turn. We apply special handling for the records from BEGIN 2845250574Smarkj * and END probes so that they are consumed first and last, 2846250574Smarkj * respectively. 2847250574Smarkj * 2848250574Smarkj * If we have just begun, we want to first process the CPU that 2849250574Smarkj * executed the BEGIN probe (if any). 2850250574Smarkj */ 2851250574Smarkj if (dtp->dt_active && dtp->dt_beganon != -1 && 2852250574Smarkj (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0) 2853249573Spfg return (rval); 2854249573Spfg 2855250574Smarkj for (i = 0; i < max_ncpus; i++) { 2856250574Smarkj dtrace_bufdesc_t *buf; 2857249573Spfg 2858178479Sjb /* 2859250574Smarkj * If we have stopped, we want to process the CPU on 2860250574Smarkj * which the END probe was processed only _after_ we 2861250574Smarkj * have processed everything else. 2862178479Sjb */ 2863250574Smarkj if (dtp->dt_stopped && (i == dtp->dt_endedon)) 2864178479Sjb continue; 2865178479Sjb 2866250574Smarkj if (dt_get_buf(dtp, i, &buf) != 0) 2867250574Smarkj return (-1); 2868250574Smarkj if (buf == NULL) 2869250574Smarkj continue; 2870250574Smarkj 2871250574Smarkj dtp->dt_flow = 0; 2872250574Smarkj dtp->dt_indent = 0; 2873250574Smarkj dtp->dt_prefix = NULL; 2874250574Smarkj rval = dt_consume_cpu(dtp, fp, i, 2875250574Smarkj buf, B_FALSE, pf, rf, arg); 2876250574Smarkj dt_put_buf(dtp, buf); 2877250574Smarkj if (rval != 0) 2878250574Smarkj return (rval); 2879178479Sjb } 2880250574Smarkj if (dtp->dt_stopped) { 2881250574Smarkj dtrace_bufdesc_t *buf; 2882178479Sjb 2883250574Smarkj if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0) 2884250574Smarkj return (-1); 2885250574Smarkj if (buf == NULL) 2886250574Smarkj return (0); 2887250574Smarkj 2888250574Smarkj rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon, 2889250574Smarkj buf, B_FALSE, pf, rf, arg); 2890250574Smarkj dt_put_buf(dtp, buf); 2891178479Sjb return (rval); 2892250574Smarkj } 2893250574Smarkj } else { 2894250574Smarkj /* 2895250574Smarkj * The output will be in the order it was traced (or for 2896250574Smarkj * speculations, when it was committed). We retrieve a buffer 2897250574Smarkj * from each CPU and put it into a priority queue, which sorts 2898250574Smarkj * based on the first entry in the buffer. This is sufficient 2899250574Smarkj * because entries within a buffer are already sorted. 2900250574Smarkj * 2901250574Smarkj * We then consume records one at a time, always consuming the 2902250574Smarkj * oldest record, as determined by the priority queue. When 2903250574Smarkj * we reach the end of the time covered by these buffers, 2904250574Smarkj * we need to stop and retrieve more records on the next pass. 2905250574Smarkj * The kernel tells us the time covered by each buffer, in 2906250574Smarkj * dtbd_timestamp. The first buffer's timestamp tells us the 2907250574Smarkj * time covered by all buffers, as subsequently retrieved 2908250574Smarkj * buffers will cover to a more recent time. 2909250574Smarkj */ 2910178479Sjb 2911250574Smarkj uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t)); 2912250574Smarkj uint64_t first_timestamp = 0; 2913250574Smarkj uint_t cookie = 0; 2914250574Smarkj dtrace_bufdesc_t *buf; 2915178479Sjb 2916250574Smarkj bzero(drops, max_ncpus * sizeof (uint64_t)); 2917178479Sjb 2918250574Smarkj if (dtp->dt_bufq == NULL) { 2919250574Smarkj dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2, 2920250574Smarkj dt_buf_oldest, NULL); 2921250574Smarkj if (dtp->dt_bufq == NULL) /* ENOMEM */ 2922250574Smarkj return (-1); 2923250574Smarkj } 2924250574Smarkj 2925250574Smarkj /* Retrieve data from each CPU. */ 2926250574Smarkj (void) dtrace_getopt(dtp, "bufsize", &size); 2927250574Smarkj for (i = 0; i < max_ncpus; i++) { 2928250574Smarkj dtrace_bufdesc_t *buf; 2929250574Smarkj 2930250574Smarkj if (dt_get_buf(dtp, i, &buf) != 0) 2931250574Smarkj return (-1); 2932250574Smarkj if (buf != NULL) { 2933250574Smarkj if (first_timestamp == 0) 2934250574Smarkj first_timestamp = buf->dtbd_timestamp; 2935250574Smarkj assert(buf->dtbd_timestamp >= first_timestamp); 2936250574Smarkj 2937250574Smarkj dt_pq_insert(dtp->dt_bufq, buf); 2938250574Smarkj drops[i] = buf->dtbd_drops; 2939250574Smarkj buf->dtbd_drops = 0; 2940250574Smarkj } 2941250574Smarkj } 2942250574Smarkj 2943250574Smarkj /* Consume records. */ 2944250574Smarkj for (;;) { 2945250574Smarkj dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq); 2946250574Smarkj uint64_t timestamp; 2947250574Smarkj 2948250574Smarkj if (buf == NULL) 2949250574Smarkj break; 2950250574Smarkj 2951250574Smarkj timestamp = dt_buf_oldest(buf, dtp); 2952250574Smarkj assert(timestamp >= dtp->dt_last_timestamp); 2953250574Smarkj dtp->dt_last_timestamp = timestamp; 2954250574Smarkj 2955250574Smarkj if (timestamp == buf->dtbd_timestamp) { 2956250574Smarkj /* 2957250574Smarkj * We've reached the end of the time covered 2958250574Smarkj * by this buffer. If this is the oldest 2959250574Smarkj * buffer, we must do another pass 2960250574Smarkj * to retrieve more data. 2961250574Smarkj */ 2962250574Smarkj dt_put_buf(dtp, buf); 2963250574Smarkj if (timestamp == first_timestamp && 2964250574Smarkj !dtp->dt_stopped) 2965250574Smarkj break; 2966250574Smarkj continue; 2967250574Smarkj } 2968250574Smarkj 2969250574Smarkj if ((rval = dt_consume_cpu(dtp, fp, 2970250574Smarkj buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0) 2971250574Smarkj return (rval); 2972250574Smarkj dt_pq_insert(dtp->dt_bufq, buf); 2973250574Smarkj } 2974250574Smarkj 2975250574Smarkj /* Consume drops. */ 2976250574Smarkj for (i = 0; i < max_ncpus; i++) { 2977250574Smarkj if (drops[i] != 0) { 2978250574Smarkj int error = dt_handle_cpudrop(dtp, i, 2979250574Smarkj DTRACEDROP_PRINCIPAL, drops[i]); 2980250574Smarkj if (error != 0) 2981250574Smarkj return (error); 2982250574Smarkj } 2983250574Smarkj } 2984250574Smarkj 2985178479Sjb /* 2986250574Smarkj * Reduce memory usage by re-allocating smaller buffers 2987250574Smarkj * for the "remnants". 2988178479Sjb */ 2989250574Smarkj while (buf = dt_pq_walk(dtp->dt_bufq, &cookie)) 2990250574Smarkj dt_realloc_buf(dtp, buf, buf->dtbd_size); 2991178479Sjb } 2992178479Sjb 2993250574Smarkj return (0); 2994178479Sjb} 2995