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