1 /* $OpenBSD: db_examine.c,v 1.27 2020/01/09 15:18:58 bluhm 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 if (loc != 0) { 292 db_printf(":\t"); 293 db_disasm(loc, 0); 294 } 295 } 296 297 /* local copy is needed here so that we can trace strlcpy() in libkern */ 298 size_t 299 db_strlcpy(char *dst, const char *src, size_t siz) 300 { 301 char *d = dst; 302 const char *s = src; 303 size_t n = siz; 304 305 /* Copy as many bytes as will fit */ 306 if (n != 0 && --n != 0) { 307 do { 308 if ((*d++ = *s++) == 0) 309 break; 310 } while (--n != 0); 311 } 312 313 /* Not enough room in dst, add NUL and traverse rest of src */ 314 if (n == 0) { 315 if (siz != 0) 316 *d = '\0'; /* NUL-terminate dst */ 317 while (*s++) 318 continue; 319 } 320 321 return(s - src - 1); /* count does not include NUL */ 322 } 323 324 /* 325 * Search for a value in memory. 326 * Syntax: search [/bhl] addr value [mask] [,count] 327 */ 328 /*ARGSUSED*/ 329 void 330 db_search_cmd(db_expr_t daddr, int have_addr, db_expr_t dcount, char *modif) 331 { 332 int t; 333 vaddr_t addr; 334 int size; 335 db_expr_t value; 336 db_expr_t mask; 337 db_expr_t count; 338 339 t = db_read_token(); 340 if (t == tSLASH) { 341 t = db_read_token(); 342 if (t != tIDENT) { 343 bad_modifier: 344 db_printf("Bad modifier\n"); 345 db_flush_lex(); 346 return; 347 } 348 349 if (!strcmp(db_tok_string, "b")) 350 size = 1; 351 else if (!strcmp(db_tok_string, "h")) 352 size = 2; 353 else if (!strcmp(db_tok_string, "l")) 354 size = 4; 355 else 356 goto bad_modifier; 357 } else { 358 db_unread_token(t); 359 size = 4; 360 } 361 362 if (!db_expression(&value)) { 363 db_printf("Address missing\n"); 364 db_flush_lex(); 365 return; 366 } 367 addr = (vaddr_t) value; 368 369 if (!db_expression(&value)) { 370 db_printf("Value missing\n"); 371 db_flush_lex(); 372 return; 373 } 374 375 if (!db_expression(&mask)) 376 mask = (int) ~0; 377 378 t = db_read_token(); 379 if (t == tCOMMA) { 380 if (!db_expression(&count)) { 381 db_printf("Count missing\n"); 382 db_flush_lex(); 383 return; 384 } 385 } else { 386 db_unread_token(t); 387 count = -1; /* forever */ 388 } 389 db_skip_to_eol(); 390 391 db_search(addr, size, value, mask, count); 392 } 393 394 void 395 db_search(vaddr_t addr, int size, db_expr_t value, db_expr_t mask, 396 db_expr_t count) 397 { 398 /* Negative counts means forever. */ 399 while (count < 0 || count-- != 0) { 400 db_prev = addr; 401 if ((db_get_value(addr, size, 0) & mask) == value) 402 break; 403 addr += size; 404 } 405 db_next = addr; 406 } 407