17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5bf5197d8Sjwadams * Common Development and Distribution License (the "License"). 6bf5197d8Sjwadams * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22cce40297SJonathan Adams * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 263b6e0a59SMatt Amdur /* 27e9f82d69SAlex Reece * Copyright (c) 2012, 2014 by Delphix. All rights reserved. 286b98d994SRobert Mustacchi * Copyright 2015 Joyent, Inc. 2938ce19d2SJosef 'Jeff' Sipek * Copyright (c) 2014 Nexenta Systems, Inc. All rights reserved. 303b6e0a59SMatt Amdur */ 313b6e0a59SMatt Amdur 327c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 337c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h> 347c478bd9Sstevel@tonic-gate #include <mdb/mdb_argvec.h> 357c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h> 367c478bd9Sstevel@tonic-gate #include <mdb/mdb_stdlib.h> 377c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 387c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 397c478bd9Sstevel@tonic-gate #include <mdb/mdb_fmt.h> 407c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf.h> 417c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf_impl.h> 427c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 433b6e0a59SMatt Amdur #include <mdb/mdb_tab.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 467c478bd9Sstevel@tonic-gate #include <sys/param.h> 477c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 483ddcfaddSBryan Cantrill #include <netinet/in.h> 497c478bd9Sstevel@tonic-gate #include <strings.h> 507c478bd9Sstevel@tonic-gate #include <libctf.h> 517c478bd9Sstevel@tonic-gate #include <ctype.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate typedef struct holeinfo { 547c478bd9Sstevel@tonic-gate ulong_t hi_offset; /* expected offset */ 557c478bd9Sstevel@tonic-gate uchar_t hi_isunion; /* represents a union */ 567c478bd9Sstevel@tonic-gate } holeinfo_t; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate typedef struct printarg { 597c478bd9Sstevel@tonic-gate mdb_tgt_t *pa_tgt; /* current target */ 607c478bd9Sstevel@tonic-gate mdb_tgt_t *pa_realtgt; /* real target (for -i) */ 617c478bd9Sstevel@tonic-gate mdb_tgt_t *pa_immtgt; /* immediate target (for -i) */ 627c478bd9Sstevel@tonic-gate mdb_tgt_as_t pa_as; /* address space to use for i/o */ 637c478bd9Sstevel@tonic-gate mdb_tgt_addr_t pa_addr; /* base address for i/o */ 647c478bd9Sstevel@tonic-gate ulong_t pa_armemlim; /* limit on array elements to print */ 657c478bd9Sstevel@tonic-gate ulong_t pa_arstrlim; /* limit on array chars to print */ 667c478bd9Sstevel@tonic-gate const char *pa_delim; /* element delimiter string */ 677c478bd9Sstevel@tonic-gate const char *pa_prefix; /* element prefix string */ 687c478bd9Sstevel@tonic-gate const char *pa_suffix; /* element suffix string */ 697c478bd9Sstevel@tonic-gate holeinfo_t *pa_holes; /* hole detection information */ 707c478bd9Sstevel@tonic-gate int pa_nholes; /* size of holes array */ 717c478bd9Sstevel@tonic-gate int pa_flags; /* formatting flags (see below) */ 727c478bd9Sstevel@tonic-gate int pa_depth; /* previous depth */ 737c478bd9Sstevel@tonic-gate int pa_nest; /* array nesting depth */ 747c478bd9Sstevel@tonic-gate int pa_tab; /* tabstop width */ 75bf5197d8Sjwadams uint_t pa_maxdepth; /* Limit max depth */ 76838d7172SSebastien Roy uint_t pa_nooutdepth; /* don't print output past this depth */ 777c478bd9Sstevel@tonic-gate } printarg_t; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #define PA_SHOWTYPE 0x001 /* print type name */ 80cce40297SJonathan Adams #define PA_SHOWBASETYPE 0x002 /* print base type name */ 81cce40297SJonathan Adams #define PA_SHOWNAME 0x004 /* print member name */ 82cce40297SJonathan Adams #define PA_SHOWADDR 0x008 /* print address */ 83cce40297SJonathan Adams #define PA_SHOWVAL 0x010 /* print value */ 84cce40297SJonathan Adams #define PA_SHOWHOLES 0x020 /* print holes in structs */ 85cce40297SJonathan Adams #define PA_INTHEX 0x040 /* print integer values in hex */ 86cce40297SJonathan Adams #define PA_INTDEC 0x080 /* print integer values in decimal */ 87cce40297SJonathan Adams #define PA_NOSYMBOLIC 0x100 /* don't print ptrs as func+offset */ 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate #define IS_CHAR(e) \ 907c478bd9Sstevel@tonic-gate (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \ 917c478bd9Sstevel@tonic-gate (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY) 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #define COMPOSITE_MASK ((1 << CTF_K_STRUCT) | \ 947c478bd9Sstevel@tonic-gate (1 << CTF_K_UNION) | (1 << CTF_K_ARRAY)) 957c478bd9Sstevel@tonic-gate #define IS_COMPOSITE(k) (((1 << k) & COMPOSITE_MASK) != 0) 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate #define SOU_MASK ((1 << CTF_K_STRUCT) | (1 << CTF_K_UNION)) 987c478bd9Sstevel@tonic-gate #define IS_SOU(k) (((1 << k) & SOU_MASK) != 0) 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate #define MEMBER_DELIM_ERR -1 1017c478bd9Sstevel@tonic-gate #define MEMBER_DELIM_DONE 0 1027c478bd9Sstevel@tonic-gate #define MEMBER_DELIM_PTR 1 1037c478bd9Sstevel@tonic-gate #define MEMBER_DELIM_DOT 2 1047c478bd9Sstevel@tonic-gate #define MEMBER_DELIM_LBR 3 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate typedef int printarg_f(const char *, const char *, 1077c478bd9Sstevel@tonic-gate mdb_ctf_id_t, mdb_ctf_id_t, ulong_t, printarg_t *); 1087c478bd9Sstevel@tonic-gate 109cce40297SJonathan Adams static int elt_print(const char *, mdb_ctf_id_t, mdb_ctf_id_t, ulong_t, int, 110cce40297SJonathan Adams void *); 1117c478bd9Sstevel@tonic-gate static void print_close_sou(printarg_t *, int); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * Given an address, look up the symbol ID of the specified symbol in its 1157c478bd9Sstevel@tonic-gate * containing module. We only support lookups for exact matches. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate static const char * 1187c478bd9Sstevel@tonic-gate addr_to_sym(mdb_tgt_t *t, uintptr_t addr, char *name, size_t namelen, 1197c478bd9Sstevel@tonic-gate GElf_Sym *symp, mdb_syminfo_t *sip) 1207c478bd9Sstevel@tonic-gate { 1217c478bd9Sstevel@tonic-gate const mdb_map_t *mp; 1227c478bd9Sstevel@tonic-gate const char *p; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_addr(t, addr, MDB_TGT_SYM_EXACT, name, 1257c478bd9Sstevel@tonic-gate namelen, NULL, NULL) == -1) 1267c478bd9Sstevel@tonic-gate return (NULL); /* address does not exactly match a symbol */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate if ((p = strrsplit(name, '`')) != NULL) { 1297c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_name(t, name, p, symp, sip) == -1) 1307c478bd9Sstevel@tonic-gate return (NULL); 1317c478bd9Sstevel@tonic-gate return (p); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate if ((mp = mdb_tgt_addr_to_map(t, addr)) == NULL) 1357c478bd9Sstevel@tonic-gate return (NULL); /* address does not fall within a mapping */ 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_name(t, mp->map_name, name, symp, sip) == -1) 1387c478bd9Sstevel@tonic-gate return (NULL); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate return (name); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* 1447c478bd9Sstevel@tonic-gate * This lets dcmds be a little fancy with their processing of type arguments 1457c478bd9Sstevel@tonic-gate * while still treating them more or less as a single argument. 1467c478bd9Sstevel@tonic-gate * For example, if a command is invokes like this: 1477c478bd9Sstevel@tonic-gate * 1487c478bd9Sstevel@tonic-gate * ::<dcmd> proc_t ... 1497c478bd9Sstevel@tonic-gate * 1507c478bd9Sstevel@tonic-gate * this function will just copy "proc_t" into the provided buffer. If the 1517c478bd9Sstevel@tonic-gate * command is instead invoked like this: 1527c478bd9Sstevel@tonic-gate * 1537c478bd9Sstevel@tonic-gate * ::<dcmd> struct proc ... 1547c478bd9Sstevel@tonic-gate * 1557c478bd9Sstevel@tonic-gate * this function will place the string "struct proc" into the provided buffer 1567c478bd9Sstevel@tonic-gate * and increment the caller's argv and argc. This allows the caller to still 1577c478bd9Sstevel@tonic-gate * treat the type argument logically as it would an other atomic argument. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate int 1607c478bd9Sstevel@tonic-gate args_to_typename(int *argcp, const mdb_arg_t **argvp, char *buf, size_t len) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate int argc = *argcp; 1637c478bd9Sstevel@tonic-gate const mdb_arg_t *argv = *argvp; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (argc < 1 || argv->a_type != MDB_TYPE_STRING) 1667c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (strcmp(argv->a_un.a_str, "struct") == 0 || 1697c478bd9Sstevel@tonic-gate strcmp(argv->a_un.a_str, "enum") == 0 || 1707c478bd9Sstevel@tonic-gate strcmp(argv->a_un.a_str, "union") == 0) { 1717c478bd9Sstevel@tonic-gate if (argc <= 1) { 1727c478bd9Sstevel@tonic-gate mdb_warn("%s is not a valid type\n", argv->a_un.a_str); 1737c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if (argv[1].a_type != MDB_TYPE_STRING) 1777c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate (void) mdb_snprintf(buf, len, "%s %s", 1807c478bd9Sstevel@tonic-gate argv[0].a_un.a_str, argv[1].a_un.a_str); 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate *argcp = argc - 1; 1837c478bd9Sstevel@tonic-gate *argvp = argv + 1; 1847c478bd9Sstevel@tonic-gate } else { 1857c478bd9Sstevel@tonic-gate (void) mdb_snprintf(buf, len, "%s", argv[0].a_un.a_str); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate return (0); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1927c478bd9Sstevel@tonic-gate int 1937c478bd9Sstevel@tonic-gate cmd_sizeof(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate mdb_ctf_id_t id; 1967c478bd9Sstevel@tonic-gate char tn[MDB_SYM_NAMLEN]; 1977c478bd9Sstevel@tonic-gate int ret; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 2007c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if ((ret = args_to_typename(&argc, &argv, tn, sizeof (tn))) != 0) 2037c478bd9Sstevel@tonic-gate return (ret); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if (argc != 1) 2067c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (mdb_ctf_lookup_by_name(tn, &id) != 0) { 2097c478bd9Sstevel@tonic-gate mdb_warn("failed to look up type %s", tn); 2107c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate if (flags & DCMD_PIPE_OUT) 2147c478bd9Sstevel@tonic-gate mdb_printf("%#lr\n", mdb_ctf_type_size(id)); 2157c478bd9Sstevel@tonic-gate else 2167c478bd9Sstevel@tonic-gate mdb_printf("sizeof (%s) = %#lr\n", tn, mdb_ctf_type_size(id)); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate return (DCMD_OK); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2213b6e0a59SMatt Amdur int 2223b6e0a59SMatt Amdur cmd_sizeof_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc, 2233b6e0a59SMatt Amdur const mdb_arg_t *argv) 2243b6e0a59SMatt Amdur { 2253b6e0a59SMatt Amdur char tn[MDB_SYM_NAMLEN]; 2263b6e0a59SMatt Amdur int ret; 2273b6e0a59SMatt Amdur 2283b6e0a59SMatt Amdur if (argc == 0 && !(flags & DCMD_TAB_SPACE)) 2293b6e0a59SMatt Amdur return (0); 2303b6e0a59SMatt Amdur 2313b6e0a59SMatt Amdur if (argc == 0 && (flags & DCMD_TAB_SPACE)) 2323b6e0a59SMatt Amdur return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_NOPOINT)); 2333b6e0a59SMatt Amdur 2343b6e0a59SMatt Amdur if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0) 2353b6e0a59SMatt Amdur return (ret); 2363b6e0a59SMatt Amdur 2373b6e0a59SMatt Amdur if (argc == 1) 2383b6e0a59SMatt Amdur return (mdb_tab_complete_type(mcp, tn, MDB_TABC_NOPOINT)); 2393b6e0a59SMatt Amdur 2403b6e0a59SMatt Amdur return (0); 2413b6e0a59SMatt Amdur } 2423b6e0a59SMatt Amdur 2437c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2447c478bd9Sstevel@tonic-gate int 2457c478bd9Sstevel@tonic-gate cmd_offsetof(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate const char *member; 2487c478bd9Sstevel@tonic-gate mdb_ctf_id_t id; 2497c478bd9Sstevel@tonic-gate ulong_t off; 2507c478bd9Sstevel@tonic-gate char tn[MDB_SYM_NAMLEN]; 251e0ad97e3SJonathan Adams ssize_t sz; 2527c478bd9Sstevel@tonic-gate int ret; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 2557c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate if ((ret = args_to_typename(&argc, &argv, tn, sizeof (tn))) != 0) 2587c478bd9Sstevel@tonic-gate return (ret); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate if (argc != 2 || argv[1].a_type != MDB_TYPE_STRING) 2617c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate if (mdb_ctf_lookup_by_name(tn, &id) != 0) { 2647c478bd9Sstevel@tonic-gate mdb_warn("failed to look up type %s", tn); 2657c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate member = argv[1].a_un.a_str; 2697c478bd9Sstevel@tonic-gate 270e0ad97e3SJonathan Adams if (mdb_ctf_member_info(id, member, &off, &id) != 0) { 2717c478bd9Sstevel@tonic-gate mdb_warn("failed to find member %s of type %s", member, tn); 2727c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 275e0ad97e3SJonathan Adams if (flags & DCMD_PIPE_OUT) { 276e0ad97e3SJonathan Adams if (off % NBBY != 0) { 277e0ad97e3SJonathan Adams mdb_warn("member %s of type %s is not byte-aligned\n", 278e0ad97e3SJonathan Adams member, tn); 279e0ad97e3SJonathan Adams return (DCMD_ERR); 280e0ad97e3SJonathan Adams } 281e0ad97e3SJonathan Adams mdb_printf("%#lr", off / NBBY); 282e0ad97e3SJonathan Adams return (DCMD_OK); 283e0ad97e3SJonathan Adams } 284e0ad97e3SJonathan Adams 285e0ad97e3SJonathan Adams mdb_printf("offsetof (%s, %s) = %#lr", 286e0ad97e3SJonathan Adams tn, member, off / NBBY); 287e0ad97e3SJonathan Adams if (off % NBBY != 0) 288e0ad97e3SJonathan Adams mdb_printf(".%lr", off % NBBY); 289e0ad97e3SJonathan Adams 290e0ad97e3SJonathan Adams if ((sz = mdb_ctf_type_size(id)) > 0) 291e0ad97e3SJonathan Adams mdb_printf(", sizeof (...->%s) = %#lr", member, sz); 292e0ad97e3SJonathan Adams 293e0ad97e3SJonathan Adams mdb_printf("\n"); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate return (DCMD_OK); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 298e0ad97e3SJonathan Adams /*ARGSUSED*/ 299e0ad97e3SJonathan Adams static int 300e0ad97e3SJonathan Adams enum_prefix_scan_cb(const char *name, int value, void *arg) 301e0ad97e3SJonathan Adams { 302e0ad97e3SJonathan Adams char *str = arg; 303e0ad97e3SJonathan Adams 304e0ad97e3SJonathan Adams /* 305e0ad97e3SJonathan Adams * This function is called with every name in the enum. We make 306e0ad97e3SJonathan Adams * "arg" be the common prefix, if any. 307e0ad97e3SJonathan Adams */ 308e0ad97e3SJonathan Adams if (str[0] == 0) { 309e0ad97e3SJonathan Adams if (strlcpy(arg, name, MDB_SYM_NAMLEN) >= MDB_SYM_NAMLEN) 310e0ad97e3SJonathan Adams return (1); 311e0ad97e3SJonathan Adams return (0); 312e0ad97e3SJonathan Adams } 313e0ad97e3SJonathan Adams 314e0ad97e3SJonathan Adams while (*name == *str) { 315e0ad97e3SJonathan Adams if (*str == 0) { 316e0ad97e3SJonathan Adams if (str != arg) { 317e0ad97e3SJonathan Adams str--; /* don't smother a name completely */ 318e0ad97e3SJonathan Adams } 319e0ad97e3SJonathan Adams break; 320e0ad97e3SJonathan Adams } 321e0ad97e3SJonathan Adams name++; 322e0ad97e3SJonathan Adams str++; 323e0ad97e3SJonathan Adams } 324e0ad97e3SJonathan Adams *str = 0; 325e0ad97e3SJonathan Adams 326e0ad97e3SJonathan Adams return (str == arg); /* only continue if prefix is non-empty */ 327e0ad97e3SJonathan Adams } 328e0ad97e3SJonathan Adams 329cce40297SJonathan Adams struct enum_p2_info { 330e0ad97e3SJonathan Adams intmax_t e_value; /* value we're processing */ 331e0ad97e3SJonathan Adams char *e_buf; /* buffer for holding names */ 332e0ad97e3SJonathan Adams size_t e_size; /* size of buffer */ 333e0ad97e3SJonathan Adams size_t e_prefix; /* length of initial prefix */ 334e0ad97e3SJonathan Adams uint_t e_allprefix; /* apply prefix to first guy, too */ 335e0ad97e3SJonathan Adams uint_t e_bits; /* bits seen */ 336e0ad97e3SJonathan Adams uint8_t e_found; /* have we seen anything? */ 337e0ad97e3SJonathan Adams uint8_t e_first; /* does buf contain the first one? */ 338e0ad97e3SJonathan Adams uint8_t e_zero; /* have we seen a zero value? */ 339cce40297SJonathan Adams }; 340cce40297SJonathan Adams 341cce40297SJonathan Adams static int 342cce40297SJonathan Adams enum_p2_cb(const char *name, int bit_arg, void *arg) 343cce40297SJonathan Adams { 344cce40297SJonathan Adams struct enum_p2_info *eiip = arg; 345e0ad97e3SJonathan Adams uintmax_t bit = bit_arg; 346cce40297SJonathan Adams 347cce40297SJonathan Adams if (bit != 0 && !ISP2(bit)) 348cce40297SJonathan Adams return (1); /* non-power-of-2; abort processing */ 349cce40297SJonathan Adams 350cce40297SJonathan Adams if ((bit == 0 && eiip->e_zero) || 351cce40297SJonathan Adams (bit != 0 && (eiip->e_bits & bit) != 0)) { 352cce40297SJonathan Adams return (0); /* already seen this value */ 353cce40297SJonathan Adams } 354cce40297SJonathan Adams 355cce40297SJonathan Adams if (bit == 0) 356cce40297SJonathan Adams eiip->e_zero = 1; 357cce40297SJonathan Adams else 358cce40297SJonathan Adams eiip->e_bits |= bit; 359cce40297SJonathan Adams 360cce40297SJonathan Adams if (eiip->e_buf != NULL && (eiip->e_value & bit) != 0) { 361e0ad97e3SJonathan Adams char *buf = eiip->e_buf; 362e0ad97e3SJonathan Adams size_t prefix = eiip->e_prefix; 363e0ad97e3SJonathan Adams 364e0ad97e3SJonathan Adams if (eiip->e_found) { 365e0ad97e3SJonathan Adams (void) strlcat(buf, "|", eiip->e_size); 366e0ad97e3SJonathan Adams 367e0ad97e3SJonathan Adams if (eiip->e_first && !eiip->e_allprefix && prefix > 0) { 368e0ad97e3SJonathan Adams char c1 = buf[prefix]; 369e0ad97e3SJonathan Adams char c2 = buf[prefix + 1]; 370e0ad97e3SJonathan Adams buf[prefix] = '{'; 371e0ad97e3SJonathan Adams buf[prefix + 1] = 0; 372e0ad97e3SJonathan Adams mdb_printf("%s", buf); 373e0ad97e3SJonathan Adams buf[prefix] = c1; 374e0ad97e3SJonathan Adams buf[prefix + 1] = c2; 375e0ad97e3SJonathan Adams mdb_printf("%s", buf + prefix); 376e0ad97e3SJonathan Adams } else { 377e0ad97e3SJonathan Adams mdb_printf("%s", buf); 378e0ad97e3SJonathan Adams } 379cce40297SJonathan Adams 380e0ad97e3SJonathan Adams } 381e0ad97e3SJonathan Adams /* skip the common prefix as necessary */ 382e0ad97e3SJonathan Adams if ((eiip->e_found || eiip->e_allprefix) && 383e0ad97e3SJonathan Adams strlen(name) > prefix) 384e0ad97e3SJonathan Adams name += prefix; 385cce40297SJonathan Adams 386e0ad97e3SJonathan Adams (void) strlcpy(eiip->e_buf, name, eiip->e_size); 387e0ad97e3SJonathan Adams eiip->e_first = !eiip->e_found; 388cce40297SJonathan Adams eiip->e_found = 1; 389cce40297SJonathan Adams } 390cce40297SJonathan Adams return (0); 391cce40297SJonathan Adams } 392cce40297SJonathan Adams 393cce40297SJonathan Adams static int 394e0ad97e3SJonathan Adams enum_is_p2(mdb_ctf_id_t id) 395cce40297SJonathan Adams { 396cce40297SJonathan Adams struct enum_p2_info eii; 397e0ad97e3SJonathan Adams bzero(&eii, sizeof (eii)); 398e0ad97e3SJonathan Adams 399e0ad97e3SJonathan Adams return (mdb_ctf_type_kind(id) == CTF_K_ENUM && 400e0ad97e3SJonathan Adams mdb_ctf_enum_iter(id, enum_p2_cb, &eii) == 0 && 401e0ad97e3SJonathan Adams eii.e_bits != 0); 402e0ad97e3SJonathan Adams } 403e0ad97e3SJonathan Adams 404e0ad97e3SJonathan Adams static int 405e0ad97e3SJonathan Adams enum_value_print_p2(mdb_ctf_id_t id, intmax_t value, uint_t allprefix) 406e0ad97e3SJonathan Adams { 407e0ad97e3SJonathan Adams struct enum_p2_info eii; 408e0ad97e3SJonathan Adams char prefix[MDB_SYM_NAMLEN + 2]; 409e0ad97e3SJonathan Adams intmax_t missed; 410cce40297SJonathan Adams 411cce40297SJonathan Adams bzero(&eii, sizeof (eii)); 412cce40297SJonathan Adams 413e0ad97e3SJonathan Adams eii.e_value = value; 414e0ad97e3SJonathan Adams eii.e_buf = prefix; 415e0ad97e3SJonathan Adams eii.e_size = sizeof (prefix); 416e0ad97e3SJonathan Adams eii.e_allprefix = allprefix; 417cce40297SJonathan Adams 418e0ad97e3SJonathan Adams prefix[0] = 0; 419e0ad97e3SJonathan Adams if (mdb_ctf_enum_iter(id, enum_prefix_scan_cb, prefix) == 0) 420e0ad97e3SJonathan Adams eii.e_prefix = strlen(prefix); 421cce40297SJonathan Adams 422e0ad97e3SJonathan Adams if (mdb_ctf_enum_iter(id, enum_p2_cb, &eii) != 0 || eii.e_bits == 0) 423cce40297SJonathan Adams return (-1); 424cce40297SJonathan Adams 425e0ad97e3SJonathan Adams missed = (value & ~(intmax_t)eii.e_bits); 426cce40297SJonathan Adams 427e0ad97e3SJonathan Adams if (eii.e_found) { 428e0ad97e3SJonathan Adams /* push out any final value, with a | if we missed anything */ 429e0ad97e3SJonathan Adams if (!eii.e_first) 430e0ad97e3SJonathan Adams (void) strlcat(prefix, "}", sizeof (prefix)); 431e0ad97e3SJonathan Adams if (missed != 0) 432e0ad97e3SJonathan Adams (void) strlcat(prefix, "|", sizeof (prefix)); 433cce40297SJonathan Adams 434e0ad97e3SJonathan Adams mdb_printf("%s", prefix); 435e0ad97e3SJonathan Adams } 436e0ad97e3SJonathan Adams 437e0ad97e3SJonathan Adams if (!eii.e_found || missed) { 438e0ad97e3SJonathan Adams mdb_printf("%#llx", missed); 439cce40297SJonathan Adams } 440cce40297SJonathan Adams 441cce40297SJonathan Adams return (0); 442cce40297SJonathan Adams } 443cce40297SJonathan Adams 4447c478bd9Sstevel@tonic-gate struct enum_cbinfo { 4457c478bd9Sstevel@tonic-gate uint_t e_flags; 4467c478bd9Sstevel@tonic-gate const char *e_string; /* NULL for value searches */ 447e0ad97e3SJonathan Adams size_t e_prefix; 448e0ad97e3SJonathan Adams intmax_t e_value; 4497c478bd9Sstevel@tonic-gate uint_t e_found; 450e0ad97e3SJonathan Adams mdb_ctf_id_t e_id; 4517c478bd9Sstevel@tonic-gate }; 452e0ad97e3SJonathan Adams #define E_PRETTY 0x01 453e0ad97e3SJonathan Adams #define E_HEX 0x02 454e0ad97e3SJonathan Adams #define E_SEARCH_STRING 0x04 455e0ad97e3SJonathan Adams #define E_SEARCH_VALUE 0x08 456e0ad97e3SJonathan Adams #define E_ELIDE_PREFIX 0x10 4577c478bd9Sstevel@tonic-gate 458cce40297SJonathan Adams static void 459cce40297SJonathan Adams enum_print(struct enum_cbinfo *info, const char *name, int value) 460cce40297SJonathan Adams { 461cce40297SJonathan Adams uint_t flags = info->e_flags; 462e0ad97e3SJonathan Adams uint_t elide_prefix = (info->e_flags & E_ELIDE_PREFIX); 463e0ad97e3SJonathan Adams 464e0ad97e3SJonathan Adams if (name != NULL && info->e_prefix && strlen(name) > info->e_prefix) 465e0ad97e3SJonathan Adams name += info->e_prefix; 466cce40297SJonathan Adams 467cce40297SJonathan Adams if (flags & E_PRETTY) { 468e0ad97e3SJonathan Adams uint_t indent = 5 + ((flags & E_HEX) ? 8 : 11); 469e0ad97e3SJonathan Adams 470e0ad97e3SJonathan Adams mdb_printf((flags & E_HEX)? "%8x " : "%11d ", value); 471e0ad97e3SJonathan Adams (void) mdb_inc_indent(indent); 472e0ad97e3SJonathan Adams if (name != NULL) { 473e0ad97e3SJonathan Adams mdb_iob_puts(mdb.m_out, name); 474e0ad97e3SJonathan Adams } else { 475e0ad97e3SJonathan Adams (void) enum_value_print_p2(info->e_id, value, 476e0ad97e3SJonathan Adams elide_prefix); 477e0ad97e3SJonathan Adams } 478e0ad97e3SJonathan Adams (void) mdb_dec_indent(indent); 479e0ad97e3SJonathan Adams mdb_printf("\n"); 480cce40297SJonathan Adams } else { 481cce40297SJonathan Adams mdb_printf("%#r\n", value); 482cce40297SJonathan Adams } 483cce40297SJonathan Adams } 484cce40297SJonathan Adams 4857c478bd9Sstevel@tonic-gate static int 4867c478bd9Sstevel@tonic-gate enum_cb(const char *name, int value, void *arg) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate struct enum_cbinfo *info = arg; 4897c478bd9Sstevel@tonic-gate uint_t flags = info->e_flags; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (flags & E_SEARCH_STRING) { 4927c478bd9Sstevel@tonic-gate if (strcmp(name, info->e_string) != 0) 4937c478bd9Sstevel@tonic-gate return (0); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate } else if (flags & E_SEARCH_VALUE) { 4967c478bd9Sstevel@tonic-gate if (value != info->e_value) 4977c478bd9Sstevel@tonic-gate return (0); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 500cce40297SJonathan Adams enum_print(info, name, value); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate info->e_found = 1; 5037c478bd9Sstevel@tonic-gate return (0); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 506e0ad97e3SJonathan Adams void 507e0ad97e3SJonathan Adams enum_help(void) 508e0ad97e3SJonathan Adams { 509e0ad97e3SJonathan Adams mdb_printf("%s", 510e0ad97e3SJonathan Adams "Without an address and name, print all values for the enumeration \"enum\".\n" 511e0ad97e3SJonathan Adams "With an address, look up a particular value in \"enum\". With a name, look\n" 512e0ad97e3SJonathan Adams "up a particular name in \"enum\".\n"); 513e0ad97e3SJonathan Adams 514e0ad97e3SJonathan Adams (void) mdb_dec_indent(2); 515e0ad97e3SJonathan Adams mdb_printf("\n%<b>OPTIONS%</b>\n"); 516e0ad97e3SJonathan Adams (void) mdb_inc_indent(2); 517e0ad97e3SJonathan Adams 518e0ad97e3SJonathan Adams mdb_printf("%s", 519e0ad97e3SJonathan Adams " -e remove common prefixes from enum names\n" 520e0ad97e3SJonathan Adams " -x report enum values in hexadecimal\n"); 521e0ad97e3SJonathan Adams } 522e0ad97e3SJonathan Adams 5237c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5247c478bd9Sstevel@tonic-gate int 5257c478bd9Sstevel@tonic-gate cmd_enum(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate struct enum_cbinfo info; 5287c478bd9Sstevel@tonic-gate 529cce40297SJonathan Adams char type[MDB_SYM_NAMLEN + sizeof ("enum ")]; 5307c478bd9Sstevel@tonic-gate char tn2[MDB_SYM_NAMLEN + sizeof ("enum ")]; 531e0ad97e3SJonathan Adams char prefix[MDB_SYM_NAMLEN]; 5327c478bd9Sstevel@tonic-gate mdb_ctf_id_t id; 5337c478bd9Sstevel@tonic-gate mdb_ctf_id_t idr; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate int i; 5367c478bd9Sstevel@tonic-gate intmax_t search; 537e0ad97e3SJonathan Adams uint_t isp2; 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate info.e_flags = (flags & DCMD_PIPE_OUT)? 0 : E_PRETTY; 5407c478bd9Sstevel@tonic-gate info.e_string = NULL; 5417c478bd9Sstevel@tonic-gate info.e_value = 0; 5427c478bd9Sstevel@tonic-gate info.e_found = 0; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate i = mdb_getopts(argc, argv, 545e0ad97e3SJonathan Adams 'e', MDB_OPT_SETBITS, E_ELIDE_PREFIX, &info.e_flags, 5467c478bd9Sstevel@tonic-gate 'x', MDB_OPT_SETBITS, E_HEX, &info.e_flags, 5477c478bd9Sstevel@tonic-gate NULL); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate argc -= i; 5507c478bd9Sstevel@tonic-gate argv += i; 5517c478bd9Sstevel@tonic-gate 552cce40297SJonathan Adams if ((i = args_to_typename(&argc, &argv, type, MDB_SYM_NAMLEN)) != 0) 5537c478bd9Sstevel@tonic-gate return (i); 5547c478bd9Sstevel@tonic-gate 555cce40297SJonathan Adams if (strchr(type, ' ') == NULL) { 5567c478bd9Sstevel@tonic-gate /* 5577c478bd9Sstevel@tonic-gate * Check as an enumeration tag first, and fall back 5587c478bd9Sstevel@tonic-gate * to checking for a typedef. Yes, this means that 5597c478bd9Sstevel@tonic-gate * anonymous enumerations whose typedefs conflict with 5607c478bd9Sstevel@tonic-gate * an enum tag can't be accessed. Don't do that. 5617c478bd9Sstevel@tonic-gate */ 562cce40297SJonathan Adams (void) mdb_snprintf(tn2, sizeof (tn2), "enum %s", type); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate if (mdb_ctf_lookup_by_name(tn2, &id) == 0) { 56580148899SSurya Prakki (void) strcpy(type, tn2); 566cce40297SJonathan Adams } else if (mdb_ctf_lookup_by_name(type, &id) != 0) { 567cce40297SJonathan Adams mdb_warn("types '%s', '%s'", tn2, type); 5687c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate } else { 571cce40297SJonathan Adams if (mdb_ctf_lookup_by_name(type, &id) != 0) { 572cce40297SJonathan Adams mdb_warn("'%s'", type); 5737c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* resolve it, and make sure we're looking at an enumeration */ 5787c478bd9Sstevel@tonic-gate if (mdb_ctf_type_resolve(id, &idr) == -1) { 5797c478bd9Sstevel@tonic-gate mdb_warn("unable to resolve '%s'", type); 5807c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate if (mdb_ctf_type_kind(idr) != CTF_K_ENUM) { 5837c478bd9Sstevel@tonic-gate mdb_warn("'%s': not an enumeration\n", type); 5847c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 587e0ad97e3SJonathan Adams info.e_id = idr; 588e0ad97e3SJonathan Adams 5897c478bd9Sstevel@tonic-gate if (argc > 2) 5907c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate if (argc == 2) { 5937c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 5947c478bd9Sstevel@tonic-gate mdb_warn("may only specify one of: name, address\n"); 5957c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate if (argv[1].a_type == MDB_TYPE_STRING) { 5997c478bd9Sstevel@tonic-gate info.e_flags |= E_SEARCH_STRING; 6007c478bd9Sstevel@tonic-gate info.e_string = argv[1].a_un.a_str; 6017c478bd9Sstevel@tonic-gate } else if (argv[1].a_type == MDB_TYPE_IMMEDIATE) { 6027c478bd9Sstevel@tonic-gate info.e_flags |= E_SEARCH_VALUE; 6037c478bd9Sstevel@tonic-gate search = argv[1].a_un.a_val; 6047c478bd9Sstevel@tonic-gate } else { 6057c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 6107c478bd9Sstevel@tonic-gate info.e_flags |= E_SEARCH_VALUE; 6117c478bd9Sstevel@tonic-gate search = mdb_get_dot(); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate if (info.e_flags & E_SEARCH_VALUE) { 6157c478bd9Sstevel@tonic-gate if ((int)search != search) { 6167c478bd9Sstevel@tonic-gate mdb_warn("value '%lld' out of enumeration range\n", 6177c478bd9Sstevel@tonic-gate search); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate info.e_value = search; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 622e0ad97e3SJonathan Adams isp2 = enum_is_p2(idr); 623e0ad97e3SJonathan Adams if (isp2) 624e0ad97e3SJonathan Adams info.e_flags |= E_HEX; 625e0ad97e3SJonathan Adams 6267c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) && (info.e_flags & E_PRETTY)) { 6277c478bd9Sstevel@tonic-gate if (info.e_flags & E_HEX) 628e0ad97e3SJonathan Adams mdb_printf("%<u>%8s %-64s%</u>\n", "VALUE", "NAME"); 6297c478bd9Sstevel@tonic-gate else 630e0ad97e3SJonathan Adams mdb_printf("%<u>%11s %-64s%</u>\n", "VALUE", "NAME"); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 633cce40297SJonathan Adams /* if the enum is a power-of-two one, process it that way */ 634e0ad97e3SJonathan Adams if ((info.e_flags & E_SEARCH_VALUE) && isp2) { 635e0ad97e3SJonathan Adams enum_print(&info, NULL, info.e_value); 636cce40297SJonathan Adams return (DCMD_OK); 637cce40297SJonathan Adams } 638cce40297SJonathan Adams 639e0ad97e3SJonathan Adams prefix[0] = 0; 640e0ad97e3SJonathan Adams if ((info.e_flags & E_ELIDE_PREFIX) && 641e0ad97e3SJonathan Adams mdb_ctf_enum_iter(id, enum_prefix_scan_cb, prefix) == 0) 642e0ad97e3SJonathan Adams info.e_prefix = strlen(prefix); 643e0ad97e3SJonathan Adams 6447c478bd9Sstevel@tonic-gate if (mdb_ctf_enum_iter(idr, enum_cb, &info) == -1) { 6457c478bd9Sstevel@tonic-gate mdb_warn("cannot walk '%s' as enum", type); 6467c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate if (info.e_found == 0 && 6507c478bd9Sstevel@tonic-gate (info.e_flags & (E_SEARCH_STRING | E_SEARCH_VALUE)) != 0) { 6517c478bd9Sstevel@tonic-gate if (info.e_flags & E_SEARCH_STRING) 6527c478bd9Sstevel@tonic-gate mdb_warn("name \"%s\" not in '%s'\n", info.e_string, 6537c478bd9Sstevel@tonic-gate type); 6547c478bd9Sstevel@tonic-gate else 655e0ad97e3SJonathan Adams mdb_warn("value %#lld not in '%s'\n", info.e_value, 656e0ad97e3SJonathan Adams type); 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate return (DCMD_OK); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate static int 6657c478bd9Sstevel@tonic-gate setup_vcb(const char *name, uintptr_t addr) 6667c478bd9Sstevel@tonic-gate { 6677c478bd9Sstevel@tonic-gate const char *p; 6687c478bd9Sstevel@tonic-gate mdb_var_t *v; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mdb.m_nv, name)) == NULL) { 6717c478bd9Sstevel@tonic-gate if ((p = strbadid(name)) != NULL) { 6727c478bd9Sstevel@tonic-gate mdb_warn("'%c' may not be used in a variable " 6737c478bd9Sstevel@tonic-gate "name\n", *p); 6747c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate if ((v = mdb_nv_insert(&mdb.m_nv, name, NULL, addr, 0)) == NULL) 6787c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6797c478bd9Sstevel@tonic-gate } else { 6807c478bd9Sstevel@tonic-gate if (v->v_flags & MDB_NV_RDONLY) { 6817c478bd9Sstevel@tonic-gate mdb_warn("variable %s is read-only\n", name); 6827c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * If there already exists a vcb for this variable, we may be 6887c478bd9Sstevel@tonic-gate * calling the dcmd in a loop. We only create a vcb for this 6897c478bd9Sstevel@tonic-gate * variable on the first invocation. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate if (mdb_vcb_find(v, mdb.m_frame) == NULL) 6927c478bd9Sstevel@tonic-gate mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate return (0); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6987c478bd9Sstevel@tonic-gate int 6997c478bd9Sstevel@tonic-gate cmd_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 7007c478bd9Sstevel@tonic-gate { 70128e4da25SMatthew Ahrens int offset; 7027c478bd9Sstevel@tonic-gate uintptr_t a, tmp; 7037c478bd9Sstevel@tonic-gate int ret; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc == 0) 7067c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate if (argv->a_type != MDB_TYPE_STRING) { 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * We are being given a raw offset in lieu of a type and 71123edb310SMax Grossman * member; confirm the number of arguments and argument 71223edb310SMax Grossman * type. 7137c478bd9Sstevel@tonic-gate */ 71423edb310SMax Grossman if (argc != 1 || argv->a_type != MDB_TYPE_IMMEDIATE) 7157c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate offset = argv->a_un.a_val; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate argv++; 7207c478bd9Sstevel@tonic-gate argc--; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate if (offset % sizeof (uintptr_t)) { 7237c478bd9Sstevel@tonic-gate mdb_warn("offset must fall on a word boundary\n"); 7247c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate } else { 7277c478bd9Sstevel@tonic-gate const char *member; 7287c478bd9Sstevel@tonic-gate char buf[MDB_SYM_NAMLEN]; 7297c478bd9Sstevel@tonic-gate int ret; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate ret = args_to_typename(&argc, &argv, buf, sizeof (buf)); 7327c478bd9Sstevel@tonic-gate if (ret != 0) 7337c478bd9Sstevel@tonic-gate return (ret); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate argv++; 7367c478bd9Sstevel@tonic-gate argc--; 7377c478bd9Sstevel@tonic-gate 738*b3eeeb30SCody Peter Mello /* 739*b3eeeb30SCody Peter Mello * If we make it here, we were provided a type name. We should 740*b3eeeb30SCody Peter Mello * only continue if we still have arguments left (e.g. member 741*b3eeeb30SCody Peter Mello * name and potentially a variable name). 742*b3eeeb30SCody Peter Mello */ 743*b3eeeb30SCody Peter Mello if (argc == 0) 744*b3eeeb30SCody Peter Mello return (DCMD_USAGE); 745*b3eeeb30SCody Peter Mello 7467c478bd9Sstevel@tonic-gate member = argv->a_un.a_str; 74728e4da25SMatthew Ahrens offset = mdb_ctf_offsetof_by_name(buf, member); 74828e4da25SMatthew Ahrens if (offset == -1) 74928e4da25SMatthew Ahrens return (DCMD_ABORT); 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate argv++; 7527c478bd9Sstevel@tonic-gate argc--; 7537c478bd9Sstevel@tonic-gate 75428e4da25SMatthew Ahrens if (offset % (sizeof (uintptr_t)) != 0) { 7557c478bd9Sstevel@tonic-gate mdb_warn("%s is not a word-aligned member\n", member); 7567c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* 7617c478bd9Sstevel@tonic-gate * If we have any unchewed arguments, a variable name must be present. 7627c478bd9Sstevel@tonic-gate */ 7637c478bd9Sstevel@tonic-gate if (argc == 1) { 7647c478bd9Sstevel@tonic-gate if (argv->a_type != MDB_TYPE_STRING) 7657c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate if ((ret = setup_vcb(argv->a_un.a_str, addr)) != 0) 7687c478bd9Sstevel@tonic-gate return (ret); 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate } else if (argc != 0) { 7717c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate a = addr; 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate do { 7777c478bd9Sstevel@tonic-gate mdb_printf("%lr\n", a); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate if (mdb_vread(&tmp, sizeof (tmp), a + offset) == -1) { 7807c478bd9Sstevel@tonic-gate mdb_warn("failed to read next pointer from object %p", 7817c478bd9Sstevel@tonic-gate a); 7827c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate a = tmp; 7867c478bd9Sstevel@tonic-gate } while (a != addr && a != NULL); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate return (DCMD_OK); 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate int 7927c478bd9Sstevel@tonic-gate cmd_array(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 7937c478bd9Sstevel@tonic-gate { 7947c478bd9Sstevel@tonic-gate mdb_ctf_id_t id; 7957c478bd9Sstevel@tonic-gate ssize_t elemsize = 0; 7967c478bd9Sstevel@tonic-gate char tn[MDB_SYM_NAMLEN]; 7977c478bd9Sstevel@tonic-gate int ret, nelem = -1; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 8007c478bd9Sstevel@tonic-gate GElf_Sym sym; 8017c478bd9Sstevel@tonic-gate mdb_ctf_arinfo_t ar; 8027c478bd9Sstevel@tonic-gate mdb_syminfo_t s_info; 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 8057c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate if (argc >= 2) { 8087c478bd9Sstevel@tonic-gate ret = args_to_typename(&argc, &argv, tn, sizeof (tn)); 8097c478bd9Sstevel@tonic-gate if (ret != 0) 8107c478bd9Sstevel@tonic-gate return (ret); 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate if (argc == 1) /* unquoted compound type without count */ 8137c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate if (mdb_ctf_lookup_by_name(tn, &id) != 0) { 8167c478bd9Sstevel@tonic-gate mdb_warn("failed to look up type %s", tn); 8177c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate if (argv[1].a_type == MDB_TYPE_IMMEDIATE) 8217c478bd9Sstevel@tonic-gate nelem = argv[1].a_un.a_val; 8227c478bd9Sstevel@tonic-gate else 8237c478bd9Sstevel@tonic-gate nelem = mdb_strtoull(argv[1].a_un.a_str); 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate elemsize = mdb_ctf_type_size(id); 8267c478bd9Sstevel@tonic-gate } else if (addr_to_sym(t, addr, tn, sizeof (tn), &sym, &s_info) 827cce40297SJonathan Adams != NULL && mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) 828cce40297SJonathan Adams == 0 && mdb_ctf_type_kind(id) == CTF_K_ARRAY && 829cce40297SJonathan Adams mdb_ctf_array_info(id, &ar) != -1) { 830cce40297SJonathan Adams elemsize = mdb_ctf_type_size(id) / ar.mta_nelems; 831cce40297SJonathan Adams nelem = ar.mta_nelems; 8327c478bd9Sstevel@tonic-gate } else { 8337c478bd9Sstevel@tonic-gate mdb_warn("no symbol information for %a", addr); 8347c478bd9Sstevel@tonic-gate return (DCMD_ERR); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate if (argc == 3 || argc == 1) { 8387c478bd9Sstevel@tonic-gate if (argv[argc - 1].a_type != MDB_TYPE_STRING) 8397c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate if ((ret = setup_vcb(argv[argc - 1].a_un.a_str, addr)) != 0) 8427c478bd9Sstevel@tonic-gate return (ret); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate } else if (argc > 3) { 8457c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate for (; nelem > 0; nelem--) { 8497c478bd9Sstevel@tonic-gate mdb_printf("%lr\n", addr); 8507c478bd9Sstevel@tonic-gate addr = addr + elemsize; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate return (DCMD_OK); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * Print an integer bitfield in hexadecimal by reading the enclosing byte(s) 8587c478bd9Sstevel@tonic-gate * and then shifting and masking the data in the lower bits of a uint64_t. 8597c478bd9Sstevel@tonic-gate */ 8607c478bd9Sstevel@tonic-gate static int 8617c478bd9Sstevel@tonic-gate print_bitfield(ulong_t off, printarg_t *pap, ctf_encoding_t *ep) 8627c478bd9Sstevel@tonic-gate { 8637c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; 8647c478bd9Sstevel@tonic-gate size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY; 8657c478bd9Sstevel@tonic-gate uint64_t mask = (1ULL << ep->cte_bits) - 1; 8667c478bd9Sstevel@tonic-gate uint64_t value = 0; 8677c478bd9Sstevel@tonic-gate uint8_t *buf = (uint8_t *)&value; 8687c478bd9Sstevel@tonic-gate uint8_t shift; 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate const char *format; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate if (!(pap->pa_flags & PA_SHOWVAL)) 8737c478bd9Sstevel@tonic-gate return (0); 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate if (ep->cte_bits > sizeof (value) * NBBY - 1) { 8767c478bd9Sstevel@tonic-gate mdb_printf("??? (invalid bitfield size %u)", ep->cte_bits); 8777c478bd9Sstevel@tonic-gate return (0); 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* 8817c478bd9Sstevel@tonic-gate * On big-endian machines, we need to adjust the buf pointer to refer 8827c478bd9Sstevel@tonic-gate * to the lowest 'size' bytes in 'value', and we need shift based on 8837c478bd9Sstevel@tonic-gate * the offset from the end of the data, not the offset of the start. 8847c478bd9Sstevel@tonic-gate */ 8857c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 8867c478bd9Sstevel@tonic-gate buf += sizeof (value) - size; 8877c478bd9Sstevel@tonic-gate off += ep->cte_bits; 8887c478bd9Sstevel@tonic-gate #endif 8897c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, buf, size, addr) != size) { 8907c478bd9Sstevel@tonic-gate mdb_warn("failed to read %lu bytes at %llx", 8917c478bd9Sstevel@tonic-gate (ulong_t)size, addr); 8927c478bd9Sstevel@tonic-gate return (1); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate shift = off % NBBY; 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * Offsets are counted from opposite ends on little- and 8997c478bd9Sstevel@tonic-gate * big-endian machines. 9007c478bd9Sstevel@tonic-gate */ 9017c478bd9Sstevel@tonic-gate #ifdef _BIG_ENDIAN 9027c478bd9Sstevel@tonic-gate shift = NBBY - shift; 9037c478bd9Sstevel@tonic-gate #endif 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* 9067c478bd9Sstevel@tonic-gate * If the bits we want do not begin on a byte boundary, shift the data 9077c478bd9Sstevel@tonic-gate * right so that the value is in the lowest 'cte_bits' of 'value'. 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate if (off % NBBY != 0) 9107c478bd9Sstevel@tonic-gate value >>= shift; 9117c478bd9Sstevel@tonic-gate value &= mask; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* 9147c478bd9Sstevel@tonic-gate * We default to printing signed bitfields as decimals, 9157c478bd9Sstevel@tonic-gate * and unsigned bitfields in hexadecimal. If they specify 9167c478bd9Sstevel@tonic-gate * hexadecimal, we treat the field as unsigned. 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate if ((pap->pa_flags & PA_INTHEX) || 9197c478bd9Sstevel@tonic-gate !(ep->cte_format & CTF_INT_SIGNED)) { 9207c478bd9Sstevel@tonic-gate format = (pap->pa_flags & PA_INTDEC)? "%#llu" : "%#llx"; 9217c478bd9Sstevel@tonic-gate } else { 9227c478bd9Sstevel@tonic-gate int sshift = sizeof (value) * NBBY - ep->cte_bits; 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* sign-extend value, and print as a signed decimal */ 9257c478bd9Sstevel@tonic-gate value = ((int64_t)value << sshift) >> sshift; 9267c478bd9Sstevel@tonic-gate format = "%#lld"; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate mdb_printf(format, value); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate return (0); 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * Print out a character or integer value. We use some simple heuristics, 9357c478bd9Sstevel@tonic-gate * described below, to determine the appropriate radix to use for output. 9367c478bd9Sstevel@tonic-gate */ 9377c478bd9Sstevel@tonic-gate static int 9387c478bd9Sstevel@tonic-gate print_int_val(const char *type, ctf_encoding_t *ep, ulong_t off, 9397c478bd9Sstevel@tonic-gate printarg_t *pap) 9407c478bd9Sstevel@tonic-gate { 9417c478bd9Sstevel@tonic-gate static const char *const sformat[] = { "%#d", "%#d", "%#d", "%#lld" }; 9427c478bd9Sstevel@tonic-gate static const char *const uformat[] = { "%#u", "%#u", "%#u", "%#llu" }; 9437c478bd9Sstevel@tonic-gate static const char *const xformat[] = { "%#x", "%#x", "%#x", "%#llx" }; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; 9467c478bd9Sstevel@tonic-gate const char *const *fsp; 9477c478bd9Sstevel@tonic-gate size_t size; 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate union { 9507c478bd9Sstevel@tonic-gate uint64_t i8; 9517c478bd9Sstevel@tonic-gate uint32_t i4; 9527c478bd9Sstevel@tonic-gate uint16_t i2; 9537c478bd9Sstevel@tonic-gate uint8_t i1; 9547c478bd9Sstevel@tonic-gate time_t t; 955838d7172SSebastien Roy ipaddr_t I; 9567c478bd9Sstevel@tonic-gate } u; 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (!(pap->pa_flags & PA_SHOWVAL)) 9597c478bd9Sstevel@tonic-gate return (0); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (ep->cte_format & CTF_INT_VARARGS) { 9627c478bd9Sstevel@tonic-gate mdb_printf("...\n"); 9637c478bd9Sstevel@tonic-gate return (0); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * If the size is not a power-of-two number of bytes in the range 1-8 9687c478bd9Sstevel@tonic-gate * then we assume it is a bitfield and print it as such. 9697c478bd9Sstevel@tonic-gate */ 9707c478bd9Sstevel@tonic-gate size = ep->cte_bits / NBBY; 9717c478bd9Sstevel@tonic-gate if (size > 8 || (ep->cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) 9727c478bd9Sstevel@tonic-gate return (print_bitfield(off, pap, ep)); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (IS_CHAR(*ep)) { 9757c478bd9Sstevel@tonic-gate mdb_printf("'"); 9767c478bd9Sstevel@tonic-gate if (mdb_fmt_print(pap->pa_tgt, pap->pa_as, 9777c478bd9Sstevel@tonic-gate addr, 1, 'C') == addr) 9787c478bd9Sstevel@tonic-gate return (1); 9797c478bd9Sstevel@tonic-gate mdb_printf("'"); 9807c478bd9Sstevel@tonic-gate return (0); 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size, addr) != size) { 9847c478bd9Sstevel@tonic-gate mdb_warn("failed to read %lu bytes at %llx", 9857c478bd9Sstevel@tonic-gate (ulong_t)size, addr); 9867c478bd9Sstevel@tonic-gate return (1); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 990838d7172SSebastien Roy * We pretty-print some integer based types. time_t values are 991838d7172SSebastien Roy * printed as a calendar date and time, and IPv4 addresses as human 992838d7172SSebastien Roy * readable dotted quads. 9937c478bd9Sstevel@tonic-gate */ 994838d7172SSebastien Roy if (!(pap->pa_flags & (PA_INTHEX | PA_INTDEC))) { 995838d7172SSebastien Roy if (strcmp(type, "time_t") == 0 && u.t != 0) { 996838d7172SSebastien Roy mdb_printf("%Y", u.t); 997838d7172SSebastien Roy return (0); 998838d7172SSebastien Roy } 999838d7172SSebastien Roy if (strcmp(type, "ipaddr_t") == 0 || 1000838d7172SSebastien Roy strcmp(type, "in_addr_t") == 0) { 1001838d7172SSebastien Roy mdb_printf("%I", u.I); 1002838d7172SSebastien Roy return (0); 1003838d7172SSebastien Roy } 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * The default format is hexadecimal. 10087c478bd9Sstevel@tonic-gate */ 10097c478bd9Sstevel@tonic-gate if (!(pap->pa_flags & PA_INTDEC)) 10107c478bd9Sstevel@tonic-gate fsp = xformat; 10117c478bd9Sstevel@tonic-gate else if (ep->cte_format & CTF_INT_SIGNED) 10127c478bd9Sstevel@tonic-gate fsp = sformat; 10137c478bd9Sstevel@tonic-gate else 10147c478bd9Sstevel@tonic-gate fsp = uformat; 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate switch (size) { 10177c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 10187c478bd9Sstevel@tonic-gate mdb_printf(fsp[0], u.i1); 10197c478bd9Sstevel@tonic-gate break; 10207c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 10217c478bd9Sstevel@tonic-gate mdb_printf(fsp[1], u.i2); 10227c478bd9Sstevel@tonic-gate break; 10237c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 10247c478bd9Sstevel@tonic-gate mdb_printf(fsp[2], u.i4); 10257c478bd9Sstevel@tonic-gate break; 10267c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 10277c478bd9Sstevel@tonic-gate mdb_printf(fsp[3], u.i8); 10287c478bd9Sstevel@tonic-gate break; 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate return (0); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10347c478bd9Sstevel@tonic-gate static int 10357c478bd9Sstevel@tonic-gate print_int(const char *type, const char *name, mdb_ctf_id_t id, 10367c478bd9Sstevel@tonic-gate mdb_ctf_id_t base, ulong_t off, printarg_t *pap) 10377c478bd9Sstevel@tonic-gate { 10387c478bd9Sstevel@tonic-gate ctf_encoding_t e; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate if (!(pap->pa_flags & PA_SHOWVAL)) 10417c478bd9Sstevel@tonic-gate return (0); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if (mdb_ctf_type_encoding(base, &e) != 0) { 10447c478bd9Sstevel@tonic-gate mdb_printf("??? (%s)", mdb_strerror(errno)); 10457c478bd9Sstevel@tonic-gate return (0); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate return (print_int_val(type, &e, off, pap)); 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate /* 10527c478bd9Sstevel@tonic-gate * Print out a floating point value. We only provide support for floats in 10537c478bd9Sstevel@tonic-gate * the ANSI-C float, double, and long double formats. 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10567c478bd9Sstevel@tonic-gate static int 10577c478bd9Sstevel@tonic-gate print_float(const char *type, const char *name, mdb_ctf_id_t id, 10587c478bd9Sstevel@tonic-gate mdb_ctf_id_t base, ulong_t off, printarg_t *pap) 10597c478bd9Sstevel@tonic-gate { 10607c478bd9Sstevel@tonic-gate #ifndef _KMDB 10617c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; 10627c478bd9Sstevel@tonic-gate ctf_encoding_t e; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate union { 10657c478bd9Sstevel@tonic-gate float f; 10667c478bd9Sstevel@tonic-gate double d; 10677c478bd9Sstevel@tonic-gate long double ld; 10687c478bd9Sstevel@tonic-gate } u; 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate if (!(pap->pa_flags & PA_SHOWVAL)) 10717c478bd9Sstevel@tonic-gate return (0); 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate if (mdb_ctf_type_encoding(base, &e) == 0) { 10747c478bd9Sstevel@tonic-gate if (e.cte_format == CTF_FP_SINGLE && 10757c478bd9Sstevel@tonic-gate e.cte_bits == sizeof (float) * NBBY) { 10767c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.f, 10777c478bd9Sstevel@tonic-gate sizeof (u.f), addr) != sizeof (u.f)) { 10787c478bd9Sstevel@tonic-gate mdb_warn("failed to read float at %llx", addr); 10797c478bd9Sstevel@tonic-gate return (1); 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate mdb_printf("%s", doubletos(u.f, 7, 'e')); 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate } else if (e.cte_format == CTF_FP_DOUBLE && 10847c478bd9Sstevel@tonic-gate e.cte_bits == sizeof (double) * NBBY) { 10857c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.d, 10867c478bd9Sstevel@tonic-gate sizeof (u.d), addr) != sizeof (u.d)) { 10877c478bd9Sstevel@tonic-gate mdb_warn("failed to read float at %llx", addr); 10887c478bd9Sstevel@tonic-gate return (1); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate mdb_printf("%s", doubletos(u.d, 7, 'e')); 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate } else if (e.cte_format == CTF_FP_LDOUBLE && 10937c478bd9Sstevel@tonic-gate e.cte_bits == sizeof (long double) * NBBY) { 10947c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.ld, 10957c478bd9Sstevel@tonic-gate sizeof (u.ld), addr) != sizeof (u.ld)) { 10967c478bd9Sstevel@tonic-gate mdb_warn("failed to read float at %llx", addr); 10977c478bd9Sstevel@tonic-gate return (1); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate mdb_printf("%s", longdoubletos(&u.ld, 16, 'e')); 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate } else { 11027c478bd9Sstevel@tonic-gate mdb_printf("??? (unsupported FP format %u / %u bits\n", 11037c478bd9Sstevel@tonic-gate e.cte_format, e.cte_bits); 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate } else 11067c478bd9Sstevel@tonic-gate mdb_printf("??? (%s)", mdb_strerror(errno)); 11077c478bd9Sstevel@tonic-gate #else 11087c478bd9Sstevel@tonic-gate mdb_printf("<FLOAT>"); 11097c478bd9Sstevel@tonic-gate #endif 11107c478bd9Sstevel@tonic-gate return (0); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate /* 11157c478bd9Sstevel@tonic-gate * Print out a pointer value as a symbol name + offset or a hexadecimal value. 11167c478bd9Sstevel@tonic-gate * If the pointer itself is a char *, we attempt to read a bit of the data 11177c478bd9Sstevel@tonic-gate * referenced by the pointer and display it if it is a printable ASCII string. 11187c478bd9Sstevel@tonic-gate */ 11197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11207c478bd9Sstevel@tonic-gate static int 11217c478bd9Sstevel@tonic-gate print_ptr(const char *type, const char *name, mdb_ctf_id_t id, 11227c478bd9Sstevel@tonic-gate mdb_ctf_id_t base, ulong_t off, printarg_t *pap) 11237c478bd9Sstevel@tonic-gate { 11247c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; 11257c478bd9Sstevel@tonic-gate ctf_encoding_t e; 11267c478bd9Sstevel@tonic-gate uintptr_t value; 11277c478bd9Sstevel@tonic-gate char buf[256]; 11287c478bd9Sstevel@tonic-gate ssize_t len; 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate if (!(pap->pa_flags & PA_SHOWVAL)) 11317c478bd9Sstevel@tonic-gate return (0); 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, 11347c478bd9Sstevel@tonic-gate &value, sizeof (value), addr) != sizeof (value)) { 11357c478bd9Sstevel@tonic-gate mdb_warn("failed to read %s pointer at %llx", name, addr); 11367c478bd9Sstevel@tonic-gate return (1); 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate if (pap->pa_flags & PA_NOSYMBOLIC) { 11407c478bd9Sstevel@tonic-gate mdb_printf("%#lx", value); 11417c478bd9Sstevel@tonic-gate return (0); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate mdb_printf("%a", value); 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate if (value == NULL || strcmp(type, "caddr_t") == 0) 11477c478bd9Sstevel@tonic-gate return (0); 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate if (mdb_ctf_type_kind(base) == CTF_K_POINTER && 11507c478bd9Sstevel@tonic-gate mdb_ctf_type_reference(base, &base) != -1 && 11517c478bd9Sstevel@tonic-gate mdb_ctf_type_resolve(base, &base) != -1 && 11527c478bd9Sstevel@tonic-gate mdb_ctf_type_encoding(base, &e) == 0 && IS_CHAR(e)) { 11537c478bd9Sstevel@tonic-gate if ((len = mdb_tgt_readstr(pap->pa_realtgt, pap->pa_as, 11547c478bd9Sstevel@tonic-gate buf, sizeof (buf), value)) >= 0 && strisprint(buf)) { 11557c478bd9Sstevel@tonic-gate if (len == sizeof (buf)) 11567c478bd9Sstevel@tonic-gate (void) strabbr(buf, sizeof (buf)); 11577c478bd9Sstevel@tonic-gate mdb_printf(" \"%s\"", buf); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate return (0); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate /* 11667c478bd9Sstevel@tonic-gate * Print out a fixed-size array. We special-case arrays of characters 11677c478bd9Sstevel@tonic-gate * and attempt to print them out as ASCII strings if possible. For other 11687c478bd9Sstevel@tonic-gate * arrays, we iterate over a maximum of pa_armemlim members and call 11697c478bd9Sstevel@tonic-gate * mdb_ctf_type_visit() again on each element to print its value. 11707c478bd9Sstevel@tonic-gate */ 11717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11727c478bd9Sstevel@tonic-gate static int 11737c478bd9Sstevel@tonic-gate print_array(const char *type, const char *name, mdb_ctf_id_t id, 11747c478bd9Sstevel@tonic-gate mdb_ctf_id_t base, ulong_t off, printarg_t *pap) 11757c478bd9Sstevel@tonic-gate { 11767c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; 11777c478bd9Sstevel@tonic-gate printarg_t pa = *pap; 11787c478bd9Sstevel@tonic-gate ssize_t eltsize; 11797c478bd9Sstevel@tonic-gate mdb_ctf_arinfo_t r; 11807c478bd9Sstevel@tonic-gate ctf_encoding_t e; 11817c478bd9Sstevel@tonic-gate uint_t i, kind, limit; 11827c478bd9Sstevel@tonic-gate int d, sou; 11837c478bd9Sstevel@tonic-gate char buf[8]; 11847c478bd9Sstevel@tonic-gate char *str; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate if (!(pap->pa_flags & PA_SHOWVAL)) 11877c478bd9Sstevel@tonic-gate return (0); 11887c478bd9Sstevel@tonic-gate 1189bf5197d8Sjwadams if (pap->pa_depth == pap->pa_maxdepth) { 1190bf5197d8Sjwadams mdb_printf("[ ... ]"); 1191bf5197d8Sjwadams return (0); 1192bf5197d8Sjwadams } 1193bf5197d8Sjwadams 11947c478bd9Sstevel@tonic-gate /* 11957c478bd9Sstevel@tonic-gate * Determine the base type and size of the array's content. If this 11967c478bd9Sstevel@tonic-gate * fails, we cannot print anything and just give up. 11977c478bd9Sstevel@tonic-gate */ 11987c478bd9Sstevel@tonic-gate if (mdb_ctf_array_info(base, &r) == -1 || 11997c478bd9Sstevel@tonic-gate mdb_ctf_type_resolve(r.mta_contents, &base) == -1 || 12007c478bd9Sstevel@tonic-gate (eltsize = mdb_ctf_type_size(base)) == -1) { 12017c478bd9Sstevel@tonic-gate mdb_printf("[ ??? ] (%s)", mdb_strerror(errno)); 12027c478bd9Sstevel@tonic-gate return (0); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* 12067c478bd9Sstevel@tonic-gate * Read a few bytes and determine if the content appears to be 12077c478bd9Sstevel@tonic-gate * printable ASCII characters. If so, read the entire array and 12087c478bd9Sstevel@tonic-gate * attempt to display it as a string if it is printable. 12097c478bd9Sstevel@tonic-gate */ 12107c478bd9Sstevel@tonic-gate if ((pap->pa_arstrlim == MDB_ARR_NOLIMIT || 12117c478bd9Sstevel@tonic-gate r.mta_nelems <= pap->pa_arstrlim) && 12127c478bd9Sstevel@tonic-gate mdb_ctf_type_encoding(base, &e) == 0 && IS_CHAR(e) && 12137c478bd9Sstevel@tonic-gate mdb_tgt_readstr(pap->pa_tgt, pap->pa_as, buf, 12147c478bd9Sstevel@tonic-gate MIN(sizeof (buf), r.mta_nelems), addr) > 0 && strisprint(buf)) { 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate str = mdb_alloc(r.mta_nelems + 1, UM_SLEEP | UM_GC); 12177c478bd9Sstevel@tonic-gate str[r.mta_nelems] = '\0'; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, str, 12207c478bd9Sstevel@tonic-gate r.mta_nelems, addr) != r.mta_nelems) { 12217c478bd9Sstevel@tonic-gate mdb_warn("failed to read char array at %llx", addr); 12227c478bd9Sstevel@tonic-gate return (1); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate if (strisprint(str)) { 12267c478bd9Sstevel@tonic-gate mdb_printf("[ \"%s\" ]", str); 12277c478bd9Sstevel@tonic-gate return (0); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate if (pap->pa_armemlim != MDB_ARR_NOLIMIT) 12327c478bd9Sstevel@tonic-gate limit = MIN(r.mta_nelems, pap->pa_armemlim); 12337c478bd9Sstevel@tonic-gate else 12347c478bd9Sstevel@tonic-gate limit = r.mta_nelems; 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate if (limit == 0) { 12377c478bd9Sstevel@tonic-gate mdb_printf("[ ... ]"); 12387c478bd9Sstevel@tonic-gate return (0); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate kind = mdb_ctf_type_kind(base); 12427c478bd9Sstevel@tonic-gate sou = IS_COMPOSITE(kind); 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate pa.pa_addr = addr; /* set base address to start of array */ 1245cce40297SJonathan Adams pa.pa_maxdepth = pa.pa_maxdepth - pa.pa_depth - 1; 12467c478bd9Sstevel@tonic-gate pa.pa_nest += pa.pa_depth + 1; /* nesting level is current depth + 1 */ 12477c478bd9Sstevel@tonic-gate pa.pa_depth = 0; /* reset depth to 0 for new scope */ 12487c478bd9Sstevel@tonic-gate pa.pa_prefix = NULL; 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate if (sou) { 12517c478bd9Sstevel@tonic-gate pa.pa_delim = "\n"; 12527c478bd9Sstevel@tonic-gate mdb_printf("[\n"); 12537c478bd9Sstevel@tonic-gate } else { 12547c478bd9Sstevel@tonic-gate pa.pa_flags &= ~(PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR); 12557c478bd9Sstevel@tonic-gate pa.pa_delim = ", "; 12567c478bd9Sstevel@tonic-gate mdb_printf("[ "); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate for (i = 0; i < limit; i++, pa.pa_addr += eltsize) { 12607c478bd9Sstevel@tonic-gate if (i == limit - 1 && !sou) { 12617c478bd9Sstevel@tonic-gate if (limit < r.mta_nelems) 12627c478bd9Sstevel@tonic-gate pa.pa_delim = ", ... ]"; 12637c478bd9Sstevel@tonic-gate else 12647c478bd9Sstevel@tonic-gate pa.pa_delim = " ]"; 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate if (mdb_ctf_type_visit(r.mta_contents, elt_print, &pa) == -1) { 12687c478bd9Sstevel@tonic-gate mdb_warn("failed to print array data"); 12697c478bd9Sstevel@tonic-gate return (1); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate if (sou) { 12747c478bd9Sstevel@tonic-gate for (d = pa.pa_depth - 1; d >= 0; d--) 12757c478bd9Sstevel@tonic-gate print_close_sou(&pa, d); 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate if (limit < r.mta_nelems) { 12787c478bd9Sstevel@tonic-gate mdb_printf("%*s... ]", 12797c478bd9Sstevel@tonic-gate (pap->pa_depth + pap->pa_nest) * pap->pa_tab, ""); 12807c478bd9Sstevel@tonic-gate } else { 12817c478bd9Sstevel@tonic-gate mdb_printf("%*s]", 12827c478bd9Sstevel@tonic-gate (pap->pa_depth + pap->pa_nest) * pap->pa_tab, ""); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate /* copy the hole array info, since it may have been grown */ 12877c478bd9Sstevel@tonic-gate pap->pa_holes = pa.pa_holes; 12887c478bd9Sstevel@tonic-gate pap->pa_nholes = pa.pa_nholes; 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate return (0); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate /* 12947c478bd9Sstevel@tonic-gate * Print out a struct or union header. We need only print the open brace 12957c478bd9Sstevel@tonic-gate * because mdb_ctf_type_visit() itself will automatically recurse through 12967c478bd9Sstevel@tonic-gate * all members of the given struct or union. 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12997c478bd9Sstevel@tonic-gate static int 13007c478bd9Sstevel@tonic-gate print_sou(const char *type, const char *name, mdb_ctf_id_t id, 13017c478bd9Sstevel@tonic-gate mdb_ctf_id_t base, ulong_t off, printarg_t *pap) 13027c478bd9Sstevel@tonic-gate { 1303838d7172SSebastien Roy mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; 1304838d7172SSebastien Roy 1305838d7172SSebastien Roy /* 1306838d7172SSebastien Roy * We have pretty-printing for some structures where displaying 1307838d7172SSebastien Roy * structure contents has no value. 1308838d7172SSebastien Roy */ 1309838d7172SSebastien Roy if (pap->pa_flags & PA_SHOWVAL) { 1310838d7172SSebastien Roy if (strcmp(type, "in6_addr_t") == 0 || 1311838d7172SSebastien Roy strcmp(type, "struct in6_addr") == 0) { 1312838d7172SSebastien Roy in6_addr_t in6addr; 1313838d7172SSebastien Roy 1314838d7172SSebastien Roy if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &in6addr, 1315838d7172SSebastien Roy sizeof (in6addr), addr) != sizeof (in6addr)) { 1316838d7172SSebastien Roy mdb_warn("failed to read %s pointer at %llx", 1317838d7172SSebastien Roy name, addr); 1318838d7172SSebastien Roy return (1); 1319838d7172SSebastien Roy } 1320838d7172SSebastien Roy mdb_printf("%N", &in6addr); 1321838d7172SSebastien Roy /* 1322838d7172SSebastien Roy * Don't print anything further down in the 1323838d7172SSebastien Roy * structure. 1324838d7172SSebastien Roy */ 1325838d7172SSebastien Roy pap->pa_nooutdepth = pap->pa_depth; 1326838d7172SSebastien Roy return (0); 1327838d7172SSebastien Roy } 1328838d7172SSebastien Roy if (strcmp(type, "struct in_addr") == 0) { 1329838d7172SSebastien Roy in_addr_t inaddr; 1330838d7172SSebastien Roy 1331838d7172SSebastien Roy if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &inaddr, 1332838d7172SSebastien Roy sizeof (inaddr), addr) != sizeof (inaddr)) { 1333838d7172SSebastien Roy mdb_warn("failed to read %s pointer at %llx", 1334838d7172SSebastien Roy name, addr); 1335838d7172SSebastien Roy return (1); 1336838d7172SSebastien Roy } 1337838d7172SSebastien Roy mdb_printf("%I", inaddr); 1338838d7172SSebastien Roy pap->pa_nooutdepth = pap->pa_depth; 1339838d7172SSebastien Roy return (0); 1340838d7172SSebastien Roy } 1341838d7172SSebastien Roy } 1342838d7172SSebastien Roy 1343bf5197d8Sjwadams if (pap->pa_depth == pap->pa_maxdepth) 1344bf5197d8Sjwadams mdb_printf("{ ... }"); 1345bf5197d8Sjwadams else 1346bf5197d8Sjwadams mdb_printf("{"); 13477c478bd9Sstevel@tonic-gate pap->pa_delim = "\n"; 13487c478bd9Sstevel@tonic-gate return (0); 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate /* 13527c478bd9Sstevel@tonic-gate * Print an enum value. We attempt to convert the value to the corresponding 13537c478bd9Sstevel@tonic-gate * enum name and print that if possible. 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13567c478bd9Sstevel@tonic-gate static int 13577c478bd9Sstevel@tonic-gate print_enum(const char *type, const char *name, mdb_ctf_id_t id, 13587c478bd9Sstevel@tonic-gate mdb_ctf_id_t base, ulong_t off, printarg_t *pap) 13597c478bd9Sstevel@tonic-gate { 13607c478bd9Sstevel@tonic-gate mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY; 13617c478bd9Sstevel@tonic-gate const char *ename; 13627c478bd9Sstevel@tonic-gate int value; 1363e0ad97e3SJonathan Adams int isp2 = enum_is_p2(base); 1364e0ad97e3SJonathan Adams int flags = pap->pa_flags | (isp2 ? PA_INTHEX : 0); 13657c478bd9Sstevel@tonic-gate 1366e0ad97e3SJonathan Adams if (!(flags & PA_SHOWVAL)) 13677c478bd9Sstevel@tonic-gate return (0); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, 13707c478bd9Sstevel@tonic-gate &value, sizeof (value), addr) != sizeof (value)) { 13717c478bd9Sstevel@tonic-gate mdb_warn("failed to read %s integer at %llx", name, addr); 13727c478bd9Sstevel@tonic-gate return (1); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 1375e0ad97e3SJonathan Adams if (flags & PA_INTHEX) 13767c478bd9Sstevel@tonic-gate mdb_printf("%#x", value); 13777c478bd9Sstevel@tonic-gate else 13787c478bd9Sstevel@tonic-gate mdb_printf("%#d", value); 13797c478bd9Sstevel@tonic-gate 1380e0ad97e3SJonathan Adams (void) mdb_inc_indent(8); 1381e0ad97e3SJonathan Adams mdb_printf(" ("); 1382cce40297SJonathan Adams 1383e0ad97e3SJonathan Adams if (!isp2 || enum_value_print_p2(base, value, 0) != 0) { 1384e0ad97e3SJonathan Adams ename = mdb_ctf_enum_name(base, value); 1385e0ad97e3SJonathan Adams if (ename == NULL) { 1386e0ad97e3SJonathan Adams ename = "???"; 1387e0ad97e3SJonathan Adams } 1388e0ad97e3SJonathan Adams mdb_printf("%s", ename); 1389e0ad97e3SJonathan Adams } 1390e0ad97e3SJonathan Adams mdb_printf(")"); 1391e0ad97e3SJonathan Adams (void) mdb_dec_indent(8); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate return (0); 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* 1397cce40297SJonathan Adams * This will only get called if the structure isn't found in any available CTF 1398cce40297SJonathan Adams * data. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14017c478bd9Sstevel@tonic-gate static int 14027c478bd9Sstevel@tonic-gate print_tag(const char *type, const char *name, mdb_ctf_id_t id, 14037c478bd9Sstevel@tonic-gate mdb_ctf_id_t base, ulong_t off, printarg_t *pap) 14047c478bd9Sstevel@tonic-gate { 1405cce40297SJonathan Adams char basename[MDB_SYM_NAMLEN]; 1406cce40297SJonathan Adams 14077c478bd9Sstevel@tonic-gate if (pap->pa_flags & PA_SHOWVAL) 14087c478bd9Sstevel@tonic-gate mdb_printf("; "); 14097c478bd9Sstevel@tonic-gate 1410cce40297SJonathan Adams if (mdb_ctf_type_name(base, basename, sizeof (basename)) != NULL) 1411cce40297SJonathan Adams mdb_printf("<forward declaration of %s>", basename); 1412cce40297SJonathan Adams else 1413cce40297SJonathan Adams mdb_printf("<forward declaration of unknown type>"); 1414cce40297SJonathan Adams 14157c478bd9Sstevel@tonic-gate return (0); 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate static void 14197c478bd9Sstevel@tonic-gate print_hole(printarg_t *pap, int depth, ulong_t off, ulong_t endoff) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate ulong_t bits = endoff - off; 14227c478bd9Sstevel@tonic-gate ulong_t size = bits / NBBY; 14237c478bd9Sstevel@tonic-gate ctf_encoding_t e; 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate static const char *const name = "<<HOLE>>"; 14267c478bd9Sstevel@tonic-gate char type[MDB_SYM_NAMLEN]; 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate int bitfield = 14297c478bd9Sstevel@tonic-gate (off % NBBY != 0 || 14307c478bd9Sstevel@tonic-gate bits % NBBY != 0 || 14317c478bd9Sstevel@tonic-gate size > 8 || 14327c478bd9Sstevel@tonic-gate (size & (size - 1)) != 0); 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate ASSERT(off < endoff); 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate if (bits > NBBY * sizeof (uint64_t)) { 14377c478bd9Sstevel@tonic-gate ulong_t end; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * The hole is larger than the largest integer type. To 14417c478bd9Sstevel@tonic-gate * handle this, we split up the hole at 8-byte-aligned 14427c478bd9Sstevel@tonic-gate * boundaries, recursing to print each subsection. For 14437c478bd9Sstevel@tonic-gate * normal C structures, we'll loop at most twice. 14447c478bd9Sstevel@tonic-gate */ 14457c478bd9Sstevel@tonic-gate for (; off < endoff; off = end) { 14467c478bd9Sstevel@tonic-gate end = P2END(off, NBBY * sizeof (uint64_t)); 14477c478bd9Sstevel@tonic-gate if (end > endoff) 14487c478bd9Sstevel@tonic-gate end = endoff; 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate ASSERT((end - off) <= NBBY * sizeof (uint64_t)); 14517c478bd9Sstevel@tonic-gate print_hole(pap, depth, off, end); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate ASSERT(end == endoff); 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate return; 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate if (bitfield) 14597c478bd9Sstevel@tonic-gate (void) mdb_snprintf(type, sizeof (type), "unsigned"); 14607c478bd9Sstevel@tonic-gate else 14617c478bd9Sstevel@tonic-gate (void) mdb_snprintf(type, sizeof (type), "uint%d_t", bits); 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate if (pap->pa_flags & (PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR)) 14647c478bd9Sstevel@tonic-gate mdb_printf("%*s", (depth + pap->pa_nest) * pap->pa_tab, ""); 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate if (pap->pa_flags & PA_SHOWADDR) { 1467bf5197d8Sjwadams if (off % NBBY == 0) 14687c478bd9Sstevel@tonic-gate mdb_printf("%llx ", pap->pa_addr + off / NBBY); 14697c478bd9Sstevel@tonic-gate else 14707c478bd9Sstevel@tonic-gate mdb_printf("%llx.%lx ", 14717c478bd9Sstevel@tonic-gate pap->pa_addr + off / NBBY, off % NBBY); 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate if (pap->pa_flags & PA_SHOWTYPE) 14757c478bd9Sstevel@tonic-gate mdb_printf("%s ", type); 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate if (pap->pa_flags & PA_SHOWNAME) 14787c478bd9Sstevel@tonic-gate mdb_printf("%s", name); 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate if (bitfield && (pap->pa_flags & PA_SHOWTYPE)) 14817c478bd9Sstevel@tonic-gate mdb_printf(" :%d", bits); 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate mdb_printf("%s ", (pap->pa_flags & PA_SHOWVAL)? " =" : ""); 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate /* 14867c478bd9Sstevel@tonic-gate * We fake up a ctf_encoding_t, and use print_int_val() to print 14877c478bd9Sstevel@tonic-gate * the value. Holes are always processed as unsigned integers. 14887c478bd9Sstevel@tonic-gate */ 14897c478bd9Sstevel@tonic-gate bzero(&e, sizeof (e)); 14907c478bd9Sstevel@tonic-gate e.cte_format = 0; 14917c478bd9Sstevel@tonic-gate e.cte_offset = 0; 14927c478bd9Sstevel@tonic-gate e.cte_bits = bits; 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate if (print_int_val(type, &e, off, pap) != 0) 14957c478bd9Sstevel@tonic-gate mdb_iob_discard(mdb.m_out); 14967c478bd9Sstevel@tonic-gate else 14977c478bd9Sstevel@tonic-gate mdb_iob_puts(mdb.m_out, pap->pa_delim); 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate * The print_close_sou() function is called for each structure or union 15027c478bd9Sstevel@tonic-gate * which has been completed. For structures, we detect and print any holes 15037c478bd9Sstevel@tonic-gate * before printing the closing brace. 15047c478bd9Sstevel@tonic-gate */ 15057c478bd9Sstevel@tonic-gate static void 15067c478bd9Sstevel@tonic-gate print_close_sou(printarg_t *pap, int newdepth) 15077c478bd9Sstevel@tonic-gate { 15087c478bd9Sstevel@tonic-gate int d = newdepth + pap->pa_nest; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate if ((pap->pa_flags & PA_SHOWHOLES) && !pap->pa_holes[d].hi_isunion) { 15117c478bd9Sstevel@tonic-gate ulong_t end = pap->pa_holes[d + 1].hi_offset; 15127c478bd9Sstevel@tonic-gate ulong_t expected = pap->pa_holes[d].hi_offset; 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate if (end < expected) 15157c478bd9Sstevel@tonic-gate print_hole(pap, newdepth + 1, end, expected); 15167c478bd9Sstevel@tonic-gate } 1517cce40297SJonathan Adams /* if the struct is an array element, print a comma after the } */ 1518cce40297SJonathan Adams mdb_printf("%*s}%s\n", d * pap->pa_tab, "", 1519cce40297SJonathan Adams (newdepth == 0 && pap->pa_nest > 0)? "," : ""); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate static printarg_f *const printfuncs[] = { 15237c478bd9Sstevel@tonic-gate print_int, /* CTF_K_INTEGER */ 15247c478bd9Sstevel@tonic-gate print_float, /* CTF_K_FLOAT */ 15257c478bd9Sstevel@tonic-gate print_ptr, /* CTF_K_POINTER */ 15267c478bd9Sstevel@tonic-gate print_array, /* CTF_K_ARRAY */ 15277c478bd9Sstevel@tonic-gate print_ptr, /* CTF_K_FUNCTION */ 15287c478bd9Sstevel@tonic-gate print_sou, /* CTF_K_STRUCT */ 15297c478bd9Sstevel@tonic-gate print_sou, /* CTF_K_UNION */ 15307c478bd9Sstevel@tonic-gate print_enum, /* CTF_K_ENUM */ 15317c478bd9Sstevel@tonic-gate print_tag /* CTF_K_FORWARD */ 15327c478bd9Sstevel@tonic-gate }; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * The elt_print function is used as the mdb_ctf_type_visit callback. For 15367c478bd9Sstevel@tonic-gate * each element, we print an appropriate name prefix and then call the 15377c478bd9Sstevel@tonic-gate * print subroutine for this type class in the array above. 15387c478bd9Sstevel@tonic-gate */ 15397c478bd9Sstevel@tonic-gate static int 1540cce40297SJonathan Adams elt_print(const char *name, mdb_ctf_id_t id, mdb_ctf_id_t base, 1541cce40297SJonathan Adams ulong_t off, int depth, void *data) 15427c478bd9Sstevel@tonic-gate { 1543cce40297SJonathan Adams char type[MDB_SYM_NAMLEN + sizeof (" <<12345678...>>")]; 15447c478bd9Sstevel@tonic-gate int kind, rc, d; 15457c478bd9Sstevel@tonic-gate printarg_t *pap = data; 15467c478bd9Sstevel@tonic-gate 1547838d7172SSebastien Roy for (d = pap->pa_depth - 1; d >= depth; d--) { 1548838d7172SSebastien Roy if (d < pap->pa_nooutdepth) 1549838d7172SSebastien Roy print_close_sou(pap, d); 1550838d7172SSebastien Roy } 1551838d7172SSebastien Roy 1552838d7172SSebastien Roy /* 1553838d7172SSebastien Roy * Reset pa_nooutdepth if we've come back out of the structure we 1554838d7172SSebastien Roy * didn't want to print. 1555838d7172SSebastien Roy */ 1556838d7172SSebastien Roy if (depth <= pap->pa_nooutdepth) 1557838d7172SSebastien Roy pap->pa_nooutdepth = (uint_t)-1; 15587c478bd9Sstevel@tonic-gate 1559838d7172SSebastien Roy if (depth > pap->pa_maxdepth || depth > pap->pa_nooutdepth) 1560bf5197d8Sjwadams return (0); 1561bf5197d8Sjwadams 1562cce40297SJonathan Adams if (!mdb_ctf_type_valid(base) || 15637c478bd9Sstevel@tonic-gate (kind = mdb_ctf_type_kind(base)) == -1) 15647c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 15657c478bd9Sstevel@tonic-gate 1566cce40297SJonathan Adams if (mdb_ctf_type_name(id, type, MDB_SYM_NAMLEN) == NULL) 15677c478bd9Sstevel@tonic-gate (void) strcpy(type, "(?)"); 15687c478bd9Sstevel@tonic-gate 1569cce40297SJonathan Adams if (pap->pa_flags & PA_SHOWBASETYPE) { 1570cce40297SJonathan Adams /* 1571cce40297SJonathan Adams * If basetype is different and informative, concatenate 1572cce40297SJonathan Adams * <<basetype>> (or <<baset...>> if it doesn't fit) 1573cce40297SJonathan Adams * 1574cce40297SJonathan Adams * We just use the end of the buffer to store the type name, and 1575cce40297SJonathan Adams * only connect it up if that's necessary. 1576cce40297SJonathan Adams */ 1577cce40297SJonathan Adams 1578cce40297SJonathan Adams char *type_end = type + strlen(type); 1579cce40297SJonathan Adams char *basetype; 1580cce40297SJonathan Adams size_t sz; 1581cce40297SJonathan Adams 1582cce40297SJonathan Adams (void) strlcat(type, " <<", sizeof (type)); 1583cce40297SJonathan Adams 1584cce40297SJonathan Adams basetype = type + strlen(type); 1585cce40297SJonathan Adams sz = sizeof (type) - (basetype - type); 1586cce40297SJonathan Adams 1587cce40297SJonathan Adams *type_end = '\0'; /* restore the end of type for strcmp() */ 1588cce40297SJonathan Adams 1589cce40297SJonathan Adams if (mdb_ctf_type_name(base, basetype, sz) != NULL && 1590cce40297SJonathan Adams strcmp(basetype, type) != 0 && 1591cce40297SJonathan Adams strcmp(basetype, "struct ") != 0 && 1592cce40297SJonathan Adams strcmp(basetype, "enum ") != 0 && 1593cce40297SJonathan Adams strcmp(basetype, "union ") != 0) { 1594cce40297SJonathan Adams type_end[0] = ' '; /* reconnect */ 1595cce40297SJonathan Adams if (strlcat(type, ">>", sizeof (type)) >= sizeof (type)) 1596cce40297SJonathan Adams (void) strlcpy( 1597cce40297SJonathan Adams type + sizeof (type) - 6, "...>>", 6); 1598cce40297SJonathan Adams } 1599cce40297SJonathan Adams } 1600cce40297SJonathan Adams 16017c478bd9Sstevel@tonic-gate if (pap->pa_flags & PA_SHOWHOLES) { 16027c478bd9Sstevel@tonic-gate ctf_encoding_t e; 16037c478bd9Sstevel@tonic-gate ssize_t nsize; 16047c478bd9Sstevel@tonic-gate ulong_t newoff; 16057c478bd9Sstevel@tonic-gate holeinfo_t *hole; 16067c478bd9Sstevel@tonic-gate int extra = IS_COMPOSITE(kind)? 1 : 0; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate /* 16097c478bd9Sstevel@tonic-gate * grow the hole array, if necessary 16107c478bd9Sstevel@tonic-gate */ 16117c478bd9Sstevel@tonic-gate if (pap->pa_nest + depth + extra >= pap->pa_nholes) { 16127c478bd9Sstevel@tonic-gate int new = MAX(MAX(8, pap->pa_nholes * 2), 16137c478bd9Sstevel@tonic-gate pap->pa_nest + depth + extra + 1); 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate holeinfo_t *nhi = mdb_zalloc( 16167c478bd9Sstevel@tonic-gate sizeof (*nhi) * new, UM_NOSLEEP | UM_GC); 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate bcopy(pap->pa_holes, nhi, 16197c478bd9Sstevel@tonic-gate pap->pa_nholes * sizeof (*nhi)); 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate pap->pa_holes = nhi; 16227c478bd9Sstevel@tonic-gate pap->pa_nholes = new; 16237c478bd9Sstevel@tonic-gate } 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate hole = &pap->pa_holes[depth + pap->pa_nest]; 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate if (depth != 0 && off > hole->hi_offset) 16287c478bd9Sstevel@tonic-gate print_hole(pap, depth, hole->hi_offset, off); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate /* compute the next expected offset */ 16317c478bd9Sstevel@tonic-gate if (kind == CTF_K_INTEGER && 16327c478bd9Sstevel@tonic-gate mdb_ctf_type_encoding(base, &e) == 0) 16337c478bd9Sstevel@tonic-gate newoff = off + e.cte_bits; 16347c478bd9Sstevel@tonic-gate else if ((nsize = mdb_ctf_type_size(base)) >= 0) 16357c478bd9Sstevel@tonic-gate newoff = off + nsize * NBBY; 16367c478bd9Sstevel@tonic-gate else { 16377c478bd9Sstevel@tonic-gate /* something bad happened, disable hole checking */ 16387c478bd9Sstevel@tonic-gate newoff = -1UL; /* ULONG_MAX */ 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate hole->hi_offset = newoff; 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate if (IS_COMPOSITE(kind)) { 16447c478bd9Sstevel@tonic-gate hole->hi_isunion = (kind == CTF_K_UNION); 16457c478bd9Sstevel@tonic-gate hole++; 16467c478bd9Sstevel@tonic-gate hole->hi_offset = off; 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate if (pap->pa_flags & (PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR)) 16517c478bd9Sstevel@tonic-gate mdb_printf("%*s", (depth + pap->pa_nest) * pap->pa_tab, ""); 16527c478bd9Sstevel@tonic-gate 1653cce40297SJonathan Adams if (pap->pa_flags & PA_SHOWADDR) { 1654cce40297SJonathan Adams if (off % NBBY == 0) 1655cce40297SJonathan Adams mdb_printf("%llx ", pap->pa_addr + off / NBBY); 1656cce40297SJonathan Adams else 1657cce40297SJonathan Adams mdb_printf("%llx.%lx ", 1658cce40297SJonathan Adams pap->pa_addr + off / NBBY, off % NBBY); 1659cce40297SJonathan Adams } 16607c478bd9Sstevel@tonic-gate 1661cce40297SJonathan Adams if ((pap->pa_flags & PA_SHOWTYPE)) { 1662cce40297SJonathan Adams mdb_printf("%s", type); 1663cce40297SJonathan Adams /* 1664cce40297SJonathan Adams * We want to avoid printing a trailing space when 1665cce40297SJonathan Adams * dealing with pointers in a structure, so we end 1666cce40297SJonathan Adams * up with: 1667cce40297SJonathan Adams * 1668cce40297SJonathan Adams * label_t *t_onfault = 0 1669cce40297SJonathan Adams * 1670cce40297SJonathan Adams * If depth is zero, always print the trailing space unless 1671cce40297SJonathan Adams * we also have a prefix. 1672cce40297SJonathan Adams */ 1673cce40297SJonathan Adams if (type[strlen(type) - 1] != '*' || 1674cce40297SJonathan Adams (depth == 0 && (!(pap->pa_flags & PA_SHOWNAME) || 1675cce40297SJonathan Adams pap->pa_prefix == NULL))) 1676cce40297SJonathan Adams mdb_printf(" "); 1677cce40297SJonathan Adams } 16787c478bd9Sstevel@tonic-gate 1679cce40297SJonathan Adams if (pap->pa_flags & PA_SHOWNAME) { 1680cce40297SJonathan Adams if (pap->pa_prefix != NULL && depth <= 1) 1681cce40297SJonathan Adams mdb_printf("%s%s", pap->pa_prefix, 1682cce40297SJonathan Adams (depth == 0) ? "" : pap->pa_suffix); 1683cce40297SJonathan Adams mdb_printf("%s", name); 1684cce40297SJonathan Adams } 16857c478bd9Sstevel@tonic-gate 1686cce40297SJonathan Adams if ((pap->pa_flags & PA_SHOWTYPE) && kind == CTF_K_INTEGER) { 1687cce40297SJonathan Adams ctf_encoding_t e; 16887c478bd9Sstevel@tonic-gate 1689cce40297SJonathan Adams if (mdb_ctf_type_encoding(base, &e) == 0) { 1690cce40297SJonathan Adams ulong_t bits = e.cte_bits; 1691cce40297SJonathan Adams ulong_t size = bits / NBBY; 16927c478bd9Sstevel@tonic-gate 1693cce40297SJonathan Adams if (bits % NBBY != 0 || 1694cce40297SJonathan Adams off % NBBY != 0 || 1695cce40297SJonathan Adams size > 8 || 1696cce40297SJonathan Adams size != mdb_ctf_type_size(base)) 1697cce40297SJonathan Adams mdb_printf(" :%d", bits); 16987c478bd9Sstevel@tonic-gate } 1699cce40297SJonathan Adams } 17007c478bd9Sstevel@tonic-gate 1701cce40297SJonathan Adams if (depth != 0 || 1702cce40297SJonathan Adams ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL)) 17037c478bd9Sstevel@tonic-gate mdb_printf("%s ", pap->pa_flags & PA_SHOWVAL ? " =" : ""); 17047c478bd9Sstevel@tonic-gate 1705cce40297SJonathan Adams if (depth == 0 && pap->pa_prefix != NULL) 1706cce40297SJonathan Adams name = pap->pa_prefix; 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate pap->pa_depth = depth; 17098a6a72fdSaf if (kind <= CTF_K_UNKNOWN || kind >= CTF_K_TYPEDEF) { 17108a6a72fdSaf mdb_warn("unknown ctf for %s type %s kind %d\n", 1711cce40297SJonathan Adams name, type, kind); 17128a6a72fdSaf return (-1); 17138a6a72fdSaf } 17147c478bd9Sstevel@tonic-gate rc = printfuncs[kind - 1](type, name, id, base, off, pap); 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate if (rc != 0) 17177c478bd9Sstevel@tonic-gate mdb_iob_discard(mdb.m_out); 17187c478bd9Sstevel@tonic-gate else 17197c478bd9Sstevel@tonic-gate mdb_iob_puts(mdb.m_out, pap->pa_delim); 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate return (rc); 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate 1724bf5197d8Sjwadams /* 1725bf5197d8Sjwadams * Special semantics for pipelines. 1726bf5197d8Sjwadams */ 1727bf5197d8Sjwadams static int 1728bf5197d8Sjwadams pipe_print(mdb_ctf_id_t id, ulong_t off, void *data) 1729bf5197d8Sjwadams { 1730bf5197d8Sjwadams printarg_t *pap = data; 1731bf5197d8Sjwadams ssize_t size; 1732bf5197d8Sjwadams static const char *const fsp[] = { "%#r", "%#r", "%#r", "%#llr" }; 1733bf5197d8Sjwadams uintptr_t value; 1734bf5197d8Sjwadams uintptr_t addr = pap->pa_addr + off / NBBY; 1735bf5197d8Sjwadams mdb_ctf_id_t base; 1736e9f82d69SAlex Reece int enum_value; 1737bf5197d8Sjwadams ctf_encoding_t e; 1738bf5197d8Sjwadams 1739bf5197d8Sjwadams union { 1740bf5197d8Sjwadams uint64_t i8; 1741bf5197d8Sjwadams uint32_t i4; 1742bf5197d8Sjwadams uint16_t i2; 1743bf5197d8Sjwadams uint8_t i1; 1744bf5197d8Sjwadams } u; 1745bf5197d8Sjwadams 1746bf5197d8Sjwadams if (mdb_ctf_type_resolve(id, &base) == -1) { 17473ddcfaddSBryan Cantrill mdb_warn("could not resolve type"); 1748bf5197d8Sjwadams return (-1); 1749bf5197d8Sjwadams } 1750bf5197d8Sjwadams 1751bf5197d8Sjwadams /* 1752bf5197d8Sjwadams * If the user gives -a, then always print out the address of the 1753bf5197d8Sjwadams * member. 1754bf5197d8Sjwadams */ 1755bf5197d8Sjwadams if ((pap->pa_flags & PA_SHOWADDR)) { 1756bf5197d8Sjwadams mdb_printf("%#lr\n", addr); 1757bf5197d8Sjwadams return (0); 1758bf5197d8Sjwadams } 1759bf5197d8Sjwadams 1760bf5197d8Sjwadams again: 1761bf5197d8Sjwadams switch (mdb_ctf_type_kind(base)) { 1762bf5197d8Sjwadams case CTF_K_POINTER: 1763bf5197d8Sjwadams if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, 1764bf5197d8Sjwadams &value, sizeof (value), addr) != sizeof (value)) { 1765bf5197d8Sjwadams mdb_warn("failed to read pointer at %p", addr); 1766bf5197d8Sjwadams return (-1); 1767bf5197d8Sjwadams } 1768bf5197d8Sjwadams mdb_printf("%#lr\n", value); 1769bf5197d8Sjwadams break; 1770bf5197d8Sjwadams 1771bf5197d8Sjwadams case CTF_K_ENUM: 1772e9f82d69SAlex Reece if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &enum_value, 1773e9f82d69SAlex Reece sizeof (enum_value), addr) != sizeof (enum_value)) { 1774e9f82d69SAlex Reece mdb_warn("failed to read enum at %llx", addr); 1775e9f82d69SAlex Reece return (-1); 1776e9f82d69SAlex Reece } 1777e9f82d69SAlex Reece mdb_printf("%#r\n", enum_value); 1778e9f82d69SAlex Reece break; 1779e9f82d69SAlex Reece 1780e9f82d69SAlex Reece case CTF_K_INTEGER: 1781bf5197d8Sjwadams if (mdb_ctf_type_encoding(base, &e) != 0) { 1782e9f82d69SAlex Reece mdb_warn("could not get type encoding\n"); 1783bf5197d8Sjwadams return (-1); 1784bf5197d8Sjwadams } 1785bf5197d8Sjwadams 1786bf5197d8Sjwadams /* 1787bf5197d8Sjwadams * For immediate values, we just print out the value. 1788bf5197d8Sjwadams */ 1789bf5197d8Sjwadams size = e.cte_bits / NBBY; 1790bf5197d8Sjwadams if (size > 8 || (e.cte_bits % NBBY) != 0 || 1791bf5197d8Sjwadams (size & (size - 1)) != 0) { 1792bf5197d8Sjwadams return (print_bitfield(off, pap, &e)); 1793bf5197d8Sjwadams } 1794bf5197d8Sjwadams 1795bf5197d8Sjwadams if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size, 1796bf5197d8Sjwadams addr) != size) { 1797bf5197d8Sjwadams mdb_warn("failed to read %lu bytes at %p", 1798bf5197d8Sjwadams (ulong_t)size, pap->pa_addr); 1799bf5197d8Sjwadams return (-1); 1800bf5197d8Sjwadams } 1801bf5197d8Sjwadams 1802bf5197d8Sjwadams switch (size) { 1803bf5197d8Sjwadams case sizeof (uint8_t): 1804bf5197d8Sjwadams mdb_printf(fsp[0], u.i1); 1805bf5197d8Sjwadams break; 1806bf5197d8Sjwadams case sizeof (uint16_t): 1807bf5197d8Sjwadams mdb_printf(fsp[1], u.i2); 1808bf5197d8Sjwadams break; 1809bf5197d8Sjwadams case sizeof (uint32_t): 1810bf5197d8Sjwadams mdb_printf(fsp[2], u.i4); 1811bf5197d8Sjwadams break; 1812bf5197d8Sjwadams case sizeof (uint64_t): 1813bf5197d8Sjwadams mdb_printf(fsp[3], u.i8); 1814bf5197d8Sjwadams break; 1815bf5197d8Sjwadams } 1816bf5197d8Sjwadams mdb_printf("\n"); 1817bf5197d8Sjwadams break; 1818bf5197d8Sjwadams 1819bf5197d8Sjwadams case CTF_K_FUNCTION: 1820bf5197d8Sjwadams case CTF_K_FLOAT: 1821bf5197d8Sjwadams case CTF_K_ARRAY: 1822bf5197d8Sjwadams case CTF_K_UNKNOWN: 1823bf5197d8Sjwadams case CTF_K_STRUCT: 1824bf5197d8Sjwadams case CTF_K_UNION: 1825bf5197d8Sjwadams case CTF_K_FORWARD: 1826bf5197d8Sjwadams /* 1827bf5197d8Sjwadams * For these types, always print the address of the member 1828bf5197d8Sjwadams */ 1829bf5197d8Sjwadams mdb_printf("%#lr\n", addr); 1830bf5197d8Sjwadams break; 1831bf5197d8Sjwadams 1832bf5197d8Sjwadams default: 1833bf5197d8Sjwadams mdb_warn("unknown type %d", mdb_ctf_type_kind(base)); 1834bf5197d8Sjwadams break; 1835bf5197d8Sjwadams } 1836bf5197d8Sjwadams 1837bf5197d8Sjwadams return (0); 1838bf5197d8Sjwadams } 1839bf5197d8Sjwadams 18407c478bd9Sstevel@tonic-gate static int 18417c478bd9Sstevel@tonic-gate parse_delimiter(char **strp) 18427c478bd9Sstevel@tonic-gate { 18437c478bd9Sstevel@tonic-gate switch (**strp) { 18447c478bd9Sstevel@tonic-gate case '\0': 18457c478bd9Sstevel@tonic-gate return (MEMBER_DELIM_DONE); 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate case '.': 18487c478bd9Sstevel@tonic-gate *strp = *strp + 1; 18497c478bd9Sstevel@tonic-gate return (MEMBER_DELIM_DOT); 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate case '[': 18527c478bd9Sstevel@tonic-gate *strp = *strp + 1; 18537c478bd9Sstevel@tonic-gate return (MEMBER_DELIM_LBR); 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate case '-': 18567c478bd9Sstevel@tonic-gate *strp = *strp + 1; 18577c478bd9Sstevel@tonic-gate if (**strp == '>') { 18587c478bd9Sstevel@tonic-gate *strp = *strp + 1; 18597c478bd9Sstevel@tonic-gate return (MEMBER_DELIM_PTR); 18607c478bd9Sstevel@tonic-gate } 18617c478bd9Sstevel@tonic-gate *strp = *strp - 1; 18627c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 18637c478bd9Sstevel@tonic-gate default: 18647c478bd9Sstevel@tonic-gate return (MEMBER_DELIM_ERR); 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate static int 18697c478bd9Sstevel@tonic-gate deref(printarg_t *pap, size_t size) 18707c478bd9Sstevel@tonic-gate { 18717c478bd9Sstevel@tonic-gate uint32_t a32; 18727c478bd9Sstevel@tonic-gate mdb_tgt_as_t as = pap->pa_as; 18737c478bd9Sstevel@tonic-gate mdb_tgt_addr_t *ap = &pap->pa_addr; 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate if (size == sizeof (mdb_tgt_addr_t)) { 18767c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(mdb.m_target, as, ap, size, *ap) == -1) { 18777c478bd9Sstevel@tonic-gate mdb_warn("could not dereference pointer %llx\n", *ap); 18787c478bd9Sstevel@tonic-gate return (-1); 18797c478bd9Sstevel@tonic-gate } 18807c478bd9Sstevel@tonic-gate } else { 18817c478bd9Sstevel@tonic-gate if (mdb_tgt_aread(mdb.m_target, as, &a32, size, *ap) == -1) { 18827c478bd9Sstevel@tonic-gate mdb_warn("could not dereference pointer %x\n", *ap); 18837c478bd9Sstevel@tonic-gate return (-1); 18847c478bd9Sstevel@tonic-gate } 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate *ap = (mdb_tgt_addr_t)a32; 18877c478bd9Sstevel@tonic-gate } 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate /* 18907c478bd9Sstevel@tonic-gate * We've dereferenced at least once, we must be on the real 18917c478bd9Sstevel@tonic-gate * target. If we were in the immediate target, reset to the real 18927c478bd9Sstevel@tonic-gate * target; it's reset as needed when we return to the print 18937c478bd9Sstevel@tonic-gate * routines. 18947c478bd9Sstevel@tonic-gate */ 18957c478bd9Sstevel@tonic-gate if (pap->pa_tgt == pap->pa_immtgt) 18967c478bd9Sstevel@tonic-gate pap->pa_tgt = pap->pa_realtgt; 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate return (0); 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate static int 19027c478bd9Sstevel@tonic-gate parse_member(printarg_t *pap, const char *str, mdb_ctf_id_t id, 19037c478bd9Sstevel@tonic-gate mdb_ctf_id_t *idp, ulong_t *offp, int *last_deref) 19047c478bd9Sstevel@tonic-gate { 19057c478bd9Sstevel@tonic-gate int delim; 19067c478bd9Sstevel@tonic-gate char member[64]; 19077c478bd9Sstevel@tonic-gate char buf[128]; 19087c478bd9Sstevel@tonic-gate uint_t index; 19097c478bd9Sstevel@tonic-gate char *start = (char *)str; 19107c478bd9Sstevel@tonic-gate char *end; 19117c478bd9Sstevel@tonic-gate ulong_t off = 0; 19127c478bd9Sstevel@tonic-gate mdb_ctf_arinfo_t ar; 19137c478bd9Sstevel@tonic-gate mdb_ctf_id_t rid; 19147c478bd9Sstevel@tonic-gate int kind; 19157c478bd9Sstevel@tonic-gate ssize_t size; 19167c478bd9Sstevel@tonic-gate int non_array = FALSE; 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate /* 19197c478bd9Sstevel@tonic-gate * id always has the unresolved type for printing error messages 19207c478bd9Sstevel@tonic-gate * that include the type; rid always has the resolved type for 19217c478bd9Sstevel@tonic-gate * use in mdb_ctf_* calls. It is possible for this command to fail, 19227c478bd9Sstevel@tonic-gate * however, if the resolved type is in the parent and it is currently 19237c478bd9Sstevel@tonic-gate * unavailable. Note that we also can't print out the name of the 19247c478bd9Sstevel@tonic-gate * type, since that would also rely on looking up the resolved name. 19257c478bd9Sstevel@tonic-gate */ 19267c478bd9Sstevel@tonic-gate if (mdb_ctf_type_resolve(id, &rid) != 0) { 19277c478bd9Sstevel@tonic-gate mdb_warn("failed to resolve type"); 19287c478bd9Sstevel@tonic-gate return (-1); 19297c478bd9Sstevel@tonic-gate } 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate delim = parse_delimiter(&start); 19327c478bd9Sstevel@tonic-gate /* 19337c478bd9Sstevel@tonic-gate * If the user fails to specify an initial delimiter, guess -> for 19347c478bd9Sstevel@tonic-gate * pointer types and . for non-pointer types. 19357c478bd9Sstevel@tonic-gate */ 19367c478bd9Sstevel@tonic-gate if (delim == MEMBER_DELIM_ERR) 19377c478bd9Sstevel@tonic-gate delim = (mdb_ctf_type_kind(rid) == CTF_K_POINTER) ? 19387c478bd9Sstevel@tonic-gate MEMBER_DELIM_PTR : MEMBER_DELIM_DOT; 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate *last_deref = FALSE; 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate while (delim != MEMBER_DELIM_DONE) { 19437c478bd9Sstevel@tonic-gate switch (delim) { 19447c478bd9Sstevel@tonic-gate case MEMBER_DELIM_PTR: 19457c478bd9Sstevel@tonic-gate kind = mdb_ctf_type_kind(rid); 19467c478bd9Sstevel@tonic-gate if (kind != CTF_K_POINTER) { 19477c478bd9Sstevel@tonic-gate mdb_warn("%s is not a pointer type\n", 19487c478bd9Sstevel@tonic-gate mdb_ctf_type_name(id, buf, sizeof (buf))); 19497c478bd9Sstevel@tonic-gate return (-1); 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate size = mdb_ctf_type_size(id); 19537c478bd9Sstevel@tonic-gate if (deref(pap, size) != 0) 19547c478bd9Sstevel@tonic-gate return (-1); 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate (void) mdb_ctf_type_reference(rid, &id); 19577c478bd9Sstevel@tonic-gate (void) mdb_ctf_type_resolve(id, &rid); 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate off = 0; 19607c478bd9Sstevel@tonic-gate break; 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate case MEMBER_DELIM_DOT: 19637c478bd9Sstevel@tonic-gate kind = mdb_ctf_type_kind(rid); 19647c478bd9Sstevel@tonic-gate if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) { 19657c478bd9Sstevel@tonic-gate mdb_warn("%s is not a struct or union type\n", 19667c478bd9Sstevel@tonic-gate mdb_ctf_type_name(id, buf, sizeof (buf))); 19677c478bd9Sstevel@tonic-gate return (-1); 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate break; 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate case MEMBER_DELIM_LBR: 19727c478bd9Sstevel@tonic-gate end = strchr(start, ']'); 19737c478bd9Sstevel@tonic-gate if (end == NULL) { 19747c478bd9Sstevel@tonic-gate mdb_warn("no trailing ']'\n"); 19757c478bd9Sstevel@tonic-gate return (-1); 19767c478bd9Sstevel@tonic-gate } 19777c478bd9Sstevel@tonic-gate 19783b6e0a59SMatt Amdur (void) mdb_snprintf(member, end - start + 1, "%s", 19793b6e0a59SMatt Amdur start); 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate index = mdb_strtoull(member); 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate switch (mdb_ctf_type_kind(rid)) { 19847c478bd9Sstevel@tonic-gate case CTF_K_POINTER: 19857c478bd9Sstevel@tonic-gate size = mdb_ctf_type_size(rid); 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate if (deref(pap, size) != 0) 19887c478bd9Sstevel@tonic-gate return (-1); 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate (void) mdb_ctf_type_reference(rid, &id); 19917c478bd9Sstevel@tonic-gate (void) mdb_ctf_type_resolve(id, &rid); 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate size = mdb_ctf_type_size(id); 19947c478bd9Sstevel@tonic-gate if (size <= 0) { 19957c478bd9Sstevel@tonic-gate mdb_warn("cannot dereference void " 19967c478bd9Sstevel@tonic-gate "type\n"); 19977c478bd9Sstevel@tonic-gate return (-1); 19987c478bd9Sstevel@tonic-gate } 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate pap->pa_addr += index * size; 20017c478bd9Sstevel@tonic-gate off = 0; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate if (index == 0 && non_array) 20047c478bd9Sstevel@tonic-gate *last_deref = TRUE; 20057c478bd9Sstevel@tonic-gate break; 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate case CTF_K_ARRAY: 20087c478bd9Sstevel@tonic-gate (void) mdb_ctf_array_info(rid, &ar); 20097c478bd9Sstevel@tonic-gate 20107c478bd9Sstevel@tonic-gate if (index >= ar.mta_nelems) { 20117c478bd9Sstevel@tonic-gate mdb_warn("index %r is outside of " 20127c478bd9Sstevel@tonic-gate "array bounds [0 .. %r]\n", 20137c478bd9Sstevel@tonic-gate index, ar.mta_nelems - 1); 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate id = ar.mta_contents; 20177c478bd9Sstevel@tonic-gate (void) mdb_ctf_type_resolve(id, &rid); 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate size = mdb_ctf_type_size(id); 20207c478bd9Sstevel@tonic-gate if (size <= 0) { 20217c478bd9Sstevel@tonic-gate mdb_warn("cannot dereference void " 20227c478bd9Sstevel@tonic-gate "type\n"); 20237c478bd9Sstevel@tonic-gate return (-1); 20247c478bd9Sstevel@tonic-gate } 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate pap->pa_addr += index * size; 20277c478bd9Sstevel@tonic-gate off = 0; 20287c478bd9Sstevel@tonic-gate break; 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate default: 20317c478bd9Sstevel@tonic-gate mdb_warn("cannot index into non-array, " 20327c478bd9Sstevel@tonic-gate "non-pointer type\n"); 20337c478bd9Sstevel@tonic-gate return (-1); 20347c478bd9Sstevel@tonic-gate } 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate start = end + 1; 20377c478bd9Sstevel@tonic-gate delim = parse_delimiter(&start); 20387c478bd9Sstevel@tonic-gate continue; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate case MEMBER_DELIM_ERR: 20417c478bd9Sstevel@tonic-gate default: 20427c478bd9Sstevel@tonic-gate mdb_warn("'%c' is not a valid delimiter\n", *start); 20437c478bd9Sstevel@tonic-gate return (-1); 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate *last_deref = FALSE; 20477c478bd9Sstevel@tonic-gate non_array = TRUE; 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate /* 20507c478bd9Sstevel@tonic-gate * Find the end of the member name; assume that a member 20517c478bd9Sstevel@tonic-gate * name is at least one character long. 20527c478bd9Sstevel@tonic-gate */ 20537c478bd9Sstevel@tonic-gate for (end = start + 1; isalnum(*end) || *end == '_'; end++) 20547c478bd9Sstevel@tonic-gate continue; 20557c478bd9Sstevel@tonic-gate 20563b6e0a59SMatt Amdur (void) mdb_snprintf(member, end - start + 1, "%s", start); 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate if (mdb_ctf_member_info(rid, member, &off, &id) != 0) { 20597c478bd9Sstevel@tonic-gate mdb_warn("failed to find member %s of %s", member, 20607c478bd9Sstevel@tonic-gate mdb_ctf_type_name(id, buf, sizeof (buf))); 20617c478bd9Sstevel@tonic-gate return (-1); 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate (void) mdb_ctf_type_resolve(id, &rid); 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate pap->pa_addr += off / NBBY; 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate start = end; 20687c478bd9Sstevel@tonic-gate delim = parse_delimiter(&start); 20697c478bd9Sstevel@tonic-gate } 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate *idp = id; 20727c478bd9Sstevel@tonic-gate *offp = off; 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate return (0); 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate 20772f045fd6SRobert Mustacchi static int 20782f045fd6SRobert Mustacchi cmd_print_tab_common(mdb_tab_cookie_t *mcp, uint_t flags, int argc, 20793b6e0a59SMatt Amdur const mdb_arg_t *argv) 20803b6e0a59SMatt Amdur { 20813b6e0a59SMatt Amdur char tn[MDB_SYM_NAMLEN]; 20823b6e0a59SMatt Amdur char member[64]; 20832f045fd6SRobert Mustacchi int delim, kind; 20843b6e0a59SMatt Amdur int ret = 0; 20853b6e0a59SMatt Amdur mdb_ctf_id_t id, rid; 20863b6e0a59SMatt Amdur mdb_ctf_arinfo_t ar; 20873b6e0a59SMatt Amdur char *start, *end; 20883b6e0a59SMatt Amdur ulong_t dul; 20893b6e0a59SMatt Amdur 20903b6e0a59SMatt Amdur if (argc == 0 && !(flags & DCMD_TAB_SPACE)) 20913b6e0a59SMatt Amdur return (0); 20923b6e0a59SMatt Amdur 20933b6e0a59SMatt Amdur if (argc == 0 && (flags & DCMD_TAB_SPACE)) 20943b6e0a59SMatt Amdur return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_NOPOINT | 20953b6e0a59SMatt Amdur MDB_TABC_NOARRAY)); 20963b6e0a59SMatt Amdur 20973b6e0a59SMatt Amdur if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0) 20983b6e0a59SMatt Amdur return (ret); 20993b6e0a59SMatt Amdur 21003b6e0a59SMatt Amdur if (argc == 1 && (!(flags & DCMD_TAB_SPACE) || ret == 1)) 21013b6e0a59SMatt Amdur return (mdb_tab_complete_type(mcp, tn, MDB_TABC_NOPOINT | 21023b6e0a59SMatt Amdur MDB_TABC_NOARRAY)); 21033b6e0a59SMatt Amdur 21043b6e0a59SMatt Amdur if (argc == 1 && (flags & DCMD_TAB_SPACE)) 21053b6e0a59SMatt Amdur return (mdb_tab_complete_member(mcp, tn, NULL)); 21063b6e0a59SMatt Amdur 21073b6e0a59SMatt Amdur /* 21083b6e0a59SMatt Amdur * This is the reason that tab completion was created. We're going to go 21093b6e0a59SMatt Amdur * along and walk the delimiters until we find something a member that 21103b6e0a59SMatt Amdur * we don't recognize, at which point we'll try and tab complete it. 21113b6e0a59SMatt Amdur * Note that ::print takes multiple args, so this is going to operate on 21123b6e0a59SMatt Amdur * whatever the last arg that we have is. 21133b6e0a59SMatt Amdur */ 21143b6e0a59SMatt Amdur if (mdb_ctf_lookup_by_name(tn, &id) != 0) 21153b6e0a59SMatt Amdur return (1); 21163b6e0a59SMatt Amdur 21173b6e0a59SMatt Amdur (void) mdb_ctf_type_resolve(id, &rid); 21183b6e0a59SMatt Amdur start = (char *)argv[argc-1].a_un.a_str; 21193b6e0a59SMatt Amdur delim = parse_delimiter(&start); 21203b6e0a59SMatt Amdur 21213b6e0a59SMatt Amdur /* 21223b6e0a59SMatt Amdur * If we hit the case where we actually have no delimiters, than we need 21233b6e0a59SMatt Amdur * to make sure that we properly set up the fields the loops would. 21243b6e0a59SMatt Amdur */ 21253b6e0a59SMatt Amdur if (delim == MEMBER_DELIM_DONE) 21263b6e0a59SMatt Amdur (void) mdb_snprintf(member, sizeof (member), "%s", start); 21273b6e0a59SMatt Amdur 21283b6e0a59SMatt Amdur while (delim != MEMBER_DELIM_DONE) { 21293b6e0a59SMatt Amdur switch (delim) { 21303b6e0a59SMatt Amdur case MEMBER_DELIM_PTR: 21313b6e0a59SMatt Amdur kind = mdb_ctf_type_kind(rid); 21323b6e0a59SMatt Amdur if (kind != CTF_K_POINTER) 21333b6e0a59SMatt Amdur return (1); 21343b6e0a59SMatt Amdur 21353b6e0a59SMatt Amdur (void) mdb_ctf_type_reference(rid, &id); 21363b6e0a59SMatt Amdur (void) mdb_ctf_type_resolve(id, &rid); 21373b6e0a59SMatt Amdur break; 21383b6e0a59SMatt Amdur case MEMBER_DELIM_DOT: 21393b6e0a59SMatt Amdur kind = mdb_ctf_type_kind(rid); 21403b6e0a59SMatt Amdur if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 21413b6e0a59SMatt Amdur return (1); 21423b6e0a59SMatt Amdur break; 21433b6e0a59SMatt Amdur case MEMBER_DELIM_LBR: 21443b6e0a59SMatt Amdur end = strchr(start, ']'); 21453b6e0a59SMatt Amdur /* 21463b6e0a59SMatt Amdur * We're not going to try and tab complete the indexes 21473b6e0a59SMatt Amdur * here. So for now, punt on it. Also, we're not going 21483b6e0a59SMatt Amdur * to try and validate you're within the bounds, just 21493b6e0a59SMatt Amdur * that you get the type you asked for. 21503b6e0a59SMatt Amdur */ 21513b6e0a59SMatt Amdur if (end == NULL) 21523b6e0a59SMatt Amdur return (1); 21533b6e0a59SMatt Amdur 21543b6e0a59SMatt Amdur switch (mdb_ctf_type_kind(rid)) { 21553b6e0a59SMatt Amdur case CTF_K_POINTER: 21563b6e0a59SMatt Amdur (void) mdb_ctf_type_reference(rid, &id); 21573b6e0a59SMatt Amdur (void) mdb_ctf_type_resolve(id, &rid); 21583b6e0a59SMatt Amdur break; 21593b6e0a59SMatt Amdur case CTF_K_ARRAY: 21603b6e0a59SMatt Amdur (void) mdb_ctf_array_info(rid, &ar); 21613b6e0a59SMatt Amdur id = ar.mta_contents; 21623b6e0a59SMatt Amdur (void) mdb_ctf_type_resolve(id, &rid); 21633b6e0a59SMatt Amdur break; 21643b6e0a59SMatt Amdur default: 21653b6e0a59SMatt Amdur return (1); 21663b6e0a59SMatt Amdur } 21673b6e0a59SMatt Amdur 21683b6e0a59SMatt Amdur start = end + 1; 21693b6e0a59SMatt Amdur delim = parse_delimiter(&start); 21703b6e0a59SMatt Amdur break; 21713b6e0a59SMatt Amdur case MEMBER_DELIM_ERR: 21723b6e0a59SMatt Amdur default: 21733b6e0a59SMatt Amdur break; 21743b6e0a59SMatt Amdur } 21753b6e0a59SMatt Amdur 21763b6e0a59SMatt Amdur for (end = start + 1; isalnum(*end) || *end == '_'; end++) 21773b6e0a59SMatt Amdur continue; 21783b6e0a59SMatt Amdur 21793b6e0a59SMatt Amdur (void) mdb_snprintf(member, end - start + 1, start); 21803b6e0a59SMatt Amdur 21813b6e0a59SMatt Amdur /* 21823b6e0a59SMatt Amdur * We are going to try to resolve this name as a member. There 21833b6e0a59SMatt Amdur * are a few two different questions that we need to answer. The 21843b6e0a59SMatt Amdur * first is do we recognize this member. The second is are we at 21853b6e0a59SMatt Amdur * the end of the string. If we encounter a member that we don't 21863b6e0a59SMatt Amdur * recognize before the end, then we have to error out and can't 21873b6e0a59SMatt Amdur * complete it. But if there are no more delimiters then we can 21883b6e0a59SMatt Amdur * try and complete it. 21893b6e0a59SMatt Amdur */ 21903b6e0a59SMatt Amdur ret = mdb_ctf_member_info(rid, member, &dul, &id); 21913b6e0a59SMatt Amdur start = end; 21923b6e0a59SMatt Amdur delim = parse_delimiter(&start); 21933b6e0a59SMatt Amdur if (ret != 0 && errno == EMDB_CTFNOMEMB) { 21943b6e0a59SMatt Amdur if (delim != MEMBER_DELIM_DONE) 21953b6e0a59SMatt Amdur return (1); 21963b6e0a59SMatt Amdur continue; 21973b6e0a59SMatt Amdur } else if (ret != 0) 21983b6e0a59SMatt Amdur return (1); 21993b6e0a59SMatt Amdur 22003b6e0a59SMatt Amdur if (delim == MEMBER_DELIM_DONE) 22013b6e0a59SMatt Amdur return (mdb_tab_complete_member_by_id(mcp, rid, 22023b6e0a59SMatt Amdur member)); 22033b6e0a59SMatt Amdur 22043b6e0a59SMatt Amdur (void) mdb_ctf_type_resolve(id, &rid); 22053b6e0a59SMatt Amdur } 22063b6e0a59SMatt Amdur 22073b6e0a59SMatt Amdur /* 22083b6e0a59SMatt Amdur * If we've reached here, then we need to try and tab complete the last 22093b6e0a59SMatt Amdur * field, which is currently member, based on the ctf type id that we 22103b6e0a59SMatt Amdur * already have in rid. 22113b6e0a59SMatt Amdur */ 22123b6e0a59SMatt Amdur return (mdb_tab_complete_member_by_id(mcp, rid, member)); 22133b6e0a59SMatt Amdur } 22143b6e0a59SMatt Amdur 22152f045fd6SRobert Mustacchi int 22162f045fd6SRobert Mustacchi cmd_print_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc, 22172f045fd6SRobert Mustacchi const mdb_arg_t *argv) 22182f045fd6SRobert Mustacchi { 22192f045fd6SRobert Mustacchi int i, dummy; 22202f045fd6SRobert Mustacchi 22212f045fd6SRobert Mustacchi /* 22222f045fd6SRobert Mustacchi * This getopts is only here to make the tab completion work better when 22232f045fd6SRobert Mustacchi * including options in the ::print arguments. None of the values should 22242f045fd6SRobert Mustacchi * be used. This should only be updated with additional arguments, if 22252f045fd6SRobert Mustacchi * they are added to cmd_print. 22262f045fd6SRobert Mustacchi */ 22272f045fd6SRobert Mustacchi i = mdb_getopts(argc, argv, 22282f045fd6SRobert Mustacchi 'a', MDB_OPT_SETBITS, PA_SHOWADDR, &dummy, 22292f045fd6SRobert Mustacchi 'C', MDB_OPT_SETBITS, TRUE, &dummy, 22302f045fd6SRobert Mustacchi 'c', MDB_OPT_UINTPTR, &dummy, 22312f045fd6SRobert Mustacchi 'd', MDB_OPT_SETBITS, PA_INTDEC, &dummy, 22322f045fd6SRobert Mustacchi 'h', MDB_OPT_SETBITS, PA_SHOWHOLES, &dummy, 22332f045fd6SRobert Mustacchi 'i', MDB_OPT_SETBITS, TRUE, &dummy, 22342f045fd6SRobert Mustacchi 'L', MDB_OPT_SETBITS, TRUE, &dummy, 22352f045fd6SRobert Mustacchi 'l', MDB_OPT_UINTPTR, &dummy, 22362f045fd6SRobert Mustacchi 'n', MDB_OPT_SETBITS, PA_NOSYMBOLIC, &dummy, 22372f045fd6SRobert Mustacchi 'p', MDB_OPT_SETBITS, TRUE, &dummy, 22382f045fd6SRobert Mustacchi 's', MDB_OPT_UINTPTR, &dummy, 22392f045fd6SRobert Mustacchi 'T', MDB_OPT_SETBITS, PA_SHOWTYPE | PA_SHOWBASETYPE, &dummy, 22402f045fd6SRobert Mustacchi 't', MDB_OPT_SETBITS, PA_SHOWTYPE, &dummy, 22412f045fd6SRobert Mustacchi 'x', MDB_OPT_SETBITS, PA_INTHEX, &dummy, 22422f045fd6SRobert Mustacchi NULL); 22432f045fd6SRobert Mustacchi 22442f045fd6SRobert Mustacchi argc -= i; 22452f045fd6SRobert Mustacchi argv += i; 22462f045fd6SRobert Mustacchi 22472f045fd6SRobert Mustacchi return (cmd_print_tab_common(mcp, flags, argc, argv)); 22482f045fd6SRobert Mustacchi } 22492f045fd6SRobert Mustacchi 22507c478bd9Sstevel@tonic-gate /* 22517c478bd9Sstevel@tonic-gate * Recursively descend a print a given data structure. We create a struct of 22527c478bd9Sstevel@tonic-gate * the relevant print arguments and then call mdb_ctf_type_visit() to do the 22537c478bd9Sstevel@tonic-gate * traversal, using elt_print() as the callback for each element. 22547c478bd9Sstevel@tonic-gate */ 22557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 22567c478bd9Sstevel@tonic-gate int 22577c478bd9Sstevel@tonic-gate cmd_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 22587c478bd9Sstevel@tonic-gate { 22597c478bd9Sstevel@tonic-gate uintptr_t opt_c = MDB_ARR_NOLIMIT, opt_l = MDB_ARR_NOLIMIT; 22607c478bd9Sstevel@tonic-gate uint_t opt_C = FALSE, opt_L = FALSE, opt_p = FALSE, opt_i = FALSE; 2261bf5197d8Sjwadams uintptr_t opt_s = (uintptr_t)-1ul; 22627c478bd9Sstevel@tonic-gate int uflags = (flags & DCMD_ADDRSPEC) ? PA_SHOWVAL : 0; 22637c478bd9Sstevel@tonic-gate mdb_ctf_id_t id; 22647c478bd9Sstevel@tonic-gate int err = DCMD_OK; 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 22677c478bd9Sstevel@tonic-gate printarg_t pa; 22687c478bd9Sstevel@tonic-gate int d, i; 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate char s_name[MDB_SYM_NAMLEN]; 22717c478bd9Sstevel@tonic-gate mdb_syminfo_t s_info; 22727c478bd9Sstevel@tonic-gate GElf_Sym sym; 22737c478bd9Sstevel@tonic-gate 22743b6e0a59SMatt Amdur /* 22753b6e0a59SMatt Amdur * If a new option is added, make sure the getopts above in 22763b6e0a59SMatt Amdur * cmd_print_tab is also updated. 22773b6e0a59SMatt Amdur */ 22787c478bd9Sstevel@tonic-gate i = mdb_getopts(argc, argv, 22797c478bd9Sstevel@tonic-gate 'a', MDB_OPT_SETBITS, PA_SHOWADDR, &uflags, 22807c478bd9Sstevel@tonic-gate 'C', MDB_OPT_SETBITS, TRUE, &opt_C, 2281cce40297SJonathan Adams 'c', MDB_OPT_UINTPTR, &opt_c, 22827c478bd9Sstevel@tonic-gate 'd', MDB_OPT_SETBITS, PA_INTDEC, &uflags, 22837c478bd9Sstevel@tonic-gate 'h', MDB_OPT_SETBITS, PA_SHOWHOLES, &uflags, 2284cce40297SJonathan Adams 'i', MDB_OPT_SETBITS, TRUE, &opt_i, 22857c478bd9Sstevel@tonic-gate 'L', MDB_OPT_SETBITS, TRUE, &opt_L, 2286cce40297SJonathan Adams 'l', MDB_OPT_UINTPTR, &opt_l, 22877c478bd9Sstevel@tonic-gate 'n', MDB_OPT_SETBITS, PA_NOSYMBOLIC, &uflags, 22887c478bd9Sstevel@tonic-gate 'p', MDB_OPT_SETBITS, TRUE, &opt_p, 2289cce40297SJonathan Adams 's', MDB_OPT_UINTPTR, &opt_s, 2290cce40297SJonathan Adams 'T', MDB_OPT_SETBITS, PA_SHOWTYPE | PA_SHOWBASETYPE, &uflags, 22917c478bd9Sstevel@tonic-gate 't', MDB_OPT_SETBITS, PA_SHOWTYPE, &uflags, 22927c478bd9Sstevel@tonic-gate 'x', MDB_OPT_SETBITS, PA_INTHEX, &uflags, 22937c478bd9Sstevel@tonic-gate NULL); 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate if (uflags & PA_INTHEX) 22967c478bd9Sstevel@tonic-gate uflags &= ~PA_INTDEC; /* -x and -d are mutually exclusive */ 22977c478bd9Sstevel@tonic-gate 2298bf5197d8Sjwadams uflags |= PA_SHOWNAME; 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate if (opt_p && opt_i) { 23017c478bd9Sstevel@tonic-gate mdb_warn("-p and -i options are incompatible\n"); 23027c478bd9Sstevel@tonic-gate return (DCMD_ERR); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate argc -= i; 23067c478bd9Sstevel@tonic-gate argv += i; 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate if (argc != 0 && argv->a_type == MDB_TYPE_STRING) { 23097c478bd9Sstevel@tonic-gate const char *t_name = s_name; 23107c478bd9Sstevel@tonic-gate int ret; 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate if (strchr("+-", argv->a_un.a_str[0]) != NULL) 23137c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate if ((ret = args_to_typename(&argc, &argv, s_name, 23167c478bd9Sstevel@tonic-gate sizeof (s_name))) != 0) 23177c478bd9Sstevel@tonic-gate return (ret); 23187c478bd9Sstevel@tonic-gate 23197c478bd9Sstevel@tonic-gate if (mdb_ctf_lookup_by_name(t_name, &id) != 0) { 23207c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || opt_i || 23217c478bd9Sstevel@tonic-gate addr_to_sym(t, addr, s_name, sizeof (s_name), 2322cce40297SJonathan Adams &sym, &s_info) == NULL || 23237c478bd9Sstevel@tonic-gate mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) { 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate mdb_warn("failed to look up type %s", t_name); 23267c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate } else { 23297c478bd9Sstevel@tonic-gate argc--; 23307c478bd9Sstevel@tonic-gate argv++; 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate } else if (!(flags & DCMD_ADDRSPEC) || opt_i) { 23347c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 23357c478bd9Sstevel@tonic-gate 23367c478bd9Sstevel@tonic-gate } else if (addr_to_sym(t, addr, s_name, sizeof (s_name), 23377c478bd9Sstevel@tonic-gate &sym, &s_info) == NULL) { 23387c478bd9Sstevel@tonic-gate mdb_warn("no symbol information for %a", addr); 23397c478bd9Sstevel@tonic-gate return (DCMD_ERR); 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate } else if (mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) { 23427c478bd9Sstevel@tonic-gate mdb_warn("no type data available for %a [%u]", addr, 23437c478bd9Sstevel@tonic-gate s_info.sym_id); 23447c478bd9Sstevel@tonic-gate return (DCMD_ERR); 23457c478bd9Sstevel@tonic-gate } 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate pa.pa_tgt = mdb.m_target; 23487c478bd9Sstevel@tonic-gate pa.pa_realtgt = pa.pa_tgt; 23497c478bd9Sstevel@tonic-gate pa.pa_immtgt = NULL; 23507c478bd9Sstevel@tonic-gate pa.pa_as = opt_p ? MDB_TGT_AS_PHYS : MDB_TGT_AS_VIRT; 23517c478bd9Sstevel@tonic-gate pa.pa_armemlim = mdb.m_armemlim; 23527c478bd9Sstevel@tonic-gate pa.pa_arstrlim = mdb.m_arstrlim; 23537c478bd9Sstevel@tonic-gate pa.pa_delim = "\n"; 23547c478bd9Sstevel@tonic-gate pa.pa_flags = uflags; 23557c478bd9Sstevel@tonic-gate pa.pa_nest = 0; 23567c478bd9Sstevel@tonic-gate pa.pa_tab = 4; 23577c478bd9Sstevel@tonic-gate pa.pa_prefix = NULL; 23587c478bd9Sstevel@tonic-gate pa.pa_suffix = NULL; 23597c478bd9Sstevel@tonic-gate pa.pa_holes = NULL; 23607c478bd9Sstevel@tonic-gate pa.pa_nholes = 0; 23617c478bd9Sstevel@tonic-gate pa.pa_depth = 0; 2362bf5197d8Sjwadams pa.pa_maxdepth = opt_s; 2363838d7172SSebastien Roy pa.pa_nooutdepth = (uint_t)-1; 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) && !opt_i) 23667c478bd9Sstevel@tonic-gate pa.pa_addr = opt_p ? mdb_get_dot() : addr; 23677c478bd9Sstevel@tonic-gate else 23687c478bd9Sstevel@tonic-gate pa.pa_addr = NULL; 23697c478bd9Sstevel@tonic-gate 23707c478bd9Sstevel@tonic-gate if (opt_i) { 23717c478bd9Sstevel@tonic-gate const char *vargv[2]; 23727c478bd9Sstevel@tonic-gate uintmax_t dot = mdb_get_dot(); 23737c478bd9Sstevel@tonic-gate size_t outsize = mdb_ctf_type_size(id); 23747c478bd9Sstevel@tonic-gate vargv[0] = (const char *)˙ 23757c478bd9Sstevel@tonic-gate vargv[1] = (const char *)&outsize; 23767c478bd9Sstevel@tonic-gate pa.pa_immtgt = mdb_tgt_create(mdb_value_tgt_create, 2377cce40297SJonathan Adams 0, 2, vargv); 23787c478bd9Sstevel@tonic-gate pa.pa_tgt = pa.pa_immtgt; 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate if (opt_c != MDB_ARR_NOLIMIT) 23827c478bd9Sstevel@tonic-gate pa.pa_arstrlim = opt_c; 23837c478bd9Sstevel@tonic-gate if (opt_C) 23847c478bd9Sstevel@tonic-gate pa.pa_arstrlim = MDB_ARR_NOLIMIT; 23857c478bd9Sstevel@tonic-gate if (opt_l != MDB_ARR_NOLIMIT) 23867c478bd9Sstevel@tonic-gate pa.pa_armemlim = opt_l; 23877c478bd9Sstevel@tonic-gate if (opt_L) 23887c478bd9Sstevel@tonic-gate pa.pa_armemlim = MDB_ARR_NOLIMIT; 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate if (argc > 0) { 23917c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 23927c478bd9Sstevel@tonic-gate mdb_ctf_id_t mid; 23937c478bd9Sstevel@tonic-gate int last_deref; 23947c478bd9Sstevel@tonic-gate ulong_t off; 23957c478bd9Sstevel@tonic-gate int kind; 23967c478bd9Sstevel@tonic-gate char buf[MDB_SYM_NAMLEN]; 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate mdb_tgt_t *oldtgt = pa.pa_tgt; 23997c478bd9Sstevel@tonic-gate mdb_tgt_as_t oldas = pa.pa_as; 24007c478bd9Sstevel@tonic-gate mdb_tgt_addr_t oldaddr = pa.pa_addr; 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_STRING) { 24037c478bd9Sstevel@tonic-gate const char *member = argv[i].a_un.a_str; 24047c478bd9Sstevel@tonic-gate mdb_ctf_id_t rid; 24057c478bd9Sstevel@tonic-gate 24067c478bd9Sstevel@tonic-gate if (parse_member(&pa, member, id, &mid, 24077c478bd9Sstevel@tonic-gate &off, &last_deref) != 0) { 24087c478bd9Sstevel@tonic-gate err = DCMD_ABORT; 24097c478bd9Sstevel@tonic-gate goto out; 24107c478bd9Sstevel@tonic-gate } 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate /* 24137c478bd9Sstevel@tonic-gate * If the member string ends with a "[0]" 24147c478bd9Sstevel@tonic-gate * (last_deref * is true) and the type is a 24157c478bd9Sstevel@tonic-gate * structure or union, * print "->" rather 24167c478bd9Sstevel@tonic-gate * than "[0]." in elt_print. 24177c478bd9Sstevel@tonic-gate */ 24187c478bd9Sstevel@tonic-gate (void) mdb_ctf_type_resolve(mid, &rid); 24197c478bd9Sstevel@tonic-gate kind = mdb_ctf_type_kind(rid); 24207c478bd9Sstevel@tonic-gate if (last_deref && IS_SOU(kind)) { 24217c478bd9Sstevel@tonic-gate char *end; 24227c478bd9Sstevel@tonic-gate (void) mdb_snprintf(buf, sizeof (buf), 24237c478bd9Sstevel@tonic-gate "%s", member); 24247c478bd9Sstevel@tonic-gate end = strrchr(buf, '['); 24257c478bd9Sstevel@tonic-gate *end = '\0'; 24267c478bd9Sstevel@tonic-gate pa.pa_suffix = "->"; 24277c478bd9Sstevel@tonic-gate member = &buf[0]; 24287c478bd9Sstevel@tonic-gate } else if (IS_SOU(kind)) { 24297c478bd9Sstevel@tonic-gate pa.pa_suffix = "."; 24307c478bd9Sstevel@tonic-gate } else { 24317c478bd9Sstevel@tonic-gate pa.pa_suffix = ""; 24327c478bd9Sstevel@tonic-gate } 24337c478bd9Sstevel@tonic-gate 24347c478bd9Sstevel@tonic-gate pa.pa_prefix = member; 24357c478bd9Sstevel@tonic-gate } else { 24367c478bd9Sstevel@tonic-gate ulong_t moff; 24377c478bd9Sstevel@tonic-gate 24387c478bd9Sstevel@tonic-gate moff = (ulong_t)argv[i].a_un.a_val; 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate if (mdb_ctf_offset_to_name(id, moff * NBBY, 24417c478bd9Sstevel@tonic-gate buf, sizeof (buf), 0, &mid, &off) == -1) { 24427c478bd9Sstevel@tonic-gate mdb_warn("invalid offset %lx\n", moff); 24437c478bd9Sstevel@tonic-gate err = DCMD_ABORT; 24447c478bd9Sstevel@tonic-gate goto out; 24457c478bd9Sstevel@tonic-gate } 24467c478bd9Sstevel@tonic-gate 24477c478bd9Sstevel@tonic-gate pa.pa_prefix = buf; 24487c478bd9Sstevel@tonic-gate pa.pa_addr += moff - off / NBBY; 24497c478bd9Sstevel@tonic-gate pa.pa_suffix = strlen(buf) == 0 ? "" : "."; 24507c478bd9Sstevel@tonic-gate } 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate off %= NBBY; 2453bf5197d8Sjwadams if (flags & DCMD_PIPE_OUT) { 2454bf5197d8Sjwadams if (pipe_print(mid, off, &pa) != 0) { 2455bf5197d8Sjwadams mdb_warn("failed to print type"); 2456bf5197d8Sjwadams err = DCMD_ERR; 2457bf5197d8Sjwadams goto out; 2458bf5197d8Sjwadams } 2459bf5197d8Sjwadams } else if (off != 0) { 2460cce40297SJonathan Adams mdb_ctf_id_t base; 2461cce40297SJonathan Adams (void) mdb_ctf_type_resolve(mid, &base); 2462cce40297SJonathan Adams 2463cce40297SJonathan Adams if (elt_print("", mid, base, off, 0, 2464cce40297SJonathan Adams &pa) != 0) { 24657c478bd9Sstevel@tonic-gate mdb_warn("failed to print type"); 24667c478bd9Sstevel@tonic-gate err = DCMD_ERR; 24677c478bd9Sstevel@tonic-gate goto out; 24687c478bd9Sstevel@tonic-gate } 24697c478bd9Sstevel@tonic-gate } else { 24707c478bd9Sstevel@tonic-gate if (mdb_ctf_type_visit(mid, elt_print, 24717c478bd9Sstevel@tonic-gate &pa) == -1) { 24727c478bd9Sstevel@tonic-gate mdb_warn("failed to print type"); 24737c478bd9Sstevel@tonic-gate err = DCMD_ERR; 24747c478bd9Sstevel@tonic-gate goto out; 24757c478bd9Sstevel@tonic-gate } 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate for (d = pa.pa_depth - 1; d >= 0; d--) 24787c478bd9Sstevel@tonic-gate print_close_sou(&pa, d); 24797c478bd9Sstevel@tonic-gate } 24807c478bd9Sstevel@tonic-gate 24817c478bd9Sstevel@tonic-gate pa.pa_depth = 0; 24827c478bd9Sstevel@tonic-gate pa.pa_tgt = oldtgt; 24837c478bd9Sstevel@tonic-gate pa.pa_as = oldas; 24847c478bd9Sstevel@tonic-gate pa.pa_addr = oldaddr; 24857c478bd9Sstevel@tonic-gate pa.pa_delim = "\n"; 24867c478bd9Sstevel@tonic-gate } 24877c478bd9Sstevel@tonic-gate 2488bf5197d8Sjwadams } else if (flags & DCMD_PIPE_OUT) { 2489bf5197d8Sjwadams if (pipe_print(id, 0, &pa) != 0) { 2490bf5197d8Sjwadams mdb_warn("failed to print type"); 2491bf5197d8Sjwadams err = DCMD_ERR; 2492bf5197d8Sjwadams goto out; 2493bf5197d8Sjwadams } 24947c478bd9Sstevel@tonic-gate } else { 24957c478bd9Sstevel@tonic-gate if (mdb_ctf_type_visit(id, elt_print, &pa) == -1) { 24967c478bd9Sstevel@tonic-gate mdb_warn("failed to print type"); 24977c478bd9Sstevel@tonic-gate err = DCMD_ERR; 24987c478bd9Sstevel@tonic-gate goto out; 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate for (d = pa.pa_depth - 1; d >= 0; d--) 25027c478bd9Sstevel@tonic-gate print_close_sou(&pa, d); 25037c478bd9Sstevel@tonic-gate } 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate mdb_set_dot(addr + mdb_ctf_type_size(id)); 25067c478bd9Sstevel@tonic-gate err = DCMD_OK; 25077c478bd9Sstevel@tonic-gate out: 25087c478bd9Sstevel@tonic-gate if (pa.pa_immtgt) 25097c478bd9Sstevel@tonic-gate mdb_tgt_destroy(pa.pa_immtgt); 25107c478bd9Sstevel@tonic-gate return (err); 25117c478bd9Sstevel@tonic-gate } 25127c478bd9Sstevel@tonic-gate 25137c478bd9Sstevel@tonic-gate void 25147c478bd9Sstevel@tonic-gate print_help(void) 25157c478bd9Sstevel@tonic-gate { 2516cce40297SJonathan Adams mdb_printf( 2517cce40297SJonathan Adams "-a show address of object\n" 25187c478bd9Sstevel@tonic-gate "-C unlimit the length of character arrays\n" 2519cce40297SJonathan Adams "-c limit limit the length of character arrays\n" 25207c478bd9Sstevel@tonic-gate "-d output values in decimal\n" 25217c478bd9Sstevel@tonic-gate "-h print holes in structures\n" 2522cce40297SJonathan Adams "-i interpret address as data of the given type\n" 25237c478bd9Sstevel@tonic-gate "-L unlimit the length of standard arrays\n" 2524cce40297SJonathan Adams "-l limit limit the length of standard arrays\n" 2525cace7e23Seschrock "-n don't print pointers as symbol offsets\n" 25267c478bd9Sstevel@tonic-gate "-p interpret address as a physical memory address\n" 2527cce40297SJonathan Adams "-s depth limit the recursion depth\n" 2528cce40297SJonathan Adams "-T show type and <<base type>> of object\n" 25297c478bd9Sstevel@tonic-gate "-t show type of object\n" 25307c478bd9Sstevel@tonic-gate "-x output values in hexadecimal\n" 25317c478bd9Sstevel@tonic-gate "\n" 25327c478bd9Sstevel@tonic-gate "type may be omitted if the C type of addr can be inferred.\n" 25337c478bd9Sstevel@tonic-gate "\n" 25347c478bd9Sstevel@tonic-gate "Members may be specified with standard C syntax using the\n" 25357c478bd9Sstevel@tonic-gate "array indexing operator \"[index]\", structure member\n" 25367c478bd9Sstevel@tonic-gate "operator \".\", or structure pointer operator \"->\".\n" 25377c478bd9Sstevel@tonic-gate "\n" 25387c478bd9Sstevel@tonic-gate "Offsets must use the $[ expression ] syntax\n"); 25397c478bd9Sstevel@tonic-gate } 25403ddcfaddSBryan Cantrill 25413ddcfaddSBryan Cantrill static int 25423ddcfaddSBryan Cantrill printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt, 25433ddcfaddSBryan Cantrill boolean_t sign) 25443ddcfaddSBryan Cantrill { 25453ddcfaddSBryan Cantrill ssize_t size; 25463ddcfaddSBryan Cantrill mdb_ctf_id_t base; 25473ddcfaddSBryan Cantrill ctf_encoding_t e; 25483ddcfaddSBryan Cantrill 25493ddcfaddSBryan Cantrill union { 25503ddcfaddSBryan Cantrill uint64_t ui8; 25513ddcfaddSBryan Cantrill uint32_t ui4; 25523ddcfaddSBryan Cantrill uint16_t ui2; 25533ddcfaddSBryan Cantrill uint8_t ui1; 25543ddcfaddSBryan Cantrill int64_t i8; 25553ddcfaddSBryan Cantrill int32_t i4; 25563ddcfaddSBryan Cantrill int16_t i2; 25573ddcfaddSBryan Cantrill int8_t i1; 25583ddcfaddSBryan Cantrill } u; 25593ddcfaddSBryan Cantrill 25603ddcfaddSBryan Cantrill if (mdb_ctf_type_resolve(id, &base) == -1) { 25613ddcfaddSBryan Cantrill mdb_warn("could not resolve type"); 25623ddcfaddSBryan Cantrill return (DCMD_ABORT); 25633ddcfaddSBryan Cantrill } 25643ddcfaddSBryan Cantrill 256538ce19d2SJosef 'Jeff' Sipek switch (mdb_ctf_type_kind(base)) { 256638ce19d2SJosef 'Jeff' Sipek case CTF_K_ENUM: 256738ce19d2SJosef 'Jeff' Sipek e.cte_format = CTF_INT_SIGNED; 256838ce19d2SJosef 'Jeff' Sipek e.cte_offset = 0; 256938ce19d2SJosef 'Jeff' Sipek e.cte_bits = mdb_ctf_type_size(id) * NBBY; 257038ce19d2SJosef 'Jeff' Sipek break; 257138ce19d2SJosef 'Jeff' Sipek case CTF_K_INTEGER: 257238ce19d2SJosef 'Jeff' Sipek if (mdb_ctf_type_encoding(base, &e) != 0) { 257338ce19d2SJosef 'Jeff' Sipek mdb_warn("could not get type encoding"); 257438ce19d2SJosef 'Jeff' Sipek return (DCMD_ABORT); 257538ce19d2SJosef 'Jeff' Sipek } 257638ce19d2SJosef 'Jeff' Sipek break; 257738ce19d2SJosef 'Jeff' Sipek default: 257838ce19d2SJosef 'Jeff' Sipek mdb_warn("expected integer type\n"); 257938ce19d2SJosef 'Jeff' Sipek return (DCMD_ABORT); 25803ddcfaddSBryan Cantrill } 25813ddcfaddSBryan Cantrill 25823ddcfaddSBryan Cantrill if (sign) 25833ddcfaddSBryan Cantrill sign = e.cte_format & CTF_INT_SIGNED; 25843ddcfaddSBryan Cantrill 25853ddcfaddSBryan Cantrill size = e.cte_bits / NBBY; 25863ddcfaddSBryan Cantrill 25873ddcfaddSBryan Cantrill /* 25883ddcfaddSBryan Cantrill * Check to see if our life has been complicated by the presence of 25893ddcfaddSBryan Cantrill * a bitfield. If it has, we will print it using logic that is only 25903ddcfaddSBryan Cantrill * slightly different than that found in print_bitfield(), above. (In 25913ddcfaddSBryan Cantrill * particular, see the comments there for an explanation of the 25923ddcfaddSBryan Cantrill * endianness differences in this code.) 25933ddcfaddSBryan Cantrill */ 25943ddcfaddSBryan Cantrill if (size > 8 || (e.cte_bits % NBBY) != 0 || 25953ddcfaddSBryan Cantrill (size & (size - 1)) != 0) { 25963ddcfaddSBryan Cantrill uint64_t mask = (1ULL << e.cte_bits) - 1; 25973ddcfaddSBryan Cantrill uint64_t value = 0; 25983ddcfaddSBryan Cantrill uint8_t *buf = (uint8_t *)&value; 25993ddcfaddSBryan Cantrill uint8_t shift; 26003ddcfaddSBryan Cantrill 26013ddcfaddSBryan Cantrill /* 26023ddcfaddSBryan Cantrill * Round our size up one byte. 26033ddcfaddSBryan Cantrill */ 26043ddcfaddSBryan Cantrill size = (e.cte_bits + (NBBY - 1)) / NBBY; 26053ddcfaddSBryan Cantrill 26063ddcfaddSBryan Cantrill if (e.cte_bits > sizeof (value) * NBBY - 1) { 26073ddcfaddSBryan Cantrill mdb_printf("invalid bitfield size %u", e.cte_bits); 26083ddcfaddSBryan Cantrill return (DCMD_ABORT); 26093ddcfaddSBryan Cantrill } 26103ddcfaddSBryan Cantrill 26113ddcfaddSBryan Cantrill #ifdef _BIG_ENDIAN 26123ddcfaddSBryan Cantrill buf += sizeof (value) - size; 26133ddcfaddSBryan Cantrill off += e.cte_bits; 26143ddcfaddSBryan Cantrill #endif 26153ddcfaddSBryan Cantrill 26163ddcfaddSBryan Cantrill if (mdb_vread(buf, size, addr) == -1) { 26173ddcfaddSBryan Cantrill mdb_warn("failed to read %lu bytes at %p", size, addr); 26183ddcfaddSBryan Cantrill return (DCMD_ERR); 26193ddcfaddSBryan Cantrill } 26203ddcfaddSBryan Cantrill 26213ddcfaddSBryan Cantrill shift = off % NBBY; 26223ddcfaddSBryan Cantrill #ifdef _BIG_ENDIAN 26233ddcfaddSBryan Cantrill shift = NBBY - shift; 26243ddcfaddSBryan Cantrill #endif 26253ddcfaddSBryan Cantrill 26263ddcfaddSBryan Cantrill /* 26273ddcfaddSBryan Cantrill * If we have a bit offset within the byte, shift it down. 26283ddcfaddSBryan Cantrill */ 26293ddcfaddSBryan Cantrill if (off % NBBY != 0) 26303ddcfaddSBryan Cantrill value >>= shift; 26313ddcfaddSBryan Cantrill value &= mask; 26323ddcfaddSBryan Cantrill 26333ddcfaddSBryan Cantrill if (sign) { 26343ddcfaddSBryan Cantrill int sshift = sizeof (value) * NBBY - e.cte_bits; 26353ddcfaddSBryan Cantrill value = ((int64_t)value << sshift) >> sshift; 26363ddcfaddSBryan Cantrill } 26373ddcfaddSBryan Cantrill 26383ddcfaddSBryan Cantrill mdb_printf(fmt, value); 26393ddcfaddSBryan Cantrill return (0); 26403ddcfaddSBryan Cantrill } 26413ddcfaddSBryan Cantrill 26423ddcfaddSBryan Cantrill if (mdb_vread(&u.i8, size, addr) == -1) { 26433ddcfaddSBryan Cantrill mdb_warn("failed to read %lu bytes at %p", (ulong_t)size, addr); 26443ddcfaddSBryan Cantrill return (DCMD_ERR); 26453ddcfaddSBryan Cantrill } 26463ddcfaddSBryan Cantrill 26473ddcfaddSBryan Cantrill switch (size) { 26483ddcfaddSBryan Cantrill case sizeof (uint8_t): 26493ddcfaddSBryan Cantrill mdb_printf(fmt, (uint64_t)(sign ? u.i1 : u.ui1)); 26503ddcfaddSBryan Cantrill break; 26513ddcfaddSBryan Cantrill case sizeof (uint16_t): 26523ddcfaddSBryan Cantrill mdb_printf(fmt, (uint64_t)(sign ? u.i2 : u.ui2)); 26533ddcfaddSBryan Cantrill break; 26543ddcfaddSBryan Cantrill case sizeof (uint32_t): 26553ddcfaddSBryan Cantrill mdb_printf(fmt, (uint64_t)(sign ? u.i4 : u.ui4)); 26563ddcfaddSBryan Cantrill break; 26573ddcfaddSBryan Cantrill case sizeof (uint64_t): 26583ddcfaddSBryan Cantrill mdb_printf(fmt, (uint64_t)(sign ? u.i8 : u.ui8)); 26593ddcfaddSBryan Cantrill break; 26603ddcfaddSBryan Cantrill } 26613ddcfaddSBryan Cantrill 26623ddcfaddSBryan Cantrill return (0); 26633ddcfaddSBryan Cantrill } 26643ddcfaddSBryan Cantrill 26653ddcfaddSBryan Cantrill static int 26663ddcfaddSBryan Cantrill printf_int(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt) 26673ddcfaddSBryan Cantrill { 26683ddcfaddSBryan Cantrill return (printf_signed(id, addr, off, fmt, B_TRUE)); 26693ddcfaddSBryan Cantrill } 26703ddcfaddSBryan Cantrill 26713ddcfaddSBryan Cantrill static int 26723ddcfaddSBryan Cantrill printf_uint(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt) 26733ddcfaddSBryan Cantrill { 26743ddcfaddSBryan Cantrill return (printf_signed(id, addr, off, fmt, B_FALSE)); 26753ddcfaddSBryan Cantrill } 26763ddcfaddSBryan Cantrill 26773ddcfaddSBryan Cantrill /*ARGSUSED*/ 26783ddcfaddSBryan Cantrill static int 26793ddcfaddSBryan Cantrill printf_uint32(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt) 26803ddcfaddSBryan Cantrill { 26813ddcfaddSBryan Cantrill mdb_ctf_id_t base; 26823ddcfaddSBryan Cantrill ctf_encoding_t e; 26833ddcfaddSBryan Cantrill uint32_t value; 26843ddcfaddSBryan Cantrill 26853ddcfaddSBryan Cantrill if (mdb_ctf_type_resolve(id, &base) == -1) { 26863ddcfaddSBryan Cantrill mdb_warn("could not resolve type\n"); 26873ddcfaddSBryan Cantrill return (DCMD_ABORT); 26883ddcfaddSBryan Cantrill } 26893ddcfaddSBryan Cantrill 26903ddcfaddSBryan Cantrill if (mdb_ctf_type_kind(base) != CTF_K_INTEGER || 26913ddcfaddSBryan Cantrill mdb_ctf_type_encoding(base, &e) != 0 || 26923ddcfaddSBryan Cantrill e.cte_bits / NBBY != sizeof (value)) { 26933ddcfaddSBryan Cantrill mdb_warn("expected 32-bit integer type\n"); 26943ddcfaddSBryan Cantrill return (DCMD_ABORT); 26953ddcfaddSBryan Cantrill } 26963ddcfaddSBryan Cantrill 26973ddcfaddSBryan Cantrill if (mdb_vread(&value, sizeof (value), addr) == -1) { 26983ddcfaddSBryan Cantrill mdb_warn("failed to read 32-bit value at %p", addr); 26993ddcfaddSBryan Cantrill return (DCMD_ERR); 27003ddcfaddSBryan Cantrill } 27013ddcfaddSBryan Cantrill 27023ddcfaddSBryan Cantrill mdb_printf(fmt, value); 27033ddcfaddSBryan Cantrill 27043ddcfaddSBryan Cantrill return (0); 27053ddcfaddSBryan Cantrill } 27063ddcfaddSBryan Cantrill 27073ddcfaddSBryan Cantrill /*ARGSUSED*/ 27083ddcfaddSBryan Cantrill static int 27093ddcfaddSBryan Cantrill printf_ptr(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt) 27103ddcfaddSBryan Cantrill { 27113ddcfaddSBryan Cantrill uintptr_t value; 27123ddcfaddSBryan Cantrill mdb_ctf_id_t base; 27133ddcfaddSBryan Cantrill 27143ddcfaddSBryan Cantrill if (mdb_ctf_type_resolve(id, &base) == -1) { 27153ddcfaddSBryan Cantrill mdb_warn("could not resolve type\n"); 27163ddcfaddSBryan Cantrill return (DCMD_ABORT); 27173ddcfaddSBryan Cantrill } 27183ddcfaddSBryan Cantrill 27193ddcfaddSBryan Cantrill if (mdb_ctf_type_kind(base) != CTF_K_POINTER) { 27203ddcfaddSBryan Cantrill mdb_warn("expected pointer type\n"); 27213ddcfaddSBryan Cantrill return (DCMD_ABORT); 27223ddcfaddSBryan Cantrill } 27233ddcfaddSBryan Cantrill 27243ddcfaddSBryan Cantrill if (mdb_vread(&value, sizeof (value), addr) == -1) { 27253ddcfaddSBryan Cantrill mdb_warn("failed to read pointer at %llx", addr); 27263ddcfaddSBryan Cantrill return (DCMD_ERR); 27273ddcfaddSBryan Cantrill } 27283ddcfaddSBryan Cantrill 27293ddcfaddSBryan Cantrill mdb_printf(fmt, value); 27303ddcfaddSBryan Cantrill 27313ddcfaddSBryan Cantrill return (0); 27323ddcfaddSBryan Cantrill } 27333ddcfaddSBryan Cantrill 27343ddcfaddSBryan Cantrill /*ARGSUSED*/ 27353ddcfaddSBryan Cantrill static int 27363ddcfaddSBryan Cantrill printf_string(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt) 27373ddcfaddSBryan Cantrill { 27383ddcfaddSBryan Cantrill mdb_ctf_id_t base; 27393ddcfaddSBryan Cantrill mdb_ctf_arinfo_t r; 27403ddcfaddSBryan Cantrill char buf[1024]; 27413ddcfaddSBryan Cantrill ssize_t size; 27423ddcfaddSBryan Cantrill 27433ddcfaddSBryan Cantrill if (mdb_ctf_type_resolve(id, &base) == -1) { 27443ddcfaddSBryan Cantrill mdb_warn("could not resolve type"); 27453ddcfaddSBryan Cantrill return (DCMD_ABORT); 27463ddcfaddSBryan Cantrill } 27473ddcfaddSBryan Cantrill 27483ddcfaddSBryan Cantrill if (mdb_ctf_type_kind(base) == CTF_K_POINTER) { 27493ddcfaddSBryan Cantrill uintptr_t value; 27503ddcfaddSBryan Cantrill 27513ddcfaddSBryan Cantrill if (mdb_vread(&value, sizeof (value), addr) == -1) { 27523ddcfaddSBryan Cantrill mdb_warn("failed to read pointer at %llx", addr); 27533ddcfaddSBryan Cantrill return (DCMD_ERR); 27543ddcfaddSBryan Cantrill } 27553ddcfaddSBryan Cantrill 27563ddcfaddSBryan Cantrill if (mdb_readstr(buf, sizeof (buf) - 1, value) < 0) { 27573ddcfaddSBryan Cantrill mdb_warn("failed to read string at %llx", value); 27583ddcfaddSBryan Cantrill return (DCMD_ERR); 27593ddcfaddSBryan Cantrill } 27603ddcfaddSBryan Cantrill 27613ddcfaddSBryan Cantrill mdb_printf(fmt, buf); 27623ddcfaddSBryan Cantrill return (0); 27633ddcfaddSBryan Cantrill } 27643ddcfaddSBryan Cantrill 276538ce19d2SJosef 'Jeff' Sipek if (mdb_ctf_type_kind(base) == CTF_K_ENUM) { 276638ce19d2SJosef 'Jeff' Sipek const char *strval; 276738ce19d2SJosef 'Jeff' Sipek int value; 276838ce19d2SJosef 'Jeff' Sipek 276938ce19d2SJosef 'Jeff' Sipek if (mdb_vread(&value, sizeof (value), addr) == -1) { 277038ce19d2SJosef 'Jeff' Sipek mdb_warn("failed to read pointer at %llx", addr); 277138ce19d2SJosef 'Jeff' Sipek return (DCMD_ERR); 277238ce19d2SJosef 'Jeff' Sipek } 277338ce19d2SJosef 'Jeff' Sipek 277438ce19d2SJosef 'Jeff' Sipek if ((strval = mdb_ctf_enum_name(id, value))) { 277538ce19d2SJosef 'Jeff' Sipek mdb_printf(fmt, strval); 277638ce19d2SJosef 'Jeff' Sipek } else { 277738ce19d2SJosef 'Jeff' Sipek (void) mdb_snprintf(buf, sizeof (buf), "<%d>", value); 277838ce19d2SJosef 'Jeff' Sipek mdb_printf(fmt, buf); 277938ce19d2SJosef 'Jeff' Sipek } 278038ce19d2SJosef 'Jeff' Sipek 278138ce19d2SJosef 'Jeff' Sipek return (0); 278238ce19d2SJosef 'Jeff' Sipek } 278338ce19d2SJosef 'Jeff' Sipek 27843ddcfaddSBryan Cantrill if (mdb_ctf_type_kind(base) != CTF_K_ARRAY) { 27853ddcfaddSBryan Cantrill mdb_warn("exepected pointer or array type\n"); 27863ddcfaddSBryan Cantrill return (DCMD_ABORT); 27873ddcfaddSBryan Cantrill } 27883ddcfaddSBryan Cantrill 27893ddcfaddSBryan Cantrill if (mdb_ctf_array_info(base, &r) == -1 || 27903ddcfaddSBryan Cantrill mdb_ctf_type_resolve(r.mta_contents, &base) == -1 || 27913ddcfaddSBryan Cantrill (size = mdb_ctf_type_size(base)) == -1) { 27923ddcfaddSBryan Cantrill mdb_warn("can't determine array type"); 27933ddcfaddSBryan Cantrill return (DCMD_ABORT); 27943ddcfaddSBryan Cantrill } 27953ddcfaddSBryan Cantrill 27963ddcfaddSBryan Cantrill if (size != 1) { 27973ddcfaddSBryan Cantrill mdb_warn("string format specifier requires " 27983ddcfaddSBryan Cantrill "an array of characters\n"); 27993ddcfaddSBryan Cantrill return (DCMD_ABORT); 28003ddcfaddSBryan Cantrill } 28013ddcfaddSBryan Cantrill 28023ddcfaddSBryan Cantrill bzero(buf, sizeof (buf)); 28033ddcfaddSBryan Cantrill 28043ddcfaddSBryan Cantrill if (mdb_vread(buf, MIN(r.mta_nelems, sizeof (buf) - 1), addr) == -1) { 28053ddcfaddSBryan Cantrill mdb_warn("failed to read array at %p", addr); 28063ddcfaddSBryan Cantrill return (DCMD_ERR); 28073ddcfaddSBryan Cantrill } 28083ddcfaddSBryan Cantrill 28093ddcfaddSBryan Cantrill mdb_printf(fmt, buf); 28103ddcfaddSBryan Cantrill 28113ddcfaddSBryan Cantrill return (0); 28123ddcfaddSBryan Cantrill } 28133ddcfaddSBryan Cantrill 28143ddcfaddSBryan Cantrill /*ARGSUSED*/ 28153ddcfaddSBryan Cantrill static int 28163ddcfaddSBryan Cantrill printf_ipv6(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt) 28173ddcfaddSBryan Cantrill { 28183ddcfaddSBryan Cantrill mdb_ctf_id_t base; 28193ddcfaddSBryan Cantrill mdb_ctf_id_t ipv6_type, ipv6_base; 28203ddcfaddSBryan Cantrill in6_addr_t ipv6; 28213ddcfaddSBryan Cantrill 28223ddcfaddSBryan Cantrill if (mdb_ctf_lookup_by_name("in6_addr_t", &ipv6_type) == -1) { 28233ddcfaddSBryan Cantrill mdb_warn("could not resolve in6_addr_t type\n"); 28243ddcfaddSBryan Cantrill return (DCMD_ABORT); 28253ddcfaddSBryan Cantrill } 28263ddcfaddSBryan Cantrill 28273ddcfaddSBryan Cantrill if (mdb_ctf_type_resolve(id, &base) == -1) { 28283ddcfaddSBryan Cantrill mdb_warn("could not resolve type\n"); 28293ddcfaddSBryan Cantrill return (DCMD_ABORT); 28303ddcfaddSBryan Cantrill } 28313ddcfaddSBryan Cantrill 28323ddcfaddSBryan Cantrill if (mdb_ctf_type_resolve(ipv6_type, &ipv6_base) == -1) { 28333ddcfaddSBryan Cantrill mdb_warn("could not resolve in6_addr_t type\n"); 28343ddcfaddSBryan Cantrill return (DCMD_ABORT); 28353ddcfaddSBryan Cantrill } 28363ddcfaddSBryan Cantrill 28373ddcfaddSBryan Cantrill if (mdb_ctf_type_cmp(base, ipv6_base) != 0) { 28383ddcfaddSBryan Cantrill mdb_warn("requires argument of type in6_addr_t\n"); 28393ddcfaddSBryan Cantrill return (DCMD_ABORT); 28403ddcfaddSBryan Cantrill } 28413ddcfaddSBryan Cantrill 28423ddcfaddSBryan Cantrill if (mdb_vread(&ipv6, sizeof (ipv6), addr) == -1) { 28433ddcfaddSBryan Cantrill mdb_warn("couldn't read in6_addr_t at %p", addr); 28443ddcfaddSBryan Cantrill return (DCMD_ERR); 28453ddcfaddSBryan Cantrill } 28463ddcfaddSBryan Cantrill 28473ddcfaddSBryan Cantrill mdb_printf(fmt, &ipv6); 28483ddcfaddSBryan Cantrill 28493ddcfaddSBryan Cantrill return (0); 28503ddcfaddSBryan Cantrill } 28513ddcfaddSBryan Cantrill 28523ddcfaddSBryan Cantrill /* 28533ddcfaddSBryan Cantrill * To validate the format string specified to ::printf, we run the format 28543ddcfaddSBryan Cantrill * string through a very simple state machine that restricts us to a subset 28553ddcfaddSBryan Cantrill * of mdb_printf() functionality. 28563ddcfaddSBryan Cantrill */ 28573ddcfaddSBryan Cantrill enum { 28583ddcfaddSBryan Cantrill PRINTF_NOFMT = 1, /* no current format specifier */ 28593ddcfaddSBryan Cantrill PRINTF_PERC, /* processed '%' */ 28603ddcfaddSBryan Cantrill PRINTF_FMT, /* processing format specifier */ 28613ddcfaddSBryan Cantrill PRINTF_LEFT, /* processed '-', expecting width */ 28623ddcfaddSBryan Cantrill PRINTF_WIDTH, /* processing width */ 28633ddcfaddSBryan Cantrill PRINTF_QUES /* processed '?', expecting format */ 28643ddcfaddSBryan Cantrill }; 28653ddcfaddSBryan Cantrill 28662f045fd6SRobert Mustacchi int 28672f045fd6SRobert Mustacchi cmd_printf_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc, 28682f045fd6SRobert Mustacchi const mdb_arg_t *argv) 28692f045fd6SRobert Mustacchi { 28702f045fd6SRobert Mustacchi int ii; 28712f045fd6SRobert Mustacchi char *f; 28722f045fd6SRobert Mustacchi 28732f045fd6SRobert Mustacchi /* 28742f045fd6SRobert Mustacchi * If argc doesn't have more than what should be the format string, 28752f045fd6SRobert Mustacchi * ignore it. 28762f045fd6SRobert Mustacchi */ 28772f045fd6SRobert Mustacchi if (argc <= 1) 28782f045fd6SRobert Mustacchi return (0); 28792f045fd6SRobert Mustacchi 28802f045fd6SRobert Mustacchi /* 28812f045fd6SRobert Mustacchi * Because we aren't leveraging the lex and yacc engine, we have to 28822f045fd6SRobert Mustacchi * manually walk the arguments to find both the first and last 28832f045fd6SRobert Mustacchi * open/close quote of the format string. 28842f045fd6SRobert Mustacchi */ 28852f045fd6SRobert Mustacchi f = strchr(argv[0].a_un.a_str, '"'); 28862f045fd6SRobert Mustacchi if (f == NULL) 28872f045fd6SRobert Mustacchi return (0); 28882f045fd6SRobert Mustacchi 28892f045fd6SRobert Mustacchi f = strchr(f + 1, '"'); 28902f045fd6SRobert Mustacchi if (f != NULL) { 28912f045fd6SRobert Mustacchi ii = 0; 28922f045fd6SRobert Mustacchi } else { 28932f045fd6SRobert Mustacchi for (ii = 1; ii < argc; ii++) { 28942f045fd6SRobert Mustacchi if (argv[ii].a_type != MDB_TYPE_STRING) 28952f045fd6SRobert Mustacchi continue; 28962f045fd6SRobert Mustacchi f = strchr(argv[ii].a_un.a_str, '"'); 28972f045fd6SRobert Mustacchi if (f != NULL) 28982f045fd6SRobert Mustacchi break; 28992f045fd6SRobert Mustacchi } 29002f045fd6SRobert Mustacchi /* Never found */ 29012f045fd6SRobert Mustacchi if (ii == argc) 29022f045fd6SRobert Mustacchi return (0); 29032f045fd6SRobert Mustacchi } 29042f045fd6SRobert Mustacchi 29052f045fd6SRobert Mustacchi ii++; 29062f045fd6SRobert Mustacchi argc -= ii; 29072f045fd6SRobert Mustacchi argv += ii; 29082f045fd6SRobert Mustacchi 29092f045fd6SRobert Mustacchi return (cmd_print_tab_common(mcp, flags, argc, argv)); 29102f045fd6SRobert Mustacchi } 29112f045fd6SRobert Mustacchi 29123ddcfaddSBryan Cantrill int 29133ddcfaddSBryan Cantrill cmd_printf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 29143ddcfaddSBryan Cantrill { 29153ddcfaddSBryan Cantrill char type[MDB_SYM_NAMLEN]; 29163ddcfaddSBryan Cantrill int i, nfmts = 0, ret; 29173ddcfaddSBryan Cantrill mdb_ctf_id_t id; 29183ddcfaddSBryan Cantrill const char *fmt, *member; 29193ddcfaddSBryan Cantrill char **fmts, *last, *dest, f; 29203ddcfaddSBryan Cantrill int (**funcs)(mdb_ctf_id_t, uintptr_t, ulong_t, char *); 29213ddcfaddSBryan Cantrill int state = PRINTF_NOFMT; 29223ddcfaddSBryan Cantrill printarg_t pa; 29233ddcfaddSBryan Cantrill 29243ddcfaddSBryan Cantrill if (!(flags & DCMD_ADDRSPEC)) 29253ddcfaddSBryan Cantrill return (DCMD_USAGE); 29263ddcfaddSBryan Cantrill 29273ddcfaddSBryan Cantrill bzero(&pa, sizeof (pa)); 29283ddcfaddSBryan Cantrill pa.pa_as = MDB_TGT_AS_VIRT; 29293ddcfaddSBryan Cantrill pa.pa_realtgt = pa.pa_tgt = mdb.m_target; 29303ddcfaddSBryan Cantrill 29313ddcfaddSBryan Cantrill if (argc == 0 || argv[0].a_type != MDB_TYPE_STRING) { 29323ddcfaddSBryan Cantrill mdb_warn("expected a format string\n"); 29333ddcfaddSBryan Cantrill return (DCMD_USAGE); 29343ddcfaddSBryan Cantrill } 29353ddcfaddSBryan Cantrill 29363ddcfaddSBryan Cantrill /* 29373ddcfaddSBryan Cantrill * Our first argument is a format string; rip it apart and run it 29383ddcfaddSBryan Cantrill * through our state machine to validate that our input is within the 29393ddcfaddSBryan Cantrill * subset of mdb_printf() format strings that we allow. 29403ddcfaddSBryan Cantrill */ 29413ddcfaddSBryan Cantrill fmt = argv[0].a_un.a_str; 29423ddcfaddSBryan Cantrill /* 29433ddcfaddSBryan Cantrill * 'dest' must be large enough to hold a copy of the format string, 29443ddcfaddSBryan Cantrill * plus a NUL and up to 2 additional characters for each conversion 29453ddcfaddSBryan Cantrill * in the format string. This gives us a bloat factor of 5/2 ~= 3. 29463ddcfaddSBryan Cantrill * e.g. "%d" (strlen of 2) --> "%lld\0" (need 5 bytes) 29473ddcfaddSBryan Cantrill */ 29483ddcfaddSBryan Cantrill dest = mdb_zalloc(strlen(fmt) * 3, UM_SLEEP | UM_GC); 29493ddcfaddSBryan Cantrill fmts = mdb_zalloc(strlen(fmt) * sizeof (char *), UM_SLEEP | UM_GC); 29503ddcfaddSBryan Cantrill funcs = mdb_zalloc(strlen(fmt) * sizeof (void *), UM_SLEEP | UM_GC); 29513ddcfaddSBryan Cantrill last = dest; 29523ddcfaddSBryan Cantrill 29533ddcfaddSBryan Cantrill for (i = 0; fmt[i] != '\0'; i++) { 29543ddcfaddSBryan Cantrill *dest++ = f = fmt[i]; 29553ddcfaddSBryan Cantrill 29563ddcfaddSBryan Cantrill switch (state) { 29573ddcfaddSBryan Cantrill case PRINTF_NOFMT: 29583ddcfaddSBryan Cantrill state = f == '%' ? PRINTF_PERC : PRINTF_NOFMT; 29593ddcfaddSBryan Cantrill break; 29603ddcfaddSBryan Cantrill 29613ddcfaddSBryan Cantrill case PRINTF_PERC: 29623ddcfaddSBryan Cantrill state = f == '-' ? PRINTF_LEFT : 29633ddcfaddSBryan Cantrill f >= '0' && f <= '9' ? PRINTF_WIDTH : 29643ddcfaddSBryan Cantrill f == '?' ? PRINTF_QUES : 29653ddcfaddSBryan Cantrill f == '%' ? PRINTF_NOFMT : PRINTF_FMT; 29663ddcfaddSBryan Cantrill break; 29673ddcfaddSBryan Cantrill 29683ddcfaddSBryan Cantrill case PRINTF_LEFT: 29693ddcfaddSBryan Cantrill state = f >= '0' && f <= '9' ? PRINTF_WIDTH : 29703ddcfaddSBryan Cantrill f == '?' ? PRINTF_QUES : PRINTF_FMT; 29713ddcfaddSBryan Cantrill break; 29723ddcfaddSBryan Cantrill 29733ddcfaddSBryan Cantrill case PRINTF_WIDTH: 29743ddcfaddSBryan Cantrill state = f >= '0' && f <= '9' ? PRINTF_WIDTH : 29753ddcfaddSBryan Cantrill PRINTF_FMT; 29763ddcfaddSBryan Cantrill break; 29773ddcfaddSBryan Cantrill 29783ddcfaddSBryan Cantrill case PRINTF_QUES: 29793ddcfaddSBryan Cantrill state = PRINTF_FMT; 29803ddcfaddSBryan Cantrill break; 29813ddcfaddSBryan Cantrill } 29823ddcfaddSBryan Cantrill 29833ddcfaddSBryan Cantrill if (state != PRINTF_FMT) 29843ddcfaddSBryan Cantrill continue; 29853ddcfaddSBryan Cantrill 29863ddcfaddSBryan Cantrill dest--; 29873ddcfaddSBryan Cantrill 29883ddcfaddSBryan Cantrill /* 29893ddcfaddSBryan Cantrill * Now check that we have one of our valid format characters. 29903ddcfaddSBryan Cantrill */ 29913ddcfaddSBryan Cantrill switch (f) { 29923ddcfaddSBryan Cantrill case 'a': 29933ddcfaddSBryan Cantrill case 'A': 29943ddcfaddSBryan Cantrill case 'p': 29953ddcfaddSBryan Cantrill funcs[nfmts] = printf_ptr; 29963ddcfaddSBryan Cantrill break; 29973ddcfaddSBryan Cantrill 29983ddcfaddSBryan Cantrill case 'd': 29993ddcfaddSBryan Cantrill case 'q': 30003ddcfaddSBryan Cantrill case 'R': 30013ddcfaddSBryan Cantrill funcs[nfmts] = printf_int; 30023ddcfaddSBryan Cantrill *dest++ = 'l'; 30033ddcfaddSBryan Cantrill *dest++ = 'l'; 30043ddcfaddSBryan Cantrill break; 30053ddcfaddSBryan Cantrill 30063ddcfaddSBryan Cantrill case 'I': 30073ddcfaddSBryan Cantrill funcs[nfmts] = printf_uint32; 30083ddcfaddSBryan Cantrill break; 30093ddcfaddSBryan Cantrill 30103ddcfaddSBryan Cantrill case 'N': 30113ddcfaddSBryan Cantrill funcs[nfmts] = printf_ipv6; 30123ddcfaddSBryan Cantrill break; 30133ddcfaddSBryan Cantrill 3014cab8de14SBryan Cantrill case 'H': 30153ddcfaddSBryan Cantrill case 'o': 30163ddcfaddSBryan Cantrill case 'r': 30173ddcfaddSBryan Cantrill case 'u': 30183ddcfaddSBryan Cantrill case 'x': 30193ddcfaddSBryan Cantrill case 'X': 30203ddcfaddSBryan Cantrill funcs[nfmts] = printf_uint; 30213ddcfaddSBryan Cantrill *dest++ = 'l'; 30223ddcfaddSBryan Cantrill *dest++ = 'l'; 30233ddcfaddSBryan Cantrill break; 30243ddcfaddSBryan Cantrill 30253ddcfaddSBryan Cantrill case 's': 30263ddcfaddSBryan Cantrill funcs[nfmts] = printf_string; 30273ddcfaddSBryan Cantrill break; 30283ddcfaddSBryan Cantrill 30293ddcfaddSBryan Cantrill case 'Y': 30303ddcfaddSBryan Cantrill funcs[nfmts] = sizeof (time_t) == sizeof (int) ? 30313ddcfaddSBryan Cantrill printf_uint32 : printf_uint; 30323ddcfaddSBryan Cantrill break; 30333ddcfaddSBryan Cantrill 30343ddcfaddSBryan Cantrill default: 30353ddcfaddSBryan Cantrill mdb_warn("illegal format string at or near " 30363ddcfaddSBryan Cantrill "'%c' (position %d)\n", f, i + 1); 30373ddcfaddSBryan Cantrill return (DCMD_ABORT); 30383ddcfaddSBryan Cantrill } 30393ddcfaddSBryan Cantrill 30403ddcfaddSBryan Cantrill *dest++ = f; 30413ddcfaddSBryan Cantrill *dest++ = '\0'; 30423ddcfaddSBryan Cantrill fmts[nfmts++] = last; 30433ddcfaddSBryan Cantrill last = dest; 30443ddcfaddSBryan Cantrill state = PRINTF_NOFMT; 30453ddcfaddSBryan Cantrill } 30463ddcfaddSBryan Cantrill 30473ddcfaddSBryan Cantrill argc--; 30483ddcfaddSBryan Cantrill argv++; 30493ddcfaddSBryan Cantrill 30503ddcfaddSBryan Cantrill /* 30513ddcfaddSBryan Cantrill * Now we expect a type name. 30523ddcfaddSBryan Cantrill */ 30533ddcfaddSBryan Cantrill if ((ret = args_to_typename(&argc, &argv, type, sizeof (type))) != 0) 30543ddcfaddSBryan Cantrill return (ret); 30553ddcfaddSBryan Cantrill 30563ddcfaddSBryan Cantrill argv++; 30573ddcfaddSBryan Cantrill argc--; 30583ddcfaddSBryan Cantrill 30593ddcfaddSBryan Cantrill if (mdb_ctf_lookup_by_name(type, &id) != 0) { 30603ddcfaddSBryan Cantrill mdb_warn("failed to look up type %s", type); 30613ddcfaddSBryan Cantrill return (DCMD_ABORT); 30623ddcfaddSBryan Cantrill } 30633ddcfaddSBryan Cantrill 30643ddcfaddSBryan Cantrill if (argc == 0) { 30653ddcfaddSBryan Cantrill mdb_warn("at least one member must be specified\n"); 30663ddcfaddSBryan Cantrill return (DCMD_USAGE); 30673ddcfaddSBryan Cantrill } 30683ddcfaddSBryan Cantrill 30693ddcfaddSBryan Cantrill if (argc != nfmts) { 30703ddcfaddSBryan Cantrill mdb_warn("%s format specifiers (found %d, expected %d)\n", 30713ddcfaddSBryan Cantrill argc > nfmts ? "missing" : "extra", nfmts, argc); 30723ddcfaddSBryan Cantrill return (DCMD_ABORT); 30733ddcfaddSBryan Cantrill } 30743ddcfaddSBryan Cantrill 30753ddcfaddSBryan Cantrill for (i = 0; i < argc; i++) { 30763ddcfaddSBryan Cantrill mdb_ctf_id_t mid; 30773ddcfaddSBryan Cantrill ulong_t off; 30783ddcfaddSBryan Cantrill int ignored; 30793ddcfaddSBryan Cantrill 30803ddcfaddSBryan Cantrill if (argv[i].a_type != MDB_TYPE_STRING) { 30813ddcfaddSBryan Cantrill mdb_warn("expected only type member arguments\n"); 30823ddcfaddSBryan Cantrill return (DCMD_ABORT); 30833ddcfaddSBryan Cantrill } 30843ddcfaddSBryan Cantrill 30853ddcfaddSBryan Cantrill if (strcmp((member = argv[i].a_un.a_str), ".") == 0) { 30863ddcfaddSBryan Cantrill /* 30873ddcfaddSBryan Cantrill * We allow "." to be specified to denote the current 30883ddcfaddSBryan Cantrill * value of dot. 30893ddcfaddSBryan Cantrill */ 30903ddcfaddSBryan Cantrill if (funcs[i] != printf_ptr && funcs[i] != printf_uint && 30913ddcfaddSBryan Cantrill funcs[i] != printf_int) { 30923ddcfaddSBryan Cantrill mdb_warn("expected integer or pointer format " 30933ddcfaddSBryan Cantrill "specifier for '.'\n"); 30943ddcfaddSBryan Cantrill return (DCMD_ABORT); 30953ddcfaddSBryan Cantrill } 30963ddcfaddSBryan Cantrill 30973ddcfaddSBryan Cantrill mdb_printf(fmts[i], mdb_get_dot()); 30983ddcfaddSBryan Cantrill continue; 30993ddcfaddSBryan Cantrill } 31003ddcfaddSBryan Cantrill 31013ddcfaddSBryan Cantrill pa.pa_addr = addr; 31023ddcfaddSBryan Cantrill 31033ddcfaddSBryan Cantrill if (parse_member(&pa, member, id, &mid, &off, &ignored) != 0) 31043ddcfaddSBryan Cantrill return (DCMD_ABORT); 31053ddcfaddSBryan Cantrill 31063ddcfaddSBryan Cantrill if ((ret = funcs[i](mid, pa.pa_addr, off, fmts[i])) != 0) { 31073ddcfaddSBryan Cantrill mdb_warn("failed to print member '%s'\n", member); 31083ddcfaddSBryan Cantrill return (ret); 31093ddcfaddSBryan Cantrill } 31103ddcfaddSBryan Cantrill } 31113ddcfaddSBryan Cantrill 31123ddcfaddSBryan Cantrill mdb_printf("%s", last); 31136b98d994SRobert Mustacchi mdb_set_dot(addr + mdb_ctf_type_size(id)); 31143ddcfaddSBryan Cantrill 31153ddcfaddSBryan Cantrill return (DCMD_OK); 31163ddcfaddSBryan Cantrill } 31173ddcfaddSBryan Cantrill 31183ddcfaddSBryan Cantrill static char _mdb_printf_help[] = 31193ddcfaddSBryan Cantrill "The format string argument is a printf(3C)-like format string that is a\n" 31203ddcfaddSBryan Cantrill "subset of the format strings supported by mdb_printf(). The type argument\n" 31213ddcfaddSBryan Cantrill "is the name of a type to be used to interpret the memory referenced by dot.\n" 31223ddcfaddSBryan Cantrill "The member should either be a field in the specified structure, or the\n" 31233ddcfaddSBryan Cantrill "special member '.', denoting the value of dot (and treated as a pointer).\n" 31243ddcfaddSBryan Cantrill "The number of members must match the number of format specifiers in the\n" 31253ddcfaddSBryan Cantrill "format string.\n" 31263ddcfaddSBryan Cantrill "\n" 31273ddcfaddSBryan Cantrill "The following format specifiers are recognized by ::printf:\n" 31283ddcfaddSBryan Cantrill "\n" 31293ddcfaddSBryan Cantrill " %% Prints the '%' symbol.\n" 31303ddcfaddSBryan Cantrill " %a Prints the member in symbolic form.\n" 31313ddcfaddSBryan Cantrill " %d Prints the member as a decimal integer. If the member is a signed\n" 31323ddcfaddSBryan Cantrill " integer type, the output will be signed.\n" 3133cab8de14SBryan Cantrill " %H Prints the member as a human-readable size.\n" 3134cab8de14SBryan Cantrill " %I Prints the member as an IPv4 address (must be 32-bit integer type).\n" 3135cab8de14SBryan Cantrill " %N Prints the member as an IPv6 address (must be of type in6_addr_t).\n" 31363ddcfaddSBryan Cantrill " %o Prints the member as an unsigned octal integer.\n" 31373ddcfaddSBryan Cantrill " %p Prints the member as a pointer, in hexadecimal.\n" 31383ddcfaddSBryan Cantrill " %q Prints the member in signed octal. Honk if you ever use this!\n" 31393ddcfaddSBryan Cantrill " %r Prints the member as an unsigned value in the current output radix.\n" 31403ddcfaddSBryan Cantrill " %R Prints the member as a signed value in the current output radix.\n" 31413ddcfaddSBryan Cantrill " %s Prints the member as a string (requires a pointer or an array of\n" 31423ddcfaddSBryan Cantrill " characters).\n" 31433ddcfaddSBryan Cantrill " %u Prints the member as an unsigned decimal integer.\n" 31443ddcfaddSBryan Cantrill " %x Prints the member in hexadecimal.\n" 31453ddcfaddSBryan Cantrill " %X Prints the member in hexadecimal, using the characters A-F as the\n" 31463ddcfaddSBryan Cantrill " digits for the values 10-15.\n" 31473ddcfaddSBryan Cantrill " %Y Prints the member as a time_t as the string " 31483ddcfaddSBryan Cantrill "'year month day HH:MM:SS'.\n" 31493ddcfaddSBryan Cantrill "\n" 31503ddcfaddSBryan Cantrill "The following field width specifiers are recognized by ::printf:\n" 31513ddcfaddSBryan Cantrill "\n" 31523ddcfaddSBryan Cantrill " %n Field width is set to the specified decimal value.\n" 31533ddcfaddSBryan Cantrill " %? Field width is set to the maximum width of a hexadecimal pointer\n" 31543ddcfaddSBryan Cantrill " value. This is 8 in an ILP32 environment, and 16 in an LP64\n" 31553ddcfaddSBryan Cantrill " environment.\n" 31563ddcfaddSBryan Cantrill "\n" 31573ddcfaddSBryan Cantrill "The following flag specifers are recognized by ::printf:\n" 31583ddcfaddSBryan Cantrill "\n" 31593ddcfaddSBryan Cantrill " %- Left-justify the output within the specified field width. If the\n" 31603ddcfaddSBryan Cantrill " width of the output is less than the specified field width, the\n" 31613ddcfaddSBryan Cantrill " output will be padded with blanks on the right-hand side. Without\n" 31623ddcfaddSBryan Cantrill " %-, values are right-justified by default.\n" 31633ddcfaddSBryan Cantrill "\n" 31643ddcfaddSBryan Cantrill " %0 Zero-fill the output field if the output is right-justified and the\n" 31653ddcfaddSBryan Cantrill " width of the output is less than the specified field width. Without\n" 31663ddcfaddSBryan Cantrill " %0, right-justified values are prepended with blanks in order to\n" 31673ddcfaddSBryan Cantrill " fill the field.\n" 31683ddcfaddSBryan Cantrill "\n" 31693ddcfaddSBryan Cantrill "Examples: \n" 31703ddcfaddSBryan Cantrill "\n" 31713ddcfaddSBryan Cantrill " ::walk proc | " 31723ddcfaddSBryan Cantrill "::printf \"%-6d %s\\n\" proc_t p_pidp->pid_id p_user.u_psargs\n" 31733ddcfaddSBryan Cantrill " ::walk thread | " 31743ddcfaddSBryan Cantrill "::printf \"%?p %3d %a\\n\" kthread_t . t_pri t_startpc\n" 31753ddcfaddSBryan Cantrill " ::walk zone | " 31763ddcfaddSBryan Cantrill "::printf \"%-40s %20s\\n\" zone_t zone_name zone_nodename\n" 31773ddcfaddSBryan Cantrill " ::walk ire | " 31783ddcfaddSBryan Cantrill "::printf \"%Y %I\\n\" ire_t ire_create_time ire_u.ire4_u.ire4_addr\n" 31793ddcfaddSBryan Cantrill "\n"; 31803ddcfaddSBryan Cantrill 31813ddcfaddSBryan Cantrill void 31823ddcfaddSBryan Cantrill printf_help(void) 31833ddcfaddSBryan Cantrill { 31843ddcfaddSBryan Cantrill mdb_printf("%s", _mdb_printf_help); 31853ddcfaddSBryan Cantrill } 3186