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@
28 * Revision 1.1.1.1 1998/09/22 21:05:47 wsanchez
29 * Import of Mac OS X kernel (~semeria)
31 * Revision 1.2 1998/04/24 19:34:23 semeria
34 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
35 * Import of OSF Mach kernel (~mburg)
37 * Revision 1.2.42.2 1997/09/12 17:15:15 stephen
38 * make x/x do zero fill right justified hex display
39 * [1997/09/12 16:31:04 stephen]
41 * Revision 1.2.42.1 1997/03/27 18:46:31 barbou
42 * Add 'p' option to the "examine" command - values in
43 * memory treated as addresses and rendered as sym+offset
44 * [1995/12/29 21:32:33 mod]
45 * ri-osc CR1560: make search command output address of any matching
46 * data it finds (so user knows it did something).
47 * [1995/09/20 15:24:55 bolinger]
50 * Revision 1.2.25.5 1996/01/09 19:15:38 devrcs
51 * Add db_print_loc() & db_print_inst() functions.
52 * Make 'l' display 32 bits and new 'q' to display 64 bits.
53 * Allow 'u' to display unsigned decimal values (same as 'U').
54 * Changed declarations of 'register foo' to 'register int foo'.
55 * [1995/12/01 21:42:03 jfraser]
57 * Merged '64-bit safe' changes from DEC alpha port.
58 * [1995/11/21 18:02:58 jfraser]
60 * Revision 1.2.25.4 1995/06/13 18:21:27 sjs
61 * Merge with flipc_shared.
64 * Revision 1.2.30.1 1995/04/03 17:35:17 randys
65 * Minor change; allow a repeat count to work properly when multiple
66 * modifier flags are given to the ddb 'x' command. This allows,
67 * for instance, examination of multiple words in activations other
68 * than the current one.
71 * Revision 1.2.25.3 1995/01/06 19:10:09 devrcs
72 * mk6 CR668 - 1.3b26 merge
73 * * Revision 1.2.6.7 1994/05/06 18:39:09 tmt
74 * Merged osc1.3dec/shared with osc1.3b19
75 * Merge Alpha changes into osc1.312b source code.
78 * [1994/11/04 08:49:22 dwm]
80 * Revision 1.2.25.2 1994/09/23 01:18:44 ezf
81 * change marker to not FREE
82 * [1994/09/22 21:09:44 ezf]
84 * Revision 1.2.25.1 1994/06/11 21:11:43 bolinger
85 * Merge up to NMK17.2.
86 * [1994/06/11 20:01:31 bolinger]
88 * Revision 1.2.23.1 1994/02/08 10:57:47 bernadat
89 * Fixed output of an examine command to have a power of 2
93 * Added dump of hexadecimal address in each line of examine command.
94 * Fixed beginning of line to be always located at position 0.
98 * Revision 1.2.21.4 1994/03/17 22:35:27 dwm
99 * The infamous name change: thread_activation + thread_shuttle = thread.
100 * [1994/03/17 21:25:43 dwm]
102 * Revision 1.2.21.3 1994/01/12 17:50:40 dwm
103 * Coloc: initial restructuring to follow Utah model.
104 * [1994/01/12 17:13:08 dwm]
106 * Revision 1.2.21.2 1993/10/12 16:38:58 dwm
107 * Print '\n' in x/s statements. [rwd]
108 * [1993/10/12 16:14:41 dwm]
110 * Revision 1.2.6.5 1993/08/11 20:37:37 elliston
111 * Add ANSI Prototypes. CR #9523.
112 * [1993/08/11 03:33:05 elliston]
114 * Revision 1.2.6.4 1993/08/09 19:34:42 dswartz
115 * Add ANSI prototypes - CR#9523
116 * [1993/08/06 15:47:32 dswartz]
118 * Revision 1.2.6.3 1993/07/27 18:27:07 elliston
119 * Add ANSI prototypes. CR #9523.
120 * [1993/07/27 18:11:21 elliston]
122 * Revision 1.2.6.2 1993/06/09 02:20:00 gm
123 * Added to OSF/1 R1.3 from NMK15.0.
124 * [1993/06/02 20:56:10 jeffc]
126 * Revision 1.2 1993/04/19 16:01:58 devrcs
128 * Added void type to functions that needed it.
129 * Added init to 'size' in db_search_cmd(). Removed unused variables.
130 * Other cleanup to quiet gcc warnings.
132 * x/u now examines current user space. x/t still examines user
133 * space of the the specified thread. x/tu is redundant.
134 * To examine an value as unsigned decimal, use x/U.
138 * Remember count argument when repeating commands instead of the
139 * default command, also apply all the formats to current address
140 * instead of incrementing addresses when switching to next format.
141 * [barbou@gr.osf.org]
143 * Support 'A' format for print 'p' command [barbou@gr.osf.org]
144 * [92/12/03 bernadat]
146 * Revision 1.1 1992/09/30 02:01:01 robert
153 * Revision 2.7 91/10/09 15:59:28 af
154 * Revision 2.6.1.1 91/10/05 13:05:49 jeffreyh
155 * Supported non current task space data examination and search.
156 * Added 'm' format and db_xcdump to print with hex and characters.
157 * Added db_examine_{forward, backward}.
158 * Changed db_print_cmd to support variable number of parameters
159 * including string constant.
160 * Included "db_access.h".
163 * Revision 2.6.1.1 91/10/05 13:05:49 jeffreyh
164 * Supported non current task space data examination and search.
165 * Added 'm' format and db_xcdump to print with hex and characters.
166 * Added db_examine_{forward, backward}.
167 * Changed db_print_cmd to support variable number of parameters
168 * including string constant.
169 * Included "db_access.h".
172 * Revision 2.6 91/08/28 11:11:01 jsb
173 * Added 'A' flag to examine: just like 'a' (address), but prints addr
174 * as a procedure type, thus printing file/line info if available.
175 * Useful when called as 'x/Ai'.
176 * [91/08/13 18:14:55 jsb]
178 * Revision 2.5 91/05/14 15:33:31 mrt
179 * Correcting copyright
181 * Revision 2.4 91/02/05 17:06:20 mrt
182 * Changed to new Mach copyright
183 * [91/01/31 16:17:37 mrt]
185 * Revision 2.3 90/11/07 16:49:23 rpd
186 * Added db_search_cmd, db_search.
189 * Revision 2.2 90/08/27 21:50:38 dbg
190 * Add 'r', 'z' to print and examine formats.
191 * Change calling sequence of db_disasm.
192 * db_examine sets db_prev and db_next instead of explicitly
195 * Reflected changes in db_printsym()'s calling seq.
205 * Mach Operating System
206 * Copyright (c) 1991,1990 Carnegie Mellon University
207 * All Rights Reserved.
209 * Permission to use, copy, modify and distribute this software and its
210 * documentation is hereby granted, provided that both the copyright
211 * notice and this permission notice appear in all copies of the
212 * software, derivative works or modified versions, and any portions
213 * thereof, and that both notices appear in supporting documentation.
215 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
216 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
217 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
219 * Carnegie Mellon requests users of this software to return to
221 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
222 * School of Computer Science
223 * Carnegie Mellon University
224 * Pittsburgh PA 15213-3890
226 * any improvements or extensions that they make and grant Carnegie Mellon
227 * the rights to redistribute these changes.
232 * Author: David B. Golub, Carnegie Mellon University
235 #include <string.h> /* For strcpy() */
236 #include <mach/boolean.h>
237 #include <machine/db_machdep.h>
239 #include <ddb/db_access.h>
240 #include <ddb/db_lex.h>
241 #include <ddb/db_output.h>
242 #include <ddb/db_command.h>
243 #include <ddb/db_sym.h>
244 #include <ddb/db_task_thread.h>
245 #include <ddb/db_command.h> /* For db_option() */
246 #include <ddb/db_examine.h>
247 #include <ddb/db_expr.h>
248 #include <kern/thread.h>
249 #include <kern/task.h>
250 #include <mach/vm_param.h>
252 #define db_act_to_task(thr_act) ((thr_act)? thr_act->task: TASK_NULL)
254 char db_examine_format
[TOK_STRING_SIZE
] = "x";
255 int db_examine_count
= 1;
256 db_addr_t db_examine_prev_addr
= 0;
257 thread_act_t db_examine_act
= THR_ACT_NULL
;
259 extern int db_max_width
;
262 /* Prototypes for functions local to this file. XXX -- should be static!
270 int db_examine_width(
276 * Examine (print) data.
285 thread_act_t thr_act
;
286 extern char db_last_modifier
[];
288 if (modif
[0] != '\0')
289 strcpy(db_examine_format
, modif
);
293 db_examine_count
= count
;
294 if (db_option(modif
, 't')) {
295 if (modif
== db_last_modifier
)
296 thr_act
= db_examine_act
;
297 else if (!db_get_next_act(&thr_act
, 0))
300 if (db_option(modif
,'u'))
301 thr_act
= current_act();
303 thr_act
= THR_ACT_NULL
;
305 db_examine_act
= thr_act
;
306 db_examine((db_addr_t
) addr
, db_examine_format
, count
,
307 db_act_to_task(thr_act
));
317 db_examine(db_next
, db_examine_format
, db_examine_count
,
318 db_act_to_task(db_examine_act
));
328 db_examine(db_examine_prev_addr
- (db_next
- db_examine_prev_addr
),
329 db_examine_format
, db_examine_count
,
330 db_act_to_task(db_examine_act
));
343 width
= size
* 2 + 1;
344 sz
= (db_max_width
- (sizeof (void *) * 2 + 4)) / width
;
345 for (entry
= 1; (entry
<< 1) < sz
; entry
<<= 1)
348 sz
= sizeof (void *) * 2 + 4 + entry
* width
;
349 while (sz
+ entry
< db_max_width
) {
353 *remainder
= (db_max_width
- sz
+ 1) / 2;
361 char * fmt
, /* format string */
362 int count
, /* repeat count */
376 db_examine_prev_addr
= addr
;
377 while (--count
>= 0) {
380 width
= db_examine_width(size
, &items
, &leader
);
381 while ((c
= *fp
++) != 0) {
385 width
= db_examine_width(size
, &items
, &leader
);
388 size
= sizeof(short);
389 width
= db_examine_width(size
, &items
, &leader
);
393 width
= db_examine_width(size
, &items
, &leader
);
397 width
= db_examine_width(size
, &items
, &leader
);
399 case 'a': /* address */
400 case 'A': /* function address */
401 /* always forces a new line */
402 if (db_print_position() != 0)
405 next_addr
= addr
+ 4;
406 db_task_printsym(addr
,
407 (c
== 'a')?DB_STGY_ANY
:DB_STGY_PROC
,
412 db_next
= db_xcdump(addr
, size
, count
+1, task
);
419 /* Reset next_addr in case we are printing in
422 if (db_print_position() == 0) {
423 /* If we hit a new symbol, print it */
427 db_find_task_sym_and_offset(addr
,&name
,&off
,task
);
429 db_printf("\r%s:\n", name
);
430 db_printf("%#n: ", addr
);
431 for (sz
= 0; sz
< leader
; sz
++)
438 case 'p': /* Addrs rendered symbolically. */
439 if( size
== sizeof(void *) ) {
444 value
= db_get_task_value( next_addr
,
445 sizeof(db_expr_t
), FALSE
, task
);
446 db_find_task_sym_and_offset( value
,
447 &symName
, &offset
, task
);
448 db_printf("\n\t*%8x(%8X) = %s",
449 next_addr
, value
, symName
);
451 db_printf("+%X", offset
);
456 case 'r': /* signed, current radix */
457 for (sz
= size
, next_addr
= addr
;
458 sz
>= sizeof (db_expr_t
);
459 sz
-= sizeof (db_expr_t
)) {
464 value
= db_get_task_value(next_addr
,
467 db_printf("%-*r", width
, value
);
468 next_addr
+= sizeof (db_expr_t
);
475 value
= db_get_task_value(next_addr
, sz
,
477 db_printf("%-*R", width
, value
);
482 case 'X': /* unsigned hex */
484 case 'x': /* unsigned hex */
485 for (sz
= size
, next_addr
= addr
;
486 sz
>= sizeof (db_expr_t
);
487 sz
-= sizeof (db_expr_t
)) {
492 value
= db_get_task_value(next_addr
,
497 db_printf("%0*X ", 2*size
, value
);
499 db_printf("%-*x", width
, value
);
501 db_printf("%-*x", width
, value
);
503 next_addr
+= sizeof (db_expr_t
);
510 value
= db_get_task_value(next_addr
, sz
,
514 db_printf("%0*X ", 2*size
, value
);
516 db_printf("%-*X", width
, value
);
518 db_printf("%-*X", width
, value
);
523 case 'z': /* signed hex */
524 for (sz
= size
, next_addr
= addr
;
525 sz
>= sizeof (db_expr_t
);
526 sz
-= sizeof (db_expr_t
)) {
531 value
= db_get_task_value(next_addr
,
534 db_printf("%-*z", width
, value
);
535 next_addr
+= sizeof (db_expr_t
);
542 value
= db_get_task_value(next_addr
,sz
,
544 db_printf("%-*Z", width
, value
);
548 case 'd': /* signed decimal */
549 for (sz
= size
, next_addr
= addr
;
550 sz
>= sizeof (db_expr_t
);
551 sz
-= sizeof (db_expr_t
)) {
556 value
= db_get_task_value(next_addr
,
559 db_printf("%-*d", width
, value
);
560 next_addr
+= sizeof (db_expr_t
);
567 value
= db_get_task_value(next_addr
, sz
,
569 db_printf("%-*D", width
, value
);
573 case 'U': /* unsigned decimal */
575 for (sz
= size
, next_addr
= addr
;
576 sz
>= sizeof (db_expr_t
);
577 sz
-= sizeof (db_expr_t
)) {
582 value
= db_get_task_value(next_addr
,
585 db_printf("%-*u", width
, value
);
586 next_addr
+= sizeof (db_expr_t
);
593 value
= db_get_task_value(next_addr
, sz
,
595 db_printf("%-*U", width
, value
);
599 case 'o': /* unsigned octal */
600 for (sz
= size
, next_addr
= addr
;
601 sz
>= sizeof (db_expr_t
);
602 sz
-= sizeof (db_expr_t
)) {
607 value
= db_get_task_value(next_addr
,
610 db_printf("%-*o", width
, value
);
611 next_addr
+= sizeof (db_expr_t
);
618 value
= db_get_task_value(next_addr
, sz
,
620 db_printf("%-*o", width
, value
);
624 case 'c': /* character */
625 for (sz
= 0, next_addr
= addr
;
628 value
= db_get_task_value(next_addr
,1,
630 if ((value
>= ' ' && value
<= '~') ||
633 db_printf("%c", value
);
635 db_printf("\\%03o", value
);
638 case 's': /* null-terminated string */
641 value
= db_get_task_value(next_addr
,1,
647 if (value
>= ' ' && value
<= '~')
648 db_printf("%c", value
);
650 db_printf("\\%03o", value
);
653 case 'i': /* instruction */
654 next_addr
= db_disasm(addr
, FALSE
, task
);
655 size
= next_addr
- addr
;
657 case 'I': /* instruction, alternate form */
658 next_addr
= db_disasm(addr
, TRUE
, task
);
659 size
= next_addr
- addr
;
664 if (db_print_position() != 0)
677 char db_print_format
= 'x';
684 task_t task
= TASK_NULL
;
686 if ((t
= db_read_token()) == tSLASH
) {
687 if (db_read_token() != tIDENT
) {
688 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
692 if (db_tok_string
[0])
693 db_print_format
= db_tok_string
[0];
694 if (db_option(db_tok_string
, 't')) {
696 task
= db_default_act
->task
;
697 if (db_print_format
== 't')
698 db_print_format
= db_tok_string
[1];
706 db_printf("%s", db_tok_string
);
710 if (!db_expression(&value
))
712 switch (db_print_format
) {
715 db_task_printsym((db_addr_t
)value
,
716 (db_print_format
== 'a') ? DB_STGY_ANY
:
721 db_printf("%11r", value
);
724 db_printf("%08x", value
);
727 db_printf("%8z", value
);
730 db_printf("%11d", value
);
733 db_printf("%11u", value
);
736 db_printf("%16o", value
);
739 value
= value
& 0xFF;
740 if (value
>= ' ' && value
<= '~')
741 db_printf("%c", value
);
743 db_printf("\\%03o", value
);
746 db_printf("Unknown format %c\n", db_print_format
);
747 db_print_format
= 'x';
758 db_task_printsym(loc
, DB_STGY_PROC
, task
);
766 (void) db_disasm(loc
, TRUE
, task
);
770 db_print_loc_and_inst(
774 db_task_printsym(loc
, DB_STGY_PROC
, task
);
776 (void) db_disasm(loc
, TRUE
, task
);
780 * Search for a value in memory.
781 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
792 thread_act_t thr_act
;
793 boolean_t thread_flag
= FALSE
;
801 db_printf("Bad modifier \"/%s\"\n", db_tok_string
);
806 for (p
= db_tok_string
; *p
; p
++) {
812 size
= sizeof(short);
829 if (!db_expression((db_expr_t
*) &addr
)) {
830 db_printf("Address missing\n");
835 if (!db_expression(&value
)) {
836 db_printf("Value missing\n");
841 if (!db_expression(&mask
))
846 if (!db_expression((db_expr_t
*) &count
)) {
847 db_printf("Count missing\n");
853 count
= -1; /* effectively forever */
856 if (!db_get_next_act(&thr_act
, 0))
859 thr_act
= THR_ACT_NULL
;
861 db_search(addr
, size
, value
, mask
, count
, db_act_to_task(thr_act
));
873 while (count
-- != 0) {
875 if ((db_get_task_value(addr
,size
,FALSE
,task
) & mask
) == value
)
879 db_printf("0x%x: ", addr
);
883 #define DB_XCDUMP_NC 16
897 char data
[DB_XCDUMP_NC
];
899 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
900 for (n
= count
*size
; n
> 0; n
-= bcount
) {
903 db_printf("%s:\n", name
);
906 db_printf("%0*X:%s", 2*sizeof(db_addr_t
), addr
,
907 (size
!= 1) ? " " : "" );
908 bcount
= ((n
> DB_XCDUMP_NC
)? DB_XCDUMP_NC
: n
);
909 if (trunc_page(addr
) != trunc_page(addr
+bcount
-1)) {
910 db_addr_t next_page_addr
= trunc_page(addr
+bcount
-1);
911 if (!DB_CHECK_ACCESS(next_page_addr
, sizeof(int), task
))
912 bcount
= next_page_addr
- addr
;
914 db_read_bytes((vm_offset_t
)addr
, bcount
, data
, task
);
915 for (i
= 0; i
< bcount
&& off
!= 0; i
+= size
) {
918 value
= db_get_task_value(addr
, size
, FALSE
, task
);
919 db_printf("%0*x ", size
*2, value
);
921 db_find_task_sym_and_offset(addr
, &name
, &off
, task
);
924 ((DB_XCDUMP_NC
-i
)/size
)*(size
*2+1)+(DB_XCDUMP_NC
-i
)/4,
927 db_printf("%s*", (size
!= 1)? " ": "");
928 for (i
= 0; i
< bcount
; i
++) {
930 db_printf("%c", (value
>= ' ' && value
<= '~')? value
: '.');