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