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