1 /* $OpenBSD: db_examine.c,v 1.28 2023/03/08 04:43:07 guenther 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(vaddr_t, char *, int);
49 void db_search(vaddr_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 void
db_examine_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)60 db_examine_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
61 {
62 if (modif[0] != '\0')
63 db_strlcpy(db_examine_format, modif, sizeof(db_examine_format));
64
65 if (count == -1)
66 count = 1;
67
68 db_examine((vaddr_t)addr, db_examine_format, count);
69 }
70
71 void
db_examine(vaddr_t addr,char * fmt,int count)72 db_examine(vaddr_t addr, char *fmt, int count)
73 {
74 int i, c;
75 db_expr_t value;
76 int size;
77 int width;
78 int bytes;
79 char * fp;
80 vaddr_t incr;
81 int dis;
82 char tmpfmt[28];
83
84 while (--count >= 0) {
85 fp = fmt;
86
87 /* defaults */
88 size = 4;
89 width = 12;
90 incr = 0;
91 dis = 0;
92
93 while ((c = *fp++) != 0) {
94 if (db_print_position() == 0) {
95 /* Always print the address. */
96 db_printsym(addr, DB_STGY_ANY, db_printf);
97 db_printf(":\t");
98 db_prev = addr;
99 }
100 incr = size;
101 switch (c) {
102 case 'b': /* byte */
103 size = 1;
104 width = 4;
105 break;
106 case 'h': /* half-word */
107 size = 2;
108 width = 8;
109 break;
110 case 'l': /* long-word */
111 size = 4;
112 width = 12;
113 break;
114 #ifdef __LP64__
115 case 'q': /* quad-word */
116 size = 8;
117 width = 20;
118 break;
119 #endif
120 case 'a': /* address */
121 db_printf("= 0x%lx\n", (long)addr);
122 incr = 0;
123 break;
124 case 'r': /* signed, current radix */
125 value = db_get_value(addr, size, 1);
126 db_format(tmpfmt, sizeof tmpfmt,
127 (long)value, DB_FORMAT_R, 0, width);
128 db_printf("%-*s", width, tmpfmt);
129 break;
130 case 'x': /* unsigned hex */
131 value = db_get_value(addr, size, 0);
132 db_printf("%*lx", width, (long)value);
133 break;
134 case 'm': /* hex dump */
135 /*
136 * Print off in chunks of size. Try to print 16
137 * bytes at a time into 4 columns. This
138 * loops modify's count extra times in order
139 * to get the nicely formatted lines.
140 */
141 incr = 0;
142 bytes = 0;
143 do {
144 for (i = 0; i < size; i++) {
145 value =
146 db_get_value(addr+bytes, 1,
147 0);
148 db_printf("%02lx",
149 (long)value);
150 bytes++;
151 if (!(bytes % 4))
152 db_printf(" ");
153 }
154 } while ((bytes != 16) && count--);
155 /* True up the columns before continuing */
156 db_printf("%-*s",
157 (16-bytes)*2 + (4 - bytes/4) + 1, " ");
158 /* Print chars, use . for non-printables */
159 while (bytes--) {
160 value = db_get_value(addr + incr, 1, 0);
161 incr++;
162 if (value >= ' ' && value <= '~')
163 db_printf("%c", (int)value);
164 else
165 db_printf(".");
166 }
167 db_printf("\n");
168 break;
169 case 'z': /* signed hex */
170 value = db_get_value(addr, size, 1);
171 db_format(tmpfmt, sizeof tmpfmt,
172 (long)value, DB_FORMAT_Z, 0, width);
173 db_printf("%-*s", width, tmpfmt);
174 break;
175 case 'd': /* signed decimal */
176 value = db_get_value(addr, size, 1);
177 db_printf("%-*ld", width, (long)value);
178 break;
179 case 'u': /* unsigned decimal */
180 value = db_get_value(addr, size, 0);
181 db_printf("%-*lu", width, (long)value);
182 break;
183 case 'o': /* unsigned octal */
184 value = db_get_value(addr, size, 0);
185 db_printf("%-*lo", width, value);
186 break;
187 case 'c': /* character */
188 value = db_get_value(addr, 1, 0);
189 incr = 1;
190 if (value >= ' ' && value <= '~')
191 db_printf("%c", (int)value);
192 else
193 db_printf("\\%03o", (int)value);
194 break;
195 case 's': /* null-terminated string */
196 incr = 0;
197 for (;;) {
198 value = db_get_value(addr + incr, 1,
199 0);
200 incr++;
201 if (value == 0)
202 break;
203 if (value >= ' ' && value <= '~')
204 db_printf("%c", (int)value);
205 else
206 db_printf("\\%03o", (int)value);
207 }
208 break;
209 case 'i': /* instruction */
210 case 'I': /* instruction, alternate form */
211 dis = c;
212 break;
213 default:
214 incr = 0;
215 break;
216 }
217 }
218 /* if we had a disassembly modifier, do it last */
219 switch (dis) {
220 case 'i': /* instruction */
221 addr = db_disasm(addr, 0);
222 break;
223 case 'I': /* instruction, alternate form */
224 addr = db_disasm(addr, 1);
225 break;
226 default:
227 addr += incr;
228 break;
229 }
230 if (db_print_position() != 0)
231 db_printf("\n");
232 }
233 db_next = addr;
234 }
235
236 /*
237 * Print value.
238 */
239 char db_print_format = 'x';
240
241 void
db_print_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)242 db_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
243 {
244 db_expr_t value;
245 char tmpfmt[28];
246
247 if (modif[0] != '\0')
248 db_print_format = modif[0];
249
250 switch (db_print_format) {
251 case 'a':
252 db_printsym((vaddr_t)addr, DB_STGY_ANY, db_printf);
253 break;
254 case 'r':
255 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr,
256 DB_FORMAT_R, 0, sizeof(db_expr_t) * 2 * 6 / 5));
257 break;
258 case 'x':
259 db_printf("%*lx", (uint)sizeof(db_expr_t) * 2, addr);
260 break;
261 case 'z':
262 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr,
263 DB_FORMAT_Z, 0, sizeof(db_expr_t) * 2));
264 break;
265 case 'd':
266 db_printf("%*ld", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr);
267 break;
268 case 'u':
269 db_printf("%*lu", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr);
270 break;
271 case 'o':
272 db_printf("%*lo", (uint)sizeof(db_expr_t) * 2 * 4 / 3, addr);
273 break;
274 case 'c':
275 value = addr & 0xFF;
276 if (value >= ' ' && value <= '~')
277 db_printf("%c", (int)value);
278 else
279 db_printf("\\%03o", (int)value);
280 break;
281 }
282 db_printf("\n");
283 }
284
285 void
db_print_loc_and_inst(vaddr_t loc)286 db_print_loc_and_inst(vaddr_t loc)
287 {
288 db_printsym(loc, DB_STGY_PROC, db_printf);
289 if (loc != 0) {
290 db_printf(":\t");
291 db_disasm(loc, 0);
292 }
293 }
294
295 /* local copy is needed here so that we can trace strlcpy() in libkern */
296 size_t
db_strlcpy(char * dst,const char * src,size_t siz)297 db_strlcpy(char *dst, const char *src, size_t siz)
298 {
299 char *d = dst;
300 const char *s = src;
301 size_t n = siz;
302
303 /* Copy as many bytes as will fit */
304 if (n != 0 && --n != 0) {
305 do {
306 if ((*d++ = *s++) == 0)
307 break;
308 } while (--n != 0);
309 }
310
311 /* Not enough room in dst, add NUL and traverse rest of src */
312 if (n == 0) {
313 if (siz != 0)
314 *d = '\0'; /* NUL-terminate dst */
315 while (*s++)
316 continue;
317 }
318
319 return(s - src - 1); /* count does not include NUL */
320 }
321
322 /*
323 * Search for a value in memory.
324 * Syntax: search [/bhl] addr value [mask] [,count]
325 */
326 void
db_search_cmd(db_expr_t daddr,int have_addr,db_expr_t dcount,char * modif)327 db_search_cmd(db_expr_t daddr, int have_addr, db_expr_t dcount, char *modif)
328 {
329 int t;
330 vaddr_t addr;
331 int size;
332 db_expr_t value;
333 db_expr_t mask;
334 db_expr_t count;
335
336 t = db_read_token();
337 if (t == tSLASH) {
338 t = db_read_token();
339 if (t != tIDENT) {
340 bad_modifier:
341 db_printf("Bad modifier\n");
342 db_flush_lex();
343 return;
344 }
345
346 if (!strcmp(db_tok_string, "b"))
347 size = 1;
348 else if (!strcmp(db_tok_string, "h"))
349 size = 2;
350 else if (!strcmp(db_tok_string, "l"))
351 size = 4;
352 else
353 goto bad_modifier;
354 } else {
355 db_unread_token(t);
356 size = 4;
357 }
358
359 if (!db_expression(&value)) {
360 db_printf("Address missing\n");
361 db_flush_lex();
362 return;
363 }
364 addr = (vaddr_t) value;
365
366 if (!db_expression(&value)) {
367 db_printf("Value missing\n");
368 db_flush_lex();
369 return;
370 }
371
372 if (!db_expression(&mask))
373 mask = (int) ~0;
374
375 t = db_read_token();
376 if (t == tCOMMA) {
377 if (!db_expression(&count)) {
378 db_printf("Count missing\n");
379 db_flush_lex();
380 return;
381 }
382 } else {
383 db_unread_token(t);
384 count = -1; /* forever */
385 }
386 db_skip_to_eol();
387
388 db_search(addr, size, value, mask, count);
389 }
390
391 void
db_search(vaddr_t addr,int size,db_expr_t value,db_expr_t mask,db_expr_t count)392 db_search(vaddr_t addr, int size, db_expr_t value, db_expr_t mask,
393 db_expr_t count)
394 {
395 /* Negative counts means forever. */
396 while (count < 0 || count-- != 0) {
397 db_prev = addr;
398 if ((db_get_value(addr, size, 0) & mask) == value)
399 break;
400 addr += size;
401 }
402 db_next = addr;
403 }
404