dbghelp: Fix mapping of DWARF register numbers on x86 OS X.

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
This commit is contained in:
Ken Thomases 2015-06-28 20:45:09 -05:00 committed by Alexandre Julliard
parent d0ae2b0d3d
commit 83c1255f66
7 changed files with 34 additions and 25 deletions

View File

@ -150,7 +150,7 @@ static BOOL arm_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CON
} }
#endif #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 <= 15) return CV_ARM_R0 + regno;
if (regno == 128) return CV_ARM_CPSR; if (regno == 128) return CV_ARM_CPSR;

View File

@ -150,7 +150,7 @@ static BOOL arm64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, C
} }
#endif #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 <= 28) return CV_ARM64_X0 + regno;
if (regno == 29) return CV_ARM64_FP; if (regno == 29) return CV_ARM64_FP;

View File

@ -513,7 +513,7 @@ done_err:
return FALSE; return FALSE;
} }
static unsigned i386_map_dwarf_register(unsigned regno) static unsigned i386_map_dwarf_register(unsigned regno, BOOL eh_frame)
{ {
unsigned reg; unsigned reg;
@ -523,8 +523,17 @@ static unsigned i386_map_dwarf_register(unsigned regno)
case 1: reg = CV_REG_ECX; break; case 1: reg = CV_REG_ECX; break;
case 2: reg = CV_REG_EDX; break; case 2: reg = CV_REG_EDX; break;
case 3: reg = CV_REG_EBX; break; case 3: reg = CV_REG_EBX; break;
case 4: reg = CV_REG_ESP; break; case 4:
case 5: reg = CV_REG_EBP; break; 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 6: reg = CV_REG_ESI; break;
case 7: reg = CV_REG_EDI; break; case 7: reg = CV_REG_EDI; break;
case 8: reg = CV_REG_EIP; break; case 8: reg = CV_REG_EIP; break;

View File

@ -54,7 +54,7 @@ static BOOL ppc_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CON
return FALSE; 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"); FIXME("not done\n");
return 0; return 0;

View File

@ -722,7 +722,7 @@ static void* x86_64_find_runtime_function(struct module* module, DWORD64 addr
return NULL; 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; unsigned reg;

View File

@ -530,7 +530,7 @@ struct cpu
void* (*find_runtime_function)(struct module*, DWORD64 addr); void* (*find_runtime_function)(struct module*, DWORD64 addr);
/* dwarf dedicated information */ /* dwarf dedicated information */
unsigned (*map_dwarf_register)(unsigned regno); unsigned (*map_dwarf_register)(unsigned regno, BOOL eh_frame);
/* context related manipulation */ /* context related manipulation */
void* (*fetch_context_reg)(CONTEXT* context, unsigned regno, unsigned* size); void* (*fetch_context_reg)(CONTEXT* context, unsigned regno, unsigned* size);

View File

@ -649,7 +649,7 @@ static unsigned dwarf2_map_register(int regno)
FIXME("What the heck map reg 0x%x\n",regno); FIXME("What the heck map reg 0x%x\n",regno);
return 0; return 0;
} }
return dbghelp_current_cpu->map_dwarf_register(regno); return dbghelp_current_cpu->map_dwarf_register(regno, FALSE);
} }
static enum location_error static enum location_error
@ -2784,7 +2784,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg)) break; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_offset %s, %ld\n", TRACE("%lx: DW_CFA_offset %s, %ld\n",
info->ip, 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); offset);
info->state.regs[reg] = offset; info->state.regs[reg] = offset;
info->state.rules[reg] = RULE_CFA_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; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_restore %s\n", TRACE("%lx: DW_CFA_restore %s\n",
info->ip, 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; info->state.rules[reg] = RULE_UNSET;
break; break;
} }
@ -2843,7 +2843,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg)) break; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_offset_extended %s, %ld\n", TRACE("%lx: DW_CFA_offset_extended %s, %ld\n",
info->ip, 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); offset);
info->state.regs[reg] = offset; info->state.regs[reg] = offset;
info->state.rules[reg] = RULE_CFA_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; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_restore_extended %s\n", TRACE("%lx: DW_CFA_restore_extended %s\n",
info->ip, 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; info->state.rules[reg] = RULE_UNSET;
break; break;
} }
@ -2865,7 +2865,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg)) break; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_undefined %s\n", TRACE("%lx: DW_CFA_undefined %s\n",
info->ip, 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; info->state.rules[reg] = RULE_UNDEFINED;
break; break;
} }
@ -2875,7 +2875,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg)) break; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_same_value %s\n", TRACE("%lx: DW_CFA_same_value %s\n",
info->ip, 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.regs[reg] = reg;
info->state.rules[reg] = RULE_SAME; info->state.rules[reg] = RULE_SAME;
break; break;
@ -2887,8 +2887,8 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg) || !valid_reg(reg2)) break; if (!valid_reg(reg) || !valid_reg(reg2)) break;
TRACE("%lx: DW_CFA_register %s == %s\n", TRACE("%lx: DW_CFA_register %s == %s\n",
info->ip, 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)),
dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg2))); dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg2, TRUE)));
info->state.regs[reg] = reg2; info->state.regs[reg] = reg2;
info->state.rules[reg] = RULE_OTHER_REG; info->state.rules[reg] = RULE_OTHER_REG;
break; break;
@ -2916,7 +2916,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg)) break; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_def_cfa %s, %ld\n", TRACE("%lx: DW_CFA_def_cfa %s, %ld\n",
info->ip, 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); offset);
info->state.cfa_reg = reg; info->state.cfa_reg = reg;
info->state.cfa_offset = offset; info->state.cfa_offset = offset;
@ -2929,7 +2929,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg)) break; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_def_cfa_register %s\n", TRACE("%lx: DW_CFA_def_cfa_register %s\n",
info->ip, 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_reg = reg;
info->state.cfa_rule = RULE_CFA_OFFSET; info->state.cfa_rule = RULE_CFA_OFFSET;
break; break;
@ -2963,7 +2963,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
if (!valid_reg(reg)) break; if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_%sexpression %s %lx-%lx\n", TRACE("%lx: DW_CFA_%sexpression %s %lx-%lx\n",
info->ip, (op == DW_CFA_expression) ? "" : "val_", 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); expr, expr + len);
info->state.regs[reg] = expr; info->state.regs[reg] = expr;
info->state.rules[reg] = (op == DW_CFA_expression) ? RULE_EXPRESSION : RULE_VAL_EXPRESSION; 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 */ /* retrieve a context register from its dwarf number */
static ULONG_PTR get_context_reg(CONTEXT *context, ULONG_PTR dw_reg) 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); ULONG_PTR* ptr = dbghelp_current_cpu->fetch_context_reg(context, regno, &sz);
if (sz != sizeof(ULONG_PTR)) 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, static void set_context_reg(struct cpu_stack_walk* csw, CONTEXT *context, ULONG_PTR dw_reg,
ULONG_PTR val, BOOL isdebuggee) 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); ULONG_PTR* ptr = dbghelp_current_cpu->fetch_context_reg(context, regno, &sz);
if (isdebuggee) 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 */ /* 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) 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 regdstno = dbghelp_current_cpu->map_dwarf_register(dwregdst, TRUE), szdst;
unsigned regsrcno = dbghelp_current_cpu->map_dwarf_register(dwregsrc), szsrc; 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* ptrdst = dbghelp_current_cpu->fetch_context_reg(dstcontext, regdstno, &szdst);
ULONG_PTR* ptrsrc = dbghelp_current_cpu->fetch_context_reg(srccontext, regsrcno, &szsrc); 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", TRACE("function %lx/%lx code_align %lu data_align %ld retaddr %s\n",
ip, info.ip, info.code_align, info.data_align, 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 at very beginning of function, return and use default unwinder */
if (ip == info.ip) return FALSE; if (ip == info.ip) return FALSE;