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