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 #ifndef NO_SYS_HEADERS 44 #include <stdarg.h> 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 sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", x); 180 M.x86.enc_str_pos += strlen(x); 181 } 182 183 void 184 x86emu_decode_printf2(const char *x, int y) 185 { 186 char temp[100]; 187 188 snprintf(temp, sizeof(temp), x, y); 189 sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp); 190 M.x86.enc_str_pos += strlen(temp); 191 } 192 193 void 194 x86emu_end_instr(void) 195 { 196 M.x86.enc_str_pos = 0; 197 M.x86.enc_pos = 0; 198 } 199 200 static void 201 print_encoded_bytes(u16 s, u16 o) 202 { 203 int i; 204 char buf1[64]; 205 206 for (i = 0; i < M.x86.enc_pos; i++) { 207 sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i)); 208 } 209 printk("%-20s", buf1); 210 } 211 212 static void 213 print_decoded_instruction(void) 214 { 215 printk("%s", M.x86.decoded_buf); 216 } 217 218 void 219 x86emu_print_int_vect(u16 iv) 220 { 221 u16 seg, off; 222 223 if (iv > 256) 224 return; 225 seg = fetch_data_word_abs(0, iv * 4); 226 off = fetch_data_word_abs(0, iv * 4 + 2); 227 printk("%04x:%04x ", seg, off); 228 } 229 230 void 231 X86EMU_dump_memory(u16 seg, u16 off, u32 amt) 232 { 233 u32 start = off & 0xfffffff0; 234 u32 end = (off + 16) & 0xfffffff0; 235 u32 i; 236 u32 current; 237 238 current = start; 239 while (end <= off + amt) { 240 printk("%04x:%04x ", seg, start); 241 for (i = start; i < off; i++) 242 printk(" "); 243 for (; i < end; i++) 244 printk("%02x ", fetch_data_byte_abs(seg, i)); 245 printk("\n"); 246 start = end; 247 end = start + 16; 248 } 249 } 250 251 void 252 x86emu_single_step(void) 253 { 254 return; 255 char s[1024]; 256 int ps[10]; 257 int ntok; 258 int cmd; 259 int done; 260 int segment; 261 int offset; 262 static int breakpoint; 263 static int noDecode = 1; 264 265 //char *p; 266 267 if (DEBUG_BREAK()) { 268 if (M.x86.saved_ip != breakpoint) { 269 return; 270 } 271 else { 272 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; 273 M.x86.debug |= DEBUG_TRACE_F; 274 M.x86.debug &= ~DEBUG_BREAK_F; 275 print_decoded_instruction(); 276 X86EMU_trace_regs(); 277 } 278 } 279 done = 0; 280 offset = M.x86.saved_ip; 281 while (!done) { 282 printk("-"); 283 //p = fgets(s, 1023, stdin); 284 cmd = parse_line(s, ps, &ntok); 285 switch (cmd) { 286 case 'u': 287 disassemble_forward(M.x86.saved_cs, (u16) offset, 10); 288 break; 289 case 'd': 290 if (ntok == 2) { 291 segment = M.x86.saved_cs; 292 offset = ps[1]; 293 X86EMU_dump_memory(segment, (u16) offset, 16); 294 offset += 16; 295 } 296 else if (ntok == 3) { 297 segment = ps[1]; 298 offset = ps[2]; 299 X86EMU_dump_memory(segment, (u16) offset, 16); 300 offset += 16; 301 } 302 else { 303 segment = M.x86.saved_cs; 304 X86EMU_dump_memory(segment, (u16) offset, 16); 305 offset += 16; 306 } 307 break; 308 case 'c': 309 M.x86.debug ^= DEBUG_TRACECALL_F; 310 break; 311 case 's': 312 M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F; 313 break; 314 case 'r': 315 X86EMU_trace_regs(); 316 break; 317 case 'x': 318 X86EMU_trace_xregs(); 319 break; 320 case 'g': 321 if (ntok == 2) { 322 breakpoint = ps[1]; 323 if (noDecode) { 324 M.x86.debug |= DEBUG_DECODE_NOPRINT_F; 325 } 326 else { 327 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; 328 } 329 M.x86.debug &= ~DEBUG_TRACE_F; 330 M.x86.debug |= DEBUG_BREAK_F; 331 done = 1; 332 } 333 break; 334 case 'q': 335 M.x86.debug |= DEBUG_EXIT; 336 return; 337 case 'P': 338 noDecode = (noDecode) ? 0 : 1; 339 printk("Toggled decoding to %s\n", (noDecode) ? "FALSE" : "TRUE"); 340 break; 341 case 't': 342 case 0: 343 done = 1; 344 break; 345 } 346 } 347 } 348 349 int 350 X86EMU_trace_on(void) 351 { 352 return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; 353 } 354 355 int 356 X86EMU_trace_off(void) 357 { 358 return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F); 359 } 360 361 static int 362 parse_line(char *s, int *ps, int *n) 363 { 364 int cmd; 365 366 *n = 0; 367 while (*s == ' ' || *s == '\t') 368 s++; 369 ps[*n] = *s; 370 switch (*s) { 371 case '\n': 372 *n += 1; 373 return 0; 374 default: 375 cmd = *s; 376 *n += 1; 377 } 378 379 while (1) { 380 while (*s != ' ' && *s != '\t' && *s != '\n') 381 s++; 382 383 if (*s == '\n') 384 return cmd; 385 386 while (*s == ' ' || *s == '\t') 387 s++; 388 389 //sscanf(s, "%x", &ps[*n]); 390 *n += 1; 391 } 392 } 393 394 #endif /* DEBUG */ 395 396 void 397 x86emu_dump_regs(void) 398 { 399 printk("\tAX=%04x ", M.x86.R_AX); 400 printk("BX=%04x ", M.x86.R_BX); 401 printk("CX=%04x ", M.x86.R_CX); 402 printk("DX=%04x ", M.x86.R_DX); 403 printk("SP=%04x ", M.x86.R_SP); 404 printk("BP=%04x ", M.x86.R_BP); 405 printk("SI=%04x ", M.x86.R_SI); 406 printk("DI=%04x\n", M.x86.R_DI); 407 printk("\tDS=%04x ", M.x86.R_DS); 408 printk("ES=%04x ", M.x86.R_ES); 409 printk("SS=%04x ", M.x86.R_SS); 410 printk("CS=%04x ", M.x86.R_CS); 411 printk("IP=%04x ", M.x86.R_IP); 412 if (ACCESS_FLAG(F_OF)) 413 printk("OV "); /* CHECKED... */ 414 else 415 printk("NV "); 416 if (ACCESS_FLAG(F_DF)) 417 printk("DN "); 418 else 419 printk("UP "); 420 if (ACCESS_FLAG(F_IF)) 421 printk("EI "); 422 else 423 printk("DI "); 424 if (ACCESS_FLAG(F_SF)) 425 printk("NG "); 426 else 427 printk("PL "); 428 if (ACCESS_FLAG(F_ZF)) 429 printk("ZR "); 430 else 431 printk("NZ "); 432 if (ACCESS_FLAG(F_AF)) 433 printk("AC "); 434 else 435 printk("NA "); 436 if (ACCESS_FLAG(F_PF)) 437 printk("PE "); 438 else 439 printk("PO "); 440 if (ACCESS_FLAG(F_CF)) 441 printk("CY "); 442 else 443 printk("NC "); 444 printk("\n"); 445 } 446 447 void 448 x86emu_dump_xregs(void) 449 { 450 printk("\tEAX=%08x ", M.x86.R_EAX); 451 printk("EBX=%08x ", M.x86.R_EBX); 452 printk("ECX=%08x ", M.x86.R_ECX); 453 printk("EDX=%08x \n", M.x86.R_EDX); 454 printk("\tESP=%08x ", M.x86.R_ESP); 455 printk("EBP=%08x ", M.x86.R_EBP); 456 printk("ESI=%08x ", M.x86.R_ESI); 457 printk("EDI=%08x\n", M.x86.R_EDI); 458 printk("\tDS=%04x ", M.x86.R_DS); 459 printk("ES=%04x ", M.x86.R_ES); 460 printk("SS=%04x ", M.x86.R_SS); 461 printk("CS=%04x ", M.x86.R_CS); 462 printk("EIP=%08x\n\t", M.x86.R_EIP); 463 if (ACCESS_FLAG(F_OF)) 464 printk("OV "); /* CHECKED... */ 465 else 466 printk("NV "); 467 if (ACCESS_FLAG(F_DF)) 468 printk("DN "); 469 else 470 printk("UP "); 471 if (ACCESS_FLAG(F_IF)) 472 printk("EI "); 473 else 474 printk("DI "); 475 if (ACCESS_FLAG(F_SF)) 476 printk("NG "); 477 else 478 printk("PL "); 479 if (ACCESS_FLAG(F_ZF)) 480 printk("ZR "); 481 else 482 printk("NZ "); 483 if (ACCESS_FLAG(F_AF)) 484 printk("AC "); 485 else 486 printk("NA "); 487 if (ACCESS_FLAG(F_PF)) 488 printk("PE "); 489 else 490 printk("PO "); 491 if (ACCESS_FLAG(F_CF)) 492 printk("CY "); 493 else 494 printk("NC "); 495 printk("\n"); 496 } 497