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