1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2013 by Delphix. All rights reserved. 25 * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 26 * Copyright 2019 Joyent, Inc. 27 * Copyright 2022 Oxide Computer Company 28 */ 29 30 #include <mdb/mdb_modapi.h> 31 #include <mdb/mdb_module.h> 32 #include <mdb/mdb_string.h> 33 #include <mdb/mdb_debug.h> 34 #include <mdb/mdb_callb.h> 35 #include <mdb/mdb_dump.h> 36 #include <mdb/mdb_err.h> 37 #include <mdb/mdb_io.h> 38 #include <mdb/mdb_lex.h> 39 #include <mdb/mdb_frame.h> 40 #include <mdb/mdb.h> 41 #include <inttypes.h> 42 43 /* 44 * Private callback structure for implementing mdb_walk_dcmd, below. 45 */ 46 typedef struct { 47 mdb_idcmd_t *dw_dcmd; 48 mdb_argvec_t dw_argv; 49 uint_t dw_flags; 50 } dcmd_walk_arg_t; 51 52 /* 53 * Global properties which modules are allowed to look at. These are 54 * re-initialized by the target activation callbacks. 55 */ 56 int mdb_prop_postmortem = FALSE; /* Are we examining a dump? */ 57 int mdb_prop_kernel = FALSE; /* Are we examining a kernel? */ 58 int mdb_prop_datamodel = 0; /* Data model (see mdb_target_impl.h) */ 59 60 static int 61 call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count, 62 uint_t flags, mdb_argvec_t *argv); 63 64 int 65 mdb_snprintfrac(char *buf, int len, 66 uint64_t numerator, uint64_t denom, int frac_digits) 67 { 68 int mul = 1; 69 int whole, frac, i; 70 71 for (i = frac_digits; i; i--) 72 mul *= 10; 73 whole = numerator / denom; 74 frac = mul * numerator / denom - mul * whole; 75 return (mdb_snprintf(buf, len, "%u.%0*u", whole, frac_digits, frac)); 76 } 77 78 void 79 mdb_nicenum(uint64_t num, char *buf) 80 { 81 uint64_t n = num; 82 int index = 0; 83 char *u; 84 85 while (n >= 1024) { 86 n = (n + (1024 / 2)) / 1024; /* Round up or down */ 87 index++; 88 } 89 90 u = &" \0K\0M\0G\0T\0P\0E\0"[index*2]; 91 92 if (index == 0) { 93 (void) mdb_snprintf(buf, MDB_NICENUM_BUFLEN, "%llu", 94 (u_longlong_t)n); 95 } else if (n < 10 && (num & (num - 1)) != 0) { 96 (void) mdb_snprintfrac(buf, MDB_NICENUM_BUFLEN, 97 num, 1ULL << 10 * index, 2); 98 (void) strcat(buf, u); 99 } else if (n < 100 && (num & (num - 1)) != 0) { 100 (void) mdb_snprintfrac(buf, MDB_NICENUM_BUFLEN, 101 num, 1ULL << 10 * index, 1); 102 (void) strcat(buf, u); 103 } else { 104 (void) mdb_snprintf(buf, MDB_NICENUM_BUFLEN, "%llu%s", 105 (u_longlong_t)n, u); 106 } 107 } 108 109 ssize_t 110 mdb_vread(void *buf, size_t nbytes, uintptr_t addr) 111 { 112 ssize_t rbytes = mdb_tgt_vread(mdb.m_target, buf, nbytes, addr); 113 114 if (rbytes > 0 && rbytes < nbytes) 115 return (set_errbytes(rbytes, nbytes)); 116 117 return (rbytes); 118 } 119 120 ssize_t 121 mdb_vwrite(const void *buf, size_t nbytes, uintptr_t addr) 122 { 123 return (mdb_tgt_vwrite(mdb.m_target, buf, nbytes, addr)); 124 } 125 126 ssize_t 127 mdb_aread(void *buf, size_t nbytes, uintptr_t addr, void *as) 128 { 129 ssize_t rbytes = mdb_tgt_aread(mdb.m_target, as, buf, nbytes, addr); 130 131 if (rbytes > 0 && rbytes < nbytes) 132 return (set_errbytes(rbytes, nbytes)); 133 134 return (rbytes); 135 } 136 137 ssize_t 138 mdb_awrite(const void *buf, size_t nbytes, uintptr_t addr, void *as) 139 { 140 return (mdb_tgt_awrite(mdb.m_target, as, buf, nbytes, addr)); 141 } 142 143 ssize_t 144 mdb_fread(void *buf, size_t nbytes, uintptr_t addr) 145 { 146 ssize_t rbytes = mdb_tgt_fread(mdb.m_target, buf, nbytes, addr); 147 148 if (rbytes > 0 && rbytes < nbytes) 149 return (set_errbytes(rbytes, nbytes)); 150 151 return (rbytes); 152 } 153 154 ssize_t 155 mdb_fwrite(const void *buf, size_t nbytes, uintptr_t addr) 156 { 157 return (mdb_tgt_fwrite(mdb.m_target, buf, nbytes, addr)); 158 } 159 160 ssize_t 161 mdb_pread(void *buf, size_t nbytes, physaddr_t addr) 162 { 163 ssize_t rbytes = mdb_tgt_pread(mdb.m_target, buf, nbytes, addr); 164 165 if (rbytes > 0 && rbytes < nbytes) 166 return (set_errbytes(rbytes, nbytes)); 167 168 return (rbytes); 169 } 170 171 ssize_t 172 mdb_pwrite(const void *buf, size_t nbytes, physaddr_t addr) 173 { 174 return (mdb_tgt_pwrite(mdb.m_target, buf, nbytes, addr)); 175 } 176 177 ssize_t 178 mdb_readstr(char *buf, size_t nbytes, uintptr_t addr) 179 { 180 return (mdb_tgt_readstr(mdb.m_target, MDB_TGT_AS_VIRT, 181 buf, nbytes, addr)); 182 } 183 184 ssize_t 185 mdb_writestr(const char *buf, uintptr_t addr) 186 { 187 return (mdb_tgt_writestr(mdb.m_target, MDB_TGT_AS_VIRT, buf, addr)); 188 } 189 190 ssize_t 191 mdb_readsym(void *buf, size_t nbytes, const char *name) 192 { 193 ssize_t rbytes = mdb_tgt_readsym(mdb.m_target, MDB_TGT_AS_VIRT, 194 buf, nbytes, MDB_TGT_OBJ_EVERY, name); 195 196 if (rbytes > 0 && rbytes < nbytes) 197 return (set_errbytes(rbytes, nbytes)); 198 199 return (rbytes); 200 } 201 202 ssize_t 203 mdb_writesym(const void *buf, size_t nbytes, const char *name) 204 { 205 return (mdb_tgt_writesym(mdb.m_target, MDB_TGT_AS_VIRT, 206 buf, nbytes, MDB_TGT_OBJ_EVERY, name)); 207 } 208 209 ssize_t 210 mdb_readvar(void *buf, const char *name) 211 { 212 GElf_Sym sym; 213 214 if (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EVERY, 215 name, &sym, NULL)) 216 return (-1); 217 218 if (mdb_tgt_vread(mdb.m_target, buf, sym.st_size, 219 (uintptr_t)sym.st_value) == sym.st_size) 220 return ((ssize_t)sym.st_size); 221 222 return (-1); 223 } 224 225 ssize_t 226 mdb_writevar(const void *buf, const char *name) 227 { 228 GElf_Sym sym; 229 230 if (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EVERY, 231 name, &sym, NULL)) 232 return (-1); 233 234 if (mdb_tgt_vwrite(mdb.m_target, buf, sym.st_size, 235 (uintptr_t)sym.st_value) == sym.st_size) 236 return ((ssize_t)sym.st_size); 237 238 return (-1); 239 } 240 241 int 242 mdb_lookup_by_name(const char *name, GElf_Sym *sym) 243 { 244 return (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, name, sym)); 245 } 246 247 int 248 mdb_lookup_by_obj(const char *obj, const char *name, GElf_Sym *sym) 249 { 250 return (mdb_tgt_lookup_by_name(mdb.m_target, obj, name, sym, NULL)); 251 } 252 253 int 254 mdb_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf, 255 size_t nbytes, GElf_Sym *sym) 256 { 257 return (mdb_tgt_lookup_by_addr(mdb.m_target, addr, flags, 258 buf, nbytes, sym, NULL)); 259 } 260 261 int 262 mdb_getareg(mdb_tid_t tid, const char *rname, mdb_reg_t *rp) 263 { 264 return (mdb_tgt_getareg(mdb.m_target, tid, rname, rp)); 265 } 266 267 static u_longlong_t 268 mdb_strtoull_int(const char *s, int radix) 269 { 270 if (s[0] == '0') { 271 switch (s[1]) { 272 case 'I': 273 case 'i': 274 radix = 2; 275 s += 2; 276 break; 277 case 'O': 278 case 'o': 279 radix = 8; 280 s += 2; 281 break; 282 case 'T': 283 case 't': 284 radix = 10; 285 s += 2; 286 break; 287 case 'X': 288 case 'x': 289 radix = 16; 290 s += 2; 291 break; 292 } 293 } 294 295 return (mdb_strtonum(s, radix)); 296 } 297 298 u_longlong_t 299 mdb_strtoullx(const char *s, mdb_strtoull_flags_t flags) 300 { 301 int radix; 302 303 if ((flags & ~MDB_STRTOULL_F_BASE_C) != 0) { 304 mdb_warn("invalid options specified: 0x%lx" PRIx64 "\n", 305 (uint64_t)flags); 306 return ((uintmax_t)ULLONG_MAX); 307 } 308 309 if ((flags & MDB_STRTOULL_F_BASE_C) != 0) { 310 radix = 10; 311 } else { 312 radix = mdb.m_radix; 313 } 314 315 return (mdb_strtoull_int(s, radix)); 316 } 317 318 u_longlong_t 319 mdb_strtoull(const char *s) 320 { 321 return (mdb_strtoull_int(s, mdb.m_radix)); 322 } 323 324 size_t 325 mdb_snprintf(char *buf, size_t nbytes, const char *format, ...) 326 { 327 va_list alist; 328 329 va_start(alist, format); 330 nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist); 331 va_end(alist); 332 333 return (nbytes); 334 } 335 336 void 337 mdb_printf(const char *format, ...) 338 { 339 va_list alist; 340 341 va_start(alist, format); 342 mdb_iob_vprintf(mdb.m_out, format, alist); 343 va_end(alist); 344 } 345 346 void 347 mdb_warn(const char *format, ...) 348 { 349 va_list alist; 350 351 va_start(alist, format); 352 vwarn(format, alist); 353 va_end(alist); 354 } 355 356 void 357 mdb_flush(void) 358 { 359 mdb_iob_flush(mdb.m_out); 360 } 361 362 /* 363 * Convert an object of len bytes pointed to by srcraw between 364 * network-order and host-order and store in dstraw. The length len must 365 * be the actual length of the objects pointed to by srcraw and dstraw (or 366 * zero) or the results are undefined. srcraw and dstraw may be the same, 367 * in which case the object is converted in-place. Note that this routine 368 * will convert from host-order to network-order or network-order to 369 * host-order, since the conversion is the same in either case. 370 */ 371 /* ARGSUSED */ 372 void 373 mdb_nhconvert(void *dstraw, const void *srcraw, size_t len) 374 { 375 #ifdef _LITTLE_ENDIAN 376 uint8_t b1, b2; 377 uint8_t *dst, *src; 378 size_t i; 379 380 dst = (uint8_t *)dstraw; 381 src = (uint8_t *)srcraw; 382 for (i = 0; i < len / 2; i++) { 383 b1 = src[i]; 384 b2 = src[len - i - 1]; 385 dst[i] = b2; 386 dst[len - i - 1] = b1; 387 } 388 #else 389 if (dstraw != srcraw) 390 bcopy(srcraw, dstraw, len); 391 #endif 392 } 393 394 395 /* 396 * Bit formatting functions: Note the interesting use of UM_GC here to 397 * allocate a buffer for the caller which will be automatically freed 398 * when the dcmd completes or is forcibly aborted. 399 */ 400 401 #define NBNB (NBBY / 2) /* number of bits per nibble */ 402 #define SETBIT(buf, j, c) { \ 403 if (((j) + 1) % (NBNB + 1) == 0) \ 404 (buf)[(j)++] = ' '; \ 405 (buf)[(j)++] = (c); \ 406 } 407 408 const char * 409 mdb_one_bit(int width, int bit, int on) 410 { 411 int i, j = 0; 412 char *buf; 413 414 buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP); 415 416 for (i = --width; i > bit; i--) 417 SETBIT(buf, j, '.'); 418 419 SETBIT(buf, j, on ? '1' : '0'); 420 421 for (i = bit - 1; i >= 0; i--) 422 SETBIT(buf, j, '.'); 423 424 return (buf); 425 } 426 427 const char * 428 mdb_inval_bits(int width, int start, int stop) 429 { 430 int i, j = 0; 431 char *buf; 432 433 buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP); 434 435 for (i = --width; i > stop; i--) 436 SETBIT(buf, j, '.'); 437 438 for (i = stop; i >= start; i--) 439 SETBIT(buf, j, 'x'); 440 441 for (; i >= 0; i--) 442 SETBIT(buf, j, '.'); 443 444 return (buf); 445 } 446 447 ulong_t 448 mdb_inc_indent(ulong_t i) 449 { 450 if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) { 451 ulong_t margin = mdb_iob_getmargin(mdb.m_out); 452 mdb_iob_margin(mdb.m_out, margin + i); 453 return (margin); 454 } 455 456 mdb_iob_margin(mdb.m_out, i); 457 mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT); 458 return (0); 459 } 460 461 ulong_t 462 mdb_dec_indent(ulong_t i) 463 { 464 if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) { 465 ulong_t margin = mdb_iob_getmargin(mdb.m_out); 466 467 if (margin < i || margin - i == 0) { 468 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT); 469 mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN); 470 } else 471 mdb_iob_margin(mdb.m_out, margin - i); 472 473 return (margin); 474 } 475 476 return (0); 477 } 478 479 int 480 mdb_eval(const char *s) 481 { 482 mdb_frame_t *ofp = mdb.m_fmark; 483 mdb_frame_t *fp = mdb.m_frame; 484 int err; 485 486 if (s == NULL) 487 return (set_errno(EINVAL)); 488 489 /* 490 * Push m_in down onto the input stack, then set m_in to point to the 491 * i/o buffer for our command string, and reset the frame marker. 492 * The mdb_run() function returns when the new m_in iob reaches EOF. 493 */ 494 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno); 495 mdb.m_in = mdb_iob_create(mdb_strio_create(s), MDB_IOB_RDONLY); 496 497 mdb.m_fmark = NULL; 498 err = mdb_run(); 499 mdb.m_fmark = ofp; 500 501 /* 502 * Now pop the old standard input stream and restore mdb.m_in and 503 * the parser's saved current line number. 504 */ 505 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk); 506 yylineno = mdb_iob_lineno(mdb.m_in); 507 508 /* 509 * If mdb_run() returned an error, propagate this backward 510 * up the stack of debugger environment frames. 511 */ 512 if (MDB_ERR_IS_FATAL(err)) 513 longjmp(fp->f_pcb, err); 514 515 if (err == MDB_ERR_PAGER || err == MDB_ERR_SIGINT) 516 return (set_errno(EMDB_CANCEL)); 517 518 if (err != 0) 519 return (set_errno(EMDB_EVAL)); 520 521 return (0); 522 } 523 524 void 525 mdb_set_dot(uintmax_t addr) 526 { 527 mdb_nv_set_value(mdb.m_dot, addr); 528 mdb.m_incr = 0; 529 } 530 531 uintmax_t 532 mdb_get_dot(void) 533 { 534 return (mdb_nv_get_value(mdb.m_dot)); 535 } 536 537 static int 538 walk_step(mdb_wcb_t *wcb) 539 { 540 mdb_wcb_t *nwcb = wcb->w_lyr_head; 541 int status; 542 543 /* 544 * If the control block has no layers, we just invoke the walker's 545 * step function and return status indicating whether to continue 546 * or stop. If the control block has layers, we need to invoke 547 * ourself recursively for the next layer, until eventually we 548 * percolate down to an unlayered walk. 549 */ 550 if (nwcb == NULL) 551 return (wcb->w_walker->iwlk_step(&wcb->w_state)); 552 553 if ((status = walk_step(nwcb)) != WALK_NEXT) { 554 wcb->w_lyr_head = nwcb->w_lyr_link; 555 nwcb->w_lyr_link = NULL; 556 mdb_wcb_destroy(nwcb); 557 } 558 559 if (status == WALK_DONE && wcb->w_lyr_head != NULL) 560 return (WALK_NEXT); 561 562 return (status); 563 } 564 565 static int 566 walk_common(mdb_wcb_t *wcb) 567 { 568 int status, rval = 0; 569 mdb_frame_t *pfp; 570 571 /* 572 * Enter the control block in the active list so that mdb can clean 573 * up after it in case we abort out of the current command. 574 */ 575 if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL) 576 mdb_wcb_insert(wcb, pfp); 577 else 578 mdb_wcb_insert(wcb, mdb.m_frame); 579 580 /* 581 * The per-walk constructor performs private buffer initialization 582 * and locates whatever symbols are necessary. 583 */ 584 if ((status = wcb->w_walker->iwlk_init(&wcb->w_state)) != WALK_NEXT) { 585 if (status != WALK_DONE) 586 rval = set_errno(EMDB_WALKINIT); 587 goto done; 588 } 589 590 /* 591 * Mark wcb to indicate that walk_init has been called (which means 592 * we can call walk_fini if the walk is aborted at this point). 593 */ 594 wcb->w_inited = TRUE; 595 596 while (walk_step(wcb) == WALK_NEXT) 597 continue; 598 done: 599 if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL) 600 mdb_wcb_delete(wcb, pfp); 601 else 602 mdb_wcb_delete(wcb, mdb.m_frame); 603 604 mdb_wcb_destroy(wcb); 605 return (rval); 606 } 607 608 typedef struct pwalk_step { 609 mdb_walk_cb_t ps_cb; 610 void *ps_private; 611 } pwalk_step_t; 612 613 static int 614 pwalk_step(uintptr_t addr, const void *data, void *private) 615 { 616 pwalk_step_t *psp = private; 617 int ret; 618 619 mdb.m_frame->f_cbactive = B_TRUE; 620 ret = psp->ps_cb(addr, data, psp->ps_private); 621 mdb.m_frame->f_cbactive = B_FALSE; 622 623 return (ret); 624 } 625 626 int 627 mdb_pwalk(const char *name, mdb_walk_cb_t func, void *private, uintptr_t addr) 628 { 629 mdb_iwalker_t *iwp = mdb_walker_lookup(name); 630 pwalk_step_t p; 631 632 if (func == NULL) 633 return (set_errno(EINVAL)); 634 635 p.ps_cb = func; 636 p.ps_private = private; 637 638 if (iwp != NULL) { 639 int ret; 640 int cbactive = mdb.m_frame->f_cbactive; 641 mdb.m_frame->f_cbactive = B_FALSE; 642 ret = walk_common(mdb_wcb_create(iwp, pwalk_step, &p, addr)); 643 mdb.m_frame->f_cbactive = cbactive; 644 return (ret); 645 } 646 647 return (-1); /* errno is set for us */ 648 } 649 650 int 651 mdb_walk(const char *name, mdb_walk_cb_t func, void *data) 652 { 653 return (mdb_pwalk(name, func, data, 0)); 654 } 655 656 /*ARGSUSED*/ 657 static int 658 walk_dcmd(uintptr_t addr, const void *ignored, dcmd_walk_arg_t *dwp) 659 { 660 int status; 661 662 mdb.m_frame->f_cbactive = B_TRUE; 663 status = call_idcmd(dwp->dw_dcmd, addr, 1, dwp->dw_flags, 664 &dwp->dw_argv); 665 mdb.m_frame->f_cbactive = B_FALSE; 666 667 if (status == DCMD_USAGE || status == DCMD_ABORT) 668 return (WALK_ERR); 669 670 dwp->dw_flags &= ~DCMD_LOOPFIRST; 671 return (WALK_NEXT); 672 } 673 674 int 675 mdb_pwalk_dcmd(const char *wname, const char *dcname, 676 int argc, const mdb_arg_t *argv, uintptr_t addr) 677 { 678 mdb_argvec_t args; 679 dcmd_walk_arg_t dw; 680 mdb_iwalker_t *iwp; 681 mdb_wcb_t *wcb; 682 int status; 683 684 if (wname == NULL || dcname == NULL) 685 return (set_errno(EINVAL)); 686 687 if ((dw.dw_dcmd = mdb_dcmd_lookup(dcname)) == NULL) 688 return (-1); /* errno is set for us */ 689 690 if ((iwp = mdb_walker_lookup(wname)) == NULL) 691 return (-1); /* errno is set for us */ 692 693 args.a_data = (mdb_arg_t *)argv; 694 args.a_nelems = args.a_size = argc; 695 696 mdb_argvec_create(&dw.dw_argv); 697 mdb_argvec_copy(&dw.dw_argv, &args); 698 dw.dw_flags = DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC; 699 700 wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)walk_dcmd, &dw, addr); 701 status = walk_common(wcb); 702 703 mdb_argvec_zero(&dw.dw_argv); 704 mdb_argvec_destroy(&dw.dw_argv); 705 706 return (status); 707 } 708 709 int 710 mdb_walk_dcmd(const char *wname, const char *dcname, 711 int argc, const mdb_arg_t *argv) 712 { 713 return (mdb_pwalk_dcmd(wname, dcname, argc, argv, 0)); 714 } 715 716 /*ARGSUSED*/ 717 static int 718 layered_walk_step(uintptr_t addr, const void *data, mdb_wcb_t *wcb) 719 { 720 /* 721 * Prior to calling the top-level walker's step function, reset its 722 * mdb_walk_state_t walk_addr and walk_layer members to refer to the 723 * target virtual address and data buffer of the underlying object. 724 */ 725 wcb->w_state.walk_addr = addr; 726 wcb->w_state.walk_layer = data; 727 728 return (wcb->w_walker->iwlk_step(&wcb->w_state)); 729 } 730 731 int 732 mdb_layered_walk(const char *wname, mdb_walk_state_t *wsp) 733 { 734 mdb_wcb_t *cwcb, *wcb; 735 mdb_iwalker_t *iwp; 736 737 if (wname == NULL || wsp == NULL) 738 return (set_errno(EINVAL)); 739 740 if ((iwp = mdb_walker_lookup(wname)) == NULL) 741 return (-1); /* errno is set for us */ 742 743 if ((cwcb = mdb_wcb_from_state(wsp)) == NULL) 744 return (set_errno(EMDB_BADWCB)); 745 746 if (cwcb->w_walker == iwp) 747 return (set_errno(EMDB_WALKLOOP)); 748 749 wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)layered_walk_step, 750 cwcb, wsp->walk_addr); 751 752 if (iwp->iwlk_init(&wcb->w_state) != WALK_NEXT) { 753 mdb_wcb_destroy(wcb); 754 return (set_errno(EMDB_WALKINIT)); 755 } 756 757 wcb->w_inited = TRUE; 758 759 mdb_dprintf(MDB_DBG_WALK, "added %s`%s as %s`%s layer\n", 760 iwp->iwlk_modp->mod_name, iwp->iwlk_name, 761 cwcb->w_walker->iwlk_modp->mod_name, cwcb->w_walker->iwlk_name); 762 763 if (cwcb->w_lyr_head != NULL) { 764 for (cwcb = cwcb->w_lyr_head; cwcb->w_lyr_link != NULL; ) 765 cwcb = cwcb->w_lyr_link; 766 cwcb->w_lyr_link = wcb; 767 } else 768 cwcb->w_lyr_head = wcb; 769 770 return (0); 771 } 772 773 int 774 mdb_call_dcmd(const char *name, uintptr_t dot, uint_t flags, 775 int argc, const mdb_arg_t *argv) 776 { 777 mdb_idcmd_t *idcp; 778 mdb_argvec_t args; 779 int status; 780 781 if (name == NULL || argc < 0) 782 return (set_errno(EINVAL)); 783 784 if ((idcp = mdb_dcmd_lookup(name)) == NULL) 785 return (-1); /* errno is set for us */ 786 787 args.a_data = (mdb_arg_t *)argv; 788 args.a_nelems = args.a_size = argc; 789 status = call_idcmd(idcp, dot, 1, flags, &args); 790 791 if (status == DCMD_ERR || status == DCMD_ABORT) 792 return (set_errno(EMDB_DCFAIL)); 793 794 if (status == DCMD_USAGE) 795 return (set_errno(EMDB_DCUSAGE)); 796 797 return (0); 798 } 799 800 /* 801 * When dcmds or walkers call a dcmd that might be in another module, 802 * we need to set mdb.m_frame->f_cp to an mdb_cmd that represents the 803 * dcmd we're currently executing, otherwise mdb_get_module gets the 804 * module of the caller instead of the module for the current dcmd. 805 */ 806 static int 807 call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count, 808 uint_t flags, mdb_argvec_t *argv) 809 { 810 mdb_cmd_t *save_cp; 811 mdb_cmd_t cmd; 812 int ret; 813 814 bzero(&cmd, sizeof (cmd)); 815 cmd.c_dcmd = idcp; 816 cmd.c_argv = *argv; 817 818 save_cp = mdb.m_frame->f_cp; 819 mdb.m_frame->f_cp = &cmd; 820 821 ret = mdb_call_idcmd(cmd.c_dcmd, addr, count, flags, 822 &cmd.c_argv, NULL, NULL); 823 824 mdb.m_frame->f_cp = save_cp; 825 826 return (ret); 827 } 828 829 int 830 mdb_add_walker(const mdb_walker_t *wp) 831 { 832 mdb_module_t *mp; 833 834 if (mdb.m_lmod == NULL) { 835 mdb_cmd_t *cp = mdb.m_frame->f_cp; 836 mp = cp->c_dcmd->idc_modp; 837 } else 838 mp = mdb.m_lmod; 839 840 return (mdb_module_add_walker(mp, wp, 0)); 841 } 842 843 int 844 mdb_remove_walker(const char *name) 845 { 846 mdb_module_t *mp; 847 848 if (mdb.m_lmod == NULL) { 849 mdb_cmd_t *cp = mdb.m_frame->f_cp; 850 mp = cp->c_dcmd->idc_modp; 851 } else 852 mp = mdb.m_lmod; 853 854 return (mdb_module_remove_walker(mp, name)); 855 } 856 857 void 858 mdb_get_pipe(mdb_pipe_t *p) 859 { 860 mdb_cmd_t *cp = mdb.m_frame->f_cp; 861 mdb_addrvec_t *adp = &cp->c_addrv; 862 863 if (p == NULL) { 864 warn("dcmd failure: mdb_get_pipe invoked with NULL pointer\n"); 865 longjmp(mdb.m_frame->f_pcb, MDB_ERR_API); 866 } 867 868 if (adp->ad_nelems != 0) { 869 ASSERT(adp->ad_ndx != 0); 870 p->pipe_data = &adp->ad_data[adp->ad_ndx - 1]; 871 p->pipe_len = adp->ad_nelems - adp->ad_ndx + 1; 872 adp->ad_ndx = adp->ad_nelems; 873 } else { 874 p->pipe_data = NULL; 875 p->pipe_len = 0; 876 } 877 } 878 879 void 880 mdb_set_pipe(const mdb_pipe_t *p) 881 { 882 mdb_cmd_t *cp = mdb.m_frame->f_pcmd; 883 884 if (p == NULL) { 885 warn("dcmd failure: mdb_set_pipe invoked with NULL pointer\n"); 886 longjmp(mdb.m_frame->f_pcb, MDB_ERR_API); 887 } 888 889 if (cp != NULL) { 890 size_t nbytes = sizeof (uintptr_t) * p->pipe_len; 891 892 mdb_cmd_reset(cp); 893 cp->c_addrv.ad_data = mdb_alloc(nbytes, UM_SLEEP); 894 bcopy(p->pipe_data, cp->c_addrv.ad_data, nbytes); 895 cp->c_addrv.ad_nelems = p->pipe_len; 896 cp->c_addrv.ad_size = p->pipe_len; 897 } 898 } 899 900 ssize_t 901 mdb_get_xdata(const char *name, void *buf, size_t nbytes) 902 { 903 return (mdb_tgt_getxdata(mdb.m_target, name, buf, nbytes)); 904 } 905 906 /* 907 * Private callback structure for implementing mdb_object_iter, below. 908 */ 909 typedef struct { 910 mdb_object_cb_t oi_cb; 911 void *oi_arg; 912 int oi_rval; 913 } object_iter_arg_t; 914 915 /*ARGSUSED*/ 916 static int 917 mdb_object_cb(void *data, const mdb_map_t *map, const char *fullname) 918 { 919 object_iter_arg_t *arg = data; 920 mdb_object_t obj; 921 922 if (arg->oi_rval != 0) 923 return (0); 924 925 bzero(&obj, sizeof (obj)); 926 obj.obj_base = map->map_base; 927 obj.obj_name = strbasename(map->map_name); 928 obj.obj_size = map->map_size; 929 obj.obj_fullname = fullname; 930 931 arg->oi_rval = arg->oi_cb(&obj, arg->oi_arg); 932 933 return (0); 934 } 935 936 int 937 mdb_object_iter(mdb_object_cb_t cb, void *data) 938 { 939 object_iter_arg_t arg; 940 941 arg.oi_cb = cb; 942 arg.oi_arg = data; 943 arg.oi_rval = 0; 944 945 if (mdb_tgt_object_iter(mdb.m_target, mdb_object_cb, &arg) != 0) 946 return (-1); 947 948 return (arg.oi_rval); 949 } 950 951 /* 952 * Private callback structure for implementing mdb_symbol_iter, below. 953 */ 954 typedef struct { 955 mdb_symbol_cb_t si_cb; 956 void *si_arg; 957 int si_rval; 958 } symbol_iter_arg_t; 959 960 /*ARGSUSED*/ 961 static int 962 mdb_symbol_cb(void *data, const GElf_Sym *gsym, const char *name, 963 const mdb_syminfo_t *sip, const char *obj) 964 { 965 symbol_iter_arg_t *arg = data; 966 mdb_symbol_t sym; 967 968 if (arg->si_rval != 0) 969 return (0); 970 971 bzero(&sym, sizeof (sym)); 972 sym.sym_name = name; 973 sym.sym_object = obj; 974 sym.sym_sym = gsym; 975 sym.sym_table = sip->sym_table; 976 sym.sym_id = sip->sym_id; 977 978 arg->si_rval = arg->si_cb(&sym, arg->si_arg); 979 980 return (0); 981 } 982 983 int 984 mdb_symbol_iter(const char *obj, uint_t which, uint_t type, 985 mdb_symbol_cb_t cb, void *data) 986 { 987 symbol_iter_arg_t arg; 988 989 arg.si_cb = cb; 990 arg.si_arg = data; 991 arg.si_rval = 0; 992 993 if (mdb_tgt_symbol_iter(mdb.m_target, obj, which, type, 994 mdb_symbol_cb, &arg) != 0) 995 return (-1); 996 997 return (arg.si_rval); 998 } 999 1000 /* 1001 * Private structure and function for implementing mdb_dumpptr on top 1002 * of mdb_dump_internal 1003 */ 1004 typedef struct dptrdat { 1005 mdb_dumpptr_cb_t func; 1006 void *arg; 1007 } dptrdat_t; 1008 1009 static ssize_t 1010 mdb_dump_aux_ptr(void *buf, size_t nbyte, uint64_t offset, void *arg) 1011 { 1012 dptrdat_t *dat = arg; 1013 1014 return (dat->func(buf, nbyte, offset, dat->arg)); 1015 } 1016 1017 /* 1018 * Private structure and function for handling callbacks which return 1019 * EMDB_PARTIAL 1020 */ 1021 typedef struct d64dat { 1022 mdb_dump64_cb_t func; 1023 void *arg; 1024 } d64dat_t; 1025 1026 static ssize_t 1027 mdb_dump_aux_partial(void *buf, size_t nbyte, uint64_t offset, void *arg) 1028 { 1029 d64dat_t *dat = arg; 1030 int result; 1031 int count; 1032 1033 result = dat->func(buf, nbyte, offset, dat->arg); 1034 if (result == -1 && errno == EMDB_PARTIAL) { 1035 count = 0; 1036 do { 1037 result = dat->func((char *)buf + count, 1, 1038 offset + count, dat->arg); 1039 if (result == 1) 1040 count++; 1041 } while (count < nbyte && result == 1); 1042 if (count) 1043 result = count; 1044 } 1045 1046 return (result); 1047 } 1048 1049 /* Default callback for mdb_dumpptr() is calling mdb_vread(). */ 1050 static ssize_t 1051 mdb_dumpptr_cb(void *buf, size_t nbytes, uintptr_t addr, void *arg __unused) 1052 { 1053 return (mdb_vread(buf, nbytes, addr)); 1054 } 1055 1056 int 1057 mdb_dumpptr(uintptr_t addr, size_t len, uint_t flags, mdb_dumpptr_cb_t fp, 1058 void *arg) 1059 { 1060 dptrdat_t dat; 1061 d64dat_t dat64; 1062 1063 if (fp == NULL) 1064 dat.func = mdb_dumpptr_cb; 1065 else 1066 dat.func = fp; 1067 dat.arg = arg; 1068 dat64.func = mdb_dump_aux_ptr; 1069 dat64.arg = &dat; 1070 return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial, 1071 &dat64, sizeof (uintptr_t))); 1072 } 1073 1074 int 1075 mdb_dump64(uint64_t addr, uint64_t len, uint_t flags, mdb_dump64_cb_t fp, 1076 void *arg) 1077 { 1078 d64dat_t dat64; 1079 1080 dat64.func = fp; 1081 dat64.arg = arg; 1082 return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial, 1083 &dat64, sizeof (uint64_t))); 1084 } 1085 1086 int 1087 mdb_get_state(void) 1088 { 1089 mdb_tgt_status_t ts; 1090 1091 (void) mdb_tgt_status(mdb.m_target, &ts); 1092 1093 return (ts.st_state); 1094 } 1095 1096 void * 1097 mdb_callback_add(int class, mdb_callback_f fp, void *arg) 1098 { 1099 mdb_module_t *m; 1100 1101 if (class != MDB_CALLBACK_STCHG && class != MDB_CALLBACK_PROMPT) { 1102 (void) set_errno(EINVAL); 1103 return (NULL); 1104 } 1105 1106 if (mdb.m_lmod != NULL) 1107 m = mdb.m_lmod; 1108 else 1109 m = mdb.m_frame->f_cp->c_dcmd->idc_modp; 1110 1111 return (mdb_callb_add(m, class, fp, arg)); 1112 } 1113 1114 void 1115 mdb_callback_remove(void *hdl) 1116 { 1117 mdb_callb_remove(hdl); 1118 } 1119