2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
61 * Author: David B. Golub, Carnegie Mellon University
64 #include <string.h> /* For strcpy() */
65 #include <mach/boolean.h>
66 #include <machine/db_machdep.h>
68 #include <ddb/db_access.h>
69 #include <ddb/db_lex.h>
70 #include <ddb/db_output.h>
71 #include <ddb/db_command.h>
72 #include <ddb/db_sym.h>
73 #include <ddb/db_task_thread.h>
74 #include <ddb/db_command.h> /* For db_option() */
75 #include <ddb/db_examine.h>
76 #include <ddb/db_expr.h>
77 #include <kern/thread.h>
78 #include <kern/task.h>
79 #include <mach/vm_param.h>
81 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
83 char db_examine_format
[TOK_STRING_SIZE
] = "x";
84 int db_examine_count
= 1;
85 db_addr_t db_examine_prev_addr
= 0;
86 thread_t db_examine_act
= THREAD_NULL
;
88 extern int db_max_width
;
91 /* Prototypes for functions local to this file. XXX -- should be static!
105 * Examine (print) data.
115 extern char db_last_modifier
[];
117 if (modif
[0] != '\0')
118 strcpy(db_examine_format
, modif
);
122 db_examine_count
= count
;
123 if (db_option(modif
, 't')) {
124 if (modif
== db_last_modifier
)
125 thr_act
= db_examine_act
;
126 else if (!db_get_next_act(&thr_act
, 0))
129 if (db_option(modif
,'u'))
130 thr_act
= current_act();
132 thr_act
= THREAD_NULL
;
134 db_examine_act
= thr_act
;
135 db_examine((db_addr_t
) addr
, db_examine_format
, count
,
136 db_act_to_task(thr_act
));
146 db_examine(db_next
, db_examine_format
, db_examine_count
,
147 db_act_to_task(db_examine_act
));
157 db_examine(db_examine_prev_addr
- (db_next
- db_examine_prev_addr
),
158 db_examine_format
, db_examine_count
,
159 db_act_to_task(db_examine_act
));
172 width
= size
* 2 + 1;
173 sz
= (db_max_width
- (sizeof (void *) * 2 + 4)) / width
;
174 for (entry
= 1; (entry
<< 1) < sz
; entry
<<= 1)
177 sz
= sizeof (void *) * 2 + 4 + entry
* width
;
178 while (sz
+ entry
< db_max_width
) {
182 *remainder
= (db_max_width
- sz
+ 1) / 2;
190 char * fmt
, /* format string */
191 int count
, /* repeat count */
205 db_examine_prev_addr
= addr
;
206 while (--count
>= 0) {
209 width
= db_examine_width(size
, &items
, &leader
);
210 while ((c
= *fp
++) != 0) {
214 width
= db_examine_width(size
, &items
, &leader
);
217 size
= sizeof(short);
218 width
= db_examine_width(size
, &items
, &leader
);
222 width
= db_examine_width(size
, &items
, &leader
);
226 width
= db_examine_width(size
, &items
, &leader
);
228 case 'a': /* address */
229 case 'A': /* function address */
230 /* always forces a new line */
231 if (db_print_position() != 0)
234 next_addr
= addr
+ 4;
235 db_task_printsym(addr
,
236 (c
== 'a')?DB_STGY_ANY
:DB_STGY_PROC
,
241 db_next
= db_xcdump(addr
, size
, count
+1, task
);
248 /* Reset next_addr in case we are printing in
251 if (db_print_position() == 0) {
252 /* If we hit a new symbol, print it */
256 db_find_task_sym_and_offset(addr
,&name
,&off
,task
);
258 db_printf("\r%s:\n", name
);
259 db_printf("%#lln: ", (unsigned long long)addr
);
260 for (sz
= 0; sz
< leader
; sz
++)
267 case 'p': /* Addrs rendered symbolically. */
268 if( size
== sizeof(void *) ) {
273 value
= db_get_task_value( next_addr
,
274 sizeof(db_expr_t
), FALSE
, task
);
275 db_find_task_sym_and_offset( value
,
276 &symName
, &offset
, task
);
277 db_printf("\n\t*%8llX(%8llX) = %s",
278 (unsigned long long)next_addr
, (unsigned long long)value
, symName
);
280 db_printf("+%llX", (unsigned long long)offset
);
285 case 'r': /* signed, current radix */
286 for (sz
= size
, next_addr
= addr
;
287 sz
>= sizeof (db_expr_t
);
288 sz
-= sizeof (db_expr_t
)) {
293 value
= db_get_task_value(next_addr
,
296 db_printf("%-*llr", width
, (unsigned long long)value
);
297 next_addr
+= sizeof (db_expr_t
);
304 value
= db_get_task_value(next_addr
, sz
,
306 db_printf("%-*llR", width
, (unsigned long long)value
);
310 case 'X': /* unsigned hex */
311 case 'x': /* unsigned hex */
312 for (sz
= size
, next_addr
= addr
;
313 sz
>= sizeof (db_expr_t
);
314 sz
-= sizeof (db_expr_t
)) {
319 value
= db_get_task_value(next_addr
,
323 db_printf("%0*llX ", 2*size
, (unsigned long long)value
);
325 db_printf("%-*llx", width
, (unsigned long long)value
);
326 next_addr
+= sizeof (db_expr_t
);
333 value
= db_get_task_value(next_addr
, sz
,
336 db_printf("%0*llX ", 2*size
, (unsigned long long)value
);
338 db_printf("%-*llX", width
, (unsigned long long)value
);
342 case 'z': /* signed hex */
343 for (sz
= size
, next_addr
= addr
;
344 sz
>= sizeof (db_expr_t
);
345 sz
-= sizeof (db_expr_t
)) {
350 value
= db_get_task_value(next_addr
,
353 db_printf("%-*llz", width
, (unsigned long long)value
);
354 next_addr
+= sizeof (db_expr_t
);
361 value
= db_get_task_value(next_addr
,sz
,
363 db_printf("%-*llZ", width
, (unsigned long long)value
);
367 case 'd': /* signed decimal */
368 for (sz
= size
, next_addr
= addr
;
369 sz
>= sizeof (db_expr_t
);
370 sz
-= sizeof (db_expr_t
)) {
375 value
= db_get_task_value(next_addr
,
378 db_printf("%-*lld", width
, (unsigned long long)value
);
379 next_addr
+= sizeof (db_expr_t
);
386 value
= db_get_task_value(next_addr
, sz
,
388 db_printf("%-*llD", width
, (unsigned long long)value
);
392 case 'U': /* unsigned decimal */
394 for (sz
= size
, next_addr
= addr
;
395 sz
>= sizeof (db_expr_t
);
396 sz
-= sizeof (db_expr_t
)) {
401 value
= db_get_task_value(next_addr
,
404 db_printf("%-*llu", width
, (unsigned long long)value
);
405 next_addr
+= sizeof (db_expr_t
);
412 value
= db_get_task_value(next_addr
, sz
,
414 db_printf("%-*llU", width
, (unsigned long long)value
);
418 case 'o': /* unsigned octal */
419 for (sz
= size
, next_addr
= addr
;
420 sz
>= sizeof (db_expr_t
);
421 sz
-= sizeof (db_expr_t
)) {
426 value
= db_get_task_value(next_addr
,
429 db_printf("%-*llo", width
, (unsigned long long)value
);
430 next_addr
+= sizeof (db_expr_t
);
437 value
= db_get_task_value(next_addr
, sz
,
439 db_printf("%-*llo", width
, (unsigned long long)value
);
443 case 'c': /* character */
444 for (sz
= 0, next_addr
= addr
;
447 value
= db_get_task_value(next_addr
,1,
449 if ((value
>= ' ' && value
<= '~') ||
452 db_printf("%llc", (unsigned long long)value
);
454 db_printf("\\%03llo", (unsigned long long)value
);
457 case 's': /* null-terminated string */
460 value
= db_get_task_value(next_addr
,1,
466 if (value
>= ' ' && value
<= '~')
467 db_printf("%llc", (unsigned long long)value
);
469 db_printf("\\%03llo", (unsigned long long)value
);
472 case 'i': /* instruction */
473 next_addr
= db_disasm(addr
, FALSE
, task
);
474 size
= next_addr
- addr
;
476 case 'I': /* instruction, alternate form */
477 next_addr
= db_disasm(addr
, TRUE
, task
);
478 size
= next_addr
- addr
;
483 if (db_print_position() != 0)
496 char db_print_format
= 'x';
503 task_t task
= TASK_NULL
;
505 if ((t
= db_read_token()) == tSLASH
) {
506 if (db_read_token() != tIDENT
) {
507 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
511 if (db_tok_string
[0])
512 db_print_format
= db_tok_string
[0];
513 if (db_option(db_tok_string
, 't')) {
515 task
= db_default_act
->task
;
516 if (db_print_format
== 't')
517 db_print_format
= db_tok_string
[1];
525 db_printf("%s", db_tok_string
);
529 if (!db_expression(&value
))
531 switch (db_print_format
) {
534 db_task_printsym((db_addr_t
)value
,
535 (db_print_format
== 'a') ? DB_STGY_ANY
:
540 db_printf("%11llr", (unsigned long long)value
);
543 db_printf("%016llX", (unsigned long long)value
);
546 db_printf("%016llx", (unsigned long long)value
);
549 db_printf("%16llz", (unsigned long long)value
);
552 db_printf("%11lld", (unsigned long long)value
);
555 db_printf("%11llu", (unsigned long long)value
);
558 db_printf("%16llo", (unsigned long long)value
);
561 value
= value
& 0xFF;
562 if (value
>= ' ' && value
<= '~')
563 db_printf("%llc", (unsigned long long)value
);
565 db_printf("\\%03llo", (unsigned long long)value
);
568 db_printf("Unknown format %c\n", db_print_format
);
569 db_print_format
= 'x';
580 db_task_printsym(loc
, DB_STGY_PROC
, task
);
588 (void) db_disasm(loc
, TRUE
, task
);
592 db_print_loc_and_inst(
596 db_task_printsym(loc
, DB_STGY_PROC
, task
);
598 (void) db_disasm(loc
, TRUE
, task
);
602 * Search for a value in memory.
603 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
615 boolean_t thread_flag
= FALSE
;
623 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
628 for (p
= db_tok_string
; *p
; p
++) {
634 size
= sizeof(short);
651 if (!db_expression((db_expr_t
*) &addr
)) {
652 db_printf("Address missing\n");
657 if (!db_expression(&value
)) {
658 db_printf("Value missing\n");
663 if (!db_expression(&mask
))
668 if (!db_expression((db_expr_t
*) &count
)) {
669 db_printf("Count missing\n");
675 count
= -1; /* effectively forever */
678 if (!db_get_next_act(&thr_act
, 0))
681 thr_act
= THREAD_NULL
;
683 db_search(addr
, size
, value
, mask
, count
, db_act_to_task(thr_act
));
695 while (count
-- != 0) {
697 if ((db_get_task_value(addr
,size
,FALSE
,task
) & mask
) == value
)
701 db_printf("0x%llx: ", (unsigned long long)addr
);
705 #define DB_XCDUMP_NC 16
719 char data
[DB_XCDUMP_NC
];
721 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
722 for (n
= count
*size
; n
> 0; n
-= bcount
) {
725 db_printf("%s:\n", name
);
728 db_printf("%0*llX:%s", 2*sizeof(db_addr_t
),(unsigned long long) addr
,
729 (size
!= 1) ? " " : "" );
730 bcount
= ((n
> DB_XCDUMP_NC
)? DB_XCDUMP_NC
: n
);
731 if (trunc_page_32(addr
) != trunc_page_32(addr
+bcount
-1)) {
732 db_addr_t next_page_addr
= trunc_page_32(addr
+bcount
-1);
733 if (!DB_CHECK_ACCESS(next_page_addr
, sizeof(int), task
))
734 bcount
= next_page_addr
- addr
;
736 db_read_bytes((vm_offset_t
)addr
, bcount
, data
, task
);
737 for (i
= 0; i
< bcount
&& off
!= 0; i
+= size
) {
740 value
= db_get_task_value(addr
, size
, FALSE
, task
);
741 db_printf("%0*llX ", size
*2, (unsigned long long)value
);
743 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
746 ((DB_XCDUMP_NC
-i
)/size
)*(size
*2+1)+(DB_XCDUMP_NC
-i
)/4,
749 db_printf("%s*", (size
!= 1)? " ": "");
750 for (i
= 0; i
< bcount
; i
++) {
752 db_printf("%llc", (value
>= ' ' && value
<= '~')? (unsigned long long)value
: (unsigned long long)'.');