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 52static void print_encoded_bytes(u16 s, u16 o); 53static void print_decoded_instruction(void); 54static int parse_line(char *s, int *ps, int *n); 55 56/* should look something like debug's output. */ 57void 58X86EMU_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 70void 71X86EMU_trace_xregs(void) 72{ 73 if (DEBUG_TRACE()) { 74 x86emu_dump_xregs(); 75 } 76} 77 78void 79x86emu_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 90static void 91disassemble_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 147void 148x86emu_check_ip_access(void) 149{ 150 /* NULL as of now */ 151} 152 153void 154x86emu_check_sp_access(void) 155{ 156} 157 158void 159x86emu_check_mem_access(u32 dummy) 160{ 161 /* check bounds, etc */ 162} 163 164void 165x86emu_check_data_access(uint dummy1, uint dummy2) 166{ 167 /* check bounds, etc */ 168} 169 170void 171x86emu_inc_decoded_inst_len(int x) 172{ 173 M.x86.enc_pos += x; 174} 175 176void 177x86emu_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 183void 184x86emu_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 193void 194x86emu_end_instr(void) 195{ 196 M.x86.enc_str_pos = 0; 197 M.x86.enc_pos = 0; 198} 199 200static void 201print_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 212static void 213print_decoded_instruction(void) 214{ 215 printk("%s", M.x86.decoded_buf); 216} 217 218void 219x86emu_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 230void 231X86EMU_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 251void 252x86emu_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 349int 350X86EMU_trace_on(void) 351{ 352 return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; 353} 354 355int 356X86EMU_trace_off(void) 357{ 358 return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F); 359} 360 361static int 362parse_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 396void 397x86emu_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 447void 448x86emu_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