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