xref: /netbsd-src/sys/ddb/db_examine.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /*	$NetBSD: db_examine.c,v 1.22 2001/11/12 22:54:04 lukem 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.22 2001/11/12 22:54:04 lukem Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.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/[bhl][cdiorsuxz]*
54  * For example, the command:
55  *  	x/bxxxx
56  * should print:
57  *  	address:  01  23  45  67
58  */
59 /*ARGSUSED*/
60 void
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_strcpy(db_examine_format, modif);
69 
70 	if (count == -1)
71 		count = 1;
72 
73 	db_examine((db_addr_t) addr, db_examine_format, count);
74 }
75 
76 void
77 db_examine(addr, fmt, count)
78 	db_addr_t	addr;
79 	char *		fmt;	/* format string */
80 	int		count;	/* repeat count */
81 {
82 	int		i, c;
83 	db_expr_t	value;
84 	int		size;
85 	int		width;
86 	int		bytes;
87 	char *		fp;
88 	char		tbuf[24];
89 
90 	while (--count >= 0) {
91 		fp = fmt;
92 		size = 4;
93 		width = 12;
94 		while ((c = *fp++) != 0) {
95 			if (db_print_position() == 0) {
96 				/* Always print the address. */
97 				db_printsym(addr, DB_STGY_ANY, db_printf);
98 				db_printf(":\t");
99 				db_prev = addr;
100 			}
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 			case 'L':	/* implementation maximum */
115 				size = sizeof value;
116 				width = 12 * (sizeof value / 4);
117 				break;
118 			case 'a':	/* address */
119 				db_printf("= 0x%lx\n", addr);
120 				break;
121 			case 'r':	/* signed, current radix */
122 				value = db_get_value(addr, size, TRUE);
123 				addr += size;
124 				db_format_radix(tbuf, 24, value, FALSE);
125 				db_printf("%-*s", width, tbuf);
126 				break;
127 			case 'x':	/* unsigned hex */
128 				value = db_get_value(addr, size, FALSE);
129 				addr += size;
130 				db_printf("%-*lx", width, value);
131 				break;
132 			case 'm':	/* hex dump */
133 				/*
134 				 * Print off in chunks of size. Try to print 16
135 				 * bytes at a time into 4 columns. This
136 				 * loops modify's count extra times in order
137 				 * to get the nicely formatted lines.
138 				 */
139 
140 				bytes = 0;
141 				do {
142 					for (i = 0; i < size; i++) {
143 						value =
144  						    db_get_value(addr+bytes, 1,
145 						        FALSE);
146 						db_printf("%02lx", value);
147 						bytes++;
148 						if (!(bytes % 4))
149 							db_printf(" ");
150 					}
151 				} while ((bytes != 16) && count--);
152 				/* True up the columns before continuing */
153 				for (i = 4; i >= (bytes / 4); i--)
154 					db_printf ("\t");
155 				/* Print chars,  use . for non-printable's. */
156 				while (bytes--) {
157 					value = db_get_value(addr, 1, FALSE);
158 					addr += 1;
159 					if (value >= ' ' && value <= '~')
160 						db_printf("%c", (char)value);
161 					else
162 						db_printf(".");
163 				}
164 				db_printf("\n");
165 				break;
166 			case 'z':	/* signed hex */
167 				value = db_get_value(addr, size, TRUE);
168 				addr += size;
169 				db_format_hex(tbuf, 24, value, FALSE);
170 				db_printf("%-*s", width, tbuf);
171 				break;
172 			case 'd':	/* signed decimal */
173 				value = db_get_value(addr, size, TRUE);
174 				addr += size;
175 				db_printf("%-*ld", width, value);
176 				break;
177 			case 'u':	/* unsigned decimal */
178 				value = db_get_value(addr, size, FALSE);
179 				addr += size;
180 				db_printf("%-*lu", width, value);
181 				break;
182 			case 'o':	/* unsigned octal */
183 				value = db_get_value(addr, size, FALSE);
184 				addr += size;
185 				db_printf("%-*lo", width, value);
186 				break;
187 			case 'c':	/* character */
188 				value = db_get_value(addr, 1, FALSE);
189 				addr += 1;
190 				if (value >= ' ' && value <= '~')
191 					db_printf("%c", (char)value);
192 				else
193 					db_printf("\\%03lo", value);
194 				break;
195 			case 's':	/* null-terminated string */
196 				for (;;) {
197 					value = db_get_value(addr, 1, FALSE);
198 					addr += 1;
199 					if (value == 0)
200 						break;
201 					if (value >= ' ' && value <= '~')
202 						db_printf("%c", (char)value);
203 					else
204 						db_printf("\\%03lo", value);
205 				}
206 				break;
207 			case 'i':	/* instruction */
208 				addr = db_disasm(addr, FALSE);
209 				break;
210 			case 'I':	/* instruction, alternate form */
211 				addr = db_disasm(addr, TRUE);
212 				break;
213 			default:
214 				break;
215 			}
216 			if (db_print_position() != 0)
217 				db_end_line();
218 		}
219 	}
220 	db_next = addr;
221 }
222 
223 /*
224  * Print value.
225  */
226 char	db_print_format = 'x';
227 
228 /*ARGSUSED*/
229 void
230 db_print_cmd(addr, have_addr, count, modif)
231 	db_expr_t	addr;
232 	int		have_addr;
233 	db_expr_t	count;
234 	char *		modif;
235 {
236 	db_expr_t	value;
237 
238 	if (modif[0] != '\0')
239 		db_print_format = modif[0];
240 
241 	switch (db_print_format) {
242 	case 'a':
243 		db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
244 		break;
245 	case 'r':
246 		{
247 			char tbuf[24];
248 
249 			db_format_radix(tbuf, 24, addr, FALSE);
250 			db_printf("%11s", tbuf);
251 			break;
252 		}
253 	case 'x':
254 		db_printf("%8lx", addr);
255 		break;
256 	case 'z':
257 		{
258 			char tbuf[24];
259 
260 			db_format_hex(tbuf, 24, addr, FALSE);
261 			db_printf("%8s", tbuf);
262 			break;
263 		}
264 	case 'd':
265 		db_printf("%11ld", addr);
266 		break;
267 	case 'u':
268 		db_printf("%11lu", addr);
269 		break;
270 	case 'o':
271 		db_printf("%16lo", addr);
272 		break;
273 	case 'c':
274 		value = addr & 0xFF;
275 		if (value >= ' ' && value <= '~')
276 			db_printf("%c", (char)value);
277 		else
278 			db_printf("\\%03lo", value);
279 		break;
280 	}
281 	db_printf("\n");
282 }
283 
284 void
285 db_print_loc_and_inst(loc)
286 	db_addr_t	loc;
287 {
288 	db_printsym(loc, DB_STGY_PROC, db_printf);
289 	db_printf(":\t");
290 	(void) db_disasm(loc, FALSE);
291 }
292 
293 void
294 db_strcpy(dst, src)
295 	char *dst;
296 	char *src;
297 {
298 	while ((*dst++ = *src++) != '\0')
299 		;
300 }
301 
302 /*
303  * Search for a value in memory.
304  * Syntax: search [/bhl] addr value [mask] [,count]
305  */
306 /*ARGSUSED*/
307 void
308 db_search_cmd(daddr, have_addr, dcount, modif)
309 	db_expr_t	daddr;
310 	int		have_addr;
311 	db_expr_t	dcount;
312 	char *		modif;
313 {
314 	int		t;
315 	db_addr_t	addr;
316 	int		size;
317 	db_expr_t	value;
318 	db_expr_t	mask;
319 	db_expr_t	count;
320 
321 	t = db_read_token();
322 	if (t == tSLASH) {
323 		t = db_read_token();
324 		if (t != tIDENT) {
325 			bad_modifier:
326 			db_printf("Bad modifier\n");
327 			db_flush_lex();
328 			return;
329 		}
330 
331 		if (!strcmp(db_tok_string, "b"))
332 			size = 1;
333 		else if (!strcmp(db_tok_string, "h"))
334 			size = 2;
335 		else if (!strcmp(db_tok_string, "l"))
336 			size = 4;
337 		else
338 			goto bad_modifier;
339 	} else {
340 		db_unread_token(t);
341 		size = 4;
342 	}
343 
344 	if (!db_expression(&value)) {
345 		db_printf("Address missing\n");
346 		db_flush_lex();
347 		return;
348 	}
349 	addr = (db_addr_t) value;
350 
351 	if (!db_expression(&value)) {
352 		db_printf("Value missing\n");
353 		db_flush_lex();
354 		return;
355 	}
356 
357 	if (!db_expression(&mask))
358 		mask = (int) ~0;
359 
360 	t = db_read_token();
361 	if (t == tCOMMA) {
362 		if (!db_expression(&count)) {
363 			db_printf("Count missing\n");
364 			db_flush_lex();
365 			return;
366 		}
367 	} else {
368 		db_unread_token(t);
369 		count = -1;		/* effectively forever */
370 	}
371 	db_skip_to_eol();
372 
373 	db_search(addr, size, value, mask, count);
374 }
375 
376 void
377 db_search(addr, size, value, mask, count)
378 	db_addr_t	addr;
379 	int		size;
380 	db_expr_t	value;
381 	db_expr_t	mask;
382 	unsigned int	count;
383 {
384 	while (count-- != 0) {
385 		db_prev = addr;
386 		if ((db_get_value(addr, size, FALSE) & mask) == value)
387 			break;
388 		addr += size;
389 	}
390 	db_next = addr;
391 }
392