1 | /* $NetBSD: db_examine.c,v 1.36 2015/06/06 22:06:05 matt 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@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.36 2015/06/06 22:06:05 matt Exp $" ); |
34 | |
35 | #include <sys/param.h> |
36 | #include <sys/systm.h> |
37 | #include <sys/buf.h> |
38 | #include <sys/proc.h> |
39 | |
40 | #include <ddb/ddb.h> |
41 | |
42 | static char db_examine_format[TOK_STRING_SIZE] = "x" ; |
43 | |
44 | static void db_examine(db_addr_t, char *, int); |
45 | static void db_search(db_addr_t, int, db_expr_t, db_expr_t, unsigned int); |
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(db_expr_t addr, bool have_addr, db_expr_t count, |
58 | const char *modif) |
59 | { |
60 | if (modif[0] != '\0') |
61 | strlcpy(db_examine_format, modif, sizeof(db_examine_format)); |
62 | |
63 | if (count == -1) |
64 | count = 1; |
65 | |
66 | db_examine((db_addr_t) addr, db_examine_format, count); |
67 | } |
68 | |
69 | static void |
70 | db_examine(db_addr_t addr, char *fmt, int count) |
71 | { |
72 | int i, c; |
73 | db_expr_t value; |
74 | int size; |
75 | int width; |
76 | int bytes; |
77 | char * fp; |
78 | char tbuf[24]; |
79 | |
80 | while (--count >= 0) { |
81 | fp = fmt; |
82 | size = 4; |
83 | width = 12; |
84 | while ((c = *fp++) != 0) { |
85 | if (db_print_position() == 0) { |
86 | /* Always print the address. */ |
87 | db_printsym(addr, DB_STGY_ANY, db_printf); |
88 | db_printf(":\t" ); |
89 | db_prev = addr; |
90 | } |
91 | switch (c) { |
92 | case 'b': /* byte */ |
93 | size = 1; |
94 | width = 4; |
95 | break; |
96 | case 'h': /* half-word */ |
97 | size = 2; |
98 | width = 8; |
99 | break; |
100 | case 'l': /* long-word */ |
101 | size = 4; |
102 | width = 12; |
103 | break; |
104 | case 'q': |
105 | if (sizeof(db_expr_t) != sizeof(uint64_t)) { |
106 | size = -1; |
107 | db_error("q not supported\n" ); |
108 | /*NOTREACHED*/ |
109 | } |
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" , (long)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("%-*" DDB_EXPR_FMT "x" , 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( |
143 | "%02" DDB_EXPR_FMT "x" , |
144 | value); |
145 | bytes++; |
146 | if (!(bytes % 4)) |
147 | db_printf(" " ); |
148 | } |
149 | } while ((bytes != 16) && count--); |
150 | /* True up the columns before continuing */ |
151 | for (i = 4; i >= (bytes / 4); i--) |
152 | db_printf ("\t" ); |
153 | /* Print chars, use . for non-printable's. */ |
154 | while (bytes--) { |
155 | value = db_get_value(addr, 1, false); |
156 | addr += 1; |
157 | if (value >= ' ' && value <= '~') |
158 | db_printf("%c" , (char)value); |
159 | else |
160 | db_printf("." ); |
161 | } |
162 | db_printf("\n" ); |
163 | break; |
164 | case 'z': /* signed hex */ |
165 | value = db_get_value(addr, size, true); |
166 | addr += size; |
167 | db_format_hex(tbuf, 24, value, false); |
168 | db_printf("%-*s" , width, tbuf); |
169 | break; |
170 | case 'd': /* signed decimal */ |
171 | value = db_get_value(addr, size, true); |
172 | addr += size; |
173 | db_printf("%-*" DDB_EXPR_FMT "d" , width, value); |
174 | break; |
175 | case 'u': /* unsigned decimal */ |
176 | value = db_get_value(addr, size, false); |
177 | addr += size; |
178 | db_printf("%-*" DDB_EXPR_FMT "u" , width, value); |
179 | break; |
180 | case 'o': /* unsigned octal */ |
181 | value = db_get_value(addr, size, false); |
182 | addr += size; |
183 | db_printf("%-*" DDB_EXPR_FMT "o" , width, value); |
184 | break; |
185 | case 'c': /* character */ |
186 | value = db_get_value(addr, 1, false); |
187 | addr += 1; |
188 | if (value >= ' ' && value <= '~') |
189 | db_printf("%c" , (char)value); |
190 | else |
191 | db_printf("\\%03o" , (int)value); |
192 | break; |
193 | case 's': /* null-terminated string */ |
194 | for (;;) { |
195 | value = db_get_value(addr, 1, false); |
196 | addr += 1; |
197 | if (value == 0) |
198 | break; |
199 | if (value >= ' ' && value <= '~') |
200 | db_printf("%c" , (char)value); |
201 | else |
202 | db_printf("\\%03o" , (int)value); |
203 | } |
204 | break; |
205 | case 'i': /* instruction */ |
206 | addr = db_disasm(addr, false); |
207 | break; |
208 | case 'I': /* instruction, alternate form */ |
209 | addr = db_disasm(addr, true); |
210 | break; |
211 | default: |
212 | break; |
213 | } |
214 | if (db_print_position() != 0) |
215 | db_end_line(); |
216 | } |
217 | } |
218 | db_next = addr; |
219 | } |
220 | |
221 | /* |
222 | * Print value. |
223 | */ |
224 | static char db_print_format = 'x'; |
225 | |
226 | /*ARGSUSED*/ |
227 | void |
228 | db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, |
229 | const char *modif) |
230 | { |
231 | db_expr_t value; |
232 | |
233 | if (modif[0] != '\0') |
234 | db_print_format = modif[0]; |
235 | |
236 | switch (db_print_format) { |
237 | case 'a': |
238 | db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf); |
239 | break; |
240 | case 'r': |
241 | { |
242 | char tbuf[24]; |
243 | |
244 | db_format_radix(tbuf, 24, addr, false); |
245 | db_printf("%11s" , tbuf); |
246 | break; |
247 | } |
248 | case 'x': |
249 | db_printf("%16" DDB_EXPR_FMT "x" , addr); |
250 | break; |
251 | case 'z': |
252 | { |
253 | char tbuf[24]; |
254 | |
255 | db_format_hex(tbuf, 24, addr, false); |
256 | db_printf("%8s" , tbuf); |
257 | break; |
258 | } |
259 | case 'd': |
260 | db_printf("%11" DDB_EXPR_FMT "d" , addr); |
261 | break; |
262 | case 'u': |
263 | db_printf("%11" DDB_EXPR_FMT "u" , addr); |
264 | break; |
265 | case 'o': |
266 | db_printf("%15" DDB_EXPR_FMT "o" , addr); |
267 | break; |
268 | case 'c': |
269 | value = addr & 0xFF; |
270 | if (value >= ' ' && value <= '~') |
271 | db_printf("%c" , (char)value); |
272 | else |
273 | db_printf("\\%03o" , (int)value); |
274 | break; |
275 | } |
276 | db_printf("\n" ); |
277 | } |
278 | |
279 | void |
280 | db_print_loc_and_inst(db_addr_t loc) |
281 | { |
282 | |
283 | db_printsym(loc, DB_STGY_PROC, db_printf); |
284 | db_printf(":\t" ); |
285 | (void) db_disasm(loc, false); |
286 | } |
287 | |
288 | /* |
289 | * Search for a value in memory. |
290 | * Syntax: search [/bhl] addr value [mask] [,count] |
291 | */ |
292 | /*ARGSUSED*/ |
293 | void |
294 | db_search_cmd(db_expr_t daddr, bool have_addr, |
295 | db_expr_t dcount, const char *modif) |
296 | { |
297 | int t; |
298 | db_addr_t addr; |
299 | int size; |
300 | db_expr_t value; |
301 | db_expr_t mask; |
302 | db_expr_t count; |
303 | |
304 | t = db_read_token(); |
305 | if (t == tSLASH) { |
306 | t = db_read_token(); |
307 | if (t != tIDENT) { |
308 | bad_modifier: |
309 | db_printf("Bad modifier\n" ); |
310 | db_flush_lex(); |
311 | return; |
312 | } |
313 | |
314 | if (!strcmp(db_tok_string, "b" )) |
315 | size = 1; |
316 | else if (!strcmp(db_tok_string, "h" )) |
317 | size = 2; |
318 | else if (!strcmp(db_tok_string, "l" )) |
319 | size = 4; |
320 | else |
321 | goto bad_modifier; |
322 | } else { |
323 | db_unread_token(t); |
324 | size = 4; |
325 | } |
326 | |
327 | if (!db_expression(&value)) { |
328 | db_printf("Address missing\n" ); |
329 | db_flush_lex(); |
330 | return; |
331 | } |
332 | addr = (db_addr_t) value; |
333 | |
334 | if (!db_expression(&value)) { |
335 | db_printf("Value missing\n" ); |
336 | db_flush_lex(); |
337 | return; |
338 | } |
339 | |
340 | if (!db_expression(&mask)) |
341 | mask = (int) ~0; |
342 | |
343 | t = db_read_token(); |
344 | if (t == tCOMMA) { |
345 | if (!db_expression(&count)) { |
346 | db_printf("Count missing\n" ); |
347 | db_flush_lex(); |
348 | return; |
349 | } |
350 | } else { |
351 | db_unread_token(t); |
352 | count = -1; /* effectively forever */ |
353 | } |
354 | db_skip_to_eol(); |
355 | |
356 | db_search(addr, size, value, mask, count); |
357 | } |
358 | |
359 | static void |
360 | db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask, |
361 | unsigned int count) |
362 | { |
363 | while (count-- != 0) { |
364 | db_prev = addr; |
365 | if ((db_get_value(addr, size, false) & mask) == value) |
366 | break; |
367 | addr += size; |
368 | } |
369 | db_next = addr; |
370 | } |
371 | |