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@
31 * Revision 1.1.1.1 1998/09/22 21:05:47 wsanchez
32 * Import of Mac OS X kernel (~semeria)
34 * Revision 1.2 1998/04/24 19:34:23 semeria
37 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
38 * Import of OSF Mach kernel (~mburg)
40 * Revision 1.2.42.2 1997/09/12 17:15:15 stephen
41 * make x/x do zero fill right justified hex display
42 * [1997/09/12 16:31:04 stephen]
44 * Revision 1.2.42.1 1997/03/27 18:46:31 barbou
45 * Add 'p' option to the "examine" command - values in
46 * memory treated as addresses and rendered as sym+offset
47 * [1995/12/29 21:32:33 mod]
48 * ri-osc CR1560: make search command output address of any matching
49 * data it finds (so user knows it did something).
50 * [1995/09/20 15:24:55 bolinger]
53 * Revision 1.2.25.5 1996/01/09 19:15:38 devrcs
54 * Add db_print_loc() & db_print_inst() functions.
55 * Make 'l' display 32 bits and new 'q' to display 64 bits.
56 * Allow 'u' to display unsigned decimal values (same as 'U').
57 * Changed declarations of 'register foo' to 'register int foo'.
58 * [1995/12/01 21:42:03 jfraser]
60 * Merged '64-bit safe' changes from DEC alpha port.
61 * [1995/11/21 18:02:58 jfraser]
63 * Revision 1.2.25.4 1995/06/13 18:21:27 sjs
64 * Merge with flipc_shared.
67 * Revision 1.2.30.1 1995/04/03 17:35:17 randys
68 * Minor change; allow a repeat count to work properly when multiple
69 * modifier flags are given to the ddb 'x' command. This allows,
70 * for instance, examination of multiple words in activations other
71 * than the current one.
74 * Revision 1.2.25.3 1995/01/06 19:10:09 devrcs
75 * mk6 CR668 - 1.3b26 merge
76 * * Revision 1.2.6.7 1994/05/06 18:39:09 tmt
77 * Merged osc1.3dec/shared with osc1.3b19
78 * Merge Alpha changes into osc1.312b source code.
81 * [1994/11/04 08:49:22 dwm]
83 * Revision 1.2.25.2 1994/09/23 01:18:44 ezf
84 * change marker to not FREE
85 * [1994/09/22 21:09:44 ezf]
87 * Revision 1.2.25.1 1994/06/11 21:11:43 bolinger
88 * Merge up to NMK17.2.
89 * [1994/06/11 20:01:31 bolinger]
91 * Revision 1.2.23.1 1994/02/08 10:57:47 bernadat
92 * Fixed output of an examine command to have a power of 2
96 * Added dump of hexadecimal address in each line of examine command.
97 * Fixed beginning of line to be always located at position 0.
101 * Revision 1.2.21.4 1994/03/17 22:35:27 dwm
102 * The infamous name change: thread_activation + thread_shuttle = thread.
103 * [1994/03/17 21:25:43 dwm]
105 * Revision 1.2.21.3 1994/01/12 17:50:40 dwm
106 * Coloc: initial restructuring to follow Utah model.
107 * [1994/01/12 17:13:08 dwm]
109 * Revision 1.2.21.2 1993/10/12 16:38:58 dwm
110 * Print '\n' in x/s statements. [rwd]
111 * [1993/10/12 16:14:41 dwm]
113 * Revision 1.2.6.5 1993/08/11 20:37:37 elliston
114 * Add ANSI Prototypes. CR #9523.
115 * [1993/08/11 03:33:05 elliston]
117 * Revision 1.2.6.4 1993/08/09 19:34:42 dswartz
118 * Add ANSI prototypes - CR#9523
119 * [1993/08/06 15:47:32 dswartz]
121 * Revision 1.2.6.3 1993/07/27 18:27:07 elliston
122 * Add ANSI prototypes. CR #9523.
123 * [1993/07/27 18:11:21 elliston]
125 * Revision 1.2.6.2 1993/06/09 02:20:00 gm
126 * Added to OSF/1 R1.3 from NMK15.0.
127 * [1993/06/02 20:56:10 jeffc]
129 * Revision 1.2 1993/04/19 16:01:58 devrcs
131 * Added void type to functions that needed it.
132 * Added init to 'size' in db_search_cmd(). Removed unused variables.
133 * Other cleanup to quiet gcc warnings.
135 * x/u now examines current user space. x/t still examines user
136 * space of the the specified thread. x/tu is redundant.
137 * To examine an value as unsigned decimal, use x/U.
141 * Remember count argument when repeating commands instead of the
142 * default command, also apply all the formats to current address
143 * instead of incrementing addresses when switching to next format.
144 * [barbou@gr.osf.org]
146 * Support 'A' format for print 'p' command [barbou@gr.osf.org]
147 * [92/12/03 bernadat]
149 * Revision 1.1 1992/09/30 02:01:01 robert
156 * Revision 2.7 91/10/09 15:59:28 af
157 * Revision 2.6.1.1 91/10/05 13:05:49 jeffreyh
158 * Supported non current task space data examination and search.
159 * Added 'm' format and db_xcdump to print with hex and characters.
160 * Added db_examine_{forward, backward}.
161 * Changed db_print_cmd to support variable number of parameters
162 * including string constant.
163 * Included "db_access.h".
166 * Revision 2.6.1.1 91/10/05 13:05:49 jeffreyh
167 * Supported non current task space data examination and search.
168 * Added 'm' format and db_xcdump to print with hex and characters.
169 * Added db_examine_{forward, backward}.
170 * Changed db_print_cmd to support variable number of parameters
171 * including string constant.
172 * Included "db_access.h".
175 * Revision 2.6 91/08/28 11:11:01 jsb
176 * Added 'A' flag to examine: just like 'a' (address), but prints addr
177 * as a procedure type, thus printing file/line info if available.
178 * Useful when called as 'x/Ai'.
179 * [91/08/13 18:14:55 jsb]
181 * Revision 2.5 91/05/14 15:33:31 mrt
182 * Correcting copyright
184 * Revision 2.4 91/02/05 17:06:20 mrt
185 * Changed to new Mach copyright
186 * [91/01/31 16:17:37 mrt]
188 * Revision 2.3 90/11/07 16:49:23 rpd
189 * Added db_search_cmd, db_search.
192 * Revision 2.2 90/08/27 21:50:38 dbg
193 * Add 'r', 'z' to print and examine formats.
194 * Change calling sequence of db_disasm.
195 * db_examine sets db_prev and db_next instead of explicitly
198 * Reflected changes in db_printsym()'s calling seq.
208 * Mach Operating System
209 * Copyright (c) 1991,1990 Carnegie Mellon University
210 * All Rights Reserved.
212 * Permission to use, copy, modify and distribute this software and its
213 * documentation is hereby granted, provided that both the copyright
214 * notice and this permission notice appear in all copies of the
215 * software, derivative works or modified versions, and any portions
216 * thereof, and that both notices appear in supporting documentation.
218 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
219 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
220 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
222 * Carnegie Mellon requests users of this software to return to
224 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
225 * School of Computer Science
226 * Carnegie Mellon University
227 * Pittsburgh PA 15213-3890
229 * any improvements or extensions that they make and grant Carnegie Mellon
230 * the rights to redistribute these changes.
235 * Author: David B. Golub, Carnegie Mellon University
238 #include <string.h> /* For strcpy() */
239 #include <mach/boolean.h>
240 #include <machine/db_machdep.h>
242 #include <ddb/db_access.h>
243 #include <ddb/db_lex.h>
244 #include <ddb/db_output.h>
245 #include <ddb/db_command.h>
246 #include <ddb/db_sym.h>
247 #include <ddb/db_task_thread.h>
248 #include <ddb/db_command.h> /* For db_option() */
249 #include <ddb/db_examine.h>
250 #include <ddb/db_expr.h>
251 #include <kern/thread.h>
252 #include <kern/task.h>
253 #include <mach/vm_param.h>
255 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
257 char db_examine_format
[TOK_STRING_SIZE
] = "x";
258 int db_examine_count
= 1;
259 db_addr_t db_examine_prev_addr
= 0;
260 thread_act_t db_examine_act
= THR_ACT_NULL
;
262 extern int db_max_width
;
265 /* Prototypes for functions local to this file. XXX -- should be static!
273 int db_examine_width(
279 * Examine (print) data.
288 thread_act_t thr_act
;
289 extern char db_last_modifier
[];
291 if (modif
[0] != '\0')
292 strcpy(db_examine_format
, modif
);
296 db_examine_count
= count
;
297 if (db_option(modif
, 't')) {
298 if (modif
== db_last_modifier
)
299 thr_act
= db_examine_act
;
300 else if (!db_get_next_act(&thr_act
, 0))
303 if (db_option(modif
,'u'))
304 thr_act
= current_act();
306 thr_act
= THR_ACT_NULL
;
308 db_examine_act
= thr_act
;
309 db_examine((db_addr_t
) addr
, db_examine_format
, count
,
310 db_act_to_task(thr_act
));
320 db_examine(db_next
, db_examine_format
, db_examine_count
,
321 db_act_to_task(db_examine_act
));
331 db_examine(db_examine_prev_addr
- (db_next
- db_examine_prev_addr
),
332 db_examine_format
, db_examine_count
,
333 db_act_to_task(db_examine_act
));
346 width
= size
* 2 + 1;
347 sz
= (db_max_width
- (sizeof (void *) * 2 + 4)) / width
;
348 for (entry
= 1; (entry
<< 1) < sz
; entry
<<= 1)
351 sz
= sizeof (void *) * 2 + 4 + entry
* width
;
352 while (sz
+ entry
< db_max_width
) {
356 *remainder
= (db_max_width
- sz
+ 1) / 2;
364 char * fmt
, /* format string */
365 int count
, /* repeat count */
379 db_examine_prev_addr
= addr
;
380 while (--count
>= 0) {
383 width
= db_examine_width(size
, &items
, &leader
);
384 while ((c
= *fp
++) != 0) {
388 width
= db_examine_width(size
, &items
, &leader
);
391 size
= sizeof(short);
392 width
= db_examine_width(size
, &items
, &leader
);
396 width
= db_examine_width(size
, &items
, &leader
);
400 width
= db_examine_width(size
, &items
, &leader
);
402 case 'a': /* address */
403 case 'A': /* function address */
404 /* always forces a new line */
405 if (db_print_position() != 0)
408 next_addr
= addr
+ 4;
409 db_task_printsym(addr
,
410 (c
== 'a')?DB_STGY_ANY
:DB_STGY_PROC
,
415 db_next
= db_xcdump(addr
, size
, count
+1, task
);
422 /* Reset next_addr in case we are printing in
425 if (db_print_position() == 0) {
426 /* If we hit a new symbol, print it */
430 db_find_task_sym_and_offset(addr
,&name
,&off
,task
);
432 db_printf("\r%s:\n", name
);
433 db_printf("%#n: ", addr
);
434 for (sz
= 0; sz
< leader
; sz
++)
441 case 'p': /* Addrs rendered symbolically. */
442 if( size
== sizeof(void *) ) {
447 value
= db_get_task_value( next_addr
,
448 sizeof(db_expr_t
), FALSE
, task
);
449 db_find_task_sym_and_offset( value
,
450 &symName
, &offset
, task
);
451 db_printf("\n\t*%8x(%8X) = %s",
452 next_addr
, value
, symName
);
454 db_printf("+%X", offset
);
459 case 'r': /* signed, current radix */
460 for (sz
= size
, next_addr
= addr
;
461 sz
>= sizeof (db_expr_t
);
462 sz
-= sizeof (db_expr_t
)) {
467 value
= db_get_task_value(next_addr
,
470 db_printf("%-*r", width
, value
);
471 next_addr
+= sizeof (db_expr_t
);
478 value
= db_get_task_value(next_addr
, sz
,
480 db_printf("%-*R", width
, value
);
485 case 'X': /* unsigned hex */
487 case 'x': /* unsigned hex */
488 for (sz
= size
, next_addr
= addr
;
489 sz
>= sizeof (db_expr_t
);
490 sz
-= sizeof (db_expr_t
)) {
495 value
= db_get_task_value(next_addr
,
500 db_printf("%0*X ", 2*size
, value
);
502 db_printf("%-*x", width
, value
);
504 db_printf("%-*x", width
, value
);
506 next_addr
+= sizeof (db_expr_t
);
513 value
= db_get_task_value(next_addr
, sz
,
517 db_printf("%0*X ", 2*size
, value
);
519 db_printf("%-*X", width
, value
);
521 db_printf("%-*X", width
, value
);
526 case 'z': /* signed hex */
527 for (sz
= size
, next_addr
= addr
;
528 sz
>= sizeof (db_expr_t
);
529 sz
-= sizeof (db_expr_t
)) {
534 value
= db_get_task_value(next_addr
,
537 db_printf("%-*z", width
, value
);
538 next_addr
+= sizeof (db_expr_t
);
545 value
= db_get_task_value(next_addr
,sz
,
547 db_printf("%-*Z", width
, value
);
551 case 'd': /* signed decimal */
552 for (sz
= size
, next_addr
= addr
;
553 sz
>= sizeof (db_expr_t
);
554 sz
-= sizeof (db_expr_t
)) {
559 value
= db_get_task_value(next_addr
,
562 db_printf("%-*d", width
, value
);
563 next_addr
+= sizeof (db_expr_t
);
570 value
= db_get_task_value(next_addr
, sz
,
572 db_printf("%-*D", width
, value
);
576 case 'U': /* unsigned decimal */
578 for (sz
= size
, next_addr
= addr
;
579 sz
>= sizeof (db_expr_t
);
580 sz
-= sizeof (db_expr_t
)) {
585 value
= db_get_task_value(next_addr
,
588 db_printf("%-*u", width
, value
);
589 next_addr
+= sizeof (db_expr_t
);
596 value
= db_get_task_value(next_addr
, sz
,
598 db_printf("%-*U", width
, value
);
602 case 'o': /* unsigned octal */
603 for (sz
= size
, next_addr
= addr
;
604 sz
>= sizeof (db_expr_t
);
605 sz
-= sizeof (db_expr_t
)) {
610 value
= db_get_task_value(next_addr
,
613 db_printf("%-*o", width
, value
);
614 next_addr
+= sizeof (db_expr_t
);
621 value
= db_get_task_value(next_addr
, sz
,
623 db_printf("%-*o", width
, value
);
627 case 'c': /* character */
628 for (sz
= 0, next_addr
= addr
;
631 value
= db_get_task_value(next_addr
,1,
633 if ((value
>= ' ' && value
<= '~') ||
636 db_printf("%c", value
);
638 db_printf("\\%03o", value
);
641 case 's': /* null-terminated string */
644 value
= db_get_task_value(next_addr
,1,
650 if (value
>= ' ' && value
<= '~')
651 db_printf("%c", value
);
653 db_printf("\\%03o", value
);
656 case 'i': /* instruction */
657 next_addr
= db_disasm(addr
, FALSE
, task
);
658 size
= next_addr
- addr
;
660 case 'I': /* instruction, alternate form */
661 next_addr
= db_disasm(addr
, TRUE
, task
);
662 size
= next_addr
- addr
;
667 if (db_print_position() != 0)
680 char db_print_format
= 'x';
687 task_t task
= TASK_NULL
;
689 if ((t
= db_read_token()) == tSLASH
) {
690 if (db_read_token() != tIDENT
) {
691 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
695 if (db_tok_string
[0])
696 db_print_format
= db_tok_string
[0];
697 if (db_option(db_tok_string
, 't')) {
699 task
= db_default_act
->task
;
700 if (db_print_format
== 't')
701 db_print_format
= db_tok_string
[1];
709 db_printf("%s", db_tok_string
);
713 if (!db_expression(&value
))
715 switch (db_print_format
) {
718 db_task_printsym((db_addr_t
)value
,
719 (db_print_format
== 'a') ? DB_STGY_ANY
:
724 db_printf("%11r", value
);
727 db_printf("%08x", value
);
730 db_printf("%8z", value
);
733 db_printf("%11d", value
);
736 db_printf("%11u", value
);
739 db_printf("%16o", value
);
742 value
= value
& 0xFF;
743 if (value
>= ' ' && value
<= '~')
744 db_printf("%c", value
);
746 db_printf("\\%03o", value
);
749 db_printf("Unknown format %c\n", db_print_format
);
750 db_print_format
= 'x';
761 db_task_printsym(loc
, DB_STGY_PROC
, task
);
769 (void) db_disasm(loc
, TRUE
, task
);
773 db_print_loc_and_inst(
777 db_task_printsym(loc
, DB_STGY_PROC
, task
);
779 (void) db_disasm(loc
, TRUE
, task
);
783 * Search for a value in memory.
784 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
795 thread_act_t thr_act
;
796 boolean_t thread_flag
= FALSE
;
804 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
809 for (p
= db_tok_string
; *p
; p
++) {
815 size
= sizeof(short);
832 if (!db_expression((db_expr_t
*) &addr
)) {
833 db_printf("Address missing\n");
838 if (!db_expression(&value
)) {
839 db_printf("Value missing\n");
844 if (!db_expression(&mask
))
849 if (!db_expression((db_expr_t
*) &count
)) {
850 db_printf("Count missing\n");
856 count
= -1; /* effectively forever */
859 if (!db_get_next_act(&thr_act
, 0))
862 thr_act
= THR_ACT_NULL
;
864 db_search(addr
, size
, value
, mask
, count
, db_act_to_task(thr_act
));
876 while (count
-- != 0) {
878 if ((db_get_task_value(addr
,size
,FALSE
,task
) & mask
) == value
)
882 db_printf("0x%x: ", addr
);
886 #define DB_XCDUMP_NC 16
900 char data
[DB_XCDUMP_NC
];
902 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
903 for (n
= count
*size
; n
> 0; n
-= bcount
) {
906 db_printf("%s:\n", name
);
909 db_printf("%0*X:%s", 2*sizeof(db_addr_t
), addr
,
910 (size
!= 1) ? " " : "" );
911 bcount
= ((n
> DB_XCDUMP_NC
)? DB_XCDUMP_NC
: n
);
912 if (trunc_page(addr
) != trunc_page(addr
+bcount
-1)) {
913 db_addr_t next_page_addr
= trunc_page(addr
+bcount
-1);
914 if (!DB_CHECK_ACCESS(next_page_addr
, sizeof(int), task
))
915 bcount
= next_page_addr
- addr
;
917 db_read_bytes((vm_offset_t
)addr
, bcount
, data
, task
);
918 for (i
= 0; i
< bcount
&& off
!= 0; i
+= size
) {
921 value
= db_get_task_value(addr
, size
, FALSE
, task
);
922 db_printf("%0*x ", size
*2, value
);
924 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
927 ((DB_XCDUMP_NC
-i
)/size
)*(size
*2+1)+(DB_XCDUMP_NC
-i
)/4,
930 db_printf("%s*", (size
!= 1)? " ": "");
931 for (i
= 0; i
< bcount
; i
++) {
933 db_printf("%c", (value
>= ' ' && value
<= '~')? value
: '.');