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