]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_examine.c
xnu-792.18.15.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_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 strcpy() */
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 /*
103 * Examine (print) data.
104 */
105 void
106 db_examine_cmd(
107 db_expr_t addr,
108 int have_addr,
109 db_expr_t count,
110 char * modif)
111 {
112 thread_t thr_act;
113 extern char db_last_modifier[];
114
115 if (modif[0] != '\0')
116 strcpy(db_examine_format, modif);
117
118 if (count == -1)
119 count = 1;
120 db_examine_count = count;
121 if (db_option(modif, 't')) {
122 if (modif == db_last_modifier)
123 thr_act = db_examine_act;
124 else if (!db_get_next_act(&thr_act, 0))
125 return;
126 } else
127 if (db_option(modif,'u'))
128 thr_act = current_act();
129 else
130 thr_act = THREAD_NULL;
131
132 db_examine_act = thr_act;
133 db_examine((db_addr_t) addr, db_examine_format, count,
134 db_act_to_task(thr_act));
135 }
136
137 void
138 db_examine_forward(
139 db_expr_t addr,
140 int have_addr,
141 db_expr_t count,
142 char * modif)
143 {
144 db_examine(db_next, db_examine_format, db_examine_count,
145 db_act_to_task(db_examine_act));
146 }
147
148 void
149 db_examine_backward(
150 db_expr_t addr,
151 int have_addr,
152 db_expr_t count,
153 char * modif)
154 {
155 db_examine(db_examine_prev_addr - (db_next - db_examine_prev_addr),
156 db_examine_format, db_examine_count,
157 db_act_to_task(db_examine_act));
158 }
159
160 int
161 db_examine_width(
162 int size,
163 int *items,
164 int *remainder)
165 {
166 int sz;
167 int entry;
168 int width;
169
170 width = size * 2 + 1;
171 sz = (db_max_width - (sizeof (void *) * 2 + 4)) / width;
172 for (entry = 1; (entry << 1) < sz; entry <<= 1)
173 continue;
174
175 sz = sizeof (void *) * 2 + 4 + entry * width;
176 while (sz + entry < db_max_width) {
177 width++;
178 sz += entry;
179 }
180 *remainder = (db_max_width - sz + 1) / 2;
181 *items = entry;
182 return width;
183 }
184
185 void
186 db_examine(
187 db_addr_t addr,
188 char * fmt, /* format string */
189 int count, /* repeat count */
190 task_t task)
191 {
192 int c;
193 db_expr_t value;
194 int size;
195 int width;
196 int leader;
197 int items;
198 int nitems;
199 char * fp;
200 db_addr_t next_addr;
201 int sz;
202
203 db_examine_prev_addr = addr;
204 while (--count >= 0) {
205 fp = fmt;
206 size = sizeof(int);
207 width = db_examine_width(size, &items, &leader);
208 while ((c = *fp++) != 0) {
209 switch (c) {
210 case 'b':
211 size = sizeof(char);
212 width = db_examine_width(size, &items, &leader);
213 break;
214 case 'h':
215 size = sizeof(short);
216 width = db_examine_width(size, &items, &leader);
217 break;
218 case 'l':
219 size = sizeof(int);
220 width = db_examine_width(size, &items, &leader);
221 break;
222 case 'q':
223 size = sizeof(long);
224 width = db_examine_width(size, &items, &leader);
225 break;
226 case 'a': /* address */
227 case 'A': /* function address */
228 /* always forces a new line */
229 if (db_print_position() != 0)
230 db_printf("\n");
231 db_prev = addr;
232 next_addr = addr + 4;
233 db_task_printsym(addr,
234 (c == 'a')?DB_STGY_ANY:DB_STGY_PROC,
235 task);
236 db_printf(":\t");
237 break;
238 case 'm':
239 db_next = db_xcdump(addr, size, count+1, task);
240 return;
241 case 't':
242 case 'u':
243 break;
244 default:
245 restart:
246 /* Reset next_addr in case we are printing in
247 multiple formats. */
248 next_addr = addr;
249 if (db_print_position() == 0) {
250 /* If we hit a new symbol, print it */
251 char * name;
252 db_addr_t off;
253
254 db_find_task_sym_and_offset(addr,&name,&off,task);
255 if (off == 0)
256 db_printf("\r%s:\n", name);
257 db_printf("%#lln: ", (unsigned long long)addr);
258 for (sz = 0; sz < leader; sz++)
259 db_putchar(' ');
260 db_prev = addr;
261 nitems = items;
262 }
263
264 switch (c) {
265 case 'p': /* Addrs rendered symbolically. */
266 if( size == sizeof(void *) ) {
267 char *symName;
268 db_addr_t offset;
269
270 items = 1;
271 value = db_get_task_value( next_addr,
272 sizeof(db_expr_t), FALSE, task );
273 db_find_task_sym_and_offset( value,
274 &symName, &offset, task);
275 db_printf("\n\t*%8llX(%8llX) = %s",
276 (unsigned long long)next_addr, (unsigned long long)value, symName );
277 if( offset ) {
278 db_printf("+%llX", (unsigned long long)offset );
279 }
280 next_addr += size;
281 }
282 break;
283 case 'r': /* signed, current radix */
284 for (sz = size, next_addr = addr;
285 sz >= sizeof (db_expr_t);
286 sz -= sizeof (db_expr_t)) {
287 if (nitems-- == 0) {
288 db_putchar('\n');
289 goto restart;
290 }
291 value = db_get_task_value(next_addr,
292 sizeof (db_expr_t),
293 TRUE,task);
294 db_printf("%-*llr", width, (unsigned long long)value);
295 next_addr += sizeof (db_expr_t);
296 }
297 if (sz > 0) {
298 if (nitems-- == 0) {
299 db_putchar('\n');
300 goto restart;
301 }
302 value = db_get_task_value(next_addr, sz,
303 TRUE, task);
304 db_printf("%-*llR", width, (unsigned long long)value);
305 next_addr += sz;
306 }
307 break;
308 case 'X': /* unsigned hex */
309 case 'x': /* unsigned hex */
310 for (sz = size, next_addr = addr;
311 sz >= sizeof (db_expr_t);
312 sz -= sizeof (db_expr_t)) {
313 if (nitems-- == 0) {
314 db_putchar('\n');
315 goto restart;
316 }
317 value = db_get_task_value(next_addr,
318 sizeof (db_expr_t),
319 FALSE,task);
320 if ( c == 'X')
321 db_printf("%0*llX ", 2*size, (unsigned long long)value);
322 else
323 db_printf("%-*llx", width, (unsigned long long)value);
324 next_addr += sizeof (db_expr_t);
325 }
326 if (sz > 0) {
327 if (nitems-- == 0) {
328 db_putchar('\n');
329 goto restart;
330 }
331 value = db_get_task_value(next_addr, sz,
332 FALSE, task);
333 if ( c == 'X')
334 db_printf("%0*llX ", 2*size, (unsigned long long)value);
335 else
336 db_printf("%-*llX", width, (unsigned long long)value);
337 next_addr += sz;
338 }
339 break;
340 case 'z': /* signed hex */
341 for (sz = size, next_addr = addr;
342 sz >= sizeof (db_expr_t);
343 sz -= sizeof (db_expr_t)) {
344 if (nitems-- == 0) {
345 db_putchar('\n');
346 goto restart;
347 }
348 value = db_get_task_value(next_addr,
349 sizeof (db_expr_t),
350 TRUE, task);
351 db_printf("%-*llz", width, (unsigned long long)value);
352 next_addr += sizeof (db_expr_t);
353 }
354 if (sz > 0) {
355 if (nitems-- == 0) {
356 db_putchar('\n');
357 goto restart;
358 }
359 value = db_get_task_value(next_addr,sz,
360 TRUE,task);
361 db_printf("%-*llZ", width, (unsigned long long)value);
362 next_addr += sz;
363 }
364 break;
365 case 'd': /* signed decimal */
366 for (sz = size, next_addr = addr;
367 sz >= sizeof (db_expr_t);
368 sz -= sizeof (db_expr_t)) {
369 if (nitems-- == 0) {
370 db_putchar('\n');
371 goto restart;
372 }
373 value = db_get_task_value(next_addr,
374 sizeof (db_expr_t),
375 TRUE,task);
376 db_printf("%-*lld", width, (unsigned long long)value);
377 next_addr += sizeof (db_expr_t);
378 }
379 if (sz > 0) {
380 if (nitems-- == 0) {
381 db_putchar('\n');
382 goto restart;
383 }
384 value = db_get_task_value(next_addr, sz,
385 TRUE, task);
386 db_printf("%-*llD", width, (unsigned long long)value);
387 next_addr += sz;
388 }
389 break;
390 case 'U': /* unsigned decimal */
391 case 'u':
392 for (sz = size, next_addr = addr;
393 sz >= sizeof (db_expr_t);
394 sz -= sizeof (db_expr_t)) {
395 if (nitems-- == 0) {
396 db_putchar('\n');
397 goto restart;
398 }
399 value = db_get_task_value(next_addr,
400 sizeof (db_expr_t),
401 FALSE,task);
402 db_printf("%-*llu", width, (unsigned long long)value);
403 next_addr += sizeof (db_expr_t);
404 }
405 if (sz > 0) {
406 if (nitems-- == 0) {
407 db_putchar('\n');
408 goto restart;
409 }
410 value = db_get_task_value(next_addr, sz,
411 FALSE, task);
412 db_printf("%-*llU", width, (unsigned long long)value);
413 next_addr += sz;
414 }
415 break;
416 case 'o': /* unsigned octal */
417 for (sz = size, next_addr = addr;
418 sz >= sizeof (db_expr_t);
419 sz -= sizeof (db_expr_t)) {
420 if (nitems-- == 0) {
421 db_putchar('\n');
422 goto restart;
423 }
424 value = db_get_task_value(next_addr,
425 sizeof (db_expr_t),
426 FALSE,task);
427 db_printf("%-*llo", width, (unsigned long long)value);
428 next_addr += sizeof (db_expr_t);
429 }
430 if (sz > 0) {
431 if (nitems-- == 0) {
432 db_putchar('\n');
433 goto restart;
434 }
435 value = db_get_task_value(next_addr, sz,
436 FALSE, task);
437 db_printf("%-*llo", width, (unsigned long long)value);
438 next_addr += sz;
439 }
440 break;
441 case 'c': /* character */
442 for (sz = 0, next_addr = addr;
443 sz < size;
444 sz++, next_addr++) {
445 value = db_get_task_value(next_addr,1,
446 FALSE,task);
447 if ((value >= ' ' && value <= '~') ||
448 value == '\n' ||
449 value == '\t')
450 db_printf("%llc", (unsigned long long)value);
451 else
452 db_printf("\\%03llo", (unsigned long long)value);
453 }
454 break;
455 case 's': /* null-terminated string */
456 size = 0;
457 for (;;) {
458 value = db_get_task_value(next_addr,1,
459 FALSE,task);
460 next_addr += 1;
461 size++;
462 if (value == 0)
463 break;
464 if (value >= ' ' && value <= '~')
465 db_printf("%llc", (unsigned long long)value);
466 else
467 db_printf("\\%03llo", (unsigned long long)value);
468 }
469 break;
470 case 'i': /* instruction */
471 next_addr = db_disasm(addr, FALSE, task);
472 size = next_addr - addr;
473 break;
474 case 'I': /* instruction, alternate form */
475 next_addr = db_disasm(addr, TRUE, task);
476 size = next_addr - addr;
477 break;
478 default:
479 break;
480 }
481 if (db_print_position() != 0)
482 db_end_line();
483 break;
484 }
485 }
486 addr = next_addr;
487 }
488 db_next = addr;
489 }
490
491 /*
492 * Print value.
493 */
494 char db_print_format = 'x';
495
496 void
497 db_print_cmd(void)
498 {
499 db_expr_t value;
500 int t;
501 task_t task = TASK_NULL;
502
503 if ((t = db_read_token()) == tSLASH) {
504 if (db_read_token() != tIDENT) {
505 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
506 db_error(0);
507 /* NOTREACHED */
508 }
509 if (db_tok_string[0])
510 db_print_format = db_tok_string[0];
511 if (db_option(db_tok_string, 't')) {
512 if (db_default_act)
513 task = db_default_act->task;
514 if (db_print_format == 't')
515 db_print_format = db_tok_string[1];
516 }
517 } else
518 db_unread_token(t);
519
520 for ( ; ; ) {
521 t = db_read_token();
522 if (t == tSTRING) {
523 db_printf("%s", db_tok_string);
524 continue;
525 }
526 db_unread_token(t);
527 if (!db_expression(&value))
528 break;
529 switch (db_print_format) {
530 case 'a':
531 case 'A':
532 db_task_printsym((db_addr_t)value,
533 (db_print_format == 'a') ? DB_STGY_ANY:
534 DB_STGY_PROC,
535 task);
536 break;
537 case 'r':
538 db_printf("%11llr", (unsigned long long)value);
539 break;
540 case 'X':
541 db_printf("%016llX", (unsigned long long)value);
542 break;
543 case 'x':
544 db_printf("%016llx", (unsigned long long)value);
545 break;
546 case 'z':
547 db_printf("%16llz", (unsigned long long)value);
548 break;
549 case 'd':
550 db_printf("%11lld", (unsigned long long)value);
551 break;
552 case 'u':
553 db_printf("%11llu", (unsigned long long)value);
554 break;
555 case 'o':
556 db_printf("%16llo", (unsigned long long)value);
557 break;
558 case 'c':
559 value = value & 0xFF;
560 if (value >= ' ' && value <= '~')
561 db_printf("%llc", (unsigned long long)value);
562 else
563 db_printf("\\%03llo", (unsigned long long)value);
564 break;
565 default:
566 db_printf("Unknown format %c\n", db_print_format);
567 db_print_format = 'x';
568 db_error(0);
569 }
570 }
571 }
572
573 void
574 db_print_loc(
575 db_addr_t loc,
576 task_t task)
577 {
578 db_task_printsym(loc, DB_STGY_PROC, task);
579 }
580
581 void
582 db_print_inst(
583 db_addr_t loc,
584 task_t task)
585 {
586 (void) db_disasm(loc, TRUE, task);
587 }
588
589 void
590 db_print_loc_and_inst(
591 db_addr_t loc,
592 task_t task)
593 {
594 db_task_printsym(loc, DB_STGY_PROC, task);
595 db_printf(":\t");
596 (void) db_disasm(loc, TRUE, task);
597 }
598
599 /*
600 * Search for a value in memory.
601 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
602 */
603 void
604 db_search_cmd(void)
605 {
606 int t;
607 db_addr_t addr;
608 int size = 0;
609 db_expr_t value;
610 db_expr_t mask;
611 db_addr_t count;
612 thread_t thr_act;
613 boolean_t thread_flag = FALSE;
614 register char *p;
615
616 t = db_read_token();
617 if (t == tSLASH) {
618 t = db_read_token();
619 if (t != tIDENT) {
620 bad_modifier:
621 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
622 db_flush_lex();
623 return;
624 }
625
626 for (p = db_tok_string; *p; p++) {
627 switch(*p) {
628 case 'b':
629 size = sizeof(char);
630 break;
631 case 'h':
632 size = sizeof(short);
633 break;
634 case 'l':
635 size = sizeof(long);
636 break;
637 case 't':
638 thread_flag = TRUE;
639 break;
640 default:
641 goto bad_modifier;
642 }
643 }
644 } else {
645 db_unread_token(t);
646 size = sizeof(int);
647 }
648
649 if (!db_expression((db_expr_t *) &addr)) {
650 db_printf("Address missing\n");
651 db_flush_lex();
652 return;
653 }
654
655 if (!db_expression(&value)) {
656 db_printf("Value missing\n");
657 db_flush_lex();
658 return;
659 }
660
661 if (!db_expression(&mask))
662 mask = ~0;
663
664 t = db_read_token();
665 if (t == tCOMMA) {
666 if (!db_expression((db_expr_t *) &count)) {
667 db_printf("Count missing\n");
668 db_flush_lex();
669 return;
670 }
671 } else {
672 db_unread_token(t);
673 count = -1; /* effectively forever */
674 }
675 if (thread_flag) {
676 if (!db_get_next_act(&thr_act, 0))
677 return;
678 } else
679 thr_act = THREAD_NULL;
680
681 db_search(addr, size, value, mask, count, db_act_to_task(thr_act));
682 }
683
684 void
685 db_search(
686 db_addr_t addr,
687 int size,
688 db_expr_t value,
689 db_expr_t mask,
690 unsigned int count,
691 task_t task)
692 {
693 while (count-- != 0) {
694 db_prev = addr;
695 if ((db_get_task_value(addr,size,FALSE,task) & mask) == value)
696 break;
697 addr += size;
698 }
699 db_printf("0x%llx: ", (unsigned long long)addr);
700 db_next = addr;
701 }
702
703 #define DB_XCDUMP_NC 16
704
705 int
706 db_xcdump(
707 db_addr_t addr,
708 int size,
709 int count,
710 task_t task)
711 {
712 register int i, n;
713 db_expr_t value;
714 int bcount;
715 db_addr_t off;
716 char *name;
717 char data[DB_XCDUMP_NC];
718
719 db_find_task_sym_and_offset(addr, &name, &off, task);
720 for (n = count*size; n > 0; n -= bcount) {
721 db_prev = addr;
722 if (off == 0) {
723 db_printf("%s:\n", name);
724 off = -1;
725 }
726 db_printf("%0*llX:%s", 2*sizeof(db_addr_t),(unsigned long long) addr,
727 (size != 1) ? " " : "" );
728 bcount = ((n > DB_XCDUMP_NC)? DB_XCDUMP_NC: n);
729 if (trunc_page_32(addr) != trunc_page_32(addr+bcount-1)) {
730 db_addr_t next_page_addr = trunc_page_32(addr+bcount-1);
731 if (!DB_CHECK_ACCESS(next_page_addr, sizeof(int), task))
732 bcount = next_page_addr - addr;
733 }
734 db_read_bytes((vm_offset_t)addr, bcount, data, task);
735 for (i = 0; i < bcount && off != 0; i += size) {
736 if (i % 4 == 0)
737 db_printf(" ");
738 value = db_get_task_value(addr, size, FALSE, task);
739 db_printf("%0*llX ", size*2, (unsigned long long)value);
740 addr += size;
741 db_find_task_sym_and_offset(addr, &name, &off, task);
742 }
743 db_printf("%*s",
744 ((DB_XCDUMP_NC-i)/size)*(size*2+1)+(DB_XCDUMP_NC-i)/4,
745 "");
746 bcount = i;
747 db_printf("%s*", (size != 1)? " ": "");
748 for (i = 0; i < bcount; i++) {
749 value = data[i];
750 db_printf("%llc", (value >= ' ' && value <= '~')? (unsigned long long)value: (unsigned long long)'.');
751 }
752 db_printf("*\n");
753 }
754 return(addr);
755 }