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