Print this page
2574 mdb needs ::printf
Reviewed by: Joshua M. Clulow <josh@sysmgr.org>
Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Approved by: ?
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
+++ new/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Copyright (c) 2012 by Delphix. All rights reserved.
29 29 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
30 30 */
31 31
32 32 #include <sys/elf.h>
33 33 #include <sys/elf_SPARC.h>
34 34
35 35 #include <libproc.h>
36 36 #include <stdlib.h>
37 37 #include <string.h>
38 38 #include <fcntl.h>
39 39 #include <errno.h>
40 40 #include <alloca.h>
41 41 #include <libctf.h>
42 42 #include <ctype.h>
43 43
44 44 #include <mdb/mdb_string.h>
45 45 #include <mdb/mdb_argvec.h>
46 46 #include <mdb/mdb_nv.h>
47 47 #include <mdb/mdb_fmt.h>
48 48 #include <mdb/mdb_target.h>
49 49 #include <mdb/mdb_err.h>
50 50 #include <mdb/mdb_debug.h>
51 51 #include <mdb/mdb_conf.h>
52 52 #include <mdb/mdb_module.h>
53 53 #include <mdb/mdb_modapi.h>
54 54 #include <mdb/mdb_stdlib.h>
55 55 #include <mdb/mdb_lex.h>
56 56 #include <mdb/mdb_io_impl.h>
57 57 #include <mdb/mdb_help.h>
58 58 #include <mdb/mdb_disasm.h>
59 59 #include <mdb/mdb_frame.h>
60 60 #include <mdb/mdb_evset.h>
61 61 #include <mdb/mdb_print.h>
62 62 #include <mdb/mdb_nm.h>
63 63 #include <mdb/mdb_set.h>
64 64 #include <mdb/mdb_demangle.h>
65 65 #include <mdb/mdb_ctf.h>
66 66 #include <mdb/mdb_whatis.h>
67 67 #include <mdb/mdb_whatis_impl.h>
68 68 #include <mdb/mdb_macalias.h>
69 69 #include <mdb/mdb_tab.h>
70 70 #ifdef _KMDB
71 71 #include <kmdb/kmdb_kdi.h>
72 72 #endif
73 73 #include <mdb/mdb.h>
74 74
75 75 #ifdef __sparc
76 76 #define SETHI_MASK 0xc1c00000
77 77 #define SETHI_VALUE 0x01000000
78 78
79 79 #define IS_SETHI(machcode) (((machcode) & SETHI_MASK) == SETHI_VALUE)
80 80
81 81 #define OP(machcode) ((machcode) >> 30)
82 82 #define OP3(machcode) (((machcode) >> 19) & 0x3f)
83 83 #define RD(machcode) (((machcode) >> 25) & 0x1f)
84 84 #define RS1(machcode) (((machcode) >> 14) & 0x1f)
85 85 #define I(machcode) (((machcode) >> 13) & 0x01)
86 86
87 87 #define IMM13(machcode) ((machcode) & 0x1fff)
88 88 #define IMM22(machcode) ((machcode) & 0x3fffff)
89 89
90 90 #define OP_ARITH_MEM_MASK 0x2
91 91 #define OP_ARITH 0x2
92 92 #define OP_MEM 0x3
93 93
94 94 #define OP3_CC_MASK 0x10
95 95 #define OP3_COMPLEX_MASK 0x20
96 96
97 97 #define OP3_ADD 0x00
98 98 #define OP3_OR 0x02
99 99 #define OP3_XOR 0x03
100 100
101 101 #ifndef R_O7
102 102 #define R_O7 0xf
103 103 #endif
104 104 #endif /* __sparc */
105 105
106 106 static mdb_tgt_addr_t
107 107 write_uint8(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
108 108 {
109 109 uint8_t o, n = (uint8_t)ull;
110 110
111 111 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
112 112 addr) == -1)
113 113 return (addr);
114 114
115 115 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
116 116 return (addr);
117 117
118 118 if (rdback) {
119 119 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
120 120 return (addr);
121 121
122 122 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8x=%8T0x%x\n",
123 123 mdb_iob_getmargin(mdb.m_out), addr, o, n);
124 124 }
125 125
126 126 return (addr + sizeof (n));
127 127 }
128 128
129 129 static mdb_tgt_addr_t
130 130 write_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
131 131 {
132 132 uint16_t o, n = (uint16_t)ull;
133 133
134 134 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
135 135 addr) == -1)
136 136 return (addr);
137 137
138 138 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
139 139 return (addr);
140 140
141 141 if (rdback) {
142 142 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
143 143 return (addr);
144 144
145 145 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8hx=%8T0x%hx\n",
146 146 mdb_iob_getmargin(mdb.m_out), addr, o, n);
147 147 }
148 148
149 149 return (addr + sizeof (n));
150 150 }
151 151
152 152 static mdb_tgt_addr_t
153 153 write_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
154 154 {
155 155 uint32_t o, n = (uint32_t)ull;
156 156
157 157 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
158 158 addr) == -1)
159 159 return (addr);
160 160
161 161 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
162 162 return (addr);
163 163
164 164 if (rdback) {
165 165 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
166 166 return (addr);
167 167
168 168 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#16x=%8T0x%x\n",
169 169 mdb_iob_getmargin(mdb.m_out), addr, o, n);
170 170 }
171 171
172 172 return (addr + sizeof (n));
173 173 }
174 174
175 175 static mdb_tgt_addr_t
176 176 write_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback)
177 177 {
178 178 uint64_t o;
179 179
180 180 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
181 181 addr) == -1)
182 182 return (addr);
183 183
184 184 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
185 185 return (addr);
186 186
187 187 if (rdback) {
188 188 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
189 189 return (addr);
190 190
191 191 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#24llx=%8T0x%llx\n",
192 192 mdb_iob_getmargin(mdb.m_out), addr, o, n);
193 193 }
194 194
195 195 return (addr + sizeof (n));
196 196 }
197 197
198 198 static int
199 199 write_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr,
200 200 int argc, const mdb_arg_t *argv)
201 201 {
202 202 mdb_tgt_addr_t (*write_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
203 203 uint64_t, uint_t);
204 204 mdb_tgt_addr_t naddr;
205 205 uintmax_t value;
206 206 int rdback = mdb.m_flags & MDB_FL_READBACK;
207 207 size_t i;
208 208
209 209 if (argc == 1) {
210 210 mdb_warn("expected value to write following %c\n",
211 211 argv->a_un.a_char);
212 212 return (DCMD_ERR);
213 213 }
214 214
215 215 switch (argv->a_un.a_char) {
216 216 case 'v':
217 217 write_value = write_uint8;
218 218 break;
219 219 case 'w':
220 220 write_value = write_uint16;
221 221 break;
222 222 case 'W':
223 223 write_value = write_uint32;
224 224 break;
225 225 case 'Z':
226 226 write_value = write_uint64;
227 227 break;
228 228 }
229 229
230 230 for (argv++, i = 1; i < argc; i++, argv++) {
231 231 if (argv->a_type == MDB_TYPE_CHAR) {
232 232 mdb_warn("expected immediate value instead of '%c'\n",
233 233 argv->a_un.a_char);
234 234 return (DCMD_ERR);
235 235 }
236 236
237 237 if (argv->a_type == MDB_TYPE_STRING) {
238 238 if (mdb_eval(argv->a_un.a_str) == -1) {
239 239 mdb_warn("failed to write \"%s\"",
240 240 argv->a_un.a_str);
241 241 return (DCMD_ERR);
242 242 }
243 243 value = mdb_nv_get_value(mdb.m_dot);
244 244 } else
245 245 value = argv->a_un.a_val;
246 246
247 247 mdb_nv_set_value(mdb.m_dot, addr);
248 248
249 249 if ((naddr = write_value(as, addr, value, rdback)) == addr) {
250 250 mdb_warn("failed to write %llr at address 0x%llx",
251 251 value, addr);
252 252 mdb.m_incr = 0;
253 253 break;
254 254 }
255 255
256 256 mdb.m_incr = naddr - addr;
257 257 addr = naddr;
258 258 }
259 259
260 260 return (DCMD_OK);
261 261 }
262 262
263 263 static mdb_tgt_addr_t
264 264 match_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
265 265 {
266 266 uint16_t x, val = (uint16_t)v64, mask = (uint16_t)m64;
267 267
268 268 for (; mdb_tgt_aread(mdb.m_target, as, &x,
269 269 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
270 270
271 271 if ((x & mask) == val) {
272 272 mdb_iob_printf(mdb.m_out, "%lla\n", addr);
273 273 break;
274 274 }
275 275 }
276 276 return (addr);
277 277 }
278 278
279 279 static mdb_tgt_addr_t
280 280 match_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
281 281 {
282 282 uint32_t x, val = (uint32_t)v64, mask = (uint32_t)m64;
283 283
284 284 for (; mdb_tgt_aread(mdb.m_target, as, &x,
285 285 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
286 286
287 287 if ((x & mask) == val) {
288 288 mdb_iob_printf(mdb.m_out, "%lla\n", addr);
289 289 break;
290 290 }
291 291 }
292 292 return (addr);
293 293 }
294 294
295 295 static mdb_tgt_addr_t
296 296 match_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t val, uint64_t mask)
297 297 {
298 298 uint64_t x;
299 299
300 300 for (; mdb_tgt_aread(mdb.m_target, as, &x,
301 301 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
302 302
303 303 if ((x & mask) == val) {
304 304 mdb_iob_printf(mdb.m_out, "%lla\n", addr);
305 305 break;
306 306 }
307 307 }
308 308 return (addr);
309 309 }
310 310
311 311 static int
312 312 match_arglist(mdb_tgt_as_t as, uint_t flags, mdb_tgt_addr_t addr,
313 313 int argc, const mdb_arg_t *argv)
314 314 {
315 315 mdb_tgt_addr_t (*match_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
316 316 uint64_t, uint64_t);
317 317
318 318 uint64_t args[2] = { 0, -1ULL }; /* [ value, mask ] */
319 319 size_t i;
320 320
321 321 if (argc < 2) {
322 322 mdb_warn("expected value following %c\n", argv->a_un.a_char);
323 323 return (DCMD_ERR);
324 324 }
325 325
326 326 if (argc > 3) {
327 327 mdb_warn("only value and mask may follow %c\n",
328 328 argv->a_un.a_char);
329 329 return (DCMD_ERR);
330 330 }
331 331
332 332 switch (argv->a_un.a_char) {
333 333 case 'l':
334 334 match_value = match_uint16;
335 335 break;
336 336 case 'L':
337 337 match_value = match_uint32;
338 338 break;
339 339 case 'M':
340 340 match_value = match_uint64;
341 341 break;
342 342 }
343 343
344 344 for (argv++, i = 1; i < argc; i++, argv++) {
345 345 if (argv->a_type == MDB_TYPE_CHAR) {
346 346 mdb_warn("expected immediate value instead of '%c'\n",
347 347 argv->a_un.a_char);
348 348 return (DCMD_ERR);
349 349 }
350 350
351 351 if (argv->a_type == MDB_TYPE_STRING) {
352 352 if (mdb_eval(argv->a_un.a_str) == -1) {
353 353 mdb_warn("failed to evaluate \"%s\"",
354 354 argv->a_un.a_str);
355 355 return (DCMD_ERR);
356 356 }
357 357 args[i - 1] = mdb_nv_get_value(mdb.m_dot);
358 358 } else
359 359 args[i - 1] = argv->a_un.a_val;
360 360 }
361 361
362 362 addr = match_value(as, addr, args[0], args[1]);
363 363 mdb_nv_set_value(mdb.m_dot, addr);
364 364
365 365 /*
366 366 * In adb(1), the match operators ignore any repeat count that has
367 367 * been applied to them. We emulate this undocumented property
368 368 * by returning DCMD_ABORT if our input is not a pipeline.
369 369 */
370 370 return ((flags & DCMD_PIPE) ? DCMD_OK : DCMD_ABORT);
371 371 }
372 372
373 373 static int
374 374 argncmp(int argc, const mdb_arg_t *argv, const char *s)
375 375 {
376 376 for (; *s != '\0'; s++, argc--, argv++) {
377 377 if (argc == 0 || argv->a_type != MDB_TYPE_CHAR)
378 378 return (FALSE);
379 379 if (argv->a_un.a_char != *s)
380 380 return (FALSE);
381 381 }
382 382 return (TRUE);
383 383 }
384 384
385 385 static int
386 386 print_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint_t flags,
387 387 int argc, const mdb_arg_t *argv)
388 388 {
389 389 char buf[MDB_TGT_SYM_NAMLEN];
390 390 mdb_tgt_addr_t oaddr = addr;
391 391 mdb_tgt_addr_t naddr;
392 392 GElf_Sym sym;
393 393 size_t i, n;
394 394
395 395 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
396 396 const char *fmt;
397 397 int is_dis;
398 398 /*
399 399 * This is nasty, but necessary for precise adb compatibility.
400 400 * Detect disassembly format by looking for "ai" or "ia":
401 401 */
402 402 if (argncmp(argc, argv, "ai")) {
403 403 fmt = "%-#*lla\n";
404 404 is_dis = TRUE;
405 405 } else if (argncmp(argc, argv, "ia")) {
406 406 fmt = "%-#*lla";
407 407 is_dis = TRUE;
408 408 } else {
409 409 fmt = "%-#*lla%16T";
410 410 is_dis = FALSE;
411 411 }
412 412
413 413 /*
414 414 * If symbolic decoding is on, disassembly is off, and the
415 415 * address exactly matches a symbol, print the symbol name:
416 416 */
417 417 if ((mdb.m_flags & MDB_FL_PSYM) && !is_dis &&
418 418 (as == MDB_TGT_AS_VIRT || as == MDB_TGT_AS_FILE) &&
419 419 mdb_tgt_lookup_by_addr(mdb.m_target, (uintptr_t)addr,
420 420 MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0)
421 421 mdb_iob_printf(mdb.m_out, "%s:\n", buf);
422 422
423 423 /*
424 424 * If this is a virtual address, cast it so that it reflects
425 425 * only the valid component of the address.
426 426 */
427 427 if (as == MDB_TGT_AS_VIRT)
428 428 addr = (uintptr_t)addr;
429 429
430 430 mdb_iob_printf(mdb.m_out, fmt,
431 431 (uint_t)mdb_iob_getmargin(mdb.m_out), addr);
432 432 }
433 433
434 434 if (argc == 0) {
435 435 /*
436 436 * Yes, for you trivia buffs: if you use a format verb and give
437 437 * no format string, you get: X^"= "i ... note that in adb the
438 438 * the '=' verb once had 'z' as its default, but then 'z' was
439 439 * deleted (it was once an alias for 'i') and so =\n now calls
440 440 * scanform("z") and produces a 'bad modifier' message.
441 441 */
442 442 static const mdb_arg_t def_argv[] = {
443 443 { MDB_TYPE_CHAR, MDB_INIT_CHAR('X') },
444 444 { MDB_TYPE_CHAR, MDB_INIT_CHAR('^') },
445 445 { MDB_TYPE_STRING, MDB_INIT_STRING("= ") },
446 446 { MDB_TYPE_CHAR, MDB_INIT_CHAR('i') }
447 447 };
448 448
449 449 argc = sizeof (def_argv) / sizeof (mdb_arg_t);
450 450 argv = def_argv;
451 451 }
452 452
453 453 mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
454 454
455 455 for (i = 0, n = 1; i < argc; i++, argv++) {
456 456 switch (argv->a_type) {
457 457 case MDB_TYPE_CHAR:
458 458 naddr = mdb_fmt_print(mdb.m_target, as, addr, n,
459 459 argv->a_un.a_char);
460 460 mdb.m_incr = naddr - addr;
461 461 addr = naddr;
462 462 n = 1;
463 463 break;
464 464
465 465 case MDB_TYPE_IMMEDIATE:
466 466 n = argv->a_un.a_val;
467 467 break;
468 468
469 469 case MDB_TYPE_STRING:
470 470 mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
471 471 n = 1;
472 472 break;
473 473 }
474 474 }
475 475
476 476 mdb.m_incr = addr - oaddr;
477 477 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
478 478 return (DCMD_OK);
479 479 }
480 480
481 481 static int
482 482 print_common(mdb_tgt_as_t as, uint_t flags, int argc, const mdb_arg_t *argv)
483 483 {
484 484 mdb_tgt_addr_t addr = mdb_nv_get_value(mdb.m_dot);
485 485
486 486 if (argc != 0 && argv->a_type == MDB_TYPE_CHAR) {
487 487 if (strchr("vwWZ", argv->a_un.a_char))
488 488 return (write_arglist(as, addr, argc, argv));
489 489 if (strchr("lLM", argv->a_un.a_char))
490 490 return (match_arglist(as, flags, addr, argc, argv));
491 491 }
492 492
493 493 return (print_arglist(as, addr, flags, argc, argv));
494 494 }
495 495
496 496 /*ARGSUSED*/
497 497 static int
498 498 cmd_print_core(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
499 499 {
500 500 return (print_common(MDB_TGT_AS_VIRT, flags, argc, argv));
501 501 }
502 502
503 503 #ifndef _KMDB
504 504 /*ARGSUSED*/
505 505 static int
506 506 cmd_print_object(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
507 507 {
508 508 return (print_common(MDB_TGT_AS_FILE, flags, argc, argv));
509 509 }
510 510 #endif
511 511
512 512 /*ARGSUSED*/
513 513 static int
514 514 cmd_print_phys(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
515 515 {
516 516 return (print_common(MDB_TGT_AS_PHYS, flags, argc, argv));
517 517 }
518 518
519 519 /*ARGSUSED*/
520 520 static int
521 521 cmd_print_value(uintptr_t addr, uint_t flags,
522 522 int argc, const mdb_arg_t *argv)
523 523 {
524 524 uintmax_t ndot, dot = mdb_get_dot();
525 525 const char *tgt_argv[1];
526 526 mdb_tgt_t *t;
527 527 size_t i, n;
528 528
529 529 if (argc == 0) {
530 530 mdb_warn("expected one or more format characters "
531 531 "following '='\n");
532 532 return (DCMD_ERR);
533 533 }
534 534
535 535 tgt_argv[0] = (const char *)˙
536 536 t = mdb_tgt_create(mdb_value_tgt_create, 0, 1, tgt_argv);
537 537 mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
538 538
539 539 for (i = 0, n = 1; i < argc; i++, argv++) {
540 540 switch (argv->a_type) {
541 541 case MDB_TYPE_CHAR:
542 542 ndot = mdb_fmt_print(t, MDB_TGT_AS_VIRT,
543 543 dot, n, argv->a_un.a_char);
544 544 if (argv->a_un.a_char == '+' ||
545 545 argv->a_un.a_char == '-')
546 546 dot = ndot;
547 547 n = 1;
548 548 break;
549 549
550 550 case MDB_TYPE_IMMEDIATE:
551 551 n = argv->a_un.a_val;
552 552 break;
553 553
554 554 case MDB_TYPE_STRING:
555 555 mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
556 556 n = 1;
557 557 break;
558 558 }
559 559 }
560 560
561 561 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
562 562 mdb_nv_set_value(mdb.m_dot, dot);
563 563 mdb.m_incr = 0;
564 564
565 565 mdb_tgt_destroy(t);
566 566 return (DCMD_OK);
567 567 }
568 568
569 569 /*ARGSUSED*/
570 570 static int
571 571 cmd_assign_variable(uintptr_t addr, uint_t flags,
572 572 int argc, const mdb_arg_t *argv)
573 573 {
574 574 uintmax_t dot = mdb_nv_get_value(mdb.m_dot);
575 575 const char *p;
576 576 mdb_var_t *v;
577 577
578 578 if (argc == 2) {
579 579 if (argv->a_type != MDB_TYPE_CHAR) {
580 580 mdb_warn("improper arguments following '>' operator\n");
581 581 return (DCMD_ERR);
582 582 }
583 583
584 584 switch (argv->a_un.a_char) {
585 585 case 'c':
586 586 addr = *((uchar_t *)&addr);
587 587 break;
588 588 case 's':
589 589 addr = *((ushort_t *)&addr);
590 590 break;
591 591 case 'i':
592 592 addr = *((uint_t *)&addr);
593 593 break;
594 594 case 'l':
595 595 addr = *((ulong_t *)&addr);
596 596 break;
597 597 default:
598 598 mdb_warn("%c is not a valid // modifier\n",
599 599 argv->a_un.a_char);
600 600 return (DCMD_ERR);
601 601 }
602 602
603 603 dot = addr;
604 604 argv++;
605 605 argc--;
606 606 }
607 607
608 608 if (argc != 1 || argv->a_type != MDB_TYPE_STRING) {
609 609 mdb_warn("expected single variable name following '>'\n");
610 610 return (DCMD_ERR);
611 611 }
612 612
613 613 if (strlen(argv->a_un.a_str) >= (size_t)MDB_NV_NAMELEN) {
614 614 mdb_warn("variable names may not exceed %d characters\n",
615 615 MDB_NV_NAMELEN - 1);
616 616 return (DCMD_ERR);
617 617 }
618 618
619 619 if ((p = strbadid(argv->a_un.a_str)) != NULL) {
620 620 mdb_warn("'%c' may not be used in a variable name\n", *p);
621 621 return (DCMD_ERR);
622 622 }
623 623
624 624 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
625 625 (void) mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str, NULL, dot, 0);
626 626 else
627 627 mdb_nv_set_value(v, dot);
628 628
629 629 mdb.m_incr = 0;
630 630 return (DCMD_OK);
631 631 }
632 632
633 633 static int
634 634 print_soutype(const char *sou, uintptr_t addr, uint_t flags)
635 635 {
636 636 static const char *prefixes[] = { "struct ", "union " };
637 637 size_t namesz = 7 + strlen(sou) + 1;
638 638 char *name = mdb_alloc(namesz, UM_SLEEP | UM_GC);
639 639 mdb_ctf_id_t id;
640 640 int i;
641 641
642 642 for (i = 0; i < 2; i++) {
643 643 (void) mdb_snprintf(name, namesz, "%s%s", prefixes[i], sou);
644 644
645 645 if (mdb_ctf_lookup_by_name(name, &id) == 0) {
646 646 mdb_arg_t v;
647 647 int rv;
648 648
649 649 v.a_type = MDB_TYPE_STRING;
650 650 v.a_un.a_str = name;
651 651
652 652 rv = mdb_call_dcmd("print", addr, flags, 1, &v);
653 653 return (rv);
654 654 }
655 655 }
656 656
657 657 return (DCMD_ERR);
658 658 }
659 659
660 660 static int
661 661 print_type(const char *name, uintptr_t addr, uint_t flags)
662 662 {
663 663 mdb_ctf_id_t id;
664 664 char *sname;
665 665 size_t snamesz;
666 666 int rv;
667 667
668 668 if (!(flags & DCMD_ADDRSPEC)) {
669 669 addr = mdb_get_dot();
670 670 flags |= DCMD_ADDRSPEC;
671 671 }
672 672
673 673 if ((rv = print_soutype(name, addr, flags)) != DCMD_ERR)
674 674 return (rv);
675 675
676 676 snamesz = strlen(name) + 3;
677 677 sname = mdb_zalloc(snamesz, UM_SLEEP | UM_GC);
678 678 (void) mdb_snprintf(sname, snamesz, "%s_t", name);
679 679
680 680 if (mdb_ctf_lookup_by_name(sname, &id) == 0) {
681 681 mdb_arg_t v;
682 682 int rv;
683 683
684 684 v.a_type = MDB_TYPE_STRING;
685 685 v.a_un.a_str = sname;
686 686
687 687 rv = mdb_call_dcmd("print", addr, flags, 1, &v);
688 688 return (rv);
689 689 }
690 690
691 691 sname[snamesz - 2] = 's';
692 692 rv = print_soutype(sname, addr, flags);
693 693 return (rv);
694 694 }
695 695
696 696 static int
697 697 exec_alias(const char *fname, uintptr_t addr, uint_t flags)
698 698 {
699 699 const char *alias;
700 700 int rv;
701 701
702 702 if ((alias = mdb_macalias_lookup(fname)) == NULL)
703 703 return (DCMD_ERR);
704 704
705 705 if (flags & DCMD_ADDRSPEC) {
706 706 size_t sz = sizeof (uintptr_t) * 2 + strlen(alias) + 1;
707 707 char *addralias = mdb_alloc(sz, UM_SLEEP | UM_GC);
708 708 (void) mdb_snprintf(addralias, sz, "%p%s", addr, alias);
709 709 rv = mdb_eval(addralias);
710 710 } else {
711 711 rv = mdb_eval(alias);
712 712 }
713 713
714 714 return (rv == -1 ? DCMD_ABORT : DCMD_OK);
715 715 }
716 716
717 717 /*ARGSUSED*/
718 718 static int
719 719 cmd_src_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
720 720 {
721 721 const char *fname;
722 722 mdb_io_t *fio;
723 723 int rv;
724 724
725 725 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
726 726 return (DCMD_USAGE);
727 727
728 728 fname = argv->a_un.a_str;
729 729
730 730 if (flags & DCMD_PIPE_OUT) {
731 731 mdb_warn("macro files cannot be used as input to a pipeline\n");
732 732 return (DCMD_ABORT);
733 733 }
734 734
735 735 if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
736 736 O_RDONLY, 0)) != NULL) {
737 737 mdb_frame_t *fp = mdb.m_frame;
738 738 int err;
739 739
740 740 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
741 741 mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
742 742 err = mdb_run();
743 743
744 744 ASSERT(fp == mdb.m_frame);
745 745 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
746 746 yylineno = mdb_iob_lineno(mdb.m_in);
747 747
748 748 if (err == MDB_ERR_PAGER && mdb.m_fmark != fp)
749 749 longjmp(fp->f_pcb, err);
750 750
751 751 if (err == MDB_ERR_QUIT || err == MDB_ERR_ABORT ||
752 752 err == MDB_ERR_SIGINT || err == MDB_ERR_OUTPUT)
753 753 longjmp(fp->f_pcb, err);
754 754
755 755 return (DCMD_OK);
756 756 }
757 757
758 758 if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
759 759 (rv = print_type(fname, addr, flags)) != DCMD_ERR)
760 760 return (rv);
761 761
762 762 mdb_warn("failed to open %s (see ::help '$<')\n", fname);
763 763 return (DCMD_ABORT);
764 764 }
765 765
766 766 static int
767 767 cmd_exec_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
768 768 {
769 769 const char *fname;
770 770 mdb_io_t *fio;
771 771 int rv;
772 772
773 773 /*
774 774 * The syntax [expr[,count]]$< with no trailing macro file name is
775 775 * magic in that if count is zero, this command won't be called and
776 776 * the expression is thus a no-op. If count is non-zero, we get
777 777 * invoked with argc == 0, and this means abort the current macro.
778 778 * If our debugger stack depth is greater than one, we may be using
779 779 * $< from within a previous $<<, so in that case we set m_in to
780 780 * NULL to force this entire frame to be popped.
781 781 */
782 782 if (argc == 0) {
783 783 if (mdb_iob_stack_size(&mdb.m_frame->f_istk) != 0) {
784 784 mdb_iob_destroy(mdb.m_in);
785 785 mdb.m_in = mdb_iob_stack_pop(&mdb.m_frame->f_istk);
786 786 } else if (mdb.m_depth > 1) {
787 787 mdb_iob_destroy(mdb.m_in);
788 788 mdb.m_in = NULL;
789 789 } else
790 790 mdb_warn("input stack is empty\n");
791 791 return (DCMD_OK);
792 792 }
793 793
794 794 if ((flags & (DCMD_PIPE | DCMD_PIPE_OUT)) || mdb.m_depth == 1)
795 795 return (cmd_src_file(addr, flags, argc, argv));
796 796
797 797 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
798 798 return (DCMD_USAGE);
799 799
800 800 fname = argv->a_un.a_str;
801 801
802 802 if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
803 803 O_RDONLY, 0)) != NULL) {
804 804 mdb_iob_destroy(mdb.m_in);
805 805 mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
806 806 return (DCMD_OK);
807 807 }
808 808
809 809 if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
810 810 (rv = print_type(fname, addr, flags)) != DCMD_ERR)
811 811 return (rv);
812 812
813 813 mdb_warn("failed to open %s (see ::help '$<')\n", fname);
814 814 return (DCMD_ABORT);
815 815 }
816 816
817 817 #ifndef _KMDB
818 818 /*ARGSUSED*/
819 819 static int
820 820 cmd_cat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
821 821 {
822 822 int status = DCMD_OK;
823 823 char buf[BUFSIZ];
824 824 mdb_iob_t *iob;
825 825 mdb_io_t *fio;
826 826
827 827 if (flags & DCMD_ADDRSPEC)
828 828 return (DCMD_USAGE);
829 829
830 830 for (; argc-- != 0; argv++) {
831 831 if (argv->a_type != MDB_TYPE_STRING) {
832 832 mdb_warn("expected string argument\n");
833 833 status = DCMD_ERR;
834 834 continue;
835 835 }
836 836
837 837 if ((fio = mdb_fdio_create_path(NULL,
838 838 argv->a_un.a_str, O_RDONLY, 0)) == NULL) {
839 839 mdb_warn("failed to open %s", argv->a_un.a_str);
840 840 status = DCMD_ERR;
841 841 continue;
842 842 }
843 843
844 844 iob = mdb_iob_create(fio, MDB_IOB_RDONLY);
845 845
846 846 while (!(mdb_iob_getflags(iob) & (MDB_IOB_EOF | MDB_IOB_ERR))) {
847 847 ssize_t len = mdb_iob_read(iob, buf, sizeof (buf));
848 848 if (len > 0) {
849 849 if (mdb_iob_write(mdb.m_out, buf, len) < 0) {
850 850 if (errno != EPIPE)
851 851 mdb_warn("write failed");
852 852 status = DCMD_ERR;
853 853 break;
854 854 }
855 855 }
856 856 }
857 857
858 858 if (mdb_iob_err(iob))
859 859 mdb_warn("error while reading %s", mdb_iob_name(iob));
860 860
861 861 mdb_iob_destroy(iob);
862 862 }
863 863
864 864 return (status);
865 865 }
866 866 #endif
867 867
868 868 /*ARGSUSED*/
869 869 static int
870 870 cmd_grep(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
871 871 {
872 872 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
873 873 return (DCMD_USAGE);
874 874
875 875 if (mdb_eval(argv->a_un.a_str) == -1)
876 876 return (DCMD_ABORT);
877 877
878 878 if (mdb_get_dot() != 0)
879 879 mdb_printf("%lr\n", addr);
880 880
881 881 return (DCMD_OK);
882 882 }
883 883
884 884 /*ARGSUSED*/
885 885 static int
886 886 cmd_map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
887 887 {
888 888 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
889 889 return (DCMD_USAGE);
890 890
891 891 if (mdb_eval(argv->a_un.a_str) == -1)
892 892 return (DCMD_ABORT);
893 893
894 894 mdb_printf("%llr\n", mdb_get_dot());
895 895 return (DCMD_OK);
896 896 }
897 897
898 898 /*ARGSUSED*/
899 899 static int
900 900 cmd_notsup(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
901 901 {
902 902 mdb_warn("command is not supported by current target\n");
903 903 return (DCMD_ERR);
904 904 }
905 905
906 906 /*ARGSUSED*/
907 907 static int
908 908 cmd_quit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
909 909 {
910 910 #ifdef _KMDB
911 911 uint_t opt_u = FALSE;
912 912
913 913 if (mdb_getopts(argc, argv,
914 914 'u', MDB_OPT_SETBITS, TRUE, &opt_u, NULL) != argc)
915 915 return (DCMD_USAGE);
916 916
917 917 if (opt_u) {
918 918 if (mdb.m_flags & MDB_FL_NOUNLOAD) {
919 919 warn("%s\n", mdb_strerror(EMDB_KNOUNLOAD));
920 920 return (DCMD_ERR);
921 921 }
922 922
923 923 kmdb_kdi_set_unload_request();
924 924 }
925 925 #endif
926 926
927 927 longjmp(mdb.m_frame->f_pcb, MDB_ERR_QUIT);
928 928 /*NOTREACHED*/
929 929 return (DCMD_ERR);
930 930 }
931 931
932 932 #ifdef _KMDB
933 933 static void
934 934 quit_help(void)
935 935 {
936 936 mdb_printf(
937 937 "-u unload the debugger (if not loaded at boot)\n");
938 938 }
939 939 #endif
940 940
941 941 /*ARGSUSED*/
942 942 static int
943 943 cmd_vars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
944 944 {
945 945 uint_t opt_nz = FALSE, opt_tag = FALSE, opt_prt = FALSE;
946 946 mdb_var_t *v;
947 947
948 948 if (mdb_getopts(argc, argv,
949 949 'n', MDB_OPT_SETBITS, TRUE, &opt_nz,
950 950 'p', MDB_OPT_SETBITS, TRUE, &opt_prt,
951 951 't', MDB_OPT_SETBITS, TRUE, &opt_tag, NULL) != argc)
952 952 return (DCMD_USAGE);
953 953
954 954 mdb_nv_rewind(&mdb.m_nv);
955 955
956 956 while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
957 957 if ((opt_tag == FALSE || (v->v_flags & MDB_NV_TAGGED)) &&
958 958 (opt_nz == FALSE || mdb_nv_get_value(v) != 0)) {
959 959 if (opt_prt) {
960 960 mdb_printf("%#llr>%s\n",
961 961 mdb_nv_get_value(v), mdb_nv_get_name(v));
962 962 } else {
963 963 mdb_printf("%s = %llr\n",
964 964 mdb_nv_get_name(v), mdb_nv_get_value(v));
965 965 }
966 966 }
967 967 }
968 968
969 969 return (DCMD_OK);
970 970 }
971 971
972 972 /*ARGSUSED*/
973 973 static int
974 974 cmd_nzvars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
975 975 {
976 976 uintmax_t value;
977 977 mdb_var_t *v;
978 978
979 979 if (argc != 0)
980 980 return (DCMD_USAGE);
981 981
982 982 mdb_nv_rewind(&mdb.m_nv);
983 983
984 984 while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
985 985 if ((value = mdb_nv_get_value(v)) != 0)
986 986 mdb_printf("%s = %llr\n", mdb_nv_get_name(v), value);
987 987 }
988 988
989 989 return (DCMD_OK);
990 990 }
991 991
992 992 /*ARGSUSED*/
993 993 static int
994 994 cmd_radix(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
995 995 {
996 996 if (argc != 0)
997 997 return (DCMD_USAGE);
998 998
999 999 if (flags & DCMD_ADDRSPEC) {
1000 1000 if (addr < 2 || addr > 16) {
1001 1001 mdb_warn("expected radix from 2 to 16\n");
1002 1002 return (DCMD_ERR);
1003 1003 }
1004 1004 mdb.m_radix = (int)addr;
1005 1005 }
1006 1006
1007 1007 mdb_iob_printf(mdb.m_out, "radix = %d base ten\n", mdb.m_radix);
1008 1008 return (DCMD_OK);
1009 1009 }
1010 1010
1011 1011 /*ARGSUSED*/
1012 1012 static int
1013 1013 cmd_symdist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1014 1014 {
1015 1015 if (argc != 0)
1016 1016 return (DCMD_USAGE);
1017 1017
1018 1018 if (flags & DCMD_ADDRSPEC)
1019 1019 mdb.m_symdist = addr;
1020 1020
1021 1021 mdb_printf("symbol matching distance = %lr (%s)\n",
1022 1022 mdb.m_symdist, mdb.m_symdist ? "absolute mode" : "smart mode");
1023 1023
1024 1024 return (DCMD_OK);
1025 1025 }
1026 1026
1027 1027 /*ARGSUSED*/
1028 1028 static int
1029 1029 cmd_pgwidth(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1030 1030 {
1031 1031 if (argc != 0)
1032 1032 return (DCMD_USAGE);
1033 1033
1034 1034 if (flags & DCMD_ADDRSPEC)
1035 1035 mdb_iob_resize(mdb.m_out, mdb.m_out->iob_rows, addr);
1036 1036
1037 1037 mdb_printf("output page width = %lu\n", mdb.m_out->iob_cols);
1038 1038 return (DCMD_OK);
1039 1039 }
1040 1040
1041 1041 /*ARGSUSED*/
1042 1042 static int
1043 1043 cmd_reopen(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1044 1044 {
1045 1045 if (argc != 0)
1046 1046 return (DCMD_USAGE);
1047 1047
1048 1048 if (mdb_tgt_setflags(mdb.m_target, MDB_TGT_F_RDWR) == -1) {
1049 1049 mdb_warn("failed to re-open target for writing");
1050 1050 return (DCMD_ERR);
1051 1051 }
1052 1052
1053 1053 return (DCMD_OK);
1054 1054 }
1055 1055
1056 1056 /*ARGSUSED*/
1057 1057 static int
1058 1058 print_xdata(void *ignored, const char *name, const char *desc, size_t nbytes)
1059 1059 {
1060 1060 mdb_printf("%-24s - %s (%lu bytes)\n", name, desc, (ulong_t)nbytes);
1061 1061 return (0);
1062 1062 }
1063 1063
1064 1064 /*ARGSUSED*/
1065 1065 static int
1066 1066 cmd_xdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1067 1067 {
1068 1068 if (argc != 0 || (flags & DCMD_ADDRSPEC))
1069 1069 return (DCMD_USAGE);
1070 1070
1071 1071 (void) mdb_tgt_xdata_iter(mdb.m_target, print_xdata, NULL);
1072 1072 return (DCMD_OK);
1073 1073 }
1074 1074
1075 1075 /*ARGSUSED*/
1076 1076 static int
1077 1077 cmd_unset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1078 1078 {
1079 1079 mdb_var_t *v;
1080 1080 size_t i;
1081 1081
1082 1082 for (i = 0; i < argc; i++) {
1083 1083 if (argv[i].a_type != MDB_TYPE_STRING) {
1084 1084 mdb_warn("bad option: arg %lu is not a string\n",
1085 1085 (ulong_t)i + 1);
1086 1086 return (DCMD_USAGE);
1087 1087 }
1088 1088 }
1089 1089
1090 1090 for (i = 0; i < argc; i++, argv++) {
1091 1091 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
1092 1092 mdb_warn("variable '%s' not defined\n",
1093 1093 argv->a_un.a_str);
1094 1094 else
1095 1095 mdb_nv_remove(&mdb.m_nv, v);
1096 1096 }
1097 1097
1098 1098 return (DCMD_OK);
1099 1099 }
1100 1100
1101 1101 #ifndef _KMDB
1102 1102 /*ARGSUSED*/
1103 1103 static int
1104 1104 cmd_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1105 1105 {
1106 1106 uint_t opt_e = FALSE, opt_d = FALSE;
1107 1107 const char *filename = NULL;
1108 1108 int i;
1109 1109
1110 1110 i = mdb_getopts(argc, argv,
1111 1111 'd', MDB_OPT_SETBITS, TRUE, &opt_d,
1112 1112 'e', MDB_OPT_SETBITS, TRUE, &opt_e, NULL);
1113 1113
1114 1114 if ((i != argc && i != argc - 1) || (opt_d && opt_e) ||
1115 1115 (i != argc && argv[i].a_type != MDB_TYPE_STRING) ||
1116 1116 (i != argc && opt_d == TRUE) || (flags & DCMD_ADDRSPEC))
1117 1117 return (DCMD_USAGE);
1118 1118
1119 1119 if (mdb.m_depth != 1) {
1120 1120 mdb_warn("log may not be manipulated in this context\n");
1121 1121 return (DCMD_ABORT);
1122 1122 }
1123 1123
1124 1124 if (i != argc)
1125 1125 filename = argv[i].a_un.a_str;
1126 1126
1127 1127 /*
1128 1128 * If no arguments were specified, print the log file name (if any)
1129 1129 * and report whether the log is enabled or disabled.
1130 1130 */
1131 1131 if (argc == 0) {
1132 1132 if (mdb.m_log) {
1133 1133 mdb_printf("%s: logging to \"%s\" is currently %s\n",
1134 1134 mdb.m_pname, IOP_NAME(mdb.m_log),
1135 1135 mdb.m_flags & MDB_FL_LOG ? "enabled" : "disabled");
1136 1136 } else
1137 1137 mdb_printf("%s: no log is active\n", mdb.m_pname);
1138 1138 return (DCMD_OK);
1139 1139 }
1140 1140
1141 1141 /*
1142 1142 * If the -d option was specified, pop the log i/o object off the
1143 1143 * i/o stack of stdin, stdout, and stderr.
1144 1144 */
1145 1145 if (opt_d) {
1146 1146 if (mdb.m_flags & MDB_FL_LOG) {
1147 1147 (void) mdb_iob_pop_io(mdb.m_in);
1148 1148 (void) mdb_iob_pop_io(mdb.m_out);
1149 1149 (void) mdb_iob_pop_io(mdb.m_err);
1150 1150 mdb.m_flags &= ~MDB_FL_LOG;
1151 1151 } else
1152 1152 mdb_warn("logging is already disabled\n");
1153 1153 return (DCMD_OK);
1154 1154 }
1155 1155
1156 1156 /*
1157 1157 * The -e option is the default: (re-)enable logging by pushing
1158 1158 * the log i/o object on to stdin, stdout, and stderr. If we have
1159 1159 * a previous log file, we need to pop it and close it. If we have
1160 1160 * no new log file, push the previous one back on.
1161 1161 */
1162 1162 if (filename != NULL) {
1163 1163 if (mdb.m_log != NULL) {
1164 1164 if (mdb.m_flags & MDB_FL_LOG) {
1165 1165 (void) mdb_iob_pop_io(mdb.m_in);
1166 1166 (void) mdb_iob_pop_io(mdb.m_out);
1167 1167 (void) mdb_iob_pop_io(mdb.m_err);
1168 1168 mdb.m_flags &= ~MDB_FL_LOG;
1169 1169 }
1170 1170 mdb_io_rele(mdb.m_log);
1171 1171 }
1172 1172
1173 1173 mdb.m_log = mdb_fdio_create_path(NULL, filename,
1174 1174 O_CREAT | O_APPEND | O_WRONLY, 0666);
1175 1175
1176 1176 if (mdb.m_log == NULL) {
1177 1177 mdb_warn("failed to open %s", filename);
1178 1178 return (DCMD_ERR);
1179 1179 }
1180 1180 }
1181 1181
1182 1182 if (mdb.m_log != NULL) {
1183 1183 mdb_iob_push_io(mdb.m_in, mdb_logio_create(mdb.m_log));
1184 1184 mdb_iob_push_io(mdb.m_out, mdb_logio_create(mdb.m_log));
1185 1185 mdb_iob_push_io(mdb.m_err, mdb_logio_create(mdb.m_log));
1186 1186
1187 1187 mdb_printf("%s: logging to \"%s\"\n", mdb.m_pname, filename);
1188 1188 mdb.m_log = mdb_io_hold(mdb.m_log);
1189 1189 mdb.m_flags |= MDB_FL_LOG;
1190 1190
1191 1191 return (DCMD_OK);
1192 1192 }
1193 1193
1194 1194 mdb_warn("no log file has been selected\n");
1195 1195 return (DCMD_ERR);
1196 1196 }
1197 1197
1198 1198 static int
1199 1199 cmd_old_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1200 1200 {
1201 1201 if (argc == 0) {
1202 1202 mdb_arg_t arg = { MDB_TYPE_STRING, MDB_INIT_STRING("-d") };
1203 1203 return (cmd_log(addr, flags, 1, &arg));
1204 1204 }
1205 1205
1206 1206 return (cmd_log(addr, flags, argc, argv));
1207 1207 }
1208 1208 #endif
1209 1209
1210 1210 /*ARGSUSED*/
1211 1211 static int
1212 1212 cmd_load(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1213 1213 {
1214 1214 int i, mode = MDB_MOD_LOCAL;
1215 1215
1216 1216 i = mdb_getopts(argc, argv,
1217 1217 #ifdef _KMDB
1218 1218 'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1219 1219 #endif
1220 1220 'f', MDB_OPT_SETBITS, MDB_MOD_FORCE, &mode,
1221 1221 'g', MDB_OPT_SETBITS, MDB_MOD_GLOBAL, &mode,
1222 1222 's', MDB_OPT_SETBITS, MDB_MOD_SILENT, &mode,
1223 1223 NULL);
1224 1224
1225 1225 argc -= i;
1226 1226 argv += i;
1227 1227
1228 1228 if ((flags & DCMD_ADDRSPEC) || argc != 1 ||
1229 1229 argv->a_type != MDB_TYPE_STRING ||
1230 1230 strchr("+-", argv->a_un.a_str[0]) != NULL)
1231 1231 return (DCMD_USAGE);
1232 1232
1233 1233 if (mdb_module_load(argv->a_un.a_str, mode) < 0)
1234 1234 return (DCMD_ERR);
1235 1235
1236 1236 return (DCMD_OK);
1237 1237 }
1238 1238
1239 1239 static void
1240 1240 load_help(void)
1241 1241 {
1242 1242 mdb_printf(
1243 1243 #ifdef _KMDB
1244 1244 "-d defer load until next continue\n"
1245 1245 #endif
1246 1246 "-s load module silently\n");
1247 1247 }
1248 1248
1249 1249 /*ARGSUSED*/
1250 1250 static int
1251 1251 cmd_unload(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1252 1252 {
1253 1253 int mode = 0;
1254 1254 int i;
1255 1255
1256 1256 i = mdb_getopts(argc, argv,
1257 1257 #ifdef _KMDB
1258 1258 'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1259 1259 #endif
1260 1260 NULL);
1261 1261
1262 1262 argc -= i;
1263 1263 argv += i;
1264 1264
1265 1265 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1266 1266 return (DCMD_USAGE);
1267 1267
1268 1268 if (mdb_module_unload(argv->a_un.a_str, mode) == -1) {
1269 1269 mdb_warn("failed to unload %s", argv->a_un.a_str);
1270 1270 return (DCMD_ERR);
1271 1271 }
1272 1272
1273 1273 return (DCMD_OK);
1274 1274 }
1275 1275
1276 1276 #ifdef _KMDB
1277 1277 static void
1278 1278 unload_help(void)
1279 1279 {
1280 1280 mdb_printf(
1281 1281 "-d defer unload until next continue\n");
1282 1282 }
1283 1283 #endif
1284 1284
1285 1285 static int
1286 1286 cmd_dbmode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1287 1287 {
1288 1288 if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1289 1289 return (DCMD_USAGE);
1290 1290
1291 1291 if (argc != 0) {
1292 1292 if (argv->a_type != MDB_TYPE_STRING)
1293 1293 return (DCMD_USAGE);
1294 1294 if ((addr = mdb_dstr2mode(argv->a_un.a_str)) != MDB_DBG_HELP)
1295 1295 mdb_dmode(addr);
1296 1296 } else if (flags & DCMD_ADDRSPEC)
1297 1297 mdb_dmode(addr);
1298 1298
1299 1299 mdb_printf("debugging mode = 0x%04x\n", mdb.m_debug);
1300 1300 return (DCMD_OK);
1301 1301 }
1302 1302
1303 1303 /*ARGSUSED*/
1304 1304 static int
1305 1305 cmd_version(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1306 1306 {
1307 1307 #ifdef DEBUG
1308 1308 mdb_printf("\r%s (DEBUG)\n", mdb_conf_version());
1309 1309 #else
1310 1310 mdb_printf("\r%s\n", mdb_conf_version());
1311 1311 #endif
1312 1312 return (DCMD_OK);
1313 1313 }
1314 1314
1315 1315 /*ARGSUSED*/
1316 1316 static int
1317 1317 cmd_algol(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1318 1318 {
1319 1319 if (mdb.m_flags & MDB_FL_ADB)
1320 1320 mdb_printf("No algol 68 here\n");
1321 1321 else
1322 1322 mdb_printf("No adb here\n");
1323 1323 return (DCMD_OK);
1324 1324 }
1325 1325
1326 1326 /*ARGSUSED*/
1327 1327 static int
1328 1328 cmd_obey(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1329 1329 {
1330 1330 if (mdb.m_flags & MDB_FL_ADB)
1331 1331 mdb_printf("CHAPTER 1\n");
1332 1332 else
1333 1333 mdb_printf("No Language H here\n");
1334 1334 return (DCMD_OK);
1335 1335 }
1336 1336
1337 1337 /*ARGSUSED*/
1338 1338 static int
1339 1339 print_global(void *data, const GElf_Sym *sym, const char *name,
1340 1340 const mdb_syminfo_t *sip, const char *obj)
1341 1341 {
1342 1342 uintptr_t value;
1343 1343
1344 1344 if (mdb_tgt_vread((mdb_tgt_t *)data, &value, sizeof (value),
1345 1345 (uintptr_t)sym->st_value) == sizeof (value))
1346 1346 mdb_printf("%s(%llr):\t%lr\n", name, sym->st_value, value);
1347 1347 else
1348 1348 mdb_printf("%s(%llr):\t?\n", name, sym->st_value);
1349 1349
1350 1350 return (0);
1351 1351 }
1352 1352
1353 1353 /*ARGSUSED*/
1354 1354 static int
1355 1355 cmd_globals(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1356 1356 {
1357 1357 if (argc != 0)
1358 1358 return (DCMD_USAGE);
1359 1359
1360 1360 (void) mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
1361 1361 MDB_TGT_SYMTAB, MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_OBJECT |
1362 1362 MDB_TGT_TYPE_FUNC, print_global, mdb.m_target);
1363 1363
1364 1364 return (0);
1365 1365 }
1366 1366
1367 1367 /*ARGSUSED*/
1368 1368 static int
1369 1369 cmd_eval(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1370 1370 {
1371 1371 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1372 1372 return (DCMD_USAGE);
1373 1373
1374 1374 if (mdb_eval(argv->a_un.a_str) == -1)
1375 1375 return (DCMD_ABORT);
1376 1376
1377 1377 return (DCMD_OK);
1378 1378 }
1379 1379
1380 1380 /*ARGSUSED*/
1381 1381 static int
1382 1382 print_file(void *data, const GElf_Sym *sym, const char *name,
1383 1383 const mdb_syminfo_t *sip, const char *obj)
1384 1384 {
1385 1385 int i = *((int *)data);
1386 1386
1387 1387 mdb_printf("%d\t%s\n", i++, name);
1388 1388 *((int *)data) = i;
1389 1389 return (0);
1390 1390 }
1391 1391
1392 1392 /*ARGSUSED*/
1393 1393 static int
1394 1394 cmd_files(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1395 1395 {
1396 1396 int i = 1;
1397 1397 const char *obj = MDB_TGT_OBJ_EVERY;
1398 1398
1399 1399 if ((flags & DCMD_ADDRSPEC) || argc > 1)
1400 1400 return (DCMD_USAGE);
1401 1401
1402 1402 if (argc == 1) {
1403 1403 if (argv->a_type != MDB_TYPE_STRING)
1404 1404 return (DCMD_USAGE);
1405 1405
1406 1406 obj = argv->a_un.a_str;
1407 1407 }
1408 1408
1409 1409 (void) mdb_tgt_symbol_iter(mdb.m_target, obj, MDB_TGT_SYMTAB,
1410 1410 MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FILE, print_file, &i);
1411 1411
1412 1412 return (DCMD_OK);
1413 1413 }
1414 1414
1415 1415 static const char *
1416 1416 map_name(const mdb_map_t *map, const char *name)
1417 1417 {
1418 1418 if (map->map_flags & MDB_TGT_MAP_HEAP)
1419 1419 return ("[ heap ]");
1420 1420 if (name != NULL && name[0] != 0)
1421 1421 return (name);
1422 1422
1423 1423 if (map->map_flags & MDB_TGT_MAP_SHMEM)
1424 1424 return ("[ shmem ]");
1425 1425 if (map->map_flags & MDB_TGT_MAP_STACK)
1426 1426 return ("[ stack ]");
1427 1427 if (map->map_flags & MDB_TGT_MAP_ANON)
1428 1428 return ("[ anon ]");
1429 1429 if (map->map_name != NULL)
1430 1430 return (map->map_name);
1431 1431 return ("[ unknown ]");
1432 1432 }
1433 1433
1434 1434 /*ARGSUSED*/
1435 1435 static int
1436 1436 print_map(void *ignored, const mdb_map_t *map, const char *name)
1437 1437 {
1438 1438 name = map_name(map, name);
1439 1439
1440 1440 mdb_printf("%?p %?p %?lx %s\n", map->map_base,
1441 1441 map->map_base + map->map_size, map->map_size, name);
1442 1442 return (0);
1443 1443 }
1444 1444
1445 1445 static int
1446 1446 cmd_mappings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1447 1447 {
1448 1448 const mdb_map_t *m;
1449 1449
1450 1450 if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1451 1451 return (DCMD_USAGE);
1452 1452
1453 1453 mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1454 1454 "BASE", "LIMIT", "SIZE", "NAME");
1455 1455
1456 1456 if (flags & DCMD_ADDRSPEC) {
1457 1457 if ((m = mdb_tgt_addr_to_map(mdb.m_target, addr)) == NULL)
1458 1458 mdb_warn("failed to obtain mapping");
1459 1459 else
1460 1460 (void) print_map(NULL, m, NULL);
1461 1461
1462 1462 } else if (argc != 0) {
1463 1463 if (argv->a_type == MDB_TYPE_STRING)
1464 1464 m = mdb_tgt_name_to_map(mdb.m_target, argv->a_un.a_str);
1465 1465 else
1466 1466 m = mdb_tgt_addr_to_map(mdb.m_target, argv->a_un.a_val);
1467 1467
1468 1468 if (m == NULL)
1469 1469 mdb_warn("failed to obtain mapping");
1470 1470 else
1471 1471 (void) print_map(NULL, m, NULL);
1472 1472
1473 1473 } else if (mdb_tgt_mapping_iter(mdb.m_target, print_map, NULL) == -1)
1474 1474 mdb_warn("failed to iterate over mappings");
1475 1475
1476 1476 return (DCMD_OK);
1477 1477 }
1478 1478
1479 1479 static int
1480 1480 whatis_map_callback(void *wp, const mdb_map_t *map, const char *name)
1481 1481 {
1482 1482 mdb_whatis_t *w = wp;
1483 1483 uintptr_t cur;
1484 1484
1485 1485 name = map_name(map, name);
1486 1486
1487 1487 while (mdb_whatis_match(w, map->map_base, map->map_size, &cur))
1488 1488 mdb_whatis_report_address(w, cur, "in %s [%p,%p)\n",
1489 1489 name, map->map_base, map->map_base + map->map_size);
1490 1490
1491 1491 return (0);
1492 1492 }
1493 1493
1494 1494 /*ARGSUSED*/
1495 1495 int
1496 1496 whatis_run_mappings(mdb_whatis_t *w, void *ignored)
1497 1497 {
1498 1498 (void) mdb_tgt_mapping_iter(mdb.m_target, whatis_map_callback, w);
1499 1499 return (0);
1500 1500 }
1501 1501
1502 1502 /*ARGSUSED*/
1503 1503 static int
1504 1504 objects_printversion(void *ignored, const mdb_map_t *map, const char *name)
1505 1505 {
1506 1506 ctf_file_t *ctfp;
1507 1507 const char *version;
1508 1508
1509 1509 ctfp = mdb_tgt_name_to_ctf(mdb.m_target, name);
1510 1510 if (ctfp == NULL || (version = ctf_label_topmost(ctfp)) == NULL)
1511 1511 version = "Unknown";
1512 1512
1513 1513 mdb_printf("%-28s %s\n", name, version);
1514 1514 return (0);
1515 1515 }
1516 1516
1517 1517 /*ARGSUSED*/
1518 1518 static int
1519 1519 cmd_objects(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1520 1520 {
1521 1521 uint_t opt_v = FALSE;
1522 1522 mdb_tgt_map_f *cb;
1523 1523
1524 1524 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1525 1525 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1526 1526 return (DCMD_USAGE);
1527 1527
1528 1528 if (opt_v) {
1529 1529 cb = objects_printversion;
1530 1530 mdb_printf("%<u>%-28s %s%</u>\n", "NAME", "VERSION");
1531 1531 } else {
1532 1532 cb = print_map;
1533 1533 mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1534 1534 "BASE", "LIMIT", "SIZE", "NAME");
1535 1535 }
1536 1536
1537 1537 if (mdb_tgt_object_iter(mdb.m_target, cb, NULL) == -1) {
1538 1538 mdb_warn("failed to iterate over objects");
1539 1539 return (DCMD_ERR);
1540 1540 }
1541 1541
1542 1542 return (DCMD_OK);
1543 1543 }
1544 1544
1545 1545 /*ARGSUSED*/
1546 1546 static int
1547 1547 showrev_addversion(void *vers_nv, const mdb_map_t *ignored, const char *object)
1548 1548 {
1549 1549 ctf_file_t *ctfp;
1550 1550 const char *version = NULL;
1551 1551 char *objname;
1552 1552
1553 1553 objname = mdb_alloc(strlen(object) + 1, UM_SLEEP | UM_GC);
1554 1554 (void) strcpy(objname, object);
1555 1555
1556 1556 if ((ctfp = mdb_tgt_name_to_ctf(mdb.m_target, objname)) != NULL)
1557 1557 version = ctf_label_topmost(ctfp);
1558 1558
1559 1559 /*
1560 1560 * Not all objects have CTF and label data, so set version to "Unknown".
1561 1561 */
1562 1562 if (version == NULL)
1563 1563 version = "Unknown";
1564 1564
1565 1565 /*
1566 1566 * The hash table implementation in OVERLOAD mode limits the version
1567 1567 * name to 31 characters because we cannot specify an external name.
1568 1568 * The full version name is available via the ::objects dcmd if needed.
1569 1569 */
1570 1570 (void) mdb_nv_insert(vers_nv, version, NULL, (uintptr_t)objname,
1571 1571 MDB_NV_OVERLOAD);
1572 1572
1573 1573 return (0);
1574 1574 }
1575 1575
1576 1576 static int
1577 1577 showrev_ispatch(const char *s)
1578 1578 {
1579 1579 if (s == NULL)
1580 1580 return (0);
1581 1581
1582 1582 if (*s == 'T')
1583 1583 s++; /* skip T for T-patch */
1584 1584
1585 1585 for (; *s != '\0'; s++) {
1586 1586 if ((*s < '0' || *s > '9') && *s != '-')
1587 1587 return (0);
1588 1588 }
1589 1589
1590 1590 return (1);
1591 1591 }
1592 1592
1593 1593 /*ARGSUSED*/
1594 1594 static int
1595 1595 showrev_printobject(mdb_var_t *v, void *ignored)
1596 1596 {
1597 1597 mdb_printf("%s ", MDB_NV_COOKIE(v));
1598 1598 return (0);
1599 1599 }
1600 1600
1601 1601 static int
1602 1602 showrev_printversion(mdb_var_t *v, void *showall)
1603 1603 {
1604 1604 const char *version = mdb_nv_get_name(v);
1605 1605 int patch;
1606 1606
1607 1607 patch = showrev_ispatch(version);
1608 1608 if (patch || (uintptr_t)showall) {
1609 1609 mdb_printf("%s: %s Objects: ",
1610 1610 (patch ? "Patch" : "Version"), version);
1611 1611 (void) mdb_inc_indent(2);
1612 1612
1613 1613 mdb_nv_defn_iter(v, showrev_printobject, NULL);
1614 1614
1615 1615 (void) mdb_dec_indent(2);
1616 1616 mdb_printf("\n");
1617 1617 }
1618 1618
1619 1619 return (0);
1620 1620 }
1621 1621
1622 1622 /*
1623 1623 * Display version information for each object in the system.
1624 1624 * Print information about patches only, unless showall is TRUE.
1625 1625 */
1626 1626 static int
1627 1627 showrev_objectversions(int showall)
1628 1628 {
1629 1629 mdb_nv_t vers_nv;
1630 1630
1631 1631 (void) mdb_nv_create(&vers_nv, UM_SLEEP | UM_GC);
1632 1632 if (mdb_tgt_object_iter(mdb.m_target, showrev_addversion,
1633 1633 &vers_nv) == -1) {
1634 1634 mdb_warn("failed to iterate over objects");
1635 1635 return (DCMD_ERR);
1636 1636 }
1637 1637
1638 1638 mdb_nv_sort_iter(&vers_nv, showrev_printversion,
1639 1639 (void *)(uintptr_t)showall, UM_SLEEP | UM_GC);
1640 1640 return (DCMD_OK);
1641 1641 }
1642 1642
1643 1643 /*
1644 1644 * Display information similar to what showrev(1M) displays when invoked
1645 1645 * with no arguments.
1646 1646 */
1647 1647 static int
1648 1648 showrev_sysinfo(void)
1649 1649 {
1650 1650 const char *s;
1651 1651 int rc;
1652 1652 struct utsname u;
1653 1653
1654 1654 if ((rc = mdb_tgt_uname(mdb.m_target, &u)) != -1) {
1655 1655 mdb_printf("Hostname: %s\n", u.nodename);
1656 1656 mdb_printf("Release: %s\n", u.release);
1657 1657 mdb_printf("Kernel architecture: %s\n", u.machine);
1658 1658 }
1659 1659
1660 1660 /*
1661 1661 * Match the order of the showrev(1M) output and put "Application
1662 1662 * architecture" before "Kernel version"
1663 1663 */
1664 1664 if ((s = mdb_tgt_isa(mdb.m_target)) != NULL)
1665 1665 mdb_printf("Application architecture: %s\n", s);
1666 1666
1667 1667 if (rc != -1)
1668 1668 mdb_printf("Kernel version: %s %s %s %s\n",
1669 1669 u.sysname, u.release, u.machine, u.version);
1670 1670
1671 1671 if ((s = mdb_tgt_platform(mdb.m_target)) != NULL)
1672 1672 mdb_printf("Platform: %s\n", s);
1673 1673
1674 1674 return (DCMD_OK);
1675 1675 }
1676 1676
1677 1677 /*ARGSUSED*/
1678 1678 static int
1679 1679 cmd_showrev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1680 1680 {
1681 1681 uint_t opt_p = FALSE, opt_v = FALSE;
1682 1682
1683 1683 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1684 1684 'p', MDB_OPT_SETBITS, TRUE, &opt_p,
1685 1685 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1686 1686 return (DCMD_USAGE);
1687 1687
1688 1688 if (opt_p || opt_v)
1689 1689 return (showrev_objectversions(opt_v));
1690 1690 else
1691 1691 return (showrev_sysinfo());
1692 1692 }
1693 1693
1694 1694 #ifdef __sparc
1695 1695 static void
1696 1696 findsym_output(uintptr_t *symlist, uintptr_t value, uintptr_t location)
1697 1697 {
1698 1698 uintptr_t *symbolp;
1699 1699
1700 1700 for (symbolp = symlist; *symbolp; symbolp++)
1701 1701 if (value == *symbolp)
1702 1702 mdb_printf("found %a at %a\n", value, location);
1703 1703 }
1704 1704
1705 1705 /*ARGSUSED*/
1706 1706 static int
1707 1707 findsym_cb(void *data, const GElf_Sym *sym, const char *name,
1708 1708 const mdb_syminfo_t *sip, const char *obj)
1709 1709 {
1710 1710 uint32_t *text;
1711 1711 int len;
1712 1712 int i;
1713 1713 int j;
1714 1714 uint8_t rd;
1715 1715 uintptr_t value;
1716 1716 int32_t imm13;
1717 1717 uint8_t op;
1718 1718 uint8_t op3;
1719 1719 uintptr_t *symlist = data;
1720 1720 size_t size = sym->st_size;
1721 1721
1722 1722 /*
1723 1723 * if the size of the symbol is 0, then this symbol must be for an
1724 1724 * alternate entry point or just some global label. We will,
1725 1725 * therefore, get back to the text that follows this symbol in
1726 1726 * some other symbol
1727 1727 */
1728 1728 if (size == 0)
1729 1729 return (0);
1730 1730
1731 1731 if (sym->st_shndx == SHN_UNDEF)
1732 1732 return (0);
1733 1733
1734 1734 text = alloca(size);
1735 1735
1736 1736 if (mdb_vread(text, size, sym->st_value) == -1) {
1737 1737 mdb_warn("failed to read text for %s", name);
1738 1738 return (0);
1739 1739 }
1740 1740
1741 1741 len = size / 4;
1742 1742 for (i = 0; i < len; i++) {
1743 1743 if (!IS_SETHI(text[i]))
1744 1744 continue;
1745 1745
1746 1746 rd = RD(text[i]);
1747 1747 value = IMM22(text[i]) << 10;
1748 1748
1749 1749 /*
1750 1750 * see if we already have a match with just the sethi
1751 1751 */
1752 1752 findsym_output(symlist, value, sym->st_value + i * 4);
1753 1753
1754 1754 /*
1755 1755 * search from the sethi on until we hit a relevant instr
1756 1756 */
1757 1757 for (j = i + 1; j < len; j++) {
1758 1758 if ((op = OP(text[j])) & OP_ARITH_MEM_MASK) {
1759 1759 op3 = OP3(text[j]);
1760 1760
1761 1761 if (RS1(text[j]) != rd)
1762 1762 goto instr_end;
1763 1763
1764 1764 /*
1765 1765 * This is a simple tool; we only deal
1766 1766 * with operations which take immediates
1767 1767 */
1768 1768 if (I(text[j]) == 0)
1769 1769 goto instr_end;
1770 1770
1771 1771 /*
1772 1772 * sign extend the immediate value
1773 1773 */
1774 1774 imm13 = IMM13(text[j]);
1775 1775 imm13 <<= 19;
1776 1776 imm13 >>= 19;
1777 1777
1778 1778 if (op == OP_ARITH) {
1779 1779 /* arithmetic operations */
1780 1780 if (op3 & OP3_COMPLEX_MASK)
1781 1781 goto instr_end;
1782 1782
1783 1783 switch (op3 & ~OP3_CC_MASK) {
1784 1784 case OP3_OR:
1785 1785 value |= imm13;
1786 1786 break;
1787 1787 case OP3_ADD:
1788 1788 value += imm13;
1789 1789 break;
1790 1790 case OP3_XOR:
1791 1791 value ^= imm13;
1792 1792 break;
1793 1793 default:
1794 1794 goto instr_end;
1795 1795 }
1796 1796 } else {
1797 1797 /* loads and stores */
1798 1798 /* op3 == OP_MEM */
1799 1799
1800 1800 value += imm13;
1801 1801 }
1802 1802
1803 1803 findsym_output(symlist, value,
1804 1804 sym->st_value + j * 4);
1805 1805 instr_end:
1806 1806 /*
1807 1807 * if we're clobbering rd, break
1808 1808 */
1809 1809 if (RD(text[j]) == rd)
1810 1810 break;
1811 1811 } else if (IS_SETHI(text[j])) {
1812 1812 if (RD(text[j]) == rd)
1813 1813 break;
1814 1814 } else if (OP(text[j]) == 1) {
1815 1815 /*
1816 1816 * see if a call clobbers an %o or %g
1817 1817 */
1818 1818 if (rd <= R_O7)
1819 1819 break;
1820 1820 }
1821 1821 }
1822 1822 }
1823 1823
1824 1824 return (0);
1825 1825 }
1826 1826
1827 1827 static int
1828 1828 cmd_findsym(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1829 1829 {
1830 1830 uintptr_t *symlist;
1831 1831 uint_t optg = FALSE;
1832 1832 uint_t type;
1833 1833 int len, i;
1834 1834
1835 1835 i = mdb_getopts(argc, argv, 'g', MDB_OPT_SETBITS, TRUE, &optg, NULL);
1836 1836
1837 1837 argc -= i;
1838 1838 argv += i;
1839 1839
1840 1840 len = argc + ((flags & DCMD_ADDRSPEC) ? 1 : 0) + 1;
1841 1841
1842 1842 if (len <= 1)
1843 1843 return (DCMD_USAGE);
1844 1844
1845 1845 /*
1846 1846 * Set up a NULL-terminated symbol list, and then iterate over the
1847 1847 * symbol table, scanning each function for references to these symbols.
1848 1848 */
1849 1849 symlist = mdb_alloc(len * sizeof (uintptr_t), UM_SLEEP | UM_GC);
1850 1850 len = 0;
1851 1851
1852 1852 for (i = 0; i < argc; i++, argv++) {
1853 1853 const char *str = argv->a_un.a_str;
1854 1854 uintptr_t value;
1855 1855 GElf_Sym sym;
1856 1856
1857 1857 if (argv->a_type == MDB_TYPE_STRING) {
1858 1858 if (strchr("+-", str[0]) != NULL)
1859 1859 return (DCMD_USAGE);
1860 1860 else if (str[0] >= '0' && str[0] <= '9')
1861 1861 value = mdb_strtoull(str);
1862 1862 else if (mdb_lookup_by_name(str, &sym) != 0) {
1863 1863 mdb_warn("symbol '%s' not found", str);
1864 1864 return (DCMD_USAGE);
1865 1865 } else
1866 1866 value = sym.st_value;
1867 1867 } else
1868 1868 value = argv[i].a_un.a_val;
1869 1869
1870 1870 if (value != NULL)
1871 1871 symlist[len++] = value;
1872 1872 }
1873 1873
1874 1874 if (flags & DCMD_ADDRSPEC)
1875 1875 symlist[len++] = addr;
1876 1876
1877 1877 symlist[len] = NULL;
1878 1878
1879 1879 if (optg)
1880 1880 type = MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_FUNC;
1881 1881 else
1882 1882 type = MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FUNC;
1883 1883
1884 1884 if (mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
1885 1885 MDB_TGT_SYMTAB, type, findsym_cb, symlist) == -1) {
1886 1886 mdb_warn("failed to iterate over symbol table");
1887 1887 return (DCMD_ERR);
1888 1888 }
1889 1889
1890 1890 return (DCMD_OK);
1891 1891 }
1892 1892 #endif /* __sparc */
1893 1893
1894 1894 static int
1895 1895 dis_str2addr(const char *s, uintptr_t *addr)
1896 1896 {
1897 1897 GElf_Sym sym;
1898 1898
1899 1899 if (s[0] >= '0' && s[0] <= '9') {
1900 1900 *addr = (uintptr_t)mdb_strtoull(s);
1901 1901 return (0);
1902 1902 }
1903 1903
1904 1904 if (mdb_tgt_lookup_by_name(mdb.m_target,
1905 1905 MDB_TGT_OBJ_EVERY, s, &sym, NULL) == -1) {
1906 1906 mdb_warn("symbol '%s' not found\n", s);
1907 1907 return (-1);
1908 1908 }
1909 1909
1910 1910 *addr = (uintptr_t)sym.st_value;
1911 1911 return (0);
1912 1912 }
1913 1913
1914 1914 static int
1915 1915 cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1916 1916 {
1917 1917 mdb_tgt_t *tgt = mdb.m_target;
1918 1918 mdb_disasm_t *dis = mdb.m_disasm;
1919 1919
1920 1920 uintptr_t oaddr, naddr;
1921 1921 mdb_tgt_as_t as;
1922 1922 mdb_tgt_status_t st;
1923 1923 char buf[BUFSIZ];
1924 1924 GElf_Sym sym;
1925 1925 int i;
1926 1926
1927 1927 uint_t opt_f = FALSE; /* File-mode off by default */
1928 1928 uint_t opt_w = FALSE; /* Window mode off by default */
1929 1929 uint_t opt_a = FALSE; /* Raw-address mode off by default */
1930 1930 uint_t opt_b = FALSE; /* Address & symbols off by default */
1931 1931 uintptr_t n = -1UL; /* Length of window in instructions */
1932 1932 uintptr_t eaddr = 0; /* Ending address; 0 if limited by n */
1933 1933
1934 1934 i = mdb_getopts(argc, argv,
1935 1935 'f', MDB_OPT_SETBITS, TRUE, &opt_f,
1936 1936 'w', MDB_OPT_SETBITS, TRUE, &opt_w,
1937 1937 'a', MDB_OPT_SETBITS, TRUE, &opt_a,
1938 1938 'b', MDB_OPT_SETBITS, TRUE, &opt_b,
1939 1939 'n', MDB_OPT_UINTPTR, &n, NULL);
1940 1940
1941 1941 /*
1942 1942 * Disgusting argument post-processing ... basically the idea is to get
1943 1943 * the target address into addr, which we do by using the specified
1944 1944 * expression value, looking up a string as a symbol name, or by
1945 1945 * using the address specified as dot.
1946 1946 */
1947 1947 if (i != argc) {
1948 1948 if (argc != 0 && (argc - i) == 1) {
1949 1949 if (argv[i].a_type == MDB_TYPE_STRING) {
1950 1950 if (argv[i].a_un.a_str[0] == '-')
1951 1951 return (DCMD_USAGE);
1952 1952
1953 1953 if (dis_str2addr(argv[i].a_un.a_str, &addr))
1954 1954 return (DCMD_ERR);
1955 1955 } else
1956 1956 addr = argv[i].a_un.a_val;
1957 1957 } else
1958 1958 return (DCMD_USAGE);
1959 1959 }
1960 1960
1961 1961 /*
1962 1962 * If we're not in window mode yet, and some type of arguments were
1963 1963 * specified, see if the address corresponds nicely to a function.
1964 1964 * If not, turn on window mode; otherwise disassemble the function.
1965 1965 */
1966 1966 if (opt_w == FALSE && (argc != i || (flags & DCMD_ADDRSPEC))) {
1967 1967 if (mdb_tgt_lookup_by_addr(tgt, addr,
1968 1968 MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0 &&
1969 1969 GELF_ST_TYPE(sym.st_info) == STT_FUNC) {
1970 1970 /*
1971 1971 * If the symbol has a size then set our end address to
1972 1972 * be the end of the function symbol we just located.
1973 1973 */
1974 1974 if (sym.st_size != 0)
1975 1975 eaddr = addr + (uintptr_t)sym.st_size;
1976 1976 } else
1977 1977 opt_w = TRUE;
1978 1978 }
1979 1979
1980 1980 /*
1981 1981 * Window-mode doesn't make sense in a loop.
1982 1982 */
1983 1983 if (flags & DCMD_LOOP)
1984 1984 opt_w = FALSE;
1985 1985
1986 1986 /*
1987 1987 * If -n was explicit, limit output to n instructions;
1988 1988 * otherwise set n to some reasonable default
1989 1989 */
1990 1990 if (n != -1UL)
1991 1991 eaddr = 0;
1992 1992 else
1993 1993 n = 10;
1994 1994
1995 1995 /*
1996 1996 * If the state is IDLE (i.e. no address space), turn on -f.
1997 1997 */
1998 1998 if (mdb_tgt_status(tgt, &st) == 0 && st.st_state == MDB_TGT_IDLE)
1999 1999 opt_f = TRUE;
2000 2000
2001 2001 if (opt_f)
2002 2002 as = MDB_TGT_AS_FILE;
2003 2003 else
2004 2004 as = MDB_TGT_AS_VIRT;
2005 2005
2006 2006 if (opt_w == FALSE) {
2007 2007 n++;
2008 2008 while ((eaddr == 0 && n-- != 0) || (addr < eaddr)) {
2009 2009 naddr = mdb_dis_ins2str(dis, tgt, as,
2010 2010 buf, sizeof (buf), addr);
2011 2011 if (naddr == addr)
2012 2012 return (DCMD_ERR);
2013 2013 if (opt_a)
2014 2014 mdb_printf("%-#32p%8T%s\n", addr, buf);
2015 2015 else if (opt_b)
2016 2016 mdb_printf("%-#10p%-#32a%8T%s\n",
2017 2017 addr, addr, buf);
2018 2018 else
2019 2019 mdb_printf("%-#32a%8T%s\n", addr, buf);
2020 2020 addr = naddr;
2021 2021 }
2022 2022
2023 2023 } else {
2024 2024 #ifdef __sparc
2025 2025 if (addr & 0x3) {
2026 2026 mdb_warn("address is not properly aligned\n");
2027 2027 return (DCMD_ERR);
2028 2028 }
2029 2029 #endif
2030 2030
2031 2031 for (oaddr = mdb_dis_previns(dis, tgt, as, addr, n);
2032 2032 oaddr < addr; oaddr = naddr) {
2033 2033 naddr = mdb_dis_ins2str(dis, tgt, as,
2034 2034 buf, sizeof (buf), oaddr);
2035 2035 if (naddr == oaddr)
2036 2036 return (DCMD_ERR);
2037 2037 if (opt_a)
2038 2038 mdb_printf("%-#32p%8T%s\n", oaddr, buf);
2039 2039 else if (opt_b)
2040 2040 mdb_printf("%-#10p%-#32a%8T%s\n",
2041 2041 oaddr, oaddr, buf);
2042 2042 else
2043 2043 mdb_printf("%-#32a%8T%s\n", oaddr, buf);
2044 2044 }
2045 2045
2046 2046 if ((naddr = mdb_dis_ins2str(dis, tgt, as,
2047 2047 buf, sizeof (buf), addr)) == addr)
2048 2048 return (DCMD_ERR);
2049 2049
2050 2050 mdb_printf("%<b>");
2051 2051 mdb_flush();
2052 2052 if (opt_a)
2053 2053 mdb_printf("%-#32p%8T%s%", addr, buf);
2054 2054 else if (opt_b)
2055 2055 mdb_printf("%-#10p%-#32a%8T%s", addr, addr, buf);
2056 2056 else
2057 2057 mdb_printf("%-#32a%8T%s%", addr, buf);
2058 2058 mdb_printf("%</b>\n");
2059 2059
2060 2060 for (addr = naddr; n-- != 0; addr = naddr) {
2061 2061 naddr = mdb_dis_ins2str(dis, tgt, as,
2062 2062 buf, sizeof (buf), addr);
2063 2063 if (naddr == addr)
2064 2064 return (DCMD_ERR);
2065 2065 if (opt_a)
2066 2066 mdb_printf("%-#32p%8T%s\n", addr, buf);
2067 2067 else if (opt_b)
2068 2068 mdb_printf("%-#10p%-#32a%8T%s\n",
2069 2069 addr, addr, buf);
2070 2070 else
2071 2071 mdb_printf("%-#32a%8T%s\n", addr, buf);
2072 2072 }
2073 2073 }
2074 2074
2075 2075 mdb_set_dot(addr);
2076 2076 return (DCMD_OK);
2077 2077 }
2078 2078
2079 2079 /*ARGSUSED*/
2080 2080 static int
2081 2081 walk_step(uintptr_t addr, const void *data, void *private)
2082 2082 {
2083 2083 mdb_printf("%lr\n", addr);
2084 2084 return (WALK_NEXT);
2085 2085 }
2086 2086
2087 2087 static int
2088 2088 cmd_walk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2089 2089 {
2090 2090 int status;
2091 2091
2092 2092 if (argc < 1 || argc > 2 || argv[0].a_type != MDB_TYPE_STRING ||
2093 2093 argv[argc - 1].a_type != MDB_TYPE_STRING)
2094 2094 return (DCMD_USAGE);
2095 2095
2096 2096 if (argc > 1) {
2097 2097 const char *name = argv[1].a_un.a_str;
2098 2098 mdb_var_t *v = mdb_nv_lookup(&mdb.m_nv, name);
2099 2099 const char *p;
2100 2100
2101 2101 if (v != NULL && (v->v_flags & MDB_NV_RDONLY) != 0) {
2102 2102 mdb_warn("variable %s is read-only\n", name);
2103 2103 return (DCMD_ABORT);
2104 2104 }
2105 2105
2106 2106 if (v == NULL && (p = strbadid(name)) != NULL) {
2107 2107 mdb_warn("'%c' may not be used in a variable "
2108 2108 "name\n", *p);
2109 2109 return (DCMD_ABORT);
2110 2110 }
2111 2111
2112 2112 if (v == NULL && (v = mdb_nv_insert(&mdb.m_nv,
2113 2113 name, NULL, 0, 0)) == NULL)
2114 2114 return (DCMD_ERR);
2115 2115
2116 2116 /*
2117 2117 * If there already exists a vcb for this variable, we may be
2118 2118 * calling ::walk in a loop. We only create a vcb for this
2119 2119 * variable on the first invocation.
2120 2120 */
2121 2121 if (mdb_vcb_find(v, mdb.m_frame) == NULL)
2122 2122 mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame);
2123 2123 }
2124 2124
2125 2125 if (flags & DCMD_ADDRSPEC)
2126 2126 status = mdb_pwalk(argv->a_un.a_str, walk_step, NULL, addr);
2127 2127 else
2128 2128 status = mdb_walk(argv->a_un.a_str, walk_step, NULL);
2129 2129
2130 2130 if (status == -1) {
2131 2131 mdb_warn("failed to perform walk");
2132 2132 return (DCMD_ERR);
2133 2133 }
2134 2134
2135 2135 return (DCMD_OK);
2136 2136 }
2137 2137
2138 2138 static int
2139 2139 cmd_walk_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
2140 2140 const mdb_arg_t *argv)
2141 2141 {
2142 2142 if (argc > 1)
2143 2143 return (1);
2144 2144
2145 2145 if (argc == 1) {
2146 2146 ASSERT(argv[0].a_type == MDB_TYPE_STRING);
2147 2147 return (mdb_tab_complete_walker(mcp, argv[0].a_un.a_str));
2148 2148 }
2149 2149
2150 2150 if (argc == 0 && flags & DCMD_TAB_SPACE)
2151 2151 return (mdb_tab_complete_walker(mcp, NULL));
2152 2152
2153 2153 return (1);
2154 2154 }
2155 2155
2156 2156 static ssize_t
2157 2157 mdb_partial_xread(void *buf, size_t nbytes, uintptr_t addr, void *arg)
2158 2158 {
2159 2159 ssize_t (*fp)(mdb_tgt_t *, const void *, size_t, uintptr_t) =
2160 2160 (ssize_t (*)(mdb_tgt_t *, const void *, size_t, uintptr_t))arg;
2161 2161
2162 2162 return (fp(mdb.m_target, buf, nbytes, addr));
2163 2163 }
2164 2164
2165 2165 /* ARGSUSED3 */
2166 2166 static ssize_t
2167 2167 mdb_partial_pread(void *buf, size_t nbytes, physaddr_t addr, void *arg)
2168 2168 {
2169 2169 return (mdb_tgt_pread(mdb.m_target, buf, nbytes, addr));
2170 2170 }
2171 2171
2172 2172
2173 2173 static int
2174 2174 cmd_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2175 2175 {
2176 2176 uint_t dflags =
2177 2177 MDB_DUMP_ALIGN | MDB_DUMP_NEWDOT | MDB_DUMP_ASCII | MDB_DUMP_HEADER;
2178 2178 uint_t phys = FALSE;
2179 2179 uint_t file = FALSE;
2180 2180 uintptr_t group = 4;
2181 2181 uintptr_t width = 1;
2182 2182 mdb_tgt_status_t st;
2183 2183 int error;
2184 2184
2185 2185 if (mdb_getopts(argc, argv,
2186 2186 'e', MDB_OPT_SETBITS, MDB_DUMP_ENDIAN, &dflags,
2187 2187 'f', MDB_OPT_SETBITS, TRUE, &file,
2188 2188 'g', MDB_OPT_UINTPTR, &group,
2189 2189 'p', MDB_OPT_SETBITS, TRUE, &phys,
2190 2190 'q', MDB_OPT_CLRBITS, MDB_DUMP_ASCII, &dflags,
2191 2191 'r', MDB_OPT_SETBITS, MDB_DUMP_RELATIVE, &dflags,
2192 2192 's', MDB_OPT_SETBITS, MDB_DUMP_SQUISH, &dflags,
2193 2193 't', MDB_OPT_SETBITS, MDB_DUMP_TRIM, &dflags,
2194 2194 'u', MDB_OPT_CLRBITS, MDB_DUMP_ALIGN, &dflags,
2195 2195 'v', MDB_OPT_SETBITS, MDB_DUMP_PEDANT, &dflags,
2196 2196 'w', MDB_OPT_UINTPTR, &width, NULL) != argc)
2197 2197 return (DCMD_USAGE);
2198 2198
2199 2199 if ((phys && file) ||
2200 2200 (width == 0) || (width > 0x10) ||
2201 2201 (group == 0) || (group > 0x100))
2202 2202 return (DCMD_USAGE);
2203 2203
2204 2204 /*
2205 2205 * If neither -f nor -p were specified and the state is IDLE (i.e. no
2206 2206 * address space), turn on -p. This is so we can read large files.
2207 2207 */
2208 2208 if (phys == FALSE && file == FALSE && mdb_tgt_status(mdb.m_target,
2209 2209 &st) == 0 && st.st_state == MDB_TGT_IDLE)
2210 2210 phys = TRUE;
2211 2211
2212 2212 dflags |= MDB_DUMP_GROUP(group) | MDB_DUMP_WIDTH(width);
2213 2213 if (phys)
2214 2214 error = mdb_dump64(mdb_get_dot(), mdb.m_dcount, dflags,
2215 2215 mdb_partial_pread, NULL);
2216 2216 else if (file)
2217 2217 error = mdb_dumpptr(addr, mdb.m_dcount, dflags,
2218 2218 mdb_partial_xread, (void *)mdb_tgt_fread);
2219 2219 else
2220 2220 error = mdb_dumpptr(addr, mdb.m_dcount, dflags,
2221 2221 mdb_partial_xread, (void *)mdb_tgt_vread);
2222 2222
2223 2223 return (((flags & DCMD_LOOP) || (error == -1)) ? DCMD_ABORT : DCMD_OK);
2224 2224 }
2225 2225
2226 2226 /*ARGSUSED*/
2227 2227 static int
2228 2228 cmd_echo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2229 2229 {
2230 2230 if (flags & DCMD_ADDRSPEC)
2231 2231 return (DCMD_USAGE);
2232 2232
2233 2233 for (; argc-- != 0; argv++) {
2234 2234 if (argv->a_type == MDB_TYPE_STRING)
2235 2235 mdb_printf("%s ", argv->a_un.a_str);
2236 2236 else
2237 2237 mdb_printf("%llr ", argv->a_un.a_val);
2238 2238 }
2239 2239
2240 2240 mdb_printf("\n");
2241 2241 return (DCMD_OK);
2242 2242 }
2243 2243
2244 2244 /*ARGSUSED*/
2245 2245 static int
2246 2246 cmd_head(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2247 2247 {
2248 2248 uint64_t cnt = 10;
2249 2249 const char *c;
2250 2250 mdb_pipe_t p;
2251 2251
2252 2252 if (!flags & DCMD_PIPE)
2253 2253 return (DCMD_USAGE);
2254 2254
2255 2255 if (argc == 1 || argc == 2) {
2256 2256 const char *num;
2257 2257
2258 2258 if (argc == 1) {
2259 2259 if (argv[0].a_type != MDB_TYPE_STRING ||
2260 2260 *argv[0].a_un.a_str != '-')
2261 2261 return (DCMD_USAGE);
2262 2262
2263 2263 num = argv[0].a_un.a_str + 1;
2264 2264
2265 2265 } else {
2266 2266 if (argv[0].a_type != MDB_TYPE_STRING ||
2267 2267 strcmp(argv[0].a_un.a_str, "-n") != 0)
2268 2268 return (DCMD_USAGE);
2269 2269
2270 2270 num = argv[1].a_un.a_str;
2271 2271 }
2272 2272
2273 2273 for (cnt = 0, c = num; *c != '\0' && isdigit(*c); c++)
2274 2274 cnt = cnt * 10 + (*c - '0');
2275 2275
2276 2276 if (*c != '\0')
2277 2277 return (DCMD_USAGE);
2278 2278
2279 2279 } else if (argc != 0) {
2280 2280 return (DCMD_USAGE);
2281 2281 }
2282 2282
2283 2283 mdb_get_pipe(&p);
2284 2284
2285 2285 if (p.pipe_data == NULL)
2286 2286 return (DCMD_OK);
2287 2287 p.pipe_len = MIN(p.pipe_len, cnt);
2288 2288
2289 2289 if (flags & DCMD_PIPE_OUT) {
2290 2290 mdb_set_pipe(&p);
2291 2291 } else {
2292 2292 while (p.pipe_len-- > 0)
2293 2293 mdb_printf("%lx\n", *p.pipe_data++);
2294 2294 }
2295 2295
2296 2296 return (DCMD_OK);
2297 2297 }
2298 2298
2299 2299 static void
2300 2300 head_help(void)
2301 2301 {
2302 2302 mdb_printf(
2303 2303 "-n num\n or\n"
2304 2304 "-num pass only the first `num' elements in the pipe.\n"
2305 2305 "\n%<b>Note:%</b> `num' is a decimal number.\n");
2306 2306 }
2307 2307
2308 2308 static int
2309 2309 cmd_typeset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2310 2310 {
2311 2311 int add_tag = 0, del_tag = 0;
2312 2312 const char *p;
2313 2313 mdb_var_t *v;
2314 2314
2315 2315 if (argc == 0)
2316 2316 return (cmd_vars(addr, flags, argc, argv));
2317 2317
2318 2318 if (argv->a_type == MDB_TYPE_STRING && (argv->a_un.a_str[0] == '-' ||
2319 2319 argv->a_un.a_str[0] == '+')) {
2320 2320 if (argv->a_un.a_str[1] != 't')
2321 2321 return (DCMD_USAGE);
2322 2322 if (argv->a_un.a_str[0] == '-')
2323 2323 add_tag++;
2324 2324 else
2325 2325 del_tag++;
2326 2326 argc--;
2327 2327 argv++;
2328 2328 }
2329 2329
2330 2330 if (!(flags & DCMD_ADDRSPEC))
2331 2331 addr = 0; /* set variables to zero unless explicit addr given */
2332 2332
2333 2333 for (; argc-- != 0; argv++) {
2334 2334 if (argv->a_type != MDB_TYPE_STRING)
2335 2335 continue;
2336 2336
2337 2337 if (argv->a_un.a_str[0] == '-' || argv->a_un.a_str[0] == '+') {
2338 2338 mdb_warn("ignored bad option -- %s\n",
2339 2339 argv->a_un.a_str);
2340 2340 continue;
2341 2341 }
2342 2342
2343 2343 if ((p = strbadid(argv->a_un.a_str)) != NULL) {
2344 2344 mdb_warn("'%c' may not be used in a variable "
2345 2345 "name\n", *p);
2346 2346 return (DCMD_ERR);
2347 2347 }
2348 2348
2349 2349 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL) {
2350 2350 v = mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str,
2351 2351 NULL, addr, 0);
2352 2352 } else if (flags & DCMD_ADDRSPEC)
2353 2353 mdb_nv_set_value(v, addr);
2354 2354
2355 2355 if (v != NULL) {
2356 2356 if (add_tag)
2357 2357 v->v_flags |= MDB_NV_TAGGED;
2358 2358 if (del_tag)
2359 2359 v->v_flags &= ~MDB_NV_TAGGED;
2360 2360 }
2361 2361 }
2362 2362
2363 2363 return (DCMD_OK);
2364 2364 }
2365 2365
2366 2366 #ifndef _KMDB
2367 2367 /*ARGSUSED*/
2368 2368 static int
2369 2369 cmd_context(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2370 2370 {
2371 2371 if (argc != 0 || !(flags & DCMD_ADDRSPEC))
2372 2372 return (DCMD_USAGE);
2373 2373
2374 2374 if (mdb_tgt_setcontext(mdb.m_target, (void *)addr) == 0)
2375 2375 return (DCMD_OK);
2376 2376
2377 2377 return (DCMD_ERR);
2378 2378 }
2379 2379 #endif
2380 2380
2381 2381 /*ARGSUSED*/
2382 2382 static int
2383 2383 cmd_prompt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2384 2384 {
2385 2385 const char *p = "";
2386 2386
2387 2387 if (argc != 0) {
2388 2388 if (argc > 1 || argv->a_type != MDB_TYPE_STRING)
2389 2389 return (DCMD_USAGE);
2390 2390 p = argv->a_un.a_str;
2391 2391 }
2392 2392
2393 2393 (void) mdb_set_prompt(p);
2394 2394 return (DCMD_OK);
2395 2395 }
2396 2396
2397 2397 /*ARGSUSED*/
2398 2398 static int
2399 2399 cmd_term(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2400 2400 {
2401 2401 mdb_printf("%s\n", mdb.m_termtype);
2402 2402
2403 2403 return (DCMD_OK);
2404 2404 }
2405 2405
2406 2406 /*ARGSUSED*/
2407 2407 static int
2408 2408 cmd_vtop(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2409 2409 {
2410 2410 physaddr_t pa;
2411 2411 mdb_tgt_as_t as = MDB_TGT_AS_VIRT;
2412 2412
2413 2413 if (mdb_getopts(argc, argv, 'a', MDB_OPT_UINTPTR, (uintptr_t *)&as,
2414 2414 NULL) != argc)
2415 2415 return (DCMD_USAGE);
2416 2416
2417 2417 if (mdb_tgt_vtop(mdb.m_target, as, addr, &pa) == -1) {
2418 2418 mdb_warn("failed to get physical mapping");
2419 2419 return (DCMD_ERR);
2420 2420 }
2421 2421
2422 2422 if (flags & DCMD_PIPE_OUT)
2423 2423 mdb_printf("%llr\n", pa);
2424 2424 else
2425 2425 mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa);
2426 2426 return (DCMD_OK);
2427 2427 }
2428 2428
2429 2429 #define EVENTS_OPT_A 0x1 /* ::events -a (show all events) */
2430 2430 #define EVENTS_OPT_V 0x2 /* ::events -v (verbose display) */
2431 2431
2432 2432 static const char *
2433 2433 event_action(const mdb_tgt_spec_desc_t *sp)
2434 2434 {
2435 2435 if (!(sp->spec_flags & MDB_TGT_SPEC_HIDDEN) && sp->spec_data != NULL)
2436 2436 return (sp->spec_data);
2437 2437
2438 2438 return ("-");
2439 2439 }
2440 2440
2441 2441 static void
2442 2442 print_evsep(void)
2443 2443 {
2444 2444 static const char dash20[] = "--------------------";
2445 2445 mdb_printf("----- - -- -- -- %s%s --%s\n", dash20, dash20, dash20);
2446 2446 }
2447 2447
2448 2448 /*ARGSUSED*/
2449 2449 static int
2450 2450 print_event(mdb_tgt_t *t, void *private, int vid, void *data)
2451 2451 {
2452 2452 uint_t opts = (uint_t)(uintptr_t)private;
2453 2453 mdb_tgt_spec_desc_t sp;
2454 2454 char s1[41], s2[22];
2455 2455 const char *s2str;
2456 2456 int visible;
2457 2457
2458 2458 (void) mdb_tgt_vespec_info(t, vid, &sp, s1, sizeof (s1));
2459 2459 visible = !(sp.spec_flags & (MDB_TGT_SPEC_HIDDEN|MDB_TGT_SPEC_DELETED));
2460 2460
2461 2461 if ((opts & EVENTS_OPT_A) || visible) {
2462 2462 int encoding = (!(sp.spec_flags & MDB_TGT_SPEC_DISABLED)) |
2463 2463 (!(sp.spec_flags & MDB_TGT_SPEC_MATCHED) << 1);
2464 2464
2465 2465 char ldelim = "<<(["[encoding];
2466 2466 char rdelim = ">>)]"[encoding];
2467 2467
2468 2468 char state = "0-+*!"[sp.spec_state];
2469 2469
2470 2470 char tflag = "T "[!(sp.spec_flags & MDB_TGT_SPEC_STICKY)];
2471 2471 char aflag = "d "[!(sp.spec_flags & MDB_TGT_SPEC_AUTODIS)];
2472 2472
2473 2473 if (sp.spec_flags & MDB_TGT_SPEC_TEMPORARY)
2474 2474 tflag = 't'; /* TEMP takes precedence over STICKY */
2475 2475 if (sp.spec_flags & MDB_TGT_SPEC_AUTODEL)
2476 2476 aflag = 'D'; /* AUTODEL takes precedence over AUTODIS */
2477 2477 if (sp.spec_flags & MDB_TGT_SPEC_AUTOSTOP)
2478 2478 aflag = 's'; /* AUTOSTOP takes precedence over both */
2479 2479
2480 2480 if (opts & EVENTS_OPT_V) {
2481 2481 if (sp.spec_state == MDB_TGT_SPEC_IDLE ||
2482 2482 sp.spec_state == MDB_TGT_SPEC_ERROR)
2483 2483 s2str = mdb_strerror(sp.spec_errno);
2484 2484 else
2485 2485 s2str = "-";
2486 2486 } else
2487 2487 s2str = event_action(&sp);
2488 2488
2489 2489 if (mdb_snprintf(s2, sizeof (s2), "%s", s2str) >= sizeof (s2))
2490 2490 (void) strabbr(s2, sizeof (s2));
2491 2491
2492 2492 if (vid > -10 && vid < 10)
2493 2493 mdb_printf("%c%2d %c", ldelim, vid, rdelim);
2494 2494 else
2495 2495 mdb_printf("%c%3d%c", ldelim, vid, rdelim);
2496 2496
2497 2497 mdb_printf(" %c %c%c %2u %2u %-40s %-21s\n",
2498 2498 state, tflag, aflag, sp.spec_hits, sp.spec_limit, s1, s2);
2499 2499
2500 2500 if (opts & EVENTS_OPT_V) {
2501 2501 mdb_printf("%-17s%s\n", "", event_action(&sp));
2502 2502 print_evsep();
2503 2503 }
2504 2504 }
2505 2505
2506 2506 return (0);
2507 2507 }
2508 2508
2509 2509 /*ARGSUSED*/
2510 2510 static int
2511 2511 cmd_events(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2512 2512 {
2513 2513 uint_t opts = 0;
2514 2514
2515 2515 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
2516 2516 'a', MDB_OPT_SETBITS, EVENTS_OPT_A, &opts,
2517 2517 'v', MDB_OPT_SETBITS, EVENTS_OPT_V, &opts, NULL) != argc)
2518 2518 return (DCMD_USAGE);
2519 2519
2520 2520
2521 2521 if (opts & EVENTS_OPT_V) {
2522 2522 mdb_printf(" ID S TA HT LM %-40s %-21s\n%-17s%s\n",
2523 2523 "Description", "Status", "", "Action");
2524 2524 } else {
2525 2525 mdb_printf(" ID S TA HT LM %-40s %-21s\n",
2526 2526 "Description", "Action");
2527 2527 }
2528 2528
2529 2529 print_evsep();
2530 2530 return (mdb_tgt_vespec_iter(mdb.m_target, print_event,
2531 2531 (void *)(uintptr_t)opts));
2532 2532 }
2533 2533
2534 2534 static int
2535 2535 tgt_status(const mdb_tgt_status_t *tsp)
2536 2536 {
2537 2537 const char *format;
2538 2538 char buf[BUFSIZ];
2539 2539
2540 2540 if (tsp->st_flags & MDB_TGT_BUSY)
2541 2541 return (DCMD_OK);
2542 2542
2543 2543 if (tsp->st_pc != 0) {
2544 2544 if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT,
2545 2545 buf, sizeof (buf), tsp->st_pc) != tsp->st_pc)
2546 2546 format = "target stopped at:\n%-#16a%8T%s\n";
2547 2547 else
2548 2548 format = "target stopped at %a:\n";
2549 2549 mdb_warn(format, tsp->st_pc, buf);
2550 2550 }
2551 2551
2552 2552 switch (tsp->st_state) {
2553 2553 case MDB_TGT_IDLE:
2554 2554 mdb_warn("target is idle\n");
2555 2555 break;
2556 2556 case MDB_TGT_RUNNING:
2557 2557 if (tsp->st_flags & MDB_TGT_DSTOP)
2558 2558 mdb_warn("target is running, stop directive pending\n");
2559 2559 else
2560 2560 mdb_warn("target is running\n");
2561 2561 break;
2562 2562 case MDB_TGT_STOPPED:
2563 2563 if (tsp->st_pc == 0)
2564 2564 mdb_warn("target is stopped\n");
2565 2565 break;
2566 2566 case MDB_TGT_UNDEAD:
2567 2567 mdb_warn("target has terminated\n");
2568 2568 break;
2569 2569 case MDB_TGT_DEAD:
2570 2570 mdb_warn("target is a core dump\n");
2571 2571 break;
2572 2572 case MDB_TGT_LOST:
2573 2573 mdb_warn("target is no longer under debugger control\n");
2574 2574 break;
2575 2575 }
2576 2576
2577 2577 mdb_set_dot(tsp->st_pc);
2578 2578 return (DCMD_OK);
2579 2579 }
2580 2580
2581 2581 /*
2582 2582 * mdb continue/step commands take an optional signal argument, but the
2583 2583 * corresponding kmdb versions don't.
2584 2584 */
2585 2585 #ifdef _KMDB
2586 2586 #define CONT_MAXARGS 0 /* no optional SIG argument */
2587 2587 #else
2588 2588 #define CONT_MAXARGS 1
2589 2589 #endif
2590 2590
2591 2591 /*ARGSUSED*/
2592 2592 static int
2593 2593 cmd_cont_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
2594 2594 int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *), const char *name)
2595 2595 {
2596 2596 mdb_tgt_t *t = mdb.m_target;
2597 2597 mdb_tgt_status_t st;
2598 2598 int sig = 0;
2599 2599
2600 2600 if ((flags & DCMD_ADDRSPEC) || argc > CONT_MAXARGS)
2601 2601 return (DCMD_USAGE);
2602 2602
2603 2603 if (argc > 0) {
2604 2604 if (argv->a_type == MDB_TYPE_STRING) {
2605 2605 if (proc_str2sig(argv->a_un.a_str, &sig) == -1) {
2606 2606 mdb_warn("invalid signal name -- %s\n",
2607 2607 argv->a_un.a_str);
2608 2608 return (DCMD_USAGE);
2609 2609 }
2610 2610 } else
2611 2611 sig = (int)(intmax_t)argv->a_un.a_val;
2612 2612 }
2613 2613
2614 2614 (void) mdb_tgt_status(t, &st);
2615 2615
2616 2616 if (st.st_state == MDB_TGT_IDLE && mdb_tgt_run(t, 0, NULL) == -1) {
2617 2617 if (errno != EMDB_TGT)
2618 2618 mdb_warn("failed to create new target");
2619 2619 return (DCMD_ERR);
2620 2620 }
2621 2621
2622 2622 if (sig != 0 && mdb_tgt_signal(t, sig) == -1) {
2623 2623 mdb_warn("failed to post signal %d", sig);
2624 2624 return (DCMD_ERR);
2625 2625 }
2626 2626
2627 2627 if (st.st_state == MDB_TGT_IDLE && t_cont == &mdb_tgt_step) {
2628 2628 (void) mdb_tgt_status(t, &st);
2629 2629 return (tgt_status(&st));
2630 2630 }
2631 2631
2632 2632 if (t_cont(t, &st) == -1) {
2633 2633 if (errno != EMDB_TGT)
2634 2634 mdb_warn("failed to %s target", name);
2635 2635 return (DCMD_ERR);
2636 2636 }
2637 2637
2638 2638 return (tgt_status(&st));
2639 2639 }
2640 2640
2641 2641 static int
2642 2642 cmd_step(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2643 2643 {
2644 2644 int (*func)(mdb_tgt_t *, mdb_tgt_status_t *) = &mdb_tgt_step;
2645 2645 const char *name = "single-step";
2646 2646
2647 2647 if (argc > 0 && argv->a_type == MDB_TYPE_STRING) {
2648 2648 if (strcmp(argv->a_un.a_str, "out") == 0) {
2649 2649 func = &mdb_tgt_step_out;
2650 2650 name = "step (out)";
2651 2651 argv++;
2652 2652 argc--;
2653 2653 } else if (strcmp(argv->a_un.a_str, "branch") == 0) {
2654 2654 func = &mdb_tgt_step_branch;
2655 2655 name = "step (branch)";
2656 2656 argv++;
2657 2657 argc--;
2658 2658 } else if (strcmp(argv->a_un.a_str, "over") == 0) {
2659 2659 func = &mdb_tgt_next;
2660 2660 name = "step (over)";
2661 2661 argv++;
2662 2662 argc--;
2663 2663 }
2664 2664 }
2665 2665
2666 2666 return (cmd_cont_common(addr, flags, argc, argv, func, name));
2667 2667 }
2668 2668
2669 2669 static int
2670 2670 cmd_step_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2671 2671 {
2672 2672 return (cmd_cont_common(addr, flags, argc, argv,
2673 2673 &mdb_tgt_step_out, "step (out)"));
2674 2674 }
2675 2675
2676 2676 static int
2677 2677 cmd_next(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2678 2678 {
2679 2679 return (cmd_cont_common(addr, flags, argc, argv,
2680 2680 &mdb_tgt_next, "step (over)"));
2681 2681 }
2682 2682
2683 2683 static int
2684 2684 cmd_cont(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2685 2685 {
2686 2686 return (cmd_cont_common(addr, flags, argc, argv,
2687 2687 &mdb_tgt_continue, "continue"));
2688 2688 }
2689 2689
2690 2690 #ifndef _KMDB
2691 2691 /*ARGSUSED*/
2692 2692 static int
2693 2693 cmd_run(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2694 2694 {
2695 2695 if (flags & DCMD_ADDRSPEC)
2696 2696 return (DCMD_USAGE);
2697 2697
2698 2698 if (mdb_tgt_run(mdb.m_target, argc, argv) == -1) {
2699 2699 if (errno != EMDB_TGT)
2700 2700 mdb_warn("failed to create new target");
2701 2701 return (DCMD_ERR);
2702 2702 }
2703 2703 return (cmd_cont(NULL, 0, 0, NULL));
2704 2704 }
2705 2705 #endif
2706 2706
2707 2707 /*
2708 2708 * To simplify the implementation of :d, :z, and ::delete, we use the sp
2709 2709 * parameter to store the criteria for what to delete. If spec_base is set,
2710 2710 * we delete vespecs with a matching address. If spec_id is set, we delete
2711 2711 * vespecs with a matching id. Otherwise, we delete all vespecs. We bump
2712 2712 * sp->spec_size so the caller can tell how many vespecs were deleted.
2713 2713 */
2714 2714 static int
2715 2715 ve_delete(mdb_tgt_t *t, mdb_tgt_spec_desc_t *sp, int vid, void *data)
2716 2716 {
2717 2717 mdb_tgt_spec_desc_t spec;
2718 2718 int status = -1;
2719 2719
2720 2720 if (vid < 0)
2721 2721 return (0); /* skip over target implementation events */
2722 2722
2723 2723 if (sp->spec_base != NULL) {
2724 2724 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2725 2725 if (sp->spec_base - spec.spec_base < spec.spec_size)
2726 2726 status = mdb_tgt_vespec_delete(t, vid);
2727 2727 } else if (sp->spec_id == 0) {
2728 2728 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2729 2729 if (!(spec.spec_flags & MDB_TGT_SPEC_STICKY))
2730 2730 status = mdb_tgt_vespec_delete(t, vid);
2731 2731 } else if (sp->spec_id == vid)
2732 2732 status = mdb_tgt_vespec_delete(t, vid);
2733 2733
2734 2734 if (status == 0) {
2735 2735 if (data != NULL)
2736 2736 strfree(data);
2737 2737 sp->spec_size++;
2738 2738 }
2739 2739
2740 2740 return (0);
2741 2741 }
2742 2742
2743 2743 static int
2744 2744 ve_delete_spec(mdb_tgt_spec_desc_t *sp)
2745 2745 {
2746 2746 (void) mdb_tgt_vespec_iter(mdb.m_target,
2747 2747 (mdb_tgt_vespec_f *)ve_delete, sp);
2748 2748
2749 2749 if (sp->spec_size == 0) {
2750 2750 if (sp->spec_id != 0 || sp->spec_base != NULL)
2751 2751 mdb_warn("no traced events matched description\n");
2752 2752 }
2753 2753
2754 2754 return (DCMD_OK);
2755 2755 }
2756 2756
2757 2757 /*ARGSUSED*/
2758 2758 static int
2759 2759 cmd_zapall(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2760 2760 {
2761 2761 mdb_tgt_spec_desc_t spec;
2762 2762
2763 2763 if ((flags & DCMD_ADDRSPEC) || argc != 0)
2764 2764 return (DCMD_USAGE);
2765 2765
2766 2766 bzero(&spec, sizeof (spec));
2767 2767 return (ve_delete_spec(&spec));
2768 2768 }
2769 2769
2770 2770 static int
2771 2771 cmd_delete(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2772 2772 {
2773 2773 mdb_tgt_spec_desc_t spec;
2774 2774
2775 2775 if (((flags & DCMD_ADDRSPEC) && argc > 0) || argc > 1)
2776 2776 return (DCMD_USAGE);
2777 2777
2778 2778 bzero(&spec, sizeof (spec));
2779 2779
2780 2780 if (flags & DCMD_ADDRSPEC)
2781 2781 spec.spec_base = addr;
2782 2782 else if (argc == 0)
2783 2783 spec.spec_base = mdb_get_dot();
2784 2784 else if (argv->a_type == MDB_TYPE_STRING &&
2785 2785 strcmp(argv->a_un.a_str, "all") != 0)
2786 2786 spec.spec_id = (int)(intmax_t)strtonum(argv->a_un.a_str, 10);
2787 2787 else if (argv->a_type == MDB_TYPE_IMMEDIATE)
2788 2788 spec.spec_id = (int)(intmax_t)argv->a_un.a_val;
2789 2789
2790 2790 return (ve_delete_spec(&spec));
2791 2791 }
2792 2792
2793 2793 static void
2794 2794 srcexec_file_help(void)
2795 2795 {
2796 2796 mdb_printf(
2797 2797 "The library of macros delivered with previous versions of Solaris have been\n"
2798 2798 "superseded by the dcmds and walkers provided by MDB. See ::help for\n"
2799 2799 "commands that can be used to list the available dcmds and walkers.\n"
2800 2800 "\n"
2801 2801 "Aliases have been created for several of the more popular macros. To see\n"
2802 2802 "the list of aliased macros, as well as their native MDB equivalents,\n"
2803 2803 "type $M.\n");
2804 2804
2805 2805 #ifdef _KMDB
2806 2806 mdb_printf(
2807 2807 "When invoked, the $< and $<< dcmds will consult the macro alias list. If an\n"
2808 2808 "alias cannot be found, an attempt will be made to locate a data type whose\n"
2809 2809 "name corresponds to the requested macro. If such a type can be found, it\n"
2810 2810 "will be displayed using the ::print dcmd.\n");
2811 2811 #else
2812 2812 mdb_printf(
2813 2813 "When invoked, the $< and $<< dcmds will first attempt to locate a macro with\n"
2814 2814 "the indicated name. If no macro can be found, and if no alias exists for\n"
2815 2815 "this macro, an attempt will be made to locate a data type whose name\n"
2816 2816 "corresponds to the requested macro. If such a type can be found, it will be\n"
2817 2817 "displayed using the ::print dcmd.\n");
2818 2818 #endif
2819 2819 }
2820 2820
2821 2821 static void
2822 2822 events_help(void)
2823 2823 {
2824 2824 mdb_printf("Options:\n"
2825 2825 "-a show all events, including internal debugger events\n"
2826 2826 "-v show verbose display, including inactivity reason\n"
2827 2827 "\nOutput Columns:\n"
2828 2828 "ID decimal event specifier id number:\n"
2829 2829 " [ ] event tracing is enabled\n"
2830 2830 " ( ) event tracing is disabled\n"
2831 2831 " < > target is currently stopped on this type of event\n\n"
2832 2832 "S event specifier state:\n"
2833 2833 " - event specifier is idle (not applicable yet)\n"
2834 2834 " + event specifier is active\n"
2835 2835 " * event specifier is armed (target program running)\n"
2836 2836 " ! error occurred while attempting to arm event\n\n"
2837 2837 "TA event specifier flags:\n"
2838 2838 " t event specifier is temporary (delete at next stop)\n"
2839 2839 " T event specifier is sticky (::delete all has no effect)\n"
2840 2840 " d event specifier will be disabled when HT = LM\n"
2841 2841 " D event specifier will be deleted when HT = LM\n"
2842 2842 " s target will automatically stop when HT = LM\n\n"
2843 2843 "HT hit count (number of times event has occurred)\n"
2844 2844 "LM hit limit (limit for autostop, disable, delete)\n");
2845 2845 }
2846 2846
2847 2847 static void
2848 2848 dump_help(void)
2849 2849 {
2850 2850 mdb_printf(
2851 2851 "-e adjust for endianness\n"
2852 2852 " (assumes 4-byte words; use -g to change word size)\n"
2853 2853 #ifdef _KMDB
2854 2854 "-f no effect\n"
2855 2855 #else
2856 2856 "-f dump from object file\n"
2857 2857 #endif
2858 2858 "-g n display bytes in groups of n\n"
2859 2859 " (default is 4; n must be a power of 2, divide line width)\n"
2860 2860 "-p dump from physical memory\n"
2861 2861 "-q don't print ASCII\n"
2862 2862 "-r use relative numbering (automatically sets -u)\n"
2863 2863 "-s elide repeated lines\n"
2864 2864 "-t only read from and display contents of specified addresses\n"
2865 2865 " (default is to read and print entire lines)\n"
2866 2866 "-u un-align output\n"
2867 2867 " (default is to align output at paragraph boundary)\n"
2868 2868 "-w n display n 16-byte paragraphs per line\n"
2869 2869 " (default is 1, maximum is 16)\n");
2870 2870 }
2871 2871
2872 2872 /*
2873 2873 * Table of built-in dcmds associated with the root 'mdb' module. Future
2874 2874 * expansion of this program should be done here, or through the external
2875 2875 * loadable module interface.
2876 2876 */
2877 2877 const mdb_dcmd_t mdb_dcmd_builtins[] = {
2878 2878
2879 2879 /*
2880 2880 * dcmds common to both mdb and kmdb
2881 2881 */
2882 2882 { ">", "variable-name", "assign variable", cmd_assign_variable },
2883 2883 { "/", "fmt-list", "format data from virtual as", cmd_print_core },
2884 2884 { "\\", "fmt-list", "format data from physical as", cmd_print_phys },
2885 2885 { "@", "fmt-list", "format data from physical as", cmd_print_phys },
2886 2886 { "=", "fmt-list", "format immediate value", cmd_print_value },
2887 2887 { "$<", "macro-name", "replace input with macro",
2888 2888 cmd_exec_file, srcexec_file_help },
2889 2889 { "$<<", "macro-name", "source macro",
2890 2890 cmd_src_file, srcexec_file_help},
2891 2891 { "$%", NULL, NULL, cmd_quit },
2892 2892 { "$?", NULL, "print status and registers", cmd_notsup },
2893 2893 { "$a", NULL, NULL, cmd_algol },
2894 2894 { "$b", "[-av]", "list traced software events",
2895 2895 cmd_events, events_help },
2896 2896 { "$c", "?[cnt]", "print stack backtrace", cmd_notsup },
2897 2897 { "$C", "?[cnt]", "print stack backtrace", cmd_notsup },
2898 2898 { "$d", NULL, "get/set default output radix", cmd_radix },
2899 2899 { "$D", "?[mode,...]", NULL, cmd_dbmode },
2900 2900 { "$e", NULL, "print listing of global symbols", cmd_globals },
2901 2901 { "$f", NULL, "print listing of source files", cmd_files },
2902 2902 { "$m", "?[name]", "print address space mappings", cmd_mappings },
2903 2903 { "$M", NULL, "list macro aliases", cmd_macalias_list },
2904 2904 { "$P", "[prompt]", "set debugger prompt string", cmd_prompt },
2905 2905 { "$q", NULL, "quit debugger", cmd_quit },
2906 2906 { "$Q", NULL, "quit debugger", cmd_quit },
2907 2907 { "$r", NULL, "print general-purpose registers", cmd_notsup },
2908 2908 { "$s", NULL, "get/set symbol matching distance", cmd_symdist },
2909 2909 { "$v", NULL, "print non-zero variables", cmd_nzvars },
2910 2910 { "$V", "[mode]", "get/set disassembly mode", cmd_dismode },
2911 2911 { "$w", NULL, "get/set output page width", cmd_pgwidth },
2912 2912 { "$W", NULL, "re-open target in write mode", cmd_reopen },
2913 2913 { ":a", ":[cmd...]", "set read access watchpoint", cmd_oldwpr },
2914 2914 { ":b", ":[cmd...]", "breakpoint at the specified address", cmd_oldbp },
2915 2915 { ":d", "?[id|all]", "delete traced software events", cmd_delete },
2916 2916 { ":p", ":[cmd...]", "set execute access watchpoint", cmd_oldwpx },
2917 2917 { ":S", NULL, NULL, cmd_step },
2918 2918 { ":w", ":[cmd...]", "set write access watchpoint", cmd_oldwpw },
2919 2919 { ":z", NULL, "delete all traced software events", cmd_zapall },
2920 2920 { "array", ":[type count] [variable]", "print each array element's "
2921 2921 "address", cmd_array },
2922 2922 { "bp", "?[+/-dDestT] [-c cmd] [-n count] sym ...", "breakpoint at the "
2923 2923 "specified addresses or symbols", cmd_bp, bp_help },
2924 2924 { "dcmds", NULL, "list available debugger commands", cmd_dcmds },
2925 2925 { "delete", "?[id|all]", "delete traced software events", cmd_delete },
2926 2926 { "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis },
2927 2927 { "disasms", NULL, "list available disassemblers", cmd_disasms },
2928 2928 { "dismode", "[mode]", "get/set disassembly mode", cmd_dismode },
2929 2929 { "dmods", "[-l] [mod]", "list loaded debugger modules", cmd_dmods },
2930 2930 { "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-w paragraphs]",
2931 2931 "dump memory from specified address", cmd_dump, dump_help },
2932 2932 { "echo", "args ...", "echo arguments", cmd_echo },
2933 2933 { "enum", "?[-ex] enum [name]", "print an enumeration", cmd_enum,
2934 2934 enum_help },
2935 2935 { "eval", "command", "evaluate the specified command", cmd_eval },
2936 2936 { "events", "[-av]", "list traced software events",
2937 2937 cmd_events, events_help },
2938 2938 { "evset", "?[+/-dDestT] [-c cmd] [-n count] id ...",
2939 2939 "set software event specifier attributes", cmd_evset, evset_help },
2940 2940 { "files", "[object]", "print listing of source files", cmd_files },
2941 2941 #ifdef __sparc
2942 2942 { "findsym", "?[-g] [symbol|addr ...]", "search for symbol references "
2943 2943 "in all known functions", cmd_findsym, NULL },
2944 2944 #endif
2945 2945 { "formats", NULL, "list format specifiers", cmd_formats },
2946 2946 { "grep", "?expr", "print dot if expression is true", cmd_grep },
2947 2947 { "head", "-num|-n num", "limit number of elements in pipe", cmd_head,
2948 2948 head_help },
2949 2949 { "help", "[cmd]", "list commands/command help", cmd_help },
2950 2950 { "list", "?type member [variable]",
2951 2951 "walk list using member as link pointer", cmd_list, NULL,
2952 2952 mdb_tab_complete_mt },
2953 2953 { "map", "?expr", "print dot after evaluating expression", cmd_map },
2954 2954 { "mappings", "?[name]", "print address space mappings", cmd_mappings },
2955 2955 { "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]",
2956 2956 "print symbols", cmd_nm, nm_help },
↓ open down ↓ |
2956 lines elided |
↑ open up ↑ |
2957 2957 { "nmadd", ":[-fo] [-e end] [-s size] name",
2958 2958 "add name to private symbol table", cmd_nmadd, nmadd_help },
2959 2959 { "nmdel", "name", "remove name from private symbol table", cmd_nmdel },
2960 2960 { "obey", NULL, NULL, cmd_obey },
2961 2961 { "objects", "[-v]", "print load objects information", cmd_objects },
2962 2962 { "offsetof", "type member", "print the offset of a given struct "
2963 2963 "or union member", cmd_offsetof, NULL, mdb_tab_complete_mt },
2964 2964 { "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]",
2965 2965 "print the contents of a data structure", cmd_print, print_help,
2966 2966 cmd_print_tab },
2967 + { "printf", "?format type member ...", "print and format the "
2968 + "member(s) of a data structure", cmd_printf, printf_help },
2967 2969 { "regs", NULL, "print general purpose registers", cmd_notsup },
2968 2970 { "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]",
2969 2971 "get/set debugger properties", cmd_set },
2970 2972 { "showrev", "[-pv]", "print version information", cmd_showrev },
2971 2973 { "sizeof", "type", "print the size of a type", cmd_sizeof, NULL,
2972 2974 cmd_sizeof_tab },
2973 2975 { "stack", "?[cnt]", "print stack backtrace", cmd_notsup },
2974 2976 { "stackregs", "?", "print stack backtrace and registers",
2975 2977 cmd_notsup },
2976 2978 { "status", NULL, "print summary of current target", cmd_notsup },
2977 2979 { "term", NULL, "display current terminal type", cmd_term },
2978 2980 { "typeset", "[+/-t] var ...", "set variable attributes", cmd_typeset },
2979 2981 { "unset", "[name ...]", "unset variables", cmd_unset },
2980 2982 { "vars", "[-npt]", "print listing of variables", cmd_vars },
2981 2983 { "version", NULL, "print debugger version string", cmd_version },
2982 2984 { "vtop", ":[-a as]", "print physical mapping of virtual address",
2983 2985 cmd_vtop },
2984 2986 { "walk", "?name [variable]", "walk data structure", cmd_walk, NULL,
2985 2987 cmd_walk_tab },
2986 2988 { "walkers", NULL, "list available walkers", cmd_walkers },
2987 2989 { "whatis", ":[-aikqv]", "given an address, return information",
2988 2990 cmd_whatis, whatis_help },
2989 2991 { "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2990 2992 { "which", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2991 2993 { "xdata", NULL, "print list of external data buffers", cmd_xdata },
2992 2994
2993 2995 #ifdef _KMDB
2994 2996 /*
2995 2997 * dcmds specific to kmdb, or which have kmdb-specific arguments
2996 2998 */
2997 2999 { "?", "fmt-list", "format data from virtual as", cmd_print_core },
2998 3000 { ":c", NULL, "continue target execution", cmd_cont },
2999 3001 { ":e", NULL, "step target over next instruction", cmd_next },
3000 3002 { ":s", NULL, "single-step target to next instruction", cmd_step },
3001 3003 { ":u", NULL, "step target out of current function", cmd_step_out },
3002 3004 { "cont", NULL, "continue target execution", cmd_cont },
3003 3005 { "load", "[-sd] module", "load debugger module", cmd_load, load_help },
3004 3006 { "next", NULL, "step target over next instruction", cmd_next },
3005 3007 { "quit", "[-u]", "quit debugger", cmd_quit, quit_help },
3006 3008 { "step", "[ over | out ]",
3007 3009 "single-step target to next instruction", cmd_step },
3008 3010 { "unload", "[-d] module", "unload debugger module", cmd_unload,
3009 3011 unload_help },
3010 3012 { "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]",
3011 3013 "set a watchpoint at the specified address", cmd_wp, wp_help },
3012 3014
3013 3015 #else
3014 3016 /*
3015 3017 * dcmds specific to mdb, or which have mdb-specific arguments
3016 3018 */
3017 3019 { "?", "fmt-list", "format data from object file", cmd_print_object },
3018 3020 { "$>", "[file]", "log session to a file", cmd_old_log },
3019 3021 { "$g", "?", "get/set C++ demangling options", cmd_demflags },
3020 3022 { "$G", NULL, "enable/disable C++ demangling support", cmd_demangle },
3021 3023 { "$i", NULL, "print signals that are ignored", cmd_notsup },
3022 3024 { "$l", NULL, "print the representative thread's lwp id", cmd_notsup },
3023 3025 { "$p", ":", "change debugger target context", cmd_context },
3024 3026 { "$x", NULL, "print floating point registers", cmd_notsup },
3025 3027 { "$X", NULL, "print floating point registers", cmd_notsup },
3026 3028 { "$y", NULL, "print floating point registers", cmd_notsup },
3027 3029 { "$Y", NULL, "print floating point registers", cmd_notsup },
3028 3030 { ":A", "?[core|pid]", "attach to process or core file", cmd_notsup },
3029 3031 { ":c", "[SIG]", "continue target execution", cmd_cont },
3030 3032 { ":e", "[SIG]", "step target over next instruction", cmd_next },
3031 3033 { ":i", ":", "ignore signal (delete all matching events)", cmd_notsup },
3032 3034 { ":k", NULL, "forcibly kill and release target", cmd_notsup },
3033 3035 { ":t", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on delivery "
3034 3036 "of the specified signals", cmd_sigbp, sigbp_help },
3035 3037 { ":r", "[ args ... ]", "run a new target process", cmd_run },
3036 3038 { ":R", NULL, "release the previously attached process", cmd_notsup },
3037 3039 { ":s", "[SIG]", "single-step target to next instruction", cmd_step },
3038 3040 { ":u", "[SIG]", "step target out of current function", cmd_step_out },
3039 3041 { "attach", "?[core|pid]",
3040 3042 "attach to process or core file", cmd_notsup },
3041 3043 { "cat", "[file ...]", "concatenate and display files", cmd_cat },
3042 3044 { "cont", "[SIG]", "continue target execution", cmd_cont },
3043 3045 { "context", ":", "change debugger target context", cmd_context },
3044 3046 { "dem", "name ...", "demangle C++ symbol names", cmd_demstr },
3045 3047 { "fltbp", "?[+/-dDestT] [-c cmd] [-n count] fault ...",
3046 3048 "stop on machine fault", cmd_fltbp, fltbp_help },
3047 3049 { "fpregs", NULL, "print floating point registers", cmd_notsup },
3048 3050 { "kill", NULL, "forcibly kill and release target", cmd_notsup },
3049 3051 { "load", "[-s] module", "load debugger module", cmd_load, load_help },
3050 3052 { "log", "[-d | [-e] file]", "log session to a file", cmd_log },
3051 3053 { "next", "[SIG]", "step target over next instruction", cmd_next },
3052 3054 { "quit", NULL, "quit debugger", cmd_quit },
3053 3055 { "release", NULL,
3054 3056 "release the previously attached process", cmd_notsup },
3055 3057 { "run", "[ args ... ]", "run a new target process", cmd_run },
3056 3058 { "sigbp", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on "
3057 3059 "delivery of the specified signals", cmd_sigbp, sigbp_help },
3058 3060 { "step", "[ over | out ] [SIG]",
3059 3061 "single-step target to next instruction", cmd_step },
3060 3062 { "sysbp", "?[+/-dDestT] [-io] [-c cmd] [-n count] syscall ...",
3061 3063 "stop on entry or exit from system call", cmd_sysbp, sysbp_help },
3062 3064 { "unload", "module", "unload debugger module", cmd_unload },
3063 3065 { "wp", ":[+/-dDelstT] [-rwx] [-c cmd] [-n count] [-L size]",
3064 3066 "set a watchpoint at the specified address", cmd_wp, wp_help },
3065 3067 #endif
3066 3068
3067 3069 { NULL }
3068 3070 };
↓ open down ↓ |
92 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX