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