xref: /netbsd-src/sys/ddb/db_examine.c (revision 6e5e6fa95872363f0872a6cfb805e8df2d1dfc30)
1 /*	$NetBSD: db_examine.c,v 1.40 2019/09/12 09:20:23 ryo 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.40 2019/09/12 09:20:23 ryo 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
db_examine_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)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
db_examine(db_addr_t addr,char * fmt,int count)70 db_examine(db_addr_t addr, char *fmt, int count)
71 {
72 	int		i, c;
73 	quad_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 'q':	/* quad-word */
105 				size = 8;
106 				width = 24;
107 				break;
108 			case 'L':	/* implementation maximum */
109 				size = sizeof value;
110 				width = 12 * (sizeof value / 4);
111 				break;
112 			case 'a':	/* address */
113 				db_printf("= 0x%lx\n", (long)addr);
114 				break;
115 			case 'p':
116 				size = sizeof(void *);
117 				value = db_get_value(addr, size, false);
118 				addr += size;
119 				db_printf("= 0x%lx ", (long)value);
120 				db_printsym((db_addr_t)value, DB_STGY_ANY, db_printf);
121 				db_printf("\n");
122 				break;
123 			case 'r':	/* signed, current radix */
124 				value = db_get_qvalue(addr, size, true);
125 				addr += size;
126 				db_format_radix(tbuf, 24, value, false);
127 				db_printf("%-*s", width, tbuf);
128 				break;
129 			case 'x':	/* unsigned hex */
130 				value = db_get_qvalue(addr, size, false);
131 				addr += size;
132 				db_printf("%-*" PRIx64, width, value);
133 				break;
134 			case 'm':	/* hex dump */
135 				/*
136 				 * Print off in chunks of size. Try to print 16
137 				 * bytes at a time into 16/size columns. This
138 				 * loops modify's count extra times in order
139 				 * to get the nicely formatted lines.
140 				 */
141 
142 				bytes = 0;
143 				do {
144 					for (i = 0; i < size; i++) {
145 						value =
146 #if BYTE_ORDER == LITTLE_ENDIAN
147 						    db_get_value(addr +
148 						    (bytes & ~(size - 1)) +
149 						    size - i - 1, 1, false);
150 #else
151 						    db_get_value(addr + bytes,
152 						    1, false);
153 #endif
154 						db_printf(
155 						    "%02" PRIx64,
156 						    value);
157 						bytes++;
158 						if (!(bytes % size))
159 							db_printf(" ");
160 					}
161 				} while ((bytes != 16) && count--);
162 				/* True up the columns before continuing */
163 				for (i = 4; i >= (bytes / 4); i--)
164 					db_printf ("\t");
165 				/* Print chars,  use . for non-printable's. */
166 				while (bytes--) {
167 					value = db_get_value(addr, 1, false);
168 					addr += 1;
169 					if (value >= ' ' && value <= '~')
170 						db_printf("%c", (char)value);
171 					else
172 						db_printf(".");
173 				}
174 				db_printf("\n");
175 				break;
176 			case 'z':	/* signed hex */
177 				value = db_get_qvalue(addr, size, true);
178 				addr += size;
179 				db_format_hex(tbuf, 24, value, false);
180 				db_printf("%-*s", width, tbuf);
181 				break;
182 			case 'd':	/* signed decimal */
183 				value = db_get_qvalue(addr, size, true);
184 				addr += size;
185 				db_printf("%-*" PRId64, width, value);
186 				break;
187 			case 'u':	/* unsigned decimal */
188 				value = db_get_qvalue(addr, size, false);
189 				addr += size;
190 				db_printf("%-*" PRIu64, width, value);
191 				break;
192 			case 'o':	/* unsigned octal */
193 				value = db_get_qvalue(addr, size, false);
194 				addr += size;
195 				db_printf("%-*" PRIo64, width, value);
196 				break;
197 			case 'c':	/* character */
198 				value = db_get_value(addr, 1, false);
199 				addr += 1;
200 				if (value >= ' ' && value <= '~')
201 					db_printf("%c", (char)value);
202 				else
203 					db_printf("\\%03o", (int)value);
204 				break;
205 			case 's':	/* null-terminated string */
206 				for (;;) {
207 					value = db_get_value(addr, 1, false);
208 					addr += 1;
209 					if (value == 0)
210 						break;
211 					if (value >= ' ' && value <= '~')
212 						db_printf("%c", (char)value);
213 					else
214 						db_printf("\\%03o", (int)value);
215 				}
216 				break;
217 			case 'i':	/* instruction */
218 				addr = db_disasm(addr, false);
219 				break;
220 			case 'I':	/* instruction, alternate form */
221 				addr = db_disasm(addr, true);
222 				break;
223 			default:
224 				break;
225 			}
226 			if (db_print_position() != 0)
227 				db_end_line();
228 		}
229 	}
230 	db_next = addr;
231 }
232 
233 /*
234  * Print value.
235  */
236 static char	db_print_format = 'x';
237 
238 /*ARGSUSED*/
239 void
db_print_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)240 db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
241     const char *modif)
242 {
243 	db_expr_t	value;
244 
245 	if (modif[0] != '\0')
246 		db_print_format = modif[0];
247 
248 	switch (db_print_format) {
249 	case 'a':
250 		db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
251 		break;
252 	case 'r':
253 		{
254 			char tbuf[24];
255 
256 			db_format_radix(tbuf, 24, addr, false);
257 			db_printf("%11s", tbuf);
258 			break;
259 		}
260 	case 'x':
261 		db_printf("%16" DDB_EXPR_FMT "x", addr);
262 		break;
263 	case 'z':
264 		{
265 			char tbuf[24];
266 
267 			db_format_hex(tbuf, 24, addr, false);
268 			db_printf("%8s", tbuf);
269 			break;
270 		}
271 	case 'd':
272 		db_printf("%11" DDB_EXPR_FMT "d", addr);
273 		break;
274 	case 'u':
275 		db_printf("%11" DDB_EXPR_FMT "u", addr);
276 		break;
277 	case 'o':
278 		db_printf("%15" DDB_EXPR_FMT "o", addr);
279 		break;
280 	case 'c':
281 		value = addr & 0xFF;
282 		if (value >= ' ' && value <= '~')
283 			db_printf("%c", (char)value);
284 		else
285 			db_printf("\\%03o", (int)value);
286 		break;
287 	}
288 	db_printf("\n");
289 }
290 
291 void
db_print_loc_and_inst(db_addr_t loc)292 db_print_loc_and_inst(db_addr_t loc)
293 {
294 
295 	db_printsym(loc, DB_STGY_PROC, db_printf);
296 	db_printf(":\t");
297 	(void) db_disasm(loc, false);
298 }
299 
300 /*
301  * Search for a value in memory.
302  * Syntax: search [/bhl] addr value [mask] [,count]
303  */
304 /*ARGSUSED*/
305 void
db_search_cmd(db_expr_t daddr,bool have_addr,db_expr_t dcount,const char * modif)306 db_search_cmd(db_expr_t daddr, bool have_addr,
307     db_expr_t dcount, const char *modif)
308 {
309 	int		t;
310 	db_addr_t	addr;
311 	int		size;
312 	db_expr_t	value;
313 	db_expr_t	mask;
314 	db_expr_t	count;
315 
316 	t = db_read_token();
317 	if (t == tSLASH) {
318 		t = db_read_token();
319 		if (t != tIDENT) {
320 			bad_modifier:
321 			db_printf("Bad modifier\n");
322 			db_flush_lex();
323 			return;
324 		}
325 
326 		if (!strcmp(db_tok_string, "b"))
327 			size = 1;
328 		else if (!strcmp(db_tok_string, "h"))
329 			size = 2;
330 		else if (!strcmp(db_tok_string, "l"))
331 			size = 4;
332 		else
333 			goto bad_modifier;
334 	} else {
335 		db_unread_token(t);
336 		size = 4;
337 	}
338 
339 	if (!db_expression(&value)) {
340 		db_printf("Address missing\n");
341 		db_flush_lex();
342 		return;
343 	}
344 	addr = (db_addr_t) value;
345 
346 	if (!db_expression(&value)) {
347 		db_printf("Value missing\n");
348 		db_flush_lex();
349 		return;
350 	}
351 
352 	if (!db_expression(&mask))
353 		mask = (int) ~0;
354 
355 	t = db_read_token();
356 	if (t == tCOMMA) {
357 		if (!db_expression(&count)) {
358 			db_printf("Count missing\n");
359 			db_flush_lex();
360 			return;
361 		}
362 	} else {
363 		db_unread_token(t);
364 		count = -1;		/* effectively forever */
365 	}
366 	db_skip_to_eol();
367 
368 	db_search(addr, size, value, mask, count);
369 }
370 
371 static void
db_search(db_addr_t addr,int size,db_expr_t value,db_expr_t mask,unsigned int count)372 db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
373     unsigned int count)
374 {
375 	while (count-- != 0) {
376 		db_prev = addr;
377 		if ((db_get_value(addr, size, false) & mask) == value)
378 			break;
379 		addr += size;
380 	}
381 	db_next = addr;
382 }
383