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