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