2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
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.
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.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
59 * Author: David B. Golub, Carnegie Mellon University
62 #include <string.h> /* For strcpy() */
63 #include <mach/boolean.h>
64 #include <machine/db_machdep.h>
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>
79 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
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
;
86 extern int db_max_width
;
89 /* Prototypes for functions local to this file. XXX -- should be static!
103 * Examine (print) data.
113 extern char db_last_modifier
[];
115 if (modif
[0] != '\0')
116 strcpy(db_examine_format
, modif
);
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))
127 if (db_option(modif
,'u'))
128 thr_act
= current_act();
130 thr_act
= THREAD_NULL
;
132 db_examine_act
= thr_act
;
133 db_examine((db_addr_t
) addr
, db_examine_format
, count
,
134 db_act_to_task(thr_act
));
144 db_examine(db_next
, db_examine_format
, db_examine_count
,
145 db_act_to_task(db_examine_act
));
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
));
170 width
= size
* 2 + 1;
171 sz
= (db_max_width
- (sizeof (void *) * 2 + 4)) / width
;
172 for (entry
= 1; (entry
<< 1) < sz
; entry
<<= 1)
175 sz
= sizeof (void *) * 2 + 4 + entry
* width
;
176 while (sz
+ entry
< db_max_width
) {
180 *remainder
= (db_max_width
- sz
+ 1) / 2;
188 char * fmt
, /* format string */
189 int count
, /* repeat count */
203 db_examine_prev_addr
= addr
;
204 while (--count
>= 0) {
207 width
= db_examine_width(size
, &items
, &leader
);
208 while ((c
= *fp
++) != 0) {
212 width
= db_examine_width(size
, &items
, &leader
);
215 size
= sizeof(short);
216 width
= db_examine_width(size
, &items
, &leader
);
220 width
= db_examine_width(size
, &items
, &leader
);
224 width
= db_examine_width(size
, &items
, &leader
);
226 case 'a': /* address */
227 case 'A': /* function address */
228 /* always forces a new line */
229 if (db_print_position() != 0)
232 next_addr
= addr
+ 4;
233 db_task_printsym(addr
,
234 (c
== 'a')?DB_STGY_ANY
:DB_STGY_PROC
,
239 db_next
= db_xcdump(addr
, size
, count
+1, task
);
246 /* Reset next_addr in case we are printing in
249 if (db_print_position() == 0) {
250 /* If we hit a new symbol, print it */
254 db_find_task_sym_and_offset(addr
,&name
,&off
,task
);
256 db_printf("\r%s:\n", name
);
257 db_printf("%#lln: ", (unsigned long long)addr
);
258 for (sz
= 0; sz
< leader
; sz
++)
265 case 'p': /* Addrs rendered symbolically. */
266 if( size
== sizeof(void *) ) {
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
);
278 db_printf("+%llX", (unsigned long long)offset
);
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
)) {
291 value
= db_get_task_value(next_addr
,
294 db_printf("%-*llr", width
, (unsigned long long)value
);
295 next_addr
+= sizeof (db_expr_t
);
302 value
= db_get_task_value(next_addr
, sz
,
304 db_printf("%-*llR", width
, (unsigned long long)value
);
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
)) {
317 value
= db_get_task_value(next_addr
,
321 db_printf("%0*llX ", 2*size
, (unsigned long long)value
);
323 db_printf("%-*llx", width
, (unsigned long long)value
);
324 next_addr
+= sizeof (db_expr_t
);
331 value
= db_get_task_value(next_addr
, sz
,
334 db_printf("%0*llX ", 2*size
, (unsigned long long)value
);
336 db_printf("%-*llX", width
, (unsigned long long)value
);
340 case 'z': /* signed hex */
341 for (sz
= size
, next_addr
= addr
;
342 sz
>= sizeof (db_expr_t
);
343 sz
-= sizeof (db_expr_t
)) {
348 value
= db_get_task_value(next_addr
,
351 db_printf("%-*llz", width
, (unsigned long long)value
);
352 next_addr
+= sizeof (db_expr_t
);
359 value
= db_get_task_value(next_addr
,sz
,
361 db_printf("%-*llZ", width
, (unsigned long long)value
);
365 case 'd': /* signed decimal */
366 for (sz
= size
, next_addr
= addr
;
367 sz
>= sizeof (db_expr_t
);
368 sz
-= sizeof (db_expr_t
)) {
373 value
= db_get_task_value(next_addr
,
376 db_printf("%-*lld", width
, (unsigned long long)value
);
377 next_addr
+= sizeof (db_expr_t
);
384 value
= db_get_task_value(next_addr
, sz
,
386 db_printf("%-*llD", width
, (unsigned long long)value
);
390 case 'U': /* unsigned decimal */
392 for (sz
= size
, next_addr
= addr
;
393 sz
>= sizeof (db_expr_t
);
394 sz
-= sizeof (db_expr_t
)) {
399 value
= db_get_task_value(next_addr
,
402 db_printf("%-*llu", width
, (unsigned long long)value
);
403 next_addr
+= sizeof (db_expr_t
);
410 value
= db_get_task_value(next_addr
, sz
,
412 db_printf("%-*llU", width
, (unsigned long long)value
);
416 case 'o': /* unsigned octal */
417 for (sz
= size
, next_addr
= addr
;
418 sz
>= sizeof (db_expr_t
);
419 sz
-= sizeof (db_expr_t
)) {
424 value
= db_get_task_value(next_addr
,
427 db_printf("%-*llo", width
, (unsigned long long)value
);
428 next_addr
+= sizeof (db_expr_t
);
435 value
= db_get_task_value(next_addr
, sz
,
437 db_printf("%-*llo", width
, (unsigned long long)value
);
441 case 'c': /* character */
442 for (sz
= 0, next_addr
= addr
;
445 value
= db_get_task_value(next_addr
,1,
447 if ((value
>= ' ' && value
<= '~') ||
450 db_printf("%llc", (unsigned long long)value
);
452 db_printf("\\%03llo", (unsigned long long)value
);
455 case 's': /* null-terminated string */
458 value
= db_get_task_value(next_addr
,1,
464 if (value
>= ' ' && value
<= '~')
465 db_printf("%llc", (unsigned long long)value
);
467 db_printf("\\%03llo", (unsigned long long)value
);
470 case 'i': /* instruction */
471 next_addr
= db_disasm(addr
, FALSE
, task
);
472 size
= next_addr
- addr
;
474 case 'I': /* instruction, alternate form */
475 next_addr
= db_disasm(addr
, TRUE
, task
);
476 size
= next_addr
- addr
;
481 if (db_print_position() != 0)
494 char db_print_format
= 'x';
501 task_t task
= TASK_NULL
;
503 if ((t
= db_read_token()) == tSLASH
) {
504 if (db_read_token() != tIDENT
) {
505 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
509 if (db_tok_string
[0])
510 db_print_format
= db_tok_string
[0];
511 if (db_option(db_tok_string
, 't')) {
513 task
= db_default_act
->task
;
514 if (db_print_format
== 't')
515 db_print_format
= db_tok_string
[1];
523 db_printf("%s", db_tok_string
);
527 if (!db_expression(&value
))
529 switch (db_print_format
) {
532 db_task_printsym((db_addr_t
)value
,
533 (db_print_format
== 'a') ? DB_STGY_ANY
:
538 db_printf("%11llr", (unsigned long long)value
);
541 db_printf("%016llX", (unsigned long long)value
);
544 db_printf("%016llx", (unsigned long long)value
);
547 db_printf("%16llz", (unsigned long long)value
);
550 db_printf("%11lld", (unsigned long long)value
);
553 db_printf("%11llu", (unsigned long long)value
);
556 db_printf("%16llo", (unsigned long long)value
);
559 value
= value
& 0xFF;
560 if (value
>= ' ' && value
<= '~')
561 db_printf("%llc", (unsigned long long)value
);
563 db_printf("\\%03llo", (unsigned long long)value
);
566 db_printf("Unknown format %c\n", db_print_format
);
567 db_print_format
= 'x';
578 db_task_printsym(loc
, DB_STGY_PROC
, task
);
586 (void) db_disasm(loc
, TRUE
, task
);
590 db_print_loc_and_inst(
594 db_task_printsym(loc
, DB_STGY_PROC
, task
);
596 (void) db_disasm(loc
, TRUE
, task
);
600 * Search for a value in memory.
601 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
613 boolean_t thread_flag
= FALSE
;
621 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
626 for (p
= db_tok_string
; *p
; p
++) {
632 size
= sizeof(short);
649 if (!db_expression((db_expr_t
*) &addr
)) {
650 db_printf("Address missing\n");
655 if (!db_expression(&value
)) {
656 db_printf("Value missing\n");
661 if (!db_expression(&mask
))
666 if (!db_expression((db_expr_t
*) &count
)) {
667 db_printf("Count missing\n");
673 count
= -1; /* effectively forever */
676 if (!db_get_next_act(&thr_act
, 0))
679 thr_act
= THREAD_NULL
;
681 db_search(addr
, size
, value
, mask
, count
, db_act_to_task(thr_act
));
693 while (count
-- != 0) {
695 if ((db_get_task_value(addr
,size
,FALSE
,task
) & mask
) == value
)
699 db_printf("0x%llx: ", (unsigned long long)addr
);
703 #define DB_XCDUMP_NC 16
717 char data
[DB_XCDUMP_NC
];
719 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
720 for (n
= count
*size
; n
> 0; n
-= bcount
) {
723 db_printf("%s:\n", name
);
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
;
734 db_read_bytes((vm_offset_t
)addr
, bcount
, data
, task
);
735 for (i
= 0; i
< bcount
&& off
!= 0; i
+= size
) {
738 value
= db_get_task_value(addr
, size
, FALSE
, task
);
739 db_printf("%0*llX ", size
*2, (unsigned long long)value
);
741 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
744 ((DB_XCDUMP_NC
-i
)/size
)*(size
*2+1)+(DB_XCDUMP_NC
-i
)/4,
747 db_printf("%s*", (size
!= 1)? " ": "");
748 for (i
= 0; i
< bcount
; i
++) {
750 db_printf("%llc", (value
>= ' ' && value
<= '~')? (unsigned long long)value
: (unsigned long long)'.');