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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2011 by Delphix. All rights reserved. 27 */ 28 /* 29 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 30 * Copyright 2022 Oxide Computer Company 31 */ 32 33 /* 34 * DTrace print() action 35 * 36 * This file contains the post-processing logic for the print() action. The 37 * print action behaves identically to trace() in that it generates a 38 * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type 39 * string stored in the DOF string table (similar to printf formats). We 40 * take the result of the trace action and post-process it in the fashion of 41 * MDB's ::print dcmd. 42 * 43 * This implementation differs from MDB's in the following ways: 44 * 45 * - We do not expose any options or flags. The behavior of print() is 46 * equivalent to "::print -tn". 47 * 48 * - MDB will display "holes" in structures (unused padding between 49 * members). 50 * 51 * - When printing arrays of structures, MDB will leave a trailing ',' 52 * after the last element. 53 * 54 * - MDB will print time_t types as date and time. 55 * 56 * - MDB will detect when an enum is actually the OR of several flags, 57 * and print it out with the constituent flags separated. 58 * 59 * - For large arrays, MDB will print the first few members and then 60 * print a "..." continuation line. 61 * 62 * - MDB will break and wrap arrays at 80 columns. 63 * 64 * - MDB prints out floats and doubles by hand, as it must run in kmdb 65 * context. We're able to leverage the printf() format strings, 66 * but the result is a slightly different format. 67 */ 68 69 #include <sys/sysmacros.h> 70 #include <strings.h> 71 #include <stdlib.h> 72 #include <alloca.h> 73 #include <assert.h> 74 #include <ctype.h> 75 #include <errno.h> 76 #include <limits.h> 77 #include <sys/socket.h> 78 #include <netdb.h> 79 #include <netinet/in.h> 80 #include <arpa/inet.h> 81 #include <arpa/nameser.h> 82 83 #include <dt_module.h> 84 #include <dt_printf.h> 85 #include <dt_string.h> 86 #include <dt_impl.h> 87 88 /* determines whether the given integer CTF encoding is a character */ 89 #define CTF_IS_CHAR(e) \ 90 (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \ 91 (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY) 92 /* determines whether the given CTF kind is a struct or union */ 93 #define CTF_IS_STRUCTLIKE(k) \ 94 ((k) == CTF_K_STRUCT || (k) == CTF_K_UNION) 95 96 /* 97 * Print structure passed down recursively through printing algorithm. 98 */ 99 typedef struct dt_printarg { 100 dtrace_hdl_t *pa_dtp; /* libdtrace handle */ 101 caddr_t pa_addr; /* base address of trace data */ 102 ctf_file_t *pa_ctfp; /* CTF container */ 103 int pa_depth; /* member depth */ 104 int pa_nest; /* nested array depth */ 105 FILE *pa_file; /* output file */ 106 } dt_printarg_t; 107 108 static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *); 109 110 /* 111 * Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it 112 * can't resolve the type. 113 */ 114 static void 115 dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen) 116 { 117 if (ctf_type_name(ctfp, id, buf, buflen) == NULL) 118 (void) snprintf(buf, buflen, "<%ld>", id); 119 } 120 121 /* 122 * Print any necessary trailing braces for structures or unions. We don't get 123 * invoked when a struct or union ends, so we infer the need to print braces 124 * based on the depth the last time we printed something and the new depth. 125 */ 126 static void 127 dt_print_trailing_braces(dt_printarg_t *pap, int depth) 128 { 129 int d; 130 131 for (d = pap->pa_depth; d > depth; d--) { 132 (void) fprintf(pap->pa_file, "%*s}%s", 133 (d + pap->pa_nest - 1) * 4, "", 134 d == depth + 1 ? "" : "\n"); 135 } 136 } 137 138 /* 139 * Print the appropriate amount of indentation given the current depth and 140 * array nesting. 141 */ 142 static void 143 dt_print_indent(dt_printarg_t *pap) 144 { 145 (void) fprintf(pap->pa_file, "%*s", 146 (pap->pa_depth + pap->pa_nest) * 4, ""); 147 } 148 149 /* 150 * Print a bitfield. It's worth noting that the D compiler support for 151 * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the 152 * various D provider files) will produce incorrect results compared to 153 * "genunix`user_desc_t". However, bitfields that are built via CTF will be 154 * fine. Note, this is derived from mdb's print_bifield in mdb_print.c. 155 */ 156 static void 157 print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep) 158 { 159 FILE *fp = pap->pa_file; 160 caddr_t addr = pap->pa_addr + off / NBBY; 161 uint64_t mask = (1ULL << ep->cte_bits) - 1; 162 uint64_t value = 0; 163 uint8_t *buf = (uint8_t *)&value; 164 uint8_t shift; 165 166 /* 167 * Our bitfield may straddle a byte boundary. We explicitly take the 168 * offset of the bitfield within its byte into account when determining 169 * the overall amount of data to copy and mask off from the underlying 170 * data. 171 */ 172 uint_t nbits = ep->cte_bits + (off % NBBY); 173 size_t size = P2ROUNDUP(nbits, NBBY) / NBBY; 174 175 /* 176 * The resulting size must fit within the 64-bit value that we're using 177 * to store the value, otherwise the bcopy below could destroy our 178 * stack. This could be handled, but is not practically worth 179 * addressing. This choice apes mdb, so if you're considering fixing 180 * this, fix mdb as well. 181 */ 182 if (size > sizeof (value)) { 183 (void) fprintf(fp, "??? (total bitfield too large after " 184 "alignment"); 185 return; 186 } 187 188 /* 189 * On big-endian machines, we need to adjust the buf pointer to refer 190 * to the lowest 'size' bytes in 'value', and we need to shift based on 191 * the offset from the end of the data, not the offset of the start. 192 */ 193 #ifdef _BIG_ENDIAN 194 buf += sizeof (value) - size; 195 off += ep->cte_bits; 196 #endif 197 bcopy(addr, buf, size); 198 shift = off % NBBY; 199 200 /* 201 * Offsets are counted from opposite ends on little- and 202 * big-endian machines. 203 */ 204 #ifdef _BIG_ENDIAN 205 shift = NBBY - shift; 206 #endif 207 208 /* 209 * If the bits we want do not begin on a byte boundary, shift the data 210 * right so that the value is in the lowest 'cte_bits' of 'value'. 211 */ 212 if (off % NBBY != 0) 213 value >>= shift; 214 value &= mask; 215 216 (void) fprintf(fp, "%#llx", (u_longlong_t)value); 217 } 218 219 /* 220 * Dump the contents of memory as a fixed-size integer in hex. 221 */ 222 static void 223 dt_print_hex(FILE *fp, caddr_t addr, size_t size) 224 { 225 switch (size) { 226 case sizeof (uint8_t): 227 (void) fprintf(fp, "%#x", *(uint8_t *)addr); 228 break; 229 case sizeof (uint16_t): 230 /* LINTED - alignment */ 231 (void) fprintf(fp, "%#x", *(uint16_t *)addr); 232 break; 233 case sizeof (uint32_t): 234 /* LINTED - alignment */ 235 (void) fprintf(fp, "%#x", *(uint32_t *)addr); 236 break; 237 case sizeof (uint64_t): 238 (void) fprintf(fp, "%#llx", 239 /* LINTED - alignment */ 240 (unsigned long long)*(uint64_t *)addr); 241 break; 242 default: 243 (void) fprintf(fp, "<invalid size %u>", (uint_t)size); 244 } 245 } 246 247 /* 248 * Print an integer type. Before dumping the contents via dt_print_hex(), we 249 * first check the encoding to see if it's part of a bitfield or a character. 250 */ 251 static void 252 dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 253 { 254 FILE *fp = pap->pa_file; 255 ctf_file_t *ctfp = pap->pa_ctfp; 256 ctf_encoding_t e; 257 size_t size; 258 caddr_t addr = pap->pa_addr + off / NBBY; 259 260 if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) { 261 (void) fprintf(fp, "<unknown encoding>"); 262 return; 263 } 264 265 /* 266 * This comes from MDB - it's not clear under what circumstances this 267 * would be found. 268 */ 269 if (e.cte_format & CTF_INT_VARARGS) { 270 (void) fprintf(fp, "..."); 271 return; 272 } 273 274 size = e.cte_bits / NBBY; 275 if (dt_is_bitfield(&e, off)) { 276 print_bitfield(pap, off, &e); 277 return; 278 } 279 280 /* 281 * If this is a character, print it out as such. 282 */ 283 if (CTF_IS_CHAR(e)) { 284 char c = *(char *)addr; 285 if (isprint(c)) 286 (void) fprintf(fp, "'%c'", c); 287 else if (c == 0) 288 (void) fprintf(fp, "'\\0'"); 289 else 290 (void) fprintf(fp, "'\\%03o'", c); 291 return; 292 } 293 294 dt_print_hex(fp, addr, size); 295 } 296 297 /* 298 * Print a floating point (float, double, long double) value. 299 */ 300 /* ARGSUSED */ 301 static void 302 dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 303 { 304 FILE *fp = pap->pa_file; 305 ctf_file_t *ctfp = pap->pa_ctfp; 306 ctf_encoding_t e; 307 caddr_t addr = pap->pa_addr + off / NBBY; 308 309 if (ctf_type_encoding(ctfp, base, &e) == 0) { 310 if (e.cte_format == CTF_FP_SINGLE && 311 e.cte_bits == sizeof (float) * NBBY) { 312 /* LINTED - alignment */ 313 (void) fprintf(fp, "%+.7e", *((float *)addr)); 314 } else if (e.cte_format == CTF_FP_DOUBLE && 315 e.cte_bits == sizeof (double) * NBBY) { 316 /* LINTED - alignment */ 317 (void) fprintf(fp, "%+.7e", *((double *)addr)); 318 } else if (e.cte_format == CTF_FP_LDOUBLE && 319 e.cte_bits == sizeof (long double) * NBBY) { 320 /* LINTED - alignment */ 321 (void) fprintf(fp, "%+.16LE", *((long double *)addr)); 322 } else { 323 (void) fprintf(fp, "<unknown encoding>"); 324 } 325 } 326 } 327 328 /* 329 * A pointer is generally printed as a fixed-size integer. If we have a 330 * function pointer, we try to look up its name. 331 */ 332 static void 333 dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 334 { 335 FILE *fp = pap->pa_file; 336 ctf_file_t *ctfp = pap->pa_ctfp; 337 caddr_t addr = pap->pa_addr + off / NBBY; 338 size_t size = ctf_type_size(ctfp, base); 339 ctf_id_t bid = ctf_type_reference(ctfp, base); 340 uint64_t pc; 341 dtrace_syminfo_t dts; 342 GElf_Sym sym; 343 344 if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) { 345 dt_print_hex(fp, addr, size); 346 } else { 347 /* LINTED - alignment */ 348 pc = *((uint64_t *)addr); 349 if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) { 350 dt_print_hex(fp, addr, size); 351 } else { 352 (void) fprintf(fp, "%s`%s", dts.dts_object, 353 dts.dts_name); 354 } 355 } 356 } 357 358 /* 359 * Print out an array. This is somewhat complex, as we must manually visit 360 * each member, and recursively invoke ctf_type_visit() for each member. If 361 * the members are non-structs, then we print them out directly: 362 * 363 * [ 0x14, 0x2e, 0 ] 364 * 365 * If they are structs, then we print out the necessary leading and trailing 366 * braces, to end up with: 367 * 368 * [ 369 * type { 370 * ... 371 * }, 372 * type { 373 * ... 374 * } 375 * ] 376 * 377 * We also use a heuristic to detect whether the array looks like a character 378 * array. If the encoding indicates it's a character, and we have all 379 * printable characters followed by a null byte, then we display it as a 380 * string: 381 * 382 * [ "string" ] 383 */ 384 static void 385 dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 386 { 387 FILE *fp = pap->pa_file; 388 ctf_file_t *ctfp = pap->pa_ctfp; 389 caddr_t addr = pap->pa_addr + off / NBBY; 390 ctf_arinfo_t car; 391 ssize_t eltsize; 392 ctf_encoding_t e; 393 int i; 394 boolean_t isstring; 395 int kind; 396 ctf_id_t rtype; 397 398 if (ctf_array_info(ctfp, base, &car) == CTF_ERR) { 399 (void) fprintf(fp, "0x%p", (void *)addr); 400 return; 401 } 402 403 if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 || 404 (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR || 405 (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) { 406 (void) fprintf(fp, "<invalid type %lu>", car.ctr_contents); 407 return; 408 } 409 410 /* see if this looks like a string */ 411 isstring = B_FALSE; 412 if (kind == CTF_K_INTEGER && 413 ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) { 414 char c; 415 for (i = 0; i < car.ctr_nelems; i++) { 416 c = *((char *)addr + eltsize * i); 417 if (!isprint(c) || c == '\0') 418 break; 419 } 420 421 if (i != car.ctr_nelems && c == '\0') 422 isstring = B_TRUE; 423 } 424 425 /* 426 * As a slight aesthetic optimization, if we are a top-level type, then 427 * don't bother printing out the brackets. This lets print("foo") look 428 * like: 429 * 430 * string "foo" 431 * 432 * As D will internally represent this as a char[256] array. 433 */ 434 if (!isstring || pap->pa_depth != 0) 435 (void) fprintf(fp, "[ "); 436 437 if (isstring) 438 (void) fprintf(fp, "\""); 439 440 for (i = 0; i < car.ctr_nelems; i++) { 441 if (isstring) { 442 char c = *((char *)addr + eltsize * i); 443 if (c == '\0') 444 break; 445 (void) fprintf(fp, "%c", c); 446 } else { 447 /* 448 * Recursively invoke ctf_type_visit() on each member. 449 * We setup a new printarg struct with 'pa_nest' set to 450 * indicate that we are within a nested array. 451 */ 452 dt_printarg_t pa = *pap; 453 pa.pa_nest += pap->pa_depth + 1; 454 pa.pa_depth = 0; 455 pa.pa_addr = addr + eltsize * i; 456 (void) ctf_type_visit(ctfp, car.ctr_contents, 457 dt_print_member, &pa); 458 459 dt_print_trailing_braces(&pa, 0); 460 if (i != car.ctr_nelems - 1) 461 (void) fprintf(fp, ", "); 462 else if (CTF_IS_STRUCTLIKE(kind)) 463 (void) fprintf(fp, "\n"); 464 } 465 } 466 467 if (isstring) 468 (void) fprintf(fp, "\""); 469 470 if (!isstring || pap->pa_depth != 0) { 471 if (CTF_IS_STRUCTLIKE(kind)) 472 dt_print_indent(pap); 473 else 474 (void) fprintf(fp, " "); 475 (void) fprintf(fp, "]"); 476 } 477 } 478 479 /* 480 * This isued by both structs and unions to print the leading brace. 481 */ 482 /* ARGSUSED */ 483 static void 484 dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap) 485 { 486 (void) fprintf(pap->pa_file, "{"); 487 } 488 489 /* 490 * For enums, we try to print the enum name, and fall back to the value if it 491 * can't be determined. We do not do any fancy flag processing like mdb. 492 */ 493 /* ARGSUSED */ 494 static void 495 dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 496 { 497 FILE *fp = pap->pa_file; 498 ctf_file_t *ctfp = pap->pa_ctfp; 499 const char *ename; 500 ssize_t size; 501 caddr_t addr = pap->pa_addr + off / NBBY; 502 int value = 0; 503 504 /* 505 * The C standard says that an enum will be at most the sizeof (int). 506 * But if all the values are less than that, the compiler can use a 507 * smaller size. Thanks standards. 508 */ 509 size = ctf_type_size(ctfp, base); 510 switch (size) { 511 case sizeof (uint8_t): 512 value = *(uint8_t *)addr; 513 break; 514 case sizeof (uint16_t): 515 /* LINTED - alignment */ 516 value = *(uint16_t *)addr; 517 break; 518 case sizeof (int32_t): 519 /* LINTED - alignment */ 520 value = *(int32_t *)addr; 521 break; 522 default: 523 (void) fprintf(fp, "<invalid enum size %u>", (uint_t)size); 524 return; 525 } 526 527 if ((ename = ctf_enum_name(ctfp, base, value)) != NULL) 528 (void) fprintf(fp, "%s", ename); 529 else 530 (void) fprintf(fp, "%d", value); 531 } 532 533 /* 534 * Forward declaration. There's not much to do here without the complete 535 * type information, so just print out this fact and drive on. 536 */ 537 /* ARGSUSED */ 538 static void 539 dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 540 { 541 (void) fprintf(pap->pa_file, "<forward decl>"); 542 } 543 544 typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *); 545 546 static dt_printarg_f *const dt_printfuncs[] = { 547 dt_print_int, /* CTF_K_INTEGER */ 548 dt_print_float, /* CTF_K_FLOAT */ 549 dt_print_ptr, /* CTF_K_POINTER */ 550 dt_print_array, /* CTF_K_ARRAY */ 551 dt_print_ptr, /* CTF_K_FUNCTION */ 552 dt_print_structlike, /* CTF_K_STRUCT */ 553 dt_print_structlike, /* CTF_K_UNION */ 554 dt_print_enum, /* CTF_K_ENUM */ 555 dt_print_tag /* CTF_K_FORWARD */ 556 }; 557 558 /* 559 * Print one member of a structure. This callback is invoked from 560 * ctf_type_visit() recursively. 561 */ 562 static int 563 dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth, 564 void *data) 565 { 566 char type[DT_TYPE_NAMELEN]; 567 int kind; 568 dt_printarg_t *pap = data; 569 FILE *fp = pap->pa_file; 570 ctf_file_t *ctfp = pap->pa_ctfp; 571 boolean_t arraymember; 572 boolean_t brief; 573 ctf_encoding_t e; 574 ctf_id_t rtype; 575 576 dt_print_trailing_braces(pap, depth); 577 /* 578 * dt_print_trailing_braces() doesn't include the trailing newline; add 579 * it here if necessary. 580 */ 581 if (depth < pap->pa_depth) 582 (void) fprintf(fp, "\n"); 583 pap->pa_depth = depth; 584 585 if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR || 586 (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR || 587 kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) { 588 dt_print_indent(pap); 589 (void) fprintf(fp, "%s = <invalid type %lu>", name, id); 590 return (0); 591 } 592 593 dt_print_type_name(ctfp, id, type, sizeof (type)); 594 595 arraymember = (pap->pa_nest != 0 && depth == 0); 596 brief = (arraymember && !CTF_IS_STRUCTLIKE(kind)); 597 598 if (!brief) { 599 /* 600 * If this is a direct array member and a struct (otherwise 601 * brief would be true), then print a trailing newline, as the 602 * array printing code doesn't include it because it might be a 603 * simple type. 604 */ 605 if (arraymember) 606 (void) fprintf(fp, "\n"); 607 dt_print_indent(pap); 608 609 /* always print the type */ 610 (void) fprintf(fp, "%s", type); 611 if (name[0] != '\0') { 612 /* 613 * For aesthetics, we don't include a space between the 614 * type name and member name if the type is a pointer. 615 * This will give us "void *foo =" instead of "void * 616 * foo =". Unions also have the odd behavior that the 617 * type name is returned as "union ", with a trailing 618 * space, so we also avoid printing a space if the type 619 * name already ends with a space. 620 */ 621 if (type[strlen(type) - 1] != '*' && 622 type[strlen(type) -1] != ' ') { 623 (void) fprintf(fp, " "); 624 } 625 (void) fprintf(fp, "%s", name); 626 627 /* 628 * If this looks like a bitfield, or is an integer not 629 * aligned on a byte boundary, print the number of 630 * bits after the name. 631 */ 632 if (kind == CTF_K_INTEGER && 633 ctf_type_encoding(ctfp, id, &e) == 0) { 634 ulong_t bits = e.cte_bits; 635 ulong_t size = bits / NBBY; 636 637 if (bits % NBBY != 0 || 638 off % NBBY != 0 || 639 size > 8 || 640 size != ctf_type_size(ctfp, id)) { 641 (void) fprintf(fp, " :%lu", bits); 642 } 643 } 644 645 (void) fprintf(fp, " ="); 646 } 647 (void) fprintf(fp, " "); 648 } 649 650 dt_printfuncs[kind - 1](rtype, off, pap); 651 652 /* direct simple array members are not separated by newlines */ 653 if (!brief) 654 (void) fprintf(fp, "\n"); 655 656 return (0); 657 } 658 659 /* 660 * Main print function invoked by dt_consume_cpu(). 661 */ 662 int 663 dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename, 664 caddr_t addr, size_t len) 665 { 666 const char *s; 667 char *object; 668 dt_printarg_t pa; 669 ctf_id_t id; 670 dt_module_t *dmp; 671 ctf_file_t *ctfp; 672 int libid; 673 674 /* 675 * Split the fully-qualified type ID (module`id). This should 676 * always be the format, but if for some reason we don't find the 677 * expected value, return 0 to fall back to the generic trace() 678 * behavior. In the case of userland CTF modules this will actually be 679 * of the format (module`lib`id). This is due to the fact that those 680 * modules have multiple CTF containers which `lib` identifies. 681 */ 682 for (s = typename; *s != '\0' && *s != '`'; s++) 683 ; 684 685 if (*s != '`') 686 return (0); 687 688 object = alloca(s - typename + 1); 689 bcopy(typename, object, s - typename); 690 object[s - typename] = '\0'; 691 dmp = dt_module_lookup_by_name(dtp, object); 692 if (dmp == NULL) 693 return (0); 694 695 if (dmp->dm_pid != 0) { 696 libid = atoi(s + 1); 697 s = strchr(s + 1, '`'); 698 if (s == NULL || libid > dmp->dm_nctflibs) 699 return (0); 700 ctfp = dmp->dm_libctfp[libid]; 701 } else { 702 ctfp = dt_module_getctf(dtp, dmp); 703 } 704 705 id = atoi(s + 1); 706 707 /* 708 * Try to get the CTF kind for this id. If something has gone horribly 709 * wrong and we can't resolve the ID, bail out and let trace() do the 710 * work. 711 */ 712 if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR) 713 return (0); 714 715 /* setup the print structure and kick off the main print routine */ 716 pa.pa_dtp = dtp; 717 pa.pa_addr = addr; 718 pa.pa_ctfp = ctfp; 719 pa.pa_nest = 0; 720 pa.pa_depth = 0; 721 pa.pa_file = fp; 722 (void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa); 723 724 dt_print_trailing_braces(&pa, 0); 725 726 return (len); 727 } 728