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