xref: /netbsd-src/sys/ddb/db_examine.c (revision 6e5e6fa95872363f0872a6cfb805e8df2d1dfc30)
1*6e5e6fa9Sryo /*	$NetBSD: db_examine.c,v 1.40 2019/09/12 09:20:23 ryo Exp $	*/
2cf92afd6Scgd 
361f28255Scgd /*
461f28255Scgd  * Mach Operating System
561f28255Scgd  * Copyright (c) 1991,1990 Carnegie Mellon University
661f28255Scgd  * All Rights Reserved.
761f28255Scgd  *
861f28255Scgd  * Permission to use, copy, modify and distribute this software and its
961f28255Scgd  * documentation is hereby granted, provided that both the copyright
1061f28255Scgd  * notice and this permission notice appear in all copies of the
1161f28255Scgd  * software, derivative works or modified versions, and any portions
1261f28255Scgd  * thereof, and that both notices appear in supporting documentation.
1361f28255Scgd  *
14b13e5d14Spk  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1561f28255Scgd  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1661f28255Scgd  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1761f28255Scgd  *
1861f28255Scgd  * Carnegie Mellon requests users of this software to return to
1961f28255Scgd  *
2061f28255Scgd  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
2161f28255Scgd  *  School of Computer Science
2261f28255Scgd  *  Carnegie Mellon University
2361f28255Scgd  *  Pittsburgh PA 15213-3890
2461f28255Scgd  *
2561f28255Scgd  * any improvements or extensions that they make and grant Carnegie the
2661f28255Scgd  * rights to redistribute these changes.
2737cabe30Scgd  *
2861f28255Scgd  *	Author: David B. Golub, Carnegie Mellon University
2961f28255Scgd  *	Date:	7/90
3061f28255Scgd  */
31f1a5c330Smycroft 
321ac69d9cSlukem #include <sys/cdefs.h>
33*6e5e6fa9Sryo __KERNEL_RCSID(0, "$NetBSD: db_examine.c,v 1.40 2019/09/12 09:20:23 ryo Exp $");
341ac69d9cSlukem 
35f1a5c330Smycroft #include <sys/param.h>
36e4eb4c6cScgd #include <sys/systm.h>
37010ce493Spooka #include <sys/buf.h>
38f1a5c330Smycroft #include <sys/proc.h>
39f1a5c330Smycroft 
40cd6b1c8fSad #include <ddb/ddb.h>
4161f28255Scgd 
424eaa4d66Ssimonb static char	db_examine_format[TOK_STRING_SIZE] = "x";
434eaa4d66Ssimonb 
444eaa4d66Ssimonb static void	db_examine(db_addr_t, char *, int);
454eaa4d66Ssimonb static void	db_search(db_addr_t, int, db_expr_t, db_expr_t, unsigned int);
4661f28255Scgd 
4761f28255Scgd /*
483e676d42Sgwr  * Examine (print) data.  Syntax is:
493e676d42Sgwr  *		x/[bhl][cdiorsuxz]*
503e676d42Sgwr  * For example, the command:
513e676d42Sgwr  *  	x/bxxxx
523e676d42Sgwr  * should print:
533e676d42Sgwr  *  	address:  01  23  45  67
5461f28255Scgd  */
5561f28255Scgd /*ARGSUSED*/
5661f28255Scgd void
db_examine_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)5793feeb12Smatt db_examine_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
584d595fd7Schristos     const char *modif)
5961f28255Scgd {
6061f28255Scgd 	if (modif[0] != '\0')
61f9121aadSitojun 		strlcpy(db_examine_format, modif, sizeof(db_examine_format));
6261f28255Scgd 
6361f28255Scgd 	if (count == -1)
6461f28255Scgd 		count = 1;
6561f28255Scgd 
6661f28255Scgd 	db_examine((db_addr_t) addr, db_examine_format, count);
6761f28255Scgd }
6861f28255Scgd 
694eaa4d66Ssimonb static void
db_examine(db_addr_t addr,char * fmt,int count)704eaa4d66Ssimonb db_examine(db_addr_t addr, char *fmt, int count)
7161f28255Scgd {
725649071cSjmc 	int		i, c;
73*6e5e6fa9Sryo 	quad_t		value;
7461f28255Scgd 	int		size;
7561f28255Scgd 	int		width;
765649071cSjmc 	int		bytes;
7761f28255Scgd 	char *		fp;
78242cedc1Stv 	char		tbuf[24];
7961f28255Scgd 
8061f28255Scgd 	while (--count >= 0) {
8161f28255Scgd 		fp = fmt;
8261f28255Scgd 		size = 4;
8321a1e8e7Sgwr 		width = 12;
8461f28255Scgd 		while ((c = *fp++) != 0) {
85df82cd38Sgwr 			if (db_print_position() == 0) {
86df82cd38Sgwr 				/* Always print the address. */
87f3528d72Sjhawk 				db_printsym(addr, DB_STGY_ANY, db_printf);
88df82cd38Sgwr 				db_printf(":\t");
89df82cd38Sgwr 				db_prev = addr;
90df82cd38Sgwr 			}
9161f28255Scgd 			switch (c) {
92df82cd38Sgwr 			case 'b':	/* byte */
9361f28255Scgd 				size = 1;
9461f28255Scgd 				width = 4;
9561f28255Scgd 				break;
96df82cd38Sgwr 			case 'h':	/* half-word */
9761f28255Scgd 				size = 2;
9861f28255Scgd 				width = 8;
9961f28255Scgd 				break;
100df82cd38Sgwr 			case 'l':	/* long-word */
10161f28255Scgd 				size = 4;
10221a1e8e7Sgwr 				width = 12;
10361f28255Scgd 				break;
10477e643c7Sryo 			case 'q':	/* quad-word */
10577e643c7Sryo 				size = 8;
106*6e5e6fa9Sryo 				width = 24;
10777e643c7Sryo 				break;
10866ffb4e4Sross 			case 'L':	/* implementation maximum */
10966ffb4e4Sross 				size = sizeof value;
11066ffb4e4Sross 				width = 12 * (sizeof value / 4);
11166ffb4e4Sross 				break;
11261f28255Scgd 			case 'a':	/* address */
113c55851c8Sscw 				db_printf("= 0x%lx\n", (long)addr);
11461f28255Scgd 				break;
11531e239d6Sryo 			case 'p':
11631e239d6Sryo 				size = sizeof(void *);
117*6e5e6fa9Sryo 				value = db_get_value(addr, size, false);
11831e239d6Sryo 				addr += size;
11931e239d6Sryo 				db_printf("= 0x%lx ", (long)value);
12031e239d6Sryo 				db_printsym((db_addr_t)value, DB_STGY_ANY, db_printf);
12131e239d6Sryo 				db_printf("\n");
12231e239d6Sryo 				break;
12361f28255Scgd 			case 'r':	/* signed, current radix */
124*6e5e6fa9Sryo 				value = db_get_qvalue(addr, size, true);
12561f28255Scgd 				addr += size;
1264f3d5a9cSthorpej 				db_format_radix(tbuf, 24, value, false);
127242cedc1Stv 				db_printf("%-*s", width, tbuf);
12861f28255Scgd 				break;
12961f28255Scgd 			case 'x':	/* unsigned hex */
130*6e5e6fa9Sryo 				value = db_get_qvalue(addr, size, false);
13161f28255Scgd 				addr += size;
132*6e5e6fa9Sryo 				db_printf("%-*" PRIx64, width, value);
13361f28255Scgd 				break;
1345649071cSjmc 			case 'm':	/* hex dump */
1355649071cSjmc 				/*
1365649071cSjmc 				 * Print off in chunks of size. Try to print 16
137*6e5e6fa9Sryo 				 * bytes at a time into 16/size columns. This
1385649071cSjmc 				 * loops modify's count extra times in order
1395649071cSjmc 				 * to get the nicely formatted lines.
1405649071cSjmc 				 */
1415649071cSjmc 
1425649071cSjmc 				bytes = 0;
1435649071cSjmc 				do {
1445649071cSjmc 					for (i = 0; i < size; i++) {
1455649071cSjmc 						value =
14677e643c7Sryo #if BYTE_ORDER == LITTLE_ENDIAN
14777e643c7Sryo 						    db_get_value(addr +
14877e643c7Sryo 						    (bytes & ~(size - 1)) +
14977e643c7Sryo 						    size - i - 1, 1, false);
15077e643c7Sryo #else
15177e643c7Sryo 						    db_get_value(addr + bytes,
15277e643c7Sryo 						    1, false);
15377e643c7Sryo #endif
15466cf68c4Sscw 						db_printf(
155*6e5e6fa9Sryo 						    "%02" PRIx64,
156a2bf8e5dSjoerg 						    value);
1575649071cSjmc 						bytes++;
15877e643c7Sryo 						if (!(bytes % size))
1595649071cSjmc 							db_printf(" ");
1605649071cSjmc 					}
1615649071cSjmc 				} while ((bytes != 16) && count--);
1625649071cSjmc 				/* True up the columns before continuing */
1635649071cSjmc 				for (i = 4; i >= (bytes / 4); i--)
1645649071cSjmc 					db_printf ("\t");
1655649071cSjmc 				/* Print chars,  use . for non-printable's. */
1665649071cSjmc 				while (bytes--) {
1674f3d5a9cSthorpej 					value = db_get_value(addr, 1, false);
1685649071cSjmc 					addr += 1;
1695649071cSjmc 					if (value >= ' ' && value <= '~')
1705649071cSjmc 						db_printf("%c", (char)value);
1715649071cSjmc 					else
1725649071cSjmc 						db_printf(".");
1735649071cSjmc 				}
1745649071cSjmc 				db_printf("\n");
1755649071cSjmc 				break;
17661f28255Scgd 			case 'z':	/* signed hex */
177*6e5e6fa9Sryo 				value = db_get_qvalue(addr, size, true);
17861f28255Scgd 				addr += size;
1794f3d5a9cSthorpej 				db_format_hex(tbuf, 24, value, false);
180242cedc1Stv 				db_printf("%-*s", width, tbuf);
18161f28255Scgd 				break;
18261f28255Scgd 			case 'd':	/* signed decimal */
183*6e5e6fa9Sryo 				value = db_get_qvalue(addr, size, true);
18461f28255Scgd 				addr += size;
185*6e5e6fa9Sryo 				db_printf("%-*" PRId64, width, value);
18661f28255Scgd 				break;
18761f28255Scgd 			case 'u':	/* unsigned decimal */
188*6e5e6fa9Sryo 				value = db_get_qvalue(addr, size, false);
18961f28255Scgd 				addr += size;
190*6e5e6fa9Sryo 				db_printf("%-*" PRIu64, width, value);
19161f28255Scgd 				break;
19261f28255Scgd 			case 'o':	/* unsigned octal */
193*6e5e6fa9Sryo 				value = db_get_qvalue(addr, size, false);
19461f28255Scgd 				addr += size;
195*6e5e6fa9Sryo 				db_printf("%-*" PRIo64, width, value);
19661f28255Scgd 				break;
19761f28255Scgd 			case 'c':	/* character */
1984f3d5a9cSthorpej 				value = db_get_value(addr, 1, false);
19961f28255Scgd 				addr += 1;
20061f28255Scgd 				if (value >= ' ' && value <= '~')
20112da023cSmycroft 					db_printf("%c", (char)value);
20261f28255Scgd 				else
20366cf68c4Sscw 					db_printf("\\%03o", (int)value);
20461f28255Scgd 				break;
20561f28255Scgd 			case 's':	/* null-terminated string */
20661f28255Scgd 				for (;;) {
2074f3d5a9cSthorpej 					value = db_get_value(addr, 1, false);
20861f28255Scgd 					addr += 1;
20961f28255Scgd 					if (value == 0)
21061f28255Scgd 						break;
21161f28255Scgd 					if (value >= ' ' && value <= '~')
21212da023cSmycroft 						db_printf("%c", (char)value);
21361f28255Scgd 					else
21466cf68c4Sscw 						db_printf("\\%03o", (int)value);
21561f28255Scgd 				}
21661f28255Scgd 				break;
21761f28255Scgd 			case 'i':	/* instruction */
2184f3d5a9cSthorpej 				addr = db_disasm(addr, false);
21961f28255Scgd 				break;
22061f28255Scgd 			case 'I':	/* instruction, alternate form */
2214f3d5a9cSthorpej 				addr = db_disasm(addr, true);
22261f28255Scgd 				break;
22361f28255Scgd 			default:
22461f28255Scgd 				break;
22561f28255Scgd 			}
22661f28255Scgd 			if (db_print_position() != 0)
22761f28255Scgd 				db_end_line();
22861f28255Scgd 		}
22961f28255Scgd 	}
23061f28255Scgd 	db_next = addr;
23161f28255Scgd }
23261f28255Scgd 
23361f28255Scgd /*
23461f28255Scgd  * Print value.
23561f28255Scgd  */
2364eaa4d66Ssimonb static char	db_print_format = 'x';
23761f28255Scgd 
23861f28255Scgd /*ARGSUSED*/
23961f28255Scgd void
db_print_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)24093feeb12Smatt db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
2414d595fd7Schristos     const char *modif)
24261f28255Scgd {
24361f28255Scgd 	db_expr_t	value;
24461f28255Scgd 
24561f28255Scgd 	if (modif[0] != '\0')
24661f28255Scgd 		db_print_format = modif[0];
24761f28255Scgd 
24861f28255Scgd 	switch (db_print_format) {
24961f28255Scgd 	case 'a':
250f3528d72Sjhawk 		db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
25161f28255Scgd 		break;
25261f28255Scgd 	case 'r':
253242cedc1Stv 		{
254242cedc1Stv 			char tbuf[24];
255242cedc1Stv 
2564f3d5a9cSthorpej 			db_format_radix(tbuf, 24, addr, false);
257242cedc1Stv 			db_printf("%11s", tbuf);
25861f28255Scgd 			break;
259242cedc1Stv 		}
26061f28255Scgd 	case 'x':
261a2bf8e5dSjoerg 		db_printf("%16" DDB_EXPR_FMT "x", addr);
26261f28255Scgd 		break;
26361f28255Scgd 	case 'z':
264242cedc1Stv 		{
265242cedc1Stv 			char tbuf[24];
266242cedc1Stv 
2674f3d5a9cSthorpej 			db_format_hex(tbuf, 24, addr, false);
268242cedc1Stv 			db_printf("%8s", tbuf);
26961f28255Scgd 			break;
270242cedc1Stv 		}
27161f28255Scgd 	case 'd':
272a2bf8e5dSjoerg 		db_printf("%11" DDB_EXPR_FMT "d", addr);
27361f28255Scgd 		break;
27461f28255Scgd 	case 'u':
275a2bf8e5dSjoerg 		db_printf("%11" DDB_EXPR_FMT "u", addr);
27661f28255Scgd 		break;
27761f28255Scgd 	case 'o':
278a2bf8e5dSjoerg 		db_printf("%15" DDB_EXPR_FMT "o", addr);
27961f28255Scgd 		break;
28061f28255Scgd 	case 'c':
28161f28255Scgd 		value = addr & 0xFF;
28261f28255Scgd 		if (value >= ' ' && value <= '~')
28312da023cSmycroft 			db_printf("%c", (char)value);
28461f28255Scgd 		else
28566cf68c4Sscw 			db_printf("\\%03o", (int)value);
28661f28255Scgd 		break;
28761f28255Scgd 	}
28861f28255Scgd 	db_printf("\n");
28961f28255Scgd }
29061f28255Scgd 
2918c2e3b4bSchristos void
db_print_loc_and_inst(db_addr_t loc)2924eaa4d66Ssimonb db_print_loc_and_inst(db_addr_t loc)
29361f28255Scgd {
2944eaa4d66Ssimonb 
295f3528d72Sjhawk 	db_printsym(loc, DB_STGY_PROC, db_printf);
29661f28255Scgd 	db_printf(":\t");
2974f3d5a9cSthorpej 	(void) db_disasm(loc, false);
29861f28255Scgd }
29961f28255Scgd 
30061f28255Scgd /*
30161f28255Scgd  * Search for a value in memory.
30261f28255Scgd  * Syntax: search [/bhl] addr value [mask] [,count]
30361f28255Scgd  */
3048c2e3b4bSchristos /*ARGSUSED*/
30561f28255Scgd void
db_search_cmd(db_expr_t daddr,bool have_addr,db_expr_t dcount,const char * modif)30693feeb12Smatt db_search_cmd(db_expr_t daddr, bool have_addr,
307168cd830Schristos     db_expr_t dcount, const char *modif)
30861f28255Scgd {
30961f28255Scgd 	int		t;
31061f28255Scgd 	db_addr_t	addr;
31161f28255Scgd 	int		size;
31261f28255Scgd 	db_expr_t	value;
31361f28255Scgd 	db_expr_t	mask;
31465a65d45Scgd 	db_expr_t	count;
31561f28255Scgd 
31661f28255Scgd 	t = db_read_token();
31761f28255Scgd 	if (t == tSLASH) {
31861f28255Scgd 		t = db_read_token();
31961f28255Scgd 		if (t != tIDENT) {
32061f28255Scgd 			bad_modifier:
32161f28255Scgd 			db_printf("Bad modifier\n");
32261f28255Scgd 			db_flush_lex();
32361f28255Scgd 			return;
32461f28255Scgd 		}
32561f28255Scgd 
32661f28255Scgd 		if (!strcmp(db_tok_string, "b"))
32761f28255Scgd 			size = 1;
32861f28255Scgd 		else if (!strcmp(db_tok_string, "h"))
32961f28255Scgd 			size = 2;
33061f28255Scgd 		else if (!strcmp(db_tok_string, "l"))
33161f28255Scgd 			size = 4;
33261f28255Scgd 		else
33361f28255Scgd 			goto bad_modifier;
33461f28255Scgd 	} else {
33561f28255Scgd 		db_unread_token(t);
33661f28255Scgd 		size = 4;
33761f28255Scgd 	}
33861f28255Scgd 
3398c2e3b4bSchristos 	if (!db_expression(&value)) {
34061f28255Scgd 		db_printf("Address missing\n");
34161f28255Scgd 		db_flush_lex();
34261f28255Scgd 		return;
34361f28255Scgd 	}
3448c2e3b4bSchristos 	addr = (db_addr_t) value;
34561f28255Scgd 
34661f28255Scgd 	if (!db_expression(&value)) {
34761f28255Scgd 		db_printf("Value missing\n");
34861f28255Scgd 		db_flush_lex();
34961f28255Scgd 		return;
35061f28255Scgd 	}
35161f28255Scgd 
35261f28255Scgd 	if (!db_expression(&mask))
3538c2e3b4bSchristos 		mask = (int) ~0;
35461f28255Scgd 
35561f28255Scgd 	t = db_read_token();
35661f28255Scgd 	if (t == tCOMMA) {
35761f28255Scgd 		if (!db_expression(&count)) {
35861f28255Scgd 			db_printf("Count missing\n");
35961f28255Scgd 			db_flush_lex();
36061f28255Scgd 			return;
36161f28255Scgd 		}
36261f28255Scgd 	} else {
36361f28255Scgd 		db_unread_token(t);
36461f28255Scgd 		count = -1;		/* effectively forever */
36561f28255Scgd 	}
36661f28255Scgd 	db_skip_to_eol();
36761f28255Scgd 
36861f28255Scgd 	db_search(addr, size, value, mask, count);
36961f28255Scgd }
37061f28255Scgd 
3714eaa4d66Ssimonb static void
db_search(db_addr_t addr,int size,db_expr_t value,db_expr_t mask,unsigned int count)3724eaa4d66Ssimonb db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
3734eaa4d66Ssimonb     unsigned int count)
37461f28255Scgd {
37561f28255Scgd 	while (count-- != 0) {
37661f28255Scgd 		db_prev = addr;
3774f3d5a9cSthorpej 		if ((db_get_value(addr, size, false) & mask) == value)
37861f28255Scgd 			break;
37961f28255Scgd 		addr += size;
38061f28255Scgd 	}
38161f28255Scgd 	db_next = addr;
38261f28255Scgd }
383