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