xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_print.c (revision bb25c06c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <mdb/mdb_modapi.h>
29 #include <mdb/mdb_target.h>
30 #include <mdb/mdb_argvec.h>
31 #include <mdb/mdb_string.h>
32 #include <mdb/mdb_stdlib.h>
33 #include <mdb/mdb_err.h>
34 #include <mdb/mdb_debug.h>
35 #include <mdb/mdb_fmt.h>
36 #include <mdb/mdb_ctf.h>
37 #include <mdb/mdb_ctf_impl.h>
38 #include <mdb/mdb.h>
39 
40 #include <sys/isa_defs.h>
41 #include <sys/param.h>
42 #include <sys/sysmacros.h>
43 #include <strings.h>
44 #include <libctf.h>
45 #include <ctype.h>
46 
47 typedef struct holeinfo {
48 	ulong_t hi_offset;		/* expected offset */
49 	uchar_t hi_isunion;		/* represents a union */
50 } holeinfo_t;
51 
52 typedef struct printarg {
53 	mdb_tgt_t *pa_tgt;		/* current target */
54 	mdb_tgt_t *pa_realtgt;		/* real target (for -i) */
55 	mdb_tgt_t *pa_immtgt;		/* immediate target (for -i) */
56 	mdb_tgt_as_t pa_as;		/* address space to use for i/o */
57 	mdb_tgt_addr_t pa_addr;		/* base address for i/o */
58 	ulong_t pa_armemlim;		/* limit on array elements to print */
59 	ulong_t pa_arstrlim;		/* limit on array chars to print */
60 	const char *pa_delim;		/* element delimiter string */
61 	const char *pa_prefix;		/* element prefix string */
62 	const char *pa_suffix;		/* element suffix string */
63 	holeinfo_t *pa_holes;		/* hole detection information */
64 	int pa_nholes;			/* size of holes array */
65 	int pa_flags;			/* formatting flags (see below) */
66 	int pa_depth;			/* previous depth */
67 	int pa_nest;			/* array nesting depth */
68 	int pa_tab;			/* tabstop width */
69 	uint_t pa_maxdepth;		/* Limit max depth */
70 } printarg_t;
71 
72 #define	PA_SHOWTYPE	0x001		/* print type name */
73 #define	PA_SHOWNAME	0x002		/* print member name */
74 #define	PA_SHOWADDR	0x004		/* print address */
75 #define	PA_SHOWVAL	0x008		/* print value */
76 #define	PA_SHOWHOLES	0x010		/* print holes in structs */
77 #define	PA_INTHEX	0x020		/* print integer values in hex */
78 #define	PA_INTDEC	0x040		/* print integer values in decimal */
79 #define	PA_NOSYMBOLIC	0x080		/* don't print ptrs as func+offset */
80 
81 #define	IS_CHAR(e) \
82 	(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
83 	(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
84 
85 #define	SCALAR_MASK	((1 << CTF_K_INTEGER) | (1 << CTF_K_FLOAT) | \
86 			(1 << CTF_K_POINTER) | (1 << CTF_K_ENUM) | \
87 			(1 << CTF_K_ARRAY))
88 #define	IS_SCALAR(k)	(((1 << k) & SCALAR_MASK) != 0)
89 
90 #define	COMPOSITE_MASK	((1 << CTF_K_STRUCT) | \
91 			(1 << CTF_K_UNION) | (1 << CTF_K_ARRAY))
92 #define	IS_COMPOSITE(k)	(((1 << k) & COMPOSITE_MASK) != 0)
93 
94 #define	SOU_MASK	((1 << CTF_K_STRUCT) | (1 << CTF_K_UNION))
95 #define	IS_SOU(k)	(((1 << k) & SOU_MASK) != 0)
96 
97 #define	MEMBER_DELIM_ERR	-1
98 #define	MEMBER_DELIM_DONE	0
99 #define	MEMBER_DELIM_PTR	1
100 #define	MEMBER_DELIM_DOT	2
101 #define	MEMBER_DELIM_LBR	3
102 
103 typedef int printarg_f(const char *, const char *,
104     mdb_ctf_id_t, mdb_ctf_id_t, ulong_t, printarg_t *);
105 
106 static int elt_print(const char *, mdb_ctf_id_t, ulong_t, int, void *);
107 static void print_close_sou(printarg_t *, int);
108 
109 /*
110  * Given an address, look up the symbol ID of the specified symbol in its
111  * containing module.  We only support lookups for exact matches.
112  */
113 static const char *
114 addr_to_sym(mdb_tgt_t *t, uintptr_t addr, char *name, size_t namelen,
115     GElf_Sym *symp, mdb_syminfo_t *sip)
116 {
117 	const mdb_map_t *mp;
118 	const char *p;
119 
120 	if (mdb_tgt_lookup_by_addr(t, addr, MDB_TGT_SYM_EXACT, name,
121 	    namelen, NULL, NULL) == -1)
122 		return (NULL); /* address does not exactly match a symbol */
123 
124 	if ((p = strrsplit(name, '`')) != NULL) {
125 		if (mdb_tgt_lookup_by_name(t, name, p, symp, sip) == -1)
126 			return (NULL);
127 		return (p);
128 	}
129 
130 	if ((mp = mdb_tgt_addr_to_map(t, addr)) == NULL)
131 		return (NULL); /* address does not fall within a mapping */
132 
133 	if (mdb_tgt_lookup_by_name(t, mp->map_name, name, symp, sip) == -1)
134 		return (NULL);
135 
136 	return (name);
137 }
138 
139 /*
140  * This lets dcmds be a little fancy with their processing of type arguments
141  * while still treating them more or less as a single argument.
142  * For example, if a command is invokes like this:
143  *
144  *   ::<dcmd> proc_t ...
145  *
146  * this function will just copy "proc_t" into the provided buffer. If the
147  * command is instead invoked like this:
148  *
149  *   ::<dcmd> struct proc ...
150  *
151  * this function will place the string "struct proc" into the provided buffer
152  * and increment the caller's argv and argc. This allows the caller to still
153  * treat the type argument logically as it would an other atomic argument.
154  */
155 int
156 args_to_typename(int *argcp, const mdb_arg_t **argvp, char *buf, size_t len)
157 {
158 	int argc = *argcp;
159 	const mdb_arg_t *argv = *argvp;
160 
161 	if (argc < 1 || argv->a_type != MDB_TYPE_STRING)
162 		return (DCMD_USAGE);
163 
164 	if (strcmp(argv->a_un.a_str, "struct") == 0 ||
165 	    strcmp(argv->a_un.a_str, "enum") == 0 ||
166 	    strcmp(argv->a_un.a_str, "union") == 0) {
167 		if (argc <= 1) {
168 			mdb_warn("%s is not a valid type\n", argv->a_un.a_str);
169 			return (DCMD_ABORT);
170 		}
171 
172 		if (argv[1].a_type != MDB_TYPE_STRING)
173 			return (DCMD_USAGE);
174 
175 		(void) mdb_snprintf(buf, len, "%s %s",
176 		    argv[0].a_un.a_str, argv[1].a_un.a_str);
177 
178 		*argcp = argc - 1;
179 		*argvp = argv + 1;
180 	} else {
181 		(void) mdb_snprintf(buf, len, "%s", argv[0].a_un.a_str);
182 	}
183 
184 	return (0);
185 }
186 
187 /*ARGSUSED*/
188 int
189 cmd_sizeof(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
190 {
191 	mdb_ctf_id_t id;
192 	char tn[MDB_SYM_NAMLEN];
193 	int ret;
194 
195 	if (flags & DCMD_ADDRSPEC)
196 		return (DCMD_USAGE);
197 
198 	if ((ret = args_to_typename(&argc, &argv, tn, sizeof (tn))) != 0)
199 		return (ret);
200 
201 	if (argc != 1)
202 		return (DCMD_USAGE);
203 
204 	if (mdb_ctf_lookup_by_name(tn, &id) != 0) {
205 		mdb_warn("failed to look up type %s", tn);
206 		return (DCMD_ERR);
207 	}
208 
209 	if (flags & DCMD_PIPE_OUT)
210 		mdb_printf("%#lr\n", mdb_ctf_type_size(id));
211 	else
212 		mdb_printf("sizeof (%s) = %#lr\n", tn, mdb_ctf_type_size(id));
213 
214 	return (DCMD_OK);
215 }
216 
217 /*ARGSUSED*/
218 int
219 cmd_offsetof(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
220 {
221 	const char *member;
222 	mdb_ctf_id_t id;
223 	ulong_t off;
224 	char tn[MDB_SYM_NAMLEN];
225 	int ret;
226 
227 	if (flags & DCMD_ADDRSPEC)
228 		return (DCMD_USAGE);
229 
230 	if ((ret = args_to_typename(&argc, &argv, tn, sizeof (tn))) != 0)
231 		return (ret);
232 
233 	if (argc != 2 || argv[1].a_type != MDB_TYPE_STRING)
234 		return (DCMD_USAGE);
235 
236 	if (mdb_ctf_lookup_by_name(tn, &id) != 0) {
237 		mdb_warn("failed to look up type %s", tn);
238 		return (DCMD_ERR);
239 	}
240 
241 	member = argv[1].a_un.a_str;
242 
243 	if (mdb_ctf_offsetof(id, member, &off) != 0) {
244 		mdb_warn("failed to find member %s of type %s", member, tn);
245 		return (DCMD_ERR);
246 	}
247 
248 	if (off % NBBY == 0)
249 		mdb_printf("offsetof (%s, %s) = %#lr\n",
250 		    tn, member, off / NBBY);
251 	else
252 		mdb_printf("offsetof (%s, %s) = %#lr bits\n",
253 		    tn, member, off);
254 
255 	return (DCMD_OK);
256 }
257 
258 struct enum_cbinfo {
259 	uint_t		e_flags;
260 	const char	*e_string;	/* NULL for value searches */
261 	int		e_value;
262 	uint_t		e_found;
263 };
264 #define	E_PRETTY		0x1
265 #define	E_HEX			0x2
266 #define	E_SEARCH_STRING		0x4
267 #define	E_SEARCH_VALUE		0x8
268 
269 static int
270 enum_cb(const char *name, int value, void *arg)
271 {
272 	struct enum_cbinfo *info = arg;
273 	uint_t flags = info->e_flags;
274 
275 	if (flags & E_SEARCH_STRING) {
276 		if (strcmp(name, info->e_string) != 0)
277 			return (0);
278 
279 	} else if (flags & E_SEARCH_VALUE) {
280 		if (value != info->e_value)
281 			return (0);
282 	}
283 
284 	if (flags & E_PRETTY) {
285 		if (flags & E_HEX)
286 			mdb_printf("%-8x %s\n", value, name);
287 		else
288 			mdb_printf("%-11d %s\n", value, name);
289 	} else {
290 		mdb_printf("%#r\n", value);
291 	}
292 
293 	info->e_found = 1;
294 	return (0);
295 }
296 
297 /*ARGSUSED*/
298 int
299 cmd_enum(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
300 {
301 	struct enum_cbinfo info;
302 
303 	const char *type;			/* type name we are using */
304 	char tn[MDB_SYM_NAMLEN];
305 	char tn2[MDB_SYM_NAMLEN + sizeof ("enum ")];
306 	mdb_ctf_id_t id;
307 	mdb_ctf_id_t idr;
308 
309 	int i;
310 	intmax_t search;
311 
312 	info.e_flags = (flags & DCMD_PIPE_OUT)? 0 : E_PRETTY;
313 	info.e_string = NULL;
314 	info.e_value = 0;
315 	info.e_found = 0;
316 
317 	i = mdb_getopts(argc, argv,
318 	    'x', MDB_OPT_SETBITS, E_HEX, &info.e_flags,
319 	    NULL);
320 
321 	argc -= i;
322 	argv += i;
323 
324 	if ((i = args_to_typename(&argc, &argv, tn, sizeof (tn))) != 0)
325 		return (i);
326 
327 	type = NULL;
328 	if (strchr(tn, ' ') == NULL) {
329 		/*
330 		 * Check as an enumeration tag first, and fall back
331 		 * to checking for a typedef.  Yes, this means that
332 		 * anonymous enumerations whose typedefs conflict with
333 		 * an enum tag can't be accessed.  Don't do that.
334 		 */
335 		(void) mdb_snprintf(tn2, sizeof (tn2), "enum %s", tn);
336 
337 		if (mdb_ctf_lookup_by_name(tn2, &id) == 0) {
338 			type = tn2;
339 		} else if (mdb_ctf_lookup_by_name(tn, &id) == 0) {
340 			type = tn;
341 		} else {
342 			mdb_warn("types '%s', '%s'", tn2, tn);
343 			return (DCMD_ERR);
344 		}
345 	} else {
346 		if (mdb_ctf_lookup_by_name(tn, &id) == 0) {
347 			type = tn;
348 		} else {
349 			mdb_warn("'%s'", tn);
350 			return (DCMD_ERR);
351 		}
352 	}
353 
354 	/* resolve it, and make sure we're looking at an enumeration */
355 	if (mdb_ctf_type_resolve(id, &idr) == -1) {
356 		mdb_warn("unable to resolve '%s'", type);
357 		return (DCMD_ERR);
358 	}
359 	if (mdb_ctf_type_kind(idr) != CTF_K_ENUM) {
360 		mdb_warn("'%s': not an enumeration\n", type);
361 		return (DCMD_ERR);
362 	}
363 
364 	if (argc > 2)
365 		return (DCMD_USAGE);
366 
367 	if (argc == 2) {
368 		if (flags & DCMD_ADDRSPEC) {
369 			mdb_warn("may only specify one of: name, address\n");
370 			return (DCMD_USAGE);
371 		}
372 
373 		if (argv[1].a_type == MDB_TYPE_STRING) {
374 			info.e_flags |= E_SEARCH_STRING;
375 			info.e_string = argv[1].a_un.a_str;
376 		} else if (argv[1].a_type == MDB_TYPE_IMMEDIATE) {
377 			info.e_flags |= E_SEARCH_VALUE;
378 			search = argv[1].a_un.a_val;
379 		} else {
380 			return (DCMD_USAGE);
381 		}
382 	}
383 
384 	if (flags & DCMD_ADDRSPEC) {
385 		info.e_flags |= E_SEARCH_VALUE;
386 		search = mdb_get_dot();
387 	}
388 
389 	if (info.e_flags & E_SEARCH_VALUE) {
390 		if ((int)search != search) {
391 			mdb_warn("value '%lld' out of enumeration range\n",
392 			    search);
393 			return (DCMD_ERR);
394 		}
395 		info.e_value = search;
396 	}
397 
398 	if (DCMD_HDRSPEC(flags) && (info.e_flags & E_PRETTY)) {
399 		if (info.e_flags & E_HEX)
400 			mdb_printf("%<b>%-8s %s%</b>\n", "VALUE", "NAME");
401 		else
402 			mdb_printf("%<b>%-11s %s%</b>\n", "VALUE", "NAME");
403 	}
404 
405 	if (mdb_ctf_enum_iter(idr, enum_cb, &info) == -1) {
406 		mdb_warn("cannot walk '%s' as enum", type);
407 		return (DCMD_ERR);
408 	}
409 
410 	if (info.e_found == 0 &&
411 	    (info.e_flags & (E_SEARCH_STRING | E_SEARCH_VALUE)) != 0) {
412 		if (info.e_flags & E_SEARCH_STRING)
413 			mdb_warn("name \"%s\" not in '%s'\n", info.e_string,
414 			    type);
415 		else
416 			mdb_warn("value %#d not in '%s'\n", info.e_value, type);
417 
418 		return (DCMD_ERR);
419 	}
420 
421 	return (DCMD_OK);
422 }
423 
424 static int
425 setup_vcb(const char *name, uintptr_t addr)
426 {
427 	const char *p;
428 	mdb_var_t *v;
429 
430 	if ((v = mdb_nv_lookup(&mdb.m_nv, name)) == NULL) {
431 		if ((p = strbadid(name)) != NULL) {
432 			mdb_warn("'%c' may not be used in a variable "
433 			    "name\n", *p);
434 			return (DCMD_ABORT);
435 		}
436 
437 		if ((v = mdb_nv_insert(&mdb.m_nv, name, NULL, addr, 0)) == NULL)
438 			return (DCMD_ERR);
439 	} else {
440 		if (v->v_flags & MDB_NV_RDONLY) {
441 			mdb_warn("variable %s is read-only\n", name);
442 			return (DCMD_ABORT);
443 		}
444 	}
445 
446 	/*
447 	 * If there already exists a vcb for this variable, we may be
448 	 * calling the dcmd in a loop.  We only create a vcb for this
449 	 * variable on the first invocation.
450 	 */
451 	if (mdb_vcb_find(v, mdb.m_frame) == NULL)
452 		mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame);
453 
454 	return (0);
455 }
456 
457 /*ARGSUSED*/
458 int
459 cmd_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
460 {
461 	mdb_ctf_id_t id;
462 	ulong_t offset;
463 	uintptr_t a, tmp;
464 	int ret;
465 
466 	if (!(flags & DCMD_ADDRSPEC) || argc == 0)
467 		return (DCMD_USAGE);
468 
469 	if (argv->a_type != MDB_TYPE_STRING) {
470 		/*
471 		 * We are being given a raw offset in lieu of a type and
472 		 * member; confirm the arguments.
473 		 */
474 		if (argv->a_type != MDB_TYPE_IMMEDIATE)
475 			return (DCMD_USAGE);
476 
477 		offset = argv->a_un.a_val;
478 
479 		argv++;
480 		argc--;
481 
482 		if (offset % sizeof (uintptr_t)) {
483 			mdb_warn("offset must fall on a word boundary\n");
484 			return (DCMD_ABORT);
485 		}
486 	} else {
487 		const char *member;
488 		char buf[MDB_SYM_NAMLEN];
489 		int ret;
490 
491 		ret = args_to_typename(&argc, &argv, buf, sizeof (buf));
492 		if (ret != 0)
493 			return (ret);
494 
495 		if (mdb_ctf_lookup_by_name(buf, &id) != 0) {
496 			mdb_warn("failed to look up type %s", buf);
497 			return (DCMD_ABORT);
498 		}
499 
500 		argv++;
501 		argc--;
502 
503 		if (argc < 1 || argv->a_type != MDB_TYPE_STRING)
504 			return (DCMD_USAGE);
505 
506 		member = argv->a_un.a_str;
507 
508 		argv++;
509 		argc--;
510 
511 		if (mdb_ctf_offsetof(id, member, &offset) != 0) {
512 			mdb_warn("failed to find member %s of type %s",
513 			    member, buf);
514 			return (DCMD_ABORT);
515 		}
516 
517 		if (offset % (sizeof (uintptr_t) * NBBY) != 0) {
518 			mdb_warn("%s is not a word-aligned member\n", member);
519 			return (DCMD_ABORT);
520 		}
521 
522 		offset /= NBBY;
523 	}
524 
525 	/*
526 	 * If we have any unchewed arguments, a variable name must be present.
527 	 */
528 	if (argc == 1) {
529 		if (argv->a_type != MDB_TYPE_STRING)
530 			return (DCMD_USAGE);
531 
532 		if ((ret = setup_vcb(argv->a_un.a_str, addr)) != 0)
533 			return (ret);
534 
535 	} else if (argc != 0) {
536 		return (DCMD_USAGE);
537 	}
538 
539 	a = addr;
540 
541 	do {
542 		mdb_printf("%lr\n", a);
543 
544 		if (mdb_vread(&tmp, sizeof (tmp), a + offset) == -1) {
545 			mdb_warn("failed to read next pointer from object %p",
546 			    a);
547 			return (DCMD_ERR);
548 		}
549 
550 		a = tmp;
551 	} while (a != addr && a != NULL);
552 
553 	return (DCMD_OK);
554 }
555 
556 int
557 cmd_array(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
558 {
559 	mdb_ctf_id_t id;
560 	ssize_t elemsize = 0;
561 	char tn[MDB_SYM_NAMLEN];
562 	int ret, nelem = -1;
563 
564 	mdb_tgt_t *t = mdb.m_target;
565 	GElf_Sym sym;
566 	mdb_ctf_arinfo_t ar;
567 	mdb_syminfo_t s_info;
568 
569 	if (!(flags & DCMD_ADDRSPEC))
570 		return (DCMD_USAGE);
571 
572 	if (argc >= 2) {
573 		ret = args_to_typename(&argc, &argv, tn, sizeof (tn));
574 		if (ret != 0)
575 			return (ret);
576 
577 		if (argc == 1)	/* unquoted compound type without count */
578 			return (DCMD_USAGE);
579 
580 		if (mdb_ctf_lookup_by_name(tn, &id) != 0) {
581 			mdb_warn("failed to look up type %s", tn);
582 			return (DCMD_ABORT);
583 		}
584 
585 		if (argv[1].a_type == MDB_TYPE_IMMEDIATE)
586 			nelem = argv[1].a_un.a_val;
587 		else
588 			nelem = mdb_strtoull(argv[1].a_un.a_str);
589 
590 		elemsize = mdb_ctf_type_size(id);
591 	} else if (addr_to_sym(t, addr, tn, sizeof (tn), &sym, &s_info)
592 		    != NULL && mdb_ctf_lookup_by_symbol(&sym, &s_info, &id)
593 		    == 0 && mdb_ctf_type_kind(id) == CTF_K_ARRAY &&
594 		    mdb_ctf_array_info(id, &ar) != -1) {
595 			elemsize = mdb_ctf_type_size(id) / ar.mta_nelems;
596 			nelem = ar.mta_nelems;
597 	} else {
598 		mdb_warn("no symbol information for %a", addr);
599 		return (DCMD_ERR);
600 	}
601 
602 	if (argc == 3 || argc == 1) {
603 		if (argv[argc - 1].a_type != MDB_TYPE_STRING)
604 			return (DCMD_USAGE);
605 
606 		if ((ret = setup_vcb(argv[argc - 1].a_un.a_str, addr)) != 0)
607 			return (ret);
608 
609 	} else if (argc > 3) {
610 		return (DCMD_USAGE);
611 	}
612 
613 	for (; nelem > 0; nelem--) {
614 		mdb_printf("%lr\n", addr);
615 		addr = addr + elemsize;
616 	}
617 
618 	return (DCMD_OK);
619 }
620 
621 /*
622  * Print an integer bitfield in hexadecimal by reading the enclosing byte(s)
623  * and then shifting and masking the data in the lower bits of a uint64_t.
624  */
625 static int
626 print_bitfield(ulong_t off, printarg_t *pap, ctf_encoding_t *ep)
627 {
628 	mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
629 	size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
630 	uint64_t mask = (1ULL << ep->cte_bits) - 1;
631 	uint64_t value = 0;
632 	uint8_t *buf = (uint8_t *)&value;
633 	uint8_t shift;
634 
635 	const char *format;
636 
637 	if (!(pap->pa_flags & PA_SHOWVAL))
638 		return (0);
639 
640 	if (ep->cte_bits > sizeof (value) * NBBY - 1) {
641 		mdb_printf("??? (invalid bitfield size %u)", ep->cte_bits);
642 		return (0);
643 	}
644 
645 	/*
646 	 * On big-endian machines, we need to adjust the buf pointer to refer
647 	 * to the lowest 'size' bytes in 'value', and we need shift based on
648 	 * the offset from the end of the data, not the offset of the start.
649 	 */
650 #ifdef _BIG_ENDIAN
651 	buf += sizeof (value) - size;
652 	off += ep->cte_bits;
653 #endif
654 	if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, buf, size, addr) != size) {
655 		mdb_warn("failed to read %lu bytes at %llx",
656 		    (ulong_t)size, addr);
657 		return (1);
658 	}
659 
660 	shift = off % NBBY;
661 
662 	/*
663 	 * Offsets are counted from opposite ends on little- and
664 	 * big-endian machines.
665 	 */
666 #ifdef _BIG_ENDIAN
667 	shift = NBBY - shift;
668 #endif
669 
670 	/*
671 	 * If the bits we want do not begin on a byte boundary, shift the data
672 	 * right so that the value is in the lowest 'cte_bits' of 'value'.
673 	 */
674 	if (off % NBBY != 0)
675 		value >>= shift;
676 	value &= mask;
677 
678 	/*
679 	 * We default to printing signed bitfields as decimals,
680 	 * and unsigned bitfields in hexadecimal.  If they specify
681 	 * hexadecimal, we treat the field as unsigned.
682 	 */
683 	if ((pap->pa_flags & PA_INTHEX) ||
684 	    !(ep->cte_format & CTF_INT_SIGNED)) {
685 		format = (pap->pa_flags & PA_INTDEC)? "%#llu" : "%#llx";
686 	} else {
687 		int sshift = sizeof (value) * NBBY - ep->cte_bits;
688 
689 		/* sign-extend value, and print as a signed decimal */
690 		value = ((int64_t)value << sshift) >> sshift;
691 		format = "%#lld";
692 	}
693 	mdb_printf(format, value);
694 
695 	return (0);
696 }
697 
698 /*
699  * Print out a character or integer value.  We use some simple heuristics,
700  * described below, to determine the appropriate radix to use for output.
701  */
702 static int
703 print_int_val(const char *type, ctf_encoding_t *ep, ulong_t off,
704     printarg_t *pap)
705 {
706 	static const char *const sformat[] = { "%#d", "%#d", "%#d", "%#lld" };
707 	static const char *const uformat[] = { "%#u", "%#u", "%#u", "%#llu" };
708 	static const char *const xformat[] = { "%#x", "%#x", "%#x", "%#llx" };
709 
710 	mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
711 	const char *const *fsp;
712 	size_t size;
713 
714 	union {
715 		uint64_t i8;
716 		uint32_t i4;
717 		uint16_t i2;
718 		uint8_t i1;
719 		time_t t;
720 	} u;
721 
722 	if (!(pap->pa_flags & PA_SHOWVAL))
723 		return (0);
724 
725 	if (ep->cte_format & CTF_INT_VARARGS) {
726 		mdb_printf("...\n");
727 		return (0);
728 	}
729 
730 	/*
731 	 * If the size is not a power-of-two number of bytes in the range 1-8
732 	 * then we assume it is a bitfield and print it as such.
733 	 */
734 	size = ep->cte_bits / NBBY;
735 	if (size > 8 || (ep->cte_bits % NBBY) != 0 || (size & (size - 1)) != 0)
736 		return (print_bitfield(off, pap, ep));
737 
738 	if (IS_CHAR(*ep)) {
739 		mdb_printf("'");
740 		if (mdb_fmt_print(pap->pa_tgt, pap->pa_as,
741 		    addr, 1, 'C') == addr)
742 			return (1);
743 		mdb_printf("'");
744 		return (0);
745 	}
746 
747 	if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size, addr) != size) {
748 		mdb_warn("failed to read %lu bytes at %llx",
749 		    (ulong_t)size, addr);
750 		return (1);
751 	}
752 
753 	/*
754 	 * We pretty-print time_t values as a calendar date and time.
755 	 */
756 	if (!(pap->pa_flags & (PA_INTHEX | PA_INTDEC)) &&
757 	    strcmp(type, "time_t") == 0 && u.t != 0) {
758 		mdb_printf("%Y", u.t);
759 		return (0);
760 	}
761 
762 	/*
763 	 * The default format is hexadecimal.
764 	 */
765 	if (!(pap->pa_flags & PA_INTDEC))
766 		fsp = xformat;
767 	else if (ep->cte_format & CTF_INT_SIGNED)
768 		fsp = sformat;
769 	else
770 		fsp = uformat;
771 
772 	switch (size) {
773 	case sizeof (uint8_t):
774 		mdb_printf(fsp[0], u.i1);
775 		break;
776 	case sizeof (uint16_t):
777 		mdb_printf(fsp[1], u.i2);
778 		break;
779 	case sizeof (uint32_t):
780 		mdb_printf(fsp[2], u.i4);
781 		break;
782 	case sizeof (uint64_t):
783 		mdb_printf(fsp[3], u.i8);
784 		break;
785 	}
786 	return (0);
787 }
788 
789 /*ARGSUSED*/
790 static int
791 print_int(const char *type, const char *name, mdb_ctf_id_t id,
792     mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
793 {
794 	ctf_encoding_t e;
795 
796 	if (!(pap->pa_flags & PA_SHOWVAL))
797 		return (0);
798 
799 	if (mdb_ctf_type_encoding(base, &e) != 0) {
800 		mdb_printf("??? (%s)", mdb_strerror(errno));
801 		return (0);
802 	}
803 
804 	return (print_int_val(type, &e, off, pap));
805 }
806 
807 /*
808  * Print out a floating point value.  We only provide support for floats in
809  * the ANSI-C float, double, and long double formats.
810  */
811 /*ARGSUSED*/
812 static int
813 print_float(const char *type, const char *name, mdb_ctf_id_t id,
814     mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
815 {
816 #ifndef _KMDB
817 	mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
818 	ctf_encoding_t e;
819 
820 	union {
821 		float f;
822 		double d;
823 		long double ld;
824 	} u;
825 
826 	if (!(pap->pa_flags & PA_SHOWVAL))
827 		return (0);
828 
829 	if (mdb_ctf_type_encoding(base, &e) == 0) {
830 		if (e.cte_format == CTF_FP_SINGLE &&
831 		    e.cte_bits == sizeof (float) * NBBY) {
832 			if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.f,
833 			    sizeof (u.f), addr) != sizeof (u.f)) {
834 				mdb_warn("failed to read float at %llx", addr);
835 				return (1);
836 			}
837 			mdb_printf("%s", doubletos(u.f, 7, 'e'));
838 
839 		} else if (e.cte_format == CTF_FP_DOUBLE &&
840 		    e.cte_bits == sizeof (double) * NBBY) {
841 			if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.d,
842 			    sizeof (u.d), addr) != sizeof (u.d)) {
843 				mdb_warn("failed to read float at %llx", addr);
844 				return (1);
845 			}
846 			mdb_printf("%s", doubletos(u.d, 7, 'e'));
847 
848 		} else if (e.cte_format == CTF_FP_LDOUBLE &&
849 		    e.cte_bits == sizeof (long double) * NBBY) {
850 			if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.ld,
851 			    sizeof (u.ld), addr) != sizeof (u.ld)) {
852 				mdb_warn("failed to read float at %llx", addr);
853 				return (1);
854 			}
855 			mdb_printf("%s", longdoubletos(&u.ld, 16, 'e'));
856 
857 		} else {
858 			mdb_printf("??? (unsupported FP format %u / %u bits\n",
859 			    e.cte_format, e.cte_bits);
860 		}
861 	} else
862 		mdb_printf("??? (%s)", mdb_strerror(errno));
863 #else
864 	mdb_printf("<FLOAT>");
865 #endif
866 	return (0);
867 }
868 
869 
870 /*
871  * Print out a pointer value as a symbol name + offset or a hexadecimal value.
872  * If the pointer itself is a char *, we attempt to read a bit of the data
873  * referenced by the pointer and display it if it is a printable ASCII string.
874  */
875 /*ARGSUSED*/
876 static int
877 print_ptr(const char *type, const char *name, mdb_ctf_id_t id,
878     mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
879 {
880 	mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
881 	ctf_encoding_t e;
882 	uintptr_t value;
883 	char buf[256];
884 	ssize_t len;
885 
886 	if (!(pap->pa_flags & PA_SHOWVAL))
887 		return (0);
888 
889 	if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
890 	    &value, sizeof (value), addr) != sizeof (value)) {
891 		mdb_warn("failed to read %s pointer at %llx", name, addr);
892 		return (1);
893 	}
894 
895 	if (pap->pa_flags & PA_NOSYMBOLIC) {
896 		mdb_printf("%#lx", value);
897 		return (0);
898 	}
899 
900 	mdb_printf("%a", value);
901 
902 	if (value == NULL || strcmp(type, "caddr_t") == 0)
903 		return (0);
904 
905 	if (mdb_ctf_type_kind(base) == CTF_K_POINTER &&
906 	    mdb_ctf_type_reference(base, &base) != -1 &&
907 	    mdb_ctf_type_resolve(base, &base) != -1 &&
908 	    mdb_ctf_type_encoding(base, &e) == 0 && IS_CHAR(e)) {
909 		if ((len = mdb_tgt_readstr(pap->pa_realtgt, pap->pa_as,
910 		    buf, sizeof (buf), value)) >= 0 && strisprint(buf)) {
911 			if (len == sizeof (buf))
912 				(void) strabbr(buf, sizeof (buf));
913 			mdb_printf(" \"%s\"", buf);
914 		}
915 	}
916 
917 	return (0);
918 }
919 
920 
921 /*
922  * Print out a fixed-size array.  We special-case arrays of characters
923  * and attempt to print them out as ASCII strings if possible.  For other
924  * arrays, we iterate over a maximum of pa_armemlim members and call
925  * mdb_ctf_type_visit() again on each element to print its value.
926  */
927 /*ARGSUSED*/
928 static int
929 print_array(const char *type, const char *name, mdb_ctf_id_t id,
930     mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
931 {
932 	mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
933 	printarg_t pa = *pap;
934 	ssize_t eltsize;
935 	mdb_ctf_arinfo_t r;
936 	ctf_encoding_t e;
937 	uint_t i, kind, limit;
938 	int d, sou;
939 	char buf[8];
940 	char *str;
941 
942 	if (!(pap->pa_flags & PA_SHOWVAL))
943 		return (0);
944 
945 	if (pap->pa_depth == pap->pa_maxdepth) {
946 		mdb_printf("[ ... ]");
947 		return (0);
948 	}
949 
950 	/*
951 	 * Determine the base type and size of the array's content.  If this
952 	 * fails, we cannot print anything and just give up.
953 	 */
954 	if (mdb_ctf_array_info(base, &r) == -1 ||
955 	    mdb_ctf_type_resolve(r.mta_contents, &base) == -1 ||
956 	    (eltsize = mdb_ctf_type_size(base)) == -1) {
957 		mdb_printf("[ ??? ] (%s)", mdb_strerror(errno));
958 		return (0);
959 	}
960 
961 	/*
962 	 * Read a few bytes and determine if the content appears to be
963 	 * printable ASCII characters.  If so, read the entire array and
964 	 * attempt to display it as a string if it is printable.
965 	 */
966 	if ((pap->pa_arstrlim == MDB_ARR_NOLIMIT ||
967 	    r.mta_nelems <= pap->pa_arstrlim) &&
968 	    mdb_ctf_type_encoding(base, &e) == 0 && IS_CHAR(e) &&
969 	    mdb_tgt_readstr(pap->pa_tgt, pap->pa_as, buf,
970 	    MIN(sizeof (buf), r.mta_nelems), addr) > 0 && strisprint(buf)) {
971 
972 		str = mdb_alloc(r.mta_nelems + 1, UM_SLEEP | UM_GC);
973 		str[r.mta_nelems] = '\0';
974 
975 		if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, str,
976 		    r.mta_nelems, addr) != r.mta_nelems) {
977 			mdb_warn("failed to read char array at %llx", addr);
978 			return (1);
979 		}
980 
981 		if (strisprint(str)) {
982 			mdb_printf("[ \"%s\" ]", str);
983 			return (0);
984 		}
985 	}
986 
987 	if (pap->pa_armemlim != MDB_ARR_NOLIMIT)
988 		limit = MIN(r.mta_nelems, pap->pa_armemlim);
989 	else
990 		limit = r.mta_nelems;
991 
992 	if (limit == 0) {
993 		mdb_printf("[ ... ]");
994 		return (0);
995 	}
996 
997 	kind = mdb_ctf_type_kind(base);
998 	sou = IS_COMPOSITE(kind);
999 
1000 	pa.pa_addr = addr;		/* set base address to start of array */
1001 	pa.pa_maxdepth = pa.pa_maxdepth - pa.pa_depth;
1002 	pa.pa_nest += pa.pa_depth + 1;	/* nesting level is current depth + 1 */
1003 	pa.pa_depth = 0;		/* reset depth to 0 for new scope */
1004 	pa.pa_prefix = NULL;
1005 
1006 	if (sou) {
1007 		pa.pa_delim = "\n";
1008 		mdb_printf("[\n");
1009 	} else {
1010 		pa.pa_flags &= ~(PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR);
1011 		pa.pa_delim = ", ";
1012 		mdb_printf("[ ");
1013 	}
1014 
1015 	for (i = 0; i < limit; i++, pa.pa_addr += eltsize) {
1016 		if (i == limit - 1 && !sou) {
1017 			if (limit < r.mta_nelems)
1018 				pa.pa_delim = ", ... ]";
1019 			else
1020 				pa.pa_delim = " ]";
1021 		}
1022 
1023 		if (mdb_ctf_type_visit(r.mta_contents, elt_print, &pa) == -1) {
1024 			mdb_warn("failed to print array data");
1025 			return (1);
1026 		}
1027 	}
1028 
1029 	if (sou) {
1030 		for (d = pa.pa_depth - 1; d >= 0; d--)
1031 			print_close_sou(&pa, d);
1032 
1033 		if (limit < r.mta_nelems) {
1034 			mdb_printf("%*s... ]",
1035 			    (pap->pa_depth + pap->pa_nest) * pap->pa_tab, "");
1036 		} else {
1037 			mdb_printf("%*s]",
1038 			    (pap->pa_depth + pap->pa_nest) * pap->pa_tab, "");
1039 		}
1040 	}
1041 
1042 	/* copy the hole array info, since it may have been grown */
1043 	pap->pa_holes = pa.pa_holes;
1044 	pap->pa_nholes = pa.pa_nholes;
1045 
1046 	return (0);
1047 }
1048 
1049 /*
1050  * Print out a struct or union header.  We need only print the open brace
1051  * because mdb_ctf_type_visit() itself will automatically recurse through
1052  * all members of the given struct or union.
1053  */
1054 /*ARGSUSED*/
1055 static int
1056 print_sou(const char *type, const char *name, mdb_ctf_id_t id,
1057     mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1058 {
1059 	if (pap->pa_depth == pap->pa_maxdepth)
1060 		mdb_printf("{ ... }");
1061 	else
1062 		mdb_printf("{");
1063 	pap->pa_delim = "\n";
1064 	return (0);
1065 }
1066 
1067 /*
1068  * Print an enum value.  We attempt to convert the value to the corresponding
1069  * enum name and print that if possible.
1070  */
1071 /*ARGSUSED*/
1072 static int
1073 print_enum(const char *type, const char *name, mdb_ctf_id_t id,
1074     mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1075 {
1076 	mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
1077 	const char *ename;
1078 	int value;
1079 
1080 	if (!(pap->pa_flags & PA_SHOWVAL))
1081 		return (0);
1082 
1083 	if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
1084 	    &value, sizeof (value), addr) != sizeof (value)) {
1085 		mdb_warn("failed to read %s integer at %llx", name, addr);
1086 		return (1);
1087 	}
1088 
1089 	if (pap->pa_flags & PA_INTHEX)
1090 		mdb_printf("%#x", value);
1091 	else
1092 		mdb_printf("%#d", value);
1093 
1094 	ename = mdb_ctf_enum_name(base, value);
1095 	mdb_printf(" (%s)", (ename != NULL)? ename : "???");
1096 
1097 	return (0);
1098 }
1099 
1100 /*
1101  * Just print a semicolon if we run into a forward tag.
1102  */
1103 /*ARGSUSED*/
1104 static int
1105 print_tag(const char *type, const char *name, mdb_ctf_id_t id,
1106     mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1107 {
1108 	if (pap->pa_flags & PA_SHOWVAL)
1109 		mdb_printf("; ");
1110 
1111 	mdb_printf("(forward declaration)");
1112 	return (0);
1113 }
1114 
1115 static void
1116 print_hole(printarg_t *pap, int depth, ulong_t off, ulong_t endoff)
1117 {
1118 	ulong_t bits = endoff - off;
1119 	ulong_t size = bits / NBBY;
1120 	ctf_encoding_t e;
1121 
1122 	static const char *const name = "<<HOLE>>";
1123 	char type[MDB_SYM_NAMLEN];
1124 
1125 	int bitfield =
1126 	    (off % NBBY != 0 ||
1127 	    bits % NBBY != 0 ||
1128 	    size > 8 ||
1129 	    (size & (size - 1)) != 0);
1130 
1131 	ASSERT(off < endoff);
1132 
1133 	if (bits > NBBY * sizeof (uint64_t)) {
1134 		ulong_t end;
1135 
1136 		/*
1137 		 * The hole is larger than the largest integer type.  To
1138 		 * handle this, we split up the hole at 8-byte-aligned
1139 		 * boundaries, recursing to print each subsection.  For
1140 		 * normal C structures, we'll loop at most twice.
1141 		 */
1142 		for (; off < endoff; off = end) {
1143 			end = P2END(off, NBBY * sizeof (uint64_t));
1144 			if (end > endoff)
1145 				end = endoff;
1146 
1147 			ASSERT((end - off) <= NBBY * sizeof (uint64_t));
1148 			print_hole(pap, depth, off, end);
1149 		}
1150 		ASSERT(end == endoff);
1151 
1152 		return;
1153 	}
1154 
1155 	if (bitfield)
1156 		(void) mdb_snprintf(type, sizeof (type), "unsigned");
1157 	else
1158 		(void) mdb_snprintf(type, sizeof (type), "uint%d_t", bits);
1159 
1160 	if (pap->pa_flags & (PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR))
1161 		mdb_printf("%*s", (depth + pap->pa_nest) * pap->pa_tab, "");
1162 
1163 	if (pap->pa_flags & PA_SHOWADDR) {
1164 		if (off % NBBY == 0)
1165 			mdb_printf("%llx ", pap->pa_addr + off / NBBY);
1166 		else
1167 			mdb_printf("%llx.%lx ",
1168 			    pap->pa_addr + off / NBBY, off % NBBY);
1169 	}
1170 
1171 	if (pap->pa_flags & PA_SHOWTYPE)
1172 		mdb_printf("%s ", type);
1173 
1174 	if (pap->pa_flags & PA_SHOWNAME)
1175 		mdb_printf("%s", name);
1176 
1177 	if (bitfield && (pap->pa_flags & PA_SHOWTYPE))
1178 		mdb_printf(" :%d", bits);
1179 
1180 	mdb_printf("%s ", (pap->pa_flags & PA_SHOWVAL)? " =" : "");
1181 
1182 	/*
1183 	 * We fake up a ctf_encoding_t, and use print_int_val() to print
1184 	 * the value.  Holes are always processed as unsigned integers.
1185 	 */
1186 	bzero(&e, sizeof (e));
1187 	e.cte_format = 0;
1188 	e.cte_offset = 0;
1189 	e.cte_bits = bits;
1190 
1191 	if (print_int_val(type, &e, off, pap) != 0)
1192 		mdb_iob_discard(mdb.m_out);
1193 	else
1194 		mdb_iob_puts(mdb.m_out, pap->pa_delim);
1195 }
1196 
1197 /*
1198  * The print_close_sou() function is called for each structure or union
1199  * which has been completed.  For structures, we detect and print any holes
1200  * before printing the closing brace.
1201  */
1202 static void
1203 print_close_sou(printarg_t *pap, int newdepth)
1204 {
1205 	int d = newdepth + pap->pa_nest;
1206 
1207 	if ((pap->pa_flags & PA_SHOWHOLES) && !pap->pa_holes[d].hi_isunion) {
1208 		ulong_t end = pap->pa_holes[d + 1].hi_offset;
1209 		ulong_t expected = pap->pa_holes[d].hi_offset;
1210 
1211 		if (end < expected)
1212 			print_hole(pap, newdepth + 1, end, expected);
1213 	}
1214 	mdb_printf("%*s}\n", d * pap->pa_tab, "");
1215 }
1216 
1217 static printarg_f *const printfuncs[] = {
1218 	print_int,	/* CTF_K_INTEGER */
1219 	print_float,	/* CTF_K_FLOAT */
1220 	print_ptr,	/* CTF_K_POINTER */
1221 	print_array,	/* CTF_K_ARRAY */
1222 	print_ptr,	/* CTF_K_FUNCTION */
1223 	print_sou,	/* CTF_K_STRUCT */
1224 	print_sou,	/* CTF_K_UNION */
1225 	print_enum,	/* CTF_K_ENUM */
1226 	print_tag	/* CTF_K_FORWARD */
1227 };
1228 
1229 /*
1230  * The elt_print function is used as the mdb_ctf_type_visit callback.  For
1231  * each element, we print an appropriate name prefix and then call the
1232  * print subroutine for this type class in the array above.
1233  */
1234 static int
1235 elt_print(const char *name, mdb_ctf_id_t id, ulong_t off, int depth, void *data)
1236 {
1237 	char type[MDB_SYM_NAMLEN];
1238 	int kind, rc, d;
1239 	mdb_ctf_id_t base;
1240 	printarg_t *pap = data;
1241 
1242 	for (d = pap->pa_depth - 1; d >= depth; d--)
1243 		print_close_sou(pap, d);
1244 
1245 	if (depth > pap->pa_maxdepth)
1246 		return (0);
1247 
1248 	if (mdb_ctf_type_resolve(id, &base) == -1 ||
1249 	    (kind = mdb_ctf_type_kind(base)) == -1)
1250 		return (-1); /* errno is set for us */
1251 
1252 	if (mdb_ctf_type_name(id, type, sizeof (type)) == NULL)
1253 		(void) strcpy(type, "(?)");
1254 
1255 	if (pap->pa_flags & PA_SHOWHOLES) {
1256 		ctf_encoding_t e;
1257 		ssize_t nsize;
1258 		ulong_t newoff;
1259 		holeinfo_t *hole;
1260 		int extra = IS_COMPOSITE(kind)? 1 : 0;
1261 
1262 		/*
1263 		 * grow the hole array, if necessary
1264 		 */
1265 		if (pap->pa_nest + depth + extra >= pap->pa_nholes) {
1266 			int new = MAX(MAX(8, pap->pa_nholes * 2),
1267 			    pap->pa_nest + depth + extra + 1);
1268 
1269 			holeinfo_t *nhi = mdb_zalloc(
1270 			    sizeof (*nhi) * new, UM_NOSLEEP | UM_GC);
1271 
1272 			bcopy(pap->pa_holes, nhi,
1273 			    pap->pa_nholes * sizeof (*nhi));
1274 
1275 			pap->pa_holes = nhi;
1276 			pap->pa_nholes = new;
1277 		}
1278 
1279 		hole = &pap->pa_holes[depth + pap->pa_nest];
1280 
1281 		if (depth != 0 && off > hole->hi_offset)
1282 			print_hole(pap, depth, hole->hi_offset, off);
1283 
1284 		/* compute the next expected offset */
1285 		if (kind == CTF_K_INTEGER &&
1286 		    mdb_ctf_type_encoding(base, &e) == 0)
1287 			newoff = off + e.cte_bits;
1288 		else if ((nsize = mdb_ctf_type_size(base)) >= 0)
1289 			newoff = off + nsize * NBBY;
1290 		else {
1291 			/* something bad happened, disable hole checking */
1292 			newoff = -1UL;		/* ULONG_MAX */
1293 		}
1294 
1295 		hole->hi_offset = newoff;
1296 
1297 		if (IS_COMPOSITE(kind)) {
1298 			hole->hi_isunion = (kind == CTF_K_UNION);
1299 			hole++;
1300 			hole->hi_offset = off;
1301 		}
1302 	}
1303 
1304 	if (pap->pa_flags & (PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR))
1305 		mdb_printf("%*s", (depth + pap->pa_nest) * pap->pa_tab, "");
1306 
1307 	if (depth != 0) {
1308 		if (pap->pa_flags & PA_SHOWADDR) {
1309 			if (off % NBBY == 0)
1310 				mdb_printf("%llx ", pap->pa_addr + off / NBBY);
1311 			else
1312 				mdb_printf("%llx.%lx ",
1313 				    pap->pa_addr + off / NBBY, off % NBBY);
1314 		}
1315 
1316 		if (pap->pa_flags & PA_SHOWTYPE) {
1317 			mdb_printf("%s", type);
1318 			/*
1319 			 * We want to avoid printing a trailing space when
1320 			 * dealing with pointers in a structure, so we end
1321 			 * up with:
1322 			 *
1323 			 *	label_t *t_onfault = 0
1324 			 */
1325 			if (type[strlen(type) - 1] != '*')
1326 				mdb_printf(" ");
1327 		}
1328 
1329 		if (pap->pa_flags & PA_SHOWNAME) {
1330 			if (depth == 1 && pap->pa_prefix != NULL)
1331 				mdb_printf("%s%s", pap->pa_prefix,
1332 				    pap->pa_suffix);
1333 			mdb_printf("%s", name);
1334 		}
1335 
1336 		if ((pap->pa_flags & PA_SHOWTYPE) && kind == CTF_K_INTEGER) {
1337 			ctf_encoding_t e;
1338 
1339 			if (mdb_ctf_type_encoding(base, &e) == 0) {
1340 				ulong_t bits = e.cte_bits;
1341 				ulong_t size = bits / NBBY;
1342 
1343 				if (bits % NBBY != 0 ||
1344 				    off % NBBY != 0 ||
1345 				    size > 8 ||
1346 				    size != mdb_ctf_type_size(base))
1347 					mdb_printf(" :%d", bits);
1348 			}
1349 		}
1350 
1351 		mdb_printf("%s ", pap->pa_flags & PA_SHOWVAL ? " =" : "");
1352 	} else if (IS_SCALAR(kind) || pap->pa_maxdepth == 0) {
1353 		if (pap->pa_flags & PA_SHOWADDR) {
1354 			if (off % NBBY == 0)
1355 				mdb_printf("%llx ", pap->pa_addr + off / NBBY);
1356 			else
1357 				mdb_printf("%llx.%lx ",
1358 				    pap->pa_addr + off / NBBY, off % NBBY);
1359 		}
1360 
1361 		if (pap->pa_flags & PA_SHOWTYPE) {
1362 			mdb_printf("%s", type);
1363 			/*
1364 			 * For the zero-depth case, we always print the trailing
1365 			 * space unless we also have a prefix.
1366 			 */
1367 			if (type[strlen(type) - 1] != '*' ||
1368 			    !((pap->pa_flags & PA_SHOWNAME) &&
1369 			    pap->pa_prefix != NULL))
1370 				mdb_printf(" ", type);
1371 		}
1372 
1373 		if ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL)
1374 			mdb_printf("%s", pap->pa_prefix);
1375 
1376 		if ((pap->pa_flags & PA_SHOWTYPE) &&
1377 		    kind == CTF_K_INTEGER) {
1378 			ctf_encoding_t e;
1379 
1380 			if (mdb_ctf_type_encoding(base, &e) == 0) {
1381 				ulong_t bits = e.cte_bits;
1382 				ulong_t size = bits / NBBY;
1383 
1384 				if (bits % NBBY != 0 ||
1385 				    off % NBBY != 0 ||
1386 				    size > 8 ||
1387 				    size != mdb_ctf_type_size(base))
1388 					mdb_printf(" :%d", bits);
1389 			}
1390 		}
1391 
1392 		if ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL)
1393 			mdb_printf("%s ",
1394 			    pap->pa_flags & PA_SHOWVAL ? " =" : "");
1395 
1396 		if (pap->pa_prefix != NULL)
1397 			name = pap->pa_prefix;
1398 	}
1399 
1400 	pap->pa_depth = depth;
1401 	ASSERT(kind > CTF_K_UNKNOWN && kind < CTF_K_TYPEDEF);
1402 	rc = printfuncs[kind - 1](type, name, id, base, off, pap);
1403 
1404 	if (rc != 0)
1405 		mdb_iob_discard(mdb.m_out);
1406 	else
1407 		mdb_iob_puts(mdb.m_out, pap->pa_delim);
1408 
1409 	return (rc);
1410 }
1411 
1412 /*
1413  * Special semantics for pipelines.
1414  */
1415 static int
1416 pipe_print(mdb_ctf_id_t id, ulong_t off, void *data)
1417 {
1418 	printarg_t *pap = data;
1419 	ssize_t size;
1420 	static const char *const fsp[] = { "%#r", "%#r", "%#r", "%#llr" };
1421 	uintptr_t value;
1422 	uintptr_t addr = pap->pa_addr + off / NBBY;
1423 	mdb_ctf_id_t base;
1424 	ctf_encoding_t e;
1425 
1426 	union {
1427 		uint64_t i8;
1428 		uint32_t i4;
1429 		uint16_t i2;
1430 		uint8_t i1;
1431 	} u;
1432 
1433 	if (mdb_ctf_type_resolve(id, &base) == -1) {
1434 		mdb_warn("could not resolve type\n");
1435 		return (-1);
1436 	}
1437 
1438 	/*
1439 	 * If the user gives -a, then always print out the address of the
1440 	 * member.
1441 	 */
1442 	if ((pap->pa_flags & PA_SHOWADDR)) {
1443 		mdb_printf("%#lr\n", addr);
1444 		return (0);
1445 	}
1446 
1447 again:
1448 	switch (mdb_ctf_type_kind(base)) {
1449 	case CTF_K_POINTER:
1450 		if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
1451 		    &value, sizeof (value), addr) != sizeof (value)) {
1452 			mdb_warn("failed to read pointer at %p", addr);
1453 			return (-1);
1454 		}
1455 		mdb_printf("%#lr\n", value);
1456 		break;
1457 
1458 	case CTF_K_INTEGER:
1459 	case CTF_K_ENUM:
1460 		if (mdb_ctf_type_encoding(base, &e) != 0) {
1461 			mdb_printf("could not get type encoding\n");
1462 			return (-1);
1463 		}
1464 
1465 		/*
1466 		 * For immediate values, we just print out the value.
1467 		 */
1468 		size = e.cte_bits / NBBY;
1469 		if (size > 8 || (e.cte_bits % NBBY) != 0 ||
1470 		    (size & (size - 1)) != 0) {
1471 			return (print_bitfield(off, pap, &e));
1472 		}
1473 
1474 		if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size,
1475 		    addr) != size) {
1476 			mdb_warn("failed to read %lu bytes at %p",
1477 			    (ulong_t)size, pap->pa_addr);
1478 			return (-1);
1479 		}
1480 
1481 		switch (size) {
1482 		case sizeof (uint8_t):
1483 			mdb_printf(fsp[0], u.i1);
1484 			break;
1485 		case sizeof (uint16_t):
1486 			mdb_printf(fsp[1], u.i2);
1487 			break;
1488 		case sizeof (uint32_t):
1489 			mdb_printf(fsp[2], u.i4);
1490 			break;
1491 		case sizeof (uint64_t):
1492 			mdb_printf(fsp[3], u.i8);
1493 			break;
1494 		}
1495 		mdb_printf("\n");
1496 		break;
1497 
1498 	case CTF_K_FUNCTION:
1499 	case CTF_K_FLOAT:
1500 	case CTF_K_ARRAY:
1501 	case CTF_K_UNKNOWN:
1502 	case CTF_K_STRUCT:
1503 	case CTF_K_UNION:
1504 	case CTF_K_FORWARD:
1505 		/*
1506 		 * For these types, always print the address of the member
1507 		 */
1508 		mdb_printf("%#lr\n", addr);
1509 		break;
1510 
1511 	default:
1512 		mdb_warn("unknown type %d", mdb_ctf_type_kind(base));
1513 		break;
1514 	}
1515 
1516 	return (0);
1517 }
1518 
1519 static int
1520 parse_delimiter(char **strp)
1521 {
1522 	switch (**strp) {
1523 	case '\0':
1524 		return (MEMBER_DELIM_DONE);
1525 
1526 	case '.':
1527 		*strp = *strp + 1;
1528 		return (MEMBER_DELIM_DOT);
1529 
1530 	case '[':
1531 		*strp = *strp + 1;
1532 		return (MEMBER_DELIM_LBR);
1533 
1534 	case '-':
1535 		*strp = *strp + 1;
1536 		if (**strp == '>') {
1537 			*strp = *strp + 1;
1538 			return (MEMBER_DELIM_PTR);
1539 		}
1540 		*strp = *strp - 1;
1541 		/*FALLTHROUGH*/
1542 	default:
1543 		return (MEMBER_DELIM_ERR);
1544 	}
1545 }
1546 
1547 static int
1548 deref(printarg_t *pap, size_t size)
1549 {
1550 	uint32_t a32;
1551 	mdb_tgt_as_t as = pap->pa_as;
1552 	mdb_tgt_addr_t *ap = &pap->pa_addr;
1553 
1554 	if (size == sizeof (mdb_tgt_addr_t)) {
1555 		if (mdb_tgt_aread(mdb.m_target, as, ap, size, *ap) == -1) {
1556 			mdb_warn("could not dereference pointer %llx\n", *ap);
1557 			return (-1);
1558 		}
1559 	} else {
1560 		if (mdb_tgt_aread(mdb.m_target, as, &a32, size, *ap) == -1) {
1561 			mdb_warn("could not dereference pointer %x\n", *ap);
1562 			return (-1);
1563 		}
1564 
1565 		*ap = (mdb_tgt_addr_t)a32;
1566 	}
1567 
1568 	/*
1569 	 * We've dereferenced at least once, we must be on the real
1570 	 * target. If we were in the immediate target, reset to the real
1571 	 * target; it's reset as needed when we return to the print
1572 	 * routines.
1573 	 */
1574 	if (pap->pa_tgt == pap->pa_immtgt)
1575 		pap->pa_tgt = pap->pa_realtgt;
1576 
1577 	return (0);
1578 }
1579 
1580 static int
1581 parse_member(printarg_t *pap, const char *str, mdb_ctf_id_t id,
1582     mdb_ctf_id_t *idp, ulong_t *offp, int *last_deref)
1583 {
1584 	int delim;
1585 	char member[64];
1586 	char buf[128];
1587 	uint_t index;
1588 	char *start = (char *)str;
1589 	char *end;
1590 	ulong_t off = 0;
1591 	mdb_ctf_arinfo_t ar;
1592 	mdb_ctf_id_t rid;
1593 	int kind;
1594 	ssize_t size;
1595 	int non_array = FALSE;
1596 
1597 	/*
1598 	 * id always has the unresolved type for printing error messages
1599 	 * that include the type; rid always has the resolved type for
1600 	 * use in mdb_ctf_* calls.  It is possible for this command to fail,
1601 	 * however, if the resolved type is in the parent and it is currently
1602 	 * unavailable.  Note that we also can't print out the name of the
1603 	 * type, since that would also rely on looking up the resolved name.
1604 	 */
1605 	if (mdb_ctf_type_resolve(id, &rid) != 0) {
1606 		mdb_warn("failed to resolve type");
1607 		return (-1);
1608 	}
1609 
1610 	delim = parse_delimiter(&start);
1611 	/*
1612 	 * If the user fails to specify an initial delimiter, guess -> for
1613 	 * pointer types and . for non-pointer types.
1614 	 */
1615 	if (delim == MEMBER_DELIM_ERR)
1616 		delim = (mdb_ctf_type_kind(rid) == CTF_K_POINTER) ?
1617 		    MEMBER_DELIM_PTR : MEMBER_DELIM_DOT;
1618 
1619 	*last_deref = FALSE;
1620 
1621 	while (delim != MEMBER_DELIM_DONE) {
1622 		switch (delim) {
1623 		case MEMBER_DELIM_PTR:
1624 			kind = mdb_ctf_type_kind(rid);
1625 			if (kind != CTF_K_POINTER) {
1626 				mdb_warn("%s is not a pointer type\n",
1627 				    mdb_ctf_type_name(id, buf, sizeof (buf)));
1628 				return (-1);
1629 			}
1630 
1631 			size = mdb_ctf_type_size(id);
1632 			if (deref(pap, size) != 0)
1633 				return (-1);
1634 
1635 			(void) mdb_ctf_type_reference(rid, &id);
1636 			(void) mdb_ctf_type_resolve(id, &rid);
1637 
1638 			off = 0;
1639 			break;
1640 
1641 		case MEMBER_DELIM_DOT:
1642 			kind = mdb_ctf_type_kind(rid);
1643 			if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) {
1644 				mdb_warn("%s is not a struct or union type\n",
1645 				    mdb_ctf_type_name(id, buf, sizeof (buf)));
1646 				return (-1);
1647 			}
1648 			break;
1649 
1650 		case MEMBER_DELIM_LBR:
1651 			end = strchr(start, ']');
1652 			if (end == NULL) {
1653 				mdb_warn("no trailing ']'\n");
1654 				return (-1);
1655 			}
1656 
1657 			(void) mdb_snprintf(member, end - start + 1, start);
1658 
1659 			index = mdb_strtoull(member);
1660 
1661 			switch (mdb_ctf_type_kind(rid)) {
1662 			case CTF_K_POINTER:
1663 				size = mdb_ctf_type_size(rid);
1664 
1665 				if (deref(pap, size) != 0)
1666 					return (-1);
1667 
1668 				(void) mdb_ctf_type_reference(rid, &id);
1669 				(void) mdb_ctf_type_resolve(id, &rid);
1670 
1671 				size = mdb_ctf_type_size(id);
1672 				if (size <= 0) {
1673 					mdb_warn("cannot dereference void "
1674 					    "type\n");
1675 					return (-1);
1676 				}
1677 
1678 				pap->pa_addr += index * size;
1679 				off = 0;
1680 
1681 				if (index == 0 && non_array)
1682 					*last_deref = TRUE;
1683 				break;
1684 
1685 			case CTF_K_ARRAY:
1686 				(void) mdb_ctf_array_info(rid, &ar);
1687 
1688 				if (index >= ar.mta_nelems) {
1689 					mdb_warn("index %r is outside of "
1690 					    "array bounds [0 .. %r]\n",
1691 					    index, ar.mta_nelems - 1);
1692 				}
1693 
1694 				id = ar.mta_contents;
1695 				(void) mdb_ctf_type_resolve(id, &rid);
1696 
1697 				size = mdb_ctf_type_size(id);
1698 				if (size <= 0) {
1699 					mdb_warn("cannot dereference void "
1700 					    "type\n");
1701 					return (-1);
1702 				}
1703 
1704 				pap->pa_addr += index * size;
1705 				off = 0;
1706 				break;
1707 
1708 			default:
1709 				mdb_warn("cannot index into non-array, "
1710 				    "non-pointer type\n");
1711 				return (-1);
1712 			}
1713 
1714 			start = end + 1;
1715 			delim = parse_delimiter(&start);
1716 			continue;
1717 
1718 		case MEMBER_DELIM_ERR:
1719 		default:
1720 			mdb_warn("'%c' is not a valid delimiter\n", *start);
1721 			return (-1);
1722 		}
1723 
1724 		*last_deref = FALSE;
1725 		non_array = TRUE;
1726 
1727 		/*
1728 		 * Find the end of the member name; assume that a member
1729 		 * name is at least one character long.
1730 		 */
1731 		for (end = start + 1; isalnum(*end) || *end == '_'; end++)
1732 			continue;
1733 
1734 		(void) mdb_snprintf(member, end - start + 1, start);
1735 
1736 		if (mdb_ctf_member_info(rid, member, &off, &id) != 0) {
1737 			mdb_warn("failed to find member %s of %s", member,
1738 			    mdb_ctf_type_name(id, buf, sizeof (buf)));
1739 			return (-1);
1740 		}
1741 		(void) mdb_ctf_type_resolve(id, &rid);
1742 
1743 		pap->pa_addr += off / NBBY;
1744 
1745 		start = end;
1746 		delim = parse_delimiter(&start);
1747 	}
1748 
1749 
1750 	*idp = id;
1751 	*offp = off;
1752 
1753 	return (0);
1754 }
1755 
1756 /*
1757  * Recursively descend a print a given data structure.  We create a struct of
1758  * the relevant print arguments and then call mdb_ctf_type_visit() to do the
1759  * traversal, using elt_print() as the callback for each element.
1760  */
1761 /*ARGSUSED*/
1762 int
1763 cmd_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1764 {
1765 	uintptr_t opt_c = MDB_ARR_NOLIMIT, opt_l = MDB_ARR_NOLIMIT;
1766 	uint_t opt_C = FALSE, opt_L = FALSE, opt_p = FALSE, opt_i = FALSE;
1767 	uintptr_t opt_s = (uintptr_t)-1ul;
1768 	int uflags = (flags & DCMD_ADDRSPEC) ? PA_SHOWVAL : 0;
1769 	mdb_ctf_id_t id;
1770 	int err = DCMD_OK;
1771 
1772 	mdb_tgt_t *t = mdb.m_target;
1773 	printarg_t pa;
1774 	int d, i;
1775 
1776 	char s_name[MDB_SYM_NAMLEN];
1777 	mdb_syminfo_t s_info;
1778 	GElf_Sym sym;
1779 
1780 	i = mdb_getopts(argc, argv,
1781 	    'a', MDB_OPT_SETBITS, PA_SHOWADDR, &uflags,
1782 	    'C', MDB_OPT_SETBITS, TRUE, &opt_C,
1783 	    'd', MDB_OPT_SETBITS, PA_INTDEC, &uflags,
1784 	    'h', MDB_OPT_SETBITS, PA_SHOWHOLES, &uflags,
1785 	    'L', MDB_OPT_SETBITS, TRUE, &opt_L,
1786 	    'n', MDB_OPT_SETBITS, PA_NOSYMBOLIC, &uflags,
1787 	    'p', MDB_OPT_SETBITS, TRUE, &opt_p,
1788 	    't', MDB_OPT_SETBITS, PA_SHOWTYPE, &uflags,
1789 	    'x', MDB_OPT_SETBITS, PA_INTHEX, &uflags,
1790 	    'c', MDB_OPT_UINTPTR, &opt_c,
1791 	    'l', MDB_OPT_UINTPTR, &opt_l,
1792 	    'i', MDB_OPT_SETBITS, TRUE, &opt_i,
1793 	    's', MDB_OPT_UINTPTR, &opt_s,
1794 	    NULL);
1795 
1796 	if (uflags & PA_INTHEX)
1797 		uflags &= ~PA_INTDEC;	/* -x and -d are mutually exclusive */
1798 
1799 	uflags |= PA_SHOWNAME;
1800 
1801 	if (opt_p && opt_i) {
1802 		mdb_warn("-p and -i options are incompatible\n");
1803 		return (DCMD_ERR);
1804 	}
1805 
1806 	argc -= i;
1807 	argv += i;
1808 
1809 	if (argc != 0 && argv->a_type == MDB_TYPE_STRING) {
1810 		const char *t_name = s_name;
1811 		int ret;
1812 
1813 		if (strchr("+-", argv->a_un.a_str[0]) != NULL)
1814 			return (DCMD_USAGE);
1815 
1816 		if ((ret = args_to_typename(&argc, &argv, s_name,
1817 		    sizeof (s_name))) != 0)
1818 			return (ret);
1819 
1820 		if (mdb_ctf_lookup_by_name(t_name, &id) != 0) {
1821 			if (!(flags & DCMD_ADDRSPEC) || opt_i ||
1822 			    addr_to_sym(t, addr, s_name, sizeof (s_name),
1823 				&sym, &s_info) == NULL ||
1824 			    mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) {
1825 
1826 				mdb_warn("failed to look up type %s", t_name);
1827 				return (DCMD_ABORT);
1828 			}
1829 		} else {
1830 			argc--;
1831 			argv++;
1832 		}
1833 
1834 	} else if (!(flags & DCMD_ADDRSPEC) || opt_i) {
1835 		return (DCMD_USAGE);
1836 
1837 	} else if (addr_to_sym(t, addr, s_name, sizeof (s_name),
1838 	    &sym, &s_info) == NULL) {
1839 		mdb_warn("no symbol information for %a", addr);
1840 		return (DCMD_ERR);
1841 
1842 	} else if (mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) {
1843 		mdb_warn("no type data available for %a [%u]", addr,
1844 		    s_info.sym_id);
1845 		return (DCMD_ERR);
1846 	}
1847 
1848 	pa.pa_tgt = mdb.m_target;
1849 	pa.pa_realtgt = pa.pa_tgt;
1850 	pa.pa_immtgt = NULL;
1851 	pa.pa_as = opt_p ? MDB_TGT_AS_PHYS : MDB_TGT_AS_VIRT;
1852 	pa.pa_armemlim = mdb.m_armemlim;
1853 	pa.pa_arstrlim = mdb.m_arstrlim;
1854 	pa.pa_delim = "\n";
1855 	pa.pa_flags = uflags;
1856 	pa.pa_nest = 0;
1857 	pa.pa_tab = 4;
1858 	pa.pa_prefix = NULL;
1859 	pa.pa_suffix = NULL;
1860 	pa.pa_holes = NULL;
1861 	pa.pa_nholes = 0;
1862 	pa.pa_depth = 0;
1863 	pa.pa_maxdepth = opt_s;
1864 
1865 	if ((flags & DCMD_ADDRSPEC) && !opt_i)
1866 		pa.pa_addr = opt_p ? mdb_get_dot() : addr;
1867 	else
1868 		pa.pa_addr = NULL;
1869 
1870 	if (opt_i) {
1871 		const char *vargv[2];
1872 		uintmax_t dot = mdb_get_dot();
1873 		size_t outsize = mdb_ctf_type_size(id);
1874 		vargv[0] = (const char *)&dot;
1875 		vargv[1] = (const char *)&outsize;
1876 		pa.pa_immtgt = mdb_tgt_create(mdb_value_tgt_create,
1877 			0, 2, vargv);
1878 		pa.pa_tgt = pa.pa_immtgt;
1879 	}
1880 
1881 	if (opt_c != MDB_ARR_NOLIMIT)
1882 		pa.pa_arstrlim = opt_c;
1883 	if (opt_C)
1884 		pa.pa_arstrlim = MDB_ARR_NOLIMIT;
1885 	if (opt_l != MDB_ARR_NOLIMIT)
1886 		pa.pa_armemlim = opt_l;
1887 	if (opt_L)
1888 		pa.pa_armemlim = MDB_ARR_NOLIMIT;
1889 
1890 	if (argc > 0) {
1891 		for (i = 0; i < argc; i++) {
1892 			mdb_ctf_id_t mid;
1893 			int last_deref;
1894 			ulong_t off;
1895 			int kind;
1896 			char buf[MDB_SYM_NAMLEN];
1897 
1898 			mdb_tgt_t *oldtgt = pa.pa_tgt;
1899 			mdb_tgt_as_t oldas = pa.pa_as;
1900 			mdb_tgt_addr_t oldaddr = pa.pa_addr;
1901 
1902 			if (argv->a_type == MDB_TYPE_STRING) {
1903 				const char *member = argv[i].a_un.a_str;
1904 				mdb_ctf_id_t rid;
1905 
1906 				if (parse_member(&pa, member, id, &mid,
1907 				    &off, &last_deref) != 0) {
1908 					err = DCMD_ABORT;
1909 					goto out;
1910 				}
1911 
1912 				/*
1913 				 * If the member string ends with a "[0]"
1914 				 * (last_deref * is true) and the type is a
1915 				 * structure or union, * print "->" rather
1916 				 * than "[0]." in elt_print.
1917 				 */
1918 				(void) mdb_ctf_type_resolve(mid, &rid);
1919 				kind = mdb_ctf_type_kind(rid);
1920 				if (last_deref && IS_SOU(kind)) {
1921 					char *end;
1922 					(void) mdb_snprintf(buf, sizeof (buf),
1923 					    "%s", member);
1924 					end = strrchr(buf, '[');
1925 					*end = '\0';
1926 					pa.pa_suffix = "->";
1927 					member = &buf[0];
1928 				} else if (IS_SOU(kind)) {
1929 					pa.pa_suffix = ".";
1930 				} else {
1931 					pa.pa_suffix = "";
1932 				}
1933 
1934 				pa.pa_prefix = member;
1935 			} else {
1936 				ulong_t moff;
1937 
1938 				moff = (ulong_t)argv[i].a_un.a_val;
1939 
1940 				if (mdb_ctf_offset_to_name(id, moff * NBBY,
1941 				    buf, sizeof (buf), 0, &mid, &off) == -1) {
1942 					mdb_warn("invalid offset %lx\n", moff);
1943 					err = DCMD_ABORT;
1944 					goto out;
1945 				}
1946 
1947 				pa.pa_prefix = buf;
1948 				pa.pa_addr += moff - off / NBBY;
1949 				pa.pa_suffix = strlen(buf) == 0 ? "" : ".";
1950 			}
1951 
1952 			off %= NBBY;
1953 			if (flags & DCMD_PIPE_OUT) {
1954 				if (pipe_print(mid, off, &pa) != 0) {
1955 					mdb_warn("failed to print type");
1956 					err = DCMD_ERR;
1957 					goto out;
1958 				}
1959 			} else if (off != 0) {
1960 				if (elt_print("", mid, off, 0, &pa) != 0) {
1961 					mdb_warn("failed to print type");
1962 					err = DCMD_ERR;
1963 					goto out;
1964 				}
1965 			} else {
1966 				if (mdb_ctf_type_visit(mid, elt_print,
1967 				    &pa) == -1) {
1968 					mdb_warn("failed to print type");
1969 					err = DCMD_ERR;
1970 					goto out;
1971 				}
1972 
1973 				for (d = pa.pa_depth - 1; d >= 0; d--)
1974 					print_close_sou(&pa, d);
1975 			}
1976 
1977 			pa.pa_depth = 0;
1978 			pa.pa_tgt = oldtgt;
1979 			pa.pa_as = oldas;
1980 			pa.pa_addr = oldaddr;
1981 			pa.pa_delim = "\n";
1982 		}
1983 
1984 	} else if (flags & DCMD_PIPE_OUT) {
1985 		if (pipe_print(id, 0, &pa) != 0) {
1986 			mdb_warn("failed to print type");
1987 			err = DCMD_ERR;
1988 			goto out;
1989 		}
1990 	} else {
1991 		if (mdb_ctf_type_visit(id, elt_print, &pa) == -1) {
1992 			mdb_warn("failed to print type");
1993 			err = DCMD_ERR;
1994 			goto out;
1995 		}
1996 
1997 		for (d = pa.pa_depth - 1; d >= 0; d--)
1998 			print_close_sou(&pa, d);
1999 	}
2000 
2001 	mdb_set_dot(addr + mdb_ctf_type_size(id));
2002 	err = DCMD_OK;
2003 out:
2004 	if (pa.pa_immtgt)
2005 		mdb_tgt_destroy(pa.pa_immtgt);
2006 	return (err);
2007 }
2008 
2009 void
2010 print_help(void)
2011 {
2012 	mdb_printf("-a         show address of object\n"
2013 	    "-c limit   limit the length of character arrays\n"
2014 	    "-C         unlimit the length of character arrays\n"
2015 	    "-d         output values in decimal\n"
2016 	    "-h         print holes in structures\n"
2017 	    "-l limit   limit the length of standard arrays\n"
2018 	    "-L         unlimit the length of standard arrays\n"
2019 	    "-n         don't print pointers as symbol offsets\n"
2020 	    "-p         interpret address as a physical memory address\n"
2021 	    "-t         show type of object\n"
2022 	    "-i         interpret address as data of the given type\n"
2023 	    "-x         output values in hexadecimal\n"
2024 	    "-s depth   limit the recursion depth\n"
2025 	    "\n"
2026 	    "type may be omitted if the C type of addr can be inferred.\n"
2027 	    "\n"
2028 	    "Members may be specified with standard C syntax using the\n"
2029 	    "array indexing operator \"[index]\", structure member\n"
2030 	    "operator \".\", or structure pointer operator \"->\".\n"
2031 	    "\n"
2032 	    "Offsets must use the $[ expression ] syntax\n");
2033 }
2034