1 /* $OpenBSD: db_examine.c,v 1.26 2019/11/07 13:16:25 mpi 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(vaddr_t, char *, int); 49 void db_search(vaddr_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((vaddr_t)addr, db_examine_format, count); 70 } 71 72 void 73 db_examine(vaddr_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 vaddr_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, 1); 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, 0); 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 0); 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, 0); 162 incr++; 163 if (value >= ' ' && value <= '~') 164 db_printf("%c", (int)value); 165 else 166 db_printf("."); 167 } 168 db_printf("\n"); 169 break; 170 case 'z': /* signed hex */ 171 value = db_get_value(addr, size, 1); 172 db_format(tmpfmt, sizeof tmpfmt, 173 (long)value, DB_FORMAT_Z, 0, width); 174 db_printf("%-*s", width, tmpfmt); 175 break; 176 case 'd': /* signed decimal */ 177 value = db_get_value(addr, size, 1); 178 db_printf("%-*ld", width, (long)value); 179 break; 180 case 'u': /* unsigned decimal */ 181 value = db_get_value(addr, size, 0); 182 db_printf("%-*lu", width, (long)value); 183 break; 184 case 'o': /* unsigned octal */ 185 value = db_get_value(addr, size, 0); 186 db_printf("%-*lo", width, value); 187 break; 188 case 'c': /* character */ 189 value = db_get_value(addr, 1, 0); 190 incr = 1; 191 if (value >= ' ' && value <= '~') 192 db_printf("%c", (int)value); 193 else 194 db_printf("\\%03o", (int)value); 195 break; 196 case 's': /* null-terminated string */ 197 incr = 0; 198 for (;;) { 199 value = db_get_value(addr + incr, 1, 200 0); 201 incr++; 202 if (value == 0) 203 break; 204 if (value >= ' ' && value <= '~') 205 db_printf("%c", (int)value); 206 else 207 db_printf("\\%03o", (int)value); 208 } 209 break; 210 case 'i': /* instruction */ 211 case 'I': /* instruction, alternate form */ 212 dis = c; 213 break; 214 default: 215 incr = 0; 216 break; 217 } 218 } 219 /* if we had a disassembly modifier, do it last */ 220 switch (dis) { 221 case 'i': /* instruction */ 222 addr = db_disasm(addr, 0); 223 break; 224 case 'I': /* instruction, alternate form */ 225 addr = db_disasm(addr, 1); 226 break; 227 default: 228 addr += incr; 229 break; 230 } 231 if (db_print_position() != 0) 232 db_printf("\n"); 233 } 234 db_next = addr; 235 } 236 237 /* 238 * Print value. 239 */ 240 char db_print_format = 'x'; 241 242 /*ARGSUSED*/ 243 void 244 db_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 245 { 246 db_expr_t value; 247 char tmpfmt[28]; 248 249 if (modif[0] != '\0') 250 db_print_format = modif[0]; 251 252 switch (db_print_format) { 253 case 'a': 254 db_printsym((vaddr_t)addr, DB_STGY_ANY, db_printf); 255 break; 256 case 'r': 257 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, 258 DB_FORMAT_R, 0, sizeof(db_expr_t) * 2 * 6 / 5)); 259 break; 260 case 'x': 261 db_printf("%*lx", (uint)sizeof(db_expr_t) * 2, addr); 262 break; 263 case 'z': 264 db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, 265 DB_FORMAT_Z, 0, sizeof(db_expr_t) * 2)); 266 break; 267 case 'd': 268 db_printf("%*ld", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr); 269 break; 270 case 'u': 271 db_printf("%*lu", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr); 272 break; 273 case 'o': 274 db_printf("%*lo", (uint)sizeof(db_expr_t) * 2 * 4 / 3, addr); 275 break; 276 case 'c': 277 value = addr & 0xFF; 278 if (value >= ' ' && value <= '~') 279 db_printf("%c", (int)value); 280 else 281 db_printf("\\%03o", (int)value); 282 break; 283 } 284 db_printf("\n"); 285 } 286 287 void 288 db_print_loc_and_inst(vaddr_t loc) 289 { 290 db_printsym(loc, DB_STGY_PROC, db_printf); 291 db_printf(":\t"); 292 (void) db_disasm(loc, 0); 293 } 294 295 /* local copy is needed here so that we can trace strlcpy() in libkern */ 296 size_t 297 db_strlcpy(char *dst, const char *src, size_t siz) 298 { 299 char *d = dst; 300 const char *s = src; 301 size_t n = siz; 302 303 /* Copy as many bytes as will fit */ 304 if (n != 0 && --n != 0) { 305 do { 306 if ((*d++ = *s++) == 0) 307 break; 308 } while (--n != 0); 309 } 310 311 /* Not enough room in dst, add NUL and traverse rest of src */ 312 if (n == 0) { 313 if (siz != 0) 314 *d = '\0'; /* NUL-terminate dst */ 315 while (*s++) 316 continue; 317 } 318 319 return(s - src - 1); /* count does not include NUL */ 320 } 321 322 /* 323 * Search for a value in memory. 324 * Syntax: search [/bhl] addr value [mask] [,count] 325 */ 326 /*ARGSUSED*/ 327 void 328 db_search_cmd(db_expr_t daddr, int have_addr, db_expr_t dcount, char *modif) 329 { 330 int t; 331 vaddr_t addr; 332 int size; 333 db_expr_t value; 334 db_expr_t mask; 335 db_expr_t count; 336 337 t = db_read_token(); 338 if (t == tSLASH) { 339 t = db_read_token(); 340 if (t != tIDENT) { 341 bad_modifier: 342 db_printf("Bad modifier\n"); 343 db_flush_lex(); 344 return; 345 } 346 347 if (!strcmp(db_tok_string, "b")) 348 size = 1; 349 else if (!strcmp(db_tok_string, "h")) 350 size = 2; 351 else if (!strcmp(db_tok_string, "l")) 352 size = 4; 353 else 354 goto bad_modifier; 355 } else { 356 db_unread_token(t); 357 size = 4; 358 } 359 360 if (!db_expression(&value)) { 361 db_printf("Address missing\n"); 362 db_flush_lex(); 363 return; 364 } 365 addr = (vaddr_t) value; 366 367 if (!db_expression(&value)) { 368 db_printf("Value missing\n"); 369 db_flush_lex(); 370 return; 371 } 372 373 if (!db_expression(&mask)) 374 mask = (int) ~0; 375 376 t = db_read_token(); 377 if (t == tCOMMA) { 378 if (!db_expression(&count)) { 379 db_printf("Count missing\n"); 380 db_flush_lex(); 381 return; 382 } 383 } else { 384 db_unread_token(t); 385 count = -1; /* forever */ 386 } 387 db_skip_to_eol(); 388 389 db_search(addr, size, value, mask, count); 390 } 391 392 void 393 db_search(vaddr_t addr, int size, db_expr_t value, db_expr_t mask, 394 db_expr_t count) 395 { 396 /* Negative counts means forever. */ 397 while (count < 0 || count-- != 0) { 398 db_prev = addr; 399 if ((db_get_value(addr, size, 0) & mask) == value) 400 break; 401 addr += size; 402 } 403 db_next = addr; 404 } 405