Module: wine Branch: master Commit: 0a7827b8b2416d60eccd507c1e8c5137eea0bf11 URL: http://source.winehq.org/git/wine.git/?a=commit;h=0a7827b8b2416d60eccd507c1e...
Author: Alexandre Julliard julliard@winehq.org Date: Fri Mar 16 13:15:38 2012 +0100
dbghelp: Add support for jump instructions in function epilogs on x86_64.
---
dlls/dbghelp/cpu_x86_64.c | 47 ++++++++++++++++++++++++++++++++------------ 1 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/dlls/dbghelp/cpu_x86_64.c b/dlls/dbghelp/cpu_x86_64.c index 8de28ef..711c78c 100644 --- a/dlls/dbghelp/cpu_x86_64.c +++ b/dlls/dbghelp/cpu_x86_64.c @@ -290,9 +290,11 @@ static int get_opcode_size(UNWIND_CODE op) } }
-static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc) +static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc, + DWORD64 base, const RUNTIME_FUNCTION *function ) { - BYTE op0, op1, op2; + BYTE op0, op1, op2; + LONG val32;
if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
@@ -338,12 +340,9 @@ static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc) /* now check for various pop instructions */ for (;;) { - BYTE rex = 0; - if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE; - if ((op0 & 0xf0) == 0x40) + if ((op0 & 0xf0) == 0x40) /* rex prefix */ { - rex = op0 & 0x0f; /* rex prefix */ if (!sw_read_mem(csw, ++pc, &op0, 1)) return FALSE; }
@@ -362,7 +361,21 @@ static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc) case 0xc2: /* ret $nn */ case 0xc3: /* ret */ return TRUE; - /* FIXME: add various jump instructions */ + case 0xe9: /* jmp nnnn */ + if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE; + pc += 5 + val32; + if (pc - base >= function->BeginAddress && pc - base < function->EndAddress) + continue; + break; + case 0xeb: /* jmp n */ + if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE; + pc += 2 + (signed char)op1; + if (pc - base >= function->BeginAddress && pc - base < function->EndAddress) + continue; + break; + case 0xf3: /* rep; ret (for amd64 prediction bug) */ + if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE; + return op1 == 0xc3; } return FALSE; } @@ -402,8 +415,8 @@ static BOOL interpret_epilog(struct cpu_stack_walk* csw, ULONG64 pc, CONTEXT *co pc++; continue; case 0x81: /* add $nnnn,%rsp */ - if (!sw_read_mem(csw, pc + 2, &val32, sizeof(ULONG))) return FALSE; - context->Rsp += (LONG)val32; + if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE; + context->Rsp += val32; pc += 2 + sizeof(LONG); continue; case 0x83: /* add $n,%rsp */ @@ -421,8 +434,8 @@ static BOOL interpret_epilog(struct cpu_stack_walk* csw, ULONG64 pc, CONTEXT *co } else /* lea nnnn(reg),%rsp */ { - if (!sw_read_mem(csw, pc + 2, &val32, sizeof(ULONG))) return FALSE; - context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + (LONG)val32; + if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE; + context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + val32; pc += 2 + sizeof(LONG); } continue; @@ -433,11 +446,19 @@ static BOOL interpret_epilog(struct cpu_stack_walk* csw, ULONG64 pc, CONTEXT *co context->Rsp += sizeof(ULONG64) + val16; return TRUE; case 0xc3: /* ret */ + case 0xf3: /* rep; ret */ if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE; context->Rip = val64; context->Rsp += sizeof(ULONG64); return TRUE; - /* FIXME: add various jump instructions */ + case 0xe9: /* jmp nnnn */ + if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE; + pc += 5 + val32; + continue; + case 0xeb: /* jmp n */ + if (!sw_read_mem(csw, pc + 1, &val8, sizeof(BYTE))) return FALSE; + pc += 2 + (signed char)val8; + continue; } FIXME("unsupported insn %x\n", insn); return FALSE; @@ -497,7 +518,7 @@ static BOOL interpret_function_table_entry(struct cpu_stack_walk* csw, else { prolog_offset = ~0; - if (is_inside_epilog(csw, context->Rip)) + if (is_inside_epilog(csw, context->Rip, base, function)) { interpret_epilog(csw, context->Rip, context); return TRUE;