db_examine.c revision 1.20 1 /* $NetBSD: db_examine.c,v 1.20 2000/12/28 07:30:06 jmc 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/proc.h>
34
35 #include <machine/db_machdep.h> /* type definitions */
36
37 #include <ddb/db_lex.h>
38 #include <ddb/db_output.h>
39 #include <ddb/db_command.h>
40 #include <ddb/db_sym.h>
41 #include <ddb/db_access.h>
42 #include <ddb/db_extern.h>
43 #include <ddb/db_interface.h>
44
45 char db_examine_format[TOK_STRING_SIZE] = "x";
46
47 /*
48 * Examine (print) data. Syntax is:
49 * x/[bhl][cdiorsuxz]*
50 * For example, the command:
51 * x/bxxxx
52 * should print:
53 * address: 01 23 45 67
54 */
55 /*ARGSUSED*/
56 void
57 db_examine_cmd(addr, have_addr, count, modif)
58 db_expr_t addr;
59 int have_addr;
60 db_expr_t count;
61 char * modif;
62 {
63 if (modif[0] != '\0')
64 db_strcpy(db_examine_format, modif);
65
66 if (count == -1)
67 count = 1;
68
69 db_examine((db_addr_t) addr, db_examine_format, count);
70 }
71
72 void
73 db_examine(addr, fmt, count)
74 db_addr_t addr;
75 char * fmt; /* format string */
76 int count; /* repeat 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 char db_print_format = 'x';
223
224 /*ARGSUSED*/
225 void
226 db_print_cmd(addr, have_addr, count, modif)
227 db_expr_t addr;
228 int have_addr;
229 db_expr_t count;
230 char * modif;
231 {
232 db_expr_t value;
233
234 if (modif[0] != '\0')
235 db_print_format = modif[0];
236
237 switch (db_print_format) {
238 case 'a':
239 db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
240 break;
241 case 'r':
242 {
243 char tbuf[24];
244
245 db_format_radix(tbuf, 24, addr, FALSE);
246 db_printf("%11s", tbuf);
247 break;
248 }
249 case 'x':
250 db_printf("%8lx", addr);
251 break;
252 case 'z':
253 {
254 char tbuf[24];
255
256 db_format_hex(tbuf, 24, addr, FALSE);
257 db_printf("%8s", tbuf);
258 break;
259 }
260 case 'd':
261 db_printf("%11ld", addr);
262 break;
263 case 'u':
264 db_printf("%11lu", addr);
265 break;
266 case 'o':
267 db_printf("%16lo", addr);
268 break;
269 case 'c':
270 value = addr & 0xFF;
271 if (value >= ' ' && value <= '~')
272 db_printf("%c", (char)value);
273 else
274 db_printf("\\%03lo", value);
275 break;
276 }
277 db_printf("\n");
278 }
279
280 void
281 db_print_loc_and_inst(loc)
282 db_addr_t loc;
283 {
284 db_printsym(loc, DB_STGY_PROC, db_printf);
285 db_printf(":\t");
286 (void) db_disasm(loc, FALSE);
287 }
288
289 void
290 db_strcpy(dst, src)
291 char *dst;
292 char *src;
293 {
294 while ((*dst++ = *src++) != '\0')
295 ;
296 }
297
298 /*
299 * Search for a value in memory.
300 * Syntax: search [/bhl] addr value [mask] [,count]
301 */
302 /*ARGSUSED*/
303 void
304 db_search_cmd(daddr, have_addr, dcount, modif)
305 db_expr_t daddr;
306 int have_addr;
307 db_expr_t dcount;
308 char * modif;
309 {
310 int t;
311 db_addr_t addr;
312 int size;
313 db_expr_t value;
314 db_expr_t mask;
315 db_expr_t count;
316
317 t = db_read_token();
318 if (t == tSLASH) {
319 t = db_read_token();
320 if (t != tIDENT) {
321 bad_modifier:
322 db_printf("Bad modifier\n");
323 db_flush_lex();
324 return;
325 }
326
327 if (!strcmp(db_tok_string, "b"))
328 size = 1;
329 else if (!strcmp(db_tok_string, "h"))
330 size = 2;
331 else if (!strcmp(db_tok_string, "l"))
332 size = 4;
333 else
334 goto bad_modifier;
335 } else {
336 db_unread_token(t);
337 size = 4;
338 }
339
340 if (!db_expression(&value)) {
341 db_printf("Address missing\n");
342 db_flush_lex();
343 return;
344 }
345 addr = (db_addr_t) value;
346
347 if (!db_expression(&value)) {
348 db_printf("Value missing\n");
349 db_flush_lex();
350 return;
351 }
352
353 if (!db_expression(&mask))
354 mask = (int) ~0;
355
356 t = db_read_token();
357 if (t == tCOMMA) {
358 if (!db_expression(&count)) {
359 db_printf("Count missing\n");
360 db_flush_lex();
361 return;
362 }
363 } else {
364 db_unread_token(t);
365 count = -1; /* effectively forever */
366 }
367 db_skip_to_eol();
368
369 db_search(addr, size, value, mask, count);
370 }
371
372 void
373 db_search(addr, size, value, mask, count)
374 db_addr_t addr;
375 int size;
376 db_expr_t value;
377 db_expr_t mask;
378 unsigned int count;
379 {
380 while (count-- != 0) {
381 db_prev = addr;
382 if ((db_get_value(addr, size, FALSE) & mask) == value)
383 break;
384 addr += size;
385 }
386 db_next = addr;
387 }
388