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 }