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