2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 * Author: David B. Golub, Carnegie Mellon University
56 #include <string.h> /* For strcpy() */
57 #include <mach/boolean.h>
58 #include <machine/db_machdep.h>
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>
73 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
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
;
80 extern int db_max_width
;
83 /* Prototypes for functions local to this file. XXX -- should be static!
97 * Examine (print) data.
106 thread_act_t thr_act
;
107 extern char db_last_modifier
[];
109 if (modif
[0] != '\0')
110 strcpy(db_examine_format
, modif
);
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))
121 if (db_option(modif
,'u'))
122 thr_act
= current_act();
124 thr_act
= THR_ACT_NULL
;
126 db_examine_act
= thr_act
;
127 db_examine((db_addr_t
) addr
, db_examine_format
, count
,
128 db_act_to_task(thr_act
));
138 db_examine(db_next
, db_examine_format
, db_examine_count
,
139 db_act_to_task(db_examine_act
));
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
));
164 width
= size
* 2 + 1;
165 sz
= (db_max_width
- (sizeof (void *) * 2 + 4)) / width
;
166 for (entry
= 1; (entry
<< 1) < sz
; entry
<<= 1)
169 sz
= sizeof (void *) * 2 + 4 + entry
* width
;
170 while (sz
+ entry
< db_max_width
) {
174 *remainder
= (db_max_width
- sz
+ 1) / 2;
182 char * fmt
, /* format string */
183 int count
, /* repeat count */
197 db_examine_prev_addr
= addr
;
198 while (--count
>= 0) {
201 width
= db_examine_width(size
, &items
, &leader
);
202 while ((c
= *fp
++) != 0) {
206 width
= db_examine_width(size
, &items
, &leader
);
209 size
= sizeof(short);
210 width
= db_examine_width(size
, &items
, &leader
);
214 width
= db_examine_width(size
, &items
, &leader
);
218 width
= db_examine_width(size
, &items
, &leader
);
220 case 'a': /* address */
221 case 'A': /* function address */
222 /* always forces a new line */
223 if (db_print_position() != 0)
226 next_addr
= addr
+ 4;
227 db_task_printsym(addr
,
228 (c
== 'a')?DB_STGY_ANY
:DB_STGY_PROC
,
233 db_next
= db_xcdump(addr
, size
, count
+1, task
);
240 /* Reset next_addr in case we are printing in
243 if (db_print_position() == 0) {
244 /* If we hit a new symbol, print it */
248 db_find_task_sym_and_offset(addr
,&name
,&off
,task
);
250 db_printf("\r%s:\n", name
);
251 db_printf("%#n: ", addr
);
252 for (sz
= 0; sz
< leader
; sz
++)
259 case 'p': /* Addrs rendered symbolically. */
260 if( size
== sizeof(void *) ) {
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
);
272 db_printf("+%llX", offset
);
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
)) {
285 value
= db_get_task_value(next_addr
,
288 db_printf("%-*llr", width
, value
);
289 next_addr
+= sizeof (db_expr_t
);
296 value
= db_get_task_value(next_addr
, sz
,
298 db_printf("%-*llR", width
, value
);
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
)) {
311 value
= db_get_task_value(next_addr
,
315 db_printf("%0*llX ", 2*size
, value
);
317 db_printf("%-*llx", width
, value
);
318 next_addr
+= sizeof (db_expr_t
);
325 value
= db_get_task_value(next_addr
, sz
,
328 db_printf("%0*llX ", 2*size
, value
);
330 db_printf("%-*llX", width
, value
);
334 case 'z': /* signed hex */
335 for (sz
= size
, next_addr
= addr
;
336 sz
>= sizeof (db_expr_t
);
337 sz
-= sizeof (db_expr_t
)) {
342 value
= db_get_task_value(next_addr
,
345 db_printf("%-*llz", width
, value
);
346 next_addr
+= sizeof (db_expr_t
);
353 value
= db_get_task_value(next_addr
,sz
,
355 db_printf("%-*llZ", width
, value
);
359 case 'd': /* signed decimal */
360 for (sz
= size
, next_addr
= addr
;
361 sz
>= sizeof (db_expr_t
);
362 sz
-= sizeof (db_expr_t
)) {
367 value
= db_get_task_value(next_addr
,
370 db_printf("%-*lld", width
, value
);
371 next_addr
+= sizeof (db_expr_t
);
378 value
= db_get_task_value(next_addr
, sz
,
380 db_printf("%-*llD", width
, value
);
384 case 'U': /* unsigned decimal */
386 for (sz
= size
, next_addr
= addr
;
387 sz
>= sizeof (db_expr_t
);
388 sz
-= sizeof (db_expr_t
)) {
393 value
= db_get_task_value(next_addr
,
396 db_printf("%-*llu", width
, value
);
397 next_addr
+= sizeof (db_expr_t
);
404 value
= db_get_task_value(next_addr
, sz
,
406 db_printf("%-*llU", width
, value
);
410 case 'o': /* unsigned octal */
411 for (sz
= size
, next_addr
= addr
;
412 sz
>= sizeof (db_expr_t
);
413 sz
-= sizeof (db_expr_t
)) {
418 value
= db_get_task_value(next_addr
,
421 db_printf("%-*llo", width
, value
);
422 next_addr
+= sizeof (db_expr_t
);
429 value
= db_get_task_value(next_addr
, sz
,
431 db_printf("%-*llo", width
, value
);
435 case 'c': /* character */
436 for (sz
= 0, next_addr
= addr
;
439 value
= db_get_task_value(next_addr
,1,
441 if ((value
>= ' ' && value
<= '~') ||
444 db_printf("%llc", value
);
446 db_printf("\\%03llo", value
);
449 case 's': /* null-terminated string */
452 value
= db_get_task_value(next_addr
,1,
458 if (value
>= ' ' && value
<= '~')
459 db_printf("%llc", value
);
461 db_printf("\\%03llo", value
);
464 case 'i': /* instruction */
465 next_addr
= db_disasm(addr
, FALSE
, task
);
466 size
= next_addr
- addr
;
468 case 'I': /* instruction, alternate form */
469 next_addr
= db_disasm(addr
, TRUE
, task
);
470 size
= next_addr
- addr
;
475 if (db_print_position() != 0)
488 char db_print_format
= 'x';
495 task_t task
= TASK_NULL
;
497 if ((t
= db_read_token()) == tSLASH
) {
498 if (db_read_token() != tIDENT
) {
499 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
503 if (db_tok_string
[0])
504 db_print_format
= db_tok_string
[0];
505 if (db_option(db_tok_string
, 't')) {
507 task
= db_default_act
->task
;
508 if (db_print_format
== 't')
509 db_print_format
= db_tok_string
[1];
517 db_printf("%s", db_tok_string
);
521 if (!db_expression(&value
))
523 switch (db_print_format
) {
526 db_task_printsym((db_addr_t
)value
,
527 (db_print_format
== 'a') ? DB_STGY_ANY
:
532 db_printf("%11llr", value
);
535 db_printf("%016llX", value
);
538 db_printf("%016llx", value
);
541 db_printf("%16llz", value
);
544 db_printf("%11lld", value
);
547 db_printf("%11llu", value
);
550 db_printf("%16llo", value
);
553 value
= value
& 0xFF;
554 if (value
>= ' ' && value
<= '~')
555 db_printf("%llc", value
);
557 db_printf("\\%03llo", value
);
560 db_printf("Unknown format %c\n", db_print_format
);
561 db_print_format
= 'x';
572 db_task_printsym(loc
, DB_STGY_PROC
, task
);
580 (void) db_disasm(loc
, TRUE
, task
);
584 db_print_loc_and_inst(
588 db_task_printsym(loc
, DB_STGY_PROC
, task
);
590 (void) db_disasm(loc
, TRUE
, task
);
594 * Search for a value in memory.
595 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
606 thread_act_t thr_act
;
607 boolean_t thread_flag
= FALSE
;
615 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
620 for (p
= db_tok_string
; *p
; p
++) {
626 size
= sizeof(short);
643 if (!db_expression((db_expr_t
*) &addr
)) {
644 db_printf("Address missing\n");
649 if (!db_expression(&value
)) {
650 db_printf("Value missing\n");
655 if (!db_expression(&mask
))
660 if (!db_expression((db_expr_t
*) &count
)) {
661 db_printf("Count missing\n");
667 count
= -1; /* effectively forever */
670 if (!db_get_next_act(&thr_act
, 0))
673 thr_act
= THR_ACT_NULL
;
675 db_search(addr
, size
, value
, mask
, count
, db_act_to_task(thr_act
));
687 while (count
-- != 0) {
689 if ((db_get_task_value(addr
,size
,FALSE
,task
) & mask
) == value
)
693 db_printf("0x%x: ", addr
);
697 #define DB_XCDUMP_NC 16
711 char data
[DB_XCDUMP_NC
];
713 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
714 for (n
= count
*size
; n
> 0; n
-= bcount
) {
717 db_printf("%s:\n", name
);
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
;
728 db_read_bytes((vm_offset_t
)addr
, bcount
, data
, task
);
729 for (i
= 0; i
< bcount
&& off
!= 0; i
+= size
) {
732 value
= db_get_task_value(addr
, size
, FALSE
, task
);
733 db_printf("%0*llX ", size
*2, value
);
735 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
738 ((DB_XCDUMP_NC
-i
)/size
)*(size
*2+1)+(DB_XCDUMP_NC
-i
)/4,
741 db_printf("%s*", (size
!= 1)? " ": "");
742 for (i
= 0; i
< bcount
; i
++) {
744 db_printf("%llc", (value
>= ' ' && value
<= '~')? value
: '.');