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 }