1/**************************************************************************** 2* 3* Realmode X86 Emulator Library 4* 5* Copyright (C) 1991-2004 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 <stdarg.h> 41#include <common.h> 42#include <linux/ctype.h> 43#include <linux/printk.h> 44#include "x86emu/x86emui.h" 45 46/*----------------------------- Implementation ----------------------------*/ 47 48#ifdef CONFIG_X86EMU_DEBUG 49 50static void print_encoded_bytes(u16 s, u16 o); 51static void print_decoded_instruction(void); 52static int x86emu_parse_line(char *s, int *ps, int *n); 53 54/* should look something like debug's output. */ 55void X86EMU_trace_regs(void) 56{ 57 if (DEBUG_TRACE()) { 58 x86emu_dump_regs(); 59 } 60 if (DEBUG_DECODE() && !DEBUG_DECODE_NOPRINT()) { 61 printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); 62 print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); 63 print_decoded_instruction(); 64 } 65} 66 67void X86EMU_trace_xregs(void) 68{ 69 if (DEBUG_TRACE()) { 70 x86emu_dump_xregs(); 71 } 72} 73 74void x86emu_just_disassemble(void) 75{ 76 /* 77 * This routine called if the flag DEBUG_DISASSEMBLE is set kind 78 * of a hack! 79 */ 80 printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); 81 print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); 82 print_decoded_instruction(); 83} 84 85static void disassemble_forward(u16 seg, u16 off, int n) 86{ 87 X86EMU_sysEnv tregs; 88 int i; 89 u8 op1; 90 /* 91 * hack, hack, hack. What we do is use the exact machinery set up 92 * for execution, except that now there is an additional state 93 * flag associated with the "execution", and we are using a copy 94 * of the register struct. All the major opcodes, once fully 95 * decoded, have the following two steps: TRACE_REGS(r,m); 96 * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to 97 * the preprocessor. The TRACE_REGS macro expands to: 98 * 99 * if (debug&DEBUG_DISASSEMBLE) 100 * {just_disassemble(); goto EndOfInstruction;} 101 * if (debug&DEBUG_TRACE) trace_regs(r,m); 102 * 103 * ...... and at the last line of the routine. 104 * 105 * EndOfInstruction: end_instr(); 106 * 107 * Up to the point where TRACE_REG is expanded, NO modifications 108 * are done to any register EXCEPT the IP register, for fetch and 109 * decoding purposes. 110 * 111 * This was done for an entirely different reason, but makes a 112 * nice way to get the system to help debug codes. 113 */ 114 tregs = M; 115 tregs.x86.R_IP = off; 116 tregs.x86.R_CS = seg; 117 118 /* reset the decoding buffers */ 119 tregs.x86.enc_str_pos = 0; 120 tregs.x86.enc_pos = 0; 121 122 /* turn on the "disassemble only, no execute" flag */ 123 tregs.x86.debug |= DEBUG_DISASSEMBLE_F; 124 125 /* DUMP NEXT n instructions to screen in straight_line fashion */ 126 /* 127 * This looks like the regular instruction fetch stream, except 128 * that when this occurs, each fetched opcode, upon seeing the 129 * DEBUG_DISASSEMBLE flag set, exits immediately after decoding 130 * the instruction. XXX --- CHECK THAT MEM IS NOT AFFECTED!!! 131 * Note the use of a copy of the register structure... 132 */ 133 for (i = 0; i < n; i++) { 134 op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++)); 135 (x86emu_optab[op1]) (op1); 136 } 137 /* end major hack mode. */ 138} 139 140void x86emu_check_ip_access(void) 141{ 142 /* NULL as of now */ 143} 144 145void x86emu_check_sp_access(void) 146{ 147} 148 149void x86emu_check_mem_access(u32 dummy) 150{ 151 /* check bounds, etc */ 152} 153 154void x86emu_check_data_access(uint dummy1, uint dummy2) 155{ 156 /* check bounds, etc */ 157} 158 159void x86emu_inc_decoded_inst_len(int x) 160{ 161 M.x86.enc_pos += x; 162} 163 164void x86emu_decode_printf(char *x) 165{ 166 sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", x); 167 M.x86.enc_str_pos += strlen(x); 168} 169 170void x86emu_decode_printf2(char *x, int y) 171{ 172 char temp[100]; 173 sprintf(temp, x, y); 174 sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp); 175 M.x86.enc_str_pos += strlen(temp); 176} 177 178void x86emu_end_instr(void) 179{ 180 M.x86.enc_str_pos = 0; 181 M.x86.enc_pos = 0; 182} 183 184static void print_encoded_bytes(u16 s, u16 o) 185{ 186 int i; 187 char buf1[64]; 188 for (i = 0; i < M.x86.enc_pos; i++) { 189 sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i)); 190 } 191 printk("%-20s", buf1); 192} 193 194static void print_decoded_instruction(void) 195{ 196 printk("%s", M.x86.decoded_buf); 197} 198 199void x86emu_print_int_vect(u16 iv) 200{ 201 u16 seg, off; 202 203 if (iv > 256) 204 return; 205 seg = fetch_data_word_abs(0, iv * 4); 206 off = fetch_data_word_abs(0, iv * 4 + 2); 207 printk("%04x:%04x ", seg, off); 208} 209 210void X86EMU_dump_memory(u16 seg, u16 off, u32 amt) 211{ 212 u32 start = off & 0xfffffff0; 213 u32 end = (off + 16) & 0xfffffff0; 214 u32 i; 215 216 while (end <= off + amt) { 217 printk("%04x:%04x ", seg, start); 218 for (i = start; i < off; i++) 219 printk(" "); 220 for (; i < end; i++) 221 printk("%02x ", fetch_data_byte_abs(seg, i)); 222 printk("\n"); 223 start = end; 224 end = start + 16; 225 } 226} 227 228void x86emu_single_step(void) 229{ 230 char s[1024]; 231 int ps[10]; 232 int ntok; 233 int cmd; 234 int done; 235 int segment; 236 int offset; 237 static int breakpoint; 238 static int noDecode = 1; 239 240 if (DEBUG_BREAK()) { 241 if (M.x86.saved_ip != breakpoint) { 242 return; 243 } else { 244 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; 245 M.x86.debug |= DEBUG_TRACE_F; 246 M.x86.debug &= ~DEBUG_BREAK_F; 247 print_decoded_instruction(); 248 X86EMU_trace_regs(); 249 } 250 } 251 done = 0; 252 offset = M.x86.saved_ip; 253 while (!done) { 254 printk("-"); 255 ps[1] = 0; /* Avoid dodgy compiler warnings */ 256 ps[2] = 0; 257 cmd = x86emu_parse_line(s, ps, &ntok); 258 switch (cmd) { 259 case 'u': 260 disassemble_forward(M.x86.saved_cs, (u16) offset, 10); 261 break; 262 case 'd': 263 if (ntok == 2) { 264 segment = M.x86.saved_cs; 265 offset = ps[1]; 266 X86EMU_dump_memory(segment, (u16) offset, 16); 267 offset += 16; 268 } else if (ntok == 3) { 269 segment = ps[1]; 270 offset = ps[2]; 271 X86EMU_dump_memory(segment, (u16) offset, 16); 272 offset += 16; 273 } else { 274 segment = M.x86.saved_cs; 275 X86EMU_dump_memory(segment, (u16) offset, 16); 276 offset += 16; 277 } 278 break; 279 case 'c': 280 M.x86.debug ^= DEBUG_TRACECALL_F; 281 break; 282 case 's': 283 M.x86.debug ^= 284 DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F; 285 break; 286 case 'r': 287 X86EMU_trace_regs(); 288 break; 289 case 'x': 290 X86EMU_trace_xregs(); 291 break; 292 case 'g': 293 if (ntok == 2) { 294 breakpoint = ps[1]; 295 if (noDecode) { 296 M.x86.debug |= DEBUG_DECODE_NOPRINT_F; 297 } else { 298 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; 299 } 300 M.x86.debug &= ~DEBUG_TRACE_F; 301 M.x86.debug |= DEBUG_BREAK_F; 302 done = 1; 303 } 304 break; 305 case 'q': 306 M.x86.debug |= DEBUG_EXIT; 307 return; 308 case 'P': 309 noDecode = (noDecode) ? 0 : 1; 310 printk("Toggled decoding to %s\n", 311 (noDecode) ? "false" : "true"); 312 break; 313 case 't': 314 case 0: 315 done = 1; 316 break; 317 } 318 } 319} 320 321int X86EMU_trace_on(void) 322{ 323 return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; 324} 325 326int X86EMU_trace_off(void) 327{ 328 return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F); 329} 330 331static int x86emu_parse_line(char *s, int *ps, int *n) 332{ 333 int cmd; 334 335 *n = 0; 336 while (isblank(*s)) 337 s++; 338 ps[*n] = *s; 339 switch (*s) { 340 case '\n': 341 *n += 1; 342 return 0; 343 default: 344 cmd = *s; 345 *n += 1; 346 } 347 348 while (1) { 349 while (!isblank(*s) && *s != '\n') 350 s++; 351 352 if (*s == '\n') 353 return cmd; 354 355 while (isblank(*s)) 356 s++; 357 358 *n += 1; 359 } 360} 361 362#endif /* DEBUG */ 363 364void x86emu_dump_regs(void) 365{ 366 printk("\tAX=%04x ", M.x86.R_AX); 367 printk("BX=%04x ", M.x86.R_BX); 368 printk("CX=%04x ", M.x86.R_CX); 369 printk("DX=%04x ", M.x86.R_DX); 370 printk("SP=%04x ", M.x86.R_SP); 371 printk("BP=%04x ", M.x86.R_BP); 372 printk("SI=%04x ", M.x86.R_SI); 373 printk("DI=%04x\n", M.x86.R_DI); 374 printk("\tDS=%04x ", M.x86.R_DS); 375 printk("ES=%04x ", M.x86.R_ES); 376 printk("SS=%04x ", M.x86.R_SS); 377 printk("CS=%04x ", M.x86.R_CS); 378 printk("IP=%04x ", M.x86.R_IP); 379 if (ACCESS_FLAG(F_OF)) 380 printk("OV "); /* CHECKED... */ 381 else 382 printk("NV "); 383 if (ACCESS_FLAG(F_DF)) 384 printk("DN "); 385 else 386 printk("UP "); 387 if (ACCESS_FLAG(F_IF)) 388 printk("EI "); 389 else 390 printk("DI "); 391 if (ACCESS_FLAG(F_SF)) 392 printk("NG "); 393 else 394 printk("PL "); 395 if (ACCESS_FLAG(F_ZF)) 396 printk("ZR "); 397 else 398 printk("NZ "); 399 if (ACCESS_FLAG(F_AF)) 400 printk("AC "); 401 else 402 printk("NA "); 403 if (ACCESS_FLAG(F_PF)) 404 printk("PE "); 405 else 406 printk("PO "); 407 if (ACCESS_FLAG(F_CF)) 408 printk("CY "); 409 else 410 printk("NC "); 411 printk("\n"); 412} 413 414void x86emu_dump_xregs(void) 415{ 416 printk("\tEAX=%08x ", M.x86.R_EAX); 417 printk("EBX=%08x ", M.x86.R_EBX); 418 printk("ECX=%08x ", M.x86.R_ECX); 419 printk("EDX=%08x \n", M.x86.R_EDX); 420 printk("\tESP=%08x ", M.x86.R_ESP); 421 printk("EBP=%08x ", M.x86.R_EBP); 422 printk("ESI=%08x ", M.x86.R_ESI); 423 printk("EDI=%08x\n", M.x86.R_EDI); 424 printk("\tDS=%04x ", M.x86.R_DS); 425 printk("ES=%04x ", M.x86.R_ES); 426 printk("SS=%04x ", M.x86.R_SS); 427 printk("CS=%04x ", M.x86.R_CS); 428 printk("EIP=%08x\n\t", M.x86.R_EIP); 429 if (ACCESS_FLAG(F_OF)) 430 printk("OV "); /* CHECKED... */ 431 else 432 printk("NV "); 433 if (ACCESS_FLAG(F_DF)) 434 printk("DN "); 435 else 436 printk("UP "); 437 if (ACCESS_FLAG(F_IF)) 438 printk("EI "); 439 else 440 printk("DI "); 441 if (ACCESS_FLAG(F_SF)) 442 printk("NG "); 443 else 444 printk("PL "); 445 if (ACCESS_FLAG(F_ZF)) 446 printk("ZR "); 447 else 448 printk("NZ "); 449 if (ACCESS_FLAG(F_AF)) 450 printk("AC "); 451 else 452 printk("NA "); 453 if (ACCESS_FLAG(F_PF)) 454 printk("PE "); 455 else 456 printk("PO "); 457 if (ACCESS_FLAG(F_CF)) 458 printk("CY "); 459 else 460 printk("NC "); 461 printk("\n"); 462} 463