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@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