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/* 27268578Srpaulo * Copyright (c) 2013, 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 62268578Srpaulostatic int 63268578Srpaulodt_ndigits(long long val) 64268578Srpaulo{ 65268578Srpaulo int rval = 1; 66268578Srpaulo long long cmp = 10; 67268578Srpaulo 68268578Srpaulo if (val < 0) { 69268578Srpaulo val = val == INT64_MIN ? INT64_MAX : -val; 70268578Srpaulo rval++; 71268578Srpaulo } 72268578Srpaulo 73268578Srpaulo while (val > cmp && cmp > 0) { 74268578Srpaulo rval++; 75268578Srpaulo cmp *= 10; 76268578Srpaulo } 77268578Srpaulo 78268578Srpaulo return (rval < 4 ? 4 : rval); 79268578Srpaulo} 80268578Srpaulo 81178479Sjb/* 82178479Sjb * 128-bit arithmetic functions needed to support the stddev() aggregating 83178479Sjb * action. 84178479Sjb */ 85178479Sjbstatic int 86178479Sjbdt_gt_128(uint64_t *a, uint64_t *b) 87178479Sjb{ 88178479Sjb return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0])); 89178479Sjb} 90178479Sjb 91178479Sjbstatic int 92178479Sjbdt_ge_128(uint64_t *a, uint64_t *b) 93178479Sjb{ 94178479Sjb return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0])); 95178479Sjb} 96178479Sjb 97178479Sjbstatic int 98178479Sjbdt_le_128(uint64_t *a, uint64_t *b) 99178479Sjb{ 100178479Sjb return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0])); 101178479Sjb} 102178479Sjb 103178479Sjb/* 104178479Sjb * Shift the 128-bit value in a by b. If b is positive, shift left. 105178479Sjb * If b is negative, shift right. 106178479Sjb */ 107178479Sjbstatic void 108178479Sjbdt_shift_128(uint64_t *a, int b) 109178479Sjb{ 110178479Sjb uint64_t mask; 111178479Sjb 112178479Sjb if (b == 0) 113178479Sjb return; 114178479Sjb 115178479Sjb if (b < 0) { 116178479Sjb b = -b; 117178479Sjb if (b >= 64) { 118178479Sjb a[0] = a[1] >> (b - 64); 119178479Sjb a[1] = 0; 120178479Sjb } else { 121178479Sjb a[0] >>= b; 122178479Sjb mask = 1LL << (64 - b); 123178479Sjb mask -= 1; 124178479Sjb a[0] |= ((a[1] & mask) << (64 - b)); 125178479Sjb a[1] >>= b; 126178479Sjb } 127178479Sjb } else { 128178479Sjb if (b >= 64) { 129178479Sjb a[1] = a[0] << (b - 64); 130178479Sjb a[0] = 0; 131178479Sjb } else { 132178479Sjb a[1] <<= b; 133178479Sjb mask = a[0] >> (64 - b); 134178479Sjb a[1] |= mask; 135178479Sjb a[0] <<= b; 136178479Sjb } 137178479Sjb } 138178479Sjb} 139178479Sjb 140178479Sjbstatic int 141178479Sjbdt_nbits_128(uint64_t *a) 142178479Sjb{ 143178479Sjb int nbits = 0; 144178479Sjb uint64_t tmp[2]; 145178479Sjb uint64_t zero[2] = { 0, 0 }; 146178479Sjb 147178479Sjb tmp[0] = a[0]; 148178479Sjb tmp[1] = a[1]; 149178479Sjb 150178479Sjb dt_shift_128(tmp, -1); 151178479Sjb while (dt_gt_128(tmp, zero)) { 152178479Sjb dt_shift_128(tmp, -1); 153178479Sjb nbits++; 154178479Sjb } 155178479Sjb 156178479Sjb return (nbits); 157178479Sjb} 158178479Sjb 159178479Sjbstatic void 160178479Sjbdt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference) 161178479Sjb{ 162178479Sjb uint64_t result[2]; 163178479Sjb 164178479Sjb result[0] = minuend[0] - subtrahend[0]; 165178479Sjb result[1] = minuend[1] - subtrahend[1] - 166178479Sjb (minuend[0] < subtrahend[0] ? 1 : 0); 167178479Sjb 168178479Sjb difference[0] = result[0]; 169178479Sjb difference[1] = result[1]; 170178479Sjb} 171178479Sjb 172178479Sjbstatic void 173178479Sjbdt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) 174178479Sjb{ 175178479Sjb uint64_t result[2]; 176178479Sjb 177178479Sjb result[0] = addend1[0] + addend2[0]; 178178479Sjb result[1] = addend1[1] + addend2[1] + 179178479Sjb (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); 180178479Sjb 181178479Sjb sum[0] = result[0]; 182178479Sjb sum[1] = result[1]; 183178479Sjb} 184178479Sjb 185178479Sjb/* 186178479Sjb * The basic idea is to break the 2 64-bit values into 4 32-bit values, 187178479Sjb * use native multiplication on those, and then re-combine into the 188178479Sjb * resulting 128-bit value. 189178479Sjb * 190178479Sjb * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) = 191178479Sjb * hi1 * hi2 << 64 + 192178479Sjb * hi1 * lo2 << 32 + 193178479Sjb * hi2 * lo1 << 32 + 194178479Sjb * lo1 * lo2 195178479Sjb */ 196178479Sjbstatic void 197178479Sjbdt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product) 198178479Sjb{ 199178479Sjb uint64_t hi1, hi2, lo1, lo2; 200178479Sjb uint64_t tmp[2]; 201178479Sjb 202178479Sjb hi1 = factor1 >> 32; 203178479Sjb hi2 = factor2 >> 32; 204178479Sjb 205178479Sjb lo1 = factor1 & DT_MASK_LO; 206178479Sjb lo2 = factor2 & DT_MASK_LO; 207178479Sjb 208178479Sjb product[0] = lo1 * lo2; 209178479Sjb product[1] = hi1 * hi2; 210178479Sjb 211178479Sjb tmp[0] = hi1 * lo2; 212178479Sjb tmp[1] = 0; 213178479Sjb dt_shift_128(tmp, 32); 214178479Sjb dt_add_128(product, tmp, product); 215178479Sjb 216178479Sjb tmp[0] = hi2 * lo1; 217178479Sjb tmp[1] = 0; 218178479Sjb dt_shift_128(tmp, 32); 219178479Sjb dt_add_128(product, tmp, product); 220178479Sjb} 221178479Sjb 222178479Sjb/* 223178479Sjb * This is long-hand division. 224178479Sjb * 225178479Sjb * We initialize subtrahend by shifting divisor left as far as possible. We 226178479Sjb * loop, comparing subtrahend to dividend: if subtrahend is smaller, we 227178479Sjb * subtract and set the appropriate bit in the result. We then shift 228178479Sjb * subtrahend right by one bit for the next comparison. 229178479Sjb */ 230178479Sjbstatic void 231178479Sjbdt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient) 232178479Sjb{ 233178479Sjb uint64_t result[2] = { 0, 0 }; 234178479Sjb uint64_t remainder[2]; 235178479Sjb uint64_t subtrahend[2]; 236178479Sjb uint64_t divisor_128[2]; 237178479Sjb uint64_t mask[2] = { 1, 0 }; 238178479Sjb int log = 0; 239178479Sjb 240178479Sjb assert(divisor != 0); 241178479Sjb 242178479Sjb divisor_128[0] = divisor; 243178479Sjb divisor_128[1] = 0; 244178479Sjb 245178479Sjb remainder[0] = dividend[0]; 246178479Sjb remainder[1] = dividend[1]; 247178479Sjb 248178479Sjb subtrahend[0] = divisor; 249178479Sjb subtrahend[1] = 0; 250178479Sjb 251178479Sjb while (divisor > 0) { 252178479Sjb log++; 253178479Sjb divisor >>= 1; 254178479Sjb } 255178479Sjb 256178479Sjb dt_shift_128(subtrahend, 128 - log); 257178479Sjb dt_shift_128(mask, 128 - log); 258178479Sjb 259178479Sjb while (dt_ge_128(remainder, divisor_128)) { 260178479Sjb if (dt_ge_128(remainder, subtrahend)) { 261178479Sjb dt_subtract_128(remainder, subtrahend, remainder); 262178479Sjb result[0] |= mask[0]; 263178479Sjb result[1] |= mask[1]; 264178479Sjb } 265178479Sjb 266178479Sjb dt_shift_128(subtrahend, -1); 267178479Sjb dt_shift_128(mask, -1); 268178479Sjb } 269178479Sjb 270178479Sjb quotient[0] = result[0]; 271178479Sjb quotient[1] = result[1]; 272178479Sjb} 273178479Sjb 274178479Sjb/* 275178479Sjb * This is the long-hand method of calculating a square root. 276178479Sjb * The algorithm is as follows: 277178479Sjb * 278178479Sjb * 1. Group the digits by 2 from the right. 279178479Sjb * 2. Over the leftmost group, find the largest single-digit number 280178479Sjb * whose square is less than that group. 281178479Sjb * 3. Subtract the result of the previous step (2 or 4, depending) and 282178479Sjb * bring down the next two-digit group. 283178479Sjb * 4. For the result R we have so far, find the largest single-digit number 284178479Sjb * x such that 2 * R * 10 * x + x^2 is less than the result from step 3. 285178479Sjb * (Note that this is doubling R and performing a decimal left-shift by 1 286178479Sjb * and searching for the appropriate decimal to fill the one's place.) 287178479Sjb * The value x is the next digit in the square root. 288178479Sjb * Repeat steps 3 and 4 until the desired precision is reached. (We're 289178479Sjb * dealing with integers, so the above is sufficient.) 290178479Sjb * 291178479Sjb * In decimal, the square root of 582,734 would be calculated as so: 292178479Sjb * 293178479Sjb * __7__6__3 294178479Sjb * | 58 27 34 295178479Sjb * -49 (7^2 == 49 => 7 is the first digit in the square root) 296178479Sjb * -- 297178479Sjb * 9 27 (Subtract and bring down the next group.) 298178479Sjb * 146 8 76 (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in 299178479Sjb * ----- the square root) 300178479Sjb * 51 34 (Subtract and bring down the next group.) 301178479Sjb * 1523 45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in 302178479Sjb * ----- the square root) 303178479Sjb * 5 65 (remainder) 304178479Sjb * 305178479Sjb * The above algorithm applies similarly in binary, but note that the 306178479Sjb * only possible non-zero value for x in step 4 is 1, so step 4 becomes a 307178479Sjb * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the 308178479Sjb * preceding difference? 309178479Sjb * 310178479Sjb * In binary, the square root of 11011011 would be calculated as so: 311178479Sjb * 312178479Sjb * __1__1__1__0 313178479Sjb * | 11 01 10 11 314178479Sjb * 01 (0 << 2 + 1 == 1 < 11 => this bit is 1) 315178479Sjb * -- 316178479Sjb * 10 01 10 11 317178479Sjb * 101 1 01 (1 << 2 + 1 == 101 < 1001 => next bit is 1) 318178479Sjb * ----- 319178479Sjb * 1 00 10 11 320178479Sjb * 1101 11 01 (11 << 2 + 1 == 1101 < 10010 => next bit is 1) 321178479Sjb * ------- 322178479Sjb * 1 01 11 323178479Sjb * 11101 1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0) 324178479Sjb * 325178479Sjb */ 326178479Sjbstatic uint64_t 327178479Sjbdt_sqrt_128(uint64_t *square) 328178479Sjb{ 329178479Sjb uint64_t result[2] = { 0, 0 }; 330178479Sjb uint64_t diff[2] = { 0, 0 }; 331178479Sjb uint64_t one[2] = { 1, 0 }; 332178479Sjb uint64_t next_pair[2]; 333178479Sjb uint64_t next_try[2]; 334178479Sjb uint64_t bit_pairs, pair_shift; 335178479Sjb int i; 336178479Sjb 337178479Sjb bit_pairs = dt_nbits_128(square) / 2; 338178479Sjb pair_shift = bit_pairs * 2; 339178479Sjb 340178479Sjb for (i = 0; i <= bit_pairs; i++) { 341178479Sjb /* 342178479Sjb * Bring down the next pair of bits. 343178479Sjb */ 344178479Sjb next_pair[0] = square[0]; 345178479Sjb next_pair[1] = square[1]; 346178479Sjb dt_shift_128(next_pair, -pair_shift); 347178479Sjb next_pair[0] &= 0x3; 348178479Sjb next_pair[1] = 0; 349178479Sjb 350178479Sjb dt_shift_128(diff, 2); 351178479Sjb dt_add_128(diff, next_pair, diff); 352178479Sjb 353178479Sjb /* 354178479Sjb * next_try = R << 2 + 1 355178479Sjb */ 356178479Sjb next_try[0] = result[0]; 357178479Sjb next_try[1] = result[1]; 358178479Sjb dt_shift_128(next_try, 2); 359178479Sjb dt_add_128(next_try, one, next_try); 360178479Sjb 361178479Sjb if (dt_le_128(next_try, diff)) { 362178479Sjb dt_subtract_128(diff, next_try, diff); 363178479Sjb dt_shift_128(result, 1); 364178479Sjb dt_add_128(result, one, result); 365178479Sjb } else { 366178479Sjb dt_shift_128(result, 1); 367178479Sjb } 368178479Sjb 369178479Sjb pair_shift -= 2; 370178479Sjb } 371178479Sjb 372178479Sjb assert(result[1] == 0); 373178479Sjb 374178479Sjb return (result[0]); 375178479Sjb} 376178479Sjb 377178479Sjbuint64_t 378178479Sjbdt_stddev(uint64_t *data, uint64_t normal) 379178479Sjb{ 380178479Sjb uint64_t avg_of_squares[2]; 381178479Sjb uint64_t square_of_avg[2]; 382178479Sjb int64_t norm_avg; 383178479Sjb uint64_t diff[2]; 384178479Sjb 385281472Smarkj if (data[0] == 0) 386281472Smarkj return (0); 387281472Smarkj 388178479Sjb /* 389178479Sjb * The standard approximation for standard deviation is 390178479Sjb * sqrt(average(x**2) - average(x)**2), i.e. the square root 391178479Sjb * of the average of the squares minus the square of the average. 392178479Sjb */ 393178479Sjb dt_divide_128(data + 2, normal, avg_of_squares); 394178479Sjb dt_divide_128(avg_of_squares, data[0], avg_of_squares); 395178479Sjb 396178479Sjb norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0]; 397178479Sjb 398178479Sjb if (norm_avg < 0) 399178479Sjb norm_avg = -norm_avg; 400178479Sjb 401178479Sjb dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg); 402178479Sjb 403178479Sjb dt_subtract_128(avg_of_squares, square_of_avg, diff); 404178479Sjb 405178479Sjb return (dt_sqrt_128(diff)); 406178479Sjb} 407178479Sjb 408178479Sjbstatic int 409178479Sjbdt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, 410178479Sjb dtrace_bufdesc_t *buf, size_t offs) 411178479Sjb{ 412178479Sjb dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; 413178479Sjb dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; 414178479Sjb char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub; 415178479Sjb dtrace_flowkind_t flow = DTRACEFLOW_NONE; 416178479Sjb const char *str = NULL; 417178479Sjb static const char *e_str[2] = { " -> ", " => " }; 418178479Sjb static const char *r_str[2] = { " <- ", " <= " }; 419178479Sjb static const char *ent = "entry", *ret = "return"; 420178479Sjb static int entlen = 0, retlen = 0; 421178479Sjb dtrace_epid_t next, id = epd->dtepd_epid; 422178479Sjb int rval; 423178479Sjb 424178479Sjb if (entlen == 0) { 425178479Sjb assert(retlen == 0); 426178479Sjb entlen = strlen(ent); 427178479Sjb retlen = strlen(ret); 428178479Sjb } 429178479Sjb 430178479Sjb /* 431178479Sjb * If the name of the probe is "entry" or ends with "-entry", we 432178479Sjb * treat it as an entry; if it is "return" or ends with "-return", 433178479Sjb * we treat it as a return. (This allows application-provided probes 434178479Sjb * like "method-entry" or "function-entry" to participate in flow 435178479Sjb * indentation -- without accidentally misinterpreting popular probe 436178479Sjb * names like "carpentry", "gentry" or "Coventry".) 437178479Sjb */ 438178479Sjb if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' && 439178479Sjb (sub == n || sub[-1] == '-')) { 440178479Sjb flow = DTRACEFLOW_ENTRY; 441178479Sjb str = e_str[strcmp(p, "syscall") == 0]; 442178479Sjb } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' && 443178479Sjb (sub == n || sub[-1] == '-')) { 444178479Sjb flow = DTRACEFLOW_RETURN; 445178479Sjb str = r_str[strcmp(p, "syscall") == 0]; 446178479Sjb } 447178479Sjb 448178479Sjb /* 449178479Sjb * If we're going to indent this, we need to check the ID of our last 450178479Sjb * call. If we're looking at the same probe ID but a different EPID, 451178479Sjb * we _don't_ want to indent. (Yes, there are some minor holes in 452178479Sjb * this scheme -- it's a heuristic.) 453178479Sjb */ 454178479Sjb if (flow == DTRACEFLOW_ENTRY) { 455178479Sjb if ((last != DTRACE_EPIDNONE && id != last && 456178479Sjb pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) 457178479Sjb flow = DTRACEFLOW_NONE; 458178479Sjb } 459178479Sjb 460178479Sjb /* 461178479Sjb * If we're going to unindent this, it's more difficult to see if 462178479Sjb * we don't actually want to unindent it -- we need to look at the 463178479Sjb * _next_ EPID. 464178479Sjb */ 465178479Sjb if (flow == DTRACEFLOW_RETURN) { 466178479Sjb offs += epd->dtepd_size; 467178479Sjb 468178479Sjb do { 469250574Smarkj if (offs >= buf->dtbd_size) 470250574Smarkj goto out; 471178479Sjb 472178479Sjb next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 473178479Sjb 474178479Sjb if (next == DTRACE_EPIDNONE) 475178479Sjb offs += sizeof (id); 476178479Sjb } while (next == DTRACE_EPIDNONE); 477178479Sjb 478178479Sjb if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) 479178479Sjb return (rval); 480178479Sjb 481178479Sjb if (next != id && npd->dtpd_id == pd->dtpd_id) 482178479Sjb flow = DTRACEFLOW_NONE; 483178479Sjb } 484178479Sjb 485178479Sjbout: 486178479Sjb if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { 487178479Sjb data->dtpda_prefix = str; 488178479Sjb } else { 489178479Sjb data->dtpda_prefix = "| "; 490178479Sjb } 491178479Sjb 492178479Sjb if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) 493178479Sjb data->dtpda_indent -= 2; 494178479Sjb 495178479Sjb data->dtpda_flow = flow; 496178479Sjb 497178479Sjb return (0); 498178479Sjb} 499178479Sjb 500178479Sjbstatic int 501178479Sjbdt_nullprobe() 502178479Sjb{ 503178479Sjb return (DTRACE_CONSUME_THIS); 504178479Sjb} 505178479Sjb 506178479Sjbstatic int 507178479Sjbdt_nullrec() 508178479Sjb{ 509178479Sjb return (DTRACE_CONSUME_NEXT); 510178479Sjb} 511178479Sjb 512268578Srpaulostatic void 513268578Srpaulodt_quantize_total(dtrace_hdl_t *dtp, int64_t datum, long double *total) 514268578Srpaulo{ 515268578Srpaulo long double val = dt_fabsl((long double)datum); 516268578Srpaulo 517268578Srpaulo if (dtp->dt_options[DTRACEOPT_AGGZOOM] == DTRACEOPT_UNSET) { 518268578Srpaulo *total += val; 519268578Srpaulo return; 520268578Srpaulo } 521268578Srpaulo 522268578Srpaulo /* 523268578Srpaulo * If we're zooming in on an aggregation, we want the height of the 524268578Srpaulo * highest value to be approximately 95% of total bar height -- so we 525268578Srpaulo * adjust up by the reciprocal of DTRACE_AGGZOOM_MAX when comparing to 526268578Srpaulo * our highest value. 527268578Srpaulo */ 528268578Srpaulo val *= 1 / DTRACE_AGGZOOM_MAX; 529268578Srpaulo 530268578Srpaulo if (*total < val) 531268578Srpaulo *total = val; 532268578Srpaulo} 533268578Srpaulo 534268578Srpaulostatic int 535268578Srpaulodt_print_quanthdr(dtrace_hdl_t *dtp, FILE *fp, int width) 536268578Srpaulo{ 537268578Srpaulo return (dt_printf(dtp, fp, "\n%*s %41s %-9s\n", 538268578Srpaulo width ? width : 16, width ? "key" : "value", 539268578Srpaulo "------------- Distribution -------------", "count")); 540268578Srpaulo} 541268578Srpaulo 542268578Srpaulostatic int 543268578Srpaulodt_print_quanthdr_packed(dtrace_hdl_t *dtp, FILE *fp, int width, 544268578Srpaulo const dtrace_aggdata_t *aggdata, dtrace_actkind_t action) 545268578Srpaulo{ 546268578Srpaulo int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin; 547268578Srpaulo int minwidth, maxwidth, i; 548268578Srpaulo 549268578Srpaulo assert(action == DTRACEAGG_QUANTIZE || action == DTRACEAGG_LQUANTIZE); 550268578Srpaulo 551268578Srpaulo if (action == DTRACEAGG_QUANTIZE) { 552268578Srpaulo if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET) 553268578Srpaulo min--; 554268578Srpaulo 555268578Srpaulo if (max < DTRACE_QUANTIZE_NBUCKETS - 1) 556268578Srpaulo max++; 557268578Srpaulo 558268578Srpaulo minwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(min)); 559268578Srpaulo maxwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(max)); 560268578Srpaulo } else { 561268578Srpaulo maxwidth = 8; 562268578Srpaulo minwidth = maxwidth - 1; 563268578Srpaulo max++; 564268578Srpaulo } 565268578Srpaulo 566268578Srpaulo if (dt_printf(dtp, fp, "\n%*s %*s .", 567268578Srpaulo width, width > 0 ? "key" : "", minwidth, "min") < 0) 568268578Srpaulo return (-1); 569268578Srpaulo 570268578Srpaulo for (i = min; i <= max; i++) { 571268578Srpaulo if (dt_printf(dtp, fp, "-") < 0) 572268578Srpaulo return (-1); 573268578Srpaulo } 574268578Srpaulo 575268578Srpaulo return (dt_printf(dtp, fp, ". %*s | count\n", -maxwidth, "max")); 576268578Srpaulo} 577268578Srpaulo 578268578Srpaulo/* 579268578Srpaulo * We use a subset of the Unicode Block Elements (U+2588 through U+258F, 580268578Srpaulo * inclusive) to represent aggregations via UTF-8 -- which are expressed via 581268578Srpaulo * 3-byte UTF-8 sequences. 582268578Srpaulo */ 583268578Srpaulo#define DTRACE_AGGUTF8_FULL 0x2588 584268578Srpaulo#define DTRACE_AGGUTF8_BASE 0x258f 585268578Srpaulo#define DTRACE_AGGUTF8_LEVELS 8 586268578Srpaulo 587268578Srpaulo#define DTRACE_AGGUTF8_BYTE0(val) (0xe0 | ((val) >> 12)) 588268578Srpaulo#define DTRACE_AGGUTF8_BYTE1(val) (0x80 | (((val) >> 6) & 0x3f)) 589268578Srpaulo#define DTRACE_AGGUTF8_BYTE2(val) (0x80 | ((val) & 0x3f)) 590268578Srpaulo 591268578Srpaulostatic int 592268578Srpaulodt_print_quantline_utf8(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 593268578Srpaulo uint64_t normal, long double total) 594268578Srpaulo{ 595268578Srpaulo uint_t len = 40, i, whole, partial; 596268578Srpaulo long double f = (dt_fabsl((long double)val) * len) / total; 597268578Srpaulo const char *spaces = " "; 598268578Srpaulo 599268578Srpaulo whole = (uint_t)f; 600268578Srpaulo partial = (uint_t)((f - (long double)(uint_t)f) * 601268578Srpaulo (long double)DTRACE_AGGUTF8_LEVELS); 602268578Srpaulo 603268578Srpaulo if (dt_printf(dtp, fp, "|") < 0) 604268578Srpaulo return (-1); 605268578Srpaulo 606268578Srpaulo for (i = 0; i < whole; i++) { 607268578Srpaulo if (dt_printf(dtp, fp, "%c%c%c", 608268578Srpaulo DTRACE_AGGUTF8_BYTE0(DTRACE_AGGUTF8_FULL), 609268578Srpaulo DTRACE_AGGUTF8_BYTE1(DTRACE_AGGUTF8_FULL), 610268578Srpaulo DTRACE_AGGUTF8_BYTE2(DTRACE_AGGUTF8_FULL)) < 0) 611268578Srpaulo return (-1); 612268578Srpaulo } 613268578Srpaulo 614268578Srpaulo if (partial != 0) { 615268578Srpaulo partial = DTRACE_AGGUTF8_BASE - (partial - 1); 616268578Srpaulo 617268578Srpaulo if (dt_printf(dtp, fp, "%c%c%c", 618268578Srpaulo DTRACE_AGGUTF8_BYTE0(partial), 619268578Srpaulo DTRACE_AGGUTF8_BYTE1(partial), 620268578Srpaulo DTRACE_AGGUTF8_BYTE2(partial)) < 0) 621268578Srpaulo return (-1); 622268578Srpaulo 623268578Srpaulo i++; 624268578Srpaulo } 625268578Srpaulo 626268578Srpaulo return (dt_printf(dtp, fp, "%s %-9lld\n", spaces + i, 627268578Srpaulo (long long)val / normal)); 628268578Srpaulo} 629268578Srpaulo 630268578Srpaulostatic int 631178479Sjbdt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 632178479Sjb uint64_t normal, long double total, char positives, char negatives) 633178479Sjb{ 634178479Sjb long double f; 635178479Sjb uint_t depth, len = 40; 636178479Sjb 637178479Sjb const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; 638178479Sjb const char *spaces = " "; 639178479Sjb 640178479Sjb assert(strlen(ats) == len && strlen(spaces) == len); 641178479Sjb assert(!(total == 0 && (positives || negatives))); 642178479Sjb assert(!(val < 0 && !negatives)); 643178479Sjb assert(!(val > 0 && !positives)); 644178479Sjb assert(!(val != 0 && total == 0)); 645178479Sjb 646178479Sjb if (!negatives) { 647178479Sjb if (positives) { 648268578Srpaulo if (dtp->dt_encoding == DT_ENCODING_UTF8) { 649268578Srpaulo return (dt_print_quantline_utf8(dtp, fp, val, 650268578Srpaulo normal, total)); 651268578Srpaulo } 652268578Srpaulo 653178479Sjb f = (dt_fabsl((long double)val) * len) / total; 654178479Sjb depth = (uint_t)(f + 0.5); 655178479Sjb } else { 656178479Sjb depth = 0; 657178479Sjb } 658178479Sjb 659178479Sjb return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth, 660178479Sjb spaces + depth, (long long)val / normal)); 661178479Sjb } 662178479Sjb 663178479Sjb if (!positives) { 664178479Sjb f = (dt_fabsl((long double)val) * len) / total; 665178479Sjb depth = (uint_t)(f + 0.5); 666178479Sjb 667178479Sjb return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth, 668178479Sjb ats + len - depth, (long long)val / normal)); 669178479Sjb } 670178479Sjb 671178479Sjb /* 672178479Sjb * If we're here, we have both positive and negative bucket values. 673178479Sjb * To express this graphically, we're going to generate both positive 674178479Sjb * and negative bars separated by a centerline. These bars are half 675178479Sjb * the size of normal quantize()/lquantize() bars, so we divide the 676178479Sjb * length in half before calculating the bar length. 677178479Sjb */ 678178479Sjb len /= 2; 679178479Sjb ats = &ats[len]; 680178479Sjb spaces = &spaces[len]; 681178479Sjb 682178479Sjb f = (dt_fabsl((long double)val) * len) / total; 683178479Sjb depth = (uint_t)(f + 0.5); 684178479Sjb 685178479Sjb if (val <= 0) { 686178479Sjb return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth, 687178479Sjb ats + len - depth, len, "", (long long)val / normal)); 688178479Sjb } else { 689178479Sjb return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "", 690178479Sjb ats + len - depth, spaces + depth, 691178479Sjb (long long)val / normal)); 692178479Sjb } 693178479Sjb} 694178479Sjb 695268578Srpaulo/* 696268578Srpaulo * As with UTF-8 printing of aggregations, we use a subset of the Unicode 697268578Srpaulo * Block Elements (U+2581 through U+2588, inclusive) to represent our packed 698268578Srpaulo * aggregation. 699268578Srpaulo */ 700268578Srpaulo#define DTRACE_AGGPACK_BASE 0x2581 701268578Srpaulo#define DTRACE_AGGPACK_LEVELS 8 702268578Srpaulo 703268578Srpaulostatic int 704268578Srpaulodt_print_packed(dtrace_hdl_t *dtp, FILE *fp, 705268578Srpaulo long double datum, long double total) 706268578Srpaulo{ 707268578Srpaulo static boolean_t utf8_checked = B_FALSE; 708268578Srpaulo static boolean_t utf8; 709268578Srpaulo char *ascii = "__xxxxXX"; 710268578Srpaulo char *neg = "vvvvVV"; 711268578Srpaulo unsigned int len; 712268578Srpaulo long double val; 713268578Srpaulo 714268578Srpaulo if (!utf8_checked) { 715268578Srpaulo char *term; 716268578Srpaulo 717268578Srpaulo /* 718268578Srpaulo * We want to determine if we can reasonably emit UTF-8 for our 719268578Srpaulo * packed aggregation. To do this, we will check for terminals 720268578Srpaulo * that are known to be primitive to emit UTF-8 on these. 721268578Srpaulo */ 722268578Srpaulo utf8_checked = B_TRUE; 723268578Srpaulo 724268578Srpaulo if (dtp->dt_encoding == DT_ENCODING_ASCII) { 725268578Srpaulo utf8 = B_FALSE; 726268578Srpaulo } else if (dtp->dt_encoding == DT_ENCODING_UTF8) { 727268578Srpaulo utf8 = B_TRUE; 728268578Srpaulo } else if ((term = getenv("TERM")) != NULL && 729268578Srpaulo (strcmp(term, "sun") == 0 || 730281473Smarkj strcmp(term, "sun-color") == 0 || 731281473Smarkj strcmp(term, "dumb") == 0)) { 732268578Srpaulo utf8 = B_FALSE; 733268578Srpaulo } else { 734268578Srpaulo utf8 = B_TRUE; 735268578Srpaulo } 736268578Srpaulo } 737268578Srpaulo 738268578Srpaulo if (datum == 0) 739268578Srpaulo return (dt_printf(dtp, fp, " ")); 740268578Srpaulo 741268578Srpaulo if (datum < 0) { 742268578Srpaulo len = strlen(neg); 743268578Srpaulo val = dt_fabsl(datum * (len - 1)) / total; 744268578Srpaulo return (dt_printf(dtp, fp, "%c", neg[(uint_t)(val + 0.5)])); 745268578Srpaulo } 746268578Srpaulo 747268578Srpaulo if (utf8) { 748268578Srpaulo int block = DTRACE_AGGPACK_BASE + (unsigned int)(((datum * 749268578Srpaulo (DTRACE_AGGPACK_LEVELS - 1)) / total) + 0.5); 750268578Srpaulo 751268578Srpaulo return (dt_printf(dtp, fp, "%c%c%c", 752268578Srpaulo DTRACE_AGGUTF8_BYTE0(block), 753268578Srpaulo DTRACE_AGGUTF8_BYTE1(block), 754268578Srpaulo DTRACE_AGGUTF8_BYTE2(block))); 755268578Srpaulo } 756268578Srpaulo 757268578Srpaulo len = strlen(ascii); 758268578Srpaulo val = (datum * (len - 1)) / total; 759268578Srpaulo return (dt_printf(dtp, fp, "%c", ascii[(uint_t)(val + 0.5)])); 760268578Srpaulo} 761268578Srpaulo 762178479Sjbint 763178479Sjbdt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 764178479Sjb size_t size, uint64_t normal) 765178479Sjb{ 766178479Sjb const int64_t *data = addr; 767178479Sjb int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; 768178479Sjb long double total = 0; 769178479Sjb char positives = 0, negatives = 0; 770178479Sjb 771178479Sjb if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 772178479Sjb return (dt_set_errno(dtp, EDT_DMISMATCH)); 773178479Sjb 774178479Sjb while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) 775178479Sjb first_bin++; 776178479Sjb 777178479Sjb if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) { 778178479Sjb /* 779268578Srpaulo * There isn't any data. This is possible if the aggregation 780268578Srpaulo * has been clear()'d or if negative increment values have been 781268578Srpaulo * used. Regardless, we'll print the buckets around 0. 782178479Sjb */ 783178479Sjb first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1; 784178479Sjb last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1; 785178479Sjb } else { 786178479Sjb if (first_bin > 0) 787178479Sjb first_bin--; 788178479Sjb 789178479Sjb while (last_bin > 0 && data[last_bin] == 0) 790178479Sjb last_bin--; 791178479Sjb 792178479Sjb if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) 793178479Sjb last_bin++; 794178479Sjb } 795178479Sjb 796178479Sjb for (i = first_bin; i <= last_bin; i++) { 797178479Sjb positives |= (data[i] > 0); 798178479Sjb negatives |= (data[i] < 0); 799268578Srpaulo dt_quantize_total(dtp, data[i], &total); 800178479Sjb } 801178479Sjb 802268578Srpaulo if (dt_print_quanthdr(dtp, fp, 0) < 0) 803178479Sjb return (-1); 804178479Sjb 805178479Sjb for (i = first_bin; i <= last_bin; i++) { 806178479Sjb if (dt_printf(dtp, fp, "%16lld ", 807178479Sjb (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0) 808178479Sjb return (-1); 809178479Sjb 810178479Sjb if (dt_print_quantline(dtp, fp, data[i], normal, total, 811178479Sjb positives, negatives) < 0) 812178479Sjb return (-1); 813178479Sjb } 814178479Sjb 815178479Sjb return (0); 816178479Sjb} 817178479Sjb 818178479Sjbint 819268578Srpaulodt_print_quantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 820268578Srpaulo size_t size, const dtrace_aggdata_t *aggdata) 821268578Srpaulo{ 822268578Srpaulo const int64_t *data = addr; 823268578Srpaulo long double total = 0, count = 0; 824268578Srpaulo int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin, i; 825268578Srpaulo int64_t minval, maxval; 826268578Srpaulo 827268578Srpaulo if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 828268578Srpaulo return (dt_set_errno(dtp, EDT_DMISMATCH)); 829268578Srpaulo 830268578Srpaulo if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET) 831268578Srpaulo min--; 832268578Srpaulo 833268578Srpaulo if (max < DTRACE_QUANTIZE_NBUCKETS - 1) 834268578Srpaulo max++; 835268578Srpaulo 836268578Srpaulo minval = DTRACE_QUANTIZE_BUCKETVAL(min); 837268578Srpaulo maxval = DTRACE_QUANTIZE_BUCKETVAL(max); 838268578Srpaulo 839268578Srpaulo if (dt_printf(dtp, fp, " %*lld :", dt_ndigits(minval), 840268578Srpaulo (long long)minval) < 0) 841268578Srpaulo return (-1); 842268578Srpaulo 843268578Srpaulo for (i = min; i <= max; i++) { 844268578Srpaulo dt_quantize_total(dtp, data[i], &total); 845268578Srpaulo count += data[i]; 846268578Srpaulo } 847268578Srpaulo 848268578Srpaulo for (i = min; i <= max; i++) { 849268578Srpaulo if (dt_print_packed(dtp, fp, data[i], total) < 0) 850268578Srpaulo return (-1); 851268578Srpaulo } 852268578Srpaulo 853268578Srpaulo if (dt_printf(dtp, fp, ": %*lld | %lld\n", 854268578Srpaulo -dt_ndigits(maxval), (long long)maxval, (long long)count) < 0) 855268578Srpaulo return (-1); 856268578Srpaulo 857268578Srpaulo return (0); 858268578Srpaulo} 859268578Srpaulo 860268578Srpauloint 861178479Sjbdt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 862178479Sjb size_t size, uint64_t normal) 863178479Sjb{ 864178479Sjb const int64_t *data = addr; 865178479Sjb int i, first_bin, last_bin, base; 866178479Sjb uint64_t arg; 867178479Sjb long double total = 0; 868178479Sjb uint16_t step, levels; 869178479Sjb char positives = 0, negatives = 0; 870178479Sjb 871178479Sjb if (size < sizeof (uint64_t)) 872178479Sjb return (dt_set_errno(dtp, EDT_DMISMATCH)); 873178479Sjb 874178479Sjb arg = *data++; 875178479Sjb size -= sizeof (uint64_t); 876178479Sjb 877178479Sjb base = DTRACE_LQUANTIZE_BASE(arg); 878178479Sjb step = DTRACE_LQUANTIZE_STEP(arg); 879178479Sjb levels = DTRACE_LQUANTIZE_LEVELS(arg); 880178479Sjb 881178479Sjb first_bin = 0; 882178479Sjb last_bin = levels + 1; 883178479Sjb 884178479Sjb if (size != sizeof (uint64_t) * (levels + 2)) 885178479Sjb return (dt_set_errno(dtp, EDT_DMISMATCH)); 886178479Sjb 887178479Sjb while (first_bin <= levels + 1 && data[first_bin] == 0) 888178479Sjb first_bin++; 889178479Sjb 890178479Sjb if (first_bin > levels + 1) { 891178479Sjb first_bin = 0; 892178479Sjb last_bin = 2; 893178479Sjb } else { 894178479Sjb if (first_bin > 0) 895178479Sjb first_bin--; 896178479Sjb 897178479Sjb while (last_bin > 0 && data[last_bin] == 0) 898178479Sjb last_bin--; 899178479Sjb 900178479Sjb if (last_bin < levels + 1) 901178479Sjb last_bin++; 902178479Sjb } 903178479Sjb 904178479Sjb for (i = first_bin; i <= last_bin; i++) { 905178479Sjb positives |= (data[i] > 0); 906178479Sjb negatives |= (data[i] < 0); 907268578Srpaulo dt_quantize_total(dtp, data[i], &total); 908178479Sjb } 909178479Sjb 910178479Sjb if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 911178479Sjb "------------- Distribution -------------", "count") < 0) 912178479Sjb return (-1); 913178479Sjb 914178479Sjb for (i = first_bin; i <= last_bin; i++) { 915178479Sjb char c[32]; 916178479Sjb int err; 917178479Sjb 918178479Sjb if (i == 0) { 919268578Srpaulo (void) snprintf(c, sizeof (c), "< %d", base); 920178479Sjb err = dt_printf(dtp, fp, "%16s ", c); 921178479Sjb } else if (i == levels + 1) { 922178479Sjb (void) snprintf(c, sizeof (c), ">= %d", 923178479Sjb base + (levels * step)); 924178479Sjb err = dt_printf(dtp, fp, "%16s ", c); 925178479Sjb } else { 926178479Sjb err = dt_printf(dtp, fp, "%16d ", 927178479Sjb base + (i - 1) * step); 928178479Sjb } 929178479Sjb 930178479Sjb if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal, 931178479Sjb total, positives, negatives) < 0) 932178479Sjb return (-1); 933178479Sjb } 934178479Sjb 935178479Sjb return (0); 936178479Sjb} 937178479Sjb 938268578Srpaulo/*ARGSUSED*/ 939237624Spfgint 940268578Srpaulodt_print_lquantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 941268578Srpaulo size_t size, const dtrace_aggdata_t *aggdata) 942268578Srpaulo{ 943268578Srpaulo const int64_t *data = addr; 944268578Srpaulo long double total = 0, count = 0; 945268578Srpaulo int min, max, base, err; 946268578Srpaulo uint64_t arg; 947268578Srpaulo uint16_t step, levels; 948268578Srpaulo char c[32]; 949268578Srpaulo unsigned int i; 950268578Srpaulo 951268578Srpaulo if (size < sizeof (uint64_t)) 952268578Srpaulo return (dt_set_errno(dtp, EDT_DMISMATCH)); 953268578Srpaulo 954268578Srpaulo arg = *data++; 955268578Srpaulo size -= sizeof (uint64_t); 956268578Srpaulo 957268578Srpaulo base = DTRACE_LQUANTIZE_BASE(arg); 958268578Srpaulo step = DTRACE_LQUANTIZE_STEP(arg); 959268578Srpaulo levels = DTRACE_LQUANTIZE_LEVELS(arg); 960268578Srpaulo 961268578Srpaulo if (size != sizeof (uint64_t) * (levels + 2)) 962268578Srpaulo return (dt_set_errno(dtp, EDT_DMISMATCH)); 963268578Srpaulo 964268578Srpaulo min = 0; 965268578Srpaulo max = levels + 1; 966268578Srpaulo 967268578Srpaulo if (min == 0) { 968268578Srpaulo (void) snprintf(c, sizeof (c), "< %d", base); 969268578Srpaulo err = dt_printf(dtp, fp, "%8s :", c); 970268578Srpaulo } else { 971268578Srpaulo err = dt_printf(dtp, fp, "%8d :", base + (min - 1) * step); 972268578Srpaulo } 973268578Srpaulo 974268578Srpaulo if (err < 0) 975268578Srpaulo return (-1); 976268578Srpaulo 977268578Srpaulo for (i = min; i <= max; i++) { 978268578Srpaulo dt_quantize_total(dtp, data[i], &total); 979268578Srpaulo count += data[i]; 980268578Srpaulo } 981268578Srpaulo 982268578Srpaulo for (i = min; i <= max; i++) { 983268578Srpaulo if (dt_print_packed(dtp, fp, data[i], total) < 0) 984268578Srpaulo return (-1); 985268578Srpaulo } 986268578Srpaulo 987268578Srpaulo (void) snprintf(c, sizeof (c), ">= %d", base + (levels * step)); 988268578Srpaulo return (dt_printf(dtp, fp, ": %-8s | %lld\n", c, (long long)count)); 989268578Srpaulo} 990268578Srpaulo 991268578Srpauloint 992237624Spfgdt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 993237624Spfg size_t size, uint64_t normal) 994237624Spfg{ 995237624Spfg int i, first_bin, last_bin, bin = 1, order, levels; 996237624Spfg uint16_t factor, low, high, nsteps; 997237624Spfg const int64_t *data = addr; 998237624Spfg int64_t value = 1, next, step; 999237624Spfg char positives = 0, negatives = 0; 1000237624Spfg long double total = 0; 1001237624Spfg uint64_t arg; 1002237624Spfg char c[32]; 1003237624Spfg 1004237624Spfg if (size < sizeof (uint64_t)) 1005237624Spfg return (dt_set_errno(dtp, EDT_DMISMATCH)); 1006237624Spfg 1007237624Spfg arg = *data++; 1008237624Spfg size -= sizeof (uint64_t); 1009237624Spfg 1010237624Spfg factor = DTRACE_LLQUANTIZE_FACTOR(arg); 1011237624Spfg low = DTRACE_LLQUANTIZE_LOW(arg); 1012237624Spfg high = DTRACE_LLQUANTIZE_HIGH(arg); 1013237624Spfg nsteps = DTRACE_LLQUANTIZE_NSTEP(arg); 1014237624Spfg 1015237624Spfg /* 1016237624Spfg * We don't expect to be handed invalid llquantize() parameters here, 1017237624Spfg * but sanity check them (to a degree) nonetheless. 1018237624Spfg */ 1019237624Spfg if (size > INT32_MAX || factor < 2 || low >= high || 1020237624Spfg nsteps == 0 || factor > nsteps) 1021237624Spfg return (dt_set_errno(dtp, EDT_DMISMATCH)); 1022237624Spfg 1023237624Spfg levels = (int)size / sizeof (uint64_t); 1024237624Spfg 1025237624Spfg first_bin = 0; 1026237624Spfg last_bin = levels - 1; 1027237624Spfg 1028237624Spfg while (first_bin < levels && data[first_bin] == 0) 1029237624Spfg first_bin++; 1030237624Spfg 1031237624Spfg if (first_bin == levels) { 1032237624Spfg first_bin = 0; 1033237624Spfg last_bin = 1; 1034237624Spfg } else { 1035237624Spfg if (first_bin > 0) 1036237624Spfg first_bin--; 1037237624Spfg 1038237624Spfg while (last_bin > 0 && data[last_bin] == 0) 1039237624Spfg last_bin--; 1040237624Spfg 1041237624Spfg if (last_bin < levels - 1) 1042237624Spfg last_bin++; 1043237624Spfg } 1044237624Spfg 1045237624Spfg for (i = first_bin; i <= last_bin; i++) { 1046237624Spfg positives |= (data[i] > 0); 1047237624Spfg negatives |= (data[i] < 0); 1048268578Srpaulo dt_quantize_total(dtp, data[i], &total); 1049237624Spfg } 1050237624Spfg 1051237624Spfg if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 1052237624Spfg "------------- Distribution -------------", "count") < 0) 1053237624Spfg return (-1); 1054237624Spfg 1055237624Spfg for (order = 0; order < low; order++) 1056237624Spfg value *= factor; 1057237624Spfg 1058237624Spfg next = value * factor; 1059237624Spfg step = next > nsteps ? next / nsteps : 1; 1060237624Spfg 1061237624Spfg if (first_bin == 0) { 1062237716Spfg (void) snprintf(c, sizeof (c), "< %lld", (long long)value); 1063237624Spfg 1064237624Spfg if (dt_printf(dtp, fp, "%16s ", c) < 0) 1065237624Spfg return (-1); 1066237624Spfg 1067237624Spfg if (dt_print_quantline(dtp, fp, data[0], normal, 1068237624Spfg total, positives, negatives) < 0) 1069237624Spfg return (-1); 1070237624Spfg } 1071237624Spfg 1072237624Spfg while (order <= high) { 1073237624Spfg if (bin >= first_bin && bin <= last_bin) { 1074237624Spfg if (dt_printf(dtp, fp, "%16lld ", (long long)value) < 0) 1075237624Spfg return (-1); 1076237624Spfg 1077237624Spfg if (dt_print_quantline(dtp, fp, data[bin], 1078237624Spfg normal, total, positives, negatives) < 0) 1079237624Spfg return (-1); 1080237624Spfg } 1081237624Spfg 1082237624Spfg assert(value < next); 1083237624Spfg bin++; 1084237624Spfg 1085237624Spfg if ((value += step) != next) 1086237624Spfg continue; 1087237624Spfg 1088237624Spfg next = value * factor; 1089237624Spfg step = next > nsteps ? next / nsteps : 1; 1090237624Spfg order++; 1091237624Spfg } 1092237624Spfg 1093237624Spfg if (last_bin < bin) 1094237624Spfg return (0); 1095237624Spfg 1096237624Spfg assert(last_bin == bin); 1097238071Sdim (void) snprintf(c, sizeof (c), ">= %lld", (long long)value); 1098237624Spfg 1099237624Spfg if (dt_printf(dtp, fp, "%16s ", c) < 0) 1100237624Spfg return (-1); 1101237624Spfg 1102237624Spfg return (dt_print_quantline(dtp, fp, data[bin], normal, 1103237624Spfg total, positives, negatives)); 1104237624Spfg} 1105237624Spfg 1106178479Sjb/*ARGSUSED*/ 1107178479Sjbstatic int 1108178479Sjbdt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 1109178479Sjb size_t size, uint64_t normal) 1110178479Sjb{ 1111178479Sjb /* LINTED - alignment */ 1112178479Sjb int64_t *data = (int64_t *)addr; 1113178479Sjb 1114178479Sjb return (dt_printf(dtp, fp, " %16lld", data[0] ? 1115178479Sjb (long long)(data[1] / (int64_t)normal / data[0]) : 0)); 1116178479Sjb} 1117178479Sjb 1118178479Sjb/*ARGSUSED*/ 1119178479Sjbstatic int 1120178479Sjbdt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 1121178479Sjb size_t size, uint64_t normal) 1122178479Sjb{ 1123178479Sjb /* LINTED - alignment */ 1124178479Sjb uint64_t *data = (uint64_t *)addr; 1125178479Sjb 1126178479Sjb return (dt_printf(dtp, fp, " %16llu", data[0] ? 1127178479Sjb (unsigned long long) dt_stddev(data, normal) : 0)); 1128178479Sjb} 1129178479Sjb 1130178479Sjb/*ARGSUSED*/ 1131268578Srpaulostatic int 1132178479Sjbdt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 1133248690Spfg size_t nbytes, int width, int quiet, int forceraw) 1134178479Sjb{ 1135178479Sjb /* 1136178479Sjb * If the byte stream is a series of printable characters, followed by 1137178479Sjb * a terminating byte, we print it out as a string. Otherwise, we 1138178479Sjb * assume that it's something else and just print the bytes. 1139178479Sjb */ 1140178479Sjb int i, j, margin = 5; 1141178479Sjb char *c = (char *)addr; 1142178479Sjb 1143178479Sjb if (nbytes == 0) 1144178479Sjb return (0); 1145178479Sjb 1146248690Spfg if (forceraw) 1147178479Sjb goto raw; 1148178479Sjb 1149248690Spfg if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) 1150248690Spfg goto raw; 1151248690Spfg 1152178479Sjb for (i = 0; i < nbytes; i++) { 1153178479Sjb /* 1154178479Sjb * We define a "printable character" to be one for which 1155178479Sjb * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 1156178479Sjb * or a character which is either backspace or the bell. 1157178479Sjb * Backspace and the bell are regrettably special because 1158178479Sjb * they fail the first two tests -- and yet they are entirely 1159178479Sjb * printable. These are the only two control characters that 1160178479Sjb * have meaning for the terminal and for which isprint(3C) and 1161178479Sjb * isspace(3C) return 0. 1162178479Sjb */ 1163178479Sjb if (isprint(c[i]) || isspace(c[i]) || 1164178479Sjb c[i] == '\b' || c[i] == '\a') 1165178479Sjb continue; 1166178479Sjb 1167178479Sjb if (c[i] == '\0' && i > 0) { 1168178479Sjb /* 1169178479Sjb * This looks like it might be a string. Before we 1170178479Sjb * assume that it is indeed a string, check the 1171178479Sjb * remainder of the byte range; if it contains 1172178479Sjb * additional non-nul characters, we'll assume that 1173178479Sjb * it's a binary stream that just happens to look like 1174178479Sjb * a string, and we'll print out the individual bytes. 1175178479Sjb */ 1176178479Sjb for (j = i + 1; j < nbytes; j++) { 1177178479Sjb if (c[j] != '\0') 1178178479Sjb break; 1179178479Sjb } 1180178479Sjb 1181178479Sjb if (j != nbytes) 1182178479Sjb break; 1183178479Sjb 1184268578Srpaulo if (quiet) { 1185178479Sjb return (dt_printf(dtp, fp, "%s", c)); 1186268578Srpaulo } else { 1187268578Srpaulo return (dt_printf(dtp, fp, " %s%*s", 1188268578Srpaulo width < 0 ? " " : "", width, c)); 1189268578Srpaulo } 1190178479Sjb } 1191178479Sjb 1192178479Sjb break; 1193178479Sjb } 1194178479Sjb 1195178479Sjb if (i == nbytes) { 1196178479Sjb /* 1197178479Sjb * The byte range is all printable characters, but there is 1198178479Sjb * no trailing nul byte. We'll assume that it's a string and 1199178479Sjb * print it as such. 1200178479Sjb */ 1201178479Sjb char *s = alloca(nbytes + 1); 1202178479Sjb bcopy(c, s, nbytes); 1203178479Sjb s[nbytes] = '\0'; 1204178479Sjb return (dt_printf(dtp, fp, " %-*s", width, s)); 1205178479Sjb } 1206178479Sjb 1207178479Sjbraw: 1208178479Sjb if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) 1209178479Sjb return (-1); 1210178479Sjb 1211178479Sjb for (i = 0; i < 16; i++) 1212178479Sjb if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) 1213178479Sjb return (-1); 1214178479Sjb 1215178479Sjb if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) 1216178479Sjb return (-1); 1217178479Sjb 1218178479Sjb 1219178479Sjb for (i = 0; i < nbytes; i += 16) { 1220178479Sjb if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) 1221178479Sjb return (-1); 1222178479Sjb 1223178479Sjb for (j = i; j < i + 16 && j < nbytes; j++) { 1224178479Sjb if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) 1225178479Sjb return (-1); 1226178479Sjb } 1227178479Sjb 1228178479Sjb while (j++ % 16) { 1229178479Sjb if (dt_printf(dtp, fp, " ") < 0) 1230178479Sjb return (-1); 1231178479Sjb } 1232178479Sjb 1233178479Sjb if (dt_printf(dtp, fp, " ") < 0) 1234178479Sjb return (-1); 1235178479Sjb 1236178479Sjb for (j = i; j < i + 16 && j < nbytes; j++) { 1237178479Sjb if (dt_printf(dtp, fp, "%c", 1238178479Sjb c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) 1239178479Sjb return (-1); 1240178479Sjb } 1241178479Sjb 1242178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 1243178479Sjb return (-1); 1244178479Sjb } 1245178479Sjb 1246178479Sjb return (0); 1247178479Sjb} 1248178479Sjb 1249178479Sjbint 1250178479Sjbdt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1251178479Sjb caddr_t addr, int depth, int size) 1252178479Sjb{ 1253178479Sjb dtrace_syminfo_t dts; 1254178479Sjb GElf_Sym sym; 1255178479Sjb int i, indent; 1256178479Sjb char c[PATH_MAX * 2]; 1257178479Sjb uint64_t pc; 1258178479Sjb 1259178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 1260178479Sjb return (-1); 1261178479Sjb 1262178479Sjb if (format == NULL) 1263178479Sjb format = "%s"; 1264178479Sjb 1265178479Sjb if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 1266178479Sjb indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 1267178479Sjb else 1268178479Sjb indent = _dtrace_stkindent; 1269178479Sjb 1270178479Sjb for (i = 0; i < depth; i++) { 1271178479Sjb switch (size) { 1272178479Sjb case sizeof (uint32_t): 1273178479Sjb /* LINTED - alignment */ 1274178479Sjb pc = *((uint32_t *)addr); 1275178479Sjb break; 1276178479Sjb 1277178479Sjb case sizeof (uint64_t): 1278178479Sjb /* LINTED - alignment */ 1279178479Sjb pc = *((uint64_t *)addr); 1280178479Sjb break; 1281178479Sjb 1282178479Sjb default: 1283178479Sjb return (dt_set_errno(dtp, EDT_BADSTACKPC)); 1284178479Sjb } 1285178479Sjb 1286178576Sjb if (pc == 0) 1287178479Sjb break; 1288178479Sjb 1289178479Sjb addr += size; 1290178479Sjb 1291178479Sjb if (dt_printf(dtp, fp, "%*s", indent, "") < 0) 1292178479Sjb return (-1); 1293178479Sjb 1294178479Sjb if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 1295178479Sjb if (pc > sym.st_value) { 1296178479Sjb (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", 1297178479Sjb dts.dts_object, dts.dts_name, 1298228579Sdim (u_longlong_t)(pc - sym.st_value)); 1299178479Sjb } else { 1300178479Sjb (void) snprintf(c, sizeof (c), "%s`%s", 1301178479Sjb dts.dts_object, dts.dts_name); 1302178479Sjb } 1303178479Sjb } else { 1304178479Sjb /* 1305178479Sjb * We'll repeat the lookup, but this time we'll specify 1306178479Sjb * a NULL GElf_Sym -- indicating that we're only 1307178479Sjb * interested in the containing module. 1308178479Sjb */ 1309178479Sjb if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1310178479Sjb (void) snprintf(c, sizeof (c), "%s`0x%llx", 1311228579Sdim dts.dts_object, (u_longlong_t)pc); 1312178479Sjb } else { 1313228579Sdim (void) snprintf(c, sizeof (c), "0x%llx", 1314228579Sdim (u_longlong_t)pc); 1315178479Sjb } 1316178479Sjb } 1317178479Sjb 1318178479Sjb if (dt_printf(dtp, fp, format, c) < 0) 1319178479Sjb return (-1); 1320178479Sjb 1321178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 1322178479Sjb return (-1); 1323178479Sjb } 1324178479Sjb 1325178479Sjb return (0); 1326178479Sjb} 1327178479Sjb 1328178479Sjbint 1329178479Sjbdt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1330178479Sjb caddr_t addr, uint64_t arg) 1331178479Sjb{ 1332178479Sjb /* LINTED - alignment */ 1333178479Sjb uint64_t *pc = (uint64_t *)addr; 1334178479Sjb uint32_t depth = DTRACE_USTACK_NFRAMES(arg); 1335178479Sjb uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); 1336178479Sjb const char *strbase = addr + (depth + 1) * sizeof (uint64_t); 1337178479Sjb const char *str = strsize ? strbase : NULL; 1338178479Sjb int err = 0; 1339178479Sjb 1340178479Sjb char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 1341178479Sjb struct ps_prochandle *P; 1342178479Sjb GElf_Sym sym; 1343178479Sjb int i, indent; 1344178479Sjb pid_t pid; 1345178479Sjb 1346178479Sjb if (depth == 0) 1347178479Sjb return (0); 1348178479Sjb 1349178479Sjb pid = (pid_t)*pc++; 1350178479Sjb 1351178479Sjb if (dt_printf(dtp, fp, "\n") < 0) 1352178479Sjb return (-1); 1353178479Sjb 1354178479Sjb if (format == NULL) 1355178479Sjb format = "%s"; 1356178479Sjb 1357178479Sjb if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 1358178479Sjb indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 1359178479Sjb else 1360178479Sjb indent = _dtrace_stkindent; 1361178479Sjb 1362178479Sjb /* 1363178479Sjb * Ultimately, we need to add an entry point in the library vector for 1364178479Sjb * determining <symbol, offset> from <pid, address>. For now, if 1365178479Sjb * this is a vector open, we just print the raw address or string. 1366178479Sjb */ 1367178479Sjb if (dtp->dt_vector == NULL) 1368178479Sjb P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 1369178479Sjb else 1370178479Sjb P = NULL; 1371178479Sjb 1372178479Sjb if (P != NULL) 1373178479Sjb dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 1374178479Sjb 1375178576Sjb for (i = 0; i < depth && pc[i] != 0; i++) { 1376178479Sjb const prmap_t *map; 1377178479Sjb 1378178479Sjb if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 1379178479Sjb break; 1380178479Sjb 1381178479Sjb if (P != NULL && Plookup_by_addr(P, pc[i], 1382178479Sjb name, sizeof (name), &sym) == 0) { 1383178479Sjb (void) Pobjname(P, pc[i], objname, sizeof (objname)); 1384178479Sjb 1385178479Sjb if (pc[i] > sym.st_value) { 1386178479Sjb (void) snprintf(c, sizeof (c), 1387178479Sjb "%s`%s+0x%llx", dt_basename(objname), name, 1388178479Sjb (u_longlong_t)(pc[i] - sym.st_value)); 1389178479Sjb } else { 1390178479Sjb (void) snprintf(c, sizeof (c), 1391178479Sjb "%s`%s", dt_basename(objname), name); 1392178479Sjb } 1393178479Sjb } else if (str != NULL && str[0] != '\0' && str[0] != '@' && 1394178479Sjb (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL || 1395178479Sjb (map->pr_mflags & MA_WRITE)))) { 1396178479Sjb /* 1397178479Sjb * If the current string pointer in the string table 1398178479Sjb * does not point to an empty string _and_ the program 1399178479Sjb * counter falls in a writable region, we'll use the 1400178479Sjb * string from the string table instead of the raw 1401178479Sjb * address. This last condition is necessary because 1402178479Sjb * some (broken) ustack helpers will return a string 1403178479Sjb * even for a program counter that they can't 1404178479Sjb * identify. If we have a string for a program 1405178479Sjb * counter that falls in a segment that isn't 1406178479Sjb * writable, we assume that we have fallen into this 1407178479Sjb * case and we refuse to use the string. 1408178479Sjb */ 1409178479Sjb (void) snprintf(c, sizeof (c), "%s", str); 1410178479Sjb } else { 1411178479Sjb if (P != NULL && Pobjname(P, pc[i], objname, 1412178576Sjb sizeof (objname)) != 0) { 1413178479Sjb (void) snprintf(c, sizeof (c), "%s`0x%llx", 1414178479Sjb dt_basename(objname), (u_longlong_t)pc[i]); 1415178479Sjb } else { 1416178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", 1417178479Sjb (u_longlong_t)pc[i]); 1418178479Sjb } 1419178479Sjb } 1420178479Sjb 1421178479Sjb if ((err = dt_printf(dtp, fp, format, c)) < 0) 1422178479Sjb break; 1423178479Sjb 1424178479Sjb if ((err = dt_printf(dtp, fp, "\n")) < 0) 1425178479Sjb break; 1426178479Sjb 1427178479Sjb if (str != NULL && str[0] == '@') { 1428178479Sjb /* 1429178479Sjb * If the first character of the string is an "at" sign, 1430178479Sjb * then the string is inferred to be an annotation -- 1431178479Sjb * and it is printed out beneath the frame and offset 1432178479Sjb * with brackets. 1433178479Sjb */ 1434178479Sjb if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 1435178479Sjb break; 1436178479Sjb 1437178479Sjb (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]); 1438178479Sjb 1439178479Sjb if ((err = dt_printf(dtp, fp, format, c)) < 0) 1440178479Sjb break; 1441178479Sjb 1442178479Sjb if ((err = dt_printf(dtp, fp, "\n")) < 0) 1443178479Sjb break; 1444178479Sjb } 1445178479Sjb 1446178479Sjb if (str != NULL) { 1447178479Sjb str += strlen(str) + 1; 1448178479Sjb if (str - strbase >= strsize) 1449178479Sjb str = NULL; 1450178479Sjb } 1451178479Sjb } 1452178479Sjb 1453178479Sjb if (P != NULL) { 1454178479Sjb dt_proc_unlock(dtp, P); 1455178479Sjb dt_proc_release(dtp, P); 1456178479Sjb } 1457178479Sjb 1458178479Sjb return (err); 1459178479Sjb} 1460178479Sjb 1461178479Sjbstatic int 1462178479Sjbdt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act) 1463178479Sjb{ 1464178479Sjb /* LINTED - alignment */ 1465178479Sjb uint64_t pid = ((uint64_t *)addr)[0]; 1466178479Sjb /* LINTED - alignment */ 1467178479Sjb uint64_t pc = ((uint64_t *)addr)[1]; 1468178479Sjb const char *format = " %-50s"; 1469178479Sjb char *s; 1470178479Sjb int n, len = 256; 1471178479Sjb 1472178479Sjb if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) { 1473178479Sjb struct ps_prochandle *P; 1474178479Sjb 1475178479Sjb if ((P = dt_proc_grab(dtp, pid, 1476178479Sjb PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) { 1477178479Sjb GElf_Sym sym; 1478178479Sjb 1479178479Sjb dt_proc_lock(dtp, P); 1480178479Sjb 1481178479Sjb if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0) 1482178479Sjb pc = sym.st_value; 1483178479Sjb 1484178479Sjb dt_proc_unlock(dtp, P); 1485178479Sjb dt_proc_release(dtp, P); 1486178479Sjb } 1487178479Sjb } 1488178479Sjb 1489178479Sjb do { 1490178479Sjb n = len; 1491178479Sjb s = alloca(n); 1492210767Srpaulo } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n); 1493178479Sjb 1494178479Sjb return (dt_printf(dtp, fp, format, s)); 1495178479Sjb} 1496178479Sjb 1497178479Sjbint 1498178479Sjbdt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1499178479Sjb{ 1500178479Sjb /* LINTED - alignment */ 1501178479Sjb uint64_t pid = ((uint64_t *)addr)[0]; 1502178479Sjb /* LINTED - alignment */ 1503178479Sjb uint64_t pc = ((uint64_t *)addr)[1]; 1504178479Sjb int err = 0; 1505178479Sjb 1506178479Sjb char objname[PATH_MAX], c[PATH_MAX * 2]; 1507178479Sjb struct ps_prochandle *P; 1508178479Sjb 1509178479Sjb if (format == NULL) 1510178479Sjb format = " %-50s"; 1511178479Sjb 1512178479Sjb /* 1513178479Sjb * See the comment in dt_print_ustack() for the rationale for 1514178479Sjb * printing raw addresses in the vectored case. 1515178479Sjb */ 1516178479Sjb if (dtp->dt_vector == NULL) 1517178479Sjb P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 1518178479Sjb else 1519178479Sjb P = NULL; 1520178479Sjb 1521178479Sjb if (P != NULL) 1522178479Sjb dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 1523178479Sjb 1524178576Sjb if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) { 1525178479Sjb (void) snprintf(c, sizeof (c), "%s", dt_basename(objname)); 1526178479Sjb } else { 1527178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1528178479Sjb } 1529178479Sjb 1530178479Sjb err = dt_printf(dtp, fp, format, c); 1531178479Sjb 1532178479Sjb if (P != NULL) { 1533178479Sjb dt_proc_unlock(dtp, P); 1534178479Sjb dt_proc_release(dtp, P); 1535178479Sjb } 1536178479Sjb 1537178479Sjb return (err); 1538178479Sjb} 1539178479Sjb 1540178576Sjbint 1541178576Sjbdt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr) 1542178576Sjb{ 1543178576Sjb int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 1544178576Sjb size_t nbytes = *((uintptr_t *) addr); 1545178576Sjb 1546178576Sjb return (dt_print_bytes(dtp, fp, addr + sizeof(uintptr_t), 1547178576Sjb nbytes, 50, quiet, 1)); 1548178576Sjb} 1549178576Sjb 1550178576Sjbtypedef struct dt_type_cbdata { 1551178576Sjb dtrace_hdl_t *dtp; 1552178576Sjb dtrace_typeinfo_t dtt; 1553178576Sjb caddr_t addr; 1554178576Sjb caddr_t addrend; 1555178576Sjb const char *name; 1556178576Sjb int f_type; 1557178576Sjb int indent; 1558178576Sjb int type_width; 1559178576Sjb int name_width; 1560178576Sjb FILE *fp; 1561178576Sjb} dt_type_cbdata_t; 1562178576Sjb 1563178576Sjbstatic int dt_print_type_data(dt_type_cbdata_t *, ctf_id_t); 1564178576Sjb 1565178479Sjbstatic int 1566178576Sjbdt_print_type_member(const char *name, ctf_id_t type, ulong_t off, void *arg) 1567178576Sjb{ 1568178576Sjb dt_type_cbdata_t cbdata; 1569178576Sjb dt_type_cbdata_t *cbdatap = arg; 1570178576Sjb ssize_t ssz; 1571178576Sjb 1572178576Sjb if ((ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type)) <= 0) 1573178576Sjb return (0); 1574178576Sjb 1575178576Sjb off /= 8; 1576178576Sjb 1577178576Sjb cbdata = *cbdatap; 1578178576Sjb cbdata.name = name; 1579178576Sjb cbdata.addr += off; 1580178576Sjb cbdata.addrend = cbdata.addr + ssz; 1581178576Sjb 1582178576Sjb return (dt_print_type_data(&cbdata, type)); 1583178576Sjb} 1584178576Sjb 1585178576Sjbstatic int 1586178576Sjbdt_print_type_width(const char *name, ctf_id_t type, ulong_t off, void *arg) 1587178576Sjb{ 1588178576Sjb char buf[DT_TYPE_NAMELEN]; 1589178576Sjb char *p; 1590178576Sjb dt_type_cbdata_t *cbdatap = arg; 1591178576Sjb size_t sz = strlen(name); 1592178576Sjb 1593178576Sjb ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf)); 1594178576Sjb 1595178576Sjb if ((p = strchr(buf, '[')) != NULL) 1596178576Sjb p[-1] = '\0'; 1597178576Sjb else 1598178576Sjb p = ""; 1599178576Sjb 1600178576Sjb sz += strlen(p); 1601178576Sjb 1602178576Sjb if (sz > cbdatap->name_width) 1603178576Sjb cbdatap->name_width = sz; 1604178576Sjb 1605178576Sjb sz = strlen(buf); 1606178576Sjb 1607178576Sjb if (sz > cbdatap->type_width) 1608178576Sjb cbdatap->type_width = sz; 1609178576Sjb 1610178576Sjb return (0); 1611178576Sjb} 1612178576Sjb 1613178576Sjbstatic int 1614178576Sjbdt_print_type_data(dt_type_cbdata_t *cbdatap, ctf_id_t type) 1615178576Sjb{ 1616178576Sjb caddr_t addr = cbdatap->addr; 1617178576Sjb caddr_t addrend = cbdatap->addrend; 1618178576Sjb char buf[DT_TYPE_NAMELEN]; 1619178576Sjb char *p; 1620178576Sjb int cnt = 0; 1621178576Sjb uint_t kind = ctf_type_kind(cbdatap->dtt.dtt_ctfp, type); 1622178576Sjb ssize_t ssz = ctf_type_size(cbdatap->dtt.dtt_ctfp, type); 1623178576Sjb 1624178576Sjb ctf_type_name(cbdatap->dtt.dtt_ctfp, type, buf, sizeof (buf)); 1625178576Sjb 1626178576Sjb if ((p = strchr(buf, '[')) != NULL) 1627178576Sjb p[-1] = '\0'; 1628178576Sjb else 1629178576Sjb p = ""; 1630178576Sjb 1631178576Sjb if (cbdatap->f_type) { 1632178576Sjb int type_width = roundup(cbdatap->type_width + 1, 4); 1633178576Sjb int name_width = roundup(cbdatap->name_width + 1, 4); 1634178576Sjb 1635178576Sjb name_width -= strlen(cbdatap->name); 1636178576Sjb 1637178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s%-*s%s%-*s = ",cbdatap->indent * 4,"",type_width,buf,cbdatap->name,name_width,p); 1638178576Sjb } 1639178576Sjb 1640178576Sjb while (addr < addrend) { 1641178576Sjb dt_type_cbdata_t cbdata; 1642178576Sjb ctf_arinfo_t arinfo; 1643178576Sjb ctf_encoding_t cte; 1644178576Sjb uintptr_t *up; 1645178576Sjb void *vp = addr; 1646178576Sjb cbdata = *cbdatap; 1647178576Sjb cbdata.name = ""; 1648178576Sjb cbdata.addr = addr; 1649178576Sjb cbdata.addrend = addr + ssz; 1650178576Sjb cbdata.f_type = 0; 1651178576Sjb cbdata.indent++; 1652178576Sjb cbdata.type_width = 0; 1653178576Sjb cbdata.name_width = 0; 1654178576Sjb 1655178576Sjb if (cnt > 0) 1656178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s", cbdatap->indent * 4,""); 1657178576Sjb 1658178576Sjb switch (kind) { 1659178576Sjb case CTF_K_INTEGER: 1660178576Sjb if (ctf_type_encoding(cbdatap->dtt.dtt_ctfp, type, &cte) != 0) 1661178576Sjb return (-1); 1662178576Sjb if ((cte.cte_format & CTF_INT_SIGNED) != 0) 1663178576Sjb switch (cte.cte_bits) { 1664178576Sjb case 8: 1665178576Sjb if (isprint(*((char *) vp))) 1666178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "'%c', ", *((char *) vp)); 1667178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((char *) vp), *((char *) vp)); 1668178576Sjb break; 1669178576Sjb case 16: 1670178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%hd (0x%hx);\n", *((short *) vp), *((u_short *) vp)); 1671178576Sjb break; 1672178576Sjb case 32: 1673178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%d (0x%x);\n", *((int *) vp), *((u_int *) vp)); 1674178576Sjb break; 1675178576Sjb case 64: 1676178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%jd (0x%jx);\n", *((long long *) vp), *((unsigned long long *) vp)); 1677178576Sjb break; 1678178576Sjb default: 1679178576Sjb 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); 1680178576Sjb break; 1681178576Sjb } 1682178576Sjb else 1683178576Sjb switch (cte.cte_bits) { 1684178576Sjb case 8: 1685178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((uint8_t *) vp) & 0xff, *((uint8_t *) vp) & 0xff); 1686178576Sjb break; 1687178576Sjb case 16: 1688178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%hu (0x%hx);\n", *((u_short *) vp), *((u_short *) vp)); 1689178576Sjb break; 1690178576Sjb case 32: 1691178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%u (0x%x);\n", *((u_int *) vp), *((u_int *) vp)); 1692178576Sjb break; 1693178576Sjb case 64: 1694178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%ju (0x%jx);\n", *((unsigned long long *) vp), *((unsigned long long *) vp)); 1695178576Sjb break; 1696178576Sjb default: 1697178576Sjb 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); 1698178576Sjb break; 1699178576Sjb } 1700178576Sjb break; 1701178576Sjb case CTF_K_FLOAT: 1702178576Sjb 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); 1703178576Sjb break; 1704178576Sjb case CTF_K_POINTER: 1705178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%p;\n", *((void **) addr)); 1706178576Sjb break; 1707178576Sjb case CTF_K_ARRAY: 1708178576Sjb if (ctf_array_info(cbdatap->dtt.dtt_ctfp, type, &arinfo) != 0) 1709178576Sjb return (-1); 1710178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "{\n%*s",cbdata.indent * 4,""); 1711178576Sjb dt_print_type_data(&cbdata, arinfo.ctr_contents); 1712178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1713178576Sjb break; 1714178576Sjb case CTF_K_FUNCTION: 1715178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "CTF_K_FUNCTION:\n"); 1716178576Sjb break; 1717178576Sjb case CTF_K_STRUCT: 1718178576Sjb cbdata.f_type = 1; 1719178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1720178576Sjb dt_print_type_width, &cbdata) != 0) 1721178576Sjb return (-1); 1722178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "{\n"); 1723178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1724178576Sjb dt_print_type_member, &cbdata) != 0) 1725178576Sjb return (-1); 1726178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1727178576Sjb break; 1728178576Sjb case CTF_K_UNION: 1729178576Sjb cbdata.f_type = 1; 1730178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1731178576Sjb dt_print_type_width, &cbdata) != 0) 1732178576Sjb return (-1); 1733178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "{\n"); 1734178576Sjb if (ctf_member_iter(cbdatap->dtt.dtt_ctfp, type, 1735178576Sjb dt_print_type_member, &cbdata) != 0) 1736178576Sjb return (-1); 1737178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%*s};\n",cbdatap->indent * 4,""); 1738178576Sjb break; 1739178576Sjb case CTF_K_ENUM: 1740178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "%s;\n", ctf_enum_name(cbdatap->dtt.dtt_ctfp, type, *((int *) vp))); 1741178576Sjb break; 1742178576Sjb case CTF_K_TYPEDEF: 1743178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1744178576Sjb break; 1745178576Sjb case CTF_K_VOLATILE: 1746178576Sjb if (cbdatap->f_type) 1747178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "volatile "); 1748178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1749178576Sjb break; 1750178576Sjb case CTF_K_CONST: 1751178576Sjb if (cbdatap->f_type) 1752178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "const "); 1753178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1754178576Sjb break; 1755178576Sjb case CTF_K_RESTRICT: 1756178576Sjb if (cbdatap->f_type) 1757178576Sjb dt_printf(cbdatap->dtp, cbdatap->fp, "restrict "); 1758178576Sjb dt_print_type_data(&cbdata, ctf_type_reference(cbdatap->dtt.dtt_ctfp,type)); 1759178576Sjb break; 1760178576Sjb default: 1761178576Sjb break; 1762178576Sjb } 1763178576Sjb 1764178576Sjb addr += ssz; 1765178576Sjb cnt++; 1766178576Sjb } 1767178576Sjb 1768178576Sjb return (0); 1769178576Sjb} 1770178576Sjb 1771178576Sjbstatic int 1772178576Sjbdt_print_type(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr) 1773178576Sjb{ 1774178576Sjb caddr_t addrend; 1775178576Sjb char *p; 1776178576Sjb dtrace_typeinfo_t dtt; 1777178576Sjb dt_type_cbdata_t cbdata; 1778178576Sjb int num = 0; 1779178576Sjb int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 1780178576Sjb ssize_t ssz; 1781178576Sjb 1782178576Sjb if (!quiet) 1783178576Sjb dt_printf(dtp, fp, "\n"); 1784178576Sjb 1785178576Sjb /* Get the total number of bytes of data buffered. */ 1786178576Sjb size_t nbytes = *((uintptr_t *) addr); 1787178576Sjb addr += sizeof(uintptr_t); 1788178576Sjb 1789178576Sjb /* 1790178576Sjb * Get the size of the type so that we can check that it matches 1791178576Sjb * the CTF data we look up and so that we can figure out how many 1792178576Sjb * type elements are buffered. 1793178576Sjb */ 1794178576Sjb size_t typs = *((uintptr_t *) addr); 1795178576Sjb addr += sizeof(uintptr_t); 1796178576Sjb 1797178576Sjb /* 1798178576Sjb * Point to the type string in the buffer. Get it's string 1799178576Sjb * length and round it up to become the offset to the start 1800178576Sjb * of the buffered type data which we would like to be aligned 1801178576Sjb * for easy access. 1802178576Sjb */ 1803178576Sjb char *strp = (char *) addr; 1804178576Sjb int offset = roundup(strlen(strp) + 1, sizeof(uintptr_t)); 1805178576Sjb 1806178576Sjb /* 1807178576Sjb * The type string might have a format such as 'int [20]'. 1808178576Sjb * Check if there is an array dimension present. 1809178576Sjb */ 1810178576Sjb if ((p = strchr(strp, '[')) != NULL) { 1811178576Sjb /* Strip off the array dimension. */ 1812178576Sjb *p++ = '\0'; 1813178576Sjb 1814178576Sjb for (; *p != '\0' && *p != ']'; p++) 1815178576Sjb num = num * 10 + *p - '0'; 1816178576Sjb } else 1817178576Sjb /* No array dimension, so default. */ 1818178576Sjb num = 1; 1819178576Sjb 1820178576Sjb /* Lookup the CTF type from the type string. */ 1821178576Sjb if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, strp, &dtt) < 0) 1822178576Sjb return (-1); 1823178576Sjb 1824178576Sjb /* Offset the buffer address to the start of the data... */ 1825178576Sjb addr += offset; 1826178576Sjb 1827178576Sjb ssz = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type); 1828178576Sjb 1829178576Sjb if (typs != ssz) { 1830178576Sjb printf("Expected type size from buffer (%lu) to match type size looked up now (%ld)\n", (u_long) typs, (long) ssz); 1831178576Sjb return (-1); 1832178576Sjb } 1833178576Sjb 1834178576Sjb cbdata.dtp = dtp; 1835178576Sjb cbdata.dtt = dtt; 1836178576Sjb cbdata.name = ""; 1837178576Sjb cbdata.addr = addr; 1838178576Sjb cbdata.addrend = addr + nbytes; 1839178576Sjb cbdata.indent = 1; 1840178576Sjb cbdata.f_type = 1; 1841178576Sjb cbdata.type_width = 0; 1842178576Sjb cbdata.name_width = 0; 1843178576Sjb cbdata.fp = fp; 1844178576Sjb 1845178576Sjb return (dt_print_type_data(&cbdata, dtt.dtt_type)); 1846178576Sjb} 1847178576Sjb 1848178576Sjbstatic int 1849178479Sjbdt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1850178479Sjb{ 1851178479Sjb /* LINTED - alignment */ 1852178479Sjb uint64_t pc = *((uint64_t *)addr); 1853178479Sjb dtrace_syminfo_t dts; 1854178479Sjb GElf_Sym sym; 1855178479Sjb char c[PATH_MAX * 2]; 1856178479Sjb 1857178479Sjb if (format == NULL) 1858178479Sjb format = " %-50s"; 1859178479Sjb 1860178479Sjb if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 1861178479Sjb (void) snprintf(c, sizeof (c), "%s`%s", 1862178479Sjb dts.dts_object, dts.dts_name); 1863178479Sjb } else { 1864178479Sjb /* 1865178479Sjb * We'll repeat the lookup, but this time we'll specify a 1866178479Sjb * NULL GElf_Sym -- indicating that we're only interested in 1867178479Sjb * the containing module. 1868178479Sjb */ 1869178479Sjb if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1870178479Sjb (void) snprintf(c, sizeof (c), "%s`0x%llx", 1871178479Sjb dts.dts_object, (u_longlong_t)pc); 1872178479Sjb } else { 1873178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", 1874178479Sjb (u_longlong_t)pc); 1875178479Sjb } 1876178479Sjb } 1877178479Sjb 1878178479Sjb if (dt_printf(dtp, fp, format, c) < 0) 1879178479Sjb return (-1); 1880178479Sjb 1881178479Sjb return (0); 1882178479Sjb} 1883178479Sjb 1884178479Sjbint 1885178479Sjbdt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1886178479Sjb{ 1887178479Sjb /* LINTED - alignment */ 1888178479Sjb uint64_t pc = *((uint64_t *)addr); 1889178479Sjb dtrace_syminfo_t dts; 1890178479Sjb char c[PATH_MAX * 2]; 1891178479Sjb 1892178479Sjb if (format == NULL) 1893178479Sjb format = " %-50s"; 1894178479Sjb 1895178479Sjb if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1896178479Sjb (void) snprintf(c, sizeof (c), "%s", dts.dts_object); 1897178479Sjb } else { 1898178479Sjb (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1899178479Sjb } 1900178479Sjb 1901178479Sjb if (dt_printf(dtp, fp, format, c) < 0) 1902178479Sjb return (-1); 1903178479Sjb 1904178479Sjb return (0); 1905178479Sjb} 1906178479Sjb 1907178479Sjbtypedef struct dt_normal { 1908178479Sjb dtrace_aggvarid_t dtnd_id; 1909178479Sjb uint64_t dtnd_normal; 1910178479Sjb} dt_normal_t; 1911178479Sjb 1912178479Sjbstatic int 1913178479Sjbdt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 1914178479Sjb{ 1915178479Sjb dt_normal_t *normal = arg; 1916178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1917178479Sjb dtrace_aggvarid_t id = normal->dtnd_id; 1918178479Sjb 1919178479Sjb if (agg->dtagd_nrecs == 0) 1920178479Sjb return (DTRACE_AGGWALK_NEXT); 1921178479Sjb 1922178479Sjb if (agg->dtagd_varid != id) 1923178479Sjb return (DTRACE_AGGWALK_NEXT); 1924178479Sjb 1925178479Sjb ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal; 1926178479Sjb return (DTRACE_AGGWALK_NORMALIZE); 1927178479Sjb} 1928178479Sjb 1929178479Sjbstatic int 1930178479Sjbdt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 1931178479Sjb{ 1932178479Sjb dt_normal_t normal; 1933178479Sjb caddr_t addr; 1934178479Sjb 1935178479Sjb /* 1936178479Sjb * We (should) have two records: the aggregation ID followed by the 1937178479Sjb * normalization value. 1938178479Sjb */ 1939178479Sjb addr = base + rec->dtrd_offset; 1940178479Sjb 1941178479Sjb if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 1942178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1943178479Sjb 1944178479Sjb /* LINTED - alignment */ 1945178479Sjb normal.dtnd_id = *((dtrace_aggvarid_t *)addr); 1946178479Sjb rec++; 1947178479Sjb 1948178479Sjb if (rec->dtrd_action != DTRACEACT_LIBACT) 1949178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1950178479Sjb 1951178479Sjb if (rec->dtrd_arg != DT_ACT_NORMALIZE) 1952178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1953178479Sjb 1954178479Sjb addr = base + rec->dtrd_offset; 1955178479Sjb 1956178479Sjb switch (rec->dtrd_size) { 1957178479Sjb case sizeof (uint64_t): 1958178479Sjb /* LINTED - alignment */ 1959178479Sjb normal.dtnd_normal = *((uint64_t *)addr); 1960178479Sjb break; 1961178479Sjb case sizeof (uint32_t): 1962178479Sjb /* LINTED - alignment */ 1963178479Sjb normal.dtnd_normal = *((uint32_t *)addr); 1964178479Sjb break; 1965178479Sjb case sizeof (uint16_t): 1966178479Sjb /* LINTED - alignment */ 1967178479Sjb normal.dtnd_normal = *((uint16_t *)addr); 1968178479Sjb break; 1969178479Sjb case sizeof (uint8_t): 1970178479Sjb normal.dtnd_normal = *((uint8_t *)addr); 1971178479Sjb break; 1972178479Sjb default: 1973178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 1974178479Sjb } 1975178479Sjb 1976178479Sjb (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal); 1977178479Sjb 1978178479Sjb return (0); 1979178479Sjb} 1980178479Sjb 1981178479Sjbstatic int 1982178479Sjbdt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 1983178479Sjb{ 1984178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1985178479Sjb dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 1986178479Sjb 1987178479Sjb if (agg->dtagd_nrecs == 0) 1988178479Sjb return (DTRACE_AGGWALK_NEXT); 1989178479Sjb 1990178479Sjb if (agg->dtagd_varid != id) 1991178479Sjb return (DTRACE_AGGWALK_NEXT); 1992178479Sjb 1993178479Sjb return (DTRACE_AGGWALK_DENORMALIZE); 1994178479Sjb} 1995178479Sjb 1996178479Sjbstatic int 1997178479Sjbdt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg) 1998178479Sjb{ 1999178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 2000178479Sjb dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 2001178479Sjb 2002178479Sjb if (agg->dtagd_nrecs == 0) 2003178479Sjb return (DTRACE_AGGWALK_NEXT); 2004178479Sjb 2005178479Sjb if (agg->dtagd_varid != id) 2006178479Sjb return (DTRACE_AGGWALK_NEXT); 2007178479Sjb 2008178479Sjb return (DTRACE_AGGWALK_CLEAR); 2009178479Sjb} 2010178479Sjb 2011178479Sjbtypedef struct dt_trunc { 2012178479Sjb dtrace_aggvarid_t dttd_id; 2013178479Sjb uint64_t dttd_remaining; 2014178479Sjb} dt_trunc_t; 2015178479Sjb 2016178479Sjbstatic int 2017178479Sjbdt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg) 2018178479Sjb{ 2019178479Sjb dt_trunc_t *trunc = arg; 2020178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 2021178479Sjb dtrace_aggvarid_t id = trunc->dttd_id; 2022178479Sjb 2023178479Sjb if (agg->dtagd_nrecs == 0) 2024178479Sjb return (DTRACE_AGGWALK_NEXT); 2025178479Sjb 2026178479Sjb if (agg->dtagd_varid != id) 2027178479Sjb return (DTRACE_AGGWALK_NEXT); 2028178479Sjb 2029178479Sjb if (trunc->dttd_remaining == 0) 2030178479Sjb return (DTRACE_AGGWALK_REMOVE); 2031178479Sjb 2032178479Sjb trunc->dttd_remaining--; 2033178479Sjb return (DTRACE_AGGWALK_NEXT); 2034178479Sjb} 2035178479Sjb 2036178479Sjbstatic int 2037178479Sjbdt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 2038178479Sjb{ 2039178479Sjb dt_trunc_t trunc; 2040178479Sjb caddr_t addr; 2041178479Sjb int64_t remaining; 2042178479Sjb int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *); 2043178479Sjb 2044178479Sjb /* 2045178479Sjb * We (should) have two records: the aggregation ID followed by the 2046178479Sjb * number of aggregation entries after which the aggregation is to be 2047178479Sjb * truncated. 2048178479Sjb */ 2049178479Sjb addr = base + rec->dtrd_offset; 2050178479Sjb 2051178479Sjb if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 2052178479Sjb return (dt_set_errno(dtp, EDT_BADTRUNC)); 2053178479Sjb 2054178479Sjb /* LINTED - alignment */ 2055178479Sjb trunc.dttd_id = *((dtrace_aggvarid_t *)addr); 2056178479Sjb rec++; 2057178479Sjb 2058178479Sjb if (rec->dtrd_action != DTRACEACT_LIBACT) 2059178479Sjb return (dt_set_errno(dtp, EDT_BADTRUNC)); 2060178479Sjb 2061178479Sjb if (rec->dtrd_arg != DT_ACT_TRUNC) 2062178479Sjb return (dt_set_errno(dtp, EDT_BADTRUNC)); 2063178479Sjb 2064178479Sjb addr = base + rec->dtrd_offset; 2065178479Sjb 2066178479Sjb switch (rec->dtrd_size) { 2067178479Sjb case sizeof (uint64_t): 2068178479Sjb /* LINTED - alignment */ 2069178479Sjb remaining = *((int64_t *)addr); 2070178479Sjb break; 2071178479Sjb case sizeof (uint32_t): 2072178479Sjb /* LINTED - alignment */ 2073178479Sjb remaining = *((int32_t *)addr); 2074178479Sjb break; 2075178479Sjb case sizeof (uint16_t): 2076178479Sjb /* LINTED - alignment */ 2077178479Sjb remaining = *((int16_t *)addr); 2078178479Sjb break; 2079178479Sjb case sizeof (uint8_t): 2080178479Sjb remaining = *((int8_t *)addr); 2081178479Sjb break; 2082178479Sjb default: 2083178479Sjb return (dt_set_errno(dtp, EDT_BADNORMAL)); 2084178479Sjb } 2085178479Sjb 2086178479Sjb if (remaining < 0) { 2087178479Sjb func = dtrace_aggregate_walk_valsorted; 2088178479Sjb remaining = -remaining; 2089178479Sjb } else { 2090178479Sjb func = dtrace_aggregate_walk_valrevsorted; 2091178479Sjb } 2092178479Sjb 2093178479Sjb assert(remaining >= 0); 2094178479Sjb trunc.dttd_remaining = remaining; 2095178479Sjb 2096178479Sjb (void) func(dtp, dt_trunc_agg, &trunc); 2097178479Sjb 2098178479Sjb return (0); 2099178479Sjb} 2100178479Sjb 2101178479Sjbstatic int 2102178479Sjbdt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, 2103268578Srpaulo caddr_t addr, size_t size, const dtrace_aggdata_t *aggdata, 2104268578Srpaulo uint64_t normal, dt_print_aggdata_t *pd) 2105178479Sjb{ 2106268578Srpaulo int err, width; 2107178479Sjb dtrace_actkind_t act = rec->dtrd_action; 2108268578Srpaulo boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack; 2109268578Srpaulo dtrace_aggdesc_t *agg = aggdata->dtada_desc; 2110178479Sjb 2111268578Srpaulo static struct { 2112268578Srpaulo size_t size; 2113268578Srpaulo int width; 2114268578Srpaulo int packedwidth; 2115268578Srpaulo } *fmt, fmttab[] = { 2116268578Srpaulo { sizeof (uint8_t), 3, 3 }, 2117268578Srpaulo { sizeof (uint16_t), 5, 5 }, 2118268578Srpaulo { sizeof (uint32_t), 8, 8 }, 2119268578Srpaulo { sizeof (uint64_t), 16, 16 }, 2120268578Srpaulo { 0, -50, 16 } 2121268578Srpaulo }; 2122268578Srpaulo 2123268578Srpaulo if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid) { 2124268578Srpaulo dtrace_recdesc_t *r; 2125268578Srpaulo 2126268578Srpaulo width = 0; 2127268578Srpaulo 2128268578Srpaulo /* 2129268578Srpaulo * To print our quantization header for either an agghist or 2130268578Srpaulo * aggpack aggregation, we need to iterate through all of our 2131268578Srpaulo * of our records to determine their width. 2132268578Srpaulo */ 2133268578Srpaulo for (r = rec; !DTRACEACT_ISAGG(r->dtrd_action); r++) { 2134268578Srpaulo for (fmt = fmttab; fmt->size && 2135268578Srpaulo fmt->size != r->dtrd_size; fmt++) 2136268578Srpaulo continue; 2137268578Srpaulo 2138268578Srpaulo width += fmt->packedwidth + 1; 2139268578Srpaulo } 2140268578Srpaulo 2141268578Srpaulo if (pd->dtpa_agghist) { 2142268578Srpaulo if (dt_print_quanthdr(dtp, fp, width) < 0) 2143268578Srpaulo return (-1); 2144268578Srpaulo } else { 2145268578Srpaulo if (dt_print_quanthdr_packed(dtp, fp, 2146268578Srpaulo width, aggdata, r->dtrd_action) < 0) 2147268578Srpaulo return (-1); 2148268578Srpaulo } 2149268578Srpaulo 2150268578Srpaulo pd->dtpa_agghisthdr = agg->dtagd_varid; 2151268578Srpaulo } 2152268578Srpaulo 2153268578Srpaulo if (pd->dtpa_agghist && DTRACEACT_ISAGG(act)) { 2154268578Srpaulo char positives = aggdata->dtada_flags & DTRACE_A_HASPOSITIVES; 2155268578Srpaulo char negatives = aggdata->dtada_flags & DTRACE_A_HASNEGATIVES; 2156268578Srpaulo int64_t val; 2157268578Srpaulo 2158268578Srpaulo assert(act == DTRACEAGG_SUM || act == DTRACEAGG_COUNT); 2159268578Srpaulo val = (long long)*((uint64_t *)addr); 2160268578Srpaulo 2161268578Srpaulo if (dt_printf(dtp, fp, " ") < 0) 2162268578Srpaulo return (-1); 2163268578Srpaulo 2164268578Srpaulo return (dt_print_quantline(dtp, fp, val, normal, 2165268578Srpaulo aggdata->dtada_total, positives, negatives)); 2166268578Srpaulo } 2167268578Srpaulo 2168268578Srpaulo if (pd->dtpa_aggpack && DTRACEACT_ISAGG(act)) { 2169268578Srpaulo switch (act) { 2170268578Srpaulo case DTRACEAGG_QUANTIZE: 2171268578Srpaulo return (dt_print_quantize_packed(dtp, 2172268578Srpaulo fp, addr, size, aggdata)); 2173268578Srpaulo case DTRACEAGG_LQUANTIZE: 2174268578Srpaulo return (dt_print_lquantize_packed(dtp, 2175268578Srpaulo fp, addr, size, aggdata)); 2176268578Srpaulo default: 2177268578Srpaulo break; 2178268578Srpaulo } 2179268578Srpaulo } 2180268578Srpaulo 2181178479Sjb switch (act) { 2182178479Sjb case DTRACEACT_STACK: 2183178479Sjb return (dt_print_stack(dtp, fp, NULL, addr, 2184178479Sjb rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg)); 2185178479Sjb 2186178479Sjb case DTRACEACT_USTACK: 2187178479Sjb case DTRACEACT_JSTACK: 2188178479Sjb return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg)); 2189178479Sjb 2190178479Sjb case DTRACEACT_USYM: 2191178479Sjb case DTRACEACT_UADDR: 2192178479Sjb return (dt_print_usym(dtp, fp, addr, act)); 2193178479Sjb 2194178479Sjb case DTRACEACT_UMOD: 2195178479Sjb return (dt_print_umod(dtp, fp, NULL, addr)); 2196178479Sjb 2197178479Sjb case DTRACEACT_SYM: 2198178479Sjb return (dt_print_sym(dtp, fp, NULL, addr)); 2199178479Sjb 2200178479Sjb case DTRACEACT_MOD: 2201178479Sjb return (dt_print_mod(dtp, fp, NULL, addr)); 2202178479Sjb 2203178479Sjb case DTRACEAGG_QUANTIZE: 2204178479Sjb return (dt_print_quantize(dtp, fp, addr, size, normal)); 2205178479Sjb 2206178479Sjb case DTRACEAGG_LQUANTIZE: 2207178479Sjb return (dt_print_lquantize(dtp, fp, addr, size, normal)); 2208178479Sjb 2209237624Spfg case DTRACEAGG_LLQUANTIZE: 2210237624Spfg return (dt_print_llquantize(dtp, fp, addr, size, normal)); 2211237624Spfg 2212178479Sjb case DTRACEAGG_AVG: 2213178479Sjb return (dt_print_average(dtp, fp, addr, size, normal)); 2214178479Sjb 2215178479Sjb case DTRACEAGG_STDDEV: 2216178479Sjb return (dt_print_stddev(dtp, fp, addr, size, normal)); 2217178479Sjb 2218178479Sjb default: 2219178479Sjb break; 2220178479Sjb } 2221178479Sjb 2222268578Srpaulo for (fmt = fmttab; fmt->size && fmt->size != size; fmt++) 2223268578Srpaulo continue; 2224268578Srpaulo 2225268578Srpaulo width = packed ? fmt->packedwidth : fmt->width; 2226268578Srpaulo 2227178479Sjb switch (size) { 2228178479Sjb case sizeof (uint64_t): 2229268578Srpaulo err = dt_printf(dtp, fp, " %*lld", width, 2230178479Sjb /* LINTED - alignment */ 2231178479Sjb (long long)*((uint64_t *)addr) / normal); 2232178479Sjb break; 2233178479Sjb case sizeof (uint32_t): 2234178479Sjb /* LINTED - alignment */ 2235268578Srpaulo err = dt_printf(dtp, fp, " %*d", width, *((uint32_t *)addr) / 2236178479Sjb (uint32_t)normal); 2237178479Sjb break; 2238178479Sjb case sizeof (uint16_t): 2239178479Sjb /* LINTED - alignment */ 2240268578Srpaulo err = dt_printf(dtp, fp, " %*d", width, *((uint16_t *)addr) / 2241178479Sjb (uint32_t)normal); 2242178479Sjb break; 2243178479Sjb case sizeof (uint8_t): 2244268578Srpaulo err = dt_printf(dtp, fp, " %*d", width, *((uint8_t *)addr) / 2245178479Sjb (uint32_t)normal); 2246178479Sjb break; 2247178479Sjb default: 2248268578Srpaulo err = dt_print_bytes(dtp, fp, addr, size, width, 0, 0); 2249178479Sjb break; 2250178479Sjb } 2251178479Sjb 2252178479Sjb return (err); 2253178479Sjb} 2254178479Sjb 2255178479Sjbint 2256178479Sjbdt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) 2257178479Sjb{ 2258178479Sjb int i, aggact = 0; 2259178479Sjb dt_print_aggdata_t *pd = arg; 2260178479Sjb const dtrace_aggdata_t *aggdata = aggsdata[0]; 2261178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 2262178479Sjb FILE *fp = pd->dtpa_fp; 2263178479Sjb dtrace_hdl_t *dtp = pd->dtpa_dtp; 2264178479Sjb dtrace_recdesc_t *rec; 2265178479Sjb dtrace_actkind_t act; 2266178479Sjb caddr_t addr; 2267178479Sjb size_t size; 2268178479Sjb 2269268578Srpaulo pd->dtpa_agghist = (aggdata->dtada_flags & DTRACE_A_TOTAL); 2270268578Srpaulo pd->dtpa_aggpack = (aggdata->dtada_flags & DTRACE_A_MINMAXBIN); 2271268578Srpaulo 2272178479Sjb /* 2273178479Sjb * Iterate over each record description in the key, printing the traced 2274178479Sjb * data, skipping the first datum (the tuple member created by the 2275178479Sjb * compiler). 2276178479Sjb */ 2277178479Sjb for (i = 1; i < agg->dtagd_nrecs; i++) { 2278178479Sjb rec = &agg->dtagd_rec[i]; 2279178479Sjb act = rec->dtrd_action; 2280178479Sjb addr = aggdata->dtada_data + rec->dtrd_offset; 2281178479Sjb size = rec->dtrd_size; 2282178479Sjb 2283178479Sjb if (DTRACEACT_ISAGG(act)) { 2284178479Sjb aggact = i; 2285178479Sjb break; 2286178479Sjb } 2287178479Sjb 2288268578Srpaulo if (dt_print_datum(dtp, fp, rec, addr, 2289268578Srpaulo size, aggdata, 1, pd) < 0) 2290178479Sjb return (-1); 2291178479Sjb 2292178479Sjb if (dt_buffered_flush(dtp, NULL, rec, aggdata, 2293178479Sjb DTRACE_BUFDATA_AGGKEY) < 0) 2294178479Sjb return (-1); 2295178479Sjb } 2296178479Sjb 2297178479Sjb assert(aggact != 0); 2298178479Sjb 2299178479Sjb for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) { 2300178479Sjb uint64_t normal; 2301178479Sjb 2302178479Sjb aggdata = aggsdata[i]; 2303178479Sjb agg = aggdata->dtada_desc; 2304178479Sjb rec = &agg->dtagd_rec[aggact]; 2305178479Sjb act = rec->dtrd_action; 2306178479Sjb addr = aggdata->dtada_data + rec->dtrd_offset; 2307178479Sjb size = rec->dtrd_size; 2308178479Sjb 2309178479Sjb assert(DTRACEACT_ISAGG(act)); 2310178479Sjb normal = aggdata->dtada_normal; 2311178479Sjb 2312268578Srpaulo if (dt_print_datum(dtp, fp, rec, addr, 2313268578Srpaulo size, aggdata, normal, pd) < 0) 2314178479Sjb return (-1); 2315178479Sjb 2316178479Sjb if (dt_buffered_flush(dtp, NULL, rec, aggdata, 2317178479Sjb DTRACE_BUFDATA_AGGVAL) < 0) 2318178479Sjb return (-1); 2319178479Sjb 2320178479Sjb if (!pd->dtpa_allunprint) 2321178479Sjb agg->dtagd_flags |= DTRACE_AGD_PRINTED; 2322178479Sjb } 2323178479Sjb 2324268578Srpaulo if (!pd->dtpa_agghist && !pd->dtpa_aggpack) { 2325268578Srpaulo if (dt_printf(dtp, fp, "\n") < 0) 2326268578Srpaulo return (-1); 2327268578Srpaulo } 2328178479Sjb 2329178479Sjb if (dt_buffered_flush(dtp, NULL, NULL, aggdata, 2330178479Sjb DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) 2331178479Sjb return (-1); 2332178479Sjb 2333178479Sjb return (0); 2334178479Sjb} 2335178479Sjb 2336178479Sjbint 2337178479Sjbdt_print_agg(const dtrace_aggdata_t *aggdata, void *arg) 2338178479Sjb{ 2339178479Sjb dt_print_aggdata_t *pd = arg; 2340178479Sjb dtrace_aggdesc_t *agg = aggdata->dtada_desc; 2341178479Sjb dtrace_aggvarid_t aggvarid = pd->dtpa_id; 2342178479Sjb 2343178479Sjb if (pd->dtpa_allunprint) { 2344178479Sjb if (agg->dtagd_flags & DTRACE_AGD_PRINTED) 2345178479Sjb return (0); 2346178479Sjb } else { 2347178479Sjb /* 2348178479Sjb * If we're not printing all unprinted aggregations, then the 2349178479Sjb * aggregation variable ID denotes a specific aggregation 2350178479Sjb * variable that we should print -- skip any other aggregations 2351178479Sjb * that we encounter. 2352178479Sjb */ 2353178479Sjb if (agg->dtagd_nrecs == 0) 2354178479Sjb return (0); 2355178479Sjb 2356178479Sjb if (aggvarid != agg->dtagd_varid) 2357178479Sjb return (0); 2358178479Sjb } 2359178479Sjb 2360178479Sjb return (dt_print_aggs(&aggdata, 1, arg)); 2361178479Sjb} 2362178479Sjb 2363178479Sjbint 2364178479Sjbdt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, 2365178479Sjb const char *option, const char *value) 2366178479Sjb{ 2367178479Sjb int len, rval; 2368178479Sjb char *msg; 2369178479Sjb const char *errstr; 2370178479Sjb dtrace_setoptdata_t optdata; 2371178479Sjb 2372178479Sjb bzero(&optdata, sizeof (optdata)); 2373178479Sjb (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval); 2374178479Sjb 2375178479Sjb if (dtrace_setopt(dtp, option, value) == 0) { 2376178479Sjb (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval); 2377178479Sjb optdata.dtsda_probe = data; 2378178479Sjb optdata.dtsda_option = option; 2379178479Sjb optdata.dtsda_handle = dtp; 2380178479Sjb 2381178479Sjb if ((rval = dt_handle_setopt(dtp, &optdata)) != 0) 2382178479Sjb return (rval); 2383178479Sjb 2384178479Sjb return (0); 2385178479Sjb } 2386178479Sjb 2387178479Sjb errstr = dtrace_errmsg(dtp, dtrace_errno(dtp)); 2388178479Sjb len = strlen(option) + strlen(value) + strlen(errstr) + 80; 2389178479Sjb msg = alloca(len); 2390178479Sjb 2391178479Sjb (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n", 2392178479Sjb option, value, errstr); 2393178479Sjb 2394178479Sjb if ((rval = dt_handle_liberr(dtp, data, msg)) == 0) 2395178479Sjb return (0); 2396178479Sjb 2397178479Sjb return (rval); 2398178479Sjb} 2399178479Sjb 2400178479Sjbstatic int 2401250574Smarkjdt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, 2402250574Smarkj dtrace_bufdesc_t *buf, boolean_t just_one, 2403178479Sjb dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) 2404178479Sjb{ 2405178479Sjb dtrace_epid_t id; 2406250574Smarkj size_t offs; 2407178479Sjb int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 2408178479Sjb int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 2409178479Sjb int rval, i, n; 2410248690Spfg uint64_t tracememsize = 0; 2411178479Sjb dtrace_probedata_t data; 2412178479Sjb uint64_t drops; 2413178479Sjb 2414178479Sjb bzero(&data, sizeof (data)); 2415178479Sjb data.dtpda_handle = dtp; 2416178479Sjb data.dtpda_cpu = cpu; 2417253725Spfg data.dtpda_flow = dtp->dt_flow; 2418253725Spfg data.dtpda_indent = dtp->dt_indent; 2419253725Spfg data.dtpda_prefix = dtp->dt_prefix; 2420178479Sjb 2421250574Smarkj for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) { 2422178479Sjb dtrace_eprobedesc_t *epd; 2423178479Sjb 2424178479Sjb /* 2425178479Sjb * We're guaranteed to have an ID. 2426178479Sjb */ 2427178479Sjb id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 2428178479Sjb 2429178479Sjb if (id == DTRACE_EPIDNONE) { 2430178479Sjb /* 2431178479Sjb * This is filler to assure proper alignment of the 2432178479Sjb * next record; we simply ignore it. 2433178479Sjb */ 2434178479Sjb offs += sizeof (id); 2435178479Sjb continue; 2436178479Sjb } 2437178479Sjb 2438178479Sjb if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc, 2439178479Sjb &data.dtpda_pdesc)) != 0) 2440178479Sjb return (rval); 2441178479Sjb 2442178479Sjb epd = data.dtpda_edesc; 2443178479Sjb data.dtpda_data = buf->dtbd_data + offs; 2444178479Sjb 2445178479Sjb if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) { 2446178479Sjb rval = dt_handle(dtp, &data); 2447178479Sjb 2448178479Sjb if (rval == DTRACE_CONSUME_NEXT) 2449178479Sjb goto nextepid; 2450178479Sjb 2451178479Sjb if (rval == DTRACE_CONSUME_ERROR) 2452178479Sjb return (-1); 2453178479Sjb } 2454178479Sjb 2455178479Sjb if (flow) 2456250574Smarkj (void) dt_flowindent(dtp, &data, dtp->dt_last_epid, 2457250574Smarkj buf, offs); 2458178479Sjb 2459178479Sjb rval = (*efunc)(&data, arg); 2460178479Sjb 2461178479Sjb if (flow) { 2462178479Sjb if (data.dtpda_flow == DTRACEFLOW_ENTRY) 2463178479Sjb data.dtpda_indent += 2; 2464178479Sjb } 2465178479Sjb 2466178479Sjb if (rval == DTRACE_CONSUME_NEXT) 2467178479Sjb goto nextepid; 2468178479Sjb 2469178479Sjb if (rval == DTRACE_CONSUME_ABORT) 2470178479Sjb return (dt_set_errno(dtp, EDT_DIRABORT)); 2471178479Sjb 2472178479Sjb if (rval != DTRACE_CONSUME_THIS) 2473178479Sjb return (dt_set_errno(dtp, EDT_BADRVAL)); 2474178479Sjb 2475178479Sjb for (i = 0; i < epd->dtepd_nrecs; i++) { 2476250574Smarkj caddr_t addr; 2477178479Sjb dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; 2478178479Sjb dtrace_actkind_t act = rec->dtrd_action; 2479178479Sjb 2480178479Sjb data.dtpda_data = buf->dtbd_data + offs + 2481178479Sjb rec->dtrd_offset; 2482178479Sjb addr = data.dtpda_data; 2483178479Sjb 2484178479Sjb if (act == DTRACEACT_LIBACT) { 2485178479Sjb uint64_t arg = rec->dtrd_arg; 2486178479Sjb dtrace_aggvarid_t id; 2487178479Sjb 2488178479Sjb switch (arg) { 2489178479Sjb case DT_ACT_CLEAR: 2490178479Sjb /* LINTED - alignment */ 2491178479Sjb id = *((dtrace_aggvarid_t *)addr); 2492178479Sjb (void) dtrace_aggregate_walk(dtp, 2493178479Sjb dt_clear_agg, &id); 2494178479Sjb continue; 2495178479Sjb 2496178479Sjb case DT_ACT_DENORMALIZE: 2497178479Sjb /* LINTED - alignment */ 2498178479Sjb id = *((dtrace_aggvarid_t *)addr); 2499178479Sjb (void) dtrace_aggregate_walk(dtp, 2500178479Sjb dt_denormalize_agg, &id); 2501178479Sjb continue; 2502178479Sjb 2503178479Sjb case DT_ACT_FTRUNCATE: 2504178479Sjb if (fp == NULL) 2505178479Sjb continue; 2506178479Sjb 2507178479Sjb (void) fflush(fp); 2508178479Sjb (void) ftruncate(fileno(fp), 0); 2509178479Sjb (void) fseeko(fp, 0, SEEK_SET); 2510178479Sjb continue; 2511178479Sjb 2512178479Sjb case DT_ACT_NORMALIZE: 2513178479Sjb if (i == epd->dtepd_nrecs - 1) 2514178479Sjb return (dt_set_errno(dtp, 2515178479Sjb EDT_BADNORMAL)); 2516178479Sjb 2517178479Sjb if (dt_normalize(dtp, 2518178479Sjb buf->dtbd_data + offs, rec) != 0) 2519178479Sjb return (-1); 2520178479Sjb 2521178479Sjb i++; 2522178479Sjb continue; 2523178479Sjb 2524178479Sjb case DT_ACT_SETOPT: { 2525178479Sjb uint64_t *opts = dtp->dt_options; 2526178479Sjb dtrace_recdesc_t *valrec; 2527178479Sjb uint32_t valsize; 2528178479Sjb caddr_t val; 2529178479Sjb int rv; 2530178479Sjb 2531178479Sjb if (i == epd->dtepd_nrecs - 1) { 2532178479Sjb return (dt_set_errno(dtp, 2533178479Sjb EDT_BADSETOPT)); 2534178479Sjb } 2535178479Sjb 2536178479Sjb valrec = &epd->dtepd_rec[++i]; 2537178479Sjb valsize = valrec->dtrd_size; 2538178479Sjb 2539178479Sjb if (valrec->dtrd_action != act || 2540178479Sjb valrec->dtrd_arg != arg) { 2541178479Sjb return (dt_set_errno(dtp, 2542178479Sjb EDT_BADSETOPT)); 2543178479Sjb } 2544178479Sjb 2545178479Sjb if (valsize > sizeof (uint64_t)) { 2546178479Sjb val = buf->dtbd_data + offs + 2547178479Sjb valrec->dtrd_offset; 2548178479Sjb } else { 2549178479Sjb val = "1"; 2550178479Sjb } 2551178479Sjb 2552178479Sjb rv = dt_setopt(dtp, &data, addr, val); 2553178479Sjb 2554178479Sjb if (rv != 0) 2555178479Sjb return (-1); 2556178479Sjb 2557178479Sjb flow = (opts[DTRACEOPT_FLOWINDENT] != 2558178479Sjb DTRACEOPT_UNSET); 2559178479Sjb quiet = (opts[DTRACEOPT_QUIET] != 2560178479Sjb DTRACEOPT_UNSET); 2561178479Sjb 2562178479Sjb continue; 2563178479Sjb } 2564178479Sjb 2565178479Sjb case DT_ACT_TRUNC: 2566178479Sjb if (i == epd->dtepd_nrecs - 1) 2567178479Sjb return (dt_set_errno(dtp, 2568178479Sjb EDT_BADTRUNC)); 2569178479Sjb 2570178479Sjb if (dt_trunc(dtp, 2571178479Sjb buf->dtbd_data + offs, rec) != 0) 2572178479Sjb return (-1); 2573178479Sjb 2574178479Sjb i++; 2575178479Sjb continue; 2576178479Sjb 2577178479Sjb default: 2578178479Sjb continue; 2579178479Sjb } 2580178479Sjb } 2581178479Sjb 2582248690Spfg if (act == DTRACEACT_TRACEMEM_DYNSIZE && 2583248690Spfg rec->dtrd_size == sizeof (uint64_t)) { 2584248708Spfg /* LINTED - alignment */ 2585248690Spfg tracememsize = *((unsigned long long *)addr); 2586248690Spfg continue; 2587248690Spfg } 2588248690Spfg 2589178479Sjb rval = (*rfunc)(&data, rec, arg); 2590178479Sjb 2591178479Sjb if (rval == DTRACE_CONSUME_NEXT) 2592178479Sjb continue; 2593178479Sjb 2594178479Sjb if (rval == DTRACE_CONSUME_ABORT) 2595178479Sjb return (dt_set_errno(dtp, EDT_DIRABORT)); 2596178479Sjb 2597178479Sjb if (rval != DTRACE_CONSUME_THIS) 2598178479Sjb return (dt_set_errno(dtp, EDT_BADRVAL)); 2599178479Sjb 2600178479Sjb if (act == DTRACEACT_STACK) { 2601178479Sjb int depth = rec->dtrd_arg; 2602178479Sjb 2603178479Sjb if (dt_print_stack(dtp, fp, NULL, addr, depth, 2604178479Sjb rec->dtrd_size / depth) < 0) 2605178479Sjb return (-1); 2606178479Sjb goto nextrec; 2607178479Sjb } 2608178479Sjb 2609178479Sjb if (act == DTRACEACT_USTACK || 2610178479Sjb act == DTRACEACT_JSTACK) { 2611178479Sjb if (dt_print_ustack(dtp, fp, NULL, 2612178479Sjb addr, rec->dtrd_arg) < 0) 2613178479Sjb return (-1); 2614178479Sjb goto nextrec; 2615178479Sjb } 2616178479Sjb 2617178479Sjb if (act == DTRACEACT_SYM) { 2618178479Sjb if (dt_print_sym(dtp, fp, NULL, addr) < 0) 2619178479Sjb return (-1); 2620178479Sjb goto nextrec; 2621178479Sjb } 2622178479Sjb 2623178479Sjb if (act == DTRACEACT_MOD) { 2624178479Sjb if (dt_print_mod(dtp, fp, NULL, addr) < 0) 2625178479Sjb return (-1); 2626178479Sjb goto nextrec; 2627178479Sjb } 2628178479Sjb 2629178479Sjb if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) { 2630178479Sjb if (dt_print_usym(dtp, fp, addr, act) < 0) 2631178479Sjb return (-1); 2632178479Sjb goto nextrec; 2633178479Sjb } 2634178479Sjb 2635178479Sjb if (act == DTRACEACT_UMOD) { 2636178479Sjb if (dt_print_umod(dtp, fp, NULL, addr) < 0) 2637178479Sjb return (-1); 2638178479Sjb goto nextrec; 2639178479Sjb } 2640178479Sjb 2641178576Sjb if (act == DTRACEACT_PRINTM) { 2642178576Sjb if (dt_print_memory(dtp, fp, addr) < 0) 2643178576Sjb return (-1); 2644178576Sjb goto nextrec; 2645178576Sjb } 2646178576Sjb 2647178576Sjb if (act == DTRACEACT_PRINTT) { 2648178576Sjb if (dt_print_type(dtp, fp, addr) < 0) 2649178576Sjb return (-1); 2650178576Sjb goto nextrec; 2651178576Sjb } 2652178576Sjb 2653178479Sjb if (DTRACEACT_ISPRINTFLIKE(act)) { 2654178479Sjb void *fmtdata; 2655178479Sjb int (*func)(dtrace_hdl_t *, FILE *, void *, 2656178479Sjb const dtrace_probedata_t *, 2657178479Sjb const dtrace_recdesc_t *, uint_t, 2658178479Sjb const void *buf, size_t); 2659178479Sjb 2660178479Sjb if ((fmtdata = dt_format_lookup(dtp, 2661178479Sjb rec->dtrd_format)) == NULL) 2662178479Sjb goto nofmt; 2663178479Sjb 2664178479Sjb switch (act) { 2665178479Sjb case DTRACEACT_PRINTF: 2666178479Sjb func = dtrace_fprintf; 2667178479Sjb break; 2668178479Sjb case DTRACEACT_PRINTA: 2669178479Sjb func = dtrace_fprinta; 2670178479Sjb break; 2671178479Sjb case DTRACEACT_SYSTEM: 2672178479Sjb func = dtrace_system; 2673178479Sjb break; 2674178479Sjb case DTRACEACT_FREOPEN: 2675178479Sjb func = dtrace_freopen; 2676178479Sjb break; 2677178479Sjb } 2678178479Sjb 2679178479Sjb n = (*func)(dtp, fp, fmtdata, &data, 2680178479Sjb rec, epd->dtepd_nrecs - i, 2681178479Sjb (uchar_t *)buf->dtbd_data + offs, 2682178479Sjb buf->dtbd_size - offs); 2683178479Sjb 2684178479Sjb if (n < 0) 2685178479Sjb return (-1); /* errno is set for us */ 2686178479Sjb 2687178479Sjb if (n > 0) 2688178479Sjb i += n - 1; 2689178479Sjb goto nextrec; 2690178479Sjb } 2691178479Sjb 2692248708Spfg /* 2693248708Spfg * If this is a DIF expression, and the record has a 2694248708Spfg * format set, this indicates we have a CTF type name 2695248708Spfg * associated with the data and we should try to print 2696248708Spfg * it out by type. 2697248708Spfg */ 2698248708Spfg if (act == DTRACEACT_DIFEXPR) { 2699248708Spfg const char *strdata = dt_strdata_lookup(dtp, 2700248708Spfg rec->dtrd_format); 2701248708Spfg if (strdata != NULL) { 2702248708Spfg n = dtrace_print(dtp, fp, strdata, 2703248708Spfg addr, rec->dtrd_size); 2704248708Spfg 2705248708Spfg /* 2706248708Spfg * dtrace_print() will return -1 on 2707248708Spfg * error, or return the number of bytes 2708248708Spfg * consumed. It will return 0 if the 2709248708Spfg * type couldn't be determined, and we 2710248708Spfg * should fall through to the normal 2711248708Spfg * trace method. 2712248708Spfg */ 2713248708Spfg if (n < 0) 2714248708Spfg return (-1); 2715248708Spfg 2716248708Spfg if (n > 0) 2717248708Spfg goto nextrec; 2718248708Spfg } 2719248708Spfg } 2720248708Spfg 2721178479Sjbnofmt: 2722178479Sjb if (act == DTRACEACT_PRINTA) { 2723178479Sjb dt_print_aggdata_t pd; 2724178479Sjb dtrace_aggvarid_t *aggvars; 2725178479Sjb int j, naggvars = 0; 2726178479Sjb size_t size = ((epd->dtepd_nrecs - i) * 2727178479Sjb sizeof (dtrace_aggvarid_t)); 2728178479Sjb 2729178479Sjb if ((aggvars = dt_alloc(dtp, size)) == NULL) 2730178479Sjb return (-1); 2731178479Sjb 2732178479Sjb /* 2733178479Sjb * This might be a printa() with multiple 2734178479Sjb * aggregation variables. We need to scan 2735178479Sjb * forward through the records until we find 2736178479Sjb * a record from a different statement. 2737178479Sjb */ 2738178479Sjb for (j = i; j < epd->dtepd_nrecs; j++) { 2739178479Sjb dtrace_recdesc_t *nrec; 2740178479Sjb caddr_t naddr; 2741178479Sjb 2742178479Sjb nrec = &epd->dtepd_rec[j]; 2743178479Sjb 2744178479Sjb if (nrec->dtrd_uarg != rec->dtrd_uarg) 2745178479Sjb break; 2746178479Sjb 2747178479Sjb if (nrec->dtrd_action != act) { 2748178479Sjb return (dt_set_errno(dtp, 2749178479Sjb EDT_BADAGG)); 2750178479Sjb } 2751178479Sjb 2752178479Sjb naddr = buf->dtbd_data + offs + 2753178479Sjb nrec->dtrd_offset; 2754178479Sjb 2755178479Sjb aggvars[naggvars++] = 2756178479Sjb /* LINTED - alignment */ 2757178479Sjb *((dtrace_aggvarid_t *)naddr); 2758178479Sjb } 2759178479Sjb 2760178479Sjb i = j - 1; 2761178479Sjb bzero(&pd, sizeof (pd)); 2762178479Sjb pd.dtpa_dtp = dtp; 2763178479Sjb pd.dtpa_fp = fp; 2764178479Sjb 2765178479Sjb assert(naggvars >= 1); 2766178479Sjb 2767178479Sjb if (naggvars == 1) { 2768178479Sjb pd.dtpa_id = aggvars[0]; 2769178479Sjb dt_free(dtp, aggvars); 2770178479Sjb 2771178479Sjb if (dt_printf(dtp, fp, "\n") < 0 || 2772178479Sjb dtrace_aggregate_walk_sorted(dtp, 2773178479Sjb dt_print_agg, &pd) < 0) 2774178479Sjb return (-1); 2775178479Sjb goto nextrec; 2776178479Sjb } 2777178479Sjb 2778178479Sjb if (dt_printf(dtp, fp, "\n") < 0 || 2779178479Sjb dtrace_aggregate_walk_joined(dtp, aggvars, 2780178479Sjb naggvars, dt_print_aggs, &pd) < 0) { 2781178479Sjb dt_free(dtp, aggvars); 2782178479Sjb return (-1); 2783178479Sjb } 2784178479Sjb 2785178479Sjb dt_free(dtp, aggvars); 2786178479Sjb goto nextrec; 2787178479Sjb } 2788178479Sjb 2789248690Spfg if (act == DTRACEACT_TRACEMEM) { 2790248690Spfg if (tracememsize == 0 || 2791248690Spfg tracememsize > rec->dtrd_size) { 2792248690Spfg tracememsize = rec->dtrd_size; 2793248690Spfg } 2794248690Spfg 2795248690Spfg n = dt_print_bytes(dtp, fp, addr, 2796268578Srpaulo tracememsize, -33, quiet, 1); 2797248690Spfg 2798248690Spfg tracememsize = 0; 2799248690Spfg 2800248690Spfg if (n < 0) 2801248690Spfg return (-1); 2802248690Spfg 2803248690Spfg goto nextrec; 2804248690Spfg } 2805248690Spfg 2806178479Sjb switch (rec->dtrd_size) { 2807178479Sjb case sizeof (uint64_t): 2808178479Sjb n = dt_printf(dtp, fp, 2809178479Sjb quiet ? "%lld" : " %16lld", 2810178479Sjb /* LINTED - alignment */ 2811178479Sjb *((unsigned long long *)addr)); 2812178479Sjb break; 2813178479Sjb case sizeof (uint32_t): 2814178479Sjb n = dt_printf(dtp, fp, quiet ? "%d" : " %8d", 2815178479Sjb /* LINTED - alignment */ 2816178479Sjb *((uint32_t *)addr)); 2817178479Sjb break; 2818178479Sjb case sizeof (uint16_t): 2819178479Sjb n = dt_printf(dtp, fp, quiet ? "%d" : " %5d", 2820178479Sjb /* LINTED - alignment */ 2821178479Sjb *((uint16_t *)addr)); 2822178479Sjb break; 2823178479Sjb case sizeof (uint8_t): 2824178479Sjb n = dt_printf(dtp, fp, quiet ? "%d" : " %3d", 2825178479Sjb *((uint8_t *)addr)); 2826178479Sjb break; 2827178479Sjb default: 2828178479Sjb n = dt_print_bytes(dtp, fp, addr, 2829268578Srpaulo rec->dtrd_size, -33, quiet, 0); 2830178479Sjb break; 2831178479Sjb } 2832178479Sjb 2833178479Sjb if (n < 0) 2834178479Sjb return (-1); /* errno is set for us */ 2835178479Sjb 2836178479Sjbnextrec: 2837178479Sjb if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0) 2838178479Sjb return (-1); /* errno is set for us */ 2839178479Sjb } 2840178479Sjb 2841178479Sjb /* 2842178479Sjb * Call the record callback with a NULL record to indicate 2843178479Sjb * that we're done processing this EPID. 2844178479Sjb */ 2845178479Sjb rval = (*rfunc)(&data, NULL, arg); 2846178479Sjbnextepid: 2847178479Sjb offs += epd->dtepd_size; 2848250574Smarkj dtp->dt_last_epid = id; 2849250574Smarkj if (just_one) { 2850250574Smarkj buf->dtbd_oldest = offs; 2851250574Smarkj break; 2852250574Smarkj } 2853178479Sjb } 2854178479Sjb 2855250574Smarkj dtp->dt_flow = data.dtpda_flow; 2856250574Smarkj dtp->dt_indent = data.dtpda_indent; 2857250574Smarkj dtp->dt_prefix = data.dtpda_prefix; 2858178479Sjb 2859178479Sjb if ((drops = buf->dtbd_drops) == 0) 2860178479Sjb return (0); 2861178479Sjb 2862178479Sjb /* 2863178479Sjb * Explicitly zero the drops to prevent us from processing them again. 2864178479Sjb */ 2865178479Sjb buf->dtbd_drops = 0; 2866178479Sjb 2867178479Sjb return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); 2868178479Sjb} 2869178479Sjb 2870250574Smarkj/* 2871250574Smarkj * Reduce memory usage by shrinking the buffer if it's no more than half full. 2872250574Smarkj * Note, we need to preserve the alignment of the data at dtbd_oldest, which is 2873250574Smarkj * only 4-byte aligned. 2874250574Smarkj */ 2875250574Smarkjstatic void 2876250574Smarkjdt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize) 2877250574Smarkj{ 2878250574Smarkj uint64_t used = buf->dtbd_size - buf->dtbd_oldest; 2879250574Smarkj if (used < cursize / 2) { 2880250574Smarkj int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2881250574Smarkj char *newdata = dt_alloc(dtp, used + misalign); 2882250574Smarkj if (newdata == NULL) 2883250574Smarkj return; 2884250574Smarkj bzero(newdata, misalign); 2885250574Smarkj bcopy(buf->dtbd_data + buf->dtbd_oldest, 2886250574Smarkj newdata + misalign, used); 2887250574Smarkj dt_free(dtp, buf->dtbd_data); 2888250574Smarkj buf->dtbd_oldest = misalign; 2889250574Smarkj buf->dtbd_size = used + misalign; 2890250574Smarkj buf->dtbd_data = newdata; 2891250574Smarkj } 2892250574Smarkj} 2893250574Smarkj 2894250574Smarkj/* 2895250574Smarkj * If the ring buffer has wrapped, the data is not in order. Rearrange it 2896250574Smarkj * so that it is. Note, we need to preserve the alignment of the data at 2897250574Smarkj * dtbd_oldest, which is only 4-byte aligned. 2898250574Smarkj */ 2899250574Smarkjstatic int 2900250574Smarkjdt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2901250574Smarkj{ 2902250574Smarkj int misalign; 2903250574Smarkj char *newdata, *ndp; 2904250574Smarkj 2905250574Smarkj if (buf->dtbd_oldest == 0) 2906250574Smarkj return (0); 2907250574Smarkj 2908250574Smarkj misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2909250574Smarkj newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign); 2910250574Smarkj 2911250574Smarkj if (newdata == NULL) 2912250574Smarkj return (-1); 2913250574Smarkj 2914250574Smarkj assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1))); 2915250574Smarkj 2916250574Smarkj bzero(ndp, misalign); 2917250574Smarkj ndp += misalign; 2918250574Smarkj 2919250574Smarkj bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp, 2920250574Smarkj buf->dtbd_size - buf->dtbd_oldest); 2921250574Smarkj ndp += buf->dtbd_size - buf->dtbd_oldest; 2922250574Smarkj 2923250574Smarkj bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest); 2924250574Smarkj 2925250574Smarkj dt_free(dtp, buf->dtbd_data); 2926250574Smarkj buf->dtbd_oldest = 0; 2927250574Smarkj buf->dtbd_data = newdata; 2928250574Smarkj buf->dtbd_size += misalign; 2929250574Smarkj 2930250574Smarkj return (0); 2931250574Smarkj} 2932250574Smarkj 2933250574Smarkjstatic void 2934250574Smarkjdt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2935250574Smarkj{ 2936250574Smarkj dt_free(dtp, buf->dtbd_data); 2937250574Smarkj dt_free(dtp, buf); 2938250574Smarkj} 2939250574Smarkj 2940250574Smarkj/* 2941250574Smarkj * Returns 0 on success, in which case *cbp will be filled in if we retrieved 2942250574Smarkj * data, or NULL if there is no data for this CPU. 2943250574Smarkj * Returns -1 on failure and sets dt_errno. 2944250574Smarkj */ 2945250574Smarkjstatic int 2946250574Smarkjdt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp) 2947250574Smarkj{ 2948250574Smarkj dtrace_optval_t size; 2949250574Smarkj dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf)); 2950270214Smarkj int error, rval; 2951250574Smarkj 2952250574Smarkj if (buf == NULL) 2953250574Smarkj return (-1); 2954250574Smarkj 2955250574Smarkj (void) dtrace_getopt(dtp, "bufsize", &size); 2956250574Smarkj buf->dtbd_data = dt_alloc(dtp, size); 2957250574Smarkj if (buf->dtbd_data == NULL) { 2958250574Smarkj dt_free(dtp, buf); 2959250574Smarkj return (-1); 2960250574Smarkj } 2961250574Smarkj buf->dtbd_size = size; 2962250574Smarkj buf->dtbd_cpu = cpu; 2963250574Smarkj 2964250574Smarkj#if defined(sun) 2965250574Smarkj if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 2966250574Smarkj#else 2967250574Smarkj if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) { 2968250574Smarkj#endif 2969250574Smarkj /* 2970250574Smarkj * If we failed with ENOENT, it may be because the 2971250574Smarkj * CPU was unconfigured -- this is okay. Any other 2972250574Smarkj * error, however, is unexpected. 2973250574Smarkj */ 2974250574Smarkj if (errno == ENOENT) { 2975250574Smarkj *bufp = NULL; 2976270214Smarkj rval = 0; 2977270214Smarkj } else 2978270214Smarkj rval = dt_set_errno(dtp, errno); 2979250574Smarkj 2980270214Smarkj dt_put_buf(dtp, buf); 2981270214Smarkj return (rval); 2982250574Smarkj } 2983250574Smarkj 2984250574Smarkj error = dt_unring_buf(dtp, buf); 2985250574Smarkj if (error != 0) { 2986250574Smarkj dt_put_buf(dtp, buf); 2987250574Smarkj return (error); 2988250574Smarkj } 2989250574Smarkj dt_realloc_buf(dtp, buf, size); 2990250574Smarkj 2991250574Smarkj *bufp = buf; 2992250574Smarkj return (0); 2993250574Smarkj} 2994250574Smarkj 2995178479Sjbtypedef struct dt_begin { 2996178479Sjb dtrace_consume_probe_f *dtbgn_probefunc; 2997178479Sjb dtrace_consume_rec_f *dtbgn_recfunc; 2998178479Sjb void *dtbgn_arg; 2999178479Sjb dtrace_handle_err_f *dtbgn_errhdlr; 3000178479Sjb void *dtbgn_errarg; 3001178479Sjb int dtbgn_beginonly; 3002178479Sjb} dt_begin_t; 3003178479Sjb 3004178479Sjbstatic int 3005178479Sjbdt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) 3006178479Sjb{ 3007253725Spfg dt_begin_t *begin = arg; 3008178479Sjb dtrace_probedesc_t *pd = data->dtpda_pdesc; 3009178479Sjb 3010178479Sjb int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 3011178479Sjb int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 3012178479Sjb 3013178479Sjb if (begin->dtbgn_beginonly) { 3014178479Sjb if (!(r1 && r2)) 3015178479Sjb return (DTRACE_CONSUME_NEXT); 3016178479Sjb } else { 3017178479Sjb if (r1 && r2) 3018178479Sjb return (DTRACE_CONSUME_NEXT); 3019178479Sjb } 3020178479Sjb 3021178479Sjb /* 3022178479Sjb * We have a record that we're interested in. Now call the underlying 3023178479Sjb * probe function... 3024178479Sjb */ 3025178479Sjb return (begin->dtbgn_probefunc(data, begin->dtbgn_arg)); 3026178479Sjb} 3027178479Sjb 3028178479Sjbstatic int 3029178479Sjbdt_consume_begin_record(const dtrace_probedata_t *data, 3030178479Sjb const dtrace_recdesc_t *rec, void *arg) 3031178479Sjb{ 3032253725Spfg dt_begin_t *begin = arg; 3033178479Sjb 3034178479Sjb return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); 3035178479Sjb} 3036178479Sjb 3037178479Sjbstatic int 3038178479Sjbdt_consume_begin_error(const dtrace_errdata_t *data, void *arg) 3039178479Sjb{ 3040178479Sjb dt_begin_t *begin = (dt_begin_t *)arg; 3041178479Sjb dtrace_probedesc_t *pd = data->dteda_pdesc; 3042178479Sjb 3043178479Sjb int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 3044178479Sjb int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 3045178479Sjb 3046178479Sjb if (begin->dtbgn_beginonly) { 3047178479Sjb if (!(r1 && r2)) 3048178479Sjb return (DTRACE_HANDLE_OK); 3049178479Sjb } else { 3050178479Sjb if (r1 && r2) 3051178479Sjb return (DTRACE_HANDLE_OK); 3052178479Sjb } 3053178479Sjb 3054178479Sjb return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg)); 3055178479Sjb} 3056178479Sjb 3057178479Sjbstatic int 3058250574Smarkjdt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, 3059178479Sjb dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 3060178479Sjb{ 3061178479Sjb /* 3062178479Sjb * There's this idea that the BEGIN probe should be processed before 3063178479Sjb * everything else, and that the END probe should be processed after 3064178479Sjb * anything else. In the common case, this is pretty easy to deal 3065178479Sjb * with. However, a situation may arise where the BEGIN enabling and 3066178479Sjb * END enabling are on the same CPU, and some enabling in the middle 3067178479Sjb * occurred on a different CPU. To deal with this (blech!) we need to 3068178479Sjb * consume the BEGIN buffer up until the end of the BEGIN probe, and 3069178479Sjb * then set it aside. We will then process every other CPU, and then 3070178479Sjb * we'll return to the BEGIN CPU and process the rest of the data 3071178479Sjb * (which will inevitably include the END probe, if any). Making this 3072178479Sjb * even more complicated (!) is the library's ERROR enabling. Because 3073178479Sjb * this enabling is processed before we even get into the consume call 3074178479Sjb * back, any ERROR firing would result in the library's ERROR enabling 3075178479Sjb * being processed twice -- once in our first pass (for BEGIN probes), 3076178479Sjb * and again in our second pass (for everything but BEGIN probes). To 3077178479Sjb * deal with this, we interpose on the ERROR handler to assure that we 3078178479Sjb * only process ERROR enablings induced by BEGIN enablings in the 3079178479Sjb * first pass, and that we only process ERROR enablings _not_ induced 3080178479Sjb * by BEGIN enablings in the second pass. 3081178479Sjb */ 3082250574Smarkj 3083178479Sjb dt_begin_t begin; 3084178479Sjb processorid_t cpu = dtp->dt_beganon; 3085178479Sjb int rval, i; 3086178479Sjb static int max_ncpus; 3087250574Smarkj dtrace_bufdesc_t *buf; 3088178479Sjb 3089178479Sjb dtp->dt_beganon = -1; 3090178479Sjb 3091250574Smarkj if (dt_get_buf(dtp, cpu, &buf) != 0) 3092250574Smarkj return (-1); 3093250574Smarkj if (buf == NULL) 3094250574Smarkj return (0); 3095178479Sjb 3096178479Sjb if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { 3097178479Sjb /* 3098178479Sjb * This is the simple case. We're either not stopped, or if 3099178479Sjb * we are, we actually processed any END probes on another 3100178479Sjb * CPU. We can simply consume this buffer and return. 3101178479Sjb */ 3102250574Smarkj rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 3103250574Smarkj pf, rf, arg); 3104250574Smarkj dt_put_buf(dtp, buf); 3105250574Smarkj return (rval); 3106178479Sjb } 3107178479Sjb 3108178479Sjb begin.dtbgn_probefunc = pf; 3109178479Sjb begin.dtbgn_recfunc = rf; 3110178479Sjb begin.dtbgn_arg = arg; 3111178479Sjb begin.dtbgn_beginonly = 1; 3112178479Sjb 3113178479Sjb /* 3114178479Sjb * We need to interpose on the ERROR handler to be sure that we 3115178479Sjb * only process ERRORs induced by BEGIN. 3116178479Sjb */ 3117178479Sjb begin.dtbgn_errhdlr = dtp->dt_errhdlr; 3118178479Sjb begin.dtbgn_errarg = dtp->dt_errarg; 3119178479Sjb dtp->dt_errhdlr = dt_consume_begin_error; 3120178479Sjb dtp->dt_errarg = &begin; 3121178479Sjb 3122250574Smarkj rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 3123250574Smarkj dt_consume_begin_probe, dt_consume_begin_record, &begin); 3124178479Sjb 3125178479Sjb dtp->dt_errhdlr = begin.dtbgn_errhdlr; 3126178479Sjb dtp->dt_errarg = begin.dtbgn_errarg; 3127178479Sjb 3128250574Smarkj if (rval != 0) { 3129250574Smarkj dt_put_buf(dtp, buf); 3130178479Sjb return (rval); 3131250574Smarkj } 3132178479Sjb 3133178479Sjb if (max_ncpus == 0) 3134178479Sjb max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 3135178479Sjb 3136178479Sjb for (i = 0; i < max_ncpus; i++) { 3137250574Smarkj dtrace_bufdesc_t *nbuf; 3138178479Sjb if (i == cpu) 3139178479Sjb continue; 3140178479Sjb 3141250574Smarkj if (dt_get_buf(dtp, i, &nbuf) != 0) { 3142250574Smarkj dt_put_buf(dtp, buf); 3143250574Smarkj return (-1); 3144178479Sjb } 3145250574Smarkj if (nbuf == NULL) 3146250574Smarkj continue; 3147178479Sjb 3148250574Smarkj rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE, 3149250574Smarkj pf, rf, arg); 3150250574Smarkj dt_put_buf(dtp, nbuf); 3151250574Smarkj if (rval != 0) { 3152250574Smarkj dt_put_buf(dtp, buf); 3153178479Sjb return (rval); 3154178479Sjb } 3155178479Sjb } 3156178479Sjb 3157178479Sjb /* 3158178479Sjb * Okay -- we're done with the other buffers. Now we want to 3159178479Sjb * reconsume the first buffer -- but this time we're looking for 3160178479Sjb * everything _but_ BEGIN. And of course, in order to only consume 3161178479Sjb * those ERRORs _not_ associated with BEGIN, we need to reinstall our 3162178479Sjb * ERROR interposition function... 3163178479Sjb */ 3164178479Sjb begin.dtbgn_beginonly = 0; 3165178479Sjb 3166178479Sjb assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr); 3167178479Sjb assert(begin.dtbgn_errarg == dtp->dt_errarg); 3168178479Sjb dtp->dt_errhdlr = dt_consume_begin_error; 3169178479Sjb dtp->dt_errarg = &begin; 3170178479Sjb 3171250574Smarkj rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 3172250574Smarkj dt_consume_begin_probe, dt_consume_begin_record, &begin); 3173178479Sjb 3174178479Sjb dtp->dt_errhdlr = begin.dtbgn_errhdlr; 3175178479Sjb dtp->dt_errarg = begin.dtbgn_errarg; 3176178479Sjb 3177178479Sjb return (rval); 3178178479Sjb} 3179178479Sjb 3180250574Smarkj/* ARGSUSED */ 3181250574Smarkjstatic uint64_t 3182250574Smarkjdt_buf_oldest(void *elem, void *arg) 3183250574Smarkj{ 3184250574Smarkj dtrace_bufdesc_t *buf = elem; 3185250574Smarkj size_t offs = buf->dtbd_oldest; 3186250574Smarkj 3187250574Smarkj while (offs < buf->dtbd_size) { 3188250574Smarkj dtrace_rechdr_t *dtrh = 3189250574Smarkj /* LINTED - alignment */ 3190250574Smarkj (dtrace_rechdr_t *)(buf->dtbd_data + offs); 3191250574Smarkj if (dtrh->dtrh_epid == DTRACE_EPIDNONE) { 3192250574Smarkj offs += sizeof (dtrace_epid_t); 3193250574Smarkj } else { 3194250574Smarkj return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh)); 3195250574Smarkj } 3196250574Smarkj } 3197250574Smarkj 3198250574Smarkj /* There are no records left; use the time the buffer was retrieved. */ 3199250574Smarkj return (buf->dtbd_timestamp); 3200250574Smarkj} 3201250574Smarkj 3202178479Sjbint 3203178479Sjbdtrace_consume(dtrace_hdl_t *dtp, FILE *fp, 3204178479Sjb dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 3205178479Sjb{ 3206178479Sjb dtrace_optval_t size; 3207178479Sjb static int max_ncpus; 3208178479Sjb int i, rval; 3209178479Sjb dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE]; 3210178479Sjb hrtime_t now = gethrtime(); 3211178479Sjb 3212178479Sjb if (dtp->dt_lastswitch != 0) { 3213178479Sjb if (now - dtp->dt_lastswitch < interval) 3214178479Sjb return (0); 3215178479Sjb 3216178479Sjb dtp->dt_lastswitch += interval; 3217178479Sjb } else { 3218178479Sjb dtp->dt_lastswitch = now; 3219178479Sjb } 3220178479Sjb 3221178479Sjb if (!dtp->dt_active) 3222178479Sjb return (dt_set_errno(dtp, EINVAL)); 3223178479Sjb 3224178479Sjb if (max_ncpus == 0) 3225178479Sjb max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 3226178479Sjb 3227178479Sjb if (pf == NULL) 3228178479Sjb pf = (dtrace_consume_probe_f *)dt_nullprobe; 3229178479Sjb 3230178479Sjb if (rf == NULL) 3231178479Sjb rf = (dtrace_consume_rec_f *)dt_nullrec; 3232178479Sjb 3233250574Smarkj if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) { 3234250574Smarkj /* 3235250574Smarkj * The output will not be in the order it was traced. Rather, 3236250574Smarkj * we will consume all of the data from each CPU's buffer in 3237250574Smarkj * turn. We apply special handling for the records from BEGIN 3238250574Smarkj * and END probes so that they are consumed first and last, 3239250574Smarkj * respectively. 3240250574Smarkj * 3241250574Smarkj * If we have just begun, we want to first process the CPU that 3242250574Smarkj * executed the BEGIN probe (if any). 3243250574Smarkj */ 3244250574Smarkj if (dtp->dt_active && dtp->dt_beganon != -1 && 3245250574Smarkj (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0) 3246249573Spfg return (rval); 3247249573Spfg 3248250574Smarkj for (i = 0; i < max_ncpus; i++) { 3249250574Smarkj dtrace_bufdesc_t *buf; 3250249573Spfg 3251178479Sjb /* 3252250574Smarkj * If we have stopped, we want to process the CPU on 3253250574Smarkj * which the END probe was processed only _after_ we 3254250574Smarkj * have processed everything else. 3255178479Sjb */ 3256250574Smarkj if (dtp->dt_stopped && (i == dtp->dt_endedon)) 3257178479Sjb continue; 3258178479Sjb 3259250574Smarkj if (dt_get_buf(dtp, i, &buf) != 0) 3260250574Smarkj return (-1); 3261250574Smarkj if (buf == NULL) 3262250574Smarkj continue; 3263250574Smarkj 3264250574Smarkj dtp->dt_flow = 0; 3265250574Smarkj dtp->dt_indent = 0; 3266250574Smarkj dtp->dt_prefix = NULL; 3267250574Smarkj rval = dt_consume_cpu(dtp, fp, i, 3268250574Smarkj buf, B_FALSE, pf, rf, arg); 3269250574Smarkj dt_put_buf(dtp, buf); 3270250574Smarkj if (rval != 0) 3271250574Smarkj return (rval); 3272178479Sjb } 3273250574Smarkj if (dtp->dt_stopped) { 3274250574Smarkj dtrace_bufdesc_t *buf; 3275178479Sjb 3276250574Smarkj if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0) 3277250574Smarkj return (-1); 3278250574Smarkj if (buf == NULL) 3279250574Smarkj return (0); 3280250574Smarkj 3281250574Smarkj rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon, 3282250574Smarkj buf, B_FALSE, pf, rf, arg); 3283250574Smarkj dt_put_buf(dtp, buf); 3284178479Sjb return (rval); 3285250574Smarkj } 3286250574Smarkj } else { 3287250574Smarkj /* 3288250574Smarkj * The output will be in the order it was traced (or for 3289250574Smarkj * speculations, when it was committed). We retrieve a buffer 3290250574Smarkj * from each CPU and put it into a priority queue, which sorts 3291250574Smarkj * based on the first entry in the buffer. This is sufficient 3292250574Smarkj * because entries within a buffer are already sorted. 3293250574Smarkj * 3294250574Smarkj * We then consume records one at a time, always consuming the 3295250574Smarkj * oldest record, as determined by the priority queue. When 3296250574Smarkj * we reach the end of the time covered by these buffers, 3297250574Smarkj * we need to stop and retrieve more records on the next pass. 3298250574Smarkj * The kernel tells us the time covered by each buffer, in 3299250574Smarkj * dtbd_timestamp. The first buffer's timestamp tells us the 3300250574Smarkj * time covered by all buffers, as subsequently retrieved 3301250574Smarkj * buffers will cover to a more recent time. 3302250574Smarkj */ 3303178479Sjb 3304250574Smarkj uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t)); 3305250574Smarkj uint64_t first_timestamp = 0; 3306250574Smarkj uint_t cookie = 0; 3307250574Smarkj dtrace_bufdesc_t *buf; 3308178479Sjb 3309250574Smarkj bzero(drops, max_ncpus * sizeof (uint64_t)); 3310178479Sjb 3311250574Smarkj if (dtp->dt_bufq == NULL) { 3312250574Smarkj dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2, 3313250574Smarkj dt_buf_oldest, NULL); 3314250574Smarkj if (dtp->dt_bufq == NULL) /* ENOMEM */ 3315250574Smarkj return (-1); 3316250574Smarkj } 3317250574Smarkj 3318250574Smarkj /* Retrieve data from each CPU. */ 3319250574Smarkj (void) dtrace_getopt(dtp, "bufsize", &size); 3320250574Smarkj for (i = 0; i < max_ncpus; i++) { 3321250574Smarkj dtrace_bufdesc_t *buf; 3322250574Smarkj 3323250574Smarkj if (dt_get_buf(dtp, i, &buf) != 0) 3324250574Smarkj return (-1); 3325250574Smarkj if (buf != NULL) { 3326250574Smarkj if (first_timestamp == 0) 3327250574Smarkj first_timestamp = buf->dtbd_timestamp; 3328250574Smarkj assert(buf->dtbd_timestamp >= first_timestamp); 3329250574Smarkj 3330250574Smarkj dt_pq_insert(dtp->dt_bufq, buf); 3331250574Smarkj drops[i] = buf->dtbd_drops; 3332250574Smarkj buf->dtbd_drops = 0; 3333250574Smarkj } 3334250574Smarkj } 3335250574Smarkj 3336250574Smarkj /* Consume records. */ 3337250574Smarkj for (;;) { 3338250574Smarkj dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq); 3339250574Smarkj uint64_t timestamp; 3340250574Smarkj 3341250574Smarkj if (buf == NULL) 3342250574Smarkj break; 3343250574Smarkj 3344250574Smarkj timestamp = dt_buf_oldest(buf, dtp); 3345250574Smarkj assert(timestamp >= dtp->dt_last_timestamp); 3346250574Smarkj dtp->dt_last_timestamp = timestamp; 3347250574Smarkj 3348250574Smarkj if (timestamp == buf->dtbd_timestamp) { 3349250574Smarkj /* 3350250574Smarkj * We've reached the end of the time covered 3351250574Smarkj * by this buffer. If this is the oldest 3352250574Smarkj * buffer, we must do another pass 3353250574Smarkj * to retrieve more data. 3354250574Smarkj */ 3355250574Smarkj dt_put_buf(dtp, buf); 3356250574Smarkj if (timestamp == first_timestamp && 3357250574Smarkj !dtp->dt_stopped) 3358250574Smarkj break; 3359250574Smarkj continue; 3360250574Smarkj } 3361250574Smarkj 3362250574Smarkj if ((rval = dt_consume_cpu(dtp, fp, 3363250574Smarkj buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0) 3364250574Smarkj return (rval); 3365250574Smarkj dt_pq_insert(dtp->dt_bufq, buf); 3366250574Smarkj } 3367250574Smarkj 3368250574Smarkj /* Consume drops. */ 3369250574Smarkj for (i = 0; i < max_ncpus; i++) { 3370250574Smarkj if (drops[i] != 0) { 3371250574Smarkj int error = dt_handle_cpudrop(dtp, i, 3372250574Smarkj DTRACEDROP_PRINCIPAL, drops[i]); 3373250574Smarkj if (error != 0) 3374250574Smarkj return (error); 3375250574Smarkj } 3376250574Smarkj } 3377250574Smarkj 3378178479Sjb /* 3379250574Smarkj * Reduce memory usage by re-allocating smaller buffers 3380250574Smarkj * for the "remnants". 3381178479Sjb */ 3382250574Smarkj while (buf = dt_pq_walk(dtp->dt_bufq, &cookie)) 3383250574Smarkj dt_realloc_buf(dtp, buf, buf->dtbd_size); 3384178479Sjb } 3385178479Sjb 3386250574Smarkj return (0); 3387178479Sjb} 3388