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