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