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