db_examine.c revision 1.24 1 /* $NetBSD: db_examine.c,v 1.24 2003/05/16 16:28:31 itojun Exp $ */
2
3 /*
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
6 * All Rights Reserved.
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
13 *
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
27 *
28 * Author: David B. Golub, Carnegie Mellon University
29 * Date: 7/90
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: db_examine.c,v 1.24 2003/05/16 16:28:31 itojun Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38
39 #include <machine/db_machdep.h> /* type definitions */
40
41 #include <ddb/db_lex.h>
42 #include <ddb/db_output.h>
43 #include <ddb/db_command.h>
44 #include <ddb/db_sym.h>
45 #include <ddb/db_access.h>
46 #include <ddb/db_extern.h>
47 #include <ddb/db_interface.h>
48
49 static char db_examine_format[TOK_STRING_SIZE] = "x";
50
51 static void db_examine(db_addr_t, char *, int);
52 static void db_search(db_addr_t, int, db_expr_t, db_expr_t, unsigned int);
53
54 /*
55 * Examine (print) data. Syntax is:
56 * x/[bhl][cdiorsuxz]*
57 * For example, the command:
58 * x/bxxxx
59 * should print:
60 * address: 01 23 45 67
61 */
62 /*ARGSUSED*/
63 void
64 db_examine_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
65 {
66 if (modif[0] != '\0')
67 strlcpy(db_examine_format, modif, sizeof(db_examine_format));
68
69 if (count == -1)
70 count = 1;
71
72 db_examine((db_addr_t) addr, db_examine_format, count);
73 }
74
75 static void
76 db_examine(db_addr_t addr, char *fmt, int count)
77 {
78 int i, c;
79 db_expr_t value;
80 int size;
81 int width;
82 int bytes;
83 char * fp;
84 char tbuf[24];
85
86 while (--count >= 0) {
87 fp = fmt;
88 size = 4;
89 width = 12;
90 while ((c = *fp++) != 0) {
91 if (db_print_position() == 0) {
92 /* Always print the address. */
93 db_printsym(addr, DB_STGY_ANY, db_printf);
94 db_printf(":\t");
95 db_prev = addr;
96 }
97 switch (c) {
98 case 'b': /* byte */
99 size = 1;
100 width = 4;
101 break;
102 case 'h': /* half-word */
103 size = 2;
104 width = 8;
105 break;
106 case 'l': /* long-word */
107 size = 4;
108 width = 12;
109 break;
110 case 'L': /* implementation maximum */
111 size = sizeof value;
112 width = 12 * (sizeof value / 4);
113 break;
114 case 'a': /* address */
115 db_printf("= 0x%lx\n", addr);
116 break;
117 case 'r': /* signed, current radix */
118 value = db_get_value(addr, size, TRUE);
119 addr += size;
120 db_format_radix(tbuf, 24, value, FALSE);
121 db_printf("%-*s", width, tbuf);
122 break;
123 case 'x': /* unsigned hex */
124 value = db_get_value(addr, size, FALSE);
125 addr += size;
126 db_printf("%-*lx", width, value);
127 break;
128 case 'm': /* hex dump */
129 /*
130 * Print off in chunks of size. Try to print 16
131 * bytes at a time into 4 columns. This
132 * loops modify's count extra times in order
133 * to get the nicely formatted lines.
134 */
135
136 bytes = 0;
137 do {
138 for (i = 0; i < size; i++) {
139 value =
140 db_get_value(addr+bytes, 1,
141 FALSE);
142 db_printf("%02lx", value);
143 bytes++;
144 if (!(bytes % 4))
145 db_printf(" ");
146 }
147 } while ((bytes != 16) && count--);
148 /* True up the columns before continuing */
149 for (i = 4; i >= (bytes / 4); i--)
150 db_printf ("\t");
151 /* Print chars, use . for non-printable's. */
152 while (bytes--) {
153 value = db_get_value(addr, 1, FALSE);
154 addr += 1;
155 if (value >= ' ' && value <= '~')
156 db_printf("%c", (char)value);
157 else
158 db_printf(".");
159 }
160 db_printf("\n");
161 break;
162 case 'z': /* signed hex */
163 value = db_get_value(addr, size, TRUE);
164 addr += size;
165 db_format_hex(tbuf, 24, value, FALSE);
166 db_printf("%-*s", width, tbuf);
167 break;
168 case 'd': /* signed decimal */
169 value = db_get_value(addr, size, TRUE);
170 addr += size;
171 db_printf("%-*ld", width, value);
172 break;
173 case 'u': /* unsigned decimal */
174 value = db_get_value(addr, size, FALSE);
175 addr += size;
176 db_printf("%-*lu", width, value);
177 break;
178 case 'o': /* unsigned octal */
179 value = db_get_value(addr, size, FALSE);
180 addr += size;
181 db_printf("%-*lo", width, value);
182 break;
183 case 'c': /* character */
184 value = db_get_value(addr, 1, FALSE);
185 addr += 1;
186 if (value >= ' ' && value <= '~')
187 db_printf("%c", (char)value);
188 else
189 db_printf("\\%03lo", value);
190 break;
191 case 's': /* null-terminated string */
192 for (;;) {
193 value = db_get_value(addr, 1, FALSE);
194 addr += 1;
195 if (value == 0)
196 break;
197 if (value >= ' ' && value <= '~')
198 db_printf("%c", (char)value);
199 else
200 db_printf("\\%03lo", value);
201 }
202 break;
203 case 'i': /* instruction */
204 addr = db_disasm(addr, FALSE);
205 break;
206 case 'I': /* instruction, alternate form */
207 addr = db_disasm(addr, TRUE);
208 break;
209 default:
210 break;
211 }
212 if (db_print_position() != 0)
213 db_end_line();
214 }
215 }
216 db_next = addr;
217 }
218
219 /*
220 * Print value.
221 */
222 static char db_print_format = 'x';
223
224 /*ARGSUSED*/
225 void
226 db_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
227 {
228 db_expr_t value;
229
230 if (modif[0] != '\0')
231 db_print_format = modif[0];
232
233 switch (db_print_format) {
234 case 'a':
235 db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
236 break;
237 case 'r':
238 {
239 char tbuf[24];
240
241 db_format_radix(tbuf, 24, addr, FALSE);
242 db_printf("%11s", tbuf);
243 break;
244 }
245 case 'x':
246 db_printf("%8lx", addr);
247 break;
248 case 'z':
249 {
250 char tbuf[24];
251
252 db_format_hex(tbuf, 24, addr, FALSE);
253 db_printf("%8s", tbuf);
254 break;
255 }
256 case 'd':
257 db_printf("%11ld", addr);
258 break;
259 case 'u':
260 db_printf("%11lu", addr);
261 break;
262 case 'o':
263 db_printf("%16lo", addr);
264 break;
265 case 'c':
266 value = addr & 0xFF;
267 if (value >= ' ' && value <= '~')
268 db_printf("%c", (char)value);
269 else
270 db_printf("\\%03lo", value);
271 break;
272 }
273 db_printf("\n");
274 }
275
276 void
277 db_print_loc_and_inst(db_addr_t loc)
278 {
279
280 db_printsym(loc, DB_STGY_PROC, db_printf);
281 db_printf(":\t");
282 (void) db_disasm(loc, FALSE);
283 }
284
285 /*
286 * Search for a value in memory.
287 * Syntax: search [/bhl] addr value [mask] [,count]
288 */
289 /*ARGSUSED*/
290 void
291 db_search_cmd(db_expr_t daddr, int have_addr, db_expr_t dcount, char *modif)
292 {
293 int t;
294 db_addr_t addr;
295 int size;
296 db_expr_t value;
297 db_expr_t mask;
298 db_expr_t count;
299
300 t = db_read_token();
301 if (t == tSLASH) {
302 t = db_read_token();
303 if (t != tIDENT) {
304 bad_modifier:
305 db_printf("Bad modifier\n");
306 db_flush_lex();
307 return;
308 }
309
310 if (!strcmp(db_tok_string, "b"))
311 size = 1;
312 else if (!strcmp(db_tok_string, "h"))
313 size = 2;
314 else if (!strcmp(db_tok_string, "l"))
315 size = 4;
316 else
317 goto bad_modifier;
318 } else {
319 db_unread_token(t);
320 size = 4;
321 }
322
323 if (!db_expression(&value)) {
324 db_printf("Address missing\n");
325 db_flush_lex();
326 return;
327 }
328 addr = (db_addr_t) value;
329
330 if (!db_expression(&value)) {
331 db_printf("Value missing\n");
332 db_flush_lex();
333 return;
334 }
335
336 if (!db_expression(&mask))
337 mask = (int) ~0;
338
339 t = db_read_token();
340 if (t == tCOMMA) {
341 if (!db_expression(&count)) {
342 db_printf("Count missing\n");
343 db_flush_lex();
344 return;
345 }
346 } else {
347 db_unread_token(t);
348 count = -1; /* effectively forever */
349 }
350 db_skip_to_eol();
351
352 db_search(addr, size, value, mask, count);
353 }
354
355 static void
356 db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
357 unsigned int count)
358 {
359 while (count-- != 0) {
360 db_prev = addr;
361 if ((db_get_value(addr, size, FALSE) & mask) == value)
362 break;
363 addr += size;
364 }
365 db_next = addr;
366 }
367