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