2 * Copyright (c) 2000-2006 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 strlcpy() */
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!
102 extern char db_last_modifier
[];
105 * Examine (print) data.
108 db_examine_cmd(db_expr_t addr
, __unused boolean_t have_addr
, db_expr_t count
,
113 if (modif
[0] != '\0')
114 strlcpy(db_examine_format
, modif
, TOK_STRING_SIZE
);
116 if (count
== (db_expr_t
)-1)
118 db_examine_count
= count
;
119 if (db_option(modif
, 't')) {
120 if (modif
== db_last_modifier
)
121 thr_act
= db_examine_act
;
122 else if (!db_get_next_act(&thr_act
, 0))
125 if (db_option(modif
,'u'))
126 thr_act
= current_thread();
128 thr_act
= THREAD_NULL
;
130 db_examine_act
= thr_act
;
131 db_examine((db_addr_t
) addr
, db_examine_format
, count
,
132 db_act_to_task(thr_act
));
136 db_examine_forward(__unused db_expr_t addr
, __unused boolean_t have_addr
,
137 __unused db_expr_t count
, __unused
char *modif
)
139 db_examine(db_next
, db_examine_format
, db_examine_count
,
140 db_act_to_task(db_examine_act
));
144 db_examine_backward(__unused db_expr_t addr
, __unused boolean_t have_addr
,
145 __unused db_expr_t count
, __unused
char *modif
)
147 db_examine(db_examine_prev_addr
- (db_next
- db_examine_prev_addr
),
148 db_examine_format
, db_examine_count
,
149 db_act_to_task(db_examine_act
));
162 width
= size
* 2 + 1;
163 sz
= (db_max_width
- (sizeof (void *) * 2 + 4)) / width
;
164 for (entry
= 1; (entry
<< 1) < sz
; entry
<<= 1)
167 sz
= sizeof (void *) * 2 + 4 + entry
* width
;
168 while (sz
+ entry
< db_max_width
) {
172 *remainder
= (db_max_width
- sz
+ 1) / 2;
180 char * fmt
, /* format string */
181 int count
, /* repeat count */
192 db_addr_t next_addr
= 0;
195 db_examine_prev_addr
= addr
;
196 while (--count
>= 0) {
199 width
= db_examine_width(size
, &items
, &leader
);
200 while ((c
= *fp
++) != 0) {
204 width
= db_examine_width(size
, &items
, &leader
);
207 size
= sizeof(short);
208 width
= db_examine_width(size
, &items
, &leader
);
212 width
= db_examine_width(size
, &items
, &leader
);
216 width
= db_examine_width(size
, &items
, &leader
);
218 case 'a': /* address */
219 case 'A': /* function address */
220 /* always forces a new line */
221 if (db_print_position() != 0)
224 next_addr
= addr
+ 4;
225 db_task_printsym(addr
,
226 (c
== 'a')?DB_STGY_ANY
:DB_STGY_PROC
,
231 db_next
= db_xcdump(addr
, size
, count
+1, task
);
238 /* Reset next_addr in case we are printing in
241 if (db_print_position() == 0) {
242 /* If we hit a new symbol, print it */
246 db_find_task_sym_and_offset(addr
,&name
,&off
,task
);
248 db_printf("\r%s:\n", name
);
249 db_printf("%#lln: ", (unsigned long long)addr
);
250 for (sz
= 0; sz
< leader
; sz
++)
257 case 'p': /* Addrs rendered symbolically. */
258 if( size
== sizeof(void *) ) {
263 value
= db_get_task_value( next_addr
,
264 sizeof(db_expr_t
), FALSE
, task
);
265 db_find_task_sym_and_offset( value
,
266 &symName
, &offset
, task
);
267 db_printf("\n\t*%8llX(%8llX) = %s",
268 (unsigned long long)next_addr
, (unsigned long long)value
, symName
);
270 db_printf("+%llX", (unsigned long long)offset
);
275 case 'r': /* signed, current radix */
276 for (sz
= size
, next_addr
= addr
;
277 sz
>= (signed)sizeof (db_expr_t
);
278 sz
-= sizeof (db_expr_t
)) {
283 value
= db_get_task_value(next_addr
,
286 db_printf("%-*llr", width
, (unsigned long long)value
);
287 next_addr
+= sizeof (db_expr_t
);
294 value
= db_get_task_value(next_addr
, sz
,
296 db_printf("%-*llR", width
, (unsigned long long)value
);
300 case 'X': /* unsigned hex */
301 case 'x': /* unsigned hex */
302 for (sz
= size
, next_addr
= addr
;
303 sz
>= (signed)sizeof (db_expr_t
);
304 sz
-= sizeof (db_expr_t
)) {
309 value
= db_get_task_value(next_addr
,
313 db_printf("%0*llX ", 2*size
, (unsigned long long)value
);
315 db_printf("%-*llx", width
, (unsigned long long)value
);
316 next_addr
+= sizeof (db_expr_t
);
323 value
= db_get_task_value(next_addr
, sz
,
326 db_printf("%0*llX ", 2*size
, (unsigned long long)value
);
328 db_printf("%-*llX", width
, (unsigned long long)value
);
332 case 'z': /* signed hex */
333 for (sz
= size
, next_addr
= addr
;
334 sz
>= (signed)sizeof (db_expr_t
);
335 sz
-= sizeof (db_expr_t
)) {
340 value
= db_get_task_value(next_addr
,
343 db_printf("%-*llz", width
, (unsigned long long)value
);
344 next_addr
+= sizeof (db_expr_t
);
351 value
= db_get_task_value(next_addr
,sz
,
353 db_printf("%-*llZ", width
, (unsigned long long)value
);
357 case 'd': /* signed decimal */
358 for (sz
= size
, next_addr
= addr
;
359 sz
>= (signed)sizeof (db_expr_t
);
360 sz
-= sizeof (db_expr_t
)) {
365 value
= db_get_task_value(next_addr
,
368 db_printf("%-*lld", width
, (unsigned long long)value
);
369 next_addr
+= sizeof (db_expr_t
);
376 value
= db_get_task_value(next_addr
, sz
,
378 db_printf("%-*llD", width
, (unsigned long long)value
);
382 case 'U': /* unsigned decimal */
384 for (sz
= size
, next_addr
= addr
;
385 sz
>= (signed)sizeof (db_expr_t
);
386 sz
-= sizeof (db_expr_t
)) {
391 value
= db_get_task_value(next_addr
,
394 db_printf("%-*llu", width
, (unsigned long long)value
);
395 next_addr
+= sizeof (db_expr_t
);
402 value
= db_get_task_value(next_addr
, sz
,
404 db_printf("%-*llU", width
, (unsigned long long)value
);
408 case 'o': /* unsigned octal */
409 for (sz
= size
, next_addr
= addr
;
410 sz
>= (signed)sizeof (db_expr_t
);
411 sz
-= sizeof (db_expr_t
)) {
416 value
= db_get_task_value(next_addr
,
419 db_printf("%-*llo", width
, (unsigned long long)value
);
420 next_addr
+= sizeof (db_expr_t
);
427 value
= db_get_task_value(next_addr
, sz
,
429 db_printf("%-*llo", width
, (unsigned long long)value
);
433 case 'c': /* character */
434 for (sz
= 0, next_addr
= addr
;
437 value
= db_get_task_value(next_addr
,1,
439 if ((value
>= ' ' && value
<= '~') ||
442 db_printf("%llc", (unsigned long long)value
);
444 db_printf("\\%03llo", (unsigned long long)value
);
447 case 's': /* null-terminated string */
450 value
= db_get_task_value(next_addr
,1,
456 if (value
>= ' ' && value
<= '~')
457 db_printf("%llc", (unsigned long long)value
);
459 db_printf("\\%03llo", (unsigned long long)value
);
462 case 'i': /* instruction */
463 next_addr
= db_disasm(addr
, FALSE
, task
);
464 size
= next_addr
- addr
;
466 case 'I': /* instruction, alternate form */
467 next_addr
= db_disasm(addr
, TRUE
, task
);
468 size
= next_addr
- addr
;
473 if (db_print_position() != 0)
486 char db_print_format
= 'x';
493 task_t task
= TASK_NULL
;
495 if ((t
= db_read_token()) == tSLASH
) {
496 if (db_read_token() != tIDENT
) {
497 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
501 if (db_tok_string
[0])
502 db_print_format
= db_tok_string
[0];
503 if (db_option(db_tok_string
, 't')) {
505 task
= db_default_act
->task
;
506 if (db_print_format
== 't')
507 db_print_format
= db_tok_string
[1];
515 db_printf("%s", db_tok_string
);
519 if (!db_expression(&value
))
521 switch (db_print_format
) {
524 db_task_printsym((db_addr_t
)value
,
525 (db_print_format
== 'a') ? DB_STGY_ANY
:
530 db_printf("%11llr", (unsigned long long)value
);
533 db_printf("%016llX", (unsigned long long)value
);
536 db_printf("%016llx", (unsigned long long)value
);
539 db_printf("%16llz", (unsigned long long)value
);
542 db_printf("%11lld", (unsigned long long)value
);
545 db_printf("%11llu", (unsigned long long)value
);
548 db_printf("%16llo", (unsigned long long)value
);
551 value
= value
& 0xFF;
552 if (value
>= ' ' && value
<= '~')
553 db_printf("%llc", (unsigned long long)value
);
555 db_printf("\\%03llo", (unsigned long long)value
);
558 db_printf("Unknown format %c\n", db_print_format
);
559 db_print_format
= 'x';
570 db_task_printsym(loc
, DB_STGY_PROC
, task
);
578 (void) db_disasm(loc
, TRUE
, task
);
582 db_print_loc_and_inst(
586 db_task_printsym(loc
, DB_STGY_PROC
, task
);
588 (void) db_disasm(loc
, TRUE
, task
);
592 * Search for a value in memory.
593 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
605 boolean_t thread_flag
= FALSE
;
613 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
618 for (p
= db_tok_string
; *p
; p
++) {
624 size
= sizeof(short);
641 if (!db_expression((db_expr_t
*) &addr
)) {
642 db_printf("Address missing\n");
647 if (!db_expression(&value
)) {
648 db_printf("Value missing\n");
653 if (!db_expression(&mask
))
658 if (!db_expression((db_expr_t
*) &count
)) {
659 db_printf("Count missing\n");
665 count
= -1; /* effectively forever */
668 if (!db_get_next_act(&thr_act
, 0))
671 thr_act
= THREAD_NULL
;
673 db_search(addr
, size
, value
, mask
, count
, db_act_to_task(thr_act
));
685 while (count
-- != 0) {
687 if ((db_get_task_value(addr
,size
,FALSE
,task
) & mask
) == value
)
691 db_printf("0x%llx: ", (unsigned long long)addr
);
695 #define DB_XCDUMP_NC 16
709 char data
[DB_XCDUMP_NC
];
711 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
712 for (n
= count
*size
; n
> 0; n
-= bcount
) {
715 db_printf("%s:\n", name
);
718 db_printf("%0*llX:%s", 2*sizeof(db_addr_t
),(unsigned long long) addr
,
719 (size
!= 1) ? " " : "" );
720 bcount
= ((n
> DB_XCDUMP_NC
)? DB_XCDUMP_NC
: n
);
721 if (trunc_page_32(addr
) != trunc_page_32(addr
+bcount
-1)) {
722 db_addr_t next_page_addr
= trunc_page_32(addr
+bcount
-1);
723 if (!DB_CHECK_ACCESS(next_page_addr
, sizeof(int), task
))
724 bcount
= next_page_addr
- addr
;
726 db_read_bytes((vm_offset_t
)addr
, bcount
, data
, task
);
727 for (i
= 0; i
< bcount
&& off
!= 0; i
+= size
) {
730 value
= db_get_task_value(addr
, size
, FALSE
, task
);
731 db_printf("%0*llX ", size
*2, (unsigned long long)value
);
733 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
736 ((DB_XCDUMP_NC
-i
)/size
)*(size
*2+1)+(DB_XCDUMP_NC
-i
)/4,
739 db_printf("%s*", (size
!= 1)? " ": "");
740 for (i
= 0; i
< bcount
; i
++) {
742 db_printf("%llc", (value
>= ' ' && value
<= '~')? (unsigned long long)value
: (unsigned long long)'.');