2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
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.
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.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
56 * Author: David B. Golub, Carnegie Mellon University
59 #include <string.h> /* For strcpy() */
60 #include <mach/boolean.h>
61 #include <machine/db_machdep.h>
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>
76 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
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
;
83 extern int db_max_width
;
86 /* Prototypes for functions local to this file. XXX -- should be static!
100 * Examine (print) data.
109 thread_act_t thr_act
;
110 extern char db_last_modifier
[];
112 if (modif
[0] != '\0')
113 strcpy(db_examine_format
, modif
);
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))
124 if (db_option(modif
,'u'))
125 thr_act
= current_act();
127 thr_act
= THR_ACT_NULL
;
129 db_examine_act
= thr_act
;
130 db_examine((db_addr_t
) addr
, db_examine_format
, count
,
131 db_act_to_task(thr_act
));
141 db_examine(db_next
, db_examine_format
, db_examine_count
,
142 db_act_to_task(db_examine_act
));
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
));
167 width
= size
* 2 + 1;
168 sz
= (db_max_width
- (sizeof (void *) * 2 + 4)) / width
;
169 for (entry
= 1; (entry
<< 1) < sz
; entry
<<= 1)
172 sz
= sizeof (void *) * 2 + 4 + entry
* width
;
173 while (sz
+ entry
< db_max_width
) {
177 *remainder
= (db_max_width
- sz
+ 1) / 2;
185 char * fmt
, /* format string */
186 int count
, /* repeat count */
200 db_examine_prev_addr
= addr
;
201 while (--count
>= 0) {
204 width
= db_examine_width(size
, &items
, &leader
);
205 while ((c
= *fp
++) != 0) {
209 width
= db_examine_width(size
, &items
, &leader
);
212 size
= sizeof(short);
213 width
= db_examine_width(size
, &items
, &leader
);
217 width
= db_examine_width(size
, &items
, &leader
);
221 width
= db_examine_width(size
, &items
, &leader
);
223 case 'a': /* address */
224 case 'A': /* function address */
225 /* always forces a new line */
226 if (db_print_position() != 0)
229 next_addr
= addr
+ 4;
230 db_task_printsym(addr
,
231 (c
== 'a')?DB_STGY_ANY
:DB_STGY_PROC
,
236 db_next
= db_xcdump(addr
, size
, count
+1, task
);
243 /* Reset next_addr in case we are printing in
246 if (db_print_position() == 0) {
247 /* If we hit a new symbol, print it */
251 db_find_task_sym_and_offset(addr
,&name
,&off
,task
);
253 db_printf("\r%s:\n", name
);
254 db_printf("%#n: ", addr
);
255 for (sz
= 0; sz
< leader
; sz
++)
262 case 'p': /* Addrs rendered symbolically. */
263 if( size
== sizeof(void *) ) {
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
);
275 db_printf("+%llX", offset
);
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
)) {
288 value
= db_get_task_value(next_addr
,
291 db_printf("%-*llr", width
, value
);
292 next_addr
+= sizeof (db_expr_t
);
299 value
= db_get_task_value(next_addr
, sz
,
301 db_printf("%-*llR", width
, value
);
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
)) {
314 value
= db_get_task_value(next_addr
,
318 db_printf("%0*llX ", 2*size
, value
);
320 db_printf("%-*llx", width
, value
);
321 next_addr
+= sizeof (db_expr_t
);
328 value
= db_get_task_value(next_addr
, sz
,
331 db_printf("%0*llX ", 2*size
, value
);
333 db_printf("%-*llX", width
, value
);
337 case 'z': /* signed hex */
338 for (sz
= size
, next_addr
= addr
;
339 sz
>= sizeof (db_expr_t
);
340 sz
-= sizeof (db_expr_t
)) {
345 value
= db_get_task_value(next_addr
,
348 db_printf("%-*llz", width
, value
);
349 next_addr
+= sizeof (db_expr_t
);
356 value
= db_get_task_value(next_addr
,sz
,
358 db_printf("%-*llZ", width
, value
);
362 case 'd': /* signed decimal */
363 for (sz
= size
, next_addr
= addr
;
364 sz
>= sizeof (db_expr_t
);
365 sz
-= sizeof (db_expr_t
)) {
370 value
= db_get_task_value(next_addr
,
373 db_printf("%-*lld", width
, value
);
374 next_addr
+= sizeof (db_expr_t
);
381 value
= db_get_task_value(next_addr
, sz
,
383 db_printf("%-*llD", width
, value
);
387 case 'U': /* unsigned decimal */
389 for (sz
= size
, next_addr
= addr
;
390 sz
>= sizeof (db_expr_t
);
391 sz
-= sizeof (db_expr_t
)) {
396 value
= db_get_task_value(next_addr
,
399 db_printf("%-*llu", width
, value
);
400 next_addr
+= sizeof (db_expr_t
);
407 value
= db_get_task_value(next_addr
, sz
,
409 db_printf("%-*llU", width
, value
);
413 case 'o': /* unsigned octal */
414 for (sz
= size
, next_addr
= addr
;
415 sz
>= sizeof (db_expr_t
);
416 sz
-= sizeof (db_expr_t
)) {
421 value
= db_get_task_value(next_addr
,
424 db_printf("%-*llo", width
, value
);
425 next_addr
+= sizeof (db_expr_t
);
432 value
= db_get_task_value(next_addr
, sz
,
434 db_printf("%-*llo", width
, value
);
438 case 'c': /* character */
439 for (sz
= 0, next_addr
= addr
;
442 value
= db_get_task_value(next_addr
,1,
444 if ((value
>= ' ' && value
<= '~') ||
447 db_printf("%llc", value
);
449 db_printf("\\%03llo", value
);
452 case 's': /* null-terminated string */
455 value
= db_get_task_value(next_addr
,1,
461 if (value
>= ' ' && value
<= '~')
462 db_printf("%llc", value
);
464 db_printf("\\%03llo", value
);
467 case 'i': /* instruction */
468 next_addr
= db_disasm(addr
, FALSE
, task
);
469 size
= next_addr
- addr
;
471 case 'I': /* instruction, alternate form */
472 next_addr
= db_disasm(addr
, TRUE
, task
);
473 size
= next_addr
- addr
;
478 if (db_print_position() != 0)
491 char db_print_format
= 'x';
498 task_t task
= TASK_NULL
;
500 if ((t
= db_read_token()) == tSLASH
) {
501 if (db_read_token() != tIDENT
) {
502 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
506 if (db_tok_string
[0])
507 db_print_format
= db_tok_string
[0];
508 if (db_option(db_tok_string
, 't')) {
510 task
= db_default_act
->task
;
511 if (db_print_format
== 't')
512 db_print_format
= db_tok_string
[1];
520 db_printf("%s", db_tok_string
);
524 if (!db_expression(&value
))
526 switch (db_print_format
) {
529 db_task_printsym((db_addr_t
)value
,
530 (db_print_format
== 'a') ? DB_STGY_ANY
:
535 db_printf("%11llr", value
);
538 db_printf("%016llX", value
);
541 db_printf("%016llx", value
);
544 db_printf("%16llz", value
);
547 db_printf("%11lld", value
);
550 db_printf("%11llu", value
);
553 db_printf("%16llo", value
);
556 value
= value
& 0xFF;
557 if (value
>= ' ' && value
<= '~')
558 db_printf("%llc", value
);
560 db_printf("\\%03llo", value
);
563 db_printf("Unknown format %c\n", db_print_format
);
564 db_print_format
= 'x';
575 db_task_printsym(loc
, DB_STGY_PROC
, task
);
583 (void) db_disasm(loc
, TRUE
, task
);
587 db_print_loc_and_inst(
591 db_task_printsym(loc
, DB_STGY_PROC
, task
);
593 (void) db_disasm(loc
, TRUE
, task
);
597 * Search for a value in memory.
598 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
609 thread_act_t thr_act
;
610 boolean_t thread_flag
= FALSE
;
618 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
623 for (p
= db_tok_string
; *p
; p
++) {
629 size
= sizeof(short);
646 if (!db_expression((db_expr_t
*) &addr
)) {
647 db_printf("Address missing\n");
652 if (!db_expression(&value
)) {
653 db_printf("Value missing\n");
658 if (!db_expression(&mask
))
663 if (!db_expression((db_expr_t
*) &count
)) {
664 db_printf("Count missing\n");
670 count
= -1; /* effectively forever */
673 if (!db_get_next_act(&thr_act
, 0))
676 thr_act
= THR_ACT_NULL
;
678 db_search(addr
, size
, value
, mask
, count
, db_act_to_task(thr_act
));
690 while (count
-- != 0) {
692 if ((db_get_task_value(addr
,size
,FALSE
,task
) & mask
) == value
)
696 db_printf("0x%x: ", addr
);
700 #define DB_XCDUMP_NC 16
714 char data
[DB_XCDUMP_NC
];
716 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
717 for (n
= count
*size
; n
> 0; n
-= bcount
) {
720 db_printf("%s:\n", name
);
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
;
731 db_read_bytes((vm_offset_t
)addr
, bcount
, data
, task
);
732 for (i
= 0; i
< bcount
&& off
!= 0; i
+= size
) {
735 value
= db_get_task_value(addr
, size
, FALSE
, task
);
736 db_printf("%0*llX ", size
*2, value
);
738 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
741 ((DB_XCDUMP_NC
-i
)/size
)*(size
*2+1)+(DB_XCDUMP_NC
-i
)/4,
744 db_printf("%s*", (size
!= 1)? " ": "");
745 for (i
= 0; i
< bcount
; i
++) {
747 db_printf("%llc", (value
>= ' ' && value
<= '~')? value
: '.');