1 /* $OpenBSD: db_examine.c,v 1.22 2016/06/07 01:31:54 tedu 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 c; 76 db_expr_t value; 77 int size; 78 int width; 79 char * fp; 80 db_addr_t incr; 81 int dis; 82 char tmpfmt[28]; 83 84 while (--count >= 0) { 85 fp = fmt; 86 87 /* defaults */ 88 size = 4; 89 width = 12; 90 incr = 0; 91 dis = 0; 92 93 while ((c = *fp++) != 0) { 94 if (db_print_position() == 0) { 95 /* Always print the address. */ 96 db_printsym(addr, DB_STGY_ANY, db_printf); 97 db_printf(":\t"); 98 db_prev = addr; 99 } 100 incr = size; 101 switch (c) { 102 case 'b': /* byte */ 103 size = 1; 104 width = 4; 105 break; 106 case 'h': /* half-word */ 107 size = 2; 108 width = 8; 109 break; 110 case 'l': /* long-word */ 111 size = 4; 112 width = 12; 113 break; 114 #ifdef __LP64__ 115 case 'q': /* quad-word */ 116 size = 8; 117 width = 20; 118 break; 119 #endif 120 case 'a': /* address */ 121 db_printf("= 0x%lx\n", (long)addr); 122 incr = 0; 123 break; 124 case 'r': /* signed, current radix */ 125 value = db_get_value(addr, size, TRUE); 126 db_format(tmpfmt, sizeof tmpfmt, 127 (long)value, DB_FORMAT_R, 0, width); 128 db_printf("%-*s", width, tmpfmt); 129 break; 130 case 'x': /* unsigned hex */ 131 value = db_get_value(addr, size, FALSE); 132 db_printf("%-*lx", width, (long)value); 133 break; 134 case 'z': /* signed hex */ 135 value = db_get_value(addr, size, TRUE); 136 db_format(tmpfmt, sizeof tmpfmt, 137 (long)value, DB_FORMAT_Z, 0, width); 138 db_printf("%-*s", width, tmpfmt); 139 break; 140 case 'd': /* signed decimal */ 141 value = db_get_value(addr, size, TRUE); 142 db_printf("%-*ld", width, (long)value); 143 break; 144 case 'u': /* unsigned decimal */ 145 value = db_get_value(addr, size, FALSE); 146 db_printf("%-*lu", width, (long)value); 147 break; 148 case 'o': /* unsigned octal */ 149 value = db_get_value(addr, size, FALSE); 150 db_printf("%-*lo", width, value); 151 break; 152 case 'c': /* character */ 153 value = db_get_value(addr, 1, FALSE); 154 incr = 1; 155 if (value >= ' ' && value <= '~') 156 db_printf("%c", (int)value); 157 else 158 db_printf("\\%03o", (int)value); 159 break; 160 case 's': /* null-terminated string */ 161 incr = 0; 162 for (;;) { 163 value = db_get_value(addr + incr, 1, 164 FALSE); 165 incr++; 166 if (value == 0) 167 break; 168 if (value >= ' ' && value <= '~') 169 db_printf("%c", (int)value); 170 else 171 db_printf("\\%03o", (int)value); 172 } 173 break; 174 case 'i': /* instruction */ 175 case 'I': /* instruction, alternate form */ 176 dis = c; 177 break; 178 default: 179 incr = 0; 180 break; 181 } 182 } 183 /* if we had a disassembly modifier, do it last */ 184 switch (dis) { 185 case 'i': /* instruction */ 186 addr = db_disasm(addr, FALSE); 187 break; 188 case 'I': /* instruction, alternate form */ 189 addr = db_disasm(addr, TRUE); 190 break; 191 default: 192 addr += incr; 193 break; 194 } 195 if (db_print_position() != 0) 196 db_printf("\n"); 197 } 198 db_next = addr; 199 } 200 201 /* 202 * Print value. 203 */ 204 char db_print_format = 'x'; 205 206 /*ARGSUSED*/ 207 void 208 db_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 209 { 210 db_expr_t value; 211 char tmpfmt[28]; 212 213 if (modif[0] != '\0') 214 db_print_format = modif[0]; 215 216 switch (db_print_format) { 217 case 'a': 218 db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf); 219 break; 220 case 'r': 221 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, 222 DB_FORMAT_R, 0, sizeof(db_expr_t) * 2 * 6 / 5)); 223 break; 224 case 'x': 225 db_printf("%*lx", (uint)sizeof(db_expr_t) * 2, addr); 226 break; 227 case 'z': 228 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, 229 DB_FORMAT_Z, 0, sizeof(db_expr_t) * 2)); 230 break; 231 case 'd': 232 db_printf("%*ld", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr); 233 break; 234 case 'u': 235 db_printf("%*lu", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr); 236 break; 237 case 'o': 238 db_printf("%*lo", (uint)sizeof(db_expr_t) * 2 * 4 / 3, addr); 239 break; 240 case 'c': 241 value = addr & 0xFF; 242 if (value >= ' ' && value <= '~') 243 db_printf("%c", (int)value); 244 else 245 db_printf("\\%03o", (int)value); 246 break; 247 } 248 db_printf("\n"); 249 } 250 251 void 252 db_print_loc_and_inst(db_addr_t loc) 253 { 254 db_printsym(loc, DB_STGY_PROC, db_printf); 255 db_printf(":\t"); 256 (void) db_disasm(loc, FALSE); 257 } 258 259 /* local copy is needed here so that we can trace strlcpy() in libkern */ 260 size_t 261 db_strlcpy(char *dst, const char *src, size_t siz) 262 { 263 char *d = dst; 264 const char *s = src; 265 size_t n = siz; 266 267 /* Copy as many bytes as will fit */ 268 if (n != 0 && --n != 0) { 269 do { 270 if ((*d++ = *s++) == 0) 271 break; 272 } while (--n != 0); 273 } 274 275 /* Not enough room in dst, add NUL and traverse rest of src */ 276 if (n == 0) { 277 if (siz != 0) 278 *d = '\0'; /* NUL-terminate dst */ 279 while (*s++) 280 continue; 281 } 282 283 return(s - src - 1); /* count does not include NUL */ 284 } 285 286 /* 287 * Search for a value in memory. 288 * Syntax: search [/bhl] addr value [mask] [,count] 289 */ 290 /*ARGSUSED*/ 291 void 292 db_search_cmd(db_expr_t daddr, int have_addr, db_expr_t dcount, char *modif) 293 { 294 int t; 295 db_addr_t addr; 296 int size; 297 db_expr_t value; 298 db_expr_t mask; 299 db_expr_t count; 300 301 t = db_read_token(); 302 if (t == tSLASH) { 303 t = db_read_token(); 304 if (t != tIDENT) { 305 bad_modifier: 306 db_printf("Bad modifier\n"); 307 db_flush_lex(); 308 return; 309 } 310 311 if (!strcmp(db_tok_string, "b")) 312 size = 1; 313 else if (!strcmp(db_tok_string, "h")) 314 size = 2; 315 else if (!strcmp(db_tok_string, "l")) 316 size = 4; 317 else 318 goto bad_modifier; 319 } else { 320 db_unread_token(t); 321 size = 4; 322 } 323 324 if (!db_expression(&value)) { 325 db_printf("Address missing\n"); 326 db_flush_lex(); 327 return; 328 } 329 addr = (db_addr_t) value; 330 331 if (!db_expression(&value)) { 332 db_printf("Value missing\n"); 333 db_flush_lex(); 334 return; 335 } 336 337 if (!db_expression(&mask)) 338 mask = (int) ~0; 339 340 t = db_read_token(); 341 if (t == tCOMMA) { 342 if (!db_expression(&count)) { 343 db_printf("Count missing\n"); 344 db_flush_lex(); 345 return; 346 } 347 } else { 348 db_unread_token(t); 349 count = -1; /* forever */ 350 } 351 db_skip_to_eol(); 352 353 db_search(addr, size, value, mask, count); 354 } 355 356 void 357 db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask, 358 db_expr_t count) 359 { 360 /* Negative counts means forever. */ 361 while (count < 0 || count-- != 0) { 362 db_prev = addr; 363 if ((db_get_value(addr, size, FALSE) & mask) == value) 364 break; 365 addr += size; 366 } 367 db_next = addr; 368 } 369