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