27 * Copyright (c) 2012 by Delphix. All rights reserved.
28 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
29 */
30
31 #include <mdb/mdb_modapi.h>
32 #include <mdb/mdb_target.h>
33 #include <mdb/mdb_argvec.h>
34 #include <mdb/mdb_string.h>
35 #include <mdb/mdb_stdlib.h>
36 #include <mdb/mdb_err.h>
37 #include <mdb/mdb_debug.h>
38 #include <mdb/mdb_fmt.h>
39 #include <mdb/mdb_ctf.h>
40 #include <mdb/mdb_ctf_impl.h>
41 #include <mdb/mdb.h>
42 #include <mdb/mdb_tab.h>
43
44 #include <sys/isa_defs.h>
45 #include <sys/param.h>
46 #include <sys/sysmacros.h>
47 #include <strings.h>
48 #include <libctf.h>
49 #include <ctype.h>
50
51 typedef struct holeinfo {
52 ulong_t hi_offset; /* expected offset */
53 uchar_t hi_isunion; /* represents a union */
54 } holeinfo_t;
55
56 typedef struct printarg {
57 mdb_tgt_t *pa_tgt; /* current target */
58 mdb_tgt_t *pa_realtgt; /* real target (for -i) */
59 mdb_tgt_t *pa_immtgt; /* immediate target (for -i) */
60 mdb_tgt_as_t pa_as; /* address space to use for i/o */
61 mdb_tgt_addr_t pa_addr; /* base address for i/o */
62 ulong_t pa_armemlim; /* limit on array elements to print */
63 ulong_t pa_arstrlim; /* limit on array chars to print */
64 const char *pa_delim; /* element delimiter string */
65 const char *pa_prefix; /* element prefix string */
66 const char *pa_suffix; /* element suffix string */
1670 */
1671 static int
1672 pipe_print(mdb_ctf_id_t id, ulong_t off, void *data)
1673 {
1674 printarg_t *pap = data;
1675 ssize_t size;
1676 static const char *const fsp[] = { "%#r", "%#r", "%#r", "%#llr" };
1677 uintptr_t value;
1678 uintptr_t addr = pap->pa_addr + off / NBBY;
1679 mdb_ctf_id_t base;
1680 ctf_encoding_t e;
1681
1682 union {
1683 uint64_t i8;
1684 uint32_t i4;
1685 uint16_t i2;
1686 uint8_t i1;
1687 } u;
1688
1689 if (mdb_ctf_type_resolve(id, &base) == -1) {
1690 mdb_warn("could not resolve type\n");
1691 return (-1);
1692 }
1693
1694 /*
1695 * If the user gives -a, then always print out the address of the
1696 * member.
1697 */
1698 if ((pap->pa_flags & PA_SHOWADDR)) {
1699 mdb_printf("%#lr\n", addr);
1700 return (0);
1701 }
1702
1703 again:
1704 switch (mdb_ctf_type_kind(base)) {
1705 case CTF_K_POINTER:
1706 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
1707 &value, sizeof (value), addr) != sizeof (value)) {
1708 mdb_warn("failed to read pointer at %p", addr);
1709 return (-1);
1710 }
1986 * name is at least one character long.
1987 */
1988 for (end = start + 1; isalnum(*end) || *end == '_'; end++)
1989 continue;
1990
1991 (void) mdb_snprintf(member, end - start + 1, "%s", start);
1992
1993 if (mdb_ctf_member_info(rid, member, &off, &id) != 0) {
1994 mdb_warn("failed to find member %s of %s", member,
1995 mdb_ctf_type_name(id, buf, sizeof (buf)));
1996 return (-1);
1997 }
1998 (void) mdb_ctf_type_resolve(id, &rid);
1999
2000 pap->pa_addr += off / NBBY;
2001
2002 start = end;
2003 delim = parse_delimiter(&start);
2004 }
2005
2006
2007 *idp = id;
2008 *offp = off;
2009
2010 return (0);
2011 }
2012
2013 int
2014 cmd_print_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
2015 const mdb_arg_t *argv)
2016 {
2017 char tn[MDB_SYM_NAMLEN];
2018 char member[64];
2019 int i, dummy, delim, kind;
2020 int ret = 0;
2021 mdb_ctf_id_t id, rid;
2022 mdb_ctf_arinfo_t ar;
2023 char *start, *end;
2024 ulong_t dul;
2025
2026 /*
2445 "-c limit limit the length of character arrays\n"
2446 "-d output values in decimal\n"
2447 "-h print holes in structures\n"
2448 "-i interpret address as data of the given type\n"
2449 "-L unlimit the length of standard arrays\n"
2450 "-l limit limit the length of standard arrays\n"
2451 "-n don't print pointers as symbol offsets\n"
2452 "-p interpret address as a physical memory address\n"
2453 "-s depth limit the recursion depth\n"
2454 "-T show type and <<base type>> of object\n"
2455 "-t show type of object\n"
2456 "-x output values in hexadecimal\n"
2457 "\n"
2458 "type may be omitted if the C type of addr can be inferred.\n"
2459 "\n"
2460 "Members may be specified with standard C syntax using the\n"
2461 "array indexing operator \"[index]\", structure member\n"
2462 "operator \".\", or structure pointer operator \"->\".\n"
2463 "\n"
2464 "Offsets must use the $[ expression ] syntax\n");
2465 }
|
27 * Copyright (c) 2012 by Delphix. All rights reserved.
28 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
29 */
30
31 #include <mdb/mdb_modapi.h>
32 #include <mdb/mdb_target.h>
33 #include <mdb/mdb_argvec.h>
34 #include <mdb/mdb_string.h>
35 #include <mdb/mdb_stdlib.h>
36 #include <mdb/mdb_err.h>
37 #include <mdb/mdb_debug.h>
38 #include <mdb/mdb_fmt.h>
39 #include <mdb/mdb_ctf.h>
40 #include <mdb/mdb_ctf_impl.h>
41 #include <mdb/mdb.h>
42 #include <mdb/mdb_tab.h>
43
44 #include <sys/isa_defs.h>
45 #include <sys/param.h>
46 #include <sys/sysmacros.h>
47 #include <netinet/in.h>
48 #include <strings.h>
49 #include <libctf.h>
50 #include <ctype.h>
51
52 typedef struct holeinfo {
53 ulong_t hi_offset; /* expected offset */
54 uchar_t hi_isunion; /* represents a union */
55 } holeinfo_t;
56
57 typedef struct printarg {
58 mdb_tgt_t *pa_tgt; /* current target */
59 mdb_tgt_t *pa_realtgt; /* real target (for -i) */
60 mdb_tgt_t *pa_immtgt; /* immediate target (for -i) */
61 mdb_tgt_as_t pa_as; /* address space to use for i/o */
62 mdb_tgt_addr_t pa_addr; /* base address for i/o */
63 ulong_t pa_armemlim; /* limit on array elements to print */
64 ulong_t pa_arstrlim; /* limit on array chars to print */
65 const char *pa_delim; /* element delimiter string */
66 const char *pa_prefix; /* element prefix string */
67 const char *pa_suffix; /* element suffix string */
1671 */
1672 static int
1673 pipe_print(mdb_ctf_id_t id, ulong_t off, void *data)
1674 {
1675 printarg_t *pap = data;
1676 ssize_t size;
1677 static const char *const fsp[] = { "%#r", "%#r", "%#r", "%#llr" };
1678 uintptr_t value;
1679 uintptr_t addr = pap->pa_addr + off / NBBY;
1680 mdb_ctf_id_t base;
1681 ctf_encoding_t e;
1682
1683 union {
1684 uint64_t i8;
1685 uint32_t i4;
1686 uint16_t i2;
1687 uint8_t i1;
1688 } u;
1689
1690 if (mdb_ctf_type_resolve(id, &base) == -1) {
1691 mdb_warn("could not resolve type");
1692 return (-1);
1693 }
1694
1695 /*
1696 * If the user gives -a, then always print out the address of the
1697 * member.
1698 */
1699 if ((pap->pa_flags & PA_SHOWADDR)) {
1700 mdb_printf("%#lr\n", addr);
1701 return (0);
1702 }
1703
1704 again:
1705 switch (mdb_ctf_type_kind(base)) {
1706 case CTF_K_POINTER:
1707 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
1708 &value, sizeof (value), addr) != sizeof (value)) {
1709 mdb_warn("failed to read pointer at %p", addr);
1710 return (-1);
1711 }
1987 * name is at least one character long.
1988 */
1989 for (end = start + 1; isalnum(*end) || *end == '_'; end++)
1990 continue;
1991
1992 (void) mdb_snprintf(member, end - start + 1, "%s", start);
1993
1994 if (mdb_ctf_member_info(rid, member, &off, &id) != 0) {
1995 mdb_warn("failed to find member %s of %s", member,
1996 mdb_ctf_type_name(id, buf, sizeof (buf)));
1997 return (-1);
1998 }
1999 (void) mdb_ctf_type_resolve(id, &rid);
2000
2001 pap->pa_addr += off / NBBY;
2002
2003 start = end;
2004 delim = parse_delimiter(&start);
2005 }
2006
2007 *idp = id;
2008 *offp = off;
2009
2010 return (0);
2011 }
2012
2013 int
2014 cmd_print_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
2015 const mdb_arg_t *argv)
2016 {
2017 char tn[MDB_SYM_NAMLEN];
2018 char member[64];
2019 int i, dummy, delim, kind;
2020 int ret = 0;
2021 mdb_ctf_id_t id, rid;
2022 mdb_ctf_arinfo_t ar;
2023 char *start, *end;
2024 ulong_t dul;
2025
2026 /*
2445 "-c limit limit the length of character arrays\n"
2446 "-d output values in decimal\n"
2447 "-h print holes in structures\n"
2448 "-i interpret address as data of the given type\n"
2449 "-L unlimit the length of standard arrays\n"
2450 "-l limit limit the length of standard arrays\n"
2451 "-n don't print pointers as symbol offsets\n"
2452 "-p interpret address as a physical memory address\n"
2453 "-s depth limit the recursion depth\n"
2454 "-T show type and <<base type>> of object\n"
2455 "-t show type of object\n"
2456 "-x output values in hexadecimal\n"
2457 "\n"
2458 "type may be omitted if the C type of addr can be inferred.\n"
2459 "\n"
2460 "Members may be specified with standard C syntax using the\n"
2461 "array indexing operator \"[index]\", structure member\n"
2462 "operator \".\", or structure pointer operator \"->\".\n"
2463 "\n"
2464 "Offsets must use the $[ expression ] syntax\n");
2465 }
2466
2467 static int
2468 printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt,
2469 boolean_t sign)
2470 {
2471 ssize_t size;
2472 mdb_ctf_id_t base;
2473 ctf_encoding_t e;
2474
2475 union {
2476 uint64_t ui8;
2477 uint32_t ui4;
2478 uint16_t ui2;
2479 uint8_t ui1;
2480 int64_t i8;
2481 int32_t i4;
2482 int16_t i2;
2483 int8_t i1;
2484 } u;
2485
2486 if (mdb_ctf_type_resolve(id, &base) == -1) {
2487 mdb_warn("could not resolve type");
2488 return (DCMD_ABORT);
2489 }
2490
2491 if (mdb_ctf_type_kind(base) != CTF_K_INTEGER) {
2492 mdb_warn("expected integer type\n");
2493 return (DCMD_ABORT);
2494 }
2495
2496 if (mdb_ctf_type_encoding(base, &e) != 0) {
2497 mdb_warn("could not get type encoding");
2498 return (DCMD_ABORT);
2499 }
2500
2501 if (sign)
2502 sign = e.cte_format & CTF_INT_SIGNED;
2503
2504 size = e.cte_bits / NBBY;
2505
2506 /*
2507 * Check to see if our life has been complicated by the presence of
2508 * a bitfield. If it has, we will print it using logic that is only
2509 * slightly different than that found in print_bitfield(), above. (In
2510 * particular, see the comments there for an explanation of the
2511 * endianness differences in this code.)
2512 */
2513 if (size > 8 || (e.cte_bits % NBBY) != 0 ||
2514 (size & (size - 1)) != 0) {
2515 uint64_t mask = (1ULL << e.cte_bits) - 1;
2516 uint64_t value = 0;
2517 uint8_t *buf = (uint8_t *)&value;
2518 uint8_t shift;
2519
2520 /*
2521 * Round our size up one byte.
2522 */
2523 size = (e.cte_bits + (NBBY - 1)) / NBBY;
2524
2525 if (e.cte_bits > sizeof (value) * NBBY - 1) {
2526 mdb_printf("invalid bitfield size %u", e.cte_bits);
2527 return (DCMD_ABORT);
2528 }
2529
2530 #ifdef _BIG_ENDIAN
2531 buf += sizeof (value) - size;
2532 off += e.cte_bits;
2533 #endif
2534
2535 if (mdb_vread(buf, size, addr) == -1) {
2536 mdb_warn("failed to read %lu bytes at %p", size, addr);
2537 return (DCMD_ERR);
2538 }
2539
2540 shift = off % NBBY;
2541 #ifdef _BIG_ENDIAN
2542 shift = NBBY - shift;
2543 #endif
2544
2545 /*
2546 * If we have a bit offset within the byte, shift it down.
2547 */
2548 if (off % NBBY != 0)
2549 value >>= shift;
2550 value &= mask;
2551
2552 if (sign) {
2553 int sshift = sizeof (value) * NBBY - e.cte_bits;
2554 value = ((int64_t)value << sshift) >> sshift;
2555 }
2556
2557 mdb_printf(fmt, value);
2558 return (0);
2559 }
2560
2561 if (mdb_vread(&u.i8, size, addr) == -1) {
2562 mdb_warn("failed to read %lu bytes at %p", (ulong_t)size, addr);
2563 return (DCMD_ERR);
2564 }
2565
2566 switch (size) {
2567 case sizeof (uint8_t):
2568 mdb_printf(fmt, (uint64_t)(sign ? u.i1 : u.ui1));
2569 break;
2570 case sizeof (uint16_t):
2571 mdb_printf(fmt, (uint64_t)(sign ? u.i2 : u.ui2));
2572 break;
2573 case sizeof (uint32_t):
2574 mdb_printf(fmt, (uint64_t)(sign ? u.i4 : u.ui4));
2575 break;
2576 case sizeof (uint64_t):
2577 mdb_printf(fmt, (uint64_t)(sign ? u.i8 : u.ui8));
2578 break;
2579 }
2580
2581 return (0);
2582 }
2583
2584 static int
2585 printf_int(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2586 {
2587 return (printf_signed(id, addr, off, fmt, B_TRUE));
2588 }
2589
2590 static int
2591 printf_uint(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2592 {
2593 return (printf_signed(id, addr, off, fmt, B_FALSE));
2594 }
2595
2596 /*ARGSUSED*/
2597 static int
2598 printf_uint32(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2599 {
2600 mdb_ctf_id_t base;
2601 ctf_encoding_t e;
2602 uint32_t value;
2603
2604 if (mdb_ctf_type_resolve(id, &base) == -1) {
2605 mdb_warn("could not resolve type\n");
2606 return (DCMD_ABORT);
2607 }
2608
2609 if (mdb_ctf_type_kind(base) != CTF_K_INTEGER ||
2610 mdb_ctf_type_encoding(base, &e) != 0 ||
2611 e.cte_bits / NBBY != sizeof (value)) {
2612 mdb_warn("expected 32-bit integer type\n");
2613 return (DCMD_ABORT);
2614 }
2615
2616 if (mdb_vread(&value, sizeof (value), addr) == -1) {
2617 mdb_warn("failed to read 32-bit value at %p", addr);
2618 return (DCMD_ERR);
2619 }
2620
2621 mdb_printf(fmt, value);
2622
2623 return (0);
2624 }
2625
2626 /*ARGSUSED*/
2627 static int
2628 printf_ptr(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2629 {
2630 uintptr_t value;
2631 mdb_ctf_id_t base;
2632
2633 if (mdb_ctf_type_resolve(id, &base) == -1) {
2634 mdb_warn("could not resolve type\n");
2635 return (DCMD_ABORT);
2636 }
2637
2638 if (mdb_ctf_type_kind(base) != CTF_K_POINTER) {
2639 mdb_warn("expected pointer type\n");
2640 return (DCMD_ABORT);
2641 }
2642
2643 if (mdb_vread(&value, sizeof (value), addr) == -1) {
2644 mdb_warn("failed to read pointer at %llx", addr);
2645 return (DCMD_ERR);
2646 }
2647
2648 mdb_printf(fmt, value);
2649
2650 return (0);
2651 }
2652
2653 /*ARGSUSED*/
2654 static int
2655 printf_string(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2656 {
2657 mdb_ctf_id_t base;
2658 mdb_ctf_arinfo_t r;
2659 char buf[1024];
2660 ssize_t size;
2661
2662 if (mdb_ctf_type_resolve(id, &base) == -1) {
2663 mdb_warn("could not resolve type");
2664 return (DCMD_ABORT);
2665 }
2666
2667 if (mdb_ctf_type_kind(base) == CTF_K_POINTER) {
2668 uintptr_t value;
2669
2670 if (mdb_vread(&value, sizeof (value), addr) == -1) {
2671 mdb_warn("failed to read pointer at %llx", addr);
2672 return (DCMD_ERR);
2673 }
2674
2675 if (mdb_readstr(buf, sizeof (buf) - 1, value) < 0) {
2676 mdb_warn("failed to read string at %llx", value);
2677 return (DCMD_ERR);
2678 }
2679
2680 mdb_printf(fmt, buf);
2681 return (0);
2682 }
2683
2684 if (mdb_ctf_type_kind(base) != CTF_K_ARRAY) {
2685 mdb_warn("exepected pointer or array type\n");
2686 return (DCMD_ABORT);
2687 }
2688
2689 if (mdb_ctf_array_info(base, &r) == -1 ||
2690 mdb_ctf_type_resolve(r.mta_contents, &base) == -1 ||
2691 (size = mdb_ctf_type_size(base)) == -1) {
2692 mdb_warn("can't determine array type");
2693 return (DCMD_ABORT);
2694 }
2695
2696 if (size != 1) {
2697 mdb_warn("string format specifier requires "
2698 "an array of characters\n");
2699 return (DCMD_ABORT);
2700 }
2701
2702 bzero(buf, sizeof (buf));
2703
2704 if (mdb_vread(buf, MIN(r.mta_nelems, sizeof (buf) - 1), addr) == -1) {
2705 mdb_warn("failed to read array at %p", addr);
2706 return (DCMD_ERR);
2707 }
2708
2709 mdb_printf(fmt, buf);
2710
2711 return (0);
2712 }
2713
2714 /*ARGSUSED*/
2715 static int
2716 printf_ipv6(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2717 {
2718 mdb_ctf_id_t base;
2719 mdb_ctf_id_t ipv6_type, ipv6_base;
2720 in6_addr_t ipv6;
2721
2722 if (mdb_ctf_lookup_by_name("in6_addr_t", &ipv6_type) == -1) {
2723 mdb_warn("could not resolve in6_addr_t type\n");
2724 return (DCMD_ABORT);
2725 }
2726
2727 if (mdb_ctf_type_resolve(id, &base) == -1) {
2728 mdb_warn("could not resolve type\n");
2729 return (DCMD_ABORT);
2730 }
2731
2732 if (mdb_ctf_type_resolve(ipv6_type, &ipv6_base) == -1) {
2733 mdb_warn("could not resolve in6_addr_t type\n");
2734 return (DCMD_ABORT);
2735 }
2736
2737 if (mdb_ctf_type_cmp(base, ipv6_base) != 0) {
2738 mdb_warn("requires argument of type in6_addr_t\n");
2739 return (DCMD_ABORT);
2740 }
2741
2742 if (mdb_vread(&ipv6, sizeof (ipv6), addr) == -1) {
2743 mdb_warn("couldn't read in6_addr_t at %p", addr);
2744 return (DCMD_ERR);
2745 }
2746
2747 mdb_printf(fmt, &ipv6);
2748
2749 return (0);
2750 }
2751
2752 /*
2753 * To validate the format string specified to ::printf, we run the format
2754 * string through a very simple state machine that restricts us to a subset
2755 * of mdb_printf() functionality.
2756 */
2757 enum {
2758 PRINTF_NOFMT = 1, /* no current format specifier */
2759 PRINTF_PERC, /* processed '%' */
2760 PRINTF_FMT, /* processing format specifier */
2761 PRINTF_LEFT, /* processed '-', expecting width */
2762 PRINTF_WIDTH, /* processing width */
2763 PRINTF_QUES /* processed '?', expecting format */
2764 };
2765
2766 int
2767 cmd_printf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2768 {
2769 char type[MDB_SYM_NAMLEN];
2770 int i, nfmts = 0, ret;
2771 mdb_ctf_id_t id;
2772 const char *fmt, *member;
2773 char **fmts, *last, *dest, f;
2774 int (**funcs)(mdb_ctf_id_t, uintptr_t, ulong_t, char *);
2775 int state = PRINTF_NOFMT;
2776 printarg_t pa;
2777
2778 if (!(flags & DCMD_ADDRSPEC))
2779 return (DCMD_USAGE);
2780
2781 bzero(&pa, sizeof (pa));
2782 pa.pa_as = MDB_TGT_AS_VIRT;
2783 pa.pa_realtgt = pa.pa_tgt = mdb.m_target;
2784
2785 if (argc == 0 || argv[0].a_type != MDB_TYPE_STRING) {
2786 mdb_warn("expected a format string\n");
2787 return (DCMD_USAGE);
2788 }
2789
2790 /*
2791 * Our first argument is a format string; rip it apart and run it
2792 * through our state machine to validate that our input is within the
2793 * subset of mdb_printf() format strings that we allow.
2794 */
2795 fmt = argv[0].a_un.a_str;
2796 /*
2797 * 'dest' must be large enough to hold a copy of the format string,
2798 * plus a NUL and up to 2 additional characters for each conversion
2799 * in the format string. This gives us a bloat factor of 5/2 ~= 3.
2800 * e.g. "%d" (strlen of 2) --> "%lld\0" (need 5 bytes)
2801 */
2802 dest = mdb_zalloc(strlen(fmt) * 3, UM_SLEEP | UM_GC);
2803 fmts = mdb_zalloc(strlen(fmt) * sizeof (char *), UM_SLEEP | UM_GC);
2804 funcs = mdb_zalloc(strlen(fmt) * sizeof (void *), UM_SLEEP | UM_GC);
2805 last = dest;
2806
2807 for (i = 0; fmt[i] != '\0'; i++) {
2808 *dest++ = f = fmt[i];
2809
2810 switch (state) {
2811 case PRINTF_NOFMT:
2812 state = f == '%' ? PRINTF_PERC : PRINTF_NOFMT;
2813 break;
2814
2815 case PRINTF_PERC:
2816 state = f == '-' ? PRINTF_LEFT :
2817 f >= '0' && f <= '9' ? PRINTF_WIDTH :
2818 f == '?' ? PRINTF_QUES :
2819 f == '%' ? PRINTF_NOFMT : PRINTF_FMT;
2820 break;
2821
2822 case PRINTF_LEFT:
2823 state = f >= '0' && f <= '9' ? PRINTF_WIDTH :
2824 f == '?' ? PRINTF_QUES : PRINTF_FMT;
2825 break;
2826
2827 case PRINTF_WIDTH:
2828 state = f >= '0' && f <= '9' ? PRINTF_WIDTH :
2829 PRINTF_FMT;
2830 break;
2831
2832 case PRINTF_QUES:
2833 state = PRINTF_FMT;
2834 break;
2835 }
2836
2837 if (state != PRINTF_FMT)
2838 continue;
2839
2840 dest--;
2841
2842 /*
2843 * Now check that we have one of our valid format characters.
2844 */
2845 switch (f) {
2846 case 'a':
2847 case 'A':
2848 case 'p':
2849 funcs[nfmts] = printf_ptr;
2850 break;
2851
2852 case 'd':
2853 case 'q':
2854 case 'R':
2855 funcs[nfmts] = printf_int;
2856 *dest++ = 'l';
2857 *dest++ = 'l';
2858 break;
2859
2860 case 'I':
2861 funcs[nfmts] = printf_uint32;
2862 break;
2863
2864 case 'N':
2865 funcs[nfmts] = printf_ipv6;
2866 break;
2867
2868 case 'o':
2869 case 'r':
2870 case 'u':
2871 case 'x':
2872 case 'X':
2873 funcs[nfmts] = printf_uint;
2874 *dest++ = 'l';
2875 *dest++ = 'l';
2876 break;
2877
2878 case 's':
2879 funcs[nfmts] = printf_string;
2880 break;
2881
2882 case 'Y':
2883 funcs[nfmts] = sizeof (time_t) == sizeof (int) ?
2884 printf_uint32 : printf_uint;
2885 break;
2886
2887 default:
2888 mdb_warn("illegal format string at or near "
2889 "'%c' (position %d)\n", f, i + 1);
2890 return (DCMD_ABORT);
2891 }
2892
2893 *dest++ = f;
2894 *dest++ = '\0';
2895 fmts[nfmts++] = last;
2896 last = dest;
2897 state = PRINTF_NOFMT;
2898 }
2899
2900 argc--;
2901 argv++;
2902
2903 /*
2904 * Now we expect a type name.
2905 */
2906 if ((ret = args_to_typename(&argc, &argv, type, sizeof (type))) != 0)
2907 return (ret);
2908
2909 argv++;
2910 argc--;
2911
2912 if (mdb_ctf_lookup_by_name(type, &id) != 0) {
2913 mdb_warn("failed to look up type %s", type);
2914 return (DCMD_ABORT);
2915 }
2916
2917 if (argc == 0) {
2918 mdb_warn("at least one member must be specified\n");
2919 return (DCMD_USAGE);
2920 }
2921
2922 if (argc != nfmts) {
2923 mdb_warn("%s format specifiers (found %d, expected %d)\n",
2924 argc > nfmts ? "missing" : "extra", nfmts, argc);
2925 return (DCMD_ABORT);
2926 }
2927
2928 for (i = 0; i < argc; i++) {
2929 mdb_ctf_id_t mid;
2930 ulong_t off;
2931 int ignored;
2932
2933 if (argv[i].a_type != MDB_TYPE_STRING) {
2934 mdb_warn("expected only type member arguments\n");
2935 return (DCMD_ABORT);
2936 }
2937
2938 if (strcmp((member = argv[i].a_un.a_str), ".") == 0) {
2939 /*
2940 * We allow "." to be specified to denote the current
2941 * value of dot.
2942 */
2943 if (funcs[i] != printf_ptr && funcs[i] != printf_uint &&
2944 funcs[i] != printf_int) {
2945 mdb_warn("expected integer or pointer format "
2946 "specifier for '.'\n");
2947 return (DCMD_ABORT);
2948 }
2949
2950 mdb_printf(fmts[i], mdb_get_dot());
2951 continue;
2952 }
2953
2954 pa.pa_addr = addr;
2955
2956 if (parse_member(&pa, member, id, &mid, &off, &ignored) != 0)
2957 return (DCMD_ABORT);
2958
2959 if ((ret = funcs[i](mid, pa.pa_addr, off, fmts[i])) != 0) {
2960 mdb_warn("failed to print member '%s'\n", member);
2961 return (ret);
2962 }
2963 }
2964
2965 mdb_printf("%s", last);
2966
2967 return (DCMD_OK);
2968 }
2969
2970 static char _mdb_printf_help[] =
2971 "The format string argument is a printf(3C)-like format string that is a\n"
2972 "subset of the format strings supported by mdb_printf(). The type argument\n"
2973 "is the name of a type to be used to interpret the memory referenced by dot.\n"
2974 "The member should either be a field in the specified structure, or the\n"
2975 "special member '.', denoting the value of dot (and treated as a pointer).\n"
2976 "The number of members must match the number of format specifiers in the\n"
2977 "format string.\n"
2978 "\n"
2979 "The following format specifiers are recognized by ::printf:\n"
2980 "\n"
2981 " %% Prints the '%' symbol.\n"
2982 " %a Prints the member in symbolic form.\n"
2983 " %d Prints the member as a decimal integer. If the member is a signed\n"
2984 " integer type, the output will be signed.\n"
2985 " %I Prints the member a IPv4 address (must be a 32-bit integer type).\n"
2986 " %N Prints the member an IPv6 address (must be of type in6_addr_t).\n"
2987 " %o Prints the member as an unsigned octal integer.\n"
2988 " %p Prints the member as a pointer, in hexadecimal.\n"
2989 " %q Prints the member in signed octal. Honk if you ever use this!\n"
2990 " %r Prints the member as an unsigned value in the current output radix.\n"
2991 " %R Prints the member as a signed value in the current output radix.\n"
2992 " %s Prints the member as a string (requires a pointer or an array of\n"
2993 " characters).\n"
2994 " %u Prints the member as an unsigned decimal integer.\n"
2995 " %x Prints the member in hexadecimal.\n"
2996 " %X Prints the member in hexadecimal, using the characters A-F as the\n"
2997 " digits for the values 10-15.\n"
2998 " %Y Prints the member as a time_t as the string "
2999 "'year month day HH:MM:SS'.\n"
3000 "\n"
3001 "The following field width specifiers are recognized by ::printf:\n"
3002 "\n"
3003 " %n Field width is set to the specified decimal value.\n"
3004 " %? Field width is set to the maximum width of a hexadecimal pointer\n"
3005 " value. This is 8 in an ILP32 environment, and 16 in an LP64\n"
3006 " environment.\n"
3007 "\n"
3008 "The following flag specifers are recognized by ::printf:\n"
3009 "\n"
3010 " %- Left-justify the output within the specified field width. If the\n"
3011 " width of the output is less than the specified field width, the\n"
3012 " output will be padded with blanks on the right-hand side. Without\n"
3013 " %-, values are right-justified by default.\n"
3014 "\n"
3015 " %0 Zero-fill the output field if the output is right-justified and the\n"
3016 " width of the output is less than the specified field width. Without\n"
3017 " %0, right-justified values are prepended with blanks in order to\n"
3018 " fill the field.\n"
3019 "\n"
3020 "Examples: \n"
3021 "\n"
3022 " ::walk proc | "
3023 "::printf \"%-6d %s\\n\" proc_t p_pidp->pid_id p_user.u_psargs\n"
3024 " ::walk thread | "
3025 "::printf \"%?p %3d %a\\n\" kthread_t . t_pri t_startpc\n"
3026 " ::walk zone | "
3027 "::printf \"%-40s %20s\\n\" zone_t zone_name zone_nodename\n"
3028 " ::walk ire | "
3029 "::printf \"%Y %I\\n\" ire_t ire_create_time ire_u.ire4_u.ire4_addr\n"
3030 "\n";
3031
3032 void
3033 printf_help(void)
3034 {
3035 mdb_printf("%s", _mdb_printf_help);
3036 }
|