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