db_examine.c revision 1.21 1 /* $NetBSD: db_examine.c,v 1.21 2001/02/24 00:00:12 cgd 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/param.h>
33 #include <sys/systm.h>
34 #include <sys/proc.h>
35
36 #include <machine/db_machdep.h> /* type definitions */
37
38 #include <ddb/db_lex.h>
39 #include <ddb/db_output.h>
40 #include <ddb/db_command.h>
41 #include <ddb/db_sym.h>
42 #include <ddb/db_access.h>
43 #include <ddb/db_extern.h>
44 #include <ddb/db_interface.h>
45
46 char db_examine_format[TOK_STRING_SIZE] = "x";
47
48 /*
49 * Examine (print) data. Syntax is:
50 * x/[bhl][cdiorsuxz]*
51 * For example, the command:
52 * x/bxxxx
53 * should print:
54 * address: 01 23 45 67
55 */
56 /*ARGSUSED*/
57 void
58 db_examine_cmd(addr, have_addr, count, modif)
59 db_expr_t addr;
60 int have_addr;
61 db_expr_t count;
62 char * modif;
63 {
64 if (modif[0] != '\0')
65 db_strcpy(db_examine_format, modif);
66
67 if (count == -1)
68 count = 1;
69
70 db_examine((db_addr_t) addr, db_examine_format, count);
71 }
72
73 void
74 db_examine(addr, fmt, count)
75 db_addr_t addr;
76 char * fmt; /* format string */
77 int count; /* repeat count */
78 {
79 int i, c;
80 db_expr_t value;
81 int size;
82 int width;
83 int bytes;
84 char * fp;
85 char tbuf[24];
86
87 while (--count >= 0) {
88 fp = fmt;
89 size = 4;
90 width = 12;
91 while ((c = *fp++) != 0) {
92 if (db_print_position() == 0) {
93 /* Always print the address. */
94 db_printsym(addr, DB_STGY_ANY, db_printf);
95 db_printf(":\t");
96 db_prev = addr;
97 }
98 switch (c) {
99 case 'b': /* byte */
100 size = 1;
101 width = 4;
102 break;
103 case 'h': /* half-word */
104 size = 2;
105 width = 8;
106 break;
107 case 'l': /* long-word */
108 size = 4;
109 width = 12;
110 break;
111 case 'L': /* implementation maximum */
112 size = sizeof value;
113 width = 12 * (sizeof value / 4);
114 break;
115 case 'a': /* address */
116 db_printf("= 0x%lx\n", addr);
117 break;
118 case 'r': /* signed, current radix */
119 value = db_get_value(addr, size, TRUE);
120 addr += size;
121 db_format_radix(tbuf, 24, value, FALSE);
122 db_printf("%-*s", width, tbuf);
123 break;
124 case 'x': /* unsigned hex */
125 value = db_get_value(addr, size, FALSE);
126 addr += size;
127 db_printf("%-*lx", width, value);
128 break;
129 case 'm': /* hex dump */
130 /*
131 * Print off in chunks of size. Try to print 16
132 * bytes at a time into 4 columns. This
133 * loops modify's count extra times in order
134 * to get the nicely formatted lines.
135 */
136
137 bytes = 0;
138 do {
139 for (i = 0; i < size; i++) {
140 value =
141 db_get_value(addr+bytes, 1,
142 FALSE);
143 db_printf("%02lx", value);
144 bytes++;
145 if (!(bytes % 4))
146 db_printf(" ");
147 }
148 } while ((bytes != 16) && count--);
149 /* True up the columns before continuing */
150 for (i = 4; i >= (bytes / 4); i--)
151 db_printf ("\t");
152 /* Print chars, use . for non-printable's. */
153 while (bytes--) {
154 value = db_get_value(addr, 1, FALSE);
155 addr += 1;
156 if (value >= ' ' && value <= '~')
157 db_printf("%c", (char)value);
158 else
159 db_printf(".");
160 }
161 db_printf("\n");
162 break;
163 case 'z': /* signed hex */
164 value = db_get_value(addr, size, TRUE);
165 addr += size;
166 db_format_hex(tbuf, 24, value, FALSE);
167 db_printf("%-*s", width, tbuf);
168 break;
169 case 'd': /* signed decimal */
170 value = db_get_value(addr, size, TRUE);
171 addr += size;
172 db_printf("%-*ld", width, value);
173 break;
174 case 'u': /* unsigned decimal */
175 value = db_get_value(addr, size, FALSE);
176 addr += size;
177 db_printf("%-*lu", width, value);
178 break;
179 case 'o': /* unsigned octal */
180 value = db_get_value(addr, size, FALSE);
181 addr += size;
182 db_printf("%-*lo", width, value);
183 break;
184 case 'c': /* character */
185 value = db_get_value(addr, 1, FALSE);
186 addr += 1;
187 if (value >= ' ' && value <= '~')
188 db_printf("%c", (char)value);
189 else
190 db_printf("\\%03lo", value);
191 break;
192 case 's': /* null-terminated string */
193 for (;;) {
194 value = db_get_value(addr, 1, FALSE);
195 addr += 1;
196 if (value == 0)
197 break;
198 if (value >= ' ' && value <= '~')
199 db_printf("%c", (char)value);
200 else
201 db_printf("\\%03lo", value);
202 }
203 break;
204 case 'i': /* instruction */
205 addr = db_disasm(addr, FALSE);
206 break;
207 case 'I': /* instruction, alternate form */
208 addr = db_disasm(addr, TRUE);
209 break;
210 default:
211 break;
212 }
213 if (db_print_position() != 0)
214 db_end_line();
215 }
216 }
217 db_next = addr;
218 }
219
220 /*
221 * Print value.
222 */
223 char db_print_format = 'x';
224
225 /*ARGSUSED*/
226 void
227 db_print_cmd(addr, have_addr, count, modif)
228 db_expr_t addr;
229 int have_addr;
230 db_expr_t count;
231 char * modif;
232 {
233 db_expr_t value;
234
235 if (modif[0] != '\0')
236 db_print_format = modif[0];
237
238 switch (db_print_format) {
239 case 'a':
240 db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
241 break;
242 case 'r':
243 {
244 char tbuf[24];
245
246 db_format_radix(tbuf, 24, addr, FALSE);
247 db_printf("%11s", tbuf);
248 break;
249 }
250 case 'x':
251 db_printf("%8lx", addr);
252 break;
253 case 'z':
254 {
255 char tbuf[24];
256
257 db_format_hex(tbuf, 24, addr, FALSE);
258 db_printf("%8s", tbuf);
259 break;
260 }
261 case 'd':
262 db_printf("%11ld", addr);
263 break;
264 case 'u':
265 db_printf("%11lu", addr);
266 break;
267 case 'o':
268 db_printf("%16lo", addr);
269 break;
270 case 'c':
271 value = addr & 0xFF;
272 if (value >= ' ' && value <= '~')
273 db_printf("%c", (char)value);
274 else
275 db_printf("\\%03lo", value);
276 break;
277 }
278 db_printf("\n");
279 }
280
281 void
282 db_print_loc_and_inst(loc)
283 db_addr_t loc;
284 {
285 db_printsym(loc, DB_STGY_PROC, db_printf);
286 db_printf(":\t");
287 (void) db_disasm(loc, FALSE);
288 }
289
290 void
291 db_strcpy(dst, src)
292 char *dst;
293 char *src;
294 {
295 while ((*dst++ = *src++) != '\0')
296 ;
297 }
298
299 /*
300 * Search for a value in memory.
301 * Syntax: search [/bhl] addr value [mask] [,count]
302 */
303 /*ARGSUSED*/
304 void
305 db_search_cmd(daddr, have_addr, dcount, modif)
306 db_expr_t daddr;
307 int have_addr;
308 db_expr_t dcount;
309 char * modif;
310 {
311 int t;
312 db_addr_t addr;
313 int size;
314 db_expr_t value;
315 db_expr_t mask;
316 db_expr_t count;
317
318 t = db_read_token();
319 if (t == tSLASH) {
320 t = db_read_token();
321 if (t != tIDENT) {
322 bad_modifier:
323 db_printf("Bad modifier\n");
324 db_flush_lex();
325 return;
326 }
327
328 if (!strcmp(db_tok_string, "b"))
329 size = 1;
330 else if (!strcmp(db_tok_string, "h"))
331 size = 2;
332 else if (!strcmp(db_tok_string, "l"))
333 size = 4;
334 else
335 goto bad_modifier;
336 } else {
337 db_unread_token(t);
338 size = 4;
339 }
340
341 if (!db_expression(&value)) {
342 db_printf("Address missing\n");
343 db_flush_lex();
344 return;
345 }
346 addr = (db_addr_t) value;
347
348 if (!db_expression(&value)) {
349 db_printf("Value missing\n");
350 db_flush_lex();
351 return;
352 }
353
354 if (!db_expression(&mask))
355 mask = (int) ~0;
356
357 t = db_read_token();
358 if (t == tCOMMA) {
359 if (!db_expression(&count)) {
360 db_printf("Count missing\n");
361 db_flush_lex();
362 return;
363 }
364 } else {
365 db_unread_token(t);
366 count = -1; /* effectively forever */
367 }
368 db_skip_to_eol();
369
370 db_search(addr, size, value, mask, count);
371 }
372
373 void
374 db_search(addr, size, value, mask, count)
375 db_addr_t addr;
376 int size;
377 db_expr_t value;
378 db_expr_t mask;
379 unsigned int count;
380 {
381 while (count-- != 0) {
382 db_prev = addr;
383 if ((db_get_value(addr, size, FALSE) & mask) == value)
384 break;
385 addr += size;
386 }
387 db_next = addr;
388 }
389