Home | History | Annotate | Line # | Download | only in ddb
db_examine.c revision 1.33
      1 /*	$NetBSD: db_examine.c,v 1.33 2008/11/16 19:34:29 pooka 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 (at) 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.33 2008/11/16 19:34:29 pooka 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 <machine/db_machdep.h>		/* type definitions */
     41 
     42 #include <ddb/db_lex.h>
     43 #include <ddb/db_output.h>
     44 #include <ddb/db_command.h>
     45 #include <ddb/db_sym.h>
     46 #include <ddb/db_access.h>
     47 #include <ddb/db_extern.h>
     48 #include <ddb/db_interface.h>
     49 
     50 static char	db_examine_format[TOK_STRING_SIZE] = "x";
     51 
     52 static void	db_examine(db_addr_t, char *, int);
     53 static void	db_search(db_addr_t, int, db_expr_t, db_expr_t, unsigned int);
     54 
     55 /*
     56  * Examine (print) data.  Syntax is:
     57  *		x/[bhl][cdiorsuxz]*
     58  * For example, the command:
     59  *  	x/bxxxx
     60  * should print:
     61  *  	address:  01  23  45  67
     62  */
     63 /*ARGSUSED*/
     64 void
     65 db_examine_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
     66     const char *modif)
     67 {
     68 	if (modif[0] != '\0')
     69 		strlcpy(db_examine_format, modif, sizeof(db_examine_format));
     70 
     71 	if (count == -1)
     72 		count = 1;
     73 
     74 	db_examine((db_addr_t) addr, db_examine_format, count);
     75 }
     76 
     77 static void
     78 db_examine(db_addr_t addr, char *fmt, int count)
     79 {
     80 	int		i, c;
     81 	db_expr_t	value;
     82 	int		size;
     83 	int		width;
     84 	int		bytes;
     85 	char *		fp;
     86 	char		tbuf[24];
     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 'L':	/* implementation maximum */
    113 				size = sizeof value;
    114 				width = 12 * (sizeof value / 4);
    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_format_radix(tbuf, 24, value, false);
    123 				db_printf("%-*s", width, tbuf);
    124 				break;
    125 			case 'x':	/* unsigned hex */
    126 				value = db_get_value(addr, size, false);
    127 				addr += size;
    128 				db_printf(DB_EXPR_T_IS_QUAD ? "%-*qx" : "%-*lx",
    129 				    width, value);
    130 				break;
    131 			case 'm':	/* hex dump */
    132 				/*
    133 				 * Print off in chunks of size. Try to print 16
    134 				 * bytes at a time into 4 columns. This
    135 				 * loops modify's count extra times in order
    136 				 * to get the nicely formatted lines.
    137 				 */
    138 
    139 				bytes = 0;
    140 				do {
    141 					for (i = 0; i < size; i++) {
    142 						value =
    143  						    db_get_value(addr+bytes, 1,
    144 							false);
    145 						db_printf(
    146 						    DB_EXPR_T_IS_QUAD ? "%02qx":
    147 						    "%02lx", value);
    148 						bytes++;
    149 						if (!(bytes % 4))
    150 							db_printf(" ");
    151 					}
    152 				} while ((bytes != 16) && count--);
    153 				/* True up the columns before continuing */
    154 				for (i = 4; i >= (bytes / 4); i--)
    155 					db_printf ("\t");
    156 				/* Print chars,  use . for non-printable's. */
    157 				while (bytes--) {
    158 					value = db_get_value(addr, 1, false);
    159 					addr += 1;
    160 					if (value >= ' ' && value <= '~')
    161 						db_printf("%c", (char)value);
    162 					else
    163 						db_printf(".");
    164 				}
    165 				db_printf("\n");
    166 				break;
    167 			case 'z':	/* signed hex */
    168 				value = db_get_value(addr, size, true);
    169 				addr += size;
    170 				db_format_hex(tbuf, 24, value, false);
    171 				db_printf("%-*s", width, tbuf);
    172 				break;
    173 			case 'd':	/* signed decimal */
    174 				value = db_get_value(addr, size, true);
    175 				addr += size;
    176 				db_printf(DB_EXPR_T_IS_QUAD ? "%-*qd" : "%-*ld",
    177 				    width, value);
    178 				break;
    179 			case 'u':	/* unsigned decimal */
    180 				value = db_get_value(addr, size, false);
    181 				addr += size;
    182 				db_printf(DB_EXPR_T_IS_QUAD ? "%-*qu" : "%-*lu",
    183 				    width, value);
    184 				break;
    185 			case 'o':	/* unsigned octal */
    186 				value = db_get_value(addr, size, false);
    187 				addr += size;
    188 				db_printf(DB_EXPR_T_IS_QUAD ? "%-*qo" : "%-*lo",
    189 				    width, value);
    190 				break;
    191 			case 'c':	/* character */
    192 				value = db_get_value(addr, 1, false);
    193 				addr += 1;
    194 				if (value >= ' ' && value <= '~')
    195 					db_printf("%c", (char)value);
    196 				else
    197 					db_printf("\\%03o", (int)value);
    198 				break;
    199 			case 's':	/* null-terminated string */
    200 				for (;;) {
    201 					value = db_get_value(addr, 1, false);
    202 					addr += 1;
    203 					if (value == 0)
    204 						break;
    205 					if (value >= ' ' && value <= '~')
    206 						db_printf("%c", (char)value);
    207 					else
    208 						db_printf("\\%03o", (int)value);
    209 				}
    210 				break;
    211 			case 'i':	/* instruction */
    212 				addr = db_disasm(addr, false);
    213 				break;
    214 			case 'I':	/* instruction, alternate form */
    215 				addr = db_disasm(addr, true);
    216 				break;
    217 			default:
    218 				break;
    219 			}
    220 			if (db_print_position() != 0)
    221 				db_end_line();
    222 		}
    223 	}
    224 	db_next = addr;
    225 }
    226 
    227 /*
    228  * Print value.
    229  */
    230 static char	db_print_format = 'x';
    231 
    232 /*ARGSUSED*/
    233 void
    234 db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
    235     const char *modif)
    236 {
    237 	db_expr_t	value;
    238 
    239 	if (modif[0] != '\0')
    240 		db_print_format = modif[0];
    241 
    242 	switch (db_print_format) {
    243 	case 'a':
    244 		db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
    245 		break;
    246 	case 'r':
    247 		{
    248 			char tbuf[24];
    249 
    250 			db_format_radix(tbuf, 24, addr, false);
    251 			db_printf("%11s", tbuf);
    252 			break;
    253 		}
    254 	case 'x':
    255 		db_printf(DB_EXPR_T_IS_QUAD ? "%16qx" : "%8lx", addr);
    256 		break;
    257 	case 'z':
    258 		{
    259 			char tbuf[24];
    260 
    261 			db_format_hex(tbuf, 24, addr, false);
    262 			db_printf("%8s", tbuf);
    263 			break;
    264 		}
    265 	case 'd':
    266 		db_printf(DB_EXPR_T_IS_QUAD ? "%11qd" : "%11ld", addr);
    267 		break;
    268 	case 'u':
    269 		db_printf(DB_EXPR_T_IS_QUAD ? "%11qu" : "%11lu", addr);
    270 		break;
    271 	case 'o':
    272 		db_printf(DB_EXPR_T_IS_QUAD ? "%15qo" : "%16lo", addr);
    273 		break;
    274 	case 'c':
    275 		value = addr & 0xFF;
    276 		if (value >= ' ' && value <= '~')
    277 			db_printf("%c", (char)value);
    278 		else
    279 			db_printf("\\%03o", (int)value);
    280 		break;
    281 	}
    282 	db_printf("\n");
    283 }
    284 
    285 void
    286 db_print_loc_and_inst(db_addr_t loc)
    287 {
    288 
    289 	db_printsym(loc, DB_STGY_PROC, db_printf);
    290 	db_printf(":\t");
    291 	(void) db_disasm(loc, false);
    292 }
    293 
    294 /*
    295  * Search for a value in memory.
    296  * Syntax: search [/bhl] addr value [mask] [,count]
    297  */
    298 /*ARGSUSED*/
    299 void
    300 db_search_cmd(db_expr_t daddr, bool have_addr,
    301     db_expr_t dcount, const char *modif)
    302 {
    303 	int		t;
    304 	db_addr_t	addr;
    305 	int		size;
    306 	db_expr_t	value;
    307 	db_expr_t	mask;
    308 	db_expr_t	count;
    309 
    310 	t = db_read_token();
    311 	if (t == tSLASH) {
    312 		t = db_read_token();
    313 		if (t != tIDENT) {
    314 			bad_modifier:
    315 			db_printf("Bad modifier\n");
    316 			db_flush_lex();
    317 			return;
    318 		}
    319 
    320 		if (!strcmp(db_tok_string, "b"))
    321 			size = 1;
    322 		else if (!strcmp(db_tok_string, "h"))
    323 			size = 2;
    324 		else if (!strcmp(db_tok_string, "l"))
    325 			size = 4;
    326 		else
    327 			goto bad_modifier;
    328 	} else {
    329 		db_unread_token(t);
    330 		size = 4;
    331 	}
    332 
    333 	if (!db_expression(&value)) {
    334 		db_printf("Address missing\n");
    335 		db_flush_lex();
    336 		return;
    337 	}
    338 	addr = (db_addr_t) value;
    339 
    340 	if (!db_expression(&value)) {
    341 		db_printf("Value missing\n");
    342 		db_flush_lex();
    343 		return;
    344 	}
    345 
    346 	if (!db_expression(&mask))
    347 		mask = (int) ~0;
    348 
    349 	t = db_read_token();
    350 	if (t == tCOMMA) {
    351 		if (!db_expression(&count)) {
    352 			db_printf("Count missing\n");
    353 			db_flush_lex();
    354 			return;
    355 		}
    356 	} else {
    357 		db_unread_token(t);
    358 		count = -1;		/* effectively forever */
    359 	}
    360 	db_skip_to_eol();
    361 
    362 	db_search(addr, size, value, mask, count);
    363 }
    364 
    365 static void
    366 db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
    367     unsigned int count)
    368 {
    369 	while (count-- != 0) {
    370 		db_prev = addr;
    371 		if ((db_get_value(addr, size, false) & mask) == value)
    372 			break;
    373 		addr += size;
    374 	}
    375 	db_next = addr;
    376 }
    377