]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_examine.c
19a46186a0e41bf0db78455854b21370de55ba2d
[apple/xnu.git] / osfmk / ddb / db_examine.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * HISTORY
27 *
28 * Revision 1.1.1.1 1998/09/22 21:05:47 wsanchez
29 * Import of Mac OS X kernel (~semeria)
30 *
31 * Revision 1.2 1998/04/24 19:34:23 semeria
32 * KDP and KDB support
33 *
34 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
35 * Import of OSF Mach kernel (~mburg)
36 *
37 * Revision 1.2.42.2 1997/09/12 17:15:15 stephen
38 * make x/x do zero fill right justified hex display
39 * [1997/09/12 16:31:04 stephen]
40 *
41 * Revision 1.2.42.1 1997/03/27 18:46:31 barbou
42 * Add 'p' option to the "examine" command - values in
43 * memory treated as addresses and rendered as sym+offset
44 * [1995/12/29 21:32:33 mod]
45 * ri-osc CR1560: make search command output address of any matching
46 * data it finds (so user knows it did something).
47 * [1995/09/20 15:24:55 bolinger]
48 * [97/02/25 barbou]
49 *
50 * Revision 1.2.25.5 1996/01/09 19:15:38 devrcs
51 * Add db_print_loc() & db_print_inst() functions.
52 * Make 'l' display 32 bits and new 'q' to display 64 bits.
53 * Allow 'u' to display unsigned decimal values (same as 'U').
54 * Changed declarations of 'register foo' to 'register int foo'.
55 * [1995/12/01 21:42:03 jfraser]
56 *
57 * Merged '64-bit safe' changes from DEC alpha port.
58 * [1995/11/21 18:02:58 jfraser]
59 *
60 * Revision 1.2.25.4 1995/06/13 18:21:27 sjs
61 * Merge with flipc_shared.
62 * [95/05/22 sjs]
63 *
64 * Revision 1.2.30.1 1995/04/03 17:35:17 randys
65 * Minor change; allow a repeat count to work properly when multiple
66 * modifier flags are given to the ddb 'x' command. This allows,
67 * for instance, examination of multiple words in activations other
68 * than the current one.
69 * [95/04/03 randys]
70 *
71 * Revision 1.2.25.3 1995/01/06 19:10:09 devrcs
72 * mk6 CR668 - 1.3b26 merge
73 * * Revision 1.2.6.7 1994/05/06 18:39:09 tmt
74 * Merged osc1.3dec/shared with osc1.3b19
75 * Merge Alpha changes into osc1.312b source code.
76 * 64bit cleanup.
77 * * End1.3merge
78 * [1994/11/04 08:49:22 dwm]
79 *
80 * Revision 1.2.25.2 1994/09/23 01:18:44 ezf
81 * change marker to not FREE
82 * [1994/09/22 21:09:44 ezf]
83 *
84 * Revision 1.2.25.1 1994/06/11 21:11:43 bolinger
85 * Merge up to NMK17.2.
86 * [1994/06/11 20:01:31 bolinger]
87 *
88 * Revision 1.2.23.1 1994/02/08 10:57:47 bernadat
89 * Fixed output of an examine command to have a power of 2
90 * number of fields.
91 * [93/09/29 paire]
92 *
93 * Added dump of hexadecimal address in each line of examine command.
94 * Fixed beginning of line to be always located at position 0.
95 * [93/08/11 paire]
96 * [94/02/07 bernadat]
97 *
98 * Revision 1.2.21.4 1994/03/17 22:35:27 dwm
99 * The infamous name change: thread_activation + thread_shuttle = thread.
100 * [1994/03/17 21:25:43 dwm]
101 *
102 * Revision 1.2.21.3 1994/01/12 17:50:40 dwm
103 * Coloc: initial restructuring to follow Utah model.
104 * [1994/01/12 17:13:08 dwm]
105 *
106 * Revision 1.2.21.2 1993/10/12 16:38:58 dwm
107 * Print '\n' in x/s statements. [rwd]
108 * [1993/10/12 16:14:41 dwm]
109 *
110 * Revision 1.2.6.5 1993/08/11 20:37:37 elliston
111 * Add ANSI Prototypes. CR #9523.
112 * [1993/08/11 03:33:05 elliston]
113 *
114 * Revision 1.2.6.4 1993/08/09 19:34:42 dswartz
115 * Add ANSI prototypes - CR#9523
116 * [1993/08/06 15:47:32 dswartz]
117 *
118 * Revision 1.2.6.3 1993/07/27 18:27:07 elliston
119 * Add ANSI prototypes. CR #9523.
120 * [1993/07/27 18:11:21 elliston]
121 *
122 * Revision 1.2.6.2 1993/06/09 02:20:00 gm
123 * Added to OSF/1 R1.3 from NMK15.0.
124 * [1993/06/02 20:56:10 jeffc]
125 *
126 * Revision 1.2 1993/04/19 16:01:58 devrcs
127 * Changes from mk78:
128 * Added void type to functions that needed it.
129 * Added init to 'size' in db_search_cmd(). Removed unused variables.
130 * Other cleanup to quiet gcc warnings.
131 * [92/05/16 jfriedl]
132 * x/u now examines current user space. x/t still examines user
133 * space of the the specified thread. x/tu is redundant.
134 * To examine an value as unsigned decimal, use x/U.
135 * [92/04/18 danner]
136 * [93/02/02 bruel]
137 *
138 * Remember count argument when repeating commands instead of the
139 * default command, also apply all the formats to current address
140 * instead of incrementing addresses when switching to next format.
141 * [barbou@gr.osf.org]
142 *
143 * Support 'A' format for print 'p' command [barbou@gr.osf.org]
144 * [92/12/03 bernadat]
145 *
146 * Revision 1.1 1992/09/30 02:01:01 robert
147 * Initial revision
148 *
149 * $EndLog$
150 */
151 /* CMU_HIST */
152 /*
153 * Revision 2.7 91/10/09 15:59:28 af
154 * Revision 2.6.1.1 91/10/05 13:05:49 jeffreyh
155 * Supported non current task space data examination and search.
156 * Added 'm' format and db_xcdump to print with hex and characters.
157 * Added db_examine_{forward, backward}.
158 * Changed db_print_cmd to support variable number of parameters
159 * including string constant.
160 * Included "db_access.h".
161 * [91/08/29 tak]
162 *
163 * Revision 2.6.1.1 91/10/05 13:05:49 jeffreyh
164 * Supported non current task space data examination and search.
165 * Added 'm' format and db_xcdump to print with hex and characters.
166 * Added db_examine_{forward, backward}.
167 * Changed db_print_cmd to support variable number of parameters
168 * including string constant.
169 * Included "db_access.h".
170 * [91/08/29 tak]
171 *
172 * Revision 2.6 91/08/28 11:11:01 jsb
173 * Added 'A' flag to examine: just like 'a' (address), but prints addr
174 * as a procedure type, thus printing file/line info if available.
175 * Useful when called as 'x/Ai'.
176 * [91/08/13 18:14:55 jsb]
177 *
178 * Revision 2.5 91/05/14 15:33:31 mrt
179 * Correcting copyright
180 *
181 * Revision 2.4 91/02/05 17:06:20 mrt
182 * Changed to new Mach copyright
183 * [91/01/31 16:17:37 mrt]
184 *
185 * Revision 2.3 90/11/07 16:49:23 rpd
186 * Added db_search_cmd, db_search.
187 * [90/11/06 rpd]
188 *
189 * Revision 2.2 90/08/27 21:50:38 dbg
190 * Add 'r', 'z' to print and examine formats.
191 * Change calling sequence of db_disasm.
192 * db_examine sets db_prev and db_next instead of explicitly
193 * advancing dot.
194 * [90/08/20 dbg]
195 * Reflected changes in db_printsym()'s calling seq.
196 * [90/08/20 af]
197 * Reduce lint.
198 * [90/08/07 dbg]
199 * Created.
200 * [90/07/25 dbg]
201 *
202 */
203 /* CMU_ENDHIST */
204 /*
205 * Mach Operating System
206 * Copyright (c) 1991,1990 Carnegie Mellon University
207 * All Rights Reserved.
208 *
209 * Permission to use, copy, modify and distribute this software and its
210 * documentation is hereby granted, provided that both the copyright
211 * notice and this permission notice appear in all copies of the
212 * software, derivative works or modified versions, and any portions
213 * thereof, and that both notices appear in supporting documentation.
214 *
215 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
216 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
217 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
218 *
219 * Carnegie Mellon requests users of this software to return to
220 *
221 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
222 * School of Computer Science
223 * Carnegie Mellon University
224 * Pittsburgh PA 15213-3890
225 *
226 * any improvements or extensions that they make and grant Carnegie Mellon
227 * the rights to redistribute these changes.
228 */
229 /*
230 */
231 /*
232 * Author: David B. Golub, Carnegie Mellon University
233 * Date: 7/90
234 */
235 #include <string.h> /* For strcpy() */
236 #include <mach/boolean.h>
237 #include <machine/db_machdep.h>
238
239 #include <ddb/db_access.h>
240 #include <ddb/db_lex.h>
241 #include <ddb/db_output.h>
242 #include <ddb/db_command.h>
243 #include <ddb/db_sym.h>
244 #include <ddb/db_task_thread.h>
245 #include <ddb/db_command.h> /* For db_option() */
246 #include <ddb/db_examine.h>
247 #include <ddb/db_expr.h>
248 #include <kern/thread.h>
249 #include <kern/task.h>
250 #include <mach/vm_param.h>
251
252 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
253
254 char db_examine_format[TOK_STRING_SIZE] = "x";
255 int db_examine_count = 1;
256 db_addr_t db_examine_prev_addr = 0;
257 thread_act_t db_examine_act = THR_ACT_NULL;
258
259 extern int db_max_width;
260
261
262 /* Prototypes for functions local to this file. XXX -- should be static!
263 */
264 int db_xcdump(
265 db_addr_t addr,
266 int size,
267 int count,
268 task_t task);
269
270 int db_examine_width(
271 int size,
272 int *items,
273 int *remainder);
274
275 /*
276 * Examine (print) data.
277 */
278 void
279 db_examine_cmd(
280 db_expr_t addr,
281 int have_addr,
282 db_expr_t count,
283 char * modif)
284 {
285 thread_act_t thr_act;
286 extern char db_last_modifier[];
287
288 if (modif[0] != '\0')
289 strcpy(db_examine_format, modif);
290
291 if (count == -1)
292 count = 1;
293 db_examine_count = count;
294 if (db_option(modif, 't')) {
295 if (modif == db_last_modifier)
296 thr_act = db_examine_act;
297 else if (!db_get_next_act(&thr_act, 0))
298 return;
299 } else
300 if (db_option(modif,'u'))
301 thr_act = current_act();
302 else
303 thr_act = THR_ACT_NULL;
304
305 db_examine_act = thr_act;
306 db_examine((db_addr_t) addr, db_examine_format, count,
307 db_act_to_task(thr_act));
308 }
309
310 void
311 db_examine_forward(
312 db_expr_t addr,
313 int have_addr,
314 db_expr_t count,
315 char * modif)
316 {
317 db_examine(db_next, db_examine_format, db_examine_count,
318 db_act_to_task(db_examine_act));
319 }
320
321 void
322 db_examine_backward(
323 db_expr_t addr,
324 int have_addr,
325 db_expr_t count,
326 char * modif)
327 {
328 db_examine(db_examine_prev_addr - (db_next - db_examine_prev_addr),
329 db_examine_format, db_examine_count,
330 db_act_to_task(db_examine_act));
331 }
332
333 int
334 db_examine_width(
335 int size,
336 int *items,
337 int *remainder)
338 {
339 int sz;
340 int entry;
341 int width;
342
343 width = size * 2 + 1;
344 sz = (db_max_width - (sizeof (void *) * 2 + 4)) / width;
345 for (entry = 1; (entry << 1) < sz; entry <<= 1)
346 continue;
347
348 sz = sizeof (void *) * 2 + 4 + entry * width;
349 while (sz + entry < db_max_width) {
350 width++;
351 sz += entry;
352 }
353 *remainder = (db_max_width - sz + 1) / 2;
354 *items = entry;
355 return width;
356 }
357
358 void
359 db_examine(
360 db_addr_t addr,
361 char * fmt, /* format string */
362 int count, /* repeat count */
363 task_t task)
364 {
365 int c;
366 db_expr_t value;
367 int size;
368 int width;
369 int leader;
370 int items;
371 int nitems;
372 char * fp;
373 db_addr_t next_addr;
374 int sz;
375
376 db_examine_prev_addr = addr;
377 while (--count >= 0) {
378 fp = fmt;
379 size = sizeof(int);
380 width = db_examine_width(size, &items, &leader);
381 while ((c = *fp++) != 0) {
382 switch (c) {
383 case 'b':
384 size = sizeof(char);
385 width = db_examine_width(size, &items, &leader);
386 break;
387 case 'h':
388 size = sizeof(short);
389 width = db_examine_width(size, &items, &leader);
390 break;
391 case 'l':
392 size = sizeof(int);
393 width = db_examine_width(size, &items, &leader);
394 break;
395 case 'q':
396 size = sizeof(long);
397 width = db_examine_width(size, &items, &leader);
398 break;
399 case 'a': /* address */
400 case 'A': /* function address */
401 /* always forces a new line */
402 if (db_print_position() != 0)
403 db_printf("\n");
404 db_prev = addr;
405 next_addr = addr + 4;
406 db_task_printsym(addr,
407 (c == 'a')?DB_STGY_ANY:DB_STGY_PROC,
408 task);
409 db_printf(":\t");
410 break;
411 case 'm':
412 db_next = db_xcdump(addr, size, count+1, task);
413 return;
414 case 't':
415 case 'u':
416 break;
417 default:
418 restart:
419 /* Reset next_addr in case we are printing in
420 multiple formats. */
421 next_addr = addr;
422 if (db_print_position() == 0) {
423 /* If we hit a new symbol, print it */
424 char * name;
425 db_addr_t off;
426
427 db_find_task_sym_and_offset(addr,&name,&off,task);
428 if (off == 0)
429 db_printf("\r%s:\n", name);
430 db_printf("%#n: ", addr);
431 for (sz = 0; sz < leader; sz++)
432 db_putchar(' ');
433 db_prev = addr;
434 nitems = items;
435 }
436
437 switch (c) {
438 case 'p': /* Addrs rendered symbolically. */
439 if( size == sizeof(void *) ) {
440 char *symName;
441 db_addr_t offset;
442
443 items = 1;
444 value = db_get_task_value( next_addr,
445 sizeof(db_expr_t), FALSE, task );
446 db_find_task_sym_and_offset( value,
447 &symName, &offset, task);
448 db_printf("\n\t*%8x(%8X) = %s",
449 next_addr, value, symName );
450 if( offset ) {
451 db_printf("+%X", offset );
452 }
453 next_addr += size;
454 }
455 break;
456 case 'r': /* signed, current radix */
457 for (sz = size, next_addr = addr;
458 sz >= sizeof (db_expr_t);
459 sz -= sizeof (db_expr_t)) {
460 if (nitems-- == 0) {
461 db_putchar('\n');
462 goto restart;
463 }
464 value = db_get_task_value(next_addr,
465 sizeof (db_expr_t),
466 TRUE,task);
467 db_printf("%-*r", width, value);
468 next_addr += sizeof (db_expr_t);
469 }
470 if (sz > 0) {
471 if (nitems-- == 0) {
472 db_putchar('\n');
473 goto restart;
474 }
475 value = db_get_task_value(next_addr, sz,
476 TRUE, task);
477 db_printf("%-*R", width, value);
478 next_addr += sz;
479 }
480 break;
481 #ifdef APPLE
482 case 'X': /* unsigned hex */
483 #endif
484 case 'x': /* unsigned hex */
485 for (sz = size, next_addr = addr;
486 sz >= sizeof (db_expr_t);
487 sz -= sizeof (db_expr_t)) {
488 if (nitems-- == 0) {
489 db_putchar('\n');
490 goto restart;
491 }
492 value = db_get_task_value(next_addr,
493 sizeof (db_expr_t),
494 FALSE,task);
495 #ifdef APPLE
496 if ( c == 'X')
497 db_printf("%0*X ", 2*size, value);
498 else
499 db_printf("%-*x", width, value);
500 #else
501 db_printf("%-*x", width, value);
502 #endif
503 next_addr += sizeof (db_expr_t);
504 }
505 if (sz > 0) {
506 if (nitems-- == 0) {
507 db_putchar('\n');
508 goto restart;
509 }
510 value = db_get_task_value(next_addr, sz,
511 FALSE, task);
512 #ifdef APPLE
513 if ( c == 'X')
514 db_printf("%0*X ", 2*size, value);
515 else
516 db_printf("%-*X", width, value);
517 #else
518 db_printf("%-*X", width, value);
519 #endif
520 next_addr += sz;
521 }
522 break;
523 case 'z': /* signed hex */
524 for (sz = size, next_addr = addr;
525 sz >= sizeof (db_expr_t);
526 sz -= sizeof (db_expr_t)) {
527 if (nitems-- == 0) {
528 db_putchar('\n');
529 goto restart;
530 }
531 value = db_get_task_value(next_addr,
532 sizeof (db_expr_t),
533 TRUE, task);
534 db_printf("%-*z", width, value);
535 next_addr += sizeof (db_expr_t);
536 }
537 if (sz > 0) {
538 if (nitems-- == 0) {
539 db_putchar('\n');
540 goto restart;
541 }
542 value = db_get_task_value(next_addr,sz,
543 TRUE,task);
544 db_printf("%-*Z", width, value);
545 next_addr += sz;
546 }
547 break;
548 case 'd': /* signed decimal */
549 for (sz = size, next_addr = addr;
550 sz >= sizeof (db_expr_t);
551 sz -= sizeof (db_expr_t)) {
552 if (nitems-- == 0) {
553 db_putchar('\n');
554 goto restart;
555 }
556 value = db_get_task_value(next_addr,
557 sizeof (db_expr_t),
558 TRUE,task);
559 db_printf("%-*d", width, value);
560 next_addr += sizeof (db_expr_t);
561 }
562 if (sz > 0) {
563 if (nitems-- == 0) {
564 db_putchar('\n');
565 goto restart;
566 }
567 value = db_get_task_value(next_addr, sz,
568 TRUE, task);
569 db_printf("%-*D", width, value);
570 next_addr += sz;
571 }
572 break;
573 case 'U': /* unsigned decimal */
574 case 'u':
575 for (sz = size, next_addr = addr;
576 sz >= sizeof (db_expr_t);
577 sz -= sizeof (db_expr_t)) {
578 if (nitems-- == 0) {
579 db_putchar('\n');
580 goto restart;
581 }
582 value = db_get_task_value(next_addr,
583 sizeof (db_expr_t),
584 FALSE,task);
585 db_printf("%-*u", width, value);
586 next_addr += sizeof (db_expr_t);
587 }
588 if (sz > 0) {
589 if (nitems-- == 0) {
590 db_putchar('\n');
591 goto restart;
592 }
593 value = db_get_task_value(next_addr, sz,
594 FALSE, task);
595 db_printf("%-*U", width, value);
596 next_addr += sz;
597 }
598 break;
599 case 'o': /* unsigned octal */
600 for (sz = size, next_addr = addr;
601 sz >= sizeof (db_expr_t);
602 sz -= sizeof (db_expr_t)) {
603 if (nitems-- == 0) {
604 db_putchar('\n');
605 goto restart;
606 }
607 value = db_get_task_value(next_addr,
608 sizeof (db_expr_t),
609 FALSE,task);
610 db_printf("%-*o", width, value);
611 next_addr += sizeof (db_expr_t);
612 }
613 if (sz > 0) {
614 if (nitems-- == 0) {
615 db_putchar('\n');
616 goto restart;
617 }
618 value = db_get_task_value(next_addr, sz,
619 FALSE, task);
620 db_printf("%-*o", width, value);
621 next_addr += sz;
622 }
623 break;
624 case 'c': /* character */
625 for (sz = 0, next_addr = addr;
626 sz < size;
627 sz++, next_addr++) {
628 value = db_get_task_value(next_addr,1,
629 FALSE,task);
630 if ((value >= ' ' && value <= '~') ||
631 value == '\n' ||
632 value == '\t')
633 db_printf("%c", value);
634 else
635 db_printf("\\%03o", value);
636 }
637 break;
638 case 's': /* null-terminated string */
639 size = 0;
640 for (;;) {
641 value = db_get_task_value(next_addr,1,
642 FALSE,task);
643 next_addr += 1;
644 size++;
645 if (value == 0)
646 break;
647 if (value >= ' ' && value <= '~')
648 db_printf("%c", value);
649 else
650 db_printf("\\%03o", value);
651 }
652 break;
653 case 'i': /* instruction */
654 next_addr = db_disasm(addr, FALSE, task);
655 size = next_addr - addr;
656 break;
657 case 'I': /* instruction, alternate form */
658 next_addr = db_disasm(addr, TRUE, task);
659 size = next_addr - addr;
660 break;
661 default:
662 break;
663 }
664 if (db_print_position() != 0)
665 db_end_line();
666 break;
667 }
668 }
669 addr = next_addr;
670 }
671 db_next = addr;
672 }
673
674 /*
675 * Print value.
676 */
677 char db_print_format = 'x';
678
679 void
680 db_print_cmd(void)
681 {
682 db_expr_t value;
683 int t;
684 task_t task = TASK_NULL;
685
686 if ((t = db_read_token()) == tSLASH) {
687 if (db_read_token() != tIDENT) {
688 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
689 db_error(0);
690 /* NOTREACHED */
691 }
692 if (db_tok_string[0])
693 db_print_format = db_tok_string[0];
694 if (db_option(db_tok_string, 't')) {
695 if (db_default_act)
696 task = db_default_act->task;
697 if (db_print_format == 't')
698 db_print_format = db_tok_string[1];
699 }
700 } else
701 db_unread_token(t);
702
703 for ( ; ; ) {
704 t = db_read_token();
705 if (t == tSTRING) {
706 db_printf("%s", db_tok_string);
707 continue;
708 }
709 db_unread_token(t);
710 if (!db_expression(&value))
711 break;
712 switch (db_print_format) {
713 case 'a':
714 case 'A':
715 db_task_printsym((db_addr_t)value,
716 (db_print_format == 'a') ? DB_STGY_ANY:
717 DB_STGY_PROC,
718 task);
719 break;
720 case 'r':
721 db_printf("%11r", value);
722 break;
723 case 'x':
724 db_printf("%08x", value);
725 break;
726 case 'z':
727 db_printf("%8z", value);
728 break;
729 case 'd':
730 db_printf("%11d", value);
731 break;
732 case 'u':
733 db_printf("%11u", value);
734 break;
735 case 'o':
736 db_printf("%16o", value);
737 break;
738 case 'c':
739 value = value & 0xFF;
740 if (value >= ' ' && value <= '~')
741 db_printf("%c", value);
742 else
743 db_printf("\\%03o", value);
744 break;
745 default:
746 db_printf("Unknown format %c\n", db_print_format);
747 db_print_format = 'x';
748 db_error(0);
749 }
750 }
751 }
752
753 void
754 db_print_loc(
755 db_addr_t loc,
756 task_t task)
757 {
758 db_task_printsym(loc, DB_STGY_PROC, task);
759 }
760
761 void
762 db_print_inst(
763 db_addr_t loc,
764 task_t task)
765 {
766 (void) db_disasm(loc, TRUE, task);
767 }
768
769 void
770 db_print_loc_and_inst(
771 db_addr_t loc,
772 task_t task)
773 {
774 db_task_printsym(loc, DB_STGY_PROC, task);
775 db_printf(":\t");
776 (void) db_disasm(loc, TRUE, task);
777 }
778
779 /*
780 * Search for a value in memory.
781 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
782 */
783 void
784 db_search_cmd(void)
785 {
786 int t;
787 db_addr_t addr;
788 int size = 0;
789 db_expr_t value;
790 db_expr_t mask;
791 db_addr_t count;
792 thread_act_t thr_act;
793 boolean_t thread_flag = FALSE;
794 register char *p;
795
796 t = db_read_token();
797 if (t == tSLASH) {
798 t = db_read_token();
799 if (t != tIDENT) {
800 bad_modifier:
801 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
802 db_flush_lex();
803 return;
804 }
805
806 for (p = db_tok_string; *p; p++) {
807 switch(*p) {
808 case 'b':
809 size = sizeof(char);
810 break;
811 case 'h':
812 size = sizeof(short);
813 break;
814 case 'l':
815 size = sizeof(long);
816 break;
817 case 't':
818 thread_flag = TRUE;
819 break;
820 default:
821 goto bad_modifier;
822 }
823 }
824 } else {
825 db_unread_token(t);
826 size = sizeof(int);
827 }
828
829 if (!db_expression((db_expr_t *) &addr)) {
830 db_printf("Address missing\n");
831 db_flush_lex();
832 return;
833 }
834
835 if (!db_expression(&value)) {
836 db_printf("Value missing\n");
837 db_flush_lex();
838 return;
839 }
840
841 if (!db_expression(&mask))
842 mask = ~0;
843
844 t = db_read_token();
845 if (t == tCOMMA) {
846 if (!db_expression((db_expr_t *) &count)) {
847 db_printf("Count missing\n");
848 db_flush_lex();
849 return;
850 }
851 } else {
852 db_unread_token(t);
853 count = -1; /* effectively forever */
854 }
855 if (thread_flag) {
856 if (!db_get_next_act(&thr_act, 0))
857 return;
858 } else
859 thr_act = THR_ACT_NULL;
860
861 db_search(addr, size, value, mask, count, db_act_to_task(thr_act));
862 }
863
864 void
865 db_search(
866 db_addr_t addr,
867 int size,
868 db_expr_t value,
869 db_expr_t mask,
870 unsigned int count,
871 task_t task)
872 {
873 while (count-- != 0) {
874 db_prev = addr;
875 if ((db_get_task_value(addr,size,FALSE,task) & mask) == value)
876 break;
877 addr += size;
878 }
879 db_printf("0x%x: ", addr);
880 db_next = addr;
881 }
882
883 #define DB_XCDUMP_NC 16
884
885 int
886 db_xcdump(
887 db_addr_t addr,
888 int size,
889 int count,
890 task_t task)
891 {
892 register int i, n;
893 db_expr_t value;
894 int bcount;
895 db_addr_t off;
896 char *name;
897 char data[DB_XCDUMP_NC];
898
899 db_find_task_sym_and_offset(addr, &name, &off, task);
900 for (n = count*size; n > 0; n -= bcount) {
901 db_prev = addr;
902 if (off == 0) {
903 db_printf("%s:\n", name);
904 off = -1;
905 }
906 db_printf("%0*X:%s", 2*sizeof(db_addr_t), addr,
907 (size != 1) ? " " : "" );
908 bcount = ((n > DB_XCDUMP_NC)? DB_XCDUMP_NC: n);
909 if (trunc_page(addr) != trunc_page(addr+bcount-1)) {
910 db_addr_t next_page_addr = trunc_page(addr+bcount-1);
911 if (!DB_CHECK_ACCESS(next_page_addr, sizeof(int), task))
912 bcount = next_page_addr - addr;
913 }
914 db_read_bytes((vm_offset_t)addr, bcount, data, task);
915 for (i = 0; i < bcount && off != 0; i += size) {
916 if (i % 4 == 0)
917 db_printf(" ");
918 value = db_get_task_value(addr, size, FALSE, task);
919 db_printf("%0*x ", size*2, value);
920 addr += size;
921 db_find_task_sym_and_offset(addr, &name, &off, task);
922 }
923 db_printf("%*s",
924 ((DB_XCDUMP_NC-i)/size)*(size*2+1)+(DB_XCDUMP_NC-i)/4,
925 "");
926 bcount = i;
927 db_printf("%s*", (size != 1)? " ": "");
928 for (i = 0; i < bcount; i++) {
929 value = data[i];
930 db_printf("%c", (value >= ' ' && value <= '~')? value: '.');
931 }
932 db_printf("*\n");
933 }
934 return(addr);
935 }