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