db_examine.c revision 2056
1/*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19 *  School of Computer Science
20 *  Carnegie Mellon University
21 *  Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 *
26 *	$Id: db_examine.c,v 1.4 1993/12/19 00:49:43 wollman Exp $
27 */
28
29/*
30 *	Author: David B. Golub, Carnegie Mellon University
31 *	Date:	7/90
32 */
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/proc.h>
36
37#include <ddb/ddb.h>
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
45char	db_examine_format[TOK_STRING_SIZE] = "x";
46
47extern	db_addr_t db_disasm(/* db_addr_t, boolean_t */);
48			/* instruction disassembler */
49
50static void db_examine(db_addr_t, char *, int);
51static void db_search(db_addr_t, int, db_expr_t, db_expr_t, u_int);
52
53/*
54 * Examine (print) data.
55 */
56/*ARGSUSED*/
57void
58db_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
73static void
74db_examine(addr, fmt, count)
75	register
76	db_addr_t	addr;
77	char *		fmt;	/* format string */
78	int		count;	/* repeat count */
79{
80	int		c;
81	db_expr_t	value;
82	int		size;
83	int		width;
84	char *		fp;
85
86	while (--count >= 0) {
87	    fp = fmt;
88	    size = 4;
89	    width = 16;
90	    while ((c = *fp++) != 0) {
91		switch (c) {
92		    case 'b':
93			size = 1;
94			width = 4;
95			break;
96		    case 'h':
97			size = 2;
98			width = 8;
99			break;
100		    case 'l':
101			size = 4;
102			width = 16;
103			break;
104		    case 'a':	/* address */
105			/* always forces a new line */
106			if (db_print_position() != 0)
107			    db_printf("\n");
108			db_prev = addr;
109			db_printsym(addr, DB_STGY_ANY);
110			db_printf(":\t");
111			break;
112		    default:
113			if (db_print_position() == 0) {
114			    /* If we hit a new symbol, print it */
115			    char *	name;
116			    db_expr_t	off;
117
118			    db_find_sym_and_offset(addr, &name, &off);
119			    if (off == 0)
120				db_printf("%s:\t", name);
121			    else
122				db_printf("\t\t");
123
124			    db_prev = addr;
125			}
126
127			switch (c) {
128			    case 'r':	/* signed, current radix */
129				value = db_get_value(addr, size, TRUE);
130				addr += size;
131				db_printf("%-*r", width, value);
132				break;
133			    case 'x':	/* unsigned hex */
134				value = db_get_value(addr, size, FALSE);
135				addr += size;
136				db_printf("%-*x", width, value);
137				break;
138			    case 'z':	/* signed hex */
139				value = db_get_value(addr, size, TRUE);
140				addr += size;
141				db_printf("%-*z", width, value);
142				break;
143			    case 'd':	/* signed decimal */
144				value = db_get_value(addr, size, TRUE);
145				addr += size;
146				db_printf("%-*d", width, value);
147				break;
148			    case 'u':	/* unsigned decimal */
149				value = db_get_value(addr, size, FALSE);
150				addr += size;
151				db_printf("%-*u", width, value);
152				break;
153			    case 'o':	/* unsigned octal */
154				value = db_get_value(addr, size, FALSE);
155				addr += size;
156				db_printf("%-*o", width, value);
157				break;
158			    case 'c':	/* character */
159				value = db_get_value(addr, 1, FALSE);
160				addr += 1;
161				if (value >= ' ' && value <= '~')
162				    db_printf("%c", value);
163				else
164				    db_printf("\\%03o", value);
165				break;
166			    case 's':	/* null-terminated string */
167				for (;;) {
168				    value = db_get_value(addr, 1, FALSE);
169				    addr += 1;
170				    if (value == 0)
171					break;
172				    if (value >= ' ' && value <= '~')
173					db_printf("%c", value);
174				    else
175					db_printf("\\%03o", value);
176				}
177				break;
178			    case 'i':	/* instruction */
179				addr = db_disasm(addr, FALSE);
180				break;
181			    case 'I':	/* instruction, alternate form */
182				addr = db_disasm(addr, TRUE);
183				break;
184			    default:
185				break;
186			}
187			if (db_print_position() != 0)
188			    db_end_line();
189			break;
190		}
191	    }
192	}
193	db_next = addr;
194}
195
196/*
197 * Print value.
198 */
199char	db_print_format = 'x';
200
201/*ARGSUSED*/
202void
203db_print_cmd(addr, have_addr, count, modif)
204	db_expr_t	addr;
205	int		have_addr;
206	db_expr_t	count;
207	char *		modif;
208{
209	db_expr_t	value;
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);
217		break;
218	    case 'r':
219		db_printf("%11r", addr);
220		break;
221	    case 'x':
222		db_printf("%8x", addr);
223		break;
224	    case 'z':
225		db_printf("%8z", addr);
226		break;
227	    case 'd':
228		db_printf("%11d", addr);
229		break;
230	    case 'u':
231		db_printf("%11u", addr);
232		break;
233	    case 'o':
234		db_printf("%16o", addr);
235		break;
236	    case 'c':
237		value = addr & 0xFF;
238		if (value >= ' ' && value <= '~')
239		    db_printf("%c", value);
240		else
241		    db_printf("\\%03o", value);
242		break;
243	}
244	db_printf("\n");
245}
246
247void
248db_print_loc_and_inst(loc)
249	db_addr_t	loc;
250{
251	db_printsym(loc, DB_STGY_PROC);
252	db_printf(":\t");
253	(void) db_disasm(loc, TRUE);
254}
255
256/*
257 * Search for a value in memory.
258 * Syntax: search [/bhl] addr value [mask] [,count]
259 */
260void
261db_search_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4)
262{
263	int		t;
264	db_addr_t	addr;
265	int		size;
266	db_expr_t	value;
267	db_expr_t	mask;
268	unsigned int	count;
269
270	t = db_read_token();
271	if (t == tSLASH) {
272	    t = db_read_token();
273	    if (t != tIDENT) {
274	      bad_modifier:
275		db_printf("Bad modifier\n");
276		db_flush_lex();
277		return;
278	    }
279
280	    if (!strcmp(db_tok_string, "b"))
281		size = 1;
282	    else if (!strcmp(db_tok_string, "h"))
283		size = 2;
284	    else if (!strcmp(db_tok_string, "l"))
285		size = 4;
286	    else
287		goto bad_modifier;
288	} else {
289	    db_unread_token(t);
290	    size = 4;
291	}
292
293	if (!db_expression((db_expr_t *)&addr)) {
294	    db_printf("Address missing\n");
295	    db_flush_lex();
296	    return;
297	}
298
299	if (!db_expression(&value)) {
300	    db_printf("Value missing\n");
301	    db_flush_lex();
302	    return;
303	}
304
305	if (!db_expression(&mask))
306	    mask = 0xffffffffUL;
307
308	t = db_read_token();
309	if (t == tCOMMA) {
310	    if (!db_expression(&count)) {
311		db_printf("Count missing\n");
312		db_flush_lex();
313		return;
314	    }
315	} else {
316	    db_unread_token(t);
317	    count = -1;		/* effectively forever */
318	}
319	db_skip_to_eol();
320
321	db_search(addr, size, value, mask, count);
322}
323
324static void
325db_search(addr, size, value, mask, count)
326	register
327	db_addr_t	addr;
328	int		size;
329	db_expr_t	value;
330	db_expr_t	mask;
331	unsigned int	count;
332{
333	while (count-- != 0) {
334		db_prev = addr;
335		if ((db_get_value(addr, size, FALSE) & mask) == value)
336			break;
337		addr += size;
338	}
339	db_next = addr;
340}
341