1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/sysmacros.h> 28 #include <strings.h> 29 #include <stdlib.h> 30 #include <alloca.h> 31 #include <assert.h> 32 #include <ctype.h> 33 #include <errno.h> 34 #include <limits.h> 35 36 #include <dt_printf.h> 37 #include <dt_string.h> 38 #include <dt_impl.h> 39 40 /*ARGSUSED*/ 41 static int 42 pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 43 { 44 return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp)); 45 } 46 47 /*ARGSUSED*/ 48 static int 49 pfcheck_kaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 50 { 51 return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp) || 52 dt_node_is_symaddr(dnp)); 53 } 54 55 /*ARGSUSED*/ 56 static int 57 pfcheck_uaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 58 { 59 dtrace_hdl_t *dtp = pfv->pfv_dtp; 60 dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target"); 61 62 if (dt_node_is_usymaddr(dnp)) 63 return (1); 64 65 if (idp == NULL || idp->di_id == 0) 66 return (0); 67 68 return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp)); 69 } 70 71 /*ARGSUSED*/ 72 static int 73 pfcheck_stack(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 74 { 75 return (dt_node_is_stack(dnp)); 76 } 77 78 /*ARGSUSED*/ 79 static int 80 pfcheck_time(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 81 { 82 return (dt_node_is_integer(dnp) && 83 dt_node_type_size(dnp) == sizeof (uint64_t)); 84 } 85 86 /*ARGSUSED*/ 87 static int 88 pfcheck_str(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 89 { 90 ctf_file_t *ctfp; 91 ctf_encoding_t e; 92 ctf_arinfo_t r; 93 ctf_id_t base; 94 uint_t kind; 95 96 if (dt_node_is_string(dnp)) 97 return (1); 98 99 ctfp = dnp->dn_ctfp; 100 base = ctf_type_resolve(ctfp, dnp->dn_type); 101 kind = ctf_type_kind(ctfp, base); 102 103 return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 && 104 (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR && 105 ctf_type_encoding(ctfp, base, &e) == 0 && IS_CHAR(e)); 106 } 107 108 /*ARGSUSED*/ 109 static int 110 pfcheck_wstr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 111 { 112 ctf_file_t *ctfp = dnp->dn_ctfp; 113 ctf_id_t base = ctf_type_resolve(ctfp, dnp->dn_type); 114 uint_t kind = ctf_type_kind(ctfp, base); 115 116 ctf_encoding_t e; 117 ctf_arinfo_t r; 118 119 return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 && 120 (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR && 121 ctf_type_kind(ctfp, base) == CTF_K_INTEGER && 122 ctf_type_encoding(ctfp, base, &e) == 0 && e.cte_bits == 32); 123 } 124 125 /*ARGSUSED*/ 126 static int 127 pfcheck_csi(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 128 { 129 return (dt_node_is_integer(dnp) && 130 dt_node_type_size(dnp) <= sizeof (int)); 131 } 132 133 /*ARGSUSED*/ 134 static int 135 pfcheck_fp(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 136 { 137 return (dt_node_is_float(dnp)); 138 } 139 140 /*ARGSUSED*/ 141 static int 142 pfcheck_xint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 143 { 144 return (dt_node_is_integer(dnp)); 145 } 146 147 /*ARGSUSED*/ 148 static int 149 pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 150 { 151 if (dnp->dn_flags & DT_NF_SIGNED) 152 pfd->pfd_flags |= DT_PFCONV_SIGNED; 153 else 154 pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u'; 155 156 return (dt_node_is_integer(dnp)); 157 } 158 159 /*ARGSUSED*/ 160 static int 161 pfcheck_xshort(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 162 { 163 ctf_file_t *ctfp = dnp->dn_ctfp; 164 ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type); 165 char n[DT_TYPE_NAMELEN]; 166 167 return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && ( 168 strcmp(n, "short") == 0 || strcmp(n, "signed short") == 0 || 169 strcmp(n, "unsigned short") == 0)); 170 } 171 172 /*ARGSUSED*/ 173 static int 174 pfcheck_xlong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 175 { 176 ctf_file_t *ctfp = dnp->dn_ctfp; 177 ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type); 178 char n[DT_TYPE_NAMELEN]; 179 180 return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && ( 181 strcmp(n, "long") == 0 || strcmp(n, "signed long") == 0 || 182 strcmp(n, "unsigned long") == 0)); 183 } 184 185 /*ARGSUSED*/ 186 static int 187 pfcheck_xlonglong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 188 { 189 ctf_file_t *ctfp = dnp->dn_ctfp; 190 ctf_id_t type = dnp->dn_type; 191 char n[DT_TYPE_NAMELEN]; 192 193 if (ctf_type_name(ctfp, ctf_type_resolve(ctfp, type), n, 194 sizeof (n)) != NULL && (strcmp(n, "long long") == 0 || 195 strcmp(n, "signed long long") == 0 || 196 strcmp(n, "unsigned long long") == 0)) 197 return (1); 198 199 /* 200 * If the type used for %llx or %llX is not an [unsigned] long long, we 201 * also permit it to be a [u]int64_t or any typedef thereof. We know 202 * that these typedefs are guaranteed to work with %ll[xX] in either 203 * compilation environment even though they alias to "long" in LP64. 204 */ 205 while (ctf_type_kind(ctfp, type) == CTF_K_TYPEDEF) { 206 if (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && 207 (strcmp(n, "int64_t") == 0 || strcmp(n, "uint64_t") == 0)) 208 return (1); 209 210 type = ctf_type_reference(ctfp, type); 211 } 212 213 return (0); 214 } 215 216 /*ARGSUSED*/ 217 static int 218 pfcheck_type(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 219 { 220 return (ctf_type_compat(dnp->dn_ctfp, ctf_type_resolve(dnp->dn_ctfp, 221 dnp->dn_type), pfd->pfd_conv->pfc_dctfp, pfd->pfd_conv->pfc_dtype)); 222 } 223 224 /*ARGSUSED*/ 225 static int 226 pfprint_sint(dtrace_hdl_t *dtp, FILE *fp, const char *format, 227 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t unormal) 228 { 229 int64_t normal = (int64_t)unormal; 230 int32_t n = (int32_t)normal; 231 232 switch (size) { 233 case sizeof (int8_t): 234 return (dt_printf(dtp, fp, format, 235 (int32_t)*((int8_t *)addr) / n)); 236 case sizeof (int16_t): 237 return (dt_printf(dtp, fp, format, 238 (int32_t)*((int16_t *)addr) / n)); 239 case sizeof (int32_t): 240 return (dt_printf(dtp, fp, format, 241 *((int32_t *)addr) / n)); 242 case sizeof (int64_t): 243 return (dt_printf(dtp, fp, format, 244 *((int64_t *)addr) / normal)); 245 default: 246 return (dt_set_errno(dtp, EDT_DMISMATCH)); 247 } 248 } 249 250 /*ARGSUSED*/ 251 static int 252 pfprint_uint(dtrace_hdl_t *dtp, FILE *fp, const char *format, 253 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 254 { 255 uint32_t n = (uint32_t)normal; 256 257 switch (size) { 258 case sizeof (uint8_t): 259 return (dt_printf(dtp, fp, format, 260 (uint32_t)*((uint8_t *)addr) / n)); 261 case sizeof (uint16_t): 262 return (dt_printf(dtp, fp, format, 263 (uint32_t)*((uint16_t *)addr) / n)); 264 case sizeof (uint32_t): 265 return (dt_printf(dtp, fp, format, 266 *((uint32_t *)addr) / n)); 267 case sizeof (uint64_t): 268 return (dt_printf(dtp, fp, format, 269 *((uint64_t *)addr) / normal)); 270 default: 271 return (dt_set_errno(dtp, EDT_DMISMATCH)); 272 } 273 } 274 275 static int 276 pfprint_dint(dtrace_hdl_t *dtp, FILE *fp, const char *format, 277 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 278 { 279 if (pfd->pfd_flags & DT_PFCONV_SIGNED) 280 return (pfprint_sint(dtp, fp, format, pfd, addr, size, normal)); 281 else 282 return (pfprint_uint(dtp, fp, format, pfd, addr, size, normal)); 283 } 284 285 /*ARGSUSED*/ 286 static int 287 pfprint_fp(dtrace_hdl_t *dtp, FILE *fp, const char *format, 288 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 289 { 290 double n = (double)normal; 291 long double ldn = (long double)normal; 292 293 switch (size) { 294 case sizeof (float): 295 return (dt_printf(dtp, fp, format, 296 (double)*((float *)addr) / n)); 297 case sizeof (double): 298 return (dt_printf(dtp, fp, format, 299 *((double *)addr) / n)); 300 case sizeof (long double): 301 return (dt_printf(dtp, fp, format, 302 *((long double *)addr) / ldn)); 303 default: 304 return (dt_set_errno(dtp, EDT_DMISMATCH)); 305 } 306 } 307 308 /*ARGSUSED*/ 309 static int 310 pfprint_addr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 311 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 312 { 313 char *s; 314 int n, len = 256; 315 uint64_t val; 316 317 switch (size) { 318 case sizeof (uint32_t): 319 val = *((uint32_t *)addr); 320 break; 321 case sizeof (uint64_t): 322 val = *((uint64_t *)addr); 323 break; 324 default: 325 return (dt_set_errno(dtp, EDT_DMISMATCH)); 326 } 327 328 do { 329 n = len; 330 s = alloca(n); 331 } while ((len = dtrace_addr2str(dtp, val, s, n)) >= n); 332 333 return (dt_printf(dtp, fp, format, s)); 334 } 335 336 /*ARGSUSED*/ 337 static int 338 pfprint_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, 339 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 340 { 341 return (dt_print_mod(dtp, fp, format, (caddr_t)addr)); 342 } 343 344 /*ARGSUSED*/ 345 static int 346 pfprint_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, 347 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 348 { 349 return (dt_print_umod(dtp, fp, format, (caddr_t)addr)); 350 } 351 352 /*ARGSUSED*/ 353 static int 354 pfprint_uaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 355 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 356 { 357 char *s; 358 int n, len = 256; 359 uint64_t val, pid = 0; 360 361 dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target"); 362 363 switch (size) { 364 case sizeof (uint32_t): 365 val = (u_longlong_t)*((uint32_t *)addr); 366 break; 367 case sizeof (uint64_t): 368 val = (u_longlong_t)*((uint64_t *)addr); 369 break; 370 case sizeof (uint64_t) * 2: 371 pid = ((uint64_t *)(uintptr_t)addr)[0]; 372 val = ((uint64_t *)(uintptr_t)addr)[1]; 373 break; 374 default: 375 return (dt_set_errno(dtp, EDT_DMISMATCH)); 376 } 377 378 if (pid == 0 && dtp->dt_vector == NULL && idp != NULL) 379 pid = idp->di_id; 380 381 do { 382 n = len; 383 s = alloca(n); 384 } while ((len = dtrace_uaddr2str(dtp, pid, val, s, n)) >= n); 385 386 return (dt_printf(dtp, fp, format, s)); 387 } 388 389 /*ARGSUSED*/ 390 static int 391 pfprint_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 392 const dt_pfargd_t *pfd, const void *vaddr, size_t size, uint64_t normal) 393 { 394 int width; 395 dtrace_optval_t saved = dtp->dt_options[DTRACEOPT_STACKINDENT]; 396 const dtrace_recdesc_t *rec = pfd->pfd_rec; 397 caddr_t addr = (caddr_t)vaddr; 398 int err = 0; 399 400 /* 401 * We have stashed the value of the STACKINDENT option, and we will 402 * now override it for the purposes of formatting the stack. If the 403 * field has been specified as left-aligned (i.e. (%-#), we set the 404 * indentation to be the width. This is a slightly odd semantic, but 405 * it's useful functionality -- and it's slightly odd to begin with to 406 * be using a single format specifier to be formatting multiple lines 407 * of text... 408 */ 409 if (pfd->pfd_dynwidth < 0) { 410 assert(pfd->pfd_flags & DT_PFCONV_DYNWIDTH); 411 width = -pfd->pfd_dynwidth; 412 } else if (pfd->pfd_flags & DT_PFCONV_LEFT) { 413 width = pfd->pfd_dynwidth ? pfd->pfd_dynwidth : pfd->pfd_width; 414 } else { 415 width = 0; 416 } 417 418 dtp->dt_options[DTRACEOPT_STACKINDENT] = width; 419 420 switch (rec->dtrd_action) { 421 case DTRACEACT_USTACK: 422 case DTRACEACT_JSTACK: 423 err = dt_print_ustack(dtp, fp, format, addr, rec->dtrd_arg); 424 break; 425 426 case DTRACEACT_STACK: 427 err = dt_print_stack(dtp, fp, format, addr, rec->dtrd_arg, 428 rec->dtrd_size / rec->dtrd_arg); 429 break; 430 431 default: 432 assert(0); 433 } 434 435 dtp->dt_options[DTRACEOPT_STACKINDENT] = saved; 436 437 return (err); 438 } 439 440 /*ARGSUSED*/ 441 static int 442 pfprint_time(dtrace_hdl_t *dtp, FILE *fp, const char *format, 443 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 444 { 445 char src[32], buf[32], *dst = buf; 446 hrtime_t time = *((uint64_t *)addr); 447 time_t sec = (time_t)(time / NANOSEC); 448 int i; 449 450 /* 451 * ctime(3C) returns a string of the form "Dec 3 17:20:00 1973\n\0". 452 * Below, we turn this into the canonical adb/mdb /[yY] format, 453 * "1973 Dec 3 17:20:00". 454 */ 455 (void) ctime_r(&sec, src, sizeof (src)); 456 457 /* 458 * Place the 4-digit year at the head of the string... 459 */ 460 for (i = 20; i < 24; i++) 461 *dst++ = src[i]; 462 463 /* 464 * ...and follow it with the remainder (month, day, hh:mm:ss). 465 */ 466 for (i = 3; i < 19; i++) 467 *dst++ = src[i]; 468 469 *dst = '\0'; 470 return (dt_printf(dtp, fp, format, buf)); 471 } 472 473 /* 474 * This prints the time in RFC 822 standard form. This is useful for emitting 475 * notions of time that are consumed by standard tools (e.g., as part of an 476 * RSS feed). 477 */ 478 /*ARGSUSED*/ 479 static int 480 pfprint_time822(dtrace_hdl_t *dtp, FILE *fp, const char *format, 481 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 482 { 483 hrtime_t time = *((uint64_t *)addr); 484 time_t sec = (time_t)(time / NANOSEC); 485 struct tm tm; 486 char buf[64]; 487 488 (void) localtime_r(&sec, &tm); 489 (void) strftime(buf, sizeof (buf), "%a, %d %b %G %T %Z", &tm); 490 return (dt_printf(dtp, fp, format, buf)); 491 } 492 493 /*ARGSUSED*/ 494 static int 495 pfprint_cstr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 496 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 497 { 498 char *s = alloca(size + 1); 499 500 bcopy(addr, s, size); 501 s[size] = '\0'; 502 return (dt_printf(dtp, fp, format, s)); 503 } 504 505 /*ARGSUSED*/ 506 static int 507 pfprint_wstr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 508 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 509 { 510 wchar_t *ws = alloca(size + sizeof (wchar_t)); 511 512 bcopy(addr, ws, size); 513 ws[size / sizeof (wchar_t)] = L'\0'; 514 return (dt_printf(dtp, fp, format, ws)); 515 } 516 517 /*ARGSUSED*/ 518 static int 519 pfprint_estr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 520 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 521 { 522 char *s; 523 int n; 524 525 if ((s = strchr2esc(addr, size)) == NULL) 526 return (dt_set_errno(dtp, EDT_NOMEM)); 527 528 n = dt_printf(dtp, fp, format, s); 529 free(s); 530 return (n); 531 } 532 533 static int 534 pfprint_echr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 535 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 536 { 537 char c; 538 539 switch (size) { 540 case sizeof (int8_t): 541 c = *(int8_t *)addr; 542 break; 543 case sizeof (int16_t): 544 c = *(int16_t *)addr; 545 break; 546 case sizeof (int32_t): 547 c = *(int32_t *)addr; 548 break; 549 default: 550 return (dt_set_errno(dtp, EDT_DMISMATCH)); 551 } 552 553 return (pfprint_estr(dtp, fp, format, pfd, &c, 1, normal)); 554 } 555 556 /*ARGSUSED*/ 557 static int 558 pfprint_pct(dtrace_hdl_t *dtp, FILE *fp, const char *format, 559 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 560 { 561 return (dt_printf(dtp, fp, "%%")); 562 } 563 564 static const char pfproto_xint[] = "char, short, int, long, or long long"; 565 static const char pfproto_csi[] = "char, short, or int"; 566 static const char pfproto_fp[] = "float, double, or long double"; 567 static const char pfproto_addr[] = "pointer or integer"; 568 static const char pfproto_uaddr[] = 569 "pointer or integer (with -p/-c) or _usymaddr (without -p/-c)"; 570 static const char pfproto_cstr[] = "char [] or string (or use stringof)"; 571 static const char pfproto_wstr[] = "wchar_t []"; 572 573 /* 574 * Printf format conversion dictionary. This table should match the set of 575 * conversions offered by printf(3C), as well as some additional extensions. 576 * The second parameter is an ASCII string which is either an actual type 577 * name we should look up (if pfcheck_type is specified), or just a descriptive 578 * string of the types expected for use in error messages. 579 */ 580 static const dt_pfconv_t _dtrace_conversions[] = { 581 { "a", "s", pfproto_addr, pfcheck_kaddr, pfprint_addr }, 582 { "A", "s", pfproto_uaddr, pfcheck_uaddr, pfprint_uaddr }, 583 { "c", "c", pfproto_csi, pfcheck_csi, pfprint_sint }, 584 { "C", "s", pfproto_csi, pfcheck_csi, pfprint_echr }, 585 { "d", "d", pfproto_xint, pfcheck_dint, pfprint_dint }, 586 { "e", "e", pfproto_fp, pfcheck_fp, pfprint_fp }, 587 { "E", "E", pfproto_fp, pfcheck_fp, pfprint_fp }, 588 { "f", "f", pfproto_fp, pfcheck_fp, pfprint_fp }, 589 { "g", "g", pfproto_fp, pfcheck_fp, pfprint_fp }, 590 { "G", "G", pfproto_fp, pfcheck_fp, pfprint_fp }, 591 { "hd", "d", "short", pfcheck_type, pfprint_sint }, 592 { "hi", "i", "short", pfcheck_type, pfprint_sint }, 593 { "ho", "o", "unsigned short", pfcheck_type, pfprint_uint }, 594 { "hu", "u", "unsigned short", pfcheck_type, pfprint_uint }, 595 { "hx", "x", "short", pfcheck_xshort, pfprint_uint }, 596 { "hX", "X", "short", pfcheck_xshort, pfprint_uint }, 597 { "i", "i", pfproto_xint, pfcheck_dint, pfprint_dint }, 598 { "k", "s", "stack", pfcheck_stack, pfprint_stack }, 599 { "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */ 600 { "ld", "d", "long", pfcheck_type, pfprint_sint }, 601 { "li", "i", "long", pfcheck_type, pfprint_sint }, 602 { "lo", "o", "unsigned long", pfcheck_type, pfprint_uint }, 603 { "lu", "u", "unsigned long", pfcheck_type, pfprint_uint }, 604 { "ls", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr }, 605 { "lx", "x", "long", pfcheck_xlong, pfprint_uint }, 606 { "lX", "X", "long", pfcheck_xlong, pfprint_uint }, 607 { "lld", "d", "long long", pfcheck_type, pfprint_sint }, 608 { "lli", "i", "long long", pfcheck_type, pfprint_sint }, 609 { "llo", "o", "unsigned long long", pfcheck_type, pfprint_uint }, 610 { "llu", "u", "unsigned long long", pfcheck_type, pfprint_uint }, 611 { "llx", "x", "long long", pfcheck_xlonglong, pfprint_uint }, 612 { "llX", "X", "long long", pfcheck_xlonglong, pfprint_uint }, 613 { "Le", "e", "long double", pfcheck_type, pfprint_fp }, 614 { "LE", "E", "long double", pfcheck_type, pfprint_fp }, 615 { "Lf", "f", "long double", pfcheck_type, pfprint_fp }, 616 { "Lg", "g", "long double", pfcheck_type, pfprint_fp }, 617 { "LG", "G", "long double", pfcheck_type, pfprint_fp }, 618 { "o", "o", pfproto_xint, pfcheck_xint, pfprint_uint }, 619 { "p", "x", pfproto_addr, pfcheck_addr, pfprint_uint }, 620 { "s", "s", "char [] or string (or use stringof)", pfcheck_str, pfprint_cstr }, 621 { "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr }, 622 { "T", "s", "int64_t", pfcheck_time, pfprint_time822 }, 623 { "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint }, 624 { "wc", "wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */ 625 { "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr }, 626 { "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint }, 627 { "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint }, 628 { "Y", "s", "int64_t", pfcheck_time, pfprint_time }, 629 { "%", "%", "void", pfcheck_type, pfprint_pct }, 630 { NULL, NULL, NULL, NULL, NULL } 631 }; 632 633 int 634 dt_pfdict_create(dtrace_hdl_t *dtp) 635 { 636 uint_t n = _dtrace_strbuckets; 637 const dt_pfconv_t *pfd; 638 dt_pfdict_t *pdi; 639 640 if ((pdi = malloc(sizeof (dt_pfdict_t))) == NULL || 641 (pdi->pdi_buckets = malloc(sizeof (dt_pfconv_t *) * n)) == NULL) { 642 free(pdi); 643 return (dt_set_errno(dtp, EDT_NOMEM)); 644 } 645 646 dtp->dt_pfdict = pdi; 647 bzero(pdi->pdi_buckets, sizeof (dt_pfconv_t *) * n); 648 pdi->pdi_nbuckets = n; 649 650 for (pfd = _dtrace_conversions; pfd->pfc_name != NULL; pfd++) { 651 dtrace_typeinfo_t dtt; 652 dt_pfconv_t *pfc; 653 uint_t h; 654 655 if ((pfc = malloc(sizeof (dt_pfconv_t))) == NULL) { 656 dt_pfdict_destroy(dtp); 657 return (dt_set_errno(dtp, EDT_NOMEM)); 658 } 659 660 bcopy(pfd, pfc, sizeof (dt_pfconv_t)); 661 h = dt_strtab_hash(pfc->pfc_name, NULL) % n; 662 pfc->pfc_next = pdi->pdi_buckets[h]; 663 pdi->pdi_buckets[h] = pfc; 664 665 dtt.dtt_ctfp = NULL; 666 dtt.dtt_type = CTF_ERR; 667 668 /* 669 * The "D" container or its parent must contain a definition of 670 * any type referenced by a printf conversion. If none can be 671 * found, we fail to initialize the printf dictionary. 672 */ 673 if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type( 674 dtp, DTRACE_OBJ_DDEFS, pfc->pfc_tstr, &dtt) != 0) { 675 dt_pfdict_destroy(dtp); 676 return (dt_set_errno(dtp, EDT_NOCONV)); 677 } 678 679 pfc->pfc_dctfp = dtt.dtt_ctfp; 680 pfc->pfc_dtype = dtt.dtt_type; 681 682 /* 683 * The "C" container may contain an alternate definition of an 684 * explicit conversion type. If it does, use it; otherwise 685 * just set pfc_ctype to pfc_dtype so it is always valid. 686 */ 687 if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type( 688 dtp, DTRACE_OBJ_CDEFS, pfc->pfc_tstr, &dtt) == 0) { 689 pfc->pfc_cctfp = dtt.dtt_ctfp; 690 pfc->pfc_ctype = dtt.dtt_type; 691 } else { 692 pfc->pfc_cctfp = pfc->pfc_dctfp; 693 pfc->pfc_ctype = pfc->pfc_dtype; 694 } 695 696 if (pfc->pfc_check == NULL || pfc->pfc_print == NULL || 697 pfc->pfc_ofmt == NULL || pfc->pfc_tstr == NULL) { 698 dt_pfdict_destroy(dtp); 699 return (dt_set_errno(dtp, EDT_BADCONV)); 700 } 701 702 dt_dprintf("loaded printf conversion %%%s\n", pfc->pfc_name); 703 } 704 705 return (0); 706 } 707 708 void 709 dt_pfdict_destroy(dtrace_hdl_t *dtp) 710 { 711 dt_pfdict_t *pdi = dtp->dt_pfdict; 712 dt_pfconv_t *pfc, *nfc; 713 uint_t i; 714 715 if (pdi == NULL) 716 return; 717 718 for (i = 0; i < pdi->pdi_nbuckets; i++) { 719 for (pfc = pdi->pdi_buckets[i]; pfc != NULL; pfc = nfc) { 720 nfc = pfc->pfc_next; 721 free(pfc); 722 } 723 } 724 725 free(pdi->pdi_buckets); 726 free(pdi); 727 dtp->dt_pfdict = NULL; 728 } 729 730 static const dt_pfconv_t * 731 dt_pfdict_lookup(dtrace_hdl_t *dtp, const char *name) 732 { 733 dt_pfdict_t *pdi = dtp->dt_pfdict; 734 uint_t h = dt_strtab_hash(name, NULL) % pdi->pdi_nbuckets; 735 const dt_pfconv_t *pfc; 736 737 for (pfc = pdi->pdi_buckets[h]; pfc != NULL; pfc = pfc->pfc_next) { 738 if (strcmp(pfc->pfc_name, name) == 0) 739 break; 740 } 741 742 return (pfc); 743 } 744 745 static dt_pfargv_t * 746 dt_printf_error(dtrace_hdl_t *dtp, int err) 747 { 748 if (yypcb != NULL) 749 longjmp(yypcb->pcb_jmpbuf, err); 750 751 (void) dt_set_errno(dtp, err); 752 return (NULL); 753 } 754 755 dt_pfargv_t * 756 dt_printf_create(dtrace_hdl_t *dtp, const char *s) 757 { 758 dt_pfargd_t *pfd, *nfd = NULL; 759 dt_pfargv_t *pfv; 760 const char *p, *q; 761 char *format; 762 763 if ((pfv = malloc(sizeof (dt_pfargv_t))) == NULL || 764 (format = strdup(s)) == NULL) { 765 free(pfv); 766 return (dt_printf_error(dtp, EDT_NOMEM)); 767 } 768 769 pfv->pfv_format = format; 770 pfv->pfv_argv = NULL; 771 pfv->pfv_argc = 0; 772 pfv->pfv_flags = 0; 773 pfv->pfv_dtp = dtp; 774 775 for (q = format; (p = strchr(q, '%')) != NULL; q = *p ? p + 1 : p) { 776 uint_t namelen = 0; 777 int digits = 0; 778 int dot = 0; 779 780 char name[8]; 781 char c; 782 int n; 783 784 if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) { 785 dt_printf_destroy(pfv); 786 return (dt_printf_error(dtp, EDT_NOMEM)); 787 } 788 789 if (pfv->pfv_argv != NULL) 790 nfd->pfd_next = pfd; 791 else 792 pfv->pfv_argv = pfd; 793 794 bzero(pfd, sizeof (dt_pfargd_t)); 795 pfv->pfv_argc++; 796 nfd = pfd; 797 798 if (p > q) { 799 pfd->pfd_preflen = (size_t)(p - q); 800 pfd->pfd_prefix = q; 801 } 802 803 fmt_switch: 804 switch (c = *++p) { 805 case '0': case '1': case '2': case '3': case '4': 806 case '5': case '6': case '7': case '8': case '9': 807 if (dot == 0 && digits == 0 && c == '0') { 808 pfd->pfd_flags |= DT_PFCONV_ZPAD; 809 pfd->pfd_flags &= ~DT_PFCONV_LEFT; 810 goto fmt_switch; 811 } 812 813 for (n = 0; isdigit(c); c = *++p) 814 n = n * 10 + c - '0'; 815 816 if (dot) 817 pfd->pfd_prec = n; 818 else 819 pfd->pfd_width = n; 820 821 p--; 822 digits++; 823 goto fmt_switch; 824 825 case '#': 826 pfd->pfd_flags |= DT_PFCONV_ALT; 827 goto fmt_switch; 828 829 case '*': 830 n = dot ? DT_PFCONV_DYNPREC : DT_PFCONV_DYNWIDTH; 831 832 if (pfd->pfd_flags & n) { 833 yywarn("format conversion #%u has more than " 834 "one '*' specified for the output %s\n", 835 pfv->pfv_argc, n ? "precision" : "width"); 836 837 dt_printf_destroy(pfv); 838 return (dt_printf_error(dtp, EDT_COMPILER)); 839 } 840 841 pfd->pfd_flags |= n; 842 goto fmt_switch; 843 844 case '+': 845 pfd->pfd_flags |= DT_PFCONV_SPOS; 846 goto fmt_switch; 847 848 case '-': 849 pfd->pfd_flags |= DT_PFCONV_LEFT; 850 pfd->pfd_flags &= ~DT_PFCONV_ZPAD; 851 goto fmt_switch; 852 853 case '.': 854 if (dot++ != 0) { 855 yywarn("format conversion #%u has more than " 856 "one '.' specified\n", pfv->pfv_argc); 857 858 dt_printf_destroy(pfv); 859 return (dt_printf_error(dtp, EDT_COMPILER)); 860 } 861 digits = 0; 862 goto fmt_switch; 863 864 case '?': 865 if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) 866 pfd->pfd_width = 16; 867 else 868 pfd->pfd_width = 8; 869 goto fmt_switch; 870 871 case '@': 872 pfd->pfd_flags |= DT_PFCONV_AGG; 873 goto fmt_switch; 874 875 case '\'': 876 pfd->pfd_flags |= DT_PFCONV_GROUP; 877 goto fmt_switch; 878 879 case ' ': 880 pfd->pfd_flags |= DT_PFCONV_SPACE; 881 goto fmt_switch; 882 883 case '$': 884 yywarn("format conversion #%u uses unsupported " 885 "positional format (%%n$)\n", pfv->pfv_argc); 886 887 dt_printf_destroy(pfv); 888 return (dt_printf_error(dtp, EDT_COMPILER)); 889 890 case '%': 891 if (p[-1] == '%') 892 goto default_lbl; /* if %% then use "%" conv */ 893 894 yywarn("format conversion #%u cannot be combined " 895 "with other format flags: %%%%\n", pfv->pfv_argc); 896 897 dt_printf_destroy(pfv); 898 return (dt_printf_error(dtp, EDT_COMPILER)); 899 900 case '\0': 901 yywarn("format conversion #%u name expected before " 902 "end of format string\n", pfv->pfv_argc); 903 904 dt_printf_destroy(pfv); 905 return (dt_printf_error(dtp, EDT_COMPILER)); 906 907 case 'h': 908 case 'l': 909 case 'L': 910 case 'w': 911 if (namelen < sizeof (name) - 2) 912 name[namelen++] = c; 913 goto fmt_switch; 914 915 default_lbl: 916 default: 917 name[namelen++] = c; 918 name[namelen] = '\0'; 919 } 920 921 pfd->pfd_conv = dt_pfdict_lookup(dtp, name); 922 923 if (pfd->pfd_conv == NULL) { 924 yywarn("format conversion #%u is undefined: %%%s\n", 925 pfv->pfv_argc, name); 926 dt_printf_destroy(pfv); 927 return (dt_printf_error(dtp, EDT_COMPILER)); 928 } 929 } 930 931 if (*q != '\0' || *format == '\0') { 932 if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) { 933 dt_printf_destroy(pfv); 934 return (dt_printf_error(dtp, EDT_NOMEM)); 935 } 936 937 if (pfv->pfv_argv != NULL) 938 nfd->pfd_next = pfd; 939 else 940 pfv->pfv_argv = pfd; 941 942 bzero(pfd, sizeof (dt_pfargd_t)); 943 pfv->pfv_argc++; 944 945 pfd->pfd_prefix = q; 946 pfd->pfd_preflen = strlen(q); 947 } 948 949 return (pfv); 950 } 951 952 void 953 dt_printf_destroy(dt_pfargv_t *pfv) 954 { 955 dt_pfargd_t *pfd, *nfd; 956 957 for (pfd = pfv->pfv_argv; pfd != NULL; pfd = nfd) { 958 nfd = pfd->pfd_next; 959 free(pfd); 960 } 961 962 free(pfv->pfv_format); 963 free(pfv); 964 } 965 966 void 967 dt_printf_validate(dt_pfargv_t *pfv, uint_t flags, 968 dt_ident_t *idp, int foff, dtrace_actkind_t kind, dt_node_t *dnp) 969 { 970 dt_pfargd_t *pfd = pfv->pfv_argv; 971 const char *func = idp->di_name; 972 973 char n[DT_TYPE_NAMELEN]; 974 dtrace_typeinfo_t dtt; 975 const char *aggtype; 976 dt_node_t aggnode; 977 int i, j; 978 979 if (pfv->pfv_format[0] == '\0') { 980 xyerror(D_PRINTF_FMT_EMPTY, 981 "%s( ) format string is empty\n", func); 982 } 983 984 pfv->pfv_flags = flags; 985 986 /* 987 * We fake up a parse node representing the type that can be used with 988 * an aggregation result conversion, which -- for all but count() -- 989 * is a signed quantity. 990 */ 991 if (kind != DTRACEAGG_COUNT) 992 aggtype = "int64_t"; 993 else 994 aggtype = "uint64_t"; 995 996 if (dt_type_lookup(aggtype, &dtt) != 0) 997 xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype); 998 999 bzero(&aggnode, sizeof (aggnode)); 1000 dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type); 1001 1002 for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 1003 const dt_pfconv_t *pfc = pfd->pfd_conv; 1004 const char *dyns[2]; 1005 int dync = 0; 1006 1007 char vname[64]; 1008 dt_node_t *vnp; 1009 1010 if (pfc == NULL) 1011 continue; /* no checking if argd is just a prefix */ 1012 1013 if (pfc->pfc_print == &pfprint_pct) { 1014 (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt); 1015 continue; 1016 } 1017 1018 if (pfd->pfd_flags & DT_PFCONV_DYNPREC) 1019 dyns[dync++] = ".*"; 1020 if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) 1021 dyns[dync++] = "*"; 1022 1023 for (; dync != 0; dync--) { 1024 if (dnp == NULL) { 1025 xyerror(D_PRINTF_DYN_PROTO, 1026 "%s( ) prototype mismatch: conversion " 1027 "#%d (%%%s) is missing a corresponding " 1028 "\"%s\" argument\n", func, i + 1, 1029 pfc->pfc_name, dyns[dync - 1]); 1030 } 1031 1032 if (dt_node_is_integer(dnp) == 0) { 1033 xyerror(D_PRINTF_DYN_TYPE, 1034 "%s( ) argument #%d is incompatible " 1035 "with conversion #%d prototype:\n" 1036 "\tconversion: %% %s %s\n" 1037 "\t prototype: int\n\t argument: %s\n", 1038 func, j + foff + 1, i + 1, 1039 dyns[dync - 1], pfc->pfc_name, 1040 dt_node_type_name(dnp, n, sizeof (n))); 1041 } 1042 1043 dnp = dnp->dn_list; 1044 j++; 1045 } 1046 1047 /* 1048 * If this conversion is consuming the aggregation data, set 1049 * the value node pointer (vnp) to a fake node based on the 1050 * aggregating function result type. Otherwise assign vnp to 1051 * the next parse node in the argument list, if there is one. 1052 */ 1053 if (pfd->pfd_flags & DT_PFCONV_AGG) { 1054 if (!(flags & DT_PRINTF_AGGREGATION)) { 1055 xyerror(D_PRINTF_AGG_CONV, 1056 "%%@ conversion requires an aggregation" 1057 " and is not for use with %s( )\n", func); 1058 } 1059 (void) strlcpy(vname, "aggregating action", 1060 sizeof (vname)); 1061 vnp = &aggnode; 1062 } else if (dnp == NULL) { 1063 xyerror(D_PRINTF_ARG_PROTO, 1064 "%s( ) prototype mismatch: conversion #%d (%%" 1065 "%s) is missing a corresponding value argument\n", 1066 func, i + 1, pfc->pfc_name); 1067 } else { 1068 (void) snprintf(vname, sizeof (vname), 1069 "argument #%d", j + foff + 1); 1070 vnp = dnp; 1071 dnp = dnp->dn_list; 1072 j++; 1073 } 1074 1075 /* 1076 * Fill in the proposed final format string by prepending any 1077 * size-related prefixes to the pfconv's format string. The 1078 * pfc_check() function below may optionally modify the format 1079 * as part of validating the type of the input argument. 1080 */ 1081 if (pfc->pfc_print == &pfprint_sint || 1082 pfc->pfc_print == &pfprint_uint || 1083 pfc->pfc_print == &pfprint_dint) { 1084 if (dt_node_type_size(vnp) == sizeof (uint64_t)) 1085 (void) strcpy(pfd->pfd_fmt, "ll"); 1086 } else if (pfc->pfc_print == &pfprint_fp) { 1087 if (dt_node_type_size(vnp) == sizeof (long double)) 1088 (void) strcpy(pfd->pfd_fmt, "L"); 1089 } 1090 1091 (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt); 1092 1093 /* 1094 * Validate the format conversion against the value node type. 1095 * If the conversion is good, create the descriptor format 1096 * string by concatenating together any required printf(3C) 1097 * size prefixes with the conversion's native format string. 1098 */ 1099 if (pfc->pfc_check(pfv, pfd, vnp) == 0) { 1100 xyerror(D_PRINTF_ARG_TYPE, 1101 "%s( ) %s is incompatible with " 1102 "conversion #%d prototype:\n\tconversion: %%%s\n" 1103 "\t prototype: %s\n\t argument: %s\n", func, 1104 vname, i + 1, pfc->pfc_name, pfc->pfc_tstr, 1105 dt_node_type_name(vnp, n, sizeof (n))); 1106 } 1107 } 1108 1109 if ((flags & DT_PRINTF_EXACTLEN) && dnp != NULL) { 1110 xyerror(D_PRINTF_ARG_EXTRA, 1111 "%s( ) prototype mismatch: only %d arguments " 1112 "required by this format string\n", func, j); 1113 } 1114 } 1115 1116 void 1117 dt_printa_validate(dt_node_t *lhs, dt_node_t *rhs) 1118 { 1119 dt_ident_t *lid, *rid; 1120 dt_node_t *lproto, *rproto; 1121 int largc, rargc, argn; 1122 char n1[DT_TYPE_NAMELEN]; 1123 char n2[DT_TYPE_NAMELEN]; 1124 1125 assert(lhs->dn_kind == DT_NODE_AGG); 1126 assert(rhs->dn_kind == DT_NODE_AGG); 1127 1128 lid = lhs->dn_ident; 1129 rid = rhs->dn_ident; 1130 1131 lproto = ((dt_idsig_t *)lid->di_data)->dis_args; 1132 rproto = ((dt_idsig_t *)rid->di_data)->dis_args; 1133 1134 /* 1135 * First, get an argument count on each side. These must match. 1136 */ 1137 for (largc = 0; lproto != NULL; lproto = lproto->dn_list) 1138 largc++; 1139 1140 for (rargc = 0; rproto != NULL; rproto = rproto->dn_list) 1141 rargc++; 1142 1143 if (largc != rargc) { 1144 xyerror(D_PRINTA_AGGKEY, "printa( ): @%s and @%s do not have " 1145 "matching key signatures: @%s has %d key%s, @%s has %d " 1146 "key%s", lid->di_name, rid->di_name, 1147 lid->di_name, largc, largc == 1 ? "" : "s", 1148 rid->di_name, rargc, rargc == 1 ? "" : "s"); 1149 } 1150 1151 /* 1152 * Now iterate over the keys to verify that each type matches. 1153 */ 1154 lproto = ((dt_idsig_t *)lid->di_data)->dis_args; 1155 rproto = ((dt_idsig_t *)rid->di_data)->dis_args; 1156 1157 for (argn = 1; lproto != NULL; argn++, lproto = lproto->dn_list, 1158 rproto = rproto->dn_list) { 1159 assert(rproto != NULL); 1160 1161 if (dt_node_is_argcompat(lproto, rproto)) 1162 continue; 1163 1164 xyerror(D_PRINTA_AGGPROTO, "printa( ): @%s[ ] key #%d is " 1165 "incompatible with @%s:\n%9s key #%d: %s\n" 1166 "%9s key #%d: %s\n", 1167 rid->di_name, argn, lid->di_name, lid->di_name, argn, 1168 dt_node_type_name(lproto, n1, sizeof (n1)), rid->di_name, 1169 argn, dt_node_type_name(rproto, n2, sizeof (n2))); 1170 } 1171 } 1172 1173 static int 1174 dt_printf_getint(dtrace_hdl_t *dtp, const dtrace_recdesc_t *recp, 1175 uint_t nrecs, const void *buf, size_t len, int *ip) 1176 { 1177 uintptr_t addr; 1178 1179 if (nrecs == 0) 1180 return (dt_set_errno(dtp, EDT_DMISMATCH)); 1181 1182 addr = (uintptr_t)buf + recp->dtrd_offset; 1183 1184 if (addr + sizeof (int) > (uintptr_t)buf + len) 1185 return (dt_set_errno(dtp, EDT_DOFFSET)); 1186 1187 if (addr & (recp->dtrd_alignment - 1)) 1188 return (dt_set_errno(dtp, EDT_DALIGN)); 1189 1190 switch (recp->dtrd_size) { 1191 case sizeof (int8_t): 1192 *ip = (int)*((int8_t *)addr); 1193 break; 1194 case sizeof (int16_t): 1195 *ip = (int)*((int16_t *)addr); 1196 break; 1197 case sizeof (int32_t): 1198 *ip = (int)*((int32_t *)addr); 1199 break; 1200 case sizeof (int64_t): 1201 *ip = (int)*((int64_t *)addr); 1202 break; 1203 default: 1204 return (dt_set_errno(dtp, EDT_DMISMATCH)); 1205 } 1206 1207 return (0); 1208 } 1209 1210 /*ARGSUSED*/ 1211 static int 1212 pfprint_average(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1213 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 1214 { 1215 const uint64_t *data = addr; 1216 1217 if (size != sizeof (uint64_t) * 2) 1218 return (dt_set_errno(dtp, EDT_DMISMATCH)); 1219 1220 return (dt_printf(dtp, fp, format, 1221 data[0] ? data[1] / normal / data[0] : 0)); 1222 } 1223 1224 /*ARGSUSED*/ 1225 static int 1226 pfprint_stddev(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1227 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 1228 { 1229 const uint64_t *data = addr; 1230 1231 if (size != sizeof (uint64_t) * 4) 1232 return (dt_set_errno(dtp, EDT_DMISMATCH)); 1233 1234 return (dt_printf(dtp, fp, format, 1235 dt_stddev((uint64_t *)data, normal))); 1236 } 1237 1238 /*ARGSUSED*/ 1239 static int 1240 pfprint_quantize(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1241 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 1242 { 1243 return (dt_print_quantize(dtp, fp, addr, size, normal)); 1244 } 1245 1246 /*ARGSUSED*/ 1247 static int 1248 pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1249 const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 1250 { 1251 return (dt_print_lquantize(dtp, fp, addr, size, normal)); 1252 } 1253 1254 static int 1255 dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv, 1256 const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf, 1257 size_t len, const dtrace_aggdata_t **aggsdata, int naggvars) 1258 { 1259 dt_pfargd_t *pfd = pfv->pfv_argv; 1260 const dtrace_recdesc_t *recp = recs; 1261 const dtrace_aggdata_t *aggdata; 1262 dtrace_aggdesc_t *agg; 1263 caddr_t lim = (caddr_t)buf + len, limit; 1264 char format[64] = "%"; 1265 int i, aggrec, curagg = -1; 1266 uint64_t normal; 1267 1268 /* 1269 * If we are formatting an aggregation, set 'aggrec' to the index of 1270 * the final record description (the aggregation result) so we can use 1271 * this record index with any conversion where DT_PFCONV_AGG is set. 1272 * (The actual aggregation used will vary as we increment through the 1273 * aggregation variables that we have been passed.) Finally, we 1274 * decrement nrecs to prevent this record from being used with any 1275 * other conversion. 1276 */ 1277 if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 1278 assert(aggsdata != NULL); 1279 assert(naggvars > 0); 1280 1281 if (nrecs == 0) 1282 return (dt_set_errno(dtp, EDT_DMISMATCH)); 1283 1284 curagg = naggvars > 1 ? 1 : 0; 1285 aggdata = aggsdata[0]; 1286 aggrec = aggdata->dtada_desc->dtagd_nrecs - 1; 1287 nrecs--; 1288 } 1289 1290 for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 1291 const dt_pfconv_t *pfc = pfd->pfd_conv; 1292 int width = pfd->pfd_width; 1293 int prec = pfd->pfd_prec; 1294 int rval; 1295 1296 char *f = format + 1; /* skip initial '%' */ 1297 const dtrace_recdesc_t *rec; 1298 dt_pfprint_f *func; 1299 caddr_t addr; 1300 size_t size; 1301 uint32_t flags; 1302 1303 if (pfd->pfd_preflen != 0) { 1304 char *tmp = alloca(pfd->pfd_preflen + 1); 1305 1306 bcopy(pfd->pfd_prefix, tmp, pfd->pfd_preflen); 1307 tmp[pfd->pfd_preflen] = '\0'; 1308 1309 if ((rval = dt_printf(dtp, fp, tmp)) < 0) 1310 return (rval); 1311 1312 if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 1313 /* 1314 * For printa(), we flush the buffer after each 1315 * prefix, setting the flags to indicate that 1316 * this is part of the printa() format string. 1317 */ 1318 flags = DTRACE_BUFDATA_AGGFORMAT; 1319 1320 if (pfc == NULL && i == pfv->pfv_argc - 1) 1321 flags |= DTRACE_BUFDATA_AGGLAST; 1322 1323 if (dt_buffered_flush(dtp, NULL, NULL, 1324 aggdata, flags) < 0) 1325 return (-1); 1326 } 1327 } 1328 1329 if (pfc == NULL) { 1330 if (pfv->pfv_argc == 1) 1331 return (nrecs != 0); 1332 continue; 1333 } 1334 1335 /* 1336 * If the conversion is %%, just invoke the print callback 1337 * with no data record and continue; it consumes no record. 1338 */ 1339 if (pfc->pfc_print == &pfprint_pct) { 1340 if (pfc->pfc_print(dtp, fp, NULL, pfd, NULL, 0, 1) >= 0) 1341 continue; 1342 return (-1); /* errno is set for us */ 1343 } 1344 1345 if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) { 1346 if (dt_printf_getint(dtp, recp++, nrecs--, buf, 1347 len, &width) == -1) 1348 return (-1); /* errno is set for us */ 1349 pfd->pfd_dynwidth = width; 1350 } else { 1351 pfd->pfd_dynwidth = 0; 1352 } 1353 1354 if ((pfd->pfd_flags & DT_PFCONV_DYNPREC) && dt_printf_getint( 1355 dtp, recp++, nrecs--, buf, len, &prec) == -1) 1356 return (-1); /* errno is set for us */ 1357 1358 if (pfd->pfd_flags & DT_PFCONV_AGG) { 1359 /* 1360 * This should be impossible -- the compiler shouldn't 1361 * create a DT_PFCONV_AGG conversion without an 1362 * aggregation present. Still, we'd rather fail 1363 * gracefully than blow up... 1364 */ 1365 if (aggsdata == NULL) 1366 return (dt_set_errno(dtp, EDT_DMISMATCH)); 1367 1368 aggdata = aggsdata[curagg]; 1369 agg = aggdata->dtada_desc; 1370 1371 /* 1372 * We increment the current aggregation variable, but 1373 * not beyond the number of aggregation variables that 1374 * we're printing. This has the (desired) effect that 1375 * DT_PFCONV_AGG conversions beyond the number of 1376 * aggregation variables (re-)convert the aggregation 1377 * value of the last aggregation variable. 1378 */ 1379 if (curagg < naggvars - 1) 1380 curagg++; 1381 1382 rec = &agg->dtagd_rec[aggrec]; 1383 addr = aggdata->dtada_data + rec->dtrd_offset; 1384 limit = addr + aggdata->dtada_size; 1385 normal = aggdata->dtada_normal; 1386 flags = DTRACE_BUFDATA_AGGVAL; 1387 } else { 1388 if (nrecs == 0) 1389 return (dt_set_errno(dtp, EDT_DMISMATCH)); 1390 1391 if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 1392 /* 1393 * When printing aggregation keys, we always 1394 * set the aggdata to be the representative 1395 * (zeroth) aggregation. The aggdata isn't 1396 * actually used here in this case, but it is 1397 * passed to the buffer handler and must 1398 * therefore still be correct. 1399 */ 1400 aggdata = aggsdata[0]; 1401 flags = DTRACE_BUFDATA_AGGKEY; 1402 } 1403 1404 rec = recp++; 1405 nrecs--; 1406 addr = (caddr_t)buf + rec->dtrd_offset; 1407 limit = lim; 1408 normal = 1; 1409 } 1410 1411 size = rec->dtrd_size; 1412 1413 if (addr + size > limit) { 1414 dt_dprintf("bad size: addr=%p size=0x%x lim=%p\n", 1415 (void *)addr, rec->dtrd_size, (void *)lim); 1416 return (dt_set_errno(dtp, EDT_DOFFSET)); 1417 } 1418 1419 if (rec->dtrd_alignment != 0 && 1420 ((uintptr_t)addr & (rec->dtrd_alignment - 1)) != 0) { 1421 dt_dprintf("bad align: addr=%p size=0x%x align=0x%x\n", 1422 (void *)addr, rec->dtrd_size, rec->dtrd_alignment); 1423 return (dt_set_errno(dtp, EDT_DALIGN)); 1424 } 1425 1426 switch (rec->dtrd_action) { 1427 case DTRACEAGG_AVG: 1428 func = pfprint_average; 1429 break; 1430 case DTRACEAGG_STDDEV: 1431 func = pfprint_stddev; 1432 break; 1433 case DTRACEAGG_QUANTIZE: 1434 func = pfprint_quantize; 1435 break; 1436 case DTRACEAGG_LQUANTIZE: 1437 func = pfprint_lquantize; 1438 break; 1439 case DTRACEACT_MOD: 1440 func = pfprint_mod; 1441 break; 1442 case DTRACEACT_UMOD: 1443 func = pfprint_umod; 1444 break; 1445 default: 1446 func = pfc->pfc_print; 1447 break; 1448 } 1449 1450 if (pfd->pfd_flags & DT_PFCONV_ALT) 1451 *f++ = '#'; 1452 if (pfd->pfd_flags & DT_PFCONV_ZPAD) 1453 *f++ = '0'; 1454 if (width < 0 || (pfd->pfd_flags & DT_PFCONV_LEFT)) 1455 *f++ = '-'; 1456 if (pfd->pfd_flags & DT_PFCONV_SPOS) 1457 *f++ = '+'; 1458 if (pfd->pfd_flags & DT_PFCONV_GROUP) 1459 *f++ = '\''; 1460 if (pfd->pfd_flags & DT_PFCONV_SPACE) 1461 *f++ = ' '; 1462 1463 /* 1464 * If we're printing a stack and DT_PFCONV_LEFT is set, we 1465 * don't add the width to the format string. See the block 1466 * comment in pfprint_stack() for a description of the 1467 * behavior in this case. 1468 */ 1469 if (func == pfprint_stack && (pfd->pfd_flags & DT_PFCONV_LEFT)) 1470 width = 0; 1471 1472 if (width != 0) 1473 f += snprintf(f, sizeof (format), "%d", ABS(width)); 1474 1475 if (prec > 0) 1476 f += snprintf(f, sizeof (format), ".%d", prec); 1477 1478 (void) strcpy(f, pfd->pfd_fmt); 1479 pfd->pfd_rec = rec; 1480 1481 if (func(dtp, fp, format, pfd, addr, size, normal) < 0) 1482 return (-1); /* errno is set for us */ 1483 1484 if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 1485 /* 1486 * For printa(), we flush the buffer after each tuple 1487 * element, inidicating that this is the last record 1488 * as appropriate. 1489 */ 1490 if (i == pfv->pfv_argc - 1) 1491 flags |= DTRACE_BUFDATA_AGGLAST; 1492 1493 if (dt_buffered_flush(dtp, NULL, 1494 rec, aggdata, flags) < 0) 1495 return (-1); 1496 } 1497 } 1498 1499 return ((int)(recp - recs)); 1500 } 1501 1502 int 1503 dtrace_sprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 1504 const dtrace_recdesc_t *recp, uint_t nrecs, const void *buf, size_t len) 1505 { 1506 dtrace_optval_t size; 1507 int rval; 1508 1509 rval = dtrace_getopt(dtp, "strsize", &size); 1510 assert(rval == 0); 1511 assert(dtp->dt_sprintf_buflen == 0); 1512 1513 if (dtp->dt_sprintf_buf != NULL) 1514 free(dtp->dt_sprintf_buf); 1515 1516 if ((dtp->dt_sprintf_buf = malloc(size)) == NULL) 1517 return (dt_set_errno(dtp, EDT_NOMEM)); 1518 1519 bzero(dtp->dt_sprintf_buf, size); 1520 dtp->dt_sprintf_buflen = size; 1521 rval = dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len, 1522 NULL, 0); 1523 dtp->dt_sprintf_buflen = 0; 1524 1525 if (rval == -1) 1526 free(dtp->dt_sprintf_buf); 1527 1528 return (rval); 1529 } 1530 1531 /*ARGSUSED*/ 1532 int 1533 dtrace_system(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 1534 const dtrace_probedata_t *data, const dtrace_recdesc_t *recp, 1535 uint_t nrecs, const void *buf, size_t len) 1536 { 1537 int rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len); 1538 1539 if (rval == -1) 1540 return (rval); 1541 1542 /* 1543 * Before we execute the specified command, flush fp to assure that 1544 * any prior dt_printf()'s appear before the output of the command 1545 * not after it. 1546 */ 1547 (void) fflush(fp); 1548 1549 if (system(dtp->dt_sprintf_buf) == -1) 1550 return (dt_set_errno(dtp, errno)); 1551 1552 return (rval); 1553 } 1554 1555 int 1556 dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 1557 const dtrace_probedata_t *data, const dtrace_recdesc_t *recp, 1558 uint_t nrecs, const void *buf, size_t len) 1559 { 1560 char selfbuf[40], restorebuf[40], *filename; 1561 FILE *nfp; 1562 int rval, errval; 1563 dt_pfargv_t *pfv = fmtdata; 1564 dt_pfargd_t *pfd = pfv->pfv_argv; 1565 1566 rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len); 1567 1568 if (rval == -1 || fp == NULL) 1569 return (rval); 1570 1571 if (pfd->pfd_preflen != 0 && 1572 strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) { 1573 /* 1574 * The only way to have the format string set to the value 1575 * DT_FREOPEN_RESTORE is via the empty freopen() string -- 1576 * denoting that we should restore the old stdout. 1577 */ 1578 assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0); 1579 1580 if (dtp->dt_stdout_fd == -1) { 1581 /* 1582 * We could complain here by generating an error, 1583 * but it seems like overkill: it seems that calling 1584 * freopen() to restore stdout when freopen() has 1585 * never before been called should just be a no-op, 1586 * so we just return in this case. 1587 */ 1588 return (rval); 1589 } 1590 1591 (void) snprintf(restorebuf, sizeof (restorebuf), 1592 "/dev/fd/%d", dtp->dt_stdout_fd); 1593 filename = restorebuf; 1594 } else { 1595 filename = dtp->dt_sprintf_buf; 1596 } 1597 1598 /* 1599 * freopen(3C) will always close the specified stream and underlying 1600 * file descriptor -- even if the specified file can't be opened. 1601 * Even for the semantic cesspool that is standard I/O, this is 1602 * surprisingly brain-dead behavior: it means that any failure to 1603 * open the specified file destroys the specified stream in the 1604 * process -- which is particularly relevant when the specified stream 1605 * happens (or rather, happened) to be stdout. This could be resolved 1606 * were there an "fdreopen()" equivalent of freopen() that allowed one 1607 * to pass a file descriptor instead of the name of a file, but there 1608 * is no such thing. However, we can effect this ourselves by first 1609 * fopen()'ing the desired file, and then (assuming that that works), 1610 * freopen()'ing "/dev/fd/[fileno]", where [fileno] is the underlying 1611 * file descriptor for the fopen()'d file. This way, if the fopen() 1612 * fails, we can fail the operation without destroying stdout. 1613 */ 1614 if ((nfp = fopen(filename, "aF")) == NULL) { 1615 char *msg = strerror(errno), *faultstr; 1616 int len = 80; 1617 1618 len += strlen(msg) + strlen(filename); 1619 faultstr = alloca(len); 1620 1621 (void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s", 1622 filename, strerror(errno)); 1623 1624 if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0) 1625 return (rval); 1626 1627 return (errval); 1628 } 1629 1630 (void) snprintf(selfbuf, sizeof (selfbuf), "/dev/fd/%d", fileno(nfp)); 1631 1632 if (dtp->dt_stdout_fd == -1) { 1633 /* 1634 * If this is the first time that we're calling freopen(), 1635 * we're going to stash away the file descriptor for stdout. 1636 * We don't expect the dup(2) to fail, so if it does we must 1637 * return failure. 1638 */ 1639 if ((dtp->dt_stdout_fd = dup(fileno(fp))) == -1) { 1640 (void) fclose(nfp); 1641 return (dt_set_errno(dtp, errno)); 1642 } 1643 } 1644 1645 if (freopen(selfbuf, "aF", fp) == NULL) { 1646 (void) fclose(nfp); 1647 return (dt_set_errno(dtp, errno)); 1648 } 1649 1650 (void) fclose(nfp); 1651 1652 return (rval); 1653 } 1654 1655 /*ARGSUSED*/ 1656 int 1657 dtrace_fprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 1658 const dtrace_probedata_t *data, const dtrace_recdesc_t *recp, 1659 uint_t nrecs, const void *buf, size_t len) 1660 { 1661 return (dt_printf_format(dtp, fp, fmtdata, 1662 recp, nrecs, buf, len, NULL, 0)); 1663 } 1664 1665 void * 1666 dtrace_printf_create(dtrace_hdl_t *dtp, const char *s) 1667 { 1668 dt_pfargv_t *pfv = dt_printf_create(dtp, s); 1669 dt_pfargd_t *pfd; 1670 int i; 1671 1672 if (pfv == NULL) 1673 return (NULL); /* errno has been set for us */ 1674 1675 pfd = pfv->pfv_argv; 1676 1677 for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 1678 const dt_pfconv_t *pfc = pfd->pfd_conv; 1679 1680 if (pfc == NULL) 1681 continue; 1682 1683 /* 1684 * If the output format is not %s then we assume that we have 1685 * been given a correctly-sized format string, so we copy the 1686 * true format name including the size modifier. If the output 1687 * format is %s, then either the input format is %s as well or 1688 * it is one of our custom formats (e.g. pfprint_addr), so we 1689 * must set pfd_fmt to be the output format conversion "s". 1690 */ 1691 if (strcmp(pfc->pfc_ofmt, "s") != 0) 1692 (void) strcat(pfd->pfd_fmt, pfc->pfc_name); 1693 else 1694 (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt); 1695 } 1696 1697 return (pfv); 1698 } 1699 1700 void * 1701 dtrace_printa_create(dtrace_hdl_t *dtp, const char *s) 1702 { 1703 dt_pfargv_t *pfv = dtrace_printf_create(dtp, s); 1704 1705 if (pfv == NULL) 1706 return (NULL); /* errno has been set for us */ 1707 1708 pfv->pfv_flags |= DT_PRINTF_AGGREGATION; 1709 1710 return (pfv); 1711 } 1712 1713 /*ARGSUSED*/ 1714 size_t 1715 dtrace_printf_format(dtrace_hdl_t *dtp, void *fmtdata, char *s, size_t len) 1716 { 1717 dt_pfargv_t *pfv = fmtdata; 1718 dt_pfargd_t *pfd = pfv->pfv_argv; 1719 1720 /* 1721 * An upper bound on the string length is the length of the original 1722 * format string, plus three times the number of conversions (each 1723 * conversion could add up an additional "ll" and/or pfd_width digit 1724 * in the case of converting %? to %16) plus one for a terminating \0. 1725 */ 1726 size_t formatlen = strlen(pfv->pfv_format) + 3 * pfv->pfv_argc + 1; 1727 char *format = alloca(formatlen); 1728 char *f = format; 1729 int i, j; 1730 1731 for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 1732 const dt_pfconv_t *pfc = pfd->pfd_conv; 1733 const char *str; 1734 int width = pfd->pfd_width; 1735 int prec = pfd->pfd_prec; 1736 1737 if (pfd->pfd_preflen != 0) { 1738 for (j = 0; j < pfd->pfd_preflen; j++) 1739 *f++ = pfd->pfd_prefix[j]; 1740 } 1741 1742 if (pfc == NULL) 1743 continue; 1744 1745 *f++ = '%'; 1746 1747 if (pfd->pfd_flags & DT_PFCONV_ALT) 1748 *f++ = '#'; 1749 if (pfd->pfd_flags & DT_PFCONV_ZPAD) 1750 *f++ = '0'; 1751 if (pfd->pfd_flags & DT_PFCONV_LEFT) 1752 *f++ = '-'; 1753 if (pfd->pfd_flags & DT_PFCONV_SPOS) 1754 *f++ = '+'; 1755 if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) 1756 *f++ = '*'; 1757 if (pfd->pfd_flags & DT_PFCONV_DYNPREC) { 1758 *f++ = '.'; 1759 *f++ = '*'; 1760 } 1761 if (pfd->pfd_flags & DT_PFCONV_GROUP) 1762 *f++ = '\''; 1763 if (pfd->pfd_flags & DT_PFCONV_SPACE) 1764 *f++ = ' '; 1765 if (pfd->pfd_flags & DT_PFCONV_AGG) 1766 *f++ = '@'; 1767 1768 if (width != 0) 1769 f += snprintf(f, sizeof (format), "%d", width); 1770 1771 if (prec != 0) 1772 f += snprintf(f, sizeof (format), ".%d", prec); 1773 1774 /* 1775 * If the output format is %s, then either %s is the underlying 1776 * conversion or the conversion is one of our customized ones, 1777 * e.g. pfprint_addr. In these cases, put the original string 1778 * name of the conversion (pfc_name) into the pickled format 1779 * string rather than the derived conversion (pfd_fmt). 1780 */ 1781 if (strcmp(pfc->pfc_ofmt, "s") == 0) 1782 str = pfc->pfc_name; 1783 else 1784 str = pfd->pfd_fmt; 1785 1786 for (j = 0; str[j] != '\0'; j++) 1787 *f++ = str[j]; 1788 } 1789 1790 *f = '\0'; /* insert nul byte; do not count in return value */ 1791 1792 assert(f < format + formatlen); 1793 (void) strncpy(s, format, len); 1794 1795 return ((size_t)(f - format)); 1796 } 1797 1798 static int 1799 dt_fprinta(const dtrace_aggdata_t *adp, void *arg) 1800 { 1801 const dtrace_aggdesc_t *agg = adp->dtada_desc; 1802 const dtrace_recdesc_t *recp = &agg->dtagd_rec[0]; 1803 uint_t nrecs = agg->dtagd_nrecs; 1804 dt_pfwalk_t *pfw = arg; 1805 dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp; 1806 int id; 1807 1808 if (dt_printf_getint(dtp, recp++, nrecs--, 1809 adp->dtada_data, adp->dtada_size, &id) != 0 || pfw->pfw_aid != id) 1810 return (0); /* no aggregation id or id does not match */ 1811 1812 if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv, 1813 recp, nrecs, adp->dtada_data, adp->dtada_size, &adp, 1) == -1) 1814 return (pfw->pfw_err = dtp->dt_errno); 1815 1816 /* 1817 * Cast away the const to set the bit indicating that this aggregation 1818 * has been printed. 1819 */ 1820 ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED; 1821 1822 return (0); 1823 } 1824 1825 static int 1826 dt_fprintas(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) 1827 { 1828 const dtrace_aggdata_t *aggdata = aggsdata[0]; 1829 const dtrace_aggdesc_t *agg = aggdata->dtada_desc; 1830 const dtrace_recdesc_t *rec = &agg->dtagd_rec[1]; 1831 uint_t nrecs = agg->dtagd_nrecs - 1; 1832 dt_pfwalk_t *pfw = arg; 1833 dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp; 1834 int i; 1835 1836 if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv, 1837 rec, nrecs, aggdata->dtada_data, aggdata->dtada_size, 1838 aggsdata, naggvars) == -1) 1839 return (pfw->pfw_err = dtp->dt_errno); 1840 1841 /* 1842 * For each aggregation, indicate that it has been printed, casting 1843 * away the const as necessary. 1844 */ 1845 for (i = 1; i < naggvars; i++) { 1846 agg = aggsdata[i]->dtada_desc; 1847 ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED; 1848 } 1849 1850 return (0); 1851 } 1852 /*ARGSUSED*/ 1853 int 1854 dtrace_fprinta(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 1855 const dtrace_probedata_t *data, const dtrace_recdesc_t *recs, 1856 uint_t nrecs, const void *buf, size_t len) 1857 { 1858 dt_pfwalk_t pfw; 1859 int i, naggvars = 0; 1860 dtrace_aggvarid_t *aggvars; 1861 1862 aggvars = alloca(nrecs * sizeof (dtrace_aggvarid_t)); 1863 1864 /* 1865 * This might be a printa() with multiple aggregation variables. We 1866 * need to scan forward through the records until we find a record from 1867 * a different statement. 1868 */ 1869 for (i = 0; i < nrecs; i++) { 1870 const dtrace_recdesc_t *nrec = &recs[i]; 1871 1872 if (nrec->dtrd_uarg != recs->dtrd_uarg) 1873 break; 1874 1875 if (nrec->dtrd_action != recs->dtrd_action) 1876 return (dt_set_errno(dtp, EDT_BADAGG)); 1877 1878 aggvars[naggvars++] = 1879 /* LINTED - alignment */ 1880 *((dtrace_aggvarid_t *)((caddr_t)buf + nrec->dtrd_offset)); 1881 } 1882 1883 if (naggvars == 0) 1884 return (dt_set_errno(dtp, EDT_BADAGG)); 1885 1886 pfw.pfw_argv = fmtdata; 1887 pfw.pfw_fp = fp; 1888 pfw.pfw_err = 0; 1889 1890 if (naggvars == 1) { 1891 pfw.pfw_aid = aggvars[0]; 1892 1893 if (dtrace_aggregate_walk_sorted(dtp, 1894 dt_fprinta, &pfw) == -1 || pfw.pfw_err != 0) 1895 return (-1); /* errno is set for us */ 1896 } else { 1897 if (dtrace_aggregate_walk_joined(dtp, aggvars, naggvars, 1898 dt_fprintas, &pfw) == -1 || pfw.pfw_err != 0) 1899 return (-1); /* errno is set for us */ 1900 } 1901 1902 return (i); 1903 } 1904