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/*
27 *	Author: David B. Golub, Carnegie Mellon University
28 *	Date:	7/90
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/systm.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
45static char	db_examine_format[TOK_STRING_SIZE] = "x";
46
47static void	db_examine(db_addr_t, char *, int);
48static void	db_search(db_addr_t, int, db_expr_t, db_expr_t, u_int);
49
50/*
51 * Examine (print) data.
52 */
53/*ARGSUSED*/
54void
55db_examine_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
56    char *modif)
57{
58	if (modif[0] != '\0')
59	    db_strcpy(db_examine_format, modif);
60
61	if (count == -1)
62	    count = 1;
63
64	db_examine((db_addr_t) addr, db_examine_format, count);
65}
66
67static void
68db_examine(db_addr_t addr, char *fmt, int count)
69{
70	int		c;
71	db_expr_t	value;
72	int		size;
73	int		width;
74	char *		fp;
75
76	while (--count >= 0 && !db_pager_quit) {
77	    fp = fmt;
78	    size = 4;
79	    while ((c = *fp++) != 0) {
80		switch (c) {
81		    case 'b':
82			size = 1;
83			break;
84		    case 'h':
85			size = 2;
86			break;
87		    case 'l':
88			size = 4;
89			break;
90		    case 'g':
91			size = 8;
92			break;
93		    case 'a':	/* address */
94			size = sizeof(void *);
95			/* always forces a new line */
96			if (db_print_position() != 0)
97			    db_printf("\n");
98			db_prev = addr;
99			db_printsym(addr, DB_STGY_ANY);
100			db_printf(":\t");
101			break;
102		    default:
103			if (db_print_position() == 0) {
104			    /* Print the address. */
105			    db_printsym(addr, DB_STGY_ANY);
106			    db_printf(":\t");
107			    db_prev = addr;
108			}
109
110			width = size * 4;
111			switch (c) {
112			    case 'r':	/* signed, current radix */
113				value = db_get_value(addr, size, TRUE);
114				addr += size;
115				db_printf("%+-*lr", width, (long)value);
116				break;
117			    case 'x':	/* unsigned hex */
118				value = db_get_value(addr, size, FALSE);
119				addr += size;
120				db_printf("%-*lx", width, (long)value);
121				break;
122			    case 'z':	/* signed hex */
123				value = db_get_value(addr, size, TRUE);
124				addr += size;
125				db_printf("%-*ly", width, (long)value);
126				break;
127			    case 'd':	/* signed decimal */
128				value = db_get_value(addr, size, TRUE);
129				addr += size;
130				db_printf("%-*ld", width, (long)value);
131				break;
132			    case 'u':	/* unsigned decimal */
133				value = db_get_value(addr, size, FALSE);
134				addr += size;
135				db_printf("%-*lu", width, (long)value);
136				break;
137			    case 'o':	/* unsigned octal */
138				value = db_get_value(addr, size, FALSE);
139				addr += size;
140				db_printf("%-*lo", width, (long)value);
141				break;
142			    case 'c':	/* character */
143				value = db_get_value(addr, 1, FALSE);
144				addr += 1;
145				if (value >= ' ' && value <= '~')
146				    db_printf("%c", (int)value);
147				else
148				    db_printf("\\%03o", (int)value);
149				break;
150			    case 's':	/* null-terminated string */
151				for (;;) {
152				    value = db_get_value(addr, 1, FALSE);
153				    addr += 1;
154				    if (value == 0)
155					break;
156				    if (value >= ' ' && value <= '~')
157					db_printf("%c", (int)value);
158				    else
159					db_printf("\\%03o", (int)value);
160				}
161				break;
162			    case 'S':	/* symbol */
163				value = db_get_value(addr, sizeof(void *),
164				    FALSE);
165				addr += sizeof(void *);
166				db_printsym(value, DB_STGY_ANY);
167				break;
168			    case 'i':	/* instruction */
169				addr = db_disasm(addr, FALSE);
170				break;
171			    case 'I':	/* instruction, alternate form */
172				addr = db_disasm(addr, TRUE);
173				break;
174			    default:
175				break;
176			}
177			if (db_print_position() != 0)
178			    db_end_line(1);
179			break;
180		}
181	    }
182	}
183	db_next = addr;
184}
185
186/*
187 * Print value.
188 */
189static char	db_print_format = 'x';
190
191/*ARGSUSED*/
192void
193db_print_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
194    char *modif)
195{
196	db_expr_t	value;
197
198	if (modif[0] != '\0')
199	    db_print_format = modif[0];
200
201	switch (db_print_format) {
202	    case 'a':
203		db_printsym((db_addr_t)addr, DB_STGY_ANY);
204		break;
205	    case 'r':
206		db_printf("%+11lr", (long)addr);
207		break;
208	    case 'x':
209		db_printf("%8lx", (unsigned long)addr);
210		break;
211	    case 'z':
212		db_printf("%8ly", (long)addr);
213		break;
214	    case 'd':
215		db_printf("%11ld", (long)addr);
216		break;
217	    case 'u':
218		db_printf("%11lu", (unsigned long)addr);
219		break;
220	    case 'o':
221		db_printf("%16lo", (unsigned long)addr);
222		break;
223	    case 'c':
224		value = addr & 0xFF;
225		if (value >= ' ' && value <= '~')
226		    db_printf("%c", (int)value);
227		else
228		    db_printf("\\%03o", (int)value);
229		break;
230	}
231	db_printf("\n");
232}
233
234void
235db_print_loc_and_inst(db_addr_t loc)
236{
237	db_printsym(loc, DB_STGY_PROC);
238	db_printf(":\t");
239	(void) db_disasm(loc, TRUE);
240}
241
242/*
243 * Search for a value in memory.
244 * Syntax: search [/bhl] addr value [mask] [,count]
245 */
246void
247db_search_cmd(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3,
248    char *dummy4)
249{
250	int		t;
251	db_addr_t	addr;
252	int		size;
253	db_expr_t	value;
254	db_expr_t	mask;
255	db_expr_t	count;
256
257	t = db_read_token();
258	if (t == tSLASH) {
259	    t = db_read_token();
260	    if (t != tIDENT) {
261	      bad_modifier:
262		db_printf("Bad modifier\n");
263		db_flush_lex();
264		return;
265	    }
266
267	    if (!strcmp(db_tok_string, "b"))
268		size = 1;
269	    else if (!strcmp(db_tok_string, "h"))
270		size = 2;
271	    else if (!strcmp(db_tok_string, "l"))
272		size = 4;
273	    else
274		goto bad_modifier;
275	} else {
276	    db_unread_token(t);
277	    size = 4;
278	}
279
280	if (!db_expression((db_expr_t *)&addr)) {
281	    db_printf("Address missing\n");
282	    db_flush_lex();
283	    return;
284	}
285
286	if (!db_expression(&value)) {
287	    db_printf("Value missing\n");
288	    db_flush_lex();
289	    return;
290	}
291
292	if (!db_expression(&mask))
293	    mask = 0xffffffffUL;
294
295	t = db_read_token();
296	if (t == tCOMMA) {
297	    if (!db_expression(&count)) {
298		db_printf("Count missing\n");
299		db_flush_lex();
300		return;
301	    }
302	} else {
303	    db_unread_token(t);
304	    count = -1;		/* effectively forever */
305	}
306	db_skip_to_eol();
307
308	db_search(addr, size, value, mask, count);
309}
310
311static void
312db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
313    unsigned int count)
314{
315	while (count-- != 0) {
316		db_prev = addr;
317		if ((db_get_value(addr, size, FALSE) & mask) == value)
318			break;
319		addr += size;
320	}
321	db_next = addr;
322}
323