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