debug.c (12339B)
1 /**************************************************************************** 2 * 3 * Realmode X86 Emulator Library 4 * 5 * Copyright (C) 1996-1999 SciTech Software, Inc. 6 * Copyright (C) David Mosberger-Tang 7 * Copyright (C) 1999 Egbert Eich 8 * 9 * ======================================================================== 10 * 11 * Permission to use, copy, modify, distribute, and sell this software and 12 * its documentation for any purpose is hereby granted without fee, 13 * provided that the above copyright notice appear in all copies and that 14 * both that copyright notice and this permission notice appear in 15 * supporting documentation, and that the name of the authors not be used 16 * in advertising or publicity pertaining to distribution of the software 17 * without specific, written prior permission. The authors makes no 18 * representations about the suitability of this software for any purpose. 19 * It is provided "as is" without express or implied warranty. 20 * 21 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 22 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 23 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 25 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 26 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 27 * PERFORMANCE OF THIS SOFTWARE. 28 * 29 * ======================================================================== 30 * 31 * Language: ANSI C 32 * Environment: Any 33 * Developer: Kendall Bennett 34 * 35 * Description: This file contains the code to handle debugging of the 36 * emulator. 37 * 38 ****************************************************************************/ 39 40 #include "x86emu/x86emui.h" 41 #include <stdio.h> 42 #include <string.h> 43 #include <stdarg.h> 44 #ifndef NO_SYS_HEADERS 45 #include <stdlib.h> 46 #endif 47 48 /*----------------------------- Implementation ----------------------------*/ 49 50 #ifdef DEBUG 51 52 static void print_encoded_bytes(u16 s, u16 o); 53 static void print_decoded_instruction(void); 54 static int parse_line(char *s, int *ps, int *n); 55 56 /* should look something like debug's output. */ 57 void 58 X86EMU_trace_regs(void) 59 { 60 if (DEBUG_TRACE()) { 61 x86emu_dump_regs(); 62 } 63 if (DEBUG_DECODE() && !DEBUG_DECODE_NOPRINT()) { 64 printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); 65 print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); 66 print_decoded_instruction(); 67 } 68 } 69 70 void 71 X86EMU_trace_xregs(void) 72 { 73 if (DEBUG_TRACE()) { 74 x86emu_dump_xregs(); 75 } 76 } 77 78 void 79 x86emu_just_disassemble(void) 80 { 81 /* 82 * This routine called if the flag DEBUG_DISASSEMBLE is set kind 83 * of a hack! 84 */ 85 printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); 86 print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); 87 print_decoded_instruction(); 88 } 89 90 static void 91 disassemble_forward(u16 seg, u16 off, int n) 92 { 93 X86EMU_sysEnv tregs; 94 int i; 95 u8 op1; 96 97 /* 98 * hack, hack, hack. What we do is use the exact machinery set up 99 * for execution, except that now there is an additional state 100 * flag associated with the "execution", and we are using a copy 101 * of the register struct. All the major opcodes, once fully 102 * decoded, have the following two steps: TRACE_REGS(r,m); 103 * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to 104 * the preprocessor. The TRACE_REGS macro expands to: 105 * 106 * if (debug&DEBUG_DISASSEMBLE) 107 * {just_disassemble(); goto EndOfInstruction;} 108 * if (debug&DEBUG_TRACE) trace_regs(r,m); 109 * 110 * ...... and at the last line of the routine. 111 * 112 * EndOfInstruction: end_instr(); 113 * 114 * Up to the point where TRACE_REG is expanded, NO modifications 115 * are done to any register EXCEPT the IP register, for fetch and 116 * decoding purposes. 117 * 118 * This was done for an entirely different reason, but makes a 119 * nice way to get the system to help debug codes. 120 */ 121 tregs = M; 122 tregs.x86.R_IP = off; 123 tregs.x86.R_CS = seg; 124 125 /* reset the decoding buffers */ 126 tregs.x86.enc_str_pos = 0; 127 tregs.x86.enc_pos = 0; 128 129 /* turn on the "disassemble only, no execute" flag */ 130 tregs.x86.debug |= DEBUG_DISASSEMBLE_F; 131 132 /* DUMP NEXT n instructions to screen in straight_line fashion */ 133 /* 134 * This looks like the regular instruction fetch stream, except 135 * that when this occurs, each fetched opcode, upon seeing the 136 * DEBUG_DISASSEMBLE flag set, exits immediately after decoding 137 * the instruction. XXX --- CHECK THAT MEM IS NOT AFFECTED!!! 138 * Note the use of a copy of the register structure... 139 */ 140 for (i = 0; i < n; i++) { 141 op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++)); 142 (x86emu_optab[op1]) (op1); 143 } 144 /* end major hack mode. */ 145 } 146 147 void 148 x86emu_check_ip_access(void) 149 { 150 /* NULL as of now */ 151 } 152 153 void 154 x86emu_check_sp_access(void) 155 { 156 } 157 158 void 159 x86emu_check_mem_access(u32 dummy) 160 { 161 /* check bounds, etc */ 162 } 163 164 void 165 x86emu_check_data_access(uint dummy1, uint dummy2) 166 { 167 /* check bounds, etc */ 168 } 169 170 void 171 x86emu_inc_decoded_inst_len(int x) 172 { 173 M.x86.enc_pos += x; 174 } 175 176 void 177 x86emu_decode_printf(const char *x, ...) 178 { 179 va_list ap; 180 char temp[100]; 181 182 va_start(ap, x); 183 vsnprintf(temp, sizeof(temp), x, ap); 184 va_end(ap); 185 sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp); 186 M.x86.enc_str_pos += strlen(temp); 187 } 188 189 void 190 x86emu_end_instr(void) 191 { 192 M.x86.enc_str_pos = 0; 193 M.x86.enc_pos = 0; 194 } 195 196 static void 197 print_encoded_bytes(u16 s, u16 o) 198 { 199 int i; 200 char buf1[64]; 201 202 for (i = 0; i < M.x86.enc_pos; i++) { 203 sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i)); 204 } 205 printk("%-20s", buf1); 206 } 207 208 static void 209 print_decoded_instruction(void) 210 { 211 printk("%s", M.x86.decoded_buf); 212 } 213 214 void 215 x86emu_print_int_vect(u16 iv) 216 { 217 u16 seg, off; 218 219 if (iv > 256) 220 return; 221 seg = fetch_data_word_abs(0, iv * 4); 222 off = fetch_data_word_abs(0, iv * 4 + 2); 223 printk("%04x:%04x ", seg, off); 224 } 225 226 void 227 X86EMU_dump_memory(u16 seg, u16 off, u32 amt) 228 { 229 u32 start = off & 0xfffffff0; 230 u32 end = (off + 16) & 0xfffffff0; 231 u32 i; 232 233 while (end <= off + amt) { 234 printk("%04x:%04x ", seg, start); 235 for (i = start; i < off; i++) 236 printk(" "); 237 for (; i < end; i++) 238 printk("%02x ", fetch_data_byte_abs(seg, i)); 239 printk("\n"); 240 start = end; 241 end = start + 16; 242 } 243 } 244 245 void 246 x86emu_single_step(void) 247 { 248 char s[1024]; 249 int ps[10]; 250 int ntok; 251 int cmd; 252 int done; 253 int segment; 254 int offset; 255 static int breakpoint; 256 static int noDecode = 1; 257 258 if (DEBUG_BREAK()) { 259 if (M.x86.saved_ip != breakpoint) { 260 return; 261 } 262 else { 263 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; 264 M.x86.debug |= DEBUG_TRACE_F; 265 M.x86.debug &= ~DEBUG_BREAK_F; 266 print_decoded_instruction(); 267 X86EMU_trace_regs(); 268 } 269 } 270 done = 0; 271 offset = M.x86.saved_ip; 272 while (!done) { 273 printk("-"); 274 (void)fgets(s, 1023, stdin); 275 cmd = parse_line(s, ps, &ntok); 276 switch (cmd) { 277 case 'u': 278 disassemble_forward(M.x86.saved_cs, (u16) offset, 10); 279 break; 280 case 'd': 281 if (ntok == 2) { 282 segment = M.x86.saved_cs; 283 offset = ps[1]; 284 X86EMU_dump_memory(segment, (u16) offset, 16); 285 offset += 16; 286 } 287 else if (ntok == 3) { 288 segment = ps[1]; 289 offset = ps[2]; 290 X86EMU_dump_memory(segment, (u16) offset, 16); 291 offset += 16; 292 } 293 else { 294 segment = M.x86.saved_cs; 295 X86EMU_dump_memory(segment, (u16) offset, 16); 296 offset += 16; 297 } 298 break; 299 case 'c': 300 M.x86.debug ^= DEBUG_TRACECALL_F; 301 break; 302 case 's': 303 M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F; 304 break; 305 case 'r': 306 X86EMU_trace_regs(); 307 break; 308 case 'x': 309 X86EMU_trace_xregs(); 310 break; 311 case 'g': 312 if (ntok == 2) { 313 breakpoint = ps[1]; 314 if (noDecode) { 315 M.x86.debug |= DEBUG_DECODE_NOPRINT_F; 316 } 317 else { 318 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; 319 } 320 M.x86.debug &= ~DEBUG_TRACE_F; 321 M.x86.debug |= DEBUG_BREAK_F; 322 done = 1; 323 } 324 break; 325 case 'q': 326 M.x86.debug |= DEBUG_EXIT; 327 return; 328 case 'P': 329 noDecode = (noDecode) ? 0 : 1; 330 printk("Toggled decoding to %s\n", (noDecode) ? "FALSE" : "TRUE"); 331 break; 332 case 't': 333 case 0: 334 done = 1; 335 break; 336 } 337 } 338 } 339 340 int 341 X86EMU_trace_on(void) 342 { 343 return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; 344 } 345 346 int 347 X86EMU_trace_off(void) 348 { 349 return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F); 350 } 351 352 static int 353 parse_line(char *s, int *ps, int *n) 354 { 355 int cmd; 356 357 *n = 0; 358 while (*s == ' ' || *s == '\t') 359 s++; 360 ps[*n] = *s; 361 switch (*s) { 362 case '\n': 363 *n += 1; 364 return 0; 365 default: 366 cmd = *s; 367 *n += 1; 368 } 369 370 while (1) { 371 while (*s != ' ' && *s != '\t' && *s != '\n') 372 s++; 373 374 if (*s == '\n') 375 return cmd; 376 377 while (*s == ' ' || *s == '\t') 378 s++; 379 380 sscanf(s, "%x", &ps[*n]); 381 *n += 1; 382 } 383 } 384 385 #endif /* DEBUG */ 386 387 void 388 x86emu_dump_regs(void) 389 { 390 printk("\tAX=%04x ", M.x86.R_AX); 391 printk("BX=%04x ", M.x86.R_BX); 392 printk("CX=%04x ", M.x86.R_CX); 393 printk("DX=%04x ", M.x86.R_DX); 394 printk("SP=%04x ", M.x86.R_SP); 395 printk("BP=%04x ", M.x86.R_BP); 396 printk("SI=%04x ", M.x86.R_SI); 397 printk("DI=%04x\n", M.x86.R_DI); 398 printk("\tDS=%04x ", M.x86.R_DS); 399 printk("ES=%04x ", M.x86.R_ES); 400 printk("SS=%04x ", M.x86.R_SS); 401 printk("CS=%04x ", M.x86.R_CS); 402 printk("IP=%04x ", M.x86.R_IP); 403 if (ACCESS_FLAG(F_OF)) 404 printk("OV "); /* CHECKED... */ 405 else 406 printk("NV "); 407 if (ACCESS_FLAG(F_DF)) 408 printk("DN "); 409 else 410 printk("UP "); 411 if (ACCESS_FLAG(F_IF)) 412 printk("EI "); 413 else 414 printk("DI "); 415 if (ACCESS_FLAG(F_SF)) 416 printk("NG "); 417 else 418 printk("PL "); 419 if (ACCESS_FLAG(F_ZF)) 420 printk("ZR "); 421 else 422 printk("NZ "); 423 if (ACCESS_FLAG(F_AF)) 424 printk("AC "); 425 else 426 printk("NA "); 427 if (ACCESS_FLAG(F_PF)) 428 printk("PE "); 429 else 430 printk("PO "); 431 if (ACCESS_FLAG(F_CF)) 432 printk("CY "); 433 else 434 printk("NC "); 435 printk("\n"); 436 } 437 438 void 439 x86emu_dump_xregs(void) 440 { 441 printk("\tEAX=%08x ", M.x86.R_EAX); 442 printk("EBX=%08x ", M.x86.R_EBX); 443 printk("ECX=%08x ", M.x86.R_ECX); 444 printk("EDX=%08x \n", M.x86.R_EDX); 445 printk("\tESP=%08x ", M.x86.R_ESP); 446 printk("EBP=%08x ", M.x86.R_EBP); 447 printk("ESI=%08x ", M.x86.R_ESI); 448 printk("EDI=%08x\n", M.x86.R_EDI); 449 printk("\tDS=%04x ", M.x86.R_DS); 450 printk("ES=%04x ", M.x86.R_ES); 451 printk("SS=%04x ", M.x86.R_SS); 452 printk("CS=%04x ", M.x86.R_CS); 453 printk("EIP=%08x\n\t", M.x86.R_EIP); 454 if (ACCESS_FLAG(F_OF)) 455 printk("OV "); /* CHECKED... */ 456 else 457 printk("NV "); 458 if (ACCESS_FLAG(F_DF)) 459 printk("DN "); 460 else 461 printk("UP "); 462 if (ACCESS_FLAG(F_IF)) 463 printk("EI "); 464 else 465 printk("DI "); 466 if (ACCESS_FLAG(F_SF)) 467 printk("NG "); 468 else 469 printk("PL "); 470 if (ACCESS_FLAG(F_ZF)) 471 printk("ZR "); 472 else 473 printk("NZ "); 474 if (ACCESS_FLAG(F_AF)) 475 printk("AC "); 476 else 477 printk("NA "); 478 if (ACCESS_FLAG(F_PF)) 479 printk("PE "); 480 else 481 printk("PO "); 482 if (ACCESS_FLAG(F_CF)) 483 printk("CY "); 484 else 485 printk("NC "); 486 printk("\n"); 487 }