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