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