1 /* $OpenBSD: db_examine.c,v 1.23 2016/10/18 19:46:00 naddy Exp $ */ 2 /* $NetBSD: db_examine.c,v 1.11 1996/03/30 22:30:07 christos Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie Mellon 27 * the rights to redistribute these changes. 28 * 29 * Author: David B. Golub, Carnegie Mellon University 30 * Date: 7/90 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 36 #include <machine/db_machdep.h> /* type definitions */ 37 38 #include <ddb/db_lex.h> 39 #include <ddb/db_output.h> 40 #include <ddb/db_command.h> 41 #include <ddb/db_sym.h> 42 #include <ddb/db_access.h> 43 #include <ddb/db_extern.h> 44 #include <ddb/db_interface.h> 45 46 char db_examine_format[TOK_STRING_SIZE] = "x"; 47 48 void db_examine(db_addr_t, char *, int); 49 void db_search(db_addr_t, int, db_expr_t, db_expr_t, db_expr_t); 50 51 /* 52 * Examine (print) data. Syntax is: 53 * x/[bhlq][cdiorsuxz]* 54 * For example, the command: 55 * x/bxxxx 56 * should print: 57 * address: 01 23 45 67 58 */ 59 /*ARGSUSED*/ 60 void 61 db_examine_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 62 { 63 if (modif[0] != '\0') 64 db_strlcpy(db_examine_format, modif, sizeof(db_examine_format)); 65 66 if (count == -1) 67 count = 1; 68 69 db_examine((db_addr_t)addr, db_examine_format, count); 70 } 71 72 void 73 db_examine(db_addr_t addr, char *fmt, int count) 74 { 75 int i, c; 76 db_expr_t value; 77 int size; 78 int width; 79 int bytes; 80 char * fp; 81 db_addr_t incr; 82 int dis; 83 char tmpfmt[28]; 84 85 while (--count >= 0) { 86 fp = fmt; 87 88 /* defaults */ 89 size = 4; 90 width = 12; 91 incr = 0; 92 dis = 0; 93 94 while ((c = *fp++) != 0) { 95 if (db_print_position() == 0) { 96 /* Always print the address. */ 97 db_printsym(addr, DB_STGY_ANY, db_printf); 98 db_printf(":\t"); 99 db_prev = addr; 100 } 101 incr = size; 102 switch (c) { 103 case 'b': /* byte */ 104 size = 1; 105 width = 4; 106 break; 107 case 'h': /* half-word */ 108 size = 2; 109 width = 8; 110 break; 111 case 'l': /* long-word */ 112 size = 4; 113 width = 12; 114 break; 115 #ifdef __LP64__ 116 case 'q': /* quad-word */ 117 size = 8; 118 width = 20; 119 break; 120 #endif 121 case 'a': /* address */ 122 db_printf("= 0x%lx\n", (long)addr); 123 incr = 0; 124 break; 125 case 'r': /* signed, current radix */ 126 value = db_get_value(addr, size, TRUE); 127 db_format(tmpfmt, sizeof tmpfmt, 128 (long)value, DB_FORMAT_R, 0, width); 129 db_printf("%-*s", width, tmpfmt); 130 break; 131 case 'x': /* unsigned hex */ 132 value = db_get_value(addr, size, FALSE); 133 db_printf("%-*lx", width, (long)value); 134 break; 135 case 'm': /* hex dump */ 136 /* 137 * Print off in chunks of size. Try to print 16 138 * bytes at a time into 4 columns. This 139 * loops modify's count extra times in order 140 * to get the nicely formatted lines. 141 */ 142 incr = 0; 143 bytes = 0; 144 do { 145 for (i = 0; i < size; i++) { 146 value = 147 db_get_value(addr+bytes, 1, 148 FALSE); 149 db_printf("%02lx", 150 (long)value); 151 bytes++; 152 if (!(bytes % 4)) 153 db_printf(" "); 154 } 155 } while ((bytes != 16) && count--); 156 /* True up the columns before continuing */ 157 db_printf("%-*s", 158 (16-bytes)*2 + (4 - bytes/4) + 1, " "); 159 /* Print chars, use . for non-printables */ 160 while (bytes--) { 161 value = db_get_value(addr + incr, 1, 162 FALSE); 163 incr++; 164 if (value >= ' ' && value <= '~') 165 db_printf("%c", (int)value); 166 else 167 db_printf("."); 168 } 169 db_printf("\n"); 170 break; 171 case 'z': /* signed hex */ 172 value = db_get_value(addr, size, TRUE); 173 db_format(tmpfmt, sizeof tmpfmt, 174 (long)value, DB_FORMAT_Z, 0, width); 175 db_printf("%-*s", width, tmpfmt); 176 break; 177 case 'd': /* signed decimal */ 178 value = db_get_value(addr, size, TRUE); 179 db_printf("%-*ld", width, (long)value); 180 break; 181 case 'u': /* unsigned decimal */ 182 value = db_get_value(addr, size, FALSE); 183 db_printf("%-*lu", width, (long)value); 184 break; 185 case 'o': /* unsigned octal */ 186 value = db_get_value(addr, size, FALSE); 187 db_printf("%-*lo", width, value); 188 break; 189 case 'c': /* character */ 190 value = db_get_value(addr, 1, FALSE); 191 incr = 1; 192 if (value >= ' ' && value <= '~') 193 db_printf("%c", (int)value); 194 else 195 db_printf("\\%03o", (int)value); 196 break; 197 case 's': /* null-terminated string */ 198 incr = 0; 199 for (;;) { 200 value = db_get_value(addr + incr, 1, 201 FALSE); 202 incr++; 203 if (value == 0) 204 break; 205 if (value >= ' ' && value <= '~') 206 db_printf("%c", (int)value); 207 else 208 db_printf("\\%03o", (int)value); 209 } 210 break; 211 case 'i': /* instruction */ 212 case 'I': /* instruction, alternate form */ 213 dis = c; 214 break; 215 default: 216 incr = 0; 217 break; 218 } 219 } 220 /* if we had a disassembly modifier, do it last */ 221 switch (dis) { 222 case 'i': /* instruction */ 223 addr = db_disasm(addr, FALSE); 224 break; 225 case 'I': /* instruction, alternate form */ 226 addr = db_disasm(addr, TRUE); 227 break; 228 default: 229 addr += incr; 230 break; 231 } 232 if (db_print_position() != 0) 233 db_printf("\n"); 234 } 235 db_next = addr; 236 } 237 238 /* 239 * Print value. 240 */ 241 char db_print_format = 'x'; 242 243 /*ARGSUSED*/ 244 void 245 db_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 246 { 247 db_expr_t value; 248 char tmpfmt[28]; 249 250 if (modif[0] != '\0') 251 db_print_format = modif[0]; 252 253 switch (db_print_format) { 254 case 'a': 255 db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf); 256 break; 257 case 'r': 258 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, 259 DB_FORMAT_R, 0, sizeof(db_expr_t) * 2 * 6 / 5)); 260 break; 261 case 'x': 262 db_printf("%*lx", (uint)sizeof(db_expr_t) * 2, addr); 263 break; 264 case 'z': 265 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, 266 DB_FORMAT_Z, 0, sizeof(db_expr_t) * 2)); 267 break; 268 case 'd': 269 db_printf("%*ld", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr); 270 break; 271 case 'u': 272 db_printf("%*lu", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr); 273 break; 274 case 'o': 275 db_printf("%*lo", (uint)sizeof(db_expr_t) * 2 * 4 / 3, addr); 276 break; 277 case 'c': 278 value = addr & 0xFF; 279 if (value >= ' ' && value <= '~') 280 db_printf("%c", (int)value); 281 else 282 db_printf("\\%03o", (int)value); 283 break; 284 } 285 db_printf("\n"); 286 } 287 288 void 289 db_print_loc_and_inst(db_addr_t loc) 290 { 291 db_printsym(loc, DB_STGY_PROC, db_printf); 292 db_printf(":\t"); 293 (void) db_disasm(loc, FALSE); 294 } 295 296 /* local copy is needed here so that we can trace strlcpy() in libkern */ 297 size_t 298 db_strlcpy(char *dst, const char *src, size_t siz) 299 { 300 char *d = dst; 301 const char *s = src; 302 size_t n = siz; 303 304 /* Copy as many bytes as will fit */ 305 if (n != 0 && --n != 0) { 306 do { 307 if ((*d++ = *s++) == 0) 308 break; 309 } while (--n != 0); 310 } 311 312 /* Not enough room in dst, add NUL and traverse rest of src */ 313 if (n == 0) { 314 if (siz != 0) 315 *d = '\0'; /* NUL-terminate dst */ 316 while (*s++) 317 continue; 318 } 319 320 return(s - src - 1); /* count does not include NUL */ 321 } 322 323 /* 324 * Search for a value in memory. 325 * Syntax: search [/bhl] addr value [mask] [,count] 326 */ 327 /*ARGSUSED*/ 328 void 329 db_search_cmd(db_expr_t daddr, int have_addr, db_expr_t dcount, char *modif) 330 { 331 int t; 332 db_addr_t addr; 333 int size; 334 db_expr_t value; 335 db_expr_t mask; 336 db_expr_t count; 337 338 t = db_read_token(); 339 if (t == tSLASH) { 340 t = db_read_token(); 341 if (t != tIDENT) { 342 bad_modifier: 343 db_printf("Bad modifier\n"); 344 db_flush_lex(); 345 return; 346 } 347 348 if (!strcmp(db_tok_string, "b")) 349 size = 1; 350 else if (!strcmp(db_tok_string, "h")) 351 size = 2; 352 else if (!strcmp(db_tok_string, "l")) 353 size = 4; 354 else 355 goto bad_modifier; 356 } else { 357 db_unread_token(t); 358 size = 4; 359 } 360 361 if (!db_expression(&value)) { 362 db_printf("Address missing\n"); 363 db_flush_lex(); 364 return; 365 } 366 addr = (db_addr_t) value; 367 368 if (!db_expression(&value)) { 369 db_printf("Value missing\n"); 370 db_flush_lex(); 371 return; 372 } 373 374 if (!db_expression(&mask)) 375 mask = (int) ~0; 376 377 t = db_read_token(); 378 if (t == tCOMMA) { 379 if (!db_expression(&count)) { 380 db_printf("Count missing\n"); 381 db_flush_lex(); 382 return; 383 } 384 } else { 385 db_unread_token(t); 386 count = -1; /* forever */ 387 } 388 db_skip_to_eol(); 389 390 db_search(addr, size, value, mask, count); 391 } 392 393 void 394 db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask, 395 db_expr_t count) 396 { 397 /* Negative counts means forever. */ 398 while (count < 0 || count-- != 0) { 399 db_prev = addr; 400 if ((db_get_value(addr, size, FALSE) & mask) == value) 401 break; 402 addr += size; 403 } 404 db_next = addr; 405 } 406