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