Mercurial > illumos > onarm
annotate usr/src/cmd/mdb/common/mdb/mdb_print.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 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 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
26 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 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 if (kind <= CTF_K_UNKNOWN || kind >= CTF_K_TYPEDEF) { | |
1402 mdb_warn("unknown ctf for %s type %s kind %d\n", | |
1403 name, type, kind); | |
1404 return (-1); | |
1405 } | |
1406 rc = printfuncs[kind - 1](type, name, id, base, off, pap); | |
1407 | |
1408 if (rc != 0) | |
1409 mdb_iob_discard(mdb.m_out); | |
1410 else | |
1411 mdb_iob_puts(mdb.m_out, pap->pa_delim); | |
1412 | |
1413 return (rc); | |
1414 } | |
1415 | |
1416 /* | |
1417 * Special semantics for pipelines. | |
1418 */ | |
1419 static int | |
1420 pipe_print(mdb_ctf_id_t id, ulong_t off, void *data) | |
1421 { | |
1422 printarg_t *pap = data; | |
1423 ssize_t size; | |
1424 static const char *const fsp[] = { "%#r", "%#r", "%#r", "%#llr" }; | |
1425 uintptr_t value; | |
1426 uintptr_t addr = pap->pa_addr + off / NBBY; | |
1427 mdb_ctf_id_t base; | |
1428 ctf_encoding_t e; | |
1429 | |
1430 union { | |
1431 uint64_t i8; | |
1432 uint32_t i4; | |
1433 uint16_t i2; | |
1434 uint8_t i1; | |
1435 } u; | |
1436 | |
1437 if (mdb_ctf_type_resolve(id, &base) == -1) { | |
1438 mdb_warn("could not resolve type\n"); | |
1439 return (-1); | |
1440 } | |
1441 | |
1442 /* | |
1443 * If the user gives -a, then always print out the address of the | |
1444 * member. | |
1445 */ | |
1446 if ((pap->pa_flags & PA_SHOWADDR)) { | |
1447 mdb_printf("%#lr\n", addr); | |
1448 return (0); | |
1449 } | |
1450 | |
1451 again: | |
1452 switch (mdb_ctf_type_kind(base)) { | |
1453 case CTF_K_POINTER: | |
1454 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, | |
1455 &value, sizeof (value), addr) != sizeof (value)) { | |
1456 mdb_warn("failed to read pointer at %p", addr); | |
1457 return (-1); | |
1458 } | |
1459 mdb_printf("%#lr\n", value); | |
1460 break; | |
1461 | |
1462 case CTF_K_INTEGER: | |
1463 case CTF_K_ENUM: | |
1464 if (mdb_ctf_type_encoding(base, &e) != 0) { | |
1465 mdb_printf("could not get type encoding\n"); | |
1466 return (-1); | |
1467 } | |
1468 | |
1469 /* | |
1470 * For immediate values, we just print out the value. | |
1471 */ | |
1472 size = e.cte_bits / NBBY; | |
1473 if (size > 8 || (e.cte_bits % NBBY) != 0 || | |
1474 (size & (size - 1)) != 0) { | |
1475 return (print_bitfield(off, pap, &e)); | |
1476 } | |
1477 | |
1478 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size, | |
1479 addr) != size) { | |
1480 mdb_warn("failed to read %lu bytes at %p", | |
1481 (ulong_t)size, pap->pa_addr); | |
1482 return (-1); | |
1483 } | |
1484 | |
1485 switch (size) { | |
1486 case sizeof (uint8_t): | |
1487 mdb_printf(fsp[0], u.i1); | |
1488 break; | |
1489 case sizeof (uint16_t): | |
1490 mdb_printf(fsp[1], u.i2); | |
1491 break; | |
1492 case sizeof (uint32_t): | |
1493 mdb_printf(fsp[2], u.i4); | |
1494 break; | |
1495 case sizeof (uint64_t): | |
1496 mdb_printf(fsp[3], u.i8); | |
1497 break; | |
1498 } | |
1499 mdb_printf("\n"); | |
1500 break; | |
1501 | |
1502 case CTF_K_FUNCTION: | |
1503 case CTF_K_FLOAT: | |
1504 case CTF_K_ARRAY: | |
1505 case CTF_K_UNKNOWN: | |
1506 case CTF_K_STRUCT: | |
1507 case CTF_K_UNION: | |
1508 case CTF_K_FORWARD: | |
1509 /* | |
1510 * For these types, always print the address of the member | |
1511 */ | |
1512 mdb_printf("%#lr\n", addr); | |
1513 break; | |
1514 | |
1515 default: | |
1516 mdb_warn("unknown type %d", mdb_ctf_type_kind(base)); | |
1517 break; | |
1518 } | |
1519 | |
1520 return (0); | |
1521 } | |
1522 | |
1523 static int | |
1524 parse_delimiter(char **strp) | |
1525 { | |
1526 switch (**strp) { | |
1527 case '\0': | |
1528 return (MEMBER_DELIM_DONE); | |
1529 | |
1530 case '.': | |
1531 *strp = *strp + 1; | |
1532 return (MEMBER_DELIM_DOT); | |
1533 | |
1534 case '[': | |
1535 *strp = *strp + 1; | |
1536 return (MEMBER_DELIM_LBR); | |
1537 | |
1538 case '-': | |
1539 *strp = *strp + 1; | |
1540 if (**strp == '>') { | |
1541 *strp = *strp + 1; | |
1542 return (MEMBER_DELIM_PTR); | |
1543 } | |
1544 *strp = *strp - 1; | |
1545 /*FALLTHROUGH*/ | |
1546 default: | |
1547 return (MEMBER_DELIM_ERR); | |
1548 } | |
1549 } | |
1550 | |
1551 static int | |
1552 deref(printarg_t *pap, size_t size) | |
1553 { | |
1554 uint32_t a32; | |
1555 mdb_tgt_as_t as = pap->pa_as; | |
1556 mdb_tgt_addr_t *ap = &pap->pa_addr; | |
1557 | |
1558 if (size == sizeof (mdb_tgt_addr_t)) { | |
1559 if (mdb_tgt_aread(mdb.m_target, as, ap, size, *ap) == -1) { | |
1560 mdb_warn("could not dereference pointer %llx\n", *ap); | |
1561 return (-1); | |
1562 } | |
1563 } else { | |
1564 if (mdb_tgt_aread(mdb.m_target, as, &a32, size, *ap) == -1) { | |
1565 mdb_warn("could not dereference pointer %x\n", *ap); | |
1566 return (-1); | |
1567 } | |
1568 | |
1569 *ap = (mdb_tgt_addr_t)a32; | |
1570 } | |
1571 | |
1572 /* | |
1573 * We've dereferenced at least once, we must be on the real | |
1574 * target. If we were in the immediate target, reset to the real | |
1575 * target; it's reset as needed when we return to the print | |
1576 * routines. | |
1577 */ | |
1578 if (pap->pa_tgt == pap->pa_immtgt) | |
1579 pap->pa_tgt = pap->pa_realtgt; | |
1580 | |
1581 return (0); | |
1582 } | |
1583 | |
1584 static int | |
1585 parse_member(printarg_t *pap, const char *str, mdb_ctf_id_t id, | |
1586 mdb_ctf_id_t *idp, ulong_t *offp, int *last_deref) | |
1587 { | |
1588 int delim; | |
1589 char member[64]; | |
1590 char buf[128]; | |
1591 uint_t index; | |
1592 char *start = (char *)str; | |
1593 char *end; | |
1594 ulong_t off = 0; | |
1595 mdb_ctf_arinfo_t ar; | |
1596 mdb_ctf_id_t rid; | |
1597 int kind; | |
1598 ssize_t size; | |
1599 int non_array = FALSE; | |
1600 | |
1601 /* | |
1602 * id always has the unresolved type for printing error messages | |
1603 * that include the type; rid always has the resolved type for | |
1604 * use in mdb_ctf_* calls. It is possible for this command to fail, | |
1605 * however, if the resolved type is in the parent and it is currently | |
1606 * unavailable. Note that we also can't print out the name of the | |
1607 * type, since that would also rely on looking up the resolved name. | |
1608 */ | |
1609 if (mdb_ctf_type_resolve(id, &rid) != 0) { | |
1610 mdb_warn("failed to resolve type"); | |
1611 return (-1); | |
1612 } | |
1613 | |
1614 delim = parse_delimiter(&start); | |
1615 /* | |
1616 * If the user fails to specify an initial delimiter, guess -> for | |
1617 * pointer types and . for non-pointer types. | |
1618 */ | |
1619 if (delim == MEMBER_DELIM_ERR) | |
1620 delim = (mdb_ctf_type_kind(rid) == CTF_K_POINTER) ? | |
1621 MEMBER_DELIM_PTR : MEMBER_DELIM_DOT; | |
1622 | |
1623 *last_deref = FALSE; | |
1624 | |
1625 while (delim != MEMBER_DELIM_DONE) { | |
1626 switch (delim) { | |
1627 case MEMBER_DELIM_PTR: | |
1628 kind = mdb_ctf_type_kind(rid); | |
1629 if (kind != CTF_K_POINTER) { | |
1630 mdb_warn("%s is not a pointer type\n", | |
1631 mdb_ctf_type_name(id, buf, sizeof (buf))); | |
1632 return (-1); | |
1633 } | |
1634 | |
1635 size = mdb_ctf_type_size(id); | |
1636 if (deref(pap, size) != 0) | |
1637 return (-1); | |
1638 | |
1639 (void) mdb_ctf_type_reference(rid, &id); | |
1640 (void) mdb_ctf_type_resolve(id, &rid); | |
1641 | |
1642 off = 0; | |
1643 break; | |
1644 | |
1645 case MEMBER_DELIM_DOT: | |
1646 kind = mdb_ctf_type_kind(rid); | |
1647 if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) { | |
1648 mdb_warn("%s is not a struct or union type\n", | |
1649 mdb_ctf_type_name(id, buf, sizeof (buf))); | |
1650 return (-1); | |
1651 } | |
1652 break; | |
1653 | |
1654 case MEMBER_DELIM_LBR: | |
1655 end = strchr(start, ']'); | |
1656 if (end == NULL) { | |
1657 mdb_warn("no trailing ']'\n"); | |
1658 return (-1); | |
1659 } | |
1660 | |
1661 (void) mdb_snprintf(member, end - start + 1, start); | |
1662 | |
1663 index = mdb_strtoull(member); | |
1664 | |
1665 switch (mdb_ctf_type_kind(rid)) { | |
1666 case CTF_K_POINTER: | |
1667 size = mdb_ctf_type_size(rid); | |
1668 | |
1669 if (deref(pap, size) != 0) | |
1670 return (-1); | |
1671 | |
1672 (void) mdb_ctf_type_reference(rid, &id); | |
1673 (void) mdb_ctf_type_resolve(id, &rid); | |
1674 | |
1675 size = mdb_ctf_type_size(id); | |
1676 if (size <= 0) { | |
1677 mdb_warn("cannot dereference void " | |
1678 "type\n"); | |
1679 return (-1); | |
1680 } | |
1681 | |
1682 pap->pa_addr += index * size; | |
1683 off = 0; | |
1684 | |
1685 if (index == 0 && non_array) | |
1686 *last_deref = TRUE; | |
1687 break; | |
1688 | |
1689 case CTF_K_ARRAY: | |
1690 (void) mdb_ctf_array_info(rid, &ar); | |
1691 | |
1692 if (index >= ar.mta_nelems) { | |
1693 mdb_warn("index %r is outside of " | |
1694 "array bounds [0 .. %r]\n", | |
1695 index, ar.mta_nelems - 1); | |
1696 } | |
1697 | |
1698 id = ar.mta_contents; | |
1699 (void) mdb_ctf_type_resolve(id, &rid); | |
1700 | |
1701 size = mdb_ctf_type_size(id); | |
1702 if (size <= 0) { | |
1703 mdb_warn("cannot dereference void " | |
1704 "type\n"); | |
1705 return (-1); | |
1706 } | |
1707 | |
1708 pap->pa_addr += index * size; | |
1709 off = 0; | |
1710 break; | |
1711 | |
1712 default: | |
1713 mdb_warn("cannot index into non-array, " | |
1714 "non-pointer type\n"); | |
1715 return (-1); | |
1716 } | |
1717 | |
1718 start = end + 1; | |
1719 delim = parse_delimiter(&start); | |
1720 continue; | |
1721 | |
1722 case MEMBER_DELIM_ERR: | |
1723 default: | |
1724 mdb_warn("'%c' is not a valid delimiter\n", *start); | |
1725 return (-1); | |
1726 } | |
1727 | |
1728 *last_deref = FALSE; | |
1729 non_array = TRUE; | |
1730 | |
1731 /* | |
1732 * Find the end of the member name; assume that a member | |
1733 * name is at least one character long. | |
1734 */ | |
1735 for (end = start + 1; isalnum(*end) || *end == '_'; end++) | |
1736 continue; | |
1737 | |
1738 (void) mdb_snprintf(member, end - start + 1, start); | |
1739 | |
1740 if (mdb_ctf_member_info(rid, member, &off, &id) != 0) { | |
1741 mdb_warn("failed to find member %s of %s", member, | |
1742 mdb_ctf_type_name(id, buf, sizeof (buf))); | |
1743 return (-1); | |
1744 } | |
1745 (void) mdb_ctf_type_resolve(id, &rid); | |
1746 | |
1747 pap->pa_addr += off / NBBY; | |
1748 | |
1749 start = end; | |
1750 delim = parse_delimiter(&start); | |
1751 } | |
1752 | |
1753 | |
1754 *idp = id; | |
1755 *offp = off; | |
1756 | |
1757 return (0); | |
1758 } | |
1759 | |
1760 /* | |
1761 * Recursively descend a print a given data structure. We create a struct of | |
1762 * the relevant print arguments and then call mdb_ctf_type_visit() to do the | |
1763 * traversal, using elt_print() as the callback for each element. | |
1764 */ | |
1765 /*ARGSUSED*/ | |
1766 int | |
1767 cmd_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) | |
1768 { | |
1769 uintptr_t opt_c = MDB_ARR_NOLIMIT, opt_l = MDB_ARR_NOLIMIT; | |
1770 uint_t opt_C = FALSE, opt_L = FALSE, opt_p = FALSE, opt_i = FALSE; | |
1771 uintptr_t opt_s = (uintptr_t)-1ul; | |
1772 int uflags = (flags & DCMD_ADDRSPEC) ? PA_SHOWVAL : 0; | |
1773 mdb_ctf_id_t id; | |
1774 int err = DCMD_OK; | |
1775 | |
1776 mdb_tgt_t *t = mdb.m_target; | |
1777 printarg_t pa; | |
1778 int d, i; | |
1779 | |
1780 char s_name[MDB_SYM_NAMLEN]; | |
1781 mdb_syminfo_t s_info; | |
1782 GElf_Sym sym; | |
1783 | |
1784 i = mdb_getopts(argc, argv, | |
1785 'a', MDB_OPT_SETBITS, PA_SHOWADDR, &uflags, | |
1786 'C', MDB_OPT_SETBITS, TRUE, &opt_C, | |
1787 'd', MDB_OPT_SETBITS, PA_INTDEC, &uflags, | |
1788 'h', MDB_OPT_SETBITS, PA_SHOWHOLES, &uflags, | |
1789 'L', MDB_OPT_SETBITS, TRUE, &opt_L, | |
1790 'n', MDB_OPT_SETBITS, PA_NOSYMBOLIC, &uflags, | |
1791 'p', MDB_OPT_SETBITS, TRUE, &opt_p, | |
1792 't', MDB_OPT_SETBITS, PA_SHOWTYPE, &uflags, | |
1793 'x', MDB_OPT_SETBITS, PA_INTHEX, &uflags, | |
1794 'c', MDB_OPT_UINTPTR, &opt_c, | |
1795 'l', MDB_OPT_UINTPTR, &opt_l, | |
1796 'i', MDB_OPT_SETBITS, TRUE, &opt_i, | |
1797 's', MDB_OPT_UINTPTR, &opt_s, | |
1798 NULL); | |
1799 | |
1800 if (uflags & PA_INTHEX) | |
1801 uflags &= ~PA_INTDEC; /* -x and -d are mutually exclusive */ | |
1802 | |
1803 uflags |= PA_SHOWNAME; | |
1804 | |
1805 if (opt_p && opt_i) { | |
1806 mdb_warn("-p and -i options are incompatible\n"); | |
1807 return (DCMD_ERR); | |
1808 } | |
1809 | |
1810 argc -= i; | |
1811 argv += i; | |
1812 | |
1813 if (argc != 0 && argv->a_type == MDB_TYPE_STRING) { | |
1814 const char *t_name = s_name; | |
1815 int ret; | |
1816 | |
1817 if (strchr("+-", argv->a_un.a_str[0]) != NULL) | |
1818 return (DCMD_USAGE); | |
1819 | |
1820 if ((ret = args_to_typename(&argc, &argv, s_name, | |
1821 sizeof (s_name))) != 0) | |
1822 return (ret); | |
1823 | |
1824 if (mdb_ctf_lookup_by_name(t_name, &id) != 0) { | |
1825 if (!(flags & DCMD_ADDRSPEC) || opt_i || | |
1826 addr_to_sym(t, addr, s_name, sizeof (s_name), | |
1827 &sym, &s_info) == NULL || | |
1828 mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) { | |
1829 | |
1830 mdb_warn("failed to look up type %s", t_name); | |
1831 return (DCMD_ABORT); | |
1832 } | |
1833 } else { | |
1834 argc--; | |
1835 argv++; | |
1836 } | |
1837 | |
1838 } else if (!(flags & DCMD_ADDRSPEC) || opt_i) { | |
1839 return (DCMD_USAGE); | |
1840 | |
1841 } else if (addr_to_sym(t, addr, s_name, sizeof (s_name), | |
1842 &sym, &s_info) == NULL) { | |
1843 mdb_warn("no symbol information for %a", addr); | |
1844 return (DCMD_ERR); | |
1845 | |
1846 } else if (mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) { | |
1847 mdb_warn("no type data available for %a [%u]", addr, | |
1848 s_info.sym_id); | |
1849 return (DCMD_ERR); | |
1850 } | |
1851 | |
1852 pa.pa_tgt = mdb.m_target; | |
1853 pa.pa_realtgt = pa.pa_tgt; | |
1854 pa.pa_immtgt = NULL; | |
1855 pa.pa_as = opt_p ? MDB_TGT_AS_PHYS : MDB_TGT_AS_VIRT; | |
1856 pa.pa_armemlim = mdb.m_armemlim; | |
1857 pa.pa_arstrlim = mdb.m_arstrlim; | |
1858 pa.pa_delim = "\n"; | |
1859 pa.pa_flags = uflags; | |
1860 pa.pa_nest = 0; | |
1861 pa.pa_tab = 4; | |
1862 pa.pa_prefix = NULL; | |
1863 pa.pa_suffix = NULL; | |
1864 pa.pa_holes = NULL; | |
1865 pa.pa_nholes = 0; | |
1866 pa.pa_depth = 0; | |
1867 pa.pa_maxdepth = opt_s; | |
1868 | |
1869 if ((flags & DCMD_ADDRSPEC) && !opt_i) | |
1870 pa.pa_addr = opt_p ? mdb_get_dot() : addr; | |
1871 else | |
1872 pa.pa_addr = NULL; | |
1873 | |
1874 if (opt_i) { | |
1875 const char *vargv[2]; | |
1876 uintmax_t dot = mdb_get_dot(); | |
1877 size_t outsize = mdb_ctf_type_size(id); | |
1878 vargv[0] = (const char *)˙ | |
1879 vargv[1] = (const char *)&outsize; | |
1880 pa.pa_immtgt = mdb_tgt_create(mdb_value_tgt_create, | |
1881 0, 2, vargv); | |
1882 pa.pa_tgt = pa.pa_immtgt; | |
1883 } | |
1884 | |
1885 if (opt_c != MDB_ARR_NOLIMIT) | |
1886 pa.pa_arstrlim = opt_c; | |
1887 if (opt_C) | |
1888 pa.pa_arstrlim = MDB_ARR_NOLIMIT; | |
1889 if (opt_l != MDB_ARR_NOLIMIT) | |
1890 pa.pa_armemlim = opt_l; | |
1891 if (opt_L) | |
1892 pa.pa_armemlim = MDB_ARR_NOLIMIT; | |
1893 | |
1894 if (argc > 0) { | |
1895 for (i = 0; i < argc; i++) { | |
1896 mdb_ctf_id_t mid; | |
1897 int last_deref; | |
1898 ulong_t off; | |
1899 int kind; | |
1900 char buf[MDB_SYM_NAMLEN]; | |
1901 | |
1902 mdb_tgt_t *oldtgt = pa.pa_tgt; | |
1903 mdb_tgt_as_t oldas = pa.pa_as; | |
1904 mdb_tgt_addr_t oldaddr = pa.pa_addr; | |
1905 | |
1906 if (argv->a_type == MDB_TYPE_STRING) { | |
1907 const char *member = argv[i].a_un.a_str; | |
1908 mdb_ctf_id_t rid; | |
1909 | |
1910 if (parse_member(&pa, member, id, &mid, | |
1911 &off, &last_deref) != 0) { | |
1912 err = DCMD_ABORT; | |
1913 goto out; | |
1914 } | |
1915 | |
1916 /* | |
1917 * If the member string ends with a "[0]" | |
1918 * (last_deref * is true) and the type is a | |
1919 * structure or union, * print "->" rather | |
1920 * than "[0]." in elt_print. | |
1921 */ | |
1922 (void) mdb_ctf_type_resolve(mid, &rid); | |
1923 kind = mdb_ctf_type_kind(rid); | |
1924 if (last_deref && IS_SOU(kind)) { | |
1925 char *end; | |
1926 (void) mdb_snprintf(buf, sizeof (buf), | |
1927 "%s", member); | |
1928 end = strrchr(buf, '['); | |
1929 *end = '\0'; | |
1930 pa.pa_suffix = "->"; | |
1931 member = &buf[0]; | |
1932 } else if (IS_SOU(kind)) { | |
1933 pa.pa_suffix = "."; | |
1934 } else { | |
1935 pa.pa_suffix = ""; | |
1936 } | |
1937 | |
1938 pa.pa_prefix = member; | |
1939 } else { | |
1940 ulong_t moff; | |
1941 | |
1942 moff = (ulong_t)argv[i].a_un.a_val; | |
1943 | |
1944 if (mdb_ctf_offset_to_name(id, moff * NBBY, | |
1945 buf, sizeof (buf), 0, &mid, &off) == -1) { | |
1946 mdb_warn("invalid offset %lx\n", moff); | |
1947 err = DCMD_ABORT; | |
1948 goto out; | |
1949 } | |
1950 | |
1951 pa.pa_prefix = buf; | |
1952 pa.pa_addr += moff - off / NBBY; | |
1953 pa.pa_suffix = strlen(buf) == 0 ? "" : "."; | |
1954 } | |
1955 | |
1956 off %= NBBY; | |
1957 if (flags & DCMD_PIPE_OUT) { | |
1958 if (pipe_print(mid, off, &pa) != 0) { | |
1959 mdb_warn("failed to print type"); | |
1960 err = DCMD_ERR; | |
1961 goto out; | |
1962 } | |
1963 } else if (off != 0) { | |
1964 if (elt_print("", mid, off, 0, &pa) != 0) { | |
1965 mdb_warn("failed to print type"); | |
1966 err = DCMD_ERR; | |
1967 goto out; | |
1968 } | |
1969 } else { | |
1970 if (mdb_ctf_type_visit(mid, elt_print, | |
1971 &pa) == -1) { | |
1972 mdb_warn("failed to print type"); | |
1973 err = DCMD_ERR; | |
1974 goto out; | |
1975 } | |
1976 | |
1977 for (d = pa.pa_depth - 1; d >= 0; d--) | |
1978 print_close_sou(&pa, d); | |
1979 } | |
1980 | |
1981 pa.pa_depth = 0; | |
1982 pa.pa_tgt = oldtgt; | |
1983 pa.pa_as = oldas; | |
1984 pa.pa_addr = oldaddr; | |
1985 pa.pa_delim = "\n"; | |
1986 } | |
1987 | |
1988 } else if (flags & DCMD_PIPE_OUT) { | |
1989 if (pipe_print(id, 0, &pa) != 0) { | |
1990 mdb_warn("failed to print type"); | |
1991 err = DCMD_ERR; | |
1992 goto out; | |
1993 } | |
1994 } else { | |
1995 if (mdb_ctf_type_visit(id, elt_print, &pa) == -1) { | |
1996 mdb_warn("failed to print type"); | |
1997 err = DCMD_ERR; | |
1998 goto out; | |
1999 } | |
2000 | |
2001 for (d = pa.pa_depth - 1; d >= 0; d--) | |
2002 print_close_sou(&pa, d); | |
2003 } | |
2004 | |
2005 mdb_set_dot(addr + mdb_ctf_type_size(id)); | |
2006 err = DCMD_OK; | |
2007 out: | |
2008 if (pa.pa_immtgt) | |
2009 mdb_tgt_destroy(pa.pa_immtgt); | |
2010 return (err); | |
2011 } | |
2012 | |
2013 void | |
2014 print_help(void) | |
2015 { | |
2016 mdb_printf("-a show address of object\n" | |
2017 "-c limit limit the length of character arrays\n" | |
2018 "-C unlimit the length of character arrays\n" | |
2019 "-d output values in decimal\n" | |
2020 "-h print holes in structures\n" | |
2021 "-l limit limit the length of standard arrays\n" | |
2022 "-L unlimit the length of standard arrays\n" | |
2023 "-n don't print pointers as symbol offsets\n" | |
2024 "-p interpret address as a physical memory address\n" | |
2025 "-t show type of object\n" | |
2026 "-i interpret address as data of the given type\n" | |
2027 "-x output values in hexadecimal\n" | |
2028 "-s depth limit the recursion depth\n" | |
2029 "\n" | |
2030 "type may be omitted if the C type of addr can be inferred.\n" | |
2031 "\n" | |
2032 "Members may be specified with standard C syntax using the\n" | |
2033 "array indexing operator \"[index]\", structure member\n" | |
2034 "operator \".\", or structure pointer operator \"->\".\n" | |
2035 "\n" | |
2036 "Offsets must use the $[ expression ] syntax\n"); | |
2037 } |