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