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 2024 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 int 326 mdb_thread_name(mdb_tid_t tid, char *buf, size_t bufsize) 327 { 328 return (mdb_tgt_thread_name(mdb.m_target, tid, buf, bufsize)); 329 } 330 331 static u_longlong_t 332 mdb_strtoull_int(const char *s, int radix) 333 { 334 if (s[0] == '0') { 335 switch (s[1]) { 336 case 'I': 337 case 'i': 338 radix = 2; 339 s += 2; 340 break; 341 case 'O': 342 case 'o': 343 radix = 8; 344 s += 2; 345 break; 346 case 'T': 347 case 't': 348 radix = 10; 349 s += 2; 350 break; 351 case 'X': 352 case 'x': 353 radix = 16; 354 s += 2; 355 break; 356 } 357 } 358 359 return (mdb_strtonum(s, radix)); 360 } 361 362 u_longlong_t 363 mdb_strtoullx(const char *s, mdb_strtoull_flags_t flags) 364 { 365 int radix; 366 367 if ((flags & ~MDB_STRTOULL_F_BASE_C) != 0) { 368 mdb_warn("invalid options specified: 0x%lx" PRIx64 "\n", 369 (uint64_t)flags); 370 return ((uintmax_t)ULLONG_MAX); 371 } 372 373 if ((flags & MDB_STRTOULL_F_BASE_C) != 0) { 374 radix = 10; 375 } else { 376 radix = mdb.m_radix; 377 } 378 379 return (mdb_strtoull_int(s, radix)); 380 } 381 382 u_longlong_t 383 mdb_strtoull(const char *s) 384 { 385 return (mdb_strtoull_int(s, mdb.m_radix)); 386 } 387 388 size_t 389 mdb_snprintf(char *buf, size_t nbytes, const char *format, ...) 390 { 391 va_list alist; 392 393 va_start(alist, format); 394 nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist); 395 va_end(alist); 396 397 return (nbytes); 398 } 399 400 void 401 mdb_printf(const char *format, ...) 402 { 403 va_list alist; 404 405 va_start(alist, format); 406 mdb_iob_vprintf(mdb.m_out, format, alist); 407 va_end(alist); 408 } 409 410 void 411 mdb_warn(const char *format, ...) 412 { 413 va_list alist; 414 415 va_start(alist, format); 416 vwarn(format, alist); 417 va_end(alist); 418 } 419 420 void 421 mdb_flush(void) 422 { 423 mdb_iob_flush(mdb.m_out); 424 } 425 426 /* 427 * Convert an object of len bytes pointed to by srcraw between 428 * network-order and host-order and store in dstraw. The length len must 429 * be the actual length of the objects pointed to by srcraw and dstraw (or 430 * zero) or the results are undefined. srcraw and dstraw may be the same, 431 * in which case the object is converted in-place. Note that this routine 432 * will convert from host-order to network-order or network-order to 433 * host-order, since the conversion is the same in either case. 434 */ 435 /* ARGSUSED */ 436 void 437 mdb_nhconvert(void *dstraw, const void *srcraw, size_t len) 438 { 439 #ifdef _LITTLE_ENDIAN 440 uint8_t b1, b2; 441 uint8_t *dst, *src; 442 size_t i; 443 444 dst = (uint8_t *)dstraw; 445 src = (uint8_t *)srcraw; 446 for (i = 0; i < len / 2; i++) { 447 b1 = src[i]; 448 b2 = src[len - i - 1]; 449 dst[i] = b2; 450 dst[len - i - 1] = b1; 451 } 452 #else 453 if (dstraw != srcraw) 454 bcopy(srcraw, dstraw, len); 455 #endif 456 } 457 458 459 /* 460 * Bit formatting functions: Note the interesting use of UM_GC here to 461 * allocate a buffer for the caller which will be automatically freed 462 * when the dcmd completes or is forcibly aborted. 463 */ 464 465 #define NBNB (NBBY / 2) /* number of bits per nibble */ 466 #define SETBIT(buf, j, c) { \ 467 if (((j) + 1) % (NBNB + 1) == 0) \ 468 (buf)[(j)++] = ' '; \ 469 (buf)[(j)++] = (c); \ 470 } 471 472 const char * 473 mdb_one_bit(int width, int bit, int on) 474 { 475 int i, j = 0; 476 char *buf; 477 478 buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP); 479 480 for (i = --width; i > bit; i--) 481 SETBIT(buf, j, '.'); 482 483 SETBIT(buf, j, on ? '1' : '0'); 484 485 for (i = bit - 1; i >= 0; i--) 486 SETBIT(buf, j, '.'); 487 488 return (buf); 489 } 490 491 const char * 492 mdb_inval_bits(int width, int start, int stop) 493 { 494 int i, j = 0; 495 char *buf; 496 497 buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP); 498 499 for (i = --width; i > stop; i--) 500 SETBIT(buf, j, '.'); 501 502 for (i = stop; i >= start; i--) 503 SETBIT(buf, j, 'x'); 504 505 for (; i >= 0; i--) 506 SETBIT(buf, j, '.'); 507 508 return (buf); 509 } 510 511 ulong_t 512 mdb_inc_indent(ulong_t i) 513 { 514 if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) { 515 ulong_t margin = mdb_iob_getmargin(mdb.m_out); 516 mdb_iob_margin(mdb.m_out, margin + i); 517 return (margin); 518 } 519 520 mdb_iob_margin(mdb.m_out, i); 521 mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT); 522 return (0); 523 } 524 525 ulong_t 526 mdb_dec_indent(ulong_t i) 527 { 528 if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) { 529 ulong_t margin = mdb_iob_getmargin(mdb.m_out); 530 531 if (margin < i || margin - i == 0) { 532 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT); 533 mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN); 534 } else 535 mdb_iob_margin(mdb.m_out, margin - i); 536 537 return (margin); 538 } 539 540 return (0); 541 } 542 543 int 544 mdb_eval(const char *s) 545 { 546 mdb_frame_t *ofp = mdb.m_fmark; 547 mdb_frame_t *fp = mdb.m_frame; 548 int err; 549 550 if (s == NULL) 551 return (set_errno(EINVAL)); 552 553 /* 554 * Push m_in down onto the input stack, then set m_in to point to the 555 * i/o buffer for our command string, and reset the frame marker. 556 * The mdb_run() function returns when the new m_in iob reaches EOF. 557 */ 558 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno); 559 mdb.m_in = mdb_iob_create(mdb_strio_create(s), MDB_IOB_RDONLY); 560 561 mdb.m_fmark = NULL; 562 err = mdb_run(); 563 mdb.m_fmark = ofp; 564 565 /* 566 * Now pop the old standard input stream and restore mdb.m_in and 567 * the parser's saved current line number. 568 */ 569 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk); 570 yylineno = mdb_iob_lineno(mdb.m_in); 571 572 /* 573 * If mdb_run() returned an error, propagate this backward 574 * up the stack of debugger environment frames. 575 */ 576 if (MDB_ERR_IS_FATAL(err)) 577 longjmp(fp->f_pcb, err); 578 579 if (err == MDB_ERR_PAGER || err == MDB_ERR_SIGINT) 580 return (set_errno(EMDB_CANCEL)); 581 582 if (err != 0) 583 return (set_errno(EMDB_EVAL)); 584 585 return (0); 586 } 587 588 void 589 mdb_set_dot(uintmax_t addr) 590 { 591 mdb_nv_set_value(mdb.m_dot, addr); 592 mdb.m_incr = 0; 593 } 594 595 uintmax_t 596 mdb_get_dot(void) 597 { 598 return (mdb_nv_get_value(mdb.m_dot)); 599 } 600 601 static int 602 walk_step(mdb_wcb_t *wcb) 603 { 604 mdb_wcb_t *nwcb = wcb->w_lyr_head; 605 int status; 606 607 /* 608 * If the control block has no layers, we just invoke the walker's 609 * step function and return status indicating whether to continue 610 * or stop. If the control block has layers, we need to invoke 611 * ourself recursively for the next layer, until eventually we 612 * percolate down to an unlayered walk. 613 */ 614 if (nwcb == NULL) 615 return (wcb->w_walker->iwlk_step(&wcb->w_state)); 616 617 if ((status = walk_step(nwcb)) != WALK_NEXT) { 618 wcb->w_lyr_head = nwcb->w_lyr_link; 619 nwcb->w_lyr_link = NULL; 620 mdb_wcb_destroy(nwcb); 621 } 622 623 if (status == WALK_DONE && wcb->w_lyr_head != NULL) 624 return (WALK_NEXT); 625 626 return (status); 627 } 628 629 static int 630 walk_common(mdb_wcb_t *wcb) 631 { 632 int status, rval = 0; 633 mdb_frame_t *pfp; 634 635 /* 636 * Enter the control block in the active list so that mdb can clean 637 * up after it in case we abort out of the current command. 638 */ 639 if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL) 640 mdb_wcb_insert(wcb, pfp); 641 else 642 mdb_wcb_insert(wcb, mdb.m_frame); 643 644 /* 645 * The per-walk constructor performs private buffer initialization 646 * and locates whatever symbols are necessary. 647 */ 648 if ((status = wcb->w_walker->iwlk_init(&wcb->w_state)) != WALK_NEXT) { 649 if (status != WALK_DONE) 650 rval = set_errno(EMDB_WALKINIT); 651 goto done; 652 } 653 654 /* 655 * Mark wcb to indicate that walk_init has been called (which means 656 * we can call walk_fini if the walk is aborted at this point). 657 */ 658 wcb->w_inited = TRUE; 659 660 while (walk_step(wcb) == WALK_NEXT) 661 continue; 662 done: 663 if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL) 664 mdb_wcb_delete(wcb, pfp); 665 else 666 mdb_wcb_delete(wcb, mdb.m_frame); 667 668 mdb_wcb_destroy(wcb); 669 return (rval); 670 } 671 672 typedef struct pwalk_step { 673 mdb_walk_cb_t ps_cb; 674 void *ps_private; 675 } pwalk_step_t; 676 677 static int 678 pwalk_step(uintptr_t addr, const void *data, void *private) 679 { 680 pwalk_step_t *psp = private; 681 int ret; 682 683 mdb.m_frame->f_cbactive = B_TRUE; 684 ret = psp->ps_cb(addr, data, psp->ps_private); 685 mdb.m_frame->f_cbactive = B_FALSE; 686 687 return (ret); 688 } 689 690 int 691 mdb_pwalk(const char *name, mdb_walk_cb_t func, void *private, uintptr_t addr) 692 { 693 mdb_iwalker_t *iwp = mdb_walker_lookup(name); 694 pwalk_step_t p; 695 696 if (func == NULL) 697 return (set_errno(EINVAL)); 698 699 p.ps_cb = func; 700 p.ps_private = private; 701 702 if (iwp != NULL) { 703 int ret; 704 int cbactive = mdb.m_frame->f_cbactive; 705 mdb.m_frame->f_cbactive = B_FALSE; 706 ret = walk_common(mdb_wcb_create(iwp, pwalk_step, &p, addr)); 707 mdb.m_frame->f_cbactive = cbactive; 708 return (ret); 709 } 710 711 return (-1); /* errno is set for us */ 712 } 713 714 int 715 mdb_walk(const char *name, mdb_walk_cb_t func, void *data) 716 { 717 return (mdb_pwalk(name, func, data, 0)); 718 } 719 720 /*ARGSUSED*/ 721 static int 722 walk_dcmd(uintptr_t addr, const void *ignored, dcmd_walk_arg_t *dwp) 723 { 724 int status; 725 726 mdb.m_frame->f_cbactive = B_TRUE; 727 status = call_idcmd(dwp->dw_dcmd, addr, 1, dwp->dw_flags, 728 &dwp->dw_argv); 729 mdb.m_frame->f_cbactive = B_FALSE; 730 731 if (status == DCMD_USAGE || status == DCMD_ABORT) 732 return (WALK_ERR); 733 734 dwp->dw_flags &= ~DCMD_LOOPFIRST; 735 return (WALK_NEXT); 736 } 737 738 static int 739 i_mdb_pwalk_dcmd(const char *wname, const char *dcname, 740 int argc, const mdb_arg_t *argv, uintptr_t addr, uint_t flags) 741 { 742 mdb_argvec_t args; 743 dcmd_walk_arg_t dw; 744 mdb_iwalker_t *iwp; 745 mdb_wcb_t *wcb; 746 int status; 747 748 if (wname == NULL || dcname == NULL) 749 return (set_errno(EINVAL)); 750 751 if ((dw.dw_dcmd = mdb_dcmd_lookup(dcname)) == NULL) 752 return (-1); /* errno is set for us */ 753 754 if ((iwp = mdb_walker_lookup(wname)) == NULL) 755 return (-1); /* errno is set for us */ 756 757 args.a_data = (mdb_arg_t *)argv; 758 args.a_nelems = args.a_size = argc; 759 760 mdb_argvec_create(&dw.dw_argv); 761 mdb_argvec_copy(&dw.dw_argv, &args); 762 dw.dw_flags = flags | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC; 763 764 wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)walk_dcmd, &dw, addr); 765 status = walk_common(wcb); 766 767 mdb_argvec_zero(&dw.dw_argv); 768 mdb_argvec_destroy(&dw.dw_argv); 769 770 return (status); 771 } 772 773 int 774 mdb_pwalk_dcmd(const char *wname, const char *dcname, 775 int argc, const mdb_arg_t *argv, uintptr_t addr) 776 { 777 return (i_mdb_pwalk_dcmd(wname, dcname, argc, argv, addr, 0)); 778 } 779 780 int 781 mdb_fpwalk_dcmd(const char *wname, const char *dcname, 782 int argc, const mdb_arg_t *argv, uintptr_t addr, uint_t flags) 783 { 784 return (i_mdb_pwalk_dcmd(wname, dcname, argc, argv, addr, flags)); 785 } 786 787 788 int 789 mdb_walk_dcmd(const char *wname, const char *dcname, 790 int argc, const mdb_arg_t *argv) 791 { 792 return (i_mdb_pwalk_dcmd(wname, dcname, argc, argv, 0, 0)); 793 } 794 795 /*ARGSUSED*/ 796 static int 797 layered_walk_step(uintptr_t addr, const void *data, mdb_wcb_t *wcb) 798 { 799 /* 800 * Prior to calling the top-level walker's step function, reset its 801 * mdb_walk_state_t walk_addr and walk_layer members to refer to the 802 * target virtual address and data buffer of the underlying object. 803 */ 804 wcb->w_state.walk_addr = addr; 805 wcb->w_state.walk_layer = data; 806 807 return (wcb->w_walker->iwlk_step(&wcb->w_state)); 808 } 809 810 int 811 mdb_layered_walk(const char *wname, mdb_walk_state_t *wsp) 812 { 813 mdb_wcb_t *cwcb, *wcb; 814 mdb_iwalker_t *iwp; 815 816 if (wname == NULL || wsp == NULL) 817 return (set_errno(EINVAL)); 818 819 if ((iwp = mdb_walker_lookup(wname)) == NULL) 820 return (-1); /* errno is set for us */ 821 822 if ((cwcb = mdb_wcb_from_state(wsp)) == NULL) 823 return (set_errno(EMDB_BADWCB)); 824 825 if (cwcb->w_walker == iwp) 826 return (set_errno(EMDB_WALKLOOP)); 827 828 wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)layered_walk_step, 829 cwcb, wsp->walk_addr); 830 831 if (iwp->iwlk_init(&wcb->w_state) != WALK_NEXT) { 832 mdb_wcb_destroy(wcb); 833 return (set_errno(EMDB_WALKINIT)); 834 } 835 836 wcb->w_inited = TRUE; 837 838 mdb_dprintf(MDB_DBG_WALK, "added %s`%s as %s`%s layer\n", 839 iwp->iwlk_modp->mod_name, iwp->iwlk_name, 840 cwcb->w_walker->iwlk_modp->mod_name, cwcb->w_walker->iwlk_name); 841 842 if (cwcb->w_lyr_head != NULL) { 843 for (cwcb = cwcb->w_lyr_head; cwcb->w_lyr_link != NULL; ) 844 cwcb = cwcb->w_lyr_link; 845 cwcb->w_lyr_link = wcb; 846 } else 847 cwcb->w_lyr_head = wcb; 848 849 return (0); 850 } 851 852 int 853 mdb_call_dcmd(const char *name, uintptr_t dot, uint_t flags, 854 int argc, const mdb_arg_t *argv) 855 { 856 mdb_idcmd_t *idcp; 857 mdb_argvec_t args; 858 int status; 859 860 if (name == NULL || argc < 0) 861 return (set_errno(EINVAL)); 862 863 if ((idcp = mdb_dcmd_lookup(name)) == NULL) 864 return (-1); /* errno is set for us */ 865 866 args.a_data = (mdb_arg_t *)argv; 867 args.a_nelems = args.a_size = argc; 868 status = call_idcmd(idcp, dot, 1, flags, &args); 869 870 if (status == DCMD_ERR || status == DCMD_ABORT) 871 return (set_errno(EMDB_DCFAIL)); 872 873 if (status == DCMD_USAGE) 874 return (set_errno(EMDB_DCUSAGE)); 875 876 return (0); 877 } 878 879 /* 880 * When dcmds or walkers call a dcmd that might be in another module, 881 * we need to set mdb.m_frame->f_cp to an mdb_cmd that represents the 882 * dcmd we're currently executing, otherwise mdb_get_module gets the 883 * module of the caller instead of the module for the current dcmd. 884 */ 885 static int 886 call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count, 887 uint_t flags, mdb_argvec_t *argv) 888 { 889 mdb_cmd_t *save_cp; 890 mdb_cmd_t cmd; 891 int ret; 892 893 bzero(&cmd, sizeof (cmd)); 894 cmd.c_dcmd = idcp; 895 cmd.c_argv = *argv; 896 897 save_cp = mdb.m_frame->f_cp; 898 mdb.m_frame->f_cp = &cmd; 899 900 ret = mdb_call_idcmd(cmd.c_dcmd, addr, count, flags, 901 &cmd.c_argv, NULL, NULL); 902 903 mdb.m_frame->f_cp = save_cp; 904 905 return (ret); 906 } 907 908 int 909 mdb_add_walker(const mdb_walker_t *wp) 910 { 911 mdb_module_t *mp; 912 913 if (mdb.m_lmod == NULL) { 914 mdb_cmd_t *cp = mdb.m_frame->f_cp; 915 mp = cp->c_dcmd->idc_modp; 916 } else 917 mp = mdb.m_lmod; 918 919 return (mdb_module_add_walker(mp, wp, 0)); 920 } 921 922 int 923 mdb_remove_walker(const char *name) 924 { 925 mdb_module_t *mp; 926 927 if (mdb.m_lmod == NULL) { 928 mdb_cmd_t *cp = mdb.m_frame->f_cp; 929 mp = cp->c_dcmd->idc_modp; 930 } else 931 mp = mdb.m_lmod; 932 933 return (mdb_module_remove_walker(mp, name)); 934 } 935 936 void 937 mdb_get_pipe(mdb_pipe_t *p) 938 { 939 mdb_cmd_t *cp = mdb.m_frame->f_cp; 940 mdb_addrvec_t *adp = &cp->c_addrv; 941 942 if (p == NULL) { 943 warn("dcmd failure: mdb_get_pipe invoked with NULL pointer\n"); 944 longjmp(mdb.m_frame->f_pcb, MDB_ERR_API); 945 } 946 947 if (adp->ad_nelems != 0) { 948 ASSERT(adp->ad_ndx != 0); 949 p->pipe_data = &adp->ad_data[adp->ad_ndx - 1]; 950 p->pipe_len = adp->ad_nelems - adp->ad_ndx + 1; 951 adp->ad_ndx = adp->ad_nelems; 952 } else { 953 p->pipe_data = NULL; 954 p->pipe_len = 0; 955 } 956 } 957 958 void 959 mdb_set_pipe(const mdb_pipe_t *p) 960 { 961 mdb_cmd_t *cp = mdb.m_frame->f_pcmd; 962 963 if (p == NULL) { 964 warn("dcmd failure: mdb_set_pipe invoked with NULL pointer\n"); 965 longjmp(mdb.m_frame->f_pcb, MDB_ERR_API); 966 } 967 968 if (cp != NULL) { 969 size_t nbytes = sizeof (uintptr_t) * p->pipe_len; 970 971 mdb_cmd_reset(cp); 972 cp->c_addrv.ad_data = mdb_alloc(nbytes, UM_SLEEP); 973 bcopy(p->pipe_data, cp->c_addrv.ad_data, nbytes); 974 cp->c_addrv.ad_nelems = p->pipe_len; 975 cp->c_addrv.ad_size = p->pipe_len; 976 } 977 } 978 979 ssize_t 980 mdb_get_xdata(const char *name, void *buf, size_t nbytes) 981 { 982 return (mdb_tgt_getxdata(mdb.m_target, name, buf, nbytes)); 983 } 984 985 /* 986 * Private callback structure for implementing mdb_object_iter, below. 987 */ 988 typedef struct { 989 mdb_object_cb_t oi_cb; 990 void *oi_arg; 991 int oi_rval; 992 } object_iter_arg_t; 993 994 /*ARGSUSED*/ 995 static int 996 mdb_object_cb(void *data, const mdb_map_t *map, const char *fullname) 997 { 998 object_iter_arg_t *arg = data; 999 mdb_object_t obj; 1000 1001 if (arg->oi_rval != 0) 1002 return (0); 1003 1004 bzero(&obj, sizeof (obj)); 1005 obj.obj_base = map->map_base; 1006 obj.obj_name = strbasename(map->map_name); 1007 obj.obj_size = map->map_size; 1008 obj.obj_fullname = fullname; 1009 1010 arg->oi_rval = arg->oi_cb(&obj, arg->oi_arg); 1011 1012 return (0); 1013 } 1014 1015 int 1016 mdb_object_iter(mdb_object_cb_t cb, void *data) 1017 { 1018 object_iter_arg_t arg; 1019 1020 arg.oi_cb = cb; 1021 arg.oi_arg = data; 1022 arg.oi_rval = 0; 1023 1024 if (mdb_tgt_object_iter(mdb.m_target, mdb_object_cb, &arg) != 0) 1025 return (-1); 1026 1027 return (arg.oi_rval); 1028 } 1029 1030 /* 1031 * Private callback structure for implementing mdb_symbol_iter, below. 1032 */ 1033 typedef struct { 1034 mdb_symbol_cb_t si_cb; 1035 void *si_arg; 1036 int si_rval; 1037 } symbol_iter_arg_t; 1038 1039 /*ARGSUSED*/ 1040 static int 1041 mdb_symbol_cb(void *data, const GElf_Sym *gsym, const char *name, 1042 const mdb_syminfo_t *sip, const char *obj) 1043 { 1044 symbol_iter_arg_t *arg = data; 1045 mdb_symbol_t sym; 1046 1047 if (arg->si_rval != 0) 1048 return (0); 1049 1050 bzero(&sym, sizeof (sym)); 1051 sym.sym_name = name; 1052 sym.sym_object = obj; 1053 sym.sym_sym = gsym; 1054 sym.sym_table = sip->sym_table; 1055 sym.sym_id = sip->sym_id; 1056 1057 arg->si_rval = arg->si_cb(&sym, arg->si_arg); 1058 1059 return (0); 1060 } 1061 1062 int 1063 mdb_symbol_iter(const char *obj, uint_t which, uint_t type, 1064 mdb_symbol_cb_t cb, void *data) 1065 { 1066 symbol_iter_arg_t arg; 1067 1068 arg.si_cb = cb; 1069 arg.si_arg = data; 1070 arg.si_rval = 0; 1071 1072 if (mdb_tgt_symbol_iter(mdb.m_target, obj, which, type, 1073 mdb_symbol_cb, &arg) != 0) 1074 return (-1); 1075 1076 return (arg.si_rval); 1077 } 1078 1079 /* 1080 * Private structure and function for implementing mdb_dumpptr on top 1081 * of mdb_dump_internal 1082 */ 1083 typedef struct dptrdat { 1084 mdb_dumpptr_cb_t func; 1085 void *arg; 1086 } dptrdat_t; 1087 1088 static ssize_t 1089 mdb_dump_aux_ptr(void *buf, size_t nbyte, uint64_t offset, void *arg) 1090 { 1091 dptrdat_t *dat = arg; 1092 1093 return (dat->func(buf, nbyte, offset, dat->arg)); 1094 } 1095 1096 /* 1097 * Private structure and function for handling callbacks which return 1098 * EMDB_PARTIAL 1099 */ 1100 typedef struct d64dat { 1101 mdb_dump64_cb_t func; 1102 void *arg; 1103 } d64dat_t; 1104 1105 static ssize_t 1106 mdb_dump_aux_partial(void *buf, size_t nbyte, uint64_t offset, void *arg) 1107 { 1108 d64dat_t *dat = arg; 1109 int result; 1110 int count; 1111 1112 result = dat->func(buf, nbyte, offset, dat->arg); 1113 if (result == -1 && errno == EMDB_PARTIAL) { 1114 count = 0; 1115 do { 1116 result = dat->func((char *)buf + count, 1, 1117 offset + count, dat->arg); 1118 if (result == 1) 1119 count++; 1120 } while (count < nbyte && result == 1); 1121 if (count) 1122 result = count; 1123 } 1124 1125 return (result); 1126 } 1127 1128 /* Default callback for mdb_dumpptr() is calling mdb_vread(). */ 1129 static ssize_t 1130 mdb_dumpptr_cb(void *buf, size_t nbytes, uintptr_t addr, void *arg __unused) 1131 { 1132 return (mdb_vread(buf, nbytes, addr)); 1133 } 1134 1135 int 1136 mdb_dumpptr(uintptr_t addr, size_t len, uint_t flags, mdb_dumpptr_cb_t fp, 1137 void *arg) 1138 { 1139 dptrdat_t dat; 1140 d64dat_t dat64; 1141 1142 if (fp == NULL) 1143 dat.func = mdb_dumpptr_cb; 1144 else 1145 dat.func = fp; 1146 dat.arg = arg; 1147 dat64.func = mdb_dump_aux_ptr; 1148 dat64.arg = &dat; 1149 return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial, 1150 &dat64, sizeof (uintptr_t))); 1151 } 1152 1153 int 1154 mdb_dump64(uint64_t addr, uint64_t len, uint_t flags, mdb_dump64_cb_t fp, 1155 void *arg) 1156 { 1157 d64dat_t dat64; 1158 1159 dat64.func = fp; 1160 dat64.arg = arg; 1161 return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial, 1162 &dat64, sizeof (uint64_t))); 1163 } 1164 1165 int 1166 mdb_get_state(void) 1167 { 1168 mdb_tgt_status_t ts; 1169 1170 (void) mdb_tgt_status(mdb.m_target, &ts); 1171 1172 return (ts.st_state); 1173 } 1174 1175 void * 1176 mdb_callback_add(int class, mdb_callback_f fp, void *arg) 1177 { 1178 mdb_module_t *m; 1179 1180 if (class != MDB_CALLBACK_STCHG && class != MDB_CALLBACK_PROMPT) { 1181 (void) set_errno(EINVAL); 1182 return (NULL); 1183 } 1184 1185 if (mdb.m_lmod != NULL) 1186 m = mdb.m_lmod; 1187 else 1188 m = mdb.m_frame->f_cp->c_dcmd->idc_modp; 1189 1190 return (mdb_callb_add(m, class, fp, arg)); 1191 } 1192 1193 void 1194 mdb_callback_remove(void *hdl) 1195 { 1196 mdb_callb_remove(hdl); 1197 } 1198