diff --git a/Makefile b/Makefile index a61ab4a76a..b007f40dde 100644 --- a/Makefile +++ b/Makefile @@ -30,16 +30,19 @@ endif ######################################################### -DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS +DEFINES+=-D_GNU_SOURCE DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" LDSCRIPT=$(ARCH).ld LIBS+=-ldl -lm -OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ - i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ - i386/dis8086.o i386/emu-ldt.o +#DEFINES+= -DGEMU -DDOSEMU -DNO_TRACE_MSGS +#OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ +# i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ +# i386/dis8086.o i386/emu-ldt.o OBJS+=translate-i386.o op-i386.o OBJS+= elfload.o main.o thunk.o syscall.o +# NOTE: the disassembler code is only needed for debugging +OBJS+=i386-dis.o dis-buf.o SRCS = $(OBJS:.o=.c) all: gemu diff --git a/cpu-i386.h b/cpu-i386.h index 4eac51fb50..9add4175d3 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -1,6 +1,11 @@ +/* NOTE: this header is included in op-i386.c where global register + variable are used. Care must be used when including glibc headers. + */ #ifndef CPU_I386_H #define CPU_I386_H +#include + #define R_EAX 0 #define R_ECX 1 #define R_EDX 2 @@ -43,6 +48,27 @@ #define VM_FLAG 0x20000 /* AC 0x40000 */ +#define EXCP00_DIVZ 1 +#define EXCP01_SSTP 2 +#define EXCP02_NMI 3 +#define EXCP03_INT3 4 +#define EXCP04_INTO 5 +#define EXCP05_BOUND 6 +#define EXCP06_ILLOP 7 +#define EXCP07_PREX 8 +#define EXCP08_DBLE 9 +#define EXCP09_XERR 10 +#define EXCP0A_TSS 11 +#define EXCP0B_NOSEG 12 +#define EXCP0C_STACK 13 +#define EXCP0D_GPF 14 +#define EXCP0E_PAGE 15 +#define EXCP10_COPR 17 +#define EXCP11_ALGN 18 +#define EXCP12_MCHK 19 + +#define EXCP_SIGNAL 256 /* async signal */ + enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ @@ -89,27 +115,34 @@ typedef struct CPUX86State { /* standard registers */ uint32_t regs[8]; uint32_t pc; /* cs_case + eip value */ - - /* eflags handling */ uint32_t eflags; + + /* emulator internal eflags handling */ uint32_t cc_src; uint32_t cc_dst; uint32_t cc_op; int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ - + /* segments */ uint8_t *segs_base[6]; - uint32_t segs[6]; /* FPU state */ - CPU86_LDouble fpregs[8]; - uint8_t fptags[8]; /* 0 = valid, 1 = empty */ unsigned int fpstt; /* top of stack index */ unsigned int fpus; unsigned int fpuc; + uint8_t fptags[8]; /* 0 = valid, 1 = empty */ + CPU86_LDouble fpregs[8]; + + /* segments */ + uint32_t segs[6]; /* emulator internal variables */ + CPU86_LDouble ft0; + + /* exception handling */ + jmp_buf jmp_env; + int exception_index; } CPUX86State; static inline int ldub(void *ptr) diff --git a/linux-user/main.c b/linux-user/main.c index 552ce006c7..68858daf4c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -21,10 +21,11 @@ #include #include #include +#include #include "gemu.h" -#include "i386/hsw_interp.h" +#include "cpu-i386.h" unsigned long x86_stack_size; unsigned long stktop; @@ -38,160 +39,8 @@ void gemu_log(const char *fmt, ...) va_end(ap); } -/* virtual x86 CPU stuff */ - -extern int invoke_code16(Interp_ENV *, int, int); -extern int invoke_code32(Interp_ENV *, int); -extern char *e_print_cpuemu_regs(ENVPARAMS, int is32); -extern char *e_emu_disasm(ENVPARAMS, unsigned char *org, int is32); -extern void init_npu(void); - -Interp_ENV env_global; -Interp_ENV *envp_global; - -QWORD EMUtime = 0; - -int CEmuStat = 0; - -long instr_count; - -/* who will initialize this? */ -unsigned long io_bitmap[IO_BITMAP_SIZE+1]; - -/* debug flag, 0=disable 1..9=level */ -int d_emu = 0; - -unsigned long CRs[5] = -{ - 0x00000013, /* valid bits: 0xe005003f */ - 0x00000000, /* invalid */ - 0x00000000, - 0x00000000, - 0x00000000 -}; - -/* - * DR0-3 = linear address of breakpoint 0-3 - * DR4=5 = reserved - * DR6 b0-b3 = BP active - * b13 = BD - * b14 = BS - * b15 = BT - * DR7 b0-b1 = G:L bp#0 - * b2-b3 = G:L bp#1 - * b4-b5 = G:L bp#2 - * b6-b7 = G:L bp#3 - * b8-b9 = GE:LE - * b13 = GD - * b16-19= LLRW bp#0 LL=00(1),01(2),11(4) - * b20-23= LLRW bp#1 RW=00(x),01(w),11(rw) - * b24-27= LLRW bp#2 - * b28-31= LLRW bp#3 - */ -unsigned long DRs[8] = -{ - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0xffff1ff0, - 0x00000400, - 0xffff1ff0, - 0x00000400 -}; - -unsigned long TRs[2] = -{ - 0x00000000, - 0x00000000 -}; - -void FatalAppExit(UINT wAction, LPCSTR lpText) -{ - fprintf(stderr, "Fatal error '%s' in CPU\n", lpText); - exit(1); -} - -int e_debug_check(unsigned char *PC) -{ - register unsigned long d7 = DRs[7]; - - if (d7&0x03) { - if (d7&0x30000) return 0; /* only execute(00) bkp */ - if ((long)PC==DRs[0]) { - e_printf("DBRK: DR0 hit at %p\n",PC); - DRs[6] |= 1; - return 1; - } - } - if (d7&0x0c) { - if (d7&0x300000) return 0; - if ((long)PC==DRs[1]) { - e_printf("DBRK: DR1 hit at %p\n",PC); - DRs[6] |= 2; - return 1; - } - } - if (d7&0x30) { - if (d7&0x3000000) return 0; - if ((long)PC==DRs[2]) { - e_printf("DBRK: DR2 hit at %p\n",PC); - DRs[6] |= 4; - return 1; - } - } - if (d7&0xc0) { - if (d7&0x30000000) return 0; - if ((long)PC==DRs[3]) { - e_printf("DBRK: DR3 hit at %p\n",PC); - DRs[6] |= 8; - return 1; - } - } - return 0; -} - -/* Debug stuff */ -void logstr(unsigned long mask, const char *fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -/* unconditional message into debug log and stderr */ -#undef error -void error(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} - -int PortIO(DWORD port, DWORD value, UINT size, BOOL is_write) -{ - fprintf(stderr, "IO: %s port=0x%lx value=0x%lx size=%d", - is_write ? "write" : "read", port, value, size); - return value; -} - -void LogProcName(WORD wSel, WORD wOff, WORD wAction) -{ - -} - -void INT_handler(int num, void *env) -{ - fprintf(stderr, "EM86: int %d\n", num); -} - /***********************************************************/ -/* new CPU core */ +/* CPUX86 core interface */ void cpu_x86_outb(int addr, int val) { @@ -245,7 +94,7 @@ int main(int argc, char **argv) const char *filename; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; - Interp_ENV *env; + CPUX86State *env; if (argc <= 1) usage(); @@ -277,26 +126,25 @@ int main(int argc, char **argv) target_set_brk((char *)info->brk); syscall_init(); - env = &env_global; - envp_global = env; - memset(env, 0, sizeof(Interp_ENV)); + env = cpu_x86_init(); - env->rax.e = regs->eax; - env->rbx.e = regs->ebx; - env->rcx.e = regs->ecx; - env->rdx.e = regs->edx; - env->rsi.esi = regs->esi; - env->rdi.edi = regs->edi; - env->rbp.ebp = regs->ebp; - env->rsp.esp = regs->esp; - env->cs.cs = __USER_CS; - env->ds.ds = __USER_DS; - env->es.es = __USER_DS; - env->ss.ss = __USER_DS; - env->fs.fs = __USER_DS; - env->gs.gs = __USER_DS; - env->trans_addr = regs->eip; + env->regs[R_EAX] = regs->eax; + env->regs[R_EBX] = regs->ebx; + env->regs[R_ECX] = regs->ecx; + env->regs[R_EDX] = regs->edx; + env->regs[R_ESI] = regs->esi; + env->regs[R_EDI] = regs->edi; + env->regs[R_EBP] = regs->ebp; + env->regs[R_ESP] = regs->esp; + env->segs[R_CS] = __USER_CS; + env->segs[R_DS] = __USER_DS; + env->segs[R_ES] = __USER_DS; + env->segs[R_SS] = __USER_DS; + env->segs[R_FS] = __USER_DS; + env->segs[R_GS] = __USER_DS; + env->pc = regs->eip; +#if 0 LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; LDT[__USER_CS >> 3].dwSelLimit = 0xfffff; LDT[__USER_CS >> 3].lpSelBase = NULL; @@ -304,41 +152,34 @@ int main(int argc, char **argv) LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; LDT[__USER_DS >> 3].lpSelBase = NULL; - init_npu(); - build_decode_tables(); +#endif for(;;) { int err; uint8_t *pc; - - err = invoke_code32(env, -1); - env->trans_addr = env->return_addr; - pc = env->seg_regs[0] + env->trans_addr; + + err = cpu_x86_exec(env); switch(err) { case EXCP0D_GPF: + pc = (uint8_t *)env->pc; if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ - env->trans_addr += 2; - env->rax.e = do_syscall(env->rax.e, - env->rbx.e, - env->rcx.e, - env->rdx.e, - env->rsi.esi, - env->rdi.edi, - env->rbp.ebp); + env->pc += 2; + env->regs[R_EAX] = do_syscall(env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP]); } else { goto trap_error; } break; default: trap_error: - fprintf(stderr, "GEMU: Unknown error %d, aborting\n", err); -#ifndef NO_TRACE_MSGS - d_emu = 9; - fprintf(stderr, "%s\n%s\n", - e_print_cpuemu_regs(env, 1), - e_emu_disasm(env,pc,1)); -#endif + fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", + (long)env->pc, err); abort(); } } diff --git a/op-i386.c b/op-i386.c index 9443e172c7..451318af72 100644 --- a/op-i386.c +++ b/op-i386.c @@ -10,11 +10,6 @@ typedef signed long long int64_t; #define NULL 0 -typedef struct FILE FILE; - -extern FILE *stderr; -extern int fprintf(FILE *, const char *, ...); - #ifdef __i386__ register int T0 asm("esi"); register int T1 asm("ebx"); @@ -91,6 +86,7 @@ typedef struct CCTable { int (*compute_c)(void); /* return the C flag */ } CCTable; +/* NOTE: data are not static to force relocation generation by GCC */ extern CCTable cc_table[]; uint8_t parity_table[256] = { @@ -191,6 +187,14 @@ static inline int lshift(int x, int n) return x >> (-n); } +/* exception support */ +/* NOTE: not static to force relocation generation by GCC */ +void raise_exception(int exception_index) +{ + env->exception_index = exception_index; + longjmp(env->jmp_env, 1); +} + /* we define the various pieces of code used by the JIT */ #define REG EAX @@ -321,7 +325,6 @@ void OPPROTO op_decl_T0_cc(void) void OPPROTO op_testl_T0_T1_cc(void) { - CC_SRC = T0; CC_DST = T0 & T1; } @@ -555,6 +558,7 @@ void OPPROTO op_stl_T0_A0(void) /* jumps */ /* indirect jump */ + void OPPROTO op_jmp_T0(void) { PC = T0; @@ -565,6 +569,30 @@ void OPPROTO op_jmp_im(void) PC = PARAM1; } +void OPPROTO op_int_im(void) +{ + PC = PARAM1; + raise_exception(EXCP0D_GPF); +} + +void OPPROTO op_int3(void) +{ + PC = PARAM1; + raise_exception(EXCP03_INT3); +} + +void OPPROTO op_into(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_O) { + PC = PARAM1; + raise_exception(EXCP04_INTO); + } else { + PC = PARAM2; + } +} + /* string ops */ #define ldul ldl @@ -663,17 +691,19 @@ void OPPROTO op_jo_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_O) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jb_cc(void) { if (cc_table[CC_OP].compute_c()) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jz_cc(void) @@ -681,9 +711,10 @@ void OPPROTO op_jz_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_Z) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jbe_cc(void) @@ -691,9 +722,10 @@ void OPPROTO op_jbe_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & (CC_Z | CC_C)) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_js_cc(void) @@ -701,9 +733,10 @@ void OPPROTO op_js_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_S) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jp_cc(void) @@ -711,9 +744,10 @@ void OPPROTO op_jp_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_P) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jl_cc(void) @@ -721,9 +755,10 @@ void OPPROTO op_jl_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if ((eflags ^ (eflags >> 4)) & 0x80) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jle_cc(void) @@ -731,9 +766,10 @@ void OPPROTO op_jle_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } /* slow set cases (compute x86 flags) */ @@ -1600,14 +1636,13 @@ void OPPROTO op_fcos(void) /* main execution loop */ uint8_t code_gen_buffer[65536]; - int cpu_x86_exec(CPUX86State *env1) { int saved_T0, saved_T1, saved_A0; CPUX86State *saved_env; - int code_gen_size; + int code_gen_size, ret; void (*gen_func)(void); - + /* first we save global registers */ saved_T0 = T0; saved_T1 = T1; @@ -1615,17 +1650,21 @@ int cpu_x86_exec(CPUX86State *env1) saved_env = env; env = env1; - for(;;) { - cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); - /* execute the generated code */ - gen_func = (void *)code_gen_buffer; - gen_func(); + /* prepare setjmp context for exception handling */ + if (setjmp(env->jmp_env) == 0) { + for(;;) { + cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); + /* execute the generated code */ + gen_func = (void *)code_gen_buffer; + gen_func(); + } } - + ret = env->exception_index; + /* restore global registers */ T0 = saved_T0; T1 = saved_T1; A0 = saved_A0; env = saved_env; - return 0; + return ret; } diff --git a/ops_template.h b/ops_template.h index 18b2ffb492..c67fe0fd41 100644 --- a/ops_template.h +++ b/ops_template.h @@ -149,18 +149,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } void OPPROTO glue(op_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST != 0) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } @@ -171,18 +171,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } void OPPROTO glue(op_js_sub, SUFFIX)(void) { if (CC_DST & SIGN_MASK) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } @@ -193,9 +193,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } @@ -206,9 +206,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } diff --git a/translate-i386.c b/translate-i386.c index 9ebc81e2ce..eb621c3e72 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -5,12 +5,24 @@ #include #include +/* dump all code */ +#define DEBUG_DISAS +#define DEBUG_LOGFILE "/tmp/gemu.log" + +#ifdef DEBUG_DISAS +#include "dis-asm.h" +#endif + #define IN_OP_I386 #include "cpu-i386.h" static uint8_t *gen_code_ptr; int __op_param1, __op_param2, __op_param3; +#ifdef DEBUG_DISAS +static FILE *logfile = NULL; +#endif + /* supress that */ static void error(const char *fmt, ...) { @@ -704,6 +716,9 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ int reg1, reg2, opreg; int mod, rm, code; +#ifdef DEBUG_DISAS + fprintf(logfile, "modrm=0x%x\n", modrm); +#endif mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -716,6 +731,9 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (base == 4) { havesib = 1; code = ldub(s->pc++); +#ifdef DEBUG_DISAS + fprintf(logfile, "sib=0x%x\n", code); +#endif scale = (code >> 6) & 3; index = (code >> 3) & 7; base = code & 7; @@ -762,6 +780,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } else if (scale == 0 && disp == 0) { gen_op_movl_A0_reg[reg1](); } else { + gen_op_movl_A0_im(disp); gen_op_addl_A0_reg_sN[scale][reg1](); } } else { @@ -953,8 +972,10 @@ static void gen_setcc(DisasContext *s, int b) } } -/* return the size of the intruction. Return -1 if no insn found */ -int disas_insn(DisasContext *s, uint8_t *pc_start) +/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr + is set to true if the instruction sets the PC (last instruction of + a basic block) */ +long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) { int b, prefixes, aflag, dflag; int shift, ot; @@ -967,6 +988,9 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) // cur_pc = s->pc; /* for insn generation */ next_byte: b = ldub(s->pc); +#ifdef DEBUG_DISAS + fprintf(logfile, "ib=0x%02x\n", b); +#endif if (b < 0) return -1; s->pc++; @@ -1195,6 +1219,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mull_EAX_T0(); break; } + s->cc_op = CC_OP_MUL; break; case 5: /* imul */ switch(ot) { @@ -1209,6 +1234,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_imull_EAX_T0(); break; } + s->cc_op = CC_OP_MUL; break; case 6: /* div */ switch(ot) { @@ -1281,9 +1307,11 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 4: /* jmp Ev */ gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 6: /* push Ev */ gen_op_pushl_T0(); @@ -1362,6 +1390,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) op_imulw_T0_T1(); } gen_op_mov_reg_T0[ot][reg](); + s->cc_op = CC_OP_MUL; break; /**************************/ @@ -1418,10 +1447,14 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); mod = (modrm >> 6) & 3; - + if (mod != 3) + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); val = insn_get(s, ot); gen_op_movl_T0_im(val); - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + if (mod != 3) + gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][modrm & 7](); break; case 0x8a: case 0x8b: /* mov Ev, Gv */ @@ -2068,10 +2101,12 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_popl_T0(); gen_op_addl_ESP_im(val); gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 0xc3: /* ret */ gen_op_popl_T0(); gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 0xe8: /* call */ val = insn_get(s, OT_LONG); @@ -2079,16 +2114,19 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_im(val); + *is_jmp_ptr = 1; break; case 0xe9: /* jmp */ val = insn_get(s, OT_LONG); val += (long)s->pc; gen_op_jmp_im(val); + *is_jmp_ptr = 1; break; case 0xeb: /* jmp Jb */ val = (int8_t)insn_get(s, OT_BYTE); val += (long)s->pc; gen_op_jmp_im(val); + *is_jmp_ptr = 1; break; case 0x70 ... 0x7f: /* jcc Jb */ val = (int8_t)insn_get(s, OT_BYTE); @@ -2103,6 +2141,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) val += (long)s->pc; /* XXX: fix 16 bit wrap */ do_jcc: gen_jcc(s, b, val); + *is_jmp_ptr = 1; break; case 0x190 ... 0x19f: @@ -2164,8 +2203,23 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) /* misc */ case 0x90: /* nop */ break; - -#if 0 + case 0xcc: /* int3 */ + gen_op_int3((long)pc_start); + *is_jmp_ptr = 1; + break; + case 0xcd: /* int N */ + val = ldub(s->pc++); + /* XXX: currently we ignore the interrupt number */ + gen_op_int_im((long)pc_start); + *is_jmp_ptr = 1; + break; + case 0xce: /* into */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_into((long)pc_start, (long)s->pc); + *is_jmp_ptr = 1; + break; +#if 0 case 0x1a2: /* cpuid */ gen_insn0(OP_ASM); break; @@ -2182,16 +2236,78 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, uint8_t *pc_start) { DisasContext dc1, *dc = &dc1; + int is_jmp; long ret; +#ifdef DEBUG_DISAS + struct disassemble_info disasm_info; +#endif + dc->cc_op = CC_OP_DYNAMIC; gen_code_ptr = gen_code_buf; gen_start(); - ret = disas_insn(dc, pc_start); + +#ifdef DEBUG_DISAS + if (!logfile) { + logfile = fopen(DEBUG_LOGFILE, "w"); + if (!logfile) { + perror(DEBUG_LOGFILE); + exit(1); + } + setvbuf(logfile, NULL, _IOLBF, 0); + } + + INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); + disasm_info.buffer = pc_start; + disasm_info.buffer_vma = (unsigned long)pc_start; + disasm_info.buffer_length = 15; +#if 0 + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); +#endif +#ifdef WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif + fprintf(logfile, "IN:\n"); + fprintf(logfile, "0x%08lx: ", (long)pc_start); + print_insn_i386((unsigned long)pc_start, &disasm_info); + fprintf(logfile, "\n\n"); +#endif + is_jmp = 0; + ret = disas_insn(dc, pc_start, &is_jmp); if (ret == -1) error("unknown instruction at PC=0x%x", pc_start); + /* we must store the eflags state if it is not already done */ + if (dc->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(dc->cc_op); + if (!is_jmp) { + /* we add an additionnal jmp to update the simulated PC */ + gen_op_jmp_im(ret); + } gen_end(); *gen_code_size_ptr = gen_code_ptr - gen_code_buf; - printf("0x%08lx: code_size = %d\n", (long)pc_start, *gen_code_size_ptr); + +#ifdef DEBUG_DISAS + { + uint8_t *pc; + int count; + + pc = gen_code_buf; + disasm_info.buffer = pc; + disasm_info.buffer_vma = (unsigned long)pc; + disasm_info.buffer_length = *gen_code_size_ptr; + fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); + while (pc < gen_code_ptr) { + fprintf(logfile, "0x%08lx: ", (long)pc); + count = print_insn_i386((unsigned long)pc, &disasm_info); + fprintf(logfile, "\n"); + pc += count; + } + fprintf(logfile, "\n"); + } +#endif return 0; }