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