]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_examine.c
xnu-517.tar.gz
[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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * @OSF_COPYRIGHT@
27 */
28 /*
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53 /*
54 */
55 /*
56 * Author: David B. Golub, Carnegie Mellon University
57 * Date: 7/90
58 */
59 #include <string.h> /* For strcpy() */
60 #include <mach/boolean.h>
61 #include <machine/db_machdep.h>
62
63 #include <ddb/db_access.h>
64 #include <ddb/db_lex.h>
65 #include <ddb/db_output.h>
66 #include <ddb/db_command.h>
67 #include <ddb/db_sym.h>
68 #include <ddb/db_task_thread.h>
69 #include <ddb/db_command.h> /* For db_option() */
70 #include <ddb/db_examine.h>
71 #include <ddb/db_expr.h>
72 #include <kern/thread.h>
73 #include <kern/task.h>
74 #include <mach/vm_param.h>
75
76 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
77
78 char db_examine_format[TOK_STRING_SIZE] = "x";
79 int db_examine_count = 1;
80 db_addr_t db_examine_prev_addr = 0;
81 thread_act_t db_examine_act = THR_ACT_NULL;
82
83 extern int db_max_width;
84
85
86 /* Prototypes for functions local to this file. XXX -- should be static!
87 */
88 int db_xcdump(
89 db_addr_t addr,
90 int size,
91 int count,
92 task_t task);
93
94 int db_examine_width(
95 int size,
96 int *items,
97 int *remainder);
98
99 /*
100 * Examine (print) data.
101 */
102 void
103 db_examine_cmd(
104 db_expr_t addr,
105 int have_addr,
106 db_expr_t count,
107 char * modif)
108 {
109 thread_act_t thr_act;
110 extern char db_last_modifier[];
111
112 if (modif[0] != '\0')
113 strcpy(db_examine_format, modif);
114
115 if (count == -1)
116 count = 1;
117 db_examine_count = count;
118 if (db_option(modif, 't')) {
119 if (modif == db_last_modifier)
120 thr_act = db_examine_act;
121 else if (!db_get_next_act(&thr_act, 0))
122 return;
123 } else
124 if (db_option(modif,'u'))
125 thr_act = current_act();
126 else
127 thr_act = THR_ACT_NULL;
128
129 db_examine_act = thr_act;
130 db_examine((db_addr_t) addr, db_examine_format, count,
131 db_act_to_task(thr_act));
132 }
133
134 void
135 db_examine_forward(
136 db_expr_t addr,
137 int have_addr,
138 db_expr_t count,
139 char * modif)
140 {
141 db_examine(db_next, db_examine_format, db_examine_count,
142 db_act_to_task(db_examine_act));
143 }
144
145 void
146 db_examine_backward(
147 db_expr_t addr,
148 int have_addr,
149 db_expr_t count,
150 char * modif)
151 {
152 db_examine(db_examine_prev_addr - (db_next - db_examine_prev_addr),
153 db_examine_format, db_examine_count,
154 db_act_to_task(db_examine_act));
155 }
156
157 int
158 db_examine_width(
159 int size,
160 int *items,
161 int *remainder)
162 {
163 int sz;
164 int entry;
165 int width;
166
167 width = size * 2 + 1;
168 sz = (db_max_width - (sizeof (void *) * 2 + 4)) / width;
169 for (entry = 1; (entry << 1) < sz; entry <<= 1)
170 continue;
171
172 sz = sizeof (void *) * 2 + 4 + entry * width;
173 while (sz + entry < db_max_width) {
174 width++;
175 sz += entry;
176 }
177 *remainder = (db_max_width - sz + 1) / 2;
178 *items = entry;
179 return width;
180 }
181
182 void
183 db_examine(
184 db_addr_t addr,
185 char * fmt, /* format string */
186 int count, /* repeat count */
187 task_t task)
188 {
189 int c;
190 db_expr_t value;
191 int size;
192 int width;
193 int leader;
194 int items;
195 int nitems;
196 char * fp;
197 db_addr_t next_addr;
198 int sz;
199
200 db_examine_prev_addr = addr;
201 while (--count >= 0) {
202 fp = fmt;
203 size = sizeof(int);
204 width = db_examine_width(size, &items, &leader);
205 while ((c = *fp++) != 0) {
206 switch (c) {
207 case 'b':
208 size = sizeof(char);
209 width = db_examine_width(size, &items, &leader);
210 break;
211 case 'h':
212 size = sizeof(short);
213 width = db_examine_width(size, &items, &leader);
214 break;
215 case 'l':
216 size = sizeof(int);
217 width = db_examine_width(size, &items, &leader);
218 break;
219 case 'q':
220 size = sizeof(long);
221 width = db_examine_width(size, &items, &leader);
222 break;
223 case 'a': /* address */
224 case 'A': /* function address */
225 /* always forces a new line */
226 if (db_print_position() != 0)
227 db_printf("\n");
228 db_prev = addr;
229 next_addr = addr + 4;
230 db_task_printsym(addr,
231 (c == 'a')?DB_STGY_ANY:DB_STGY_PROC,
232 task);
233 db_printf(":\t");
234 break;
235 case 'm':
236 db_next = db_xcdump(addr, size, count+1, task);
237 return;
238 case 't':
239 case 'u':
240 break;
241 default:
242 restart:
243 /* Reset next_addr in case we are printing in
244 multiple formats. */
245 next_addr = addr;
246 if (db_print_position() == 0) {
247 /* If we hit a new symbol, print it */
248 char * name;
249 db_addr_t off;
250
251 db_find_task_sym_and_offset(addr,&name,&off,task);
252 if (off == 0)
253 db_printf("\r%s:\n", name);
254 db_printf("%#n: ", addr);
255 for (sz = 0; sz < leader; sz++)
256 db_putchar(' ');
257 db_prev = addr;
258 nitems = items;
259 }
260
261 switch (c) {
262 case 'p': /* Addrs rendered symbolically. */
263 if( size == sizeof(void *) ) {
264 char *symName;
265 db_addr_t offset;
266
267 items = 1;
268 value = db_get_task_value( next_addr,
269 sizeof(db_expr_t), FALSE, task );
270 db_find_task_sym_and_offset( value,
271 &symName, &offset, task);
272 db_printf("\n\t*%8llX(%8llX) = %s",
273 next_addr, value, symName );
274 if( offset ) {
275 db_printf("+%llX", offset );
276 }
277 next_addr += size;
278 }
279 break;
280 case 'r': /* signed, current radix */
281 for (sz = size, next_addr = addr;
282 sz >= sizeof (db_expr_t);
283 sz -= sizeof (db_expr_t)) {
284 if (nitems-- == 0) {
285 db_putchar('\n');
286 goto restart;
287 }
288 value = db_get_task_value(next_addr,
289 sizeof (db_expr_t),
290 TRUE,task);
291 db_printf("%-*llr", width, value);
292 next_addr += sizeof (db_expr_t);
293 }
294 if (sz > 0) {
295 if (nitems-- == 0) {
296 db_putchar('\n');
297 goto restart;
298 }
299 value = db_get_task_value(next_addr, sz,
300 TRUE, task);
301 db_printf("%-*llR", width, value);
302 next_addr += sz;
303 }
304 break;
305 case 'X': /* unsigned hex */
306 case 'x': /* unsigned hex */
307 for (sz = size, next_addr = addr;
308 sz >= sizeof (db_expr_t);
309 sz -= sizeof (db_expr_t)) {
310 if (nitems-- == 0) {
311 db_putchar('\n');
312 goto restart;
313 }
314 value = db_get_task_value(next_addr,
315 sizeof (db_expr_t),
316 FALSE,task);
317 if ( c == 'X')
318 db_printf("%0*llX ", 2*size, value);
319 else
320 db_printf("%-*llx", width, value);
321 next_addr += sizeof (db_expr_t);
322 }
323 if (sz > 0) {
324 if (nitems-- == 0) {
325 db_putchar('\n');
326 goto restart;
327 }
328 value = db_get_task_value(next_addr, sz,
329 FALSE, task);
330 if ( c == 'X')
331 db_printf("%0*llX ", 2*size, value);
332 else
333 db_printf("%-*llX", width, value);
334 next_addr += sz;
335 }
336 break;
337 case 'z': /* signed hex */
338 for (sz = size, next_addr = addr;
339 sz >= sizeof (db_expr_t);
340 sz -= sizeof (db_expr_t)) {
341 if (nitems-- == 0) {
342 db_putchar('\n');
343 goto restart;
344 }
345 value = db_get_task_value(next_addr,
346 sizeof (db_expr_t),
347 TRUE, task);
348 db_printf("%-*llz", width, value);
349 next_addr += sizeof (db_expr_t);
350 }
351 if (sz > 0) {
352 if (nitems-- == 0) {
353 db_putchar('\n');
354 goto restart;
355 }
356 value = db_get_task_value(next_addr,sz,
357 TRUE,task);
358 db_printf("%-*llZ", width, value);
359 next_addr += sz;
360 }
361 break;
362 case 'd': /* signed decimal */
363 for (sz = size, next_addr = addr;
364 sz >= sizeof (db_expr_t);
365 sz -= sizeof (db_expr_t)) {
366 if (nitems-- == 0) {
367 db_putchar('\n');
368 goto restart;
369 }
370 value = db_get_task_value(next_addr,
371 sizeof (db_expr_t),
372 TRUE,task);
373 db_printf("%-*lld", width, value);
374 next_addr += sizeof (db_expr_t);
375 }
376 if (sz > 0) {
377 if (nitems-- == 0) {
378 db_putchar('\n');
379 goto restart;
380 }
381 value = db_get_task_value(next_addr, sz,
382 TRUE, task);
383 db_printf("%-*llD", width, value);
384 next_addr += sz;
385 }
386 break;
387 case 'U': /* unsigned decimal */
388 case 'u':
389 for (sz = size, next_addr = addr;
390 sz >= sizeof (db_expr_t);
391 sz -= sizeof (db_expr_t)) {
392 if (nitems-- == 0) {
393 db_putchar('\n');
394 goto restart;
395 }
396 value = db_get_task_value(next_addr,
397 sizeof (db_expr_t),
398 FALSE,task);
399 db_printf("%-*llu", width, value);
400 next_addr += sizeof (db_expr_t);
401 }
402 if (sz > 0) {
403 if (nitems-- == 0) {
404 db_putchar('\n');
405 goto restart;
406 }
407 value = db_get_task_value(next_addr, sz,
408 FALSE, task);
409 db_printf("%-*llU", width, value);
410 next_addr += sz;
411 }
412 break;
413 case 'o': /* unsigned octal */
414 for (sz = size, next_addr = addr;
415 sz >= sizeof (db_expr_t);
416 sz -= sizeof (db_expr_t)) {
417 if (nitems-- == 0) {
418 db_putchar('\n');
419 goto restart;
420 }
421 value = db_get_task_value(next_addr,
422 sizeof (db_expr_t),
423 FALSE,task);
424 db_printf("%-*llo", width, value);
425 next_addr += sizeof (db_expr_t);
426 }
427 if (sz > 0) {
428 if (nitems-- == 0) {
429 db_putchar('\n');
430 goto restart;
431 }
432 value = db_get_task_value(next_addr, sz,
433 FALSE, task);
434 db_printf("%-*llo", width, value);
435 next_addr += sz;
436 }
437 break;
438 case 'c': /* character */
439 for (sz = 0, next_addr = addr;
440 sz < size;
441 sz++, next_addr++) {
442 value = db_get_task_value(next_addr,1,
443 FALSE,task);
444 if ((value >= ' ' && value <= '~') ||
445 value == '\n' ||
446 value == '\t')
447 db_printf("%llc", value);
448 else
449 db_printf("\\%03llo", value);
450 }
451 break;
452 case 's': /* null-terminated string */
453 size = 0;
454 for (;;) {
455 value = db_get_task_value(next_addr,1,
456 FALSE,task);
457 next_addr += 1;
458 size++;
459 if (value == 0)
460 break;
461 if (value >= ' ' && value <= '~')
462 db_printf("%llc", value);
463 else
464 db_printf("\\%03llo", value);
465 }
466 break;
467 case 'i': /* instruction */
468 next_addr = db_disasm(addr, FALSE, task);
469 size = next_addr - addr;
470 break;
471 case 'I': /* instruction, alternate form */
472 next_addr = db_disasm(addr, TRUE, task);
473 size = next_addr - addr;
474 break;
475 default:
476 break;
477 }
478 if (db_print_position() != 0)
479 db_end_line();
480 break;
481 }
482 }
483 addr = next_addr;
484 }
485 db_next = addr;
486 }
487
488 /*
489 * Print value.
490 */
491 char db_print_format = 'x';
492
493 void
494 db_print_cmd(void)
495 {
496 db_expr_t value;
497 int t;
498 task_t task = TASK_NULL;
499
500 if ((t = db_read_token()) == tSLASH) {
501 if (db_read_token() != tIDENT) {
502 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
503 db_error(0);
504 /* NOTREACHED */
505 }
506 if (db_tok_string[0])
507 db_print_format = db_tok_string[0];
508 if (db_option(db_tok_string, 't')) {
509 if (db_default_act)
510 task = db_default_act->task;
511 if (db_print_format == 't')
512 db_print_format = db_tok_string[1];
513 }
514 } else
515 db_unread_token(t);
516
517 for ( ; ; ) {
518 t = db_read_token();
519 if (t == tSTRING) {
520 db_printf("%s", db_tok_string);
521 continue;
522 }
523 db_unread_token(t);
524 if (!db_expression(&value))
525 break;
526 switch (db_print_format) {
527 case 'a':
528 case 'A':
529 db_task_printsym((db_addr_t)value,
530 (db_print_format == 'a') ? DB_STGY_ANY:
531 DB_STGY_PROC,
532 task);
533 break;
534 case 'r':
535 db_printf("%11llr", value);
536 break;
537 case 'X':
538 db_printf("%016llX", value);
539 break;
540 case 'x':
541 db_printf("%016llx", value);
542 break;
543 case 'z':
544 db_printf("%16llz", value);
545 break;
546 case 'd':
547 db_printf("%11lld", value);
548 break;
549 case 'u':
550 db_printf("%11llu", value);
551 break;
552 case 'o':
553 db_printf("%16llo", value);
554 break;
555 case 'c':
556 value = value & 0xFF;
557 if (value >= ' ' && value <= '~')
558 db_printf("%llc", value);
559 else
560 db_printf("\\%03llo", value);
561 break;
562 default:
563 db_printf("Unknown format %c\n", db_print_format);
564 db_print_format = 'x';
565 db_error(0);
566 }
567 }
568 }
569
570 void
571 db_print_loc(
572 db_addr_t loc,
573 task_t task)
574 {
575 db_task_printsym(loc, DB_STGY_PROC, task);
576 }
577
578 void
579 db_print_inst(
580 db_addr_t loc,
581 task_t task)
582 {
583 (void) db_disasm(loc, TRUE, task);
584 }
585
586 void
587 db_print_loc_and_inst(
588 db_addr_t loc,
589 task_t task)
590 {
591 db_task_printsym(loc, DB_STGY_PROC, task);
592 db_printf(":\t");
593 (void) db_disasm(loc, TRUE, task);
594 }
595
596 /*
597 * Search for a value in memory.
598 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
599 */
600 void
601 db_search_cmd(void)
602 {
603 int t;
604 db_addr_t addr;
605 int size = 0;
606 db_expr_t value;
607 db_expr_t mask;
608 db_addr_t count;
609 thread_act_t thr_act;
610 boolean_t thread_flag = FALSE;
611 register char *p;
612
613 t = db_read_token();
614 if (t == tSLASH) {
615 t = db_read_token();
616 if (t != tIDENT) {
617 bad_modifier:
618 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
619 db_flush_lex();
620 return;
621 }
622
623 for (p = db_tok_string; *p; p++) {
624 switch(*p) {
625 case 'b':
626 size = sizeof(char);
627 break;
628 case 'h':
629 size = sizeof(short);
630 break;
631 case 'l':
632 size = sizeof(long);
633 break;
634 case 't':
635 thread_flag = TRUE;
636 break;
637 default:
638 goto bad_modifier;
639 }
640 }
641 } else {
642 db_unread_token(t);
643 size = sizeof(int);
644 }
645
646 if (!db_expression((db_expr_t *) &addr)) {
647 db_printf("Address missing\n");
648 db_flush_lex();
649 return;
650 }
651
652 if (!db_expression(&value)) {
653 db_printf("Value missing\n");
654 db_flush_lex();
655 return;
656 }
657
658 if (!db_expression(&mask))
659 mask = ~0;
660
661 t = db_read_token();
662 if (t == tCOMMA) {
663 if (!db_expression((db_expr_t *) &count)) {
664 db_printf("Count missing\n");
665 db_flush_lex();
666 return;
667 }
668 } else {
669 db_unread_token(t);
670 count = -1; /* effectively forever */
671 }
672 if (thread_flag) {
673 if (!db_get_next_act(&thr_act, 0))
674 return;
675 } else
676 thr_act = THR_ACT_NULL;
677
678 db_search(addr, size, value, mask, count, db_act_to_task(thr_act));
679 }
680
681 void
682 db_search(
683 db_addr_t addr,
684 int size,
685 db_expr_t value,
686 db_expr_t mask,
687 unsigned int count,
688 task_t task)
689 {
690 while (count-- != 0) {
691 db_prev = addr;
692 if ((db_get_task_value(addr,size,FALSE,task) & mask) == value)
693 break;
694 addr += size;
695 }
696 db_printf("0x%x: ", addr);
697 db_next = addr;
698 }
699
700 #define DB_XCDUMP_NC 16
701
702 int
703 db_xcdump(
704 db_addr_t addr,
705 int size,
706 int count,
707 task_t task)
708 {
709 register int i, n;
710 db_expr_t value;
711 int bcount;
712 db_addr_t off;
713 char *name;
714 char data[DB_XCDUMP_NC];
715
716 db_find_task_sym_and_offset(addr, &name, &off, task);
717 for (n = count*size; n > 0; n -= bcount) {
718 db_prev = addr;
719 if (off == 0) {
720 db_printf("%s:\n", name);
721 off = -1;
722 }
723 db_printf("%0*llX:%s", 2*sizeof(db_addr_t), addr,
724 (size != 1) ? " " : "" );
725 bcount = ((n > DB_XCDUMP_NC)? DB_XCDUMP_NC: n);
726 if (trunc_page_32(addr) != trunc_page_32(addr+bcount-1)) {
727 db_addr_t next_page_addr = trunc_page_32(addr+bcount-1);
728 if (!DB_CHECK_ACCESS(next_page_addr, sizeof(int), task))
729 bcount = next_page_addr - addr;
730 }
731 db_read_bytes((vm_offset_t)addr, bcount, data, task);
732 for (i = 0; i < bcount && off != 0; i += size) {
733 if (i % 4 == 0)
734 db_printf(" ");
735 value = db_get_task_value(addr, size, FALSE, task);
736 db_printf("%0*llX ", size*2, value);
737 addr += size;
738 db_find_task_sym_and_offset(addr, &name, &off, task);
739 }
740 db_printf("%*s",
741 ((DB_XCDUMP_NC-i)/size)*(size*2+1)+(DB_XCDUMP_NC-i)/4,
742 "");
743 bcount = i;
744 db_printf("%s*", (size != 1)? " ": "");
745 for (i = 0; i < bcount; i++) {
746 value = data[i];
747 db_printf("%llc", (value >= ' ' && value <= '~')? value: '.');
748 }
749 db_printf("*\n");
750 }
751 return(addr);
752 }