From: Ken Thomases Subject: [PATCH 1/4] dbghelp: Fix mapping of DWARF register numbers on x86 OS X. Message-Id: <1435542312-72473-1-git-send-email-ken@codeweavers.com> Date: Sun, 28 Jun 2015 20:45:09 -0500 For backward compatibility with old, buggy GCC, Apple uses a different register numbering scheme for the eh_frame section. See, for reference, the comments near the top of this file from LLDB's source: https://github.com/llvm-mirror/lldb/blob/release_36/source/Plugins/Process/Utility/RegisterContext_x86.h --- dlls/dbghelp/cpu_arm.c | 2 +- dlls/dbghelp/cpu_arm64.c | 2 +- dlls/dbghelp/cpu_i386.c | 15 ++++++++++++--- dlls/dbghelp/cpu_ppc.c | 2 +- dlls/dbghelp/cpu_x86_64.c | 2 +- dlls/dbghelp/dbghelp_private.h | 2 +- dlls/dbghelp/dwarf.c | 34 +++++++++++++++++----------------- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/dlls/dbghelp/cpu_arm.c b/dlls/dbghelp/cpu_arm.c index bd2c677..ca9bf99 100644 --- a/dlls/dbghelp/cpu_arm.c +++ b/dlls/dbghelp/cpu_arm.c @@ -150,7 +150,7 @@ static BOOL arm_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CON } #endif -static unsigned arm_map_dwarf_register(unsigned regno) +static unsigned arm_map_dwarf_register(unsigned regno, BOOL eh_frame) { if (regno <= 15) return CV_ARM_R0 + regno; if (regno == 128) return CV_ARM_CPSR; diff --git a/dlls/dbghelp/cpu_arm64.c b/dlls/dbghelp/cpu_arm64.c index 9c17e27..85d17da 100644 --- a/dlls/dbghelp/cpu_arm64.c +++ b/dlls/dbghelp/cpu_arm64.c @@ -150,7 +150,7 @@ static BOOL arm64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, C } #endif -static unsigned arm64_map_dwarf_register(unsigned regno) +static unsigned arm64_map_dwarf_register(unsigned regno, BOOL eh_frame) { if (regno <= 28) return CV_ARM64_X0 + regno; if (regno == 29) return CV_ARM64_FP; diff --git a/dlls/dbghelp/cpu_i386.c b/dlls/dbghelp/cpu_i386.c index 8a3c074..00745cb 100644 --- a/dlls/dbghelp/cpu_i386.c +++ b/dlls/dbghelp/cpu_i386.c @@ -513,7 +513,7 @@ done_err: return FALSE; } -static unsigned i386_map_dwarf_register(unsigned regno) +static unsigned i386_map_dwarf_register(unsigned regno, BOOL eh_frame) { unsigned reg; @@ -523,8 +523,17 @@ static unsigned i386_map_dwarf_register(unsigned regno) case 1: reg = CV_REG_ECX; break; case 2: reg = CV_REG_EDX; break; case 3: reg = CV_REG_EBX; break; - case 4: reg = CV_REG_ESP; break; - case 5: reg = CV_REG_EBP; break; + case 4: + case 5: +#ifdef __APPLE__ + /* On OS X, DWARF eh_frame uses a different mapping for the registers. It's + apparently the mapping as emitted by GCC, at least at some point in its history. */ + if (eh_frame) + reg = (regno == 4) ? CV_REG_EBP : CV_REG_ESP; + else +#endif + reg = (regno == 4) ? CV_REG_ESP : CV_REG_EBP; + break; case 6: reg = CV_REG_ESI; break; case 7: reg = CV_REG_EDI; break; case 8: reg = CV_REG_EIP; break; diff --git a/dlls/dbghelp/cpu_ppc.c b/dlls/dbghelp/cpu_ppc.c index 3b2a843..a481685 100644 --- a/dlls/dbghelp/cpu_ppc.c +++ b/dlls/dbghelp/cpu_ppc.c @@ -54,7 +54,7 @@ static BOOL ppc_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CON return FALSE; } -static unsigned ppc_map_dwarf_register(unsigned regno) +static unsigned ppc_map_dwarf_register(unsigned regno, BOOL eh_frame) { FIXME("not done\n"); return 0; diff --git a/dlls/dbghelp/cpu_x86_64.c b/dlls/dbghelp/cpu_x86_64.c index a5aa03f..99b5c17 100644 --- a/dlls/dbghelp/cpu_x86_64.c +++ b/dlls/dbghelp/cpu_x86_64.c @@ -722,7 +722,7 @@ static void* x86_64_find_runtime_function(struct module* module, DWORD64 addr return NULL; } -static unsigned x86_64_map_dwarf_register(unsigned regno) +static unsigned x86_64_map_dwarf_register(unsigned regno, BOOL eh_frame) { unsigned reg; diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 827cfa6..5a38dbe 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -530,7 +530,7 @@ struct cpu void* (*find_runtime_function)(struct module*, DWORD64 addr); /* dwarf dedicated information */ - unsigned (*map_dwarf_register)(unsigned regno); + unsigned (*map_dwarf_register)(unsigned regno, BOOL eh_frame); /* context related manipulation */ void* (*fetch_context_reg)(CONTEXT* context, unsigned regno, unsigned* size); diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 03eb43b..9e0c7d1 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -649,7 +649,7 @@ static unsigned dwarf2_map_register(int regno) FIXME("What the heck map reg 0x%x\n",regno); return 0; } - return dbghelp_current_cpu->map_dwarf_register(regno); + return dbghelp_current_cpu->map_dwarf_register(regno, FALSE); } static enum location_error @@ -2784,7 +2784,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_offset %s, %ld\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg)), + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE)), offset); info->state.regs[reg] = offset; info->state.rules[reg] = RULE_CFA_OFFSET; @@ -2796,7 +2796,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_restore %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg))); + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE))); info->state.rules[reg] = RULE_UNSET; break; } @@ -2843,7 +2843,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_offset_extended %s, %ld\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg)), + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE)), offset); info->state.regs[reg] = offset; info->state.rules[reg] = RULE_CFA_OFFSET; @@ -2855,7 +2855,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_restore_extended %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg))); + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE))); info->state.rules[reg] = RULE_UNSET; break; } @@ -2865,7 +2865,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_undefined %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg))); + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE))); info->state.rules[reg] = RULE_UNDEFINED; break; } @@ -2875,7 +2875,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_same_value %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg))); + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE))); info->state.regs[reg] = reg; info->state.rules[reg] = RULE_SAME; break; @@ -2887,8 +2887,8 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg) || !valid_reg(reg2)) break; TRACE("%lx: DW_CFA_register %s == %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg)), - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg2))); + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE)), + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg2, TRUE))); info->state.regs[reg] = reg2; info->state.rules[reg] = RULE_OTHER_REG; break; @@ -2916,7 +2916,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_def_cfa %s, %ld\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg)), + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE)), offset); info->state.cfa_reg = reg; info->state.cfa_offset = offset; @@ -2929,7 +2929,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_def_cfa_register %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg))); + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE))); info->state.cfa_reg = reg; info->state.cfa_rule = RULE_CFA_OFFSET; break; @@ -2963,7 +2963,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_%sexpression %s %lx-%lx\n", info->ip, (op == DW_CFA_expression) ? "" : "val_", - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg)), + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, TRUE)), expr, expr + len); info->state.regs[reg] = expr; info->state.rules[reg] = (op == DW_CFA_expression) ? RULE_EXPRESSION : RULE_VAL_EXPRESSION; @@ -2988,7 +2988,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx, /* retrieve a context register from its dwarf number */ static ULONG_PTR get_context_reg(CONTEXT *context, ULONG_PTR dw_reg) { - unsigned regno = dbghelp_current_cpu->map_dwarf_register(dw_reg), sz; + unsigned regno = dbghelp_current_cpu->map_dwarf_register(dw_reg, TRUE), sz; ULONG_PTR* ptr = dbghelp_current_cpu->fetch_context_reg(context, regno, &sz); if (sz != sizeof(ULONG_PTR)) @@ -3003,7 +3003,7 @@ static ULONG_PTR get_context_reg(CONTEXT *context, ULONG_PTR dw_reg) static void set_context_reg(struct cpu_stack_walk* csw, CONTEXT *context, ULONG_PTR dw_reg, ULONG_PTR val, BOOL isdebuggee) { - unsigned regno = dbghelp_current_cpu->map_dwarf_register(dw_reg), sz; + unsigned regno = dbghelp_current_cpu->map_dwarf_register(dw_reg, TRUE), sz; ULONG_PTR* ptr = dbghelp_current_cpu->fetch_context_reg(context, regno, &sz); if (isdebuggee) @@ -3036,8 +3036,8 @@ static void set_context_reg(struct cpu_stack_walk* csw, CONTEXT *context, ULONG_ /* copy a register from one context to another using dwarf number */ static void copy_context_reg(CONTEXT *dstcontext, ULONG_PTR dwregdst, CONTEXT* srccontext, ULONG_PTR dwregsrc) { - unsigned regdstno = dbghelp_current_cpu->map_dwarf_register(dwregdst), szdst; - unsigned regsrcno = dbghelp_current_cpu->map_dwarf_register(dwregsrc), szsrc; + unsigned regdstno = dbghelp_current_cpu->map_dwarf_register(dwregdst, TRUE), szdst; + unsigned regsrcno = dbghelp_current_cpu->map_dwarf_register(dwregsrc, TRUE), szsrc; ULONG_PTR* ptrdst = dbghelp_current_cpu->fetch_context_reg(dstcontext, regdstno, &szdst); ULONG_PTR* ptrsrc = dbghelp_current_cpu->fetch_context_reg(srccontext, regsrcno, &szsrc); @@ -3258,7 +3258,7 @@ BOOL dwarf2_virtual_unwind(struct cpu_stack_walk* csw, ULONG_PTR ip, CONTEXT* co TRACE("function %lx/%lx code_align %lu data_align %ld retaddr %s\n", ip, info.ip, info.code_align, info.data_align, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(info.retaddr_reg))); + dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(info.retaddr_reg, TRUE))); /* if at very beginning of function, return and use default unwinder */ if (ip == info.ip) return FALSE; -- 2.4.3