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