Print this page
5231 ::printf doesn't handle enums
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: Alex Reece <alex@delphix.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mdb/common/mdb/mdb_print.c
+++ new/usr/src/cmd/mdb/common/mdb/mdb_print.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
28 28 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
29 + * Copyright (c) 2014 Nexenta Systems, Inc. All rights reserved.
29 30 */
30 31
31 32 #include <mdb/mdb_modapi.h>
32 33 #include <mdb/mdb_target.h>
33 34 #include <mdb/mdb_argvec.h>
34 35 #include <mdb/mdb_string.h>
35 36 #include <mdb/mdb_stdlib.h>
36 37 #include <mdb/mdb_err.h>
37 38 #include <mdb/mdb_debug.h>
38 39 #include <mdb/mdb_fmt.h>
39 40 #include <mdb/mdb_ctf.h>
40 41 #include <mdb/mdb_ctf_impl.h>
41 42 #include <mdb/mdb.h>
42 43 #include <mdb/mdb_tab.h>
43 44
44 45 #include <sys/isa_defs.h>
45 46 #include <sys/param.h>
46 47 #include <sys/sysmacros.h>
47 48 #include <netinet/in.h>
48 49 #include <strings.h>
49 50 #include <libctf.h>
50 51 #include <ctype.h>
51 52
52 53 typedef struct holeinfo {
53 54 ulong_t hi_offset; /* expected offset */
54 55 uchar_t hi_isunion; /* represents a union */
55 56 } holeinfo_t;
56 57
57 58 typedef struct printarg {
58 59 mdb_tgt_t *pa_tgt; /* current target */
59 60 mdb_tgt_t *pa_realtgt; /* real target (for -i) */
60 61 mdb_tgt_t *pa_immtgt; /* immediate target (for -i) */
61 62 mdb_tgt_as_t pa_as; /* address space to use for i/o */
62 63 mdb_tgt_addr_t pa_addr; /* base address for i/o */
63 64 ulong_t pa_armemlim; /* limit on array elements to print */
64 65 ulong_t pa_arstrlim; /* limit on array chars to print */
65 66 const char *pa_delim; /* element delimiter string */
66 67 const char *pa_prefix; /* element prefix string */
67 68 const char *pa_suffix; /* element suffix string */
68 69 holeinfo_t *pa_holes; /* hole detection information */
69 70 int pa_nholes; /* size of holes array */
70 71 int pa_flags; /* formatting flags (see below) */
71 72 int pa_depth; /* previous depth */
72 73 int pa_nest; /* array nesting depth */
73 74 int pa_tab; /* tabstop width */
74 75 uint_t pa_maxdepth; /* Limit max depth */
75 76 uint_t pa_nooutdepth; /* don't print output past this depth */
76 77 } printarg_t;
77 78
78 79 #define PA_SHOWTYPE 0x001 /* print type name */
79 80 #define PA_SHOWBASETYPE 0x002 /* print base type name */
80 81 #define PA_SHOWNAME 0x004 /* print member name */
81 82 #define PA_SHOWADDR 0x008 /* print address */
82 83 #define PA_SHOWVAL 0x010 /* print value */
83 84 #define PA_SHOWHOLES 0x020 /* print holes in structs */
84 85 #define PA_INTHEX 0x040 /* print integer values in hex */
85 86 #define PA_INTDEC 0x080 /* print integer values in decimal */
86 87 #define PA_NOSYMBOLIC 0x100 /* don't print ptrs as func+offset */
87 88
88 89 #define IS_CHAR(e) \
89 90 (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
90 91 (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
91 92
92 93 #define COMPOSITE_MASK ((1 << CTF_K_STRUCT) | \
93 94 (1 << CTF_K_UNION) | (1 << CTF_K_ARRAY))
94 95 #define IS_COMPOSITE(k) (((1 << k) & COMPOSITE_MASK) != 0)
95 96
96 97 #define SOU_MASK ((1 << CTF_K_STRUCT) | (1 << CTF_K_UNION))
97 98 #define IS_SOU(k) (((1 << k) & SOU_MASK) != 0)
98 99
99 100 #define MEMBER_DELIM_ERR -1
100 101 #define MEMBER_DELIM_DONE 0
101 102 #define MEMBER_DELIM_PTR 1
102 103 #define MEMBER_DELIM_DOT 2
103 104 #define MEMBER_DELIM_LBR 3
104 105
105 106 typedef int printarg_f(const char *, const char *,
106 107 mdb_ctf_id_t, mdb_ctf_id_t, ulong_t, printarg_t *);
107 108
108 109 static int elt_print(const char *, mdb_ctf_id_t, mdb_ctf_id_t, ulong_t, int,
109 110 void *);
110 111 static void print_close_sou(printarg_t *, int);
111 112
112 113 /*
113 114 * Given an address, look up the symbol ID of the specified symbol in its
114 115 * containing module. We only support lookups for exact matches.
115 116 */
116 117 static const char *
117 118 addr_to_sym(mdb_tgt_t *t, uintptr_t addr, char *name, size_t namelen,
118 119 GElf_Sym *symp, mdb_syminfo_t *sip)
119 120 {
120 121 const mdb_map_t *mp;
121 122 const char *p;
122 123
123 124 if (mdb_tgt_lookup_by_addr(t, addr, MDB_TGT_SYM_EXACT, name,
124 125 namelen, NULL, NULL) == -1)
125 126 return (NULL); /* address does not exactly match a symbol */
126 127
127 128 if ((p = strrsplit(name, '`')) != NULL) {
128 129 if (mdb_tgt_lookup_by_name(t, name, p, symp, sip) == -1)
129 130 return (NULL);
130 131 return (p);
131 132 }
132 133
133 134 if ((mp = mdb_tgt_addr_to_map(t, addr)) == NULL)
134 135 return (NULL); /* address does not fall within a mapping */
135 136
136 137 if (mdb_tgt_lookup_by_name(t, mp->map_name, name, symp, sip) == -1)
137 138 return (NULL);
138 139
139 140 return (name);
140 141 }
141 142
142 143 /*
143 144 * This lets dcmds be a little fancy with their processing of type arguments
144 145 * while still treating them more or less as a single argument.
145 146 * For example, if a command is invokes like this:
146 147 *
147 148 * ::<dcmd> proc_t ...
148 149 *
149 150 * this function will just copy "proc_t" into the provided buffer. If the
150 151 * command is instead invoked like this:
151 152 *
152 153 * ::<dcmd> struct proc ...
153 154 *
154 155 * this function will place the string "struct proc" into the provided buffer
155 156 * and increment the caller's argv and argc. This allows the caller to still
156 157 * treat the type argument logically as it would an other atomic argument.
157 158 */
158 159 int
159 160 args_to_typename(int *argcp, const mdb_arg_t **argvp, char *buf, size_t len)
160 161 {
161 162 int argc = *argcp;
162 163 const mdb_arg_t *argv = *argvp;
163 164
164 165 if (argc < 1 || argv->a_type != MDB_TYPE_STRING)
165 166 return (DCMD_USAGE);
166 167
167 168 if (strcmp(argv->a_un.a_str, "struct") == 0 ||
168 169 strcmp(argv->a_un.a_str, "enum") == 0 ||
169 170 strcmp(argv->a_un.a_str, "union") == 0) {
170 171 if (argc <= 1) {
171 172 mdb_warn("%s is not a valid type\n", argv->a_un.a_str);
172 173 return (DCMD_ABORT);
173 174 }
174 175
175 176 if (argv[1].a_type != MDB_TYPE_STRING)
176 177 return (DCMD_USAGE);
177 178
178 179 (void) mdb_snprintf(buf, len, "%s %s",
179 180 argv[0].a_un.a_str, argv[1].a_un.a_str);
180 181
181 182 *argcp = argc - 1;
182 183 *argvp = argv + 1;
183 184 } else {
184 185 (void) mdb_snprintf(buf, len, "%s", argv[0].a_un.a_str);
185 186 }
186 187
187 188 return (0);
188 189 }
189 190
190 191 /*ARGSUSED*/
191 192 int
192 193 cmd_sizeof(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
193 194 {
194 195 mdb_ctf_id_t id;
195 196 char tn[MDB_SYM_NAMLEN];
196 197 int ret;
197 198
198 199 if (flags & DCMD_ADDRSPEC)
199 200 return (DCMD_USAGE);
200 201
201 202 if ((ret = args_to_typename(&argc, &argv, tn, sizeof (tn))) != 0)
202 203 return (ret);
203 204
204 205 if (argc != 1)
205 206 return (DCMD_USAGE);
206 207
207 208 if (mdb_ctf_lookup_by_name(tn, &id) != 0) {
208 209 mdb_warn("failed to look up type %s", tn);
209 210 return (DCMD_ERR);
210 211 }
211 212
212 213 if (flags & DCMD_PIPE_OUT)
213 214 mdb_printf("%#lr\n", mdb_ctf_type_size(id));
214 215 else
215 216 mdb_printf("sizeof (%s) = %#lr\n", tn, mdb_ctf_type_size(id));
216 217
217 218 return (DCMD_OK);
218 219 }
219 220
220 221 int
221 222 cmd_sizeof_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
222 223 const mdb_arg_t *argv)
223 224 {
224 225 char tn[MDB_SYM_NAMLEN];
225 226 int ret;
226 227
227 228 if (argc == 0 && !(flags & DCMD_TAB_SPACE))
228 229 return (0);
229 230
230 231 if (argc == 0 && (flags & DCMD_TAB_SPACE))
231 232 return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_NOPOINT));
232 233
233 234 if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0)
234 235 return (ret);
235 236
236 237 if (argc == 1)
237 238 return (mdb_tab_complete_type(mcp, tn, MDB_TABC_NOPOINT));
238 239
239 240 return (0);
240 241 }
241 242
242 243 /*ARGSUSED*/
243 244 int
244 245 cmd_offsetof(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
245 246 {
246 247 const char *member;
247 248 mdb_ctf_id_t id;
248 249 ulong_t off;
249 250 char tn[MDB_SYM_NAMLEN];
250 251 ssize_t sz;
251 252 int ret;
252 253
253 254 if (flags & DCMD_ADDRSPEC)
254 255 return (DCMD_USAGE);
255 256
256 257 if ((ret = args_to_typename(&argc, &argv, tn, sizeof (tn))) != 0)
257 258 return (ret);
258 259
259 260 if (argc != 2 || argv[1].a_type != MDB_TYPE_STRING)
260 261 return (DCMD_USAGE);
261 262
262 263 if (mdb_ctf_lookup_by_name(tn, &id) != 0) {
263 264 mdb_warn("failed to look up type %s", tn);
264 265 return (DCMD_ERR);
265 266 }
266 267
267 268 member = argv[1].a_un.a_str;
268 269
269 270 if (mdb_ctf_member_info(id, member, &off, &id) != 0) {
270 271 mdb_warn("failed to find member %s of type %s", member, tn);
271 272 return (DCMD_ERR);
272 273 }
273 274
274 275 if (flags & DCMD_PIPE_OUT) {
275 276 if (off % NBBY != 0) {
276 277 mdb_warn("member %s of type %s is not byte-aligned\n",
277 278 member, tn);
278 279 return (DCMD_ERR);
279 280 }
280 281 mdb_printf("%#lr", off / NBBY);
281 282 return (DCMD_OK);
282 283 }
283 284
284 285 mdb_printf("offsetof (%s, %s) = %#lr",
285 286 tn, member, off / NBBY);
286 287 if (off % NBBY != 0)
287 288 mdb_printf(".%lr", off % NBBY);
288 289
289 290 if ((sz = mdb_ctf_type_size(id)) > 0)
290 291 mdb_printf(", sizeof (...->%s) = %#lr", member, sz);
291 292
292 293 mdb_printf("\n");
293 294
294 295 return (DCMD_OK);
295 296 }
296 297
297 298 /*ARGSUSED*/
298 299 static int
299 300 enum_prefix_scan_cb(const char *name, int value, void *arg)
300 301 {
301 302 char *str = arg;
302 303
303 304 /*
304 305 * This function is called with every name in the enum. We make
305 306 * "arg" be the common prefix, if any.
306 307 */
307 308 if (str[0] == 0) {
308 309 if (strlcpy(arg, name, MDB_SYM_NAMLEN) >= MDB_SYM_NAMLEN)
309 310 return (1);
310 311 return (0);
311 312 }
312 313
313 314 while (*name == *str) {
314 315 if (*str == 0) {
315 316 if (str != arg) {
316 317 str--; /* don't smother a name completely */
317 318 }
318 319 break;
319 320 }
320 321 name++;
321 322 str++;
322 323 }
323 324 *str = 0;
324 325
325 326 return (str == arg); /* only continue if prefix is non-empty */
326 327 }
327 328
328 329 struct enum_p2_info {
329 330 intmax_t e_value; /* value we're processing */
330 331 char *e_buf; /* buffer for holding names */
331 332 size_t e_size; /* size of buffer */
332 333 size_t e_prefix; /* length of initial prefix */
333 334 uint_t e_allprefix; /* apply prefix to first guy, too */
334 335 uint_t e_bits; /* bits seen */
335 336 uint8_t e_found; /* have we seen anything? */
336 337 uint8_t e_first; /* does buf contain the first one? */
337 338 uint8_t e_zero; /* have we seen a zero value? */
338 339 };
339 340
340 341 static int
341 342 enum_p2_cb(const char *name, int bit_arg, void *arg)
342 343 {
343 344 struct enum_p2_info *eiip = arg;
344 345 uintmax_t bit = bit_arg;
345 346
346 347 if (bit != 0 && !ISP2(bit))
347 348 return (1); /* non-power-of-2; abort processing */
348 349
349 350 if ((bit == 0 && eiip->e_zero) ||
350 351 (bit != 0 && (eiip->e_bits & bit) != 0)) {
351 352 return (0); /* already seen this value */
352 353 }
353 354
354 355 if (bit == 0)
355 356 eiip->e_zero = 1;
356 357 else
357 358 eiip->e_bits |= bit;
358 359
359 360 if (eiip->e_buf != NULL && (eiip->e_value & bit) != 0) {
360 361 char *buf = eiip->e_buf;
361 362 size_t prefix = eiip->e_prefix;
362 363
363 364 if (eiip->e_found) {
364 365 (void) strlcat(buf, "|", eiip->e_size);
365 366
366 367 if (eiip->e_first && !eiip->e_allprefix && prefix > 0) {
367 368 char c1 = buf[prefix];
368 369 char c2 = buf[prefix + 1];
369 370 buf[prefix] = '{';
370 371 buf[prefix + 1] = 0;
371 372 mdb_printf("%s", buf);
372 373 buf[prefix] = c1;
373 374 buf[prefix + 1] = c2;
374 375 mdb_printf("%s", buf + prefix);
375 376 } else {
376 377 mdb_printf("%s", buf);
377 378 }
378 379
379 380 }
380 381 /* skip the common prefix as necessary */
381 382 if ((eiip->e_found || eiip->e_allprefix) &&
382 383 strlen(name) > prefix)
383 384 name += prefix;
384 385
385 386 (void) strlcpy(eiip->e_buf, name, eiip->e_size);
386 387 eiip->e_first = !eiip->e_found;
387 388 eiip->e_found = 1;
388 389 }
389 390 return (0);
390 391 }
391 392
392 393 static int
393 394 enum_is_p2(mdb_ctf_id_t id)
394 395 {
395 396 struct enum_p2_info eii;
396 397 bzero(&eii, sizeof (eii));
397 398
398 399 return (mdb_ctf_type_kind(id) == CTF_K_ENUM &&
399 400 mdb_ctf_enum_iter(id, enum_p2_cb, &eii) == 0 &&
400 401 eii.e_bits != 0);
401 402 }
402 403
403 404 static int
404 405 enum_value_print_p2(mdb_ctf_id_t id, intmax_t value, uint_t allprefix)
405 406 {
406 407 struct enum_p2_info eii;
407 408 char prefix[MDB_SYM_NAMLEN + 2];
408 409 intmax_t missed;
409 410
410 411 bzero(&eii, sizeof (eii));
411 412
412 413 eii.e_value = value;
413 414 eii.e_buf = prefix;
414 415 eii.e_size = sizeof (prefix);
415 416 eii.e_allprefix = allprefix;
416 417
417 418 prefix[0] = 0;
418 419 if (mdb_ctf_enum_iter(id, enum_prefix_scan_cb, prefix) == 0)
419 420 eii.e_prefix = strlen(prefix);
420 421
421 422 if (mdb_ctf_enum_iter(id, enum_p2_cb, &eii) != 0 || eii.e_bits == 0)
422 423 return (-1);
423 424
424 425 missed = (value & ~(intmax_t)eii.e_bits);
425 426
426 427 if (eii.e_found) {
427 428 /* push out any final value, with a | if we missed anything */
428 429 if (!eii.e_first)
429 430 (void) strlcat(prefix, "}", sizeof (prefix));
430 431 if (missed != 0)
431 432 (void) strlcat(prefix, "|", sizeof (prefix));
432 433
433 434 mdb_printf("%s", prefix);
434 435 }
435 436
436 437 if (!eii.e_found || missed) {
437 438 mdb_printf("%#llx", missed);
438 439 }
439 440
440 441 return (0);
441 442 }
442 443
443 444 struct enum_cbinfo {
444 445 uint_t e_flags;
445 446 const char *e_string; /* NULL for value searches */
446 447 size_t e_prefix;
447 448 intmax_t e_value;
448 449 uint_t e_found;
449 450 mdb_ctf_id_t e_id;
450 451 };
451 452 #define E_PRETTY 0x01
452 453 #define E_HEX 0x02
453 454 #define E_SEARCH_STRING 0x04
454 455 #define E_SEARCH_VALUE 0x08
455 456 #define E_ELIDE_PREFIX 0x10
456 457
457 458 static void
458 459 enum_print(struct enum_cbinfo *info, const char *name, int value)
459 460 {
460 461 uint_t flags = info->e_flags;
461 462 uint_t elide_prefix = (info->e_flags & E_ELIDE_PREFIX);
462 463
463 464 if (name != NULL && info->e_prefix && strlen(name) > info->e_prefix)
464 465 name += info->e_prefix;
465 466
466 467 if (flags & E_PRETTY) {
467 468 uint_t indent = 5 + ((flags & E_HEX) ? 8 : 11);
468 469
469 470 mdb_printf((flags & E_HEX)? "%8x " : "%11d ", value);
470 471 (void) mdb_inc_indent(indent);
471 472 if (name != NULL) {
472 473 mdb_iob_puts(mdb.m_out, name);
473 474 } else {
474 475 (void) enum_value_print_p2(info->e_id, value,
475 476 elide_prefix);
476 477 }
477 478 (void) mdb_dec_indent(indent);
478 479 mdb_printf("\n");
479 480 } else {
480 481 mdb_printf("%#r\n", value);
481 482 }
482 483 }
483 484
484 485 static int
485 486 enum_cb(const char *name, int value, void *arg)
486 487 {
487 488 struct enum_cbinfo *info = arg;
488 489 uint_t flags = info->e_flags;
489 490
490 491 if (flags & E_SEARCH_STRING) {
491 492 if (strcmp(name, info->e_string) != 0)
492 493 return (0);
493 494
494 495 } else if (flags & E_SEARCH_VALUE) {
495 496 if (value != info->e_value)
496 497 return (0);
497 498 }
498 499
499 500 enum_print(info, name, value);
500 501
501 502 info->e_found = 1;
502 503 return (0);
503 504 }
504 505
505 506 void
506 507 enum_help(void)
507 508 {
508 509 mdb_printf("%s",
509 510 "Without an address and name, print all values for the enumeration \"enum\".\n"
510 511 "With an address, look up a particular value in \"enum\". With a name, look\n"
511 512 "up a particular name in \"enum\".\n");
512 513
513 514 (void) mdb_dec_indent(2);
514 515 mdb_printf("\n%<b>OPTIONS%</b>\n");
515 516 (void) mdb_inc_indent(2);
516 517
517 518 mdb_printf("%s",
518 519 " -e remove common prefixes from enum names\n"
519 520 " -x report enum values in hexadecimal\n");
520 521 }
521 522
522 523 /*ARGSUSED*/
523 524 int
524 525 cmd_enum(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
525 526 {
526 527 struct enum_cbinfo info;
527 528
528 529 char type[MDB_SYM_NAMLEN + sizeof ("enum ")];
529 530 char tn2[MDB_SYM_NAMLEN + sizeof ("enum ")];
530 531 char prefix[MDB_SYM_NAMLEN];
531 532 mdb_ctf_id_t id;
532 533 mdb_ctf_id_t idr;
533 534
534 535 int i;
535 536 intmax_t search;
536 537 uint_t isp2;
537 538
538 539 info.e_flags = (flags & DCMD_PIPE_OUT)? 0 : E_PRETTY;
539 540 info.e_string = NULL;
540 541 info.e_value = 0;
541 542 info.e_found = 0;
542 543
543 544 i = mdb_getopts(argc, argv,
544 545 'e', MDB_OPT_SETBITS, E_ELIDE_PREFIX, &info.e_flags,
545 546 'x', MDB_OPT_SETBITS, E_HEX, &info.e_flags,
546 547 NULL);
547 548
548 549 argc -= i;
549 550 argv += i;
550 551
551 552 if ((i = args_to_typename(&argc, &argv, type, MDB_SYM_NAMLEN)) != 0)
552 553 return (i);
553 554
554 555 if (strchr(type, ' ') == NULL) {
555 556 /*
556 557 * Check as an enumeration tag first, and fall back
557 558 * to checking for a typedef. Yes, this means that
558 559 * anonymous enumerations whose typedefs conflict with
559 560 * an enum tag can't be accessed. Don't do that.
560 561 */
561 562 (void) mdb_snprintf(tn2, sizeof (tn2), "enum %s", type);
562 563
563 564 if (mdb_ctf_lookup_by_name(tn2, &id) == 0) {
564 565 (void) strcpy(type, tn2);
565 566 } else if (mdb_ctf_lookup_by_name(type, &id) != 0) {
566 567 mdb_warn("types '%s', '%s'", tn2, type);
567 568 return (DCMD_ERR);
568 569 }
569 570 } else {
570 571 if (mdb_ctf_lookup_by_name(type, &id) != 0) {
571 572 mdb_warn("'%s'", type);
572 573 return (DCMD_ERR);
573 574 }
574 575 }
575 576
576 577 /* resolve it, and make sure we're looking at an enumeration */
577 578 if (mdb_ctf_type_resolve(id, &idr) == -1) {
578 579 mdb_warn("unable to resolve '%s'", type);
579 580 return (DCMD_ERR);
580 581 }
581 582 if (mdb_ctf_type_kind(idr) != CTF_K_ENUM) {
582 583 mdb_warn("'%s': not an enumeration\n", type);
583 584 return (DCMD_ERR);
584 585 }
585 586
586 587 info.e_id = idr;
587 588
588 589 if (argc > 2)
589 590 return (DCMD_USAGE);
590 591
591 592 if (argc == 2) {
592 593 if (flags & DCMD_ADDRSPEC) {
593 594 mdb_warn("may only specify one of: name, address\n");
594 595 return (DCMD_USAGE);
595 596 }
596 597
597 598 if (argv[1].a_type == MDB_TYPE_STRING) {
598 599 info.e_flags |= E_SEARCH_STRING;
599 600 info.e_string = argv[1].a_un.a_str;
600 601 } else if (argv[1].a_type == MDB_TYPE_IMMEDIATE) {
601 602 info.e_flags |= E_SEARCH_VALUE;
602 603 search = argv[1].a_un.a_val;
603 604 } else {
604 605 return (DCMD_USAGE);
605 606 }
606 607 }
607 608
608 609 if (flags & DCMD_ADDRSPEC) {
609 610 info.e_flags |= E_SEARCH_VALUE;
610 611 search = mdb_get_dot();
611 612 }
612 613
613 614 if (info.e_flags & E_SEARCH_VALUE) {
614 615 if ((int)search != search) {
615 616 mdb_warn("value '%lld' out of enumeration range\n",
616 617 search);
617 618 }
618 619 info.e_value = search;
619 620 }
620 621
621 622 isp2 = enum_is_p2(idr);
622 623 if (isp2)
623 624 info.e_flags |= E_HEX;
624 625
625 626 if (DCMD_HDRSPEC(flags) && (info.e_flags & E_PRETTY)) {
626 627 if (info.e_flags & E_HEX)
627 628 mdb_printf("%<u>%8s %-64s%</u>\n", "VALUE", "NAME");
628 629 else
629 630 mdb_printf("%<u>%11s %-64s%</u>\n", "VALUE", "NAME");
630 631 }
631 632
632 633 /* if the enum is a power-of-two one, process it that way */
633 634 if ((info.e_flags & E_SEARCH_VALUE) && isp2) {
634 635 enum_print(&info, NULL, info.e_value);
635 636 return (DCMD_OK);
636 637 }
637 638
638 639 prefix[0] = 0;
639 640 if ((info.e_flags & E_ELIDE_PREFIX) &&
640 641 mdb_ctf_enum_iter(id, enum_prefix_scan_cb, prefix) == 0)
641 642 info.e_prefix = strlen(prefix);
642 643
643 644 if (mdb_ctf_enum_iter(idr, enum_cb, &info) == -1) {
644 645 mdb_warn("cannot walk '%s' as enum", type);
645 646 return (DCMD_ERR);
646 647 }
647 648
648 649 if (info.e_found == 0 &&
649 650 (info.e_flags & (E_SEARCH_STRING | E_SEARCH_VALUE)) != 0) {
650 651 if (info.e_flags & E_SEARCH_STRING)
651 652 mdb_warn("name \"%s\" not in '%s'\n", info.e_string,
652 653 type);
653 654 else
654 655 mdb_warn("value %#lld not in '%s'\n", info.e_value,
655 656 type);
656 657
657 658 return (DCMD_ERR);
658 659 }
659 660
660 661 return (DCMD_OK);
661 662 }
662 663
663 664 static int
664 665 setup_vcb(const char *name, uintptr_t addr)
665 666 {
666 667 const char *p;
667 668 mdb_var_t *v;
668 669
669 670 if ((v = mdb_nv_lookup(&mdb.m_nv, name)) == NULL) {
670 671 if ((p = strbadid(name)) != NULL) {
671 672 mdb_warn("'%c' may not be used in a variable "
672 673 "name\n", *p);
673 674 return (DCMD_ABORT);
674 675 }
675 676
676 677 if ((v = mdb_nv_insert(&mdb.m_nv, name, NULL, addr, 0)) == NULL)
677 678 return (DCMD_ERR);
678 679 } else {
679 680 if (v->v_flags & MDB_NV_RDONLY) {
680 681 mdb_warn("variable %s is read-only\n", name);
681 682 return (DCMD_ABORT);
682 683 }
683 684 }
684 685
685 686 /*
686 687 * If there already exists a vcb for this variable, we may be
687 688 * calling the dcmd in a loop. We only create a vcb for this
688 689 * variable on the first invocation.
689 690 */
690 691 if (mdb_vcb_find(v, mdb.m_frame) == NULL)
691 692 mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame);
692 693
693 694 return (0);
694 695 }
695 696
696 697 /*ARGSUSED*/
697 698 int
698 699 cmd_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
699 700 {
700 701 int offset;
701 702 uintptr_t a, tmp;
702 703 int ret;
703 704
704 705 if (!(flags & DCMD_ADDRSPEC) || argc == 0)
705 706 return (DCMD_USAGE);
706 707
707 708 if (argv->a_type != MDB_TYPE_STRING) {
708 709 /*
709 710 * We are being given a raw offset in lieu of a type and
710 711 * member; confirm the number of arguments and argument
711 712 * type.
712 713 */
713 714 if (argc != 1 || argv->a_type != MDB_TYPE_IMMEDIATE)
714 715 return (DCMD_USAGE);
715 716
716 717 offset = argv->a_un.a_val;
717 718
718 719 argv++;
719 720 argc--;
720 721
721 722 if (offset % sizeof (uintptr_t)) {
722 723 mdb_warn("offset must fall on a word boundary\n");
723 724 return (DCMD_ABORT);
724 725 }
725 726 } else {
726 727 const char *member;
727 728 char buf[MDB_SYM_NAMLEN];
728 729 int ret;
729 730
730 731 /*
731 732 * Check that we were provided 2 arguments: a type name
732 733 * and a member of that type.
733 734 */
734 735 if (argc != 2)
735 736 return (DCMD_USAGE);
736 737
737 738 ret = args_to_typename(&argc, &argv, buf, sizeof (buf));
738 739 if (ret != 0)
739 740 return (ret);
740 741
741 742 argv++;
742 743 argc--;
743 744
744 745 member = argv->a_un.a_str;
745 746 offset = mdb_ctf_offsetof_by_name(buf, member);
746 747 if (offset == -1)
747 748 return (DCMD_ABORT);
748 749
749 750 argv++;
750 751 argc--;
751 752
752 753 if (offset % (sizeof (uintptr_t)) != 0) {
753 754 mdb_warn("%s is not a word-aligned member\n", member);
754 755 return (DCMD_ABORT);
755 756 }
756 757 }
757 758
758 759 /*
759 760 * If we have any unchewed arguments, a variable name must be present.
760 761 */
761 762 if (argc == 1) {
762 763 if (argv->a_type != MDB_TYPE_STRING)
763 764 return (DCMD_USAGE);
764 765
765 766 if ((ret = setup_vcb(argv->a_un.a_str, addr)) != 0)
766 767 return (ret);
767 768
768 769 } else if (argc != 0) {
769 770 return (DCMD_USAGE);
770 771 }
771 772
772 773 a = addr;
773 774
774 775 do {
775 776 mdb_printf("%lr\n", a);
776 777
777 778 if (mdb_vread(&tmp, sizeof (tmp), a + offset) == -1) {
778 779 mdb_warn("failed to read next pointer from object %p",
779 780 a);
780 781 return (DCMD_ERR);
781 782 }
782 783
783 784 a = tmp;
784 785 } while (a != addr && a != NULL);
785 786
786 787 return (DCMD_OK);
787 788 }
788 789
789 790 int
790 791 cmd_array(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
791 792 {
792 793 mdb_ctf_id_t id;
793 794 ssize_t elemsize = 0;
794 795 char tn[MDB_SYM_NAMLEN];
795 796 int ret, nelem = -1;
796 797
797 798 mdb_tgt_t *t = mdb.m_target;
798 799 GElf_Sym sym;
799 800 mdb_ctf_arinfo_t ar;
800 801 mdb_syminfo_t s_info;
801 802
802 803 if (!(flags & DCMD_ADDRSPEC))
803 804 return (DCMD_USAGE);
804 805
805 806 if (argc >= 2) {
806 807 ret = args_to_typename(&argc, &argv, tn, sizeof (tn));
807 808 if (ret != 0)
808 809 return (ret);
809 810
810 811 if (argc == 1) /* unquoted compound type without count */
811 812 return (DCMD_USAGE);
812 813
813 814 if (mdb_ctf_lookup_by_name(tn, &id) != 0) {
814 815 mdb_warn("failed to look up type %s", tn);
815 816 return (DCMD_ABORT);
816 817 }
817 818
818 819 if (argv[1].a_type == MDB_TYPE_IMMEDIATE)
819 820 nelem = argv[1].a_un.a_val;
820 821 else
821 822 nelem = mdb_strtoull(argv[1].a_un.a_str);
822 823
823 824 elemsize = mdb_ctf_type_size(id);
824 825 } else if (addr_to_sym(t, addr, tn, sizeof (tn), &sym, &s_info)
825 826 != NULL && mdb_ctf_lookup_by_symbol(&sym, &s_info, &id)
826 827 == 0 && mdb_ctf_type_kind(id) == CTF_K_ARRAY &&
827 828 mdb_ctf_array_info(id, &ar) != -1) {
828 829 elemsize = mdb_ctf_type_size(id) / ar.mta_nelems;
829 830 nelem = ar.mta_nelems;
830 831 } else {
831 832 mdb_warn("no symbol information for %a", addr);
832 833 return (DCMD_ERR);
833 834 }
834 835
835 836 if (argc == 3 || argc == 1) {
836 837 if (argv[argc - 1].a_type != MDB_TYPE_STRING)
837 838 return (DCMD_USAGE);
838 839
839 840 if ((ret = setup_vcb(argv[argc - 1].a_un.a_str, addr)) != 0)
840 841 return (ret);
841 842
842 843 } else if (argc > 3) {
843 844 return (DCMD_USAGE);
844 845 }
845 846
846 847 for (; nelem > 0; nelem--) {
847 848 mdb_printf("%lr\n", addr);
848 849 addr = addr + elemsize;
849 850 }
850 851
851 852 return (DCMD_OK);
852 853 }
853 854
854 855 /*
855 856 * Print an integer bitfield in hexadecimal by reading the enclosing byte(s)
856 857 * and then shifting and masking the data in the lower bits of a uint64_t.
857 858 */
858 859 static int
859 860 print_bitfield(ulong_t off, printarg_t *pap, ctf_encoding_t *ep)
860 861 {
861 862 mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
862 863 size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
863 864 uint64_t mask = (1ULL << ep->cte_bits) - 1;
864 865 uint64_t value = 0;
865 866 uint8_t *buf = (uint8_t *)&value;
866 867 uint8_t shift;
867 868
868 869 const char *format;
869 870
870 871 if (!(pap->pa_flags & PA_SHOWVAL))
871 872 return (0);
872 873
873 874 if (ep->cte_bits > sizeof (value) * NBBY - 1) {
874 875 mdb_printf("??? (invalid bitfield size %u)", ep->cte_bits);
875 876 return (0);
876 877 }
877 878
878 879 /*
879 880 * On big-endian machines, we need to adjust the buf pointer to refer
880 881 * to the lowest 'size' bytes in 'value', and we need shift based on
881 882 * the offset from the end of the data, not the offset of the start.
882 883 */
883 884 #ifdef _BIG_ENDIAN
884 885 buf += sizeof (value) - size;
885 886 off += ep->cte_bits;
886 887 #endif
887 888 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, buf, size, addr) != size) {
888 889 mdb_warn("failed to read %lu bytes at %llx",
889 890 (ulong_t)size, addr);
890 891 return (1);
891 892 }
892 893
893 894 shift = off % NBBY;
894 895
895 896 /*
896 897 * Offsets are counted from opposite ends on little- and
897 898 * big-endian machines.
898 899 */
899 900 #ifdef _BIG_ENDIAN
900 901 shift = NBBY - shift;
901 902 #endif
902 903
903 904 /*
904 905 * If the bits we want do not begin on a byte boundary, shift the data
905 906 * right so that the value is in the lowest 'cte_bits' of 'value'.
906 907 */
907 908 if (off % NBBY != 0)
908 909 value >>= shift;
909 910 value &= mask;
910 911
911 912 /*
912 913 * We default to printing signed bitfields as decimals,
913 914 * and unsigned bitfields in hexadecimal. If they specify
914 915 * hexadecimal, we treat the field as unsigned.
915 916 */
916 917 if ((pap->pa_flags & PA_INTHEX) ||
917 918 !(ep->cte_format & CTF_INT_SIGNED)) {
918 919 format = (pap->pa_flags & PA_INTDEC)? "%#llu" : "%#llx";
919 920 } else {
920 921 int sshift = sizeof (value) * NBBY - ep->cte_bits;
921 922
922 923 /* sign-extend value, and print as a signed decimal */
923 924 value = ((int64_t)value << sshift) >> sshift;
924 925 format = "%#lld";
925 926 }
926 927 mdb_printf(format, value);
927 928
928 929 return (0);
929 930 }
930 931
931 932 /*
932 933 * Print out a character or integer value. We use some simple heuristics,
933 934 * described below, to determine the appropriate radix to use for output.
934 935 */
935 936 static int
936 937 print_int_val(const char *type, ctf_encoding_t *ep, ulong_t off,
937 938 printarg_t *pap)
938 939 {
939 940 static const char *const sformat[] = { "%#d", "%#d", "%#d", "%#lld" };
940 941 static const char *const uformat[] = { "%#u", "%#u", "%#u", "%#llu" };
941 942 static const char *const xformat[] = { "%#x", "%#x", "%#x", "%#llx" };
942 943
943 944 mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
944 945 const char *const *fsp;
945 946 size_t size;
946 947
947 948 union {
948 949 uint64_t i8;
949 950 uint32_t i4;
950 951 uint16_t i2;
951 952 uint8_t i1;
952 953 time_t t;
953 954 ipaddr_t I;
954 955 } u;
955 956
956 957 if (!(pap->pa_flags & PA_SHOWVAL))
957 958 return (0);
958 959
959 960 if (ep->cte_format & CTF_INT_VARARGS) {
960 961 mdb_printf("...\n");
961 962 return (0);
962 963 }
963 964
964 965 /*
965 966 * If the size is not a power-of-two number of bytes in the range 1-8
966 967 * then we assume it is a bitfield and print it as such.
967 968 */
968 969 size = ep->cte_bits / NBBY;
969 970 if (size > 8 || (ep->cte_bits % NBBY) != 0 || (size & (size - 1)) != 0)
970 971 return (print_bitfield(off, pap, ep));
971 972
972 973 if (IS_CHAR(*ep)) {
973 974 mdb_printf("'");
974 975 if (mdb_fmt_print(pap->pa_tgt, pap->pa_as,
975 976 addr, 1, 'C') == addr)
976 977 return (1);
977 978 mdb_printf("'");
978 979 return (0);
979 980 }
980 981
981 982 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size, addr) != size) {
982 983 mdb_warn("failed to read %lu bytes at %llx",
983 984 (ulong_t)size, addr);
984 985 return (1);
985 986 }
986 987
987 988 /*
988 989 * We pretty-print some integer based types. time_t values are
989 990 * printed as a calendar date and time, and IPv4 addresses as human
990 991 * readable dotted quads.
991 992 */
992 993 if (!(pap->pa_flags & (PA_INTHEX | PA_INTDEC))) {
993 994 if (strcmp(type, "time_t") == 0 && u.t != 0) {
994 995 mdb_printf("%Y", u.t);
995 996 return (0);
996 997 }
997 998 if (strcmp(type, "ipaddr_t") == 0 ||
998 999 strcmp(type, "in_addr_t") == 0) {
999 1000 mdb_printf("%I", u.I);
1000 1001 return (0);
1001 1002 }
1002 1003 }
1003 1004
1004 1005 /*
1005 1006 * The default format is hexadecimal.
1006 1007 */
1007 1008 if (!(pap->pa_flags & PA_INTDEC))
1008 1009 fsp = xformat;
1009 1010 else if (ep->cte_format & CTF_INT_SIGNED)
1010 1011 fsp = sformat;
1011 1012 else
1012 1013 fsp = uformat;
1013 1014
1014 1015 switch (size) {
1015 1016 case sizeof (uint8_t):
1016 1017 mdb_printf(fsp[0], u.i1);
1017 1018 break;
1018 1019 case sizeof (uint16_t):
1019 1020 mdb_printf(fsp[1], u.i2);
1020 1021 break;
1021 1022 case sizeof (uint32_t):
1022 1023 mdb_printf(fsp[2], u.i4);
1023 1024 break;
1024 1025 case sizeof (uint64_t):
1025 1026 mdb_printf(fsp[3], u.i8);
1026 1027 break;
1027 1028 }
1028 1029 return (0);
1029 1030 }
1030 1031
1031 1032 /*ARGSUSED*/
1032 1033 static int
1033 1034 print_int(const char *type, const char *name, mdb_ctf_id_t id,
1034 1035 mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1035 1036 {
1036 1037 ctf_encoding_t e;
1037 1038
1038 1039 if (!(pap->pa_flags & PA_SHOWVAL))
1039 1040 return (0);
1040 1041
1041 1042 if (mdb_ctf_type_encoding(base, &e) != 0) {
1042 1043 mdb_printf("??? (%s)", mdb_strerror(errno));
1043 1044 return (0);
1044 1045 }
1045 1046
1046 1047 return (print_int_val(type, &e, off, pap));
1047 1048 }
1048 1049
1049 1050 /*
1050 1051 * Print out a floating point value. We only provide support for floats in
1051 1052 * the ANSI-C float, double, and long double formats.
1052 1053 */
1053 1054 /*ARGSUSED*/
1054 1055 static int
1055 1056 print_float(const char *type, const char *name, mdb_ctf_id_t id,
1056 1057 mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1057 1058 {
1058 1059 #ifndef _KMDB
1059 1060 mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
1060 1061 ctf_encoding_t e;
1061 1062
1062 1063 union {
1063 1064 float f;
1064 1065 double d;
1065 1066 long double ld;
1066 1067 } u;
1067 1068
1068 1069 if (!(pap->pa_flags & PA_SHOWVAL))
1069 1070 return (0);
1070 1071
1071 1072 if (mdb_ctf_type_encoding(base, &e) == 0) {
1072 1073 if (e.cte_format == CTF_FP_SINGLE &&
1073 1074 e.cte_bits == sizeof (float) * NBBY) {
1074 1075 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.f,
1075 1076 sizeof (u.f), addr) != sizeof (u.f)) {
1076 1077 mdb_warn("failed to read float at %llx", addr);
1077 1078 return (1);
1078 1079 }
1079 1080 mdb_printf("%s", doubletos(u.f, 7, 'e'));
1080 1081
1081 1082 } else if (e.cte_format == CTF_FP_DOUBLE &&
1082 1083 e.cte_bits == sizeof (double) * NBBY) {
1083 1084 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.d,
1084 1085 sizeof (u.d), addr) != sizeof (u.d)) {
1085 1086 mdb_warn("failed to read float at %llx", addr);
1086 1087 return (1);
1087 1088 }
1088 1089 mdb_printf("%s", doubletos(u.d, 7, 'e'));
1089 1090
1090 1091 } else if (e.cte_format == CTF_FP_LDOUBLE &&
1091 1092 e.cte_bits == sizeof (long double) * NBBY) {
1092 1093 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.ld,
1093 1094 sizeof (u.ld), addr) != sizeof (u.ld)) {
1094 1095 mdb_warn("failed to read float at %llx", addr);
1095 1096 return (1);
1096 1097 }
1097 1098 mdb_printf("%s", longdoubletos(&u.ld, 16, 'e'));
1098 1099
1099 1100 } else {
1100 1101 mdb_printf("??? (unsupported FP format %u / %u bits\n",
1101 1102 e.cte_format, e.cte_bits);
1102 1103 }
1103 1104 } else
1104 1105 mdb_printf("??? (%s)", mdb_strerror(errno));
1105 1106 #else
1106 1107 mdb_printf("<FLOAT>");
1107 1108 #endif
1108 1109 return (0);
1109 1110 }
1110 1111
1111 1112
1112 1113 /*
1113 1114 * Print out a pointer value as a symbol name + offset or a hexadecimal value.
1114 1115 * If the pointer itself is a char *, we attempt to read a bit of the data
1115 1116 * referenced by the pointer and display it if it is a printable ASCII string.
1116 1117 */
1117 1118 /*ARGSUSED*/
1118 1119 static int
1119 1120 print_ptr(const char *type, const char *name, mdb_ctf_id_t id,
1120 1121 mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1121 1122 {
1122 1123 mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
1123 1124 ctf_encoding_t e;
1124 1125 uintptr_t value;
1125 1126 char buf[256];
1126 1127 ssize_t len;
1127 1128
1128 1129 if (!(pap->pa_flags & PA_SHOWVAL))
1129 1130 return (0);
1130 1131
1131 1132 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
1132 1133 &value, sizeof (value), addr) != sizeof (value)) {
1133 1134 mdb_warn("failed to read %s pointer at %llx", name, addr);
1134 1135 return (1);
1135 1136 }
1136 1137
1137 1138 if (pap->pa_flags & PA_NOSYMBOLIC) {
1138 1139 mdb_printf("%#lx", value);
1139 1140 return (0);
1140 1141 }
1141 1142
1142 1143 mdb_printf("%a", value);
1143 1144
1144 1145 if (value == NULL || strcmp(type, "caddr_t") == 0)
1145 1146 return (0);
1146 1147
1147 1148 if (mdb_ctf_type_kind(base) == CTF_K_POINTER &&
1148 1149 mdb_ctf_type_reference(base, &base) != -1 &&
1149 1150 mdb_ctf_type_resolve(base, &base) != -1 &&
1150 1151 mdb_ctf_type_encoding(base, &e) == 0 && IS_CHAR(e)) {
1151 1152 if ((len = mdb_tgt_readstr(pap->pa_realtgt, pap->pa_as,
1152 1153 buf, sizeof (buf), value)) >= 0 && strisprint(buf)) {
1153 1154 if (len == sizeof (buf))
1154 1155 (void) strabbr(buf, sizeof (buf));
1155 1156 mdb_printf(" \"%s\"", buf);
1156 1157 }
1157 1158 }
1158 1159
1159 1160 return (0);
1160 1161 }
1161 1162
1162 1163
1163 1164 /*
1164 1165 * Print out a fixed-size array. We special-case arrays of characters
1165 1166 * and attempt to print them out as ASCII strings if possible. For other
1166 1167 * arrays, we iterate over a maximum of pa_armemlim members and call
1167 1168 * mdb_ctf_type_visit() again on each element to print its value.
1168 1169 */
1169 1170 /*ARGSUSED*/
1170 1171 static int
1171 1172 print_array(const char *type, const char *name, mdb_ctf_id_t id,
1172 1173 mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1173 1174 {
1174 1175 mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
1175 1176 printarg_t pa = *pap;
1176 1177 ssize_t eltsize;
1177 1178 mdb_ctf_arinfo_t r;
1178 1179 ctf_encoding_t e;
1179 1180 uint_t i, kind, limit;
1180 1181 int d, sou;
1181 1182 char buf[8];
1182 1183 char *str;
1183 1184
1184 1185 if (!(pap->pa_flags & PA_SHOWVAL))
1185 1186 return (0);
1186 1187
1187 1188 if (pap->pa_depth == pap->pa_maxdepth) {
1188 1189 mdb_printf("[ ... ]");
1189 1190 return (0);
1190 1191 }
1191 1192
1192 1193 /*
1193 1194 * Determine the base type and size of the array's content. If this
1194 1195 * fails, we cannot print anything and just give up.
1195 1196 */
1196 1197 if (mdb_ctf_array_info(base, &r) == -1 ||
1197 1198 mdb_ctf_type_resolve(r.mta_contents, &base) == -1 ||
1198 1199 (eltsize = mdb_ctf_type_size(base)) == -1) {
1199 1200 mdb_printf("[ ??? ] (%s)", mdb_strerror(errno));
1200 1201 return (0);
1201 1202 }
1202 1203
1203 1204 /*
1204 1205 * Read a few bytes and determine if the content appears to be
1205 1206 * printable ASCII characters. If so, read the entire array and
1206 1207 * attempt to display it as a string if it is printable.
1207 1208 */
1208 1209 if ((pap->pa_arstrlim == MDB_ARR_NOLIMIT ||
1209 1210 r.mta_nelems <= pap->pa_arstrlim) &&
1210 1211 mdb_ctf_type_encoding(base, &e) == 0 && IS_CHAR(e) &&
1211 1212 mdb_tgt_readstr(pap->pa_tgt, pap->pa_as, buf,
1212 1213 MIN(sizeof (buf), r.mta_nelems), addr) > 0 && strisprint(buf)) {
1213 1214
1214 1215 str = mdb_alloc(r.mta_nelems + 1, UM_SLEEP | UM_GC);
1215 1216 str[r.mta_nelems] = '\0';
1216 1217
1217 1218 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, str,
1218 1219 r.mta_nelems, addr) != r.mta_nelems) {
1219 1220 mdb_warn("failed to read char array at %llx", addr);
1220 1221 return (1);
1221 1222 }
1222 1223
1223 1224 if (strisprint(str)) {
1224 1225 mdb_printf("[ \"%s\" ]", str);
1225 1226 return (0);
1226 1227 }
1227 1228 }
1228 1229
1229 1230 if (pap->pa_armemlim != MDB_ARR_NOLIMIT)
1230 1231 limit = MIN(r.mta_nelems, pap->pa_armemlim);
1231 1232 else
1232 1233 limit = r.mta_nelems;
1233 1234
1234 1235 if (limit == 0) {
1235 1236 mdb_printf("[ ... ]");
1236 1237 return (0);
1237 1238 }
1238 1239
1239 1240 kind = mdb_ctf_type_kind(base);
1240 1241 sou = IS_COMPOSITE(kind);
1241 1242
1242 1243 pa.pa_addr = addr; /* set base address to start of array */
1243 1244 pa.pa_maxdepth = pa.pa_maxdepth - pa.pa_depth - 1;
1244 1245 pa.pa_nest += pa.pa_depth + 1; /* nesting level is current depth + 1 */
1245 1246 pa.pa_depth = 0; /* reset depth to 0 for new scope */
1246 1247 pa.pa_prefix = NULL;
1247 1248
1248 1249 if (sou) {
1249 1250 pa.pa_delim = "\n";
1250 1251 mdb_printf("[\n");
1251 1252 } else {
1252 1253 pa.pa_flags &= ~(PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR);
1253 1254 pa.pa_delim = ", ";
1254 1255 mdb_printf("[ ");
1255 1256 }
1256 1257
1257 1258 for (i = 0; i < limit; i++, pa.pa_addr += eltsize) {
1258 1259 if (i == limit - 1 && !sou) {
1259 1260 if (limit < r.mta_nelems)
1260 1261 pa.pa_delim = ", ... ]";
1261 1262 else
1262 1263 pa.pa_delim = " ]";
1263 1264 }
1264 1265
1265 1266 if (mdb_ctf_type_visit(r.mta_contents, elt_print, &pa) == -1) {
1266 1267 mdb_warn("failed to print array data");
1267 1268 return (1);
1268 1269 }
1269 1270 }
1270 1271
1271 1272 if (sou) {
1272 1273 for (d = pa.pa_depth - 1; d >= 0; d--)
1273 1274 print_close_sou(&pa, d);
1274 1275
1275 1276 if (limit < r.mta_nelems) {
1276 1277 mdb_printf("%*s... ]",
1277 1278 (pap->pa_depth + pap->pa_nest) * pap->pa_tab, "");
1278 1279 } else {
1279 1280 mdb_printf("%*s]",
1280 1281 (pap->pa_depth + pap->pa_nest) * pap->pa_tab, "");
1281 1282 }
1282 1283 }
1283 1284
1284 1285 /* copy the hole array info, since it may have been grown */
1285 1286 pap->pa_holes = pa.pa_holes;
1286 1287 pap->pa_nholes = pa.pa_nholes;
1287 1288
1288 1289 return (0);
1289 1290 }
1290 1291
1291 1292 /*
1292 1293 * Print out a struct or union header. We need only print the open brace
1293 1294 * because mdb_ctf_type_visit() itself will automatically recurse through
1294 1295 * all members of the given struct or union.
1295 1296 */
1296 1297 /*ARGSUSED*/
1297 1298 static int
1298 1299 print_sou(const char *type, const char *name, mdb_ctf_id_t id,
1299 1300 mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1300 1301 {
1301 1302 mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
1302 1303
1303 1304 /*
1304 1305 * We have pretty-printing for some structures where displaying
1305 1306 * structure contents has no value.
1306 1307 */
1307 1308 if (pap->pa_flags & PA_SHOWVAL) {
1308 1309 if (strcmp(type, "in6_addr_t") == 0 ||
1309 1310 strcmp(type, "struct in6_addr") == 0) {
1310 1311 in6_addr_t in6addr;
1311 1312
1312 1313 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &in6addr,
1313 1314 sizeof (in6addr), addr) != sizeof (in6addr)) {
1314 1315 mdb_warn("failed to read %s pointer at %llx",
1315 1316 name, addr);
1316 1317 return (1);
1317 1318 }
1318 1319 mdb_printf("%N", &in6addr);
1319 1320 /*
1320 1321 * Don't print anything further down in the
1321 1322 * structure.
1322 1323 */
1323 1324 pap->pa_nooutdepth = pap->pa_depth;
1324 1325 return (0);
1325 1326 }
1326 1327 if (strcmp(type, "struct in_addr") == 0) {
1327 1328 in_addr_t inaddr;
1328 1329
1329 1330 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &inaddr,
1330 1331 sizeof (inaddr), addr) != sizeof (inaddr)) {
1331 1332 mdb_warn("failed to read %s pointer at %llx",
1332 1333 name, addr);
1333 1334 return (1);
1334 1335 }
1335 1336 mdb_printf("%I", inaddr);
1336 1337 pap->pa_nooutdepth = pap->pa_depth;
1337 1338 return (0);
1338 1339 }
1339 1340 }
1340 1341
1341 1342 if (pap->pa_depth == pap->pa_maxdepth)
1342 1343 mdb_printf("{ ... }");
1343 1344 else
1344 1345 mdb_printf("{");
1345 1346 pap->pa_delim = "\n";
1346 1347 return (0);
1347 1348 }
1348 1349
1349 1350 /*
1350 1351 * Print an enum value. We attempt to convert the value to the corresponding
1351 1352 * enum name and print that if possible.
1352 1353 */
1353 1354 /*ARGSUSED*/
1354 1355 static int
1355 1356 print_enum(const char *type, const char *name, mdb_ctf_id_t id,
1356 1357 mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1357 1358 {
1358 1359 mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
1359 1360 const char *ename;
1360 1361 int value;
1361 1362 int isp2 = enum_is_p2(base);
1362 1363 int flags = pap->pa_flags | (isp2 ? PA_INTHEX : 0);
1363 1364
1364 1365 if (!(flags & PA_SHOWVAL))
1365 1366 return (0);
1366 1367
1367 1368 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
1368 1369 &value, sizeof (value), addr) != sizeof (value)) {
1369 1370 mdb_warn("failed to read %s integer at %llx", name, addr);
1370 1371 return (1);
1371 1372 }
1372 1373
1373 1374 if (flags & PA_INTHEX)
1374 1375 mdb_printf("%#x", value);
1375 1376 else
1376 1377 mdb_printf("%#d", value);
1377 1378
1378 1379 (void) mdb_inc_indent(8);
1379 1380 mdb_printf(" (");
1380 1381
1381 1382 if (!isp2 || enum_value_print_p2(base, value, 0) != 0) {
1382 1383 ename = mdb_ctf_enum_name(base, value);
1383 1384 if (ename == NULL) {
1384 1385 ename = "???";
1385 1386 }
1386 1387 mdb_printf("%s", ename);
1387 1388 }
1388 1389 mdb_printf(")");
1389 1390 (void) mdb_dec_indent(8);
1390 1391
1391 1392 return (0);
1392 1393 }
1393 1394
1394 1395 /*
1395 1396 * This will only get called if the structure isn't found in any available CTF
1396 1397 * data.
1397 1398 */
1398 1399 /*ARGSUSED*/
1399 1400 static int
1400 1401 print_tag(const char *type, const char *name, mdb_ctf_id_t id,
1401 1402 mdb_ctf_id_t base, ulong_t off, printarg_t *pap)
1402 1403 {
1403 1404 char basename[MDB_SYM_NAMLEN];
1404 1405
1405 1406 if (pap->pa_flags & PA_SHOWVAL)
1406 1407 mdb_printf("; ");
1407 1408
1408 1409 if (mdb_ctf_type_name(base, basename, sizeof (basename)) != NULL)
1409 1410 mdb_printf("<forward declaration of %s>", basename);
1410 1411 else
1411 1412 mdb_printf("<forward declaration of unknown type>");
1412 1413
1413 1414 return (0);
1414 1415 }
1415 1416
1416 1417 static void
1417 1418 print_hole(printarg_t *pap, int depth, ulong_t off, ulong_t endoff)
1418 1419 {
1419 1420 ulong_t bits = endoff - off;
1420 1421 ulong_t size = bits / NBBY;
1421 1422 ctf_encoding_t e;
1422 1423
1423 1424 static const char *const name = "<<HOLE>>";
1424 1425 char type[MDB_SYM_NAMLEN];
1425 1426
1426 1427 int bitfield =
1427 1428 (off % NBBY != 0 ||
1428 1429 bits % NBBY != 0 ||
1429 1430 size > 8 ||
1430 1431 (size & (size - 1)) != 0);
1431 1432
1432 1433 ASSERT(off < endoff);
1433 1434
1434 1435 if (bits > NBBY * sizeof (uint64_t)) {
1435 1436 ulong_t end;
1436 1437
1437 1438 /*
1438 1439 * The hole is larger than the largest integer type. To
1439 1440 * handle this, we split up the hole at 8-byte-aligned
1440 1441 * boundaries, recursing to print each subsection. For
1441 1442 * normal C structures, we'll loop at most twice.
1442 1443 */
1443 1444 for (; off < endoff; off = end) {
1444 1445 end = P2END(off, NBBY * sizeof (uint64_t));
1445 1446 if (end > endoff)
1446 1447 end = endoff;
1447 1448
1448 1449 ASSERT((end - off) <= NBBY * sizeof (uint64_t));
1449 1450 print_hole(pap, depth, off, end);
1450 1451 }
1451 1452 ASSERT(end == endoff);
1452 1453
1453 1454 return;
1454 1455 }
1455 1456
1456 1457 if (bitfield)
1457 1458 (void) mdb_snprintf(type, sizeof (type), "unsigned");
1458 1459 else
1459 1460 (void) mdb_snprintf(type, sizeof (type), "uint%d_t", bits);
1460 1461
1461 1462 if (pap->pa_flags & (PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR))
1462 1463 mdb_printf("%*s", (depth + pap->pa_nest) * pap->pa_tab, "");
1463 1464
1464 1465 if (pap->pa_flags & PA_SHOWADDR) {
1465 1466 if (off % NBBY == 0)
1466 1467 mdb_printf("%llx ", pap->pa_addr + off / NBBY);
1467 1468 else
1468 1469 mdb_printf("%llx.%lx ",
1469 1470 pap->pa_addr + off / NBBY, off % NBBY);
1470 1471 }
1471 1472
1472 1473 if (pap->pa_flags & PA_SHOWTYPE)
1473 1474 mdb_printf("%s ", type);
1474 1475
1475 1476 if (pap->pa_flags & PA_SHOWNAME)
1476 1477 mdb_printf("%s", name);
1477 1478
1478 1479 if (bitfield && (pap->pa_flags & PA_SHOWTYPE))
1479 1480 mdb_printf(" :%d", bits);
1480 1481
1481 1482 mdb_printf("%s ", (pap->pa_flags & PA_SHOWVAL)? " =" : "");
1482 1483
1483 1484 /*
1484 1485 * We fake up a ctf_encoding_t, and use print_int_val() to print
1485 1486 * the value. Holes are always processed as unsigned integers.
1486 1487 */
1487 1488 bzero(&e, sizeof (e));
1488 1489 e.cte_format = 0;
1489 1490 e.cte_offset = 0;
1490 1491 e.cte_bits = bits;
1491 1492
1492 1493 if (print_int_val(type, &e, off, pap) != 0)
1493 1494 mdb_iob_discard(mdb.m_out);
1494 1495 else
1495 1496 mdb_iob_puts(mdb.m_out, pap->pa_delim);
1496 1497 }
1497 1498
1498 1499 /*
1499 1500 * The print_close_sou() function is called for each structure or union
1500 1501 * which has been completed. For structures, we detect and print any holes
1501 1502 * before printing the closing brace.
1502 1503 */
1503 1504 static void
1504 1505 print_close_sou(printarg_t *pap, int newdepth)
1505 1506 {
1506 1507 int d = newdepth + pap->pa_nest;
1507 1508
1508 1509 if ((pap->pa_flags & PA_SHOWHOLES) && !pap->pa_holes[d].hi_isunion) {
1509 1510 ulong_t end = pap->pa_holes[d + 1].hi_offset;
1510 1511 ulong_t expected = pap->pa_holes[d].hi_offset;
1511 1512
1512 1513 if (end < expected)
1513 1514 print_hole(pap, newdepth + 1, end, expected);
1514 1515 }
1515 1516 /* if the struct is an array element, print a comma after the } */
1516 1517 mdb_printf("%*s}%s\n", d * pap->pa_tab, "",
1517 1518 (newdepth == 0 && pap->pa_nest > 0)? "," : "");
1518 1519 }
1519 1520
1520 1521 static printarg_f *const printfuncs[] = {
1521 1522 print_int, /* CTF_K_INTEGER */
1522 1523 print_float, /* CTF_K_FLOAT */
1523 1524 print_ptr, /* CTF_K_POINTER */
1524 1525 print_array, /* CTF_K_ARRAY */
1525 1526 print_ptr, /* CTF_K_FUNCTION */
1526 1527 print_sou, /* CTF_K_STRUCT */
1527 1528 print_sou, /* CTF_K_UNION */
1528 1529 print_enum, /* CTF_K_ENUM */
1529 1530 print_tag /* CTF_K_FORWARD */
1530 1531 };
1531 1532
1532 1533 /*
1533 1534 * The elt_print function is used as the mdb_ctf_type_visit callback. For
1534 1535 * each element, we print an appropriate name prefix and then call the
1535 1536 * print subroutine for this type class in the array above.
1536 1537 */
1537 1538 static int
1538 1539 elt_print(const char *name, mdb_ctf_id_t id, mdb_ctf_id_t base,
1539 1540 ulong_t off, int depth, void *data)
1540 1541 {
1541 1542 char type[MDB_SYM_NAMLEN + sizeof (" <<12345678...>>")];
1542 1543 int kind, rc, d;
1543 1544 printarg_t *pap = data;
1544 1545
1545 1546 for (d = pap->pa_depth - 1; d >= depth; d--) {
1546 1547 if (d < pap->pa_nooutdepth)
1547 1548 print_close_sou(pap, d);
1548 1549 }
1549 1550
1550 1551 /*
1551 1552 * Reset pa_nooutdepth if we've come back out of the structure we
1552 1553 * didn't want to print.
1553 1554 */
1554 1555 if (depth <= pap->pa_nooutdepth)
1555 1556 pap->pa_nooutdepth = (uint_t)-1;
1556 1557
1557 1558 if (depth > pap->pa_maxdepth || depth > pap->pa_nooutdepth)
1558 1559 return (0);
1559 1560
1560 1561 if (!mdb_ctf_type_valid(base) ||
1561 1562 (kind = mdb_ctf_type_kind(base)) == -1)
1562 1563 return (-1); /* errno is set for us */
1563 1564
1564 1565 if (mdb_ctf_type_name(id, type, MDB_SYM_NAMLEN) == NULL)
1565 1566 (void) strcpy(type, "(?)");
1566 1567
1567 1568 if (pap->pa_flags & PA_SHOWBASETYPE) {
1568 1569 /*
1569 1570 * If basetype is different and informative, concatenate
1570 1571 * <<basetype>> (or <<baset...>> if it doesn't fit)
1571 1572 *
1572 1573 * We just use the end of the buffer to store the type name, and
1573 1574 * only connect it up if that's necessary.
1574 1575 */
1575 1576
1576 1577 char *type_end = type + strlen(type);
1577 1578 char *basetype;
1578 1579 size_t sz;
1579 1580
1580 1581 (void) strlcat(type, " <<", sizeof (type));
1581 1582
1582 1583 basetype = type + strlen(type);
1583 1584 sz = sizeof (type) - (basetype - type);
1584 1585
1585 1586 *type_end = '\0'; /* restore the end of type for strcmp() */
1586 1587
1587 1588 if (mdb_ctf_type_name(base, basetype, sz) != NULL &&
1588 1589 strcmp(basetype, type) != 0 &&
1589 1590 strcmp(basetype, "struct ") != 0 &&
1590 1591 strcmp(basetype, "enum ") != 0 &&
1591 1592 strcmp(basetype, "union ") != 0) {
1592 1593 type_end[0] = ' '; /* reconnect */
1593 1594 if (strlcat(type, ">>", sizeof (type)) >= sizeof (type))
1594 1595 (void) strlcpy(
1595 1596 type + sizeof (type) - 6, "...>>", 6);
1596 1597 }
1597 1598 }
1598 1599
1599 1600 if (pap->pa_flags & PA_SHOWHOLES) {
1600 1601 ctf_encoding_t e;
1601 1602 ssize_t nsize;
1602 1603 ulong_t newoff;
1603 1604 holeinfo_t *hole;
1604 1605 int extra = IS_COMPOSITE(kind)? 1 : 0;
1605 1606
1606 1607 /*
1607 1608 * grow the hole array, if necessary
1608 1609 */
1609 1610 if (pap->pa_nest + depth + extra >= pap->pa_nholes) {
1610 1611 int new = MAX(MAX(8, pap->pa_nholes * 2),
1611 1612 pap->pa_nest + depth + extra + 1);
1612 1613
1613 1614 holeinfo_t *nhi = mdb_zalloc(
1614 1615 sizeof (*nhi) * new, UM_NOSLEEP | UM_GC);
1615 1616
1616 1617 bcopy(pap->pa_holes, nhi,
1617 1618 pap->pa_nholes * sizeof (*nhi));
1618 1619
1619 1620 pap->pa_holes = nhi;
1620 1621 pap->pa_nholes = new;
1621 1622 }
1622 1623
1623 1624 hole = &pap->pa_holes[depth + pap->pa_nest];
1624 1625
1625 1626 if (depth != 0 && off > hole->hi_offset)
1626 1627 print_hole(pap, depth, hole->hi_offset, off);
1627 1628
1628 1629 /* compute the next expected offset */
1629 1630 if (kind == CTF_K_INTEGER &&
1630 1631 mdb_ctf_type_encoding(base, &e) == 0)
1631 1632 newoff = off + e.cte_bits;
1632 1633 else if ((nsize = mdb_ctf_type_size(base)) >= 0)
1633 1634 newoff = off + nsize * NBBY;
1634 1635 else {
1635 1636 /* something bad happened, disable hole checking */
1636 1637 newoff = -1UL; /* ULONG_MAX */
1637 1638 }
1638 1639
1639 1640 hole->hi_offset = newoff;
1640 1641
1641 1642 if (IS_COMPOSITE(kind)) {
1642 1643 hole->hi_isunion = (kind == CTF_K_UNION);
1643 1644 hole++;
1644 1645 hole->hi_offset = off;
1645 1646 }
1646 1647 }
1647 1648
1648 1649 if (pap->pa_flags & (PA_SHOWTYPE | PA_SHOWNAME | PA_SHOWADDR))
1649 1650 mdb_printf("%*s", (depth + pap->pa_nest) * pap->pa_tab, "");
1650 1651
1651 1652 if (pap->pa_flags & PA_SHOWADDR) {
1652 1653 if (off % NBBY == 0)
1653 1654 mdb_printf("%llx ", pap->pa_addr + off / NBBY);
1654 1655 else
1655 1656 mdb_printf("%llx.%lx ",
1656 1657 pap->pa_addr + off / NBBY, off % NBBY);
1657 1658 }
1658 1659
1659 1660 if ((pap->pa_flags & PA_SHOWTYPE)) {
1660 1661 mdb_printf("%s", type);
1661 1662 /*
1662 1663 * We want to avoid printing a trailing space when
1663 1664 * dealing with pointers in a structure, so we end
1664 1665 * up with:
1665 1666 *
1666 1667 * label_t *t_onfault = 0
1667 1668 *
1668 1669 * If depth is zero, always print the trailing space unless
1669 1670 * we also have a prefix.
1670 1671 */
1671 1672 if (type[strlen(type) - 1] != '*' ||
1672 1673 (depth == 0 && (!(pap->pa_flags & PA_SHOWNAME) ||
1673 1674 pap->pa_prefix == NULL)))
1674 1675 mdb_printf(" ");
1675 1676 }
1676 1677
1677 1678 if (pap->pa_flags & PA_SHOWNAME) {
1678 1679 if (pap->pa_prefix != NULL && depth <= 1)
1679 1680 mdb_printf("%s%s", pap->pa_prefix,
1680 1681 (depth == 0) ? "" : pap->pa_suffix);
1681 1682 mdb_printf("%s", name);
1682 1683 }
1683 1684
1684 1685 if ((pap->pa_flags & PA_SHOWTYPE) && kind == CTF_K_INTEGER) {
1685 1686 ctf_encoding_t e;
1686 1687
1687 1688 if (mdb_ctf_type_encoding(base, &e) == 0) {
1688 1689 ulong_t bits = e.cte_bits;
1689 1690 ulong_t size = bits / NBBY;
1690 1691
1691 1692 if (bits % NBBY != 0 ||
1692 1693 off % NBBY != 0 ||
1693 1694 size > 8 ||
1694 1695 size != mdb_ctf_type_size(base))
1695 1696 mdb_printf(" :%d", bits);
1696 1697 }
1697 1698 }
1698 1699
1699 1700 if (depth != 0 ||
1700 1701 ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL))
1701 1702 mdb_printf("%s ", pap->pa_flags & PA_SHOWVAL ? " =" : "");
1702 1703
1703 1704 if (depth == 0 && pap->pa_prefix != NULL)
1704 1705 name = pap->pa_prefix;
1705 1706
1706 1707 pap->pa_depth = depth;
1707 1708 if (kind <= CTF_K_UNKNOWN || kind >= CTF_K_TYPEDEF) {
1708 1709 mdb_warn("unknown ctf for %s type %s kind %d\n",
1709 1710 name, type, kind);
1710 1711 return (-1);
1711 1712 }
1712 1713 rc = printfuncs[kind - 1](type, name, id, base, off, pap);
1713 1714
1714 1715 if (rc != 0)
1715 1716 mdb_iob_discard(mdb.m_out);
1716 1717 else
1717 1718 mdb_iob_puts(mdb.m_out, pap->pa_delim);
1718 1719
1719 1720 return (rc);
1720 1721 }
1721 1722
1722 1723 /*
1723 1724 * Special semantics for pipelines.
1724 1725 */
1725 1726 static int
1726 1727 pipe_print(mdb_ctf_id_t id, ulong_t off, void *data)
1727 1728 {
1728 1729 printarg_t *pap = data;
1729 1730 ssize_t size;
1730 1731 static const char *const fsp[] = { "%#r", "%#r", "%#r", "%#llr" };
1731 1732 uintptr_t value;
1732 1733 uintptr_t addr = pap->pa_addr + off / NBBY;
1733 1734 mdb_ctf_id_t base;
1734 1735 int enum_value;
1735 1736 ctf_encoding_t e;
1736 1737
1737 1738 union {
1738 1739 uint64_t i8;
1739 1740 uint32_t i4;
1740 1741 uint16_t i2;
1741 1742 uint8_t i1;
1742 1743 } u;
1743 1744
1744 1745 if (mdb_ctf_type_resolve(id, &base) == -1) {
1745 1746 mdb_warn("could not resolve type");
1746 1747 return (-1);
1747 1748 }
1748 1749
1749 1750 /*
1750 1751 * If the user gives -a, then always print out the address of the
1751 1752 * member.
1752 1753 */
1753 1754 if ((pap->pa_flags & PA_SHOWADDR)) {
1754 1755 mdb_printf("%#lr\n", addr);
1755 1756 return (0);
1756 1757 }
1757 1758
1758 1759 again:
1759 1760 switch (mdb_ctf_type_kind(base)) {
1760 1761 case CTF_K_POINTER:
1761 1762 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as,
1762 1763 &value, sizeof (value), addr) != sizeof (value)) {
1763 1764 mdb_warn("failed to read pointer at %p", addr);
1764 1765 return (-1);
1765 1766 }
1766 1767 mdb_printf("%#lr\n", value);
1767 1768 break;
1768 1769
1769 1770 case CTF_K_ENUM:
1770 1771 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &enum_value,
1771 1772 sizeof (enum_value), addr) != sizeof (enum_value)) {
1772 1773 mdb_warn("failed to read enum at %llx", addr);
1773 1774 return (-1);
1774 1775 }
1775 1776 mdb_printf("%#r\n", enum_value);
1776 1777 break;
1777 1778
1778 1779 case CTF_K_INTEGER:
1779 1780 if (mdb_ctf_type_encoding(base, &e) != 0) {
1780 1781 mdb_warn("could not get type encoding\n");
1781 1782 return (-1);
1782 1783 }
1783 1784
1784 1785 /*
1785 1786 * For immediate values, we just print out the value.
1786 1787 */
1787 1788 size = e.cte_bits / NBBY;
1788 1789 if (size > 8 || (e.cte_bits % NBBY) != 0 ||
1789 1790 (size & (size - 1)) != 0) {
1790 1791 return (print_bitfield(off, pap, &e));
1791 1792 }
1792 1793
1793 1794 if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size,
1794 1795 addr) != size) {
1795 1796 mdb_warn("failed to read %lu bytes at %p",
1796 1797 (ulong_t)size, pap->pa_addr);
1797 1798 return (-1);
1798 1799 }
1799 1800
1800 1801 switch (size) {
1801 1802 case sizeof (uint8_t):
1802 1803 mdb_printf(fsp[0], u.i1);
1803 1804 break;
1804 1805 case sizeof (uint16_t):
1805 1806 mdb_printf(fsp[1], u.i2);
1806 1807 break;
1807 1808 case sizeof (uint32_t):
1808 1809 mdb_printf(fsp[2], u.i4);
1809 1810 break;
1810 1811 case sizeof (uint64_t):
1811 1812 mdb_printf(fsp[3], u.i8);
1812 1813 break;
1813 1814 }
1814 1815 mdb_printf("\n");
1815 1816 break;
1816 1817
1817 1818 case CTF_K_FUNCTION:
1818 1819 case CTF_K_FLOAT:
1819 1820 case CTF_K_ARRAY:
1820 1821 case CTF_K_UNKNOWN:
1821 1822 case CTF_K_STRUCT:
1822 1823 case CTF_K_UNION:
1823 1824 case CTF_K_FORWARD:
1824 1825 /*
1825 1826 * For these types, always print the address of the member
1826 1827 */
1827 1828 mdb_printf("%#lr\n", addr);
1828 1829 break;
1829 1830
1830 1831 default:
1831 1832 mdb_warn("unknown type %d", mdb_ctf_type_kind(base));
1832 1833 break;
1833 1834 }
1834 1835
1835 1836 return (0);
1836 1837 }
1837 1838
1838 1839 static int
1839 1840 parse_delimiter(char **strp)
1840 1841 {
1841 1842 switch (**strp) {
1842 1843 case '\0':
1843 1844 return (MEMBER_DELIM_DONE);
1844 1845
1845 1846 case '.':
1846 1847 *strp = *strp + 1;
1847 1848 return (MEMBER_DELIM_DOT);
1848 1849
1849 1850 case '[':
1850 1851 *strp = *strp + 1;
1851 1852 return (MEMBER_DELIM_LBR);
1852 1853
1853 1854 case '-':
1854 1855 *strp = *strp + 1;
1855 1856 if (**strp == '>') {
1856 1857 *strp = *strp + 1;
1857 1858 return (MEMBER_DELIM_PTR);
1858 1859 }
1859 1860 *strp = *strp - 1;
1860 1861 /*FALLTHROUGH*/
1861 1862 default:
1862 1863 return (MEMBER_DELIM_ERR);
1863 1864 }
1864 1865 }
1865 1866
1866 1867 static int
1867 1868 deref(printarg_t *pap, size_t size)
1868 1869 {
1869 1870 uint32_t a32;
1870 1871 mdb_tgt_as_t as = pap->pa_as;
1871 1872 mdb_tgt_addr_t *ap = &pap->pa_addr;
1872 1873
1873 1874 if (size == sizeof (mdb_tgt_addr_t)) {
1874 1875 if (mdb_tgt_aread(mdb.m_target, as, ap, size, *ap) == -1) {
1875 1876 mdb_warn("could not dereference pointer %llx\n", *ap);
1876 1877 return (-1);
1877 1878 }
1878 1879 } else {
1879 1880 if (mdb_tgt_aread(mdb.m_target, as, &a32, size, *ap) == -1) {
1880 1881 mdb_warn("could not dereference pointer %x\n", *ap);
1881 1882 return (-1);
1882 1883 }
1883 1884
1884 1885 *ap = (mdb_tgt_addr_t)a32;
1885 1886 }
1886 1887
1887 1888 /*
1888 1889 * We've dereferenced at least once, we must be on the real
1889 1890 * target. If we were in the immediate target, reset to the real
1890 1891 * target; it's reset as needed when we return to the print
1891 1892 * routines.
1892 1893 */
1893 1894 if (pap->pa_tgt == pap->pa_immtgt)
1894 1895 pap->pa_tgt = pap->pa_realtgt;
1895 1896
1896 1897 return (0);
1897 1898 }
1898 1899
1899 1900 static int
1900 1901 parse_member(printarg_t *pap, const char *str, mdb_ctf_id_t id,
1901 1902 mdb_ctf_id_t *idp, ulong_t *offp, int *last_deref)
1902 1903 {
1903 1904 int delim;
1904 1905 char member[64];
1905 1906 char buf[128];
1906 1907 uint_t index;
1907 1908 char *start = (char *)str;
1908 1909 char *end;
1909 1910 ulong_t off = 0;
1910 1911 mdb_ctf_arinfo_t ar;
1911 1912 mdb_ctf_id_t rid;
1912 1913 int kind;
1913 1914 ssize_t size;
1914 1915 int non_array = FALSE;
1915 1916
1916 1917 /*
1917 1918 * id always has the unresolved type for printing error messages
1918 1919 * that include the type; rid always has the resolved type for
1919 1920 * use in mdb_ctf_* calls. It is possible for this command to fail,
1920 1921 * however, if the resolved type is in the parent and it is currently
1921 1922 * unavailable. Note that we also can't print out the name of the
1922 1923 * type, since that would also rely on looking up the resolved name.
1923 1924 */
1924 1925 if (mdb_ctf_type_resolve(id, &rid) != 0) {
1925 1926 mdb_warn("failed to resolve type");
1926 1927 return (-1);
1927 1928 }
1928 1929
1929 1930 delim = parse_delimiter(&start);
1930 1931 /*
1931 1932 * If the user fails to specify an initial delimiter, guess -> for
1932 1933 * pointer types and . for non-pointer types.
1933 1934 */
1934 1935 if (delim == MEMBER_DELIM_ERR)
1935 1936 delim = (mdb_ctf_type_kind(rid) == CTF_K_POINTER) ?
1936 1937 MEMBER_DELIM_PTR : MEMBER_DELIM_DOT;
1937 1938
1938 1939 *last_deref = FALSE;
1939 1940
1940 1941 while (delim != MEMBER_DELIM_DONE) {
1941 1942 switch (delim) {
1942 1943 case MEMBER_DELIM_PTR:
1943 1944 kind = mdb_ctf_type_kind(rid);
1944 1945 if (kind != CTF_K_POINTER) {
1945 1946 mdb_warn("%s is not a pointer type\n",
1946 1947 mdb_ctf_type_name(id, buf, sizeof (buf)));
1947 1948 return (-1);
1948 1949 }
1949 1950
1950 1951 size = mdb_ctf_type_size(id);
1951 1952 if (deref(pap, size) != 0)
1952 1953 return (-1);
1953 1954
1954 1955 (void) mdb_ctf_type_reference(rid, &id);
1955 1956 (void) mdb_ctf_type_resolve(id, &rid);
1956 1957
1957 1958 off = 0;
1958 1959 break;
1959 1960
1960 1961 case MEMBER_DELIM_DOT:
1961 1962 kind = mdb_ctf_type_kind(rid);
1962 1963 if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) {
1963 1964 mdb_warn("%s is not a struct or union type\n",
1964 1965 mdb_ctf_type_name(id, buf, sizeof (buf)));
1965 1966 return (-1);
1966 1967 }
1967 1968 break;
1968 1969
1969 1970 case MEMBER_DELIM_LBR:
1970 1971 end = strchr(start, ']');
1971 1972 if (end == NULL) {
1972 1973 mdb_warn("no trailing ']'\n");
1973 1974 return (-1);
1974 1975 }
1975 1976
1976 1977 (void) mdb_snprintf(member, end - start + 1, "%s",
1977 1978 start);
1978 1979
1979 1980 index = mdb_strtoull(member);
1980 1981
1981 1982 switch (mdb_ctf_type_kind(rid)) {
1982 1983 case CTF_K_POINTER:
1983 1984 size = mdb_ctf_type_size(rid);
1984 1985
1985 1986 if (deref(pap, size) != 0)
1986 1987 return (-1);
1987 1988
1988 1989 (void) mdb_ctf_type_reference(rid, &id);
1989 1990 (void) mdb_ctf_type_resolve(id, &rid);
1990 1991
1991 1992 size = mdb_ctf_type_size(id);
1992 1993 if (size <= 0) {
1993 1994 mdb_warn("cannot dereference void "
1994 1995 "type\n");
1995 1996 return (-1);
1996 1997 }
1997 1998
1998 1999 pap->pa_addr += index * size;
1999 2000 off = 0;
2000 2001
2001 2002 if (index == 0 && non_array)
2002 2003 *last_deref = TRUE;
2003 2004 break;
2004 2005
2005 2006 case CTF_K_ARRAY:
2006 2007 (void) mdb_ctf_array_info(rid, &ar);
2007 2008
2008 2009 if (index >= ar.mta_nelems) {
2009 2010 mdb_warn("index %r is outside of "
2010 2011 "array bounds [0 .. %r]\n",
2011 2012 index, ar.mta_nelems - 1);
2012 2013 }
2013 2014
2014 2015 id = ar.mta_contents;
2015 2016 (void) mdb_ctf_type_resolve(id, &rid);
2016 2017
2017 2018 size = mdb_ctf_type_size(id);
2018 2019 if (size <= 0) {
2019 2020 mdb_warn("cannot dereference void "
2020 2021 "type\n");
2021 2022 return (-1);
2022 2023 }
2023 2024
2024 2025 pap->pa_addr += index * size;
2025 2026 off = 0;
2026 2027 break;
2027 2028
2028 2029 default:
2029 2030 mdb_warn("cannot index into non-array, "
2030 2031 "non-pointer type\n");
2031 2032 return (-1);
2032 2033 }
2033 2034
2034 2035 start = end + 1;
2035 2036 delim = parse_delimiter(&start);
2036 2037 continue;
2037 2038
2038 2039 case MEMBER_DELIM_ERR:
2039 2040 default:
2040 2041 mdb_warn("'%c' is not a valid delimiter\n", *start);
2041 2042 return (-1);
2042 2043 }
2043 2044
2044 2045 *last_deref = FALSE;
2045 2046 non_array = TRUE;
2046 2047
2047 2048 /*
2048 2049 * Find the end of the member name; assume that a member
2049 2050 * name is at least one character long.
2050 2051 */
2051 2052 for (end = start + 1; isalnum(*end) || *end == '_'; end++)
2052 2053 continue;
2053 2054
2054 2055 (void) mdb_snprintf(member, end - start + 1, "%s", start);
2055 2056
2056 2057 if (mdb_ctf_member_info(rid, member, &off, &id) != 0) {
2057 2058 mdb_warn("failed to find member %s of %s", member,
2058 2059 mdb_ctf_type_name(id, buf, sizeof (buf)));
2059 2060 return (-1);
2060 2061 }
2061 2062 (void) mdb_ctf_type_resolve(id, &rid);
2062 2063
2063 2064 pap->pa_addr += off / NBBY;
2064 2065
2065 2066 start = end;
2066 2067 delim = parse_delimiter(&start);
2067 2068 }
2068 2069
2069 2070 *idp = id;
2070 2071 *offp = off;
2071 2072
2072 2073 return (0);
2073 2074 }
2074 2075
2075 2076 static int
2076 2077 cmd_print_tab_common(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
2077 2078 const mdb_arg_t *argv)
2078 2079 {
2079 2080 char tn[MDB_SYM_NAMLEN];
2080 2081 char member[64];
2081 2082 int delim, kind;
2082 2083 int ret = 0;
2083 2084 mdb_ctf_id_t id, rid;
2084 2085 mdb_ctf_arinfo_t ar;
2085 2086 char *start, *end;
2086 2087 ulong_t dul;
2087 2088
2088 2089 if (argc == 0 && !(flags & DCMD_TAB_SPACE))
2089 2090 return (0);
2090 2091
2091 2092 if (argc == 0 && (flags & DCMD_TAB_SPACE))
2092 2093 return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_NOPOINT |
2093 2094 MDB_TABC_NOARRAY));
2094 2095
2095 2096 if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0)
2096 2097 return (ret);
2097 2098
2098 2099 if (argc == 1 && (!(flags & DCMD_TAB_SPACE) || ret == 1))
2099 2100 return (mdb_tab_complete_type(mcp, tn, MDB_TABC_NOPOINT |
2100 2101 MDB_TABC_NOARRAY));
2101 2102
2102 2103 if (argc == 1 && (flags & DCMD_TAB_SPACE))
2103 2104 return (mdb_tab_complete_member(mcp, tn, NULL));
2104 2105
2105 2106 /*
2106 2107 * This is the reason that tab completion was created. We're going to go
2107 2108 * along and walk the delimiters until we find something a member that
2108 2109 * we don't recognize, at which point we'll try and tab complete it.
2109 2110 * Note that ::print takes multiple args, so this is going to operate on
2110 2111 * whatever the last arg that we have is.
2111 2112 */
2112 2113 if (mdb_ctf_lookup_by_name(tn, &id) != 0)
2113 2114 return (1);
2114 2115
2115 2116 (void) mdb_ctf_type_resolve(id, &rid);
2116 2117 start = (char *)argv[argc-1].a_un.a_str;
2117 2118 delim = parse_delimiter(&start);
2118 2119
2119 2120 /*
2120 2121 * If we hit the case where we actually have no delimiters, than we need
2121 2122 * to make sure that we properly set up the fields the loops would.
2122 2123 */
2123 2124 if (delim == MEMBER_DELIM_DONE)
2124 2125 (void) mdb_snprintf(member, sizeof (member), "%s", start);
2125 2126
2126 2127 while (delim != MEMBER_DELIM_DONE) {
2127 2128 switch (delim) {
2128 2129 case MEMBER_DELIM_PTR:
2129 2130 kind = mdb_ctf_type_kind(rid);
2130 2131 if (kind != CTF_K_POINTER)
2131 2132 return (1);
2132 2133
2133 2134 (void) mdb_ctf_type_reference(rid, &id);
2134 2135 (void) mdb_ctf_type_resolve(id, &rid);
2135 2136 break;
2136 2137 case MEMBER_DELIM_DOT:
2137 2138 kind = mdb_ctf_type_kind(rid);
2138 2139 if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
2139 2140 return (1);
2140 2141 break;
2141 2142 case MEMBER_DELIM_LBR:
2142 2143 end = strchr(start, ']');
2143 2144 /*
2144 2145 * We're not going to try and tab complete the indexes
2145 2146 * here. So for now, punt on it. Also, we're not going
2146 2147 * to try and validate you're within the bounds, just
2147 2148 * that you get the type you asked for.
2148 2149 */
2149 2150 if (end == NULL)
2150 2151 return (1);
2151 2152
2152 2153 switch (mdb_ctf_type_kind(rid)) {
2153 2154 case CTF_K_POINTER:
2154 2155 (void) mdb_ctf_type_reference(rid, &id);
2155 2156 (void) mdb_ctf_type_resolve(id, &rid);
2156 2157 break;
2157 2158 case CTF_K_ARRAY:
2158 2159 (void) mdb_ctf_array_info(rid, &ar);
2159 2160 id = ar.mta_contents;
2160 2161 (void) mdb_ctf_type_resolve(id, &rid);
2161 2162 break;
2162 2163 default:
2163 2164 return (1);
2164 2165 }
2165 2166
2166 2167 start = end + 1;
2167 2168 delim = parse_delimiter(&start);
2168 2169 break;
2169 2170 case MEMBER_DELIM_ERR:
2170 2171 default:
2171 2172 break;
2172 2173 }
2173 2174
2174 2175 for (end = start + 1; isalnum(*end) || *end == '_'; end++)
2175 2176 continue;
2176 2177
2177 2178 (void) mdb_snprintf(member, end - start + 1, start);
2178 2179
2179 2180 /*
2180 2181 * We are going to try to resolve this name as a member. There
2181 2182 * are a few two different questions that we need to answer. The
2182 2183 * first is do we recognize this member. The second is are we at
2183 2184 * the end of the string. If we encounter a member that we don't
2184 2185 * recognize before the end, then we have to error out and can't
2185 2186 * complete it. But if there are no more delimiters then we can
2186 2187 * try and complete it.
2187 2188 */
2188 2189 ret = mdb_ctf_member_info(rid, member, &dul, &id);
2189 2190 start = end;
2190 2191 delim = parse_delimiter(&start);
2191 2192 if (ret != 0 && errno == EMDB_CTFNOMEMB) {
2192 2193 if (delim != MEMBER_DELIM_DONE)
2193 2194 return (1);
2194 2195 continue;
2195 2196 } else if (ret != 0)
2196 2197 return (1);
2197 2198
2198 2199 if (delim == MEMBER_DELIM_DONE)
2199 2200 return (mdb_tab_complete_member_by_id(mcp, rid,
2200 2201 member));
2201 2202
2202 2203 (void) mdb_ctf_type_resolve(id, &rid);
2203 2204 }
2204 2205
2205 2206 /*
2206 2207 * If we've reached here, then we need to try and tab complete the last
2207 2208 * field, which is currently member, based on the ctf type id that we
2208 2209 * already have in rid.
2209 2210 */
2210 2211 return (mdb_tab_complete_member_by_id(mcp, rid, member));
2211 2212 }
2212 2213
2213 2214 int
2214 2215 cmd_print_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
2215 2216 const mdb_arg_t *argv)
2216 2217 {
2217 2218 int i, dummy;
2218 2219
2219 2220 /*
2220 2221 * This getopts is only here to make the tab completion work better when
2221 2222 * including options in the ::print arguments. None of the values should
2222 2223 * be used. This should only be updated with additional arguments, if
2223 2224 * they are added to cmd_print.
2224 2225 */
2225 2226 i = mdb_getopts(argc, argv,
2226 2227 'a', MDB_OPT_SETBITS, PA_SHOWADDR, &dummy,
2227 2228 'C', MDB_OPT_SETBITS, TRUE, &dummy,
2228 2229 'c', MDB_OPT_UINTPTR, &dummy,
2229 2230 'd', MDB_OPT_SETBITS, PA_INTDEC, &dummy,
2230 2231 'h', MDB_OPT_SETBITS, PA_SHOWHOLES, &dummy,
2231 2232 'i', MDB_OPT_SETBITS, TRUE, &dummy,
2232 2233 'L', MDB_OPT_SETBITS, TRUE, &dummy,
2233 2234 'l', MDB_OPT_UINTPTR, &dummy,
2234 2235 'n', MDB_OPT_SETBITS, PA_NOSYMBOLIC, &dummy,
2235 2236 'p', MDB_OPT_SETBITS, TRUE, &dummy,
2236 2237 's', MDB_OPT_UINTPTR, &dummy,
2237 2238 'T', MDB_OPT_SETBITS, PA_SHOWTYPE | PA_SHOWBASETYPE, &dummy,
2238 2239 't', MDB_OPT_SETBITS, PA_SHOWTYPE, &dummy,
2239 2240 'x', MDB_OPT_SETBITS, PA_INTHEX, &dummy,
2240 2241 NULL);
2241 2242
2242 2243 argc -= i;
2243 2244 argv += i;
2244 2245
2245 2246 return (cmd_print_tab_common(mcp, flags, argc, argv));
2246 2247 }
2247 2248
2248 2249 /*
2249 2250 * Recursively descend a print a given data structure. We create a struct of
2250 2251 * the relevant print arguments and then call mdb_ctf_type_visit() to do the
2251 2252 * traversal, using elt_print() as the callback for each element.
2252 2253 */
2253 2254 /*ARGSUSED*/
2254 2255 int
2255 2256 cmd_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2256 2257 {
2257 2258 uintptr_t opt_c = MDB_ARR_NOLIMIT, opt_l = MDB_ARR_NOLIMIT;
2258 2259 uint_t opt_C = FALSE, opt_L = FALSE, opt_p = FALSE, opt_i = FALSE;
2259 2260 uintptr_t opt_s = (uintptr_t)-1ul;
2260 2261 int uflags = (flags & DCMD_ADDRSPEC) ? PA_SHOWVAL : 0;
2261 2262 mdb_ctf_id_t id;
2262 2263 int err = DCMD_OK;
2263 2264
2264 2265 mdb_tgt_t *t = mdb.m_target;
2265 2266 printarg_t pa;
2266 2267 int d, i;
2267 2268
2268 2269 char s_name[MDB_SYM_NAMLEN];
2269 2270 mdb_syminfo_t s_info;
2270 2271 GElf_Sym sym;
2271 2272
2272 2273 /*
2273 2274 * If a new option is added, make sure the getopts above in
2274 2275 * cmd_print_tab is also updated.
2275 2276 */
2276 2277 i = mdb_getopts(argc, argv,
2277 2278 'a', MDB_OPT_SETBITS, PA_SHOWADDR, &uflags,
2278 2279 'C', MDB_OPT_SETBITS, TRUE, &opt_C,
2279 2280 'c', MDB_OPT_UINTPTR, &opt_c,
2280 2281 'd', MDB_OPT_SETBITS, PA_INTDEC, &uflags,
2281 2282 'h', MDB_OPT_SETBITS, PA_SHOWHOLES, &uflags,
2282 2283 'i', MDB_OPT_SETBITS, TRUE, &opt_i,
2283 2284 'L', MDB_OPT_SETBITS, TRUE, &opt_L,
2284 2285 'l', MDB_OPT_UINTPTR, &opt_l,
2285 2286 'n', MDB_OPT_SETBITS, PA_NOSYMBOLIC, &uflags,
2286 2287 'p', MDB_OPT_SETBITS, TRUE, &opt_p,
2287 2288 's', MDB_OPT_UINTPTR, &opt_s,
2288 2289 'T', MDB_OPT_SETBITS, PA_SHOWTYPE | PA_SHOWBASETYPE, &uflags,
2289 2290 't', MDB_OPT_SETBITS, PA_SHOWTYPE, &uflags,
2290 2291 'x', MDB_OPT_SETBITS, PA_INTHEX, &uflags,
2291 2292 NULL);
2292 2293
2293 2294 if (uflags & PA_INTHEX)
2294 2295 uflags &= ~PA_INTDEC; /* -x and -d are mutually exclusive */
2295 2296
2296 2297 uflags |= PA_SHOWNAME;
2297 2298
2298 2299 if (opt_p && opt_i) {
2299 2300 mdb_warn("-p and -i options are incompatible\n");
2300 2301 return (DCMD_ERR);
2301 2302 }
2302 2303
2303 2304 argc -= i;
2304 2305 argv += i;
2305 2306
2306 2307 if (argc != 0 && argv->a_type == MDB_TYPE_STRING) {
2307 2308 const char *t_name = s_name;
2308 2309 int ret;
2309 2310
2310 2311 if (strchr("+-", argv->a_un.a_str[0]) != NULL)
2311 2312 return (DCMD_USAGE);
2312 2313
2313 2314 if ((ret = args_to_typename(&argc, &argv, s_name,
2314 2315 sizeof (s_name))) != 0)
2315 2316 return (ret);
2316 2317
2317 2318 if (mdb_ctf_lookup_by_name(t_name, &id) != 0) {
2318 2319 if (!(flags & DCMD_ADDRSPEC) || opt_i ||
2319 2320 addr_to_sym(t, addr, s_name, sizeof (s_name),
2320 2321 &sym, &s_info) == NULL ||
2321 2322 mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) {
2322 2323
2323 2324 mdb_warn("failed to look up type %s", t_name);
2324 2325 return (DCMD_ABORT);
2325 2326 }
2326 2327 } else {
2327 2328 argc--;
2328 2329 argv++;
2329 2330 }
2330 2331
2331 2332 } else if (!(flags & DCMD_ADDRSPEC) || opt_i) {
2332 2333 return (DCMD_USAGE);
2333 2334
2334 2335 } else if (addr_to_sym(t, addr, s_name, sizeof (s_name),
2335 2336 &sym, &s_info) == NULL) {
2336 2337 mdb_warn("no symbol information for %a", addr);
2337 2338 return (DCMD_ERR);
2338 2339
2339 2340 } else if (mdb_ctf_lookup_by_symbol(&sym, &s_info, &id) != 0) {
2340 2341 mdb_warn("no type data available for %a [%u]", addr,
2341 2342 s_info.sym_id);
2342 2343 return (DCMD_ERR);
2343 2344 }
2344 2345
2345 2346 pa.pa_tgt = mdb.m_target;
2346 2347 pa.pa_realtgt = pa.pa_tgt;
2347 2348 pa.pa_immtgt = NULL;
2348 2349 pa.pa_as = opt_p ? MDB_TGT_AS_PHYS : MDB_TGT_AS_VIRT;
2349 2350 pa.pa_armemlim = mdb.m_armemlim;
2350 2351 pa.pa_arstrlim = mdb.m_arstrlim;
2351 2352 pa.pa_delim = "\n";
2352 2353 pa.pa_flags = uflags;
2353 2354 pa.pa_nest = 0;
2354 2355 pa.pa_tab = 4;
2355 2356 pa.pa_prefix = NULL;
2356 2357 pa.pa_suffix = NULL;
2357 2358 pa.pa_holes = NULL;
2358 2359 pa.pa_nholes = 0;
2359 2360 pa.pa_depth = 0;
2360 2361 pa.pa_maxdepth = opt_s;
2361 2362 pa.pa_nooutdepth = (uint_t)-1;
2362 2363
2363 2364 if ((flags & DCMD_ADDRSPEC) && !opt_i)
2364 2365 pa.pa_addr = opt_p ? mdb_get_dot() : addr;
2365 2366 else
2366 2367 pa.pa_addr = NULL;
2367 2368
2368 2369 if (opt_i) {
2369 2370 const char *vargv[2];
2370 2371 uintmax_t dot = mdb_get_dot();
2371 2372 size_t outsize = mdb_ctf_type_size(id);
2372 2373 vargv[0] = (const char *)˙
2373 2374 vargv[1] = (const char *)&outsize;
2374 2375 pa.pa_immtgt = mdb_tgt_create(mdb_value_tgt_create,
2375 2376 0, 2, vargv);
2376 2377 pa.pa_tgt = pa.pa_immtgt;
2377 2378 }
2378 2379
2379 2380 if (opt_c != MDB_ARR_NOLIMIT)
2380 2381 pa.pa_arstrlim = opt_c;
2381 2382 if (opt_C)
2382 2383 pa.pa_arstrlim = MDB_ARR_NOLIMIT;
2383 2384 if (opt_l != MDB_ARR_NOLIMIT)
2384 2385 pa.pa_armemlim = opt_l;
2385 2386 if (opt_L)
2386 2387 pa.pa_armemlim = MDB_ARR_NOLIMIT;
2387 2388
2388 2389 if (argc > 0) {
2389 2390 for (i = 0; i < argc; i++) {
2390 2391 mdb_ctf_id_t mid;
2391 2392 int last_deref;
2392 2393 ulong_t off;
2393 2394 int kind;
2394 2395 char buf[MDB_SYM_NAMLEN];
2395 2396
2396 2397 mdb_tgt_t *oldtgt = pa.pa_tgt;
2397 2398 mdb_tgt_as_t oldas = pa.pa_as;
2398 2399 mdb_tgt_addr_t oldaddr = pa.pa_addr;
2399 2400
2400 2401 if (argv->a_type == MDB_TYPE_STRING) {
2401 2402 const char *member = argv[i].a_un.a_str;
2402 2403 mdb_ctf_id_t rid;
2403 2404
2404 2405 if (parse_member(&pa, member, id, &mid,
2405 2406 &off, &last_deref) != 0) {
2406 2407 err = DCMD_ABORT;
2407 2408 goto out;
2408 2409 }
2409 2410
2410 2411 /*
2411 2412 * If the member string ends with a "[0]"
2412 2413 * (last_deref * is true) and the type is a
2413 2414 * structure or union, * print "->" rather
2414 2415 * than "[0]." in elt_print.
2415 2416 */
2416 2417 (void) mdb_ctf_type_resolve(mid, &rid);
2417 2418 kind = mdb_ctf_type_kind(rid);
2418 2419 if (last_deref && IS_SOU(kind)) {
2419 2420 char *end;
2420 2421 (void) mdb_snprintf(buf, sizeof (buf),
2421 2422 "%s", member);
2422 2423 end = strrchr(buf, '[');
2423 2424 *end = '\0';
2424 2425 pa.pa_suffix = "->";
2425 2426 member = &buf[0];
2426 2427 } else if (IS_SOU(kind)) {
2427 2428 pa.pa_suffix = ".";
2428 2429 } else {
2429 2430 pa.pa_suffix = "";
2430 2431 }
2431 2432
2432 2433 pa.pa_prefix = member;
2433 2434 } else {
2434 2435 ulong_t moff;
2435 2436
2436 2437 moff = (ulong_t)argv[i].a_un.a_val;
2437 2438
2438 2439 if (mdb_ctf_offset_to_name(id, moff * NBBY,
2439 2440 buf, sizeof (buf), 0, &mid, &off) == -1) {
2440 2441 mdb_warn("invalid offset %lx\n", moff);
2441 2442 err = DCMD_ABORT;
2442 2443 goto out;
2443 2444 }
2444 2445
2445 2446 pa.pa_prefix = buf;
2446 2447 pa.pa_addr += moff - off / NBBY;
2447 2448 pa.pa_suffix = strlen(buf) == 0 ? "" : ".";
2448 2449 }
2449 2450
2450 2451 off %= NBBY;
2451 2452 if (flags & DCMD_PIPE_OUT) {
2452 2453 if (pipe_print(mid, off, &pa) != 0) {
2453 2454 mdb_warn("failed to print type");
2454 2455 err = DCMD_ERR;
2455 2456 goto out;
2456 2457 }
2457 2458 } else if (off != 0) {
2458 2459 mdb_ctf_id_t base;
2459 2460 (void) mdb_ctf_type_resolve(mid, &base);
2460 2461
2461 2462 if (elt_print("", mid, base, off, 0,
2462 2463 &pa) != 0) {
2463 2464 mdb_warn("failed to print type");
2464 2465 err = DCMD_ERR;
2465 2466 goto out;
2466 2467 }
2467 2468 } else {
2468 2469 if (mdb_ctf_type_visit(mid, elt_print,
2469 2470 &pa) == -1) {
2470 2471 mdb_warn("failed to print type");
2471 2472 err = DCMD_ERR;
2472 2473 goto out;
2473 2474 }
2474 2475
2475 2476 for (d = pa.pa_depth - 1; d >= 0; d--)
2476 2477 print_close_sou(&pa, d);
2477 2478 }
2478 2479
2479 2480 pa.pa_depth = 0;
2480 2481 pa.pa_tgt = oldtgt;
2481 2482 pa.pa_as = oldas;
2482 2483 pa.pa_addr = oldaddr;
2483 2484 pa.pa_delim = "\n";
2484 2485 }
2485 2486
2486 2487 } else if (flags & DCMD_PIPE_OUT) {
2487 2488 if (pipe_print(id, 0, &pa) != 0) {
2488 2489 mdb_warn("failed to print type");
2489 2490 err = DCMD_ERR;
2490 2491 goto out;
2491 2492 }
2492 2493 } else {
2493 2494 if (mdb_ctf_type_visit(id, elt_print, &pa) == -1) {
2494 2495 mdb_warn("failed to print type");
2495 2496 err = DCMD_ERR;
2496 2497 goto out;
2497 2498 }
2498 2499
2499 2500 for (d = pa.pa_depth - 1; d >= 0; d--)
2500 2501 print_close_sou(&pa, d);
2501 2502 }
2502 2503
2503 2504 mdb_set_dot(addr + mdb_ctf_type_size(id));
2504 2505 err = DCMD_OK;
2505 2506 out:
2506 2507 if (pa.pa_immtgt)
2507 2508 mdb_tgt_destroy(pa.pa_immtgt);
2508 2509 return (err);
2509 2510 }
2510 2511
2511 2512 void
2512 2513 print_help(void)
2513 2514 {
2514 2515 mdb_printf(
2515 2516 "-a show address of object\n"
2516 2517 "-C unlimit the length of character arrays\n"
2517 2518 "-c limit limit the length of character arrays\n"
2518 2519 "-d output values in decimal\n"
2519 2520 "-h print holes in structures\n"
2520 2521 "-i interpret address as data of the given type\n"
2521 2522 "-L unlimit the length of standard arrays\n"
2522 2523 "-l limit limit the length of standard arrays\n"
2523 2524 "-n don't print pointers as symbol offsets\n"
2524 2525 "-p interpret address as a physical memory address\n"
2525 2526 "-s depth limit the recursion depth\n"
2526 2527 "-T show type and <<base type>> of object\n"
2527 2528 "-t show type of object\n"
2528 2529 "-x output values in hexadecimal\n"
2529 2530 "\n"
2530 2531 "type may be omitted if the C type of addr can be inferred.\n"
2531 2532 "\n"
2532 2533 "Members may be specified with standard C syntax using the\n"
2533 2534 "array indexing operator \"[index]\", structure member\n"
2534 2535 "operator \".\", or structure pointer operator \"->\".\n"
2535 2536 "\n"
2536 2537 "Offsets must use the $[ expression ] syntax\n");
2537 2538 }
2538 2539
2539 2540 static int
2540 2541 printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt,
2541 2542 boolean_t sign)
2542 2543 {
2543 2544 ssize_t size;
2544 2545 mdb_ctf_id_t base;
2545 2546 ctf_encoding_t e;
2546 2547
2547 2548 union {
2548 2549 uint64_t ui8;
2549 2550 uint32_t ui4;
2550 2551 uint16_t ui2;
2551 2552 uint8_t ui1;
2552 2553 int64_t i8;
↓ open down ↓ |
2514 lines elided |
↑ open up ↑ |
2553 2554 int32_t i4;
2554 2555 int16_t i2;
2555 2556 int8_t i1;
2556 2557 } u;
2557 2558
2558 2559 if (mdb_ctf_type_resolve(id, &base) == -1) {
2559 2560 mdb_warn("could not resolve type");
2560 2561 return (DCMD_ABORT);
2561 2562 }
2562 2563
2563 - if (mdb_ctf_type_kind(base) != CTF_K_INTEGER) {
2564 - mdb_warn("expected integer type\n");
2565 - return (DCMD_ABORT);
2566 - }
2567 -
2568 - if (mdb_ctf_type_encoding(base, &e) != 0) {
2569 - mdb_warn("could not get type encoding");
2570 - return (DCMD_ABORT);
2564 + switch (mdb_ctf_type_kind(base)) {
2565 + case CTF_K_ENUM:
2566 + e.cte_format = CTF_INT_SIGNED;
2567 + e.cte_offset = 0;
2568 + e.cte_bits = mdb_ctf_type_size(id) * NBBY;
2569 + break;
2570 + case CTF_K_INTEGER:
2571 + if (mdb_ctf_type_encoding(base, &e) != 0) {
2572 + mdb_warn("could not get type encoding");
2573 + return (DCMD_ABORT);
2574 + }
2575 + break;
2576 + default:
2577 + mdb_warn("expected integer type\n");
2578 + return (DCMD_ABORT);
2571 2579 }
2572 2580
2573 2581 if (sign)
2574 2582 sign = e.cte_format & CTF_INT_SIGNED;
2575 2583
2576 2584 size = e.cte_bits / NBBY;
2577 2585
2578 2586 /*
2579 2587 * Check to see if our life has been complicated by the presence of
2580 2588 * a bitfield. If it has, we will print it using logic that is only
2581 2589 * slightly different than that found in print_bitfield(), above. (In
2582 2590 * particular, see the comments there for an explanation of the
2583 2591 * endianness differences in this code.)
2584 2592 */
2585 2593 if (size > 8 || (e.cte_bits % NBBY) != 0 ||
2586 2594 (size & (size - 1)) != 0) {
2587 2595 uint64_t mask = (1ULL << e.cte_bits) - 1;
2588 2596 uint64_t value = 0;
2589 2597 uint8_t *buf = (uint8_t *)&value;
2590 2598 uint8_t shift;
2591 2599
2592 2600 /*
2593 2601 * Round our size up one byte.
2594 2602 */
2595 2603 size = (e.cte_bits + (NBBY - 1)) / NBBY;
2596 2604
2597 2605 if (e.cte_bits > sizeof (value) * NBBY - 1) {
2598 2606 mdb_printf("invalid bitfield size %u", e.cte_bits);
2599 2607 return (DCMD_ABORT);
2600 2608 }
2601 2609
2602 2610 #ifdef _BIG_ENDIAN
2603 2611 buf += sizeof (value) - size;
2604 2612 off += e.cte_bits;
2605 2613 #endif
2606 2614
2607 2615 if (mdb_vread(buf, size, addr) == -1) {
2608 2616 mdb_warn("failed to read %lu bytes at %p", size, addr);
2609 2617 return (DCMD_ERR);
2610 2618 }
2611 2619
2612 2620 shift = off % NBBY;
2613 2621 #ifdef _BIG_ENDIAN
2614 2622 shift = NBBY - shift;
2615 2623 #endif
2616 2624
2617 2625 /*
2618 2626 * If we have a bit offset within the byte, shift it down.
2619 2627 */
2620 2628 if (off % NBBY != 0)
2621 2629 value >>= shift;
2622 2630 value &= mask;
2623 2631
2624 2632 if (sign) {
2625 2633 int sshift = sizeof (value) * NBBY - e.cte_bits;
2626 2634 value = ((int64_t)value << sshift) >> sshift;
2627 2635 }
2628 2636
2629 2637 mdb_printf(fmt, value);
2630 2638 return (0);
2631 2639 }
2632 2640
2633 2641 if (mdb_vread(&u.i8, size, addr) == -1) {
2634 2642 mdb_warn("failed to read %lu bytes at %p", (ulong_t)size, addr);
2635 2643 return (DCMD_ERR);
2636 2644 }
2637 2645
2638 2646 switch (size) {
2639 2647 case sizeof (uint8_t):
2640 2648 mdb_printf(fmt, (uint64_t)(sign ? u.i1 : u.ui1));
2641 2649 break;
2642 2650 case sizeof (uint16_t):
2643 2651 mdb_printf(fmt, (uint64_t)(sign ? u.i2 : u.ui2));
2644 2652 break;
2645 2653 case sizeof (uint32_t):
2646 2654 mdb_printf(fmt, (uint64_t)(sign ? u.i4 : u.ui4));
2647 2655 break;
2648 2656 case sizeof (uint64_t):
2649 2657 mdb_printf(fmt, (uint64_t)(sign ? u.i8 : u.ui8));
2650 2658 break;
2651 2659 }
2652 2660
2653 2661 return (0);
2654 2662 }
2655 2663
2656 2664 static int
2657 2665 printf_int(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2658 2666 {
2659 2667 return (printf_signed(id, addr, off, fmt, B_TRUE));
2660 2668 }
2661 2669
2662 2670 static int
2663 2671 printf_uint(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2664 2672 {
2665 2673 return (printf_signed(id, addr, off, fmt, B_FALSE));
2666 2674 }
2667 2675
2668 2676 /*ARGSUSED*/
2669 2677 static int
2670 2678 printf_uint32(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2671 2679 {
2672 2680 mdb_ctf_id_t base;
2673 2681 ctf_encoding_t e;
2674 2682 uint32_t value;
2675 2683
2676 2684 if (mdb_ctf_type_resolve(id, &base) == -1) {
2677 2685 mdb_warn("could not resolve type\n");
2678 2686 return (DCMD_ABORT);
2679 2687 }
2680 2688
2681 2689 if (mdb_ctf_type_kind(base) != CTF_K_INTEGER ||
2682 2690 mdb_ctf_type_encoding(base, &e) != 0 ||
2683 2691 e.cte_bits / NBBY != sizeof (value)) {
2684 2692 mdb_warn("expected 32-bit integer type\n");
2685 2693 return (DCMD_ABORT);
2686 2694 }
2687 2695
2688 2696 if (mdb_vread(&value, sizeof (value), addr) == -1) {
2689 2697 mdb_warn("failed to read 32-bit value at %p", addr);
2690 2698 return (DCMD_ERR);
2691 2699 }
2692 2700
2693 2701 mdb_printf(fmt, value);
2694 2702
2695 2703 return (0);
2696 2704 }
2697 2705
2698 2706 /*ARGSUSED*/
2699 2707 static int
2700 2708 printf_ptr(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2701 2709 {
2702 2710 uintptr_t value;
2703 2711 mdb_ctf_id_t base;
2704 2712
2705 2713 if (mdb_ctf_type_resolve(id, &base) == -1) {
2706 2714 mdb_warn("could not resolve type\n");
2707 2715 return (DCMD_ABORT);
2708 2716 }
2709 2717
2710 2718 if (mdb_ctf_type_kind(base) != CTF_K_POINTER) {
2711 2719 mdb_warn("expected pointer type\n");
2712 2720 return (DCMD_ABORT);
2713 2721 }
2714 2722
2715 2723 if (mdb_vread(&value, sizeof (value), addr) == -1) {
2716 2724 mdb_warn("failed to read pointer at %llx", addr);
2717 2725 return (DCMD_ERR);
2718 2726 }
2719 2727
2720 2728 mdb_printf(fmt, value);
2721 2729
2722 2730 return (0);
2723 2731 }
2724 2732
2725 2733 /*ARGSUSED*/
2726 2734 static int
2727 2735 printf_string(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2728 2736 {
2729 2737 mdb_ctf_id_t base;
2730 2738 mdb_ctf_arinfo_t r;
2731 2739 char buf[1024];
2732 2740 ssize_t size;
2733 2741
2734 2742 if (mdb_ctf_type_resolve(id, &base) == -1) {
2735 2743 mdb_warn("could not resolve type");
2736 2744 return (DCMD_ABORT);
2737 2745 }
2738 2746
2739 2747 if (mdb_ctf_type_kind(base) == CTF_K_POINTER) {
2740 2748 uintptr_t value;
2741 2749
2742 2750 if (mdb_vread(&value, sizeof (value), addr) == -1) {
↓ open down ↓ |
162 lines elided |
↑ open up ↑ |
2743 2751 mdb_warn("failed to read pointer at %llx", addr);
2744 2752 return (DCMD_ERR);
2745 2753 }
2746 2754
2747 2755 if (mdb_readstr(buf, sizeof (buf) - 1, value) < 0) {
2748 2756 mdb_warn("failed to read string at %llx", value);
2749 2757 return (DCMD_ERR);
2750 2758 }
2751 2759
2752 2760 mdb_printf(fmt, buf);
2761 + return (0);
2762 + }
2763 +
2764 + if (mdb_ctf_type_kind(base) == CTF_K_ENUM) {
2765 + const char *strval;
2766 + int value;
2767 +
2768 + if (mdb_vread(&value, sizeof (value), addr) == -1) {
2769 + mdb_warn("failed to read pointer at %llx", addr);
2770 + return (DCMD_ERR);
2771 + }
2772 +
2773 + if ((strval = mdb_ctf_enum_name(id, value))) {
2774 + mdb_printf(fmt, strval);
2775 + } else {
2776 + (void) mdb_snprintf(buf, sizeof (buf), "<%d>", value);
2777 + mdb_printf(fmt, buf);
2778 + }
2779 +
2753 2780 return (0);
2754 2781 }
2755 2782
2756 2783 if (mdb_ctf_type_kind(base) != CTF_K_ARRAY) {
2757 2784 mdb_warn("exepected pointer or array type\n");
2758 2785 return (DCMD_ABORT);
2759 2786 }
2760 2787
2761 2788 if (mdb_ctf_array_info(base, &r) == -1 ||
2762 2789 mdb_ctf_type_resolve(r.mta_contents, &base) == -1 ||
2763 2790 (size = mdb_ctf_type_size(base)) == -1) {
2764 2791 mdb_warn("can't determine array type");
2765 2792 return (DCMD_ABORT);
2766 2793 }
2767 2794
2768 2795 if (size != 1) {
2769 2796 mdb_warn("string format specifier requires "
2770 2797 "an array of characters\n");
2771 2798 return (DCMD_ABORT);
2772 2799 }
2773 2800
2774 2801 bzero(buf, sizeof (buf));
2775 2802
2776 2803 if (mdb_vread(buf, MIN(r.mta_nelems, sizeof (buf) - 1), addr) == -1) {
2777 2804 mdb_warn("failed to read array at %p", addr);
2778 2805 return (DCMD_ERR);
2779 2806 }
2780 2807
2781 2808 mdb_printf(fmt, buf);
2782 2809
2783 2810 return (0);
2784 2811 }
2785 2812
2786 2813 /*ARGSUSED*/
2787 2814 static int
2788 2815 printf_ipv6(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
2789 2816 {
2790 2817 mdb_ctf_id_t base;
2791 2818 mdb_ctf_id_t ipv6_type, ipv6_base;
2792 2819 in6_addr_t ipv6;
2793 2820
2794 2821 if (mdb_ctf_lookup_by_name("in6_addr_t", &ipv6_type) == -1) {
2795 2822 mdb_warn("could not resolve in6_addr_t type\n");
2796 2823 return (DCMD_ABORT);
2797 2824 }
2798 2825
2799 2826 if (mdb_ctf_type_resolve(id, &base) == -1) {
2800 2827 mdb_warn("could not resolve type\n");
2801 2828 return (DCMD_ABORT);
2802 2829 }
2803 2830
2804 2831 if (mdb_ctf_type_resolve(ipv6_type, &ipv6_base) == -1) {
2805 2832 mdb_warn("could not resolve in6_addr_t type\n");
2806 2833 return (DCMD_ABORT);
2807 2834 }
2808 2835
2809 2836 if (mdb_ctf_type_cmp(base, ipv6_base) != 0) {
2810 2837 mdb_warn("requires argument of type in6_addr_t\n");
2811 2838 return (DCMD_ABORT);
2812 2839 }
2813 2840
2814 2841 if (mdb_vread(&ipv6, sizeof (ipv6), addr) == -1) {
2815 2842 mdb_warn("couldn't read in6_addr_t at %p", addr);
2816 2843 return (DCMD_ERR);
2817 2844 }
2818 2845
2819 2846 mdb_printf(fmt, &ipv6);
2820 2847
2821 2848 return (0);
2822 2849 }
2823 2850
2824 2851 /*
2825 2852 * To validate the format string specified to ::printf, we run the format
2826 2853 * string through a very simple state machine that restricts us to a subset
2827 2854 * of mdb_printf() functionality.
2828 2855 */
2829 2856 enum {
2830 2857 PRINTF_NOFMT = 1, /* no current format specifier */
2831 2858 PRINTF_PERC, /* processed '%' */
2832 2859 PRINTF_FMT, /* processing format specifier */
2833 2860 PRINTF_LEFT, /* processed '-', expecting width */
2834 2861 PRINTF_WIDTH, /* processing width */
2835 2862 PRINTF_QUES /* processed '?', expecting format */
2836 2863 };
2837 2864
2838 2865 int
2839 2866 cmd_printf_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
2840 2867 const mdb_arg_t *argv)
2841 2868 {
2842 2869 int ii;
2843 2870 char *f;
2844 2871
2845 2872 /*
2846 2873 * If argc doesn't have more than what should be the format string,
2847 2874 * ignore it.
2848 2875 */
2849 2876 if (argc <= 1)
2850 2877 return (0);
2851 2878
2852 2879 /*
2853 2880 * Because we aren't leveraging the lex and yacc engine, we have to
2854 2881 * manually walk the arguments to find both the first and last
2855 2882 * open/close quote of the format string.
2856 2883 */
2857 2884 f = strchr(argv[0].a_un.a_str, '"');
2858 2885 if (f == NULL)
2859 2886 return (0);
2860 2887
2861 2888 f = strchr(f + 1, '"');
2862 2889 if (f != NULL) {
2863 2890 ii = 0;
2864 2891 } else {
2865 2892 for (ii = 1; ii < argc; ii++) {
2866 2893 if (argv[ii].a_type != MDB_TYPE_STRING)
2867 2894 continue;
2868 2895 f = strchr(argv[ii].a_un.a_str, '"');
2869 2896 if (f != NULL)
2870 2897 break;
2871 2898 }
2872 2899 /* Never found */
2873 2900 if (ii == argc)
2874 2901 return (0);
2875 2902 }
2876 2903
2877 2904 ii++;
2878 2905 argc -= ii;
2879 2906 argv += ii;
2880 2907
2881 2908 return (cmd_print_tab_common(mcp, flags, argc, argv));
2882 2909 }
2883 2910
2884 2911 int
2885 2912 cmd_printf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2886 2913 {
2887 2914 char type[MDB_SYM_NAMLEN];
2888 2915 int i, nfmts = 0, ret;
2889 2916 mdb_ctf_id_t id;
2890 2917 const char *fmt, *member;
2891 2918 char **fmts, *last, *dest, f;
2892 2919 int (**funcs)(mdb_ctf_id_t, uintptr_t, ulong_t, char *);
2893 2920 int state = PRINTF_NOFMT;
2894 2921 printarg_t pa;
2895 2922
2896 2923 if (!(flags & DCMD_ADDRSPEC))
2897 2924 return (DCMD_USAGE);
2898 2925
2899 2926 bzero(&pa, sizeof (pa));
2900 2927 pa.pa_as = MDB_TGT_AS_VIRT;
2901 2928 pa.pa_realtgt = pa.pa_tgt = mdb.m_target;
2902 2929
2903 2930 if (argc == 0 || argv[0].a_type != MDB_TYPE_STRING) {
2904 2931 mdb_warn("expected a format string\n");
2905 2932 return (DCMD_USAGE);
2906 2933 }
2907 2934
2908 2935 /*
2909 2936 * Our first argument is a format string; rip it apart and run it
2910 2937 * through our state machine to validate that our input is within the
2911 2938 * subset of mdb_printf() format strings that we allow.
2912 2939 */
2913 2940 fmt = argv[0].a_un.a_str;
2914 2941 /*
2915 2942 * 'dest' must be large enough to hold a copy of the format string,
2916 2943 * plus a NUL and up to 2 additional characters for each conversion
2917 2944 * in the format string. This gives us a bloat factor of 5/2 ~= 3.
2918 2945 * e.g. "%d" (strlen of 2) --> "%lld\0" (need 5 bytes)
2919 2946 */
2920 2947 dest = mdb_zalloc(strlen(fmt) * 3, UM_SLEEP | UM_GC);
2921 2948 fmts = mdb_zalloc(strlen(fmt) * sizeof (char *), UM_SLEEP | UM_GC);
2922 2949 funcs = mdb_zalloc(strlen(fmt) * sizeof (void *), UM_SLEEP | UM_GC);
2923 2950 last = dest;
2924 2951
2925 2952 for (i = 0; fmt[i] != '\0'; i++) {
2926 2953 *dest++ = f = fmt[i];
2927 2954
2928 2955 switch (state) {
2929 2956 case PRINTF_NOFMT:
2930 2957 state = f == '%' ? PRINTF_PERC : PRINTF_NOFMT;
2931 2958 break;
2932 2959
2933 2960 case PRINTF_PERC:
2934 2961 state = f == '-' ? PRINTF_LEFT :
2935 2962 f >= '0' && f <= '9' ? PRINTF_WIDTH :
2936 2963 f == '?' ? PRINTF_QUES :
2937 2964 f == '%' ? PRINTF_NOFMT : PRINTF_FMT;
2938 2965 break;
2939 2966
2940 2967 case PRINTF_LEFT:
2941 2968 state = f >= '0' && f <= '9' ? PRINTF_WIDTH :
2942 2969 f == '?' ? PRINTF_QUES : PRINTF_FMT;
2943 2970 break;
2944 2971
2945 2972 case PRINTF_WIDTH:
2946 2973 state = f >= '0' && f <= '9' ? PRINTF_WIDTH :
2947 2974 PRINTF_FMT;
2948 2975 break;
2949 2976
2950 2977 case PRINTF_QUES:
2951 2978 state = PRINTF_FMT;
2952 2979 break;
2953 2980 }
2954 2981
2955 2982 if (state != PRINTF_FMT)
2956 2983 continue;
2957 2984
2958 2985 dest--;
2959 2986
2960 2987 /*
2961 2988 * Now check that we have one of our valid format characters.
2962 2989 */
2963 2990 switch (f) {
2964 2991 case 'a':
2965 2992 case 'A':
2966 2993 case 'p':
2967 2994 funcs[nfmts] = printf_ptr;
2968 2995 break;
2969 2996
2970 2997 case 'd':
2971 2998 case 'q':
2972 2999 case 'R':
2973 3000 funcs[nfmts] = printf_int;
2974 3001 *dest++ = 'l';
2975 3002 *dest++ = 'l';
2976 3003 break;
2977 3004
2978 3005 case 'I':
2979 3006 funcs[nfmts] = printf_uint32;
2980 3007 break;
2981 3008
2982 3009 case 'N':
2983 3010 funcs[nfmts] = printf_ipv6;
2984 3011 break;
2985 3012
2986 3013 case 'H':
2987 3014 case 'o':
2988 3015 case 'r':
2989 3016 case 'u':
2990 3017 case 'x':
2991 3018 case 'X':
2992 3019 funcs[nfmts] = printf_uint;
2993 3020 *dest++ = 'l';
2994 3021 *dest++ = 'l';
2995 3022 break;
2996 3023
2997 3024 case 's':
2998 3025 funcs[nfmts] = printf_string;
2999 3026 break;
3000 3027
3001 3028 case 'Y':
3002 3029 funcs[nfmts] = sizeof (time_t) == sizeof (int) ?
3003 3030 printf_uint32 : printf_uint;
3004 3031 break;
3005 3032
3006 3033 default:
3007 3034 mdb_warn("illegal format string at or near "
3008 3035 "'%c' (position %d)\n", f, i + 1);
3009 3036 return (DCMD_ABORT);
3010 3037 }
3011 3038
3012 3039 *dest++ = f;
3013 3040 *dest++ = '\0';
3014 3041 fmts[nfmts++] = last;
3015 3042 last = dest;
3016 3043 state = PRINTF_NOFMT;
3017 3044 }
3018 3045
3019 3046 argc--;
3020 3047 argv++;
3021 3048
3022 3049 /*
3023 3050 * Now we expect a type name.
3024 3051 */
3025 3052 if ((ret = args_to_typename(&argc, &argv, type, sizeof (type))) != 0)
3026 3053 return (ret);
3027 3054
3028 3055 argv++;
3029 3056 argc--;
3030 3057
3031 3058 if (mdb_ctf_lookup_by_name(type, &id) != 0) {
3032 3059 mdb_warn("failed to look up type %s", type);
3033 3060 return (DCMD_ABORT);
3034 3061 }
3035 3062
3036 3063 if (argc == 0) {
3037 3064 mdb_warn("at least one member must be specified\n");
3038 3065 return (DCMD_USAGE);
3039 3066 }
3040 3067
3041 3068 if (argc != nfmts) {
3042 3069 mdb_warn("%s format specifiers (found %d, expected %d)\n",
3043 3070 argc > nfmts ? "missing" : "extra", nfmts, argc);
3044 3071 return (DCMD_ABORT);
3045 3072 }
3046 3073
3047 3074 for (i = 0; i < argc; i++) {
3048 3075 mdb_ctf_id_t mid;
3049 3076 ulong_t off;
3050 3077 int ignored;
3051 3078
3052 3079 if (argv[i].a_type != MDB_TYPE_STRING) {
3053 3080 mdb_warn("expected only type member arguments\n");
3054 3081 return (DCMD_ABORT);
3055 3082 }
3056 3083
3057 3084 if (strcmp((member = argv[i].a_un.a_str), ".") == 0) {
3058 3085 /*
3059 3086 * We allow "." to be specified to denote the current
3060 3087 * value of dot.
3061 3088 */
3062 3089 if (funcs[i] != printf_ptr && funcs[i] != printf_uint &&
3063 3090 funcs[i] != printf_int) {
3064 3091 mdb_warn("expected integer or pointer format "
3065 3092 "specifier for '.'\n");
3066 3093 return (DCMD_ABORT);
3067 3094 }
3068 3095
3069 3096 mdb_printf(fmts[i], mdb_get_dot());
3070 3097 continue;
3071 3098 }
3072 3099
3073 3100 pa.pa_addr = addr;
3074 3101
3075 3102 if (parse_member(&pa, member, id, &mid, &off, &ignored) != 0)
3076 3103 return (DCMD_ABORT);
3077 3104
3078 3105 if ((ret = funcs[i](mid, pa.pa_addr, off, fmts[i])) != 0) {
3079 3106 mdb_warn("failed to print member '%s'\n", member);
3080 3107 return (ret);
3081 3108 }
3082 3109 }
3083 3110
3084 3111 mdb_printf("%s", last);
3085 3112
3086 3113 return (DCMD_OK);
3087 3114 }
3088 3115
3089 3116 static char _mdb_printf_help[] =
3090 3117 "The format string argument is a printf(3C)-like format string that is a\n"
3091 3118 "subset of the format strings supported by mdb_printf(). The type argument\n"
3092 3119 "is the name of a type to be used to interpret the memory referenced by dot.\n"
3093 3120 "The member should either be a field in the specified structure, or the\n"
3094 3121 "special member '.', denoting the value of dot (and treated as a pointer).\n"
3095 3122 "The number of members must match the number of format specifiers in the\n"
3096 3123 "format string.\n"
3097 3124 "\n"
3098 3125 "The following format specifiers are recognized by ::printf:\n"
3099 3126 "\n"
3100 3127 " %% Prints the '%' symbol.\n"
3101 3128 " %a Prints the member in symbolic form.\n"
3102 3129 " %d Prints the member as a decimal integer. If the member is a signed\n"
3103 3130 " integer type, the output will be signed.\n"
3104 3131 " %H Prints the member as a human-readable size.\n"
3105 3132 " %I Prints the member as an IPv4 address (must be 32-bit integer type).\n"
3106 3133 " %N Prints the member as an IPv6 address (must be of type in6_addr_t).\n"
3107 3134 " %o Prints the member as an unsigned octal integer.\n"
3108 3135 " %p Prints the member as a pointer, in hexadecimal.\n"
3109 3136 " %q Prints the member in signed octal. Honk if you ever use this!\n"
3110 3137 " %r Prints the member as an unsigned value in the current output radix.\n"
3111 3138 " %R Prints the member as a signed value in the current output radix.\n"
3112 3139 " %s Prints the member as a string (requires a pointer or an array of\n"
3113 3140 " characters).\n"
3114 3141 " %u Prints the member as an unsigned decimal integer.\n"
3115 3142 " %x Prints the member in hexadecimal.\n"
3116 3143 " %X Prints the member in hexadecimal, using the characters A-F as the\n"
3117 3144 " digits for the values 10-15.\n"
3118 3145 " %Y Prints the member as a time_t as the string "
3119 3146 "'year month day HH:MM:SS'.\n"
3120 3147 "\n"
3121 3148 "The following field width specifiers are recognized by ::printf:\n"
3122 3149 "\n"
3123 3150 " %n Field width is set to the specified decimal value.\n"
3124 3151 " %? Field width is set to the maximum width of a hexadecimal pointer\n"
3125 3152 " value. This is 8 in an ILP32 environment, and 16 in an LP64\n"
3126 3153 " environment.\n"
3127 3154 "\n"
3128 3155 "The following flag specifers are recognized by ::printf:\n"
3129 3156 "\n"
3130 3157 " %- Left-justify the output within the specified field width. If the\n"
3131 3158 " width of the output is less than the specified field width, the\n"
3132 3159 " output will be padded with blanks on the right-hand side. Without\n"
3133 3160 " %-, values are right-justified by default.\n"
3134 3161 "\n"
3135 3162 " %0 Zero-fill the output field if the output is right-justified and the\n"
3136 3163 " width of the output is less than the specified field width. Without\n"
3137 3164 " %0, right-justified values are prepended with blanks in order to\n"
3138 3165 " fill the field.\n"
3139 3166 "\n"
3140 3167 "Examples: \n"
3141 3168 "\n"
3142 3169 " ::walk proc | "
3143 3170 "::printf \"%-6d %s\\n\" proc_t p_pidp->pid_id p_user.u_psargs\n"
3144 3171 " ::walk thread | "
3145 3172 "::printf \"%?p %3d %a\\n\" kthread_t . t_pri t_startpc\n"
3146 3173 " ::walk zone | "
3147 3174 "::printf \"%-40s %20s\\n\" zone_t zone_name zone_nodename\n"
3148 3175 " ::walk ire | "
3149 3176 "::printf \"%Y %I\\n\" ire_t ire_create_time ire_u.ire4_u.ire4_addr\n"
3150 3177 "\n";
3151 3178
3152 3179 void
3153 3180 printf_help(void)
3154 3181 {
3155 3182 mdb_printf("%s", _mdb_printf_help);
3156 3183 }
↓ open down ↓ |
394 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX