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