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