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