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