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