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 }