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