/* Summarise ctx into si, if possible. Returns True if successful.
This is taken to be just after ctx's loc advances; hence the
- summary is up to but not including the current loc.
+ summary is up to but not including the current loc. This works
+ on both x86 and amd64.
*/
static Bool summarise_context( /*OUT*/CfiSI* si,
Addr loc_start,
UnwindContext* ctx )
{
+ Int why = 0;
initCfiSI(si);
/* How to generate the CFA */
si->cfa_sprel = False;
si->cfa_off = ctx->cfa_offset;
} else {
+ why = 1;
goto failed;
}
case RR_Undef: _how = CFIR_UNKNOWN; _off = 0; break; \
case RR_Same: _how = CFIR_SAME; _off = 0; break; \
case RR_CFAoff: _how = CFIR_MEMCFAREL; _off = _ctxreg.coff; break; \
- default: goto failed; /* otherwise give up */ \
+ default: { why = 2; goto failed; } /* otherwise give up */ \
}
SUMMARISE_HOW(si->ra_how, si->ra_off, ctx->reg[RA_COL] );
# undef SUMMARISE_HOW
- /* on x86, it seems the old %esp value before the call is always
- the same as the CFA. Therefore ... */
+ /* on x86/amd64, it seems the old %{e,r}sp value before the call is
+ always the same as the CFA. Therefore ... */
si->sp_how = CFIR_CFAREL;
si->sp_off = 0;
- /* also, gcc says "Undef" for %ebp when it is unchanged. So .. */
+ /* also, gcc says "Undef" for %{e,r}bp when it is unchanged. So
+ .. */
if (ctx->reg[FP_COL].tag == RR_Undef)
si->fp_how = CFIR_SAME;
/* knock out some obviously stupid cases */
- if (si->ra_how == CFIR_SAME) goto failed;
+ if (si->ra_how == CFIR_SAME)
+ { why = 3; goto failed; }
/* bogus looking range? Note, we require that the difference is
representable in 32 bits. */
- if (loc_start >= ctx->loc) goto failed;
+ if (loc_start >= ctx->loc)
+ { why = 4; goto failed; }
if (ctx->loc - loc_start > 10000000 /* let's say */)
- goto failed;
+ { why = 5; goto failed; }
si->base = loc_start + ctx->initloc;
si->len = (UInt)(ctx->loc - loc_start);
failed:
VG_(printf)("summarise_context(loc_start = %p)"
- ": cannot summarise:\n ", loc_start);
+ ": cannot summarise(why=%d):\n ", loc_start, why);
ppUnwindContext(ctx);
return False;
}
return data[0];
}
-static UChar default_address_encoding ()
+static UChar default_Addr_encoding ()
{
switch (sizeof(Addr)) {
case 4: return DW_EH_PE_udata4;
}
}
-static UInt size_of_encoded_address ( UChar encoding )
+static UInt size_of_encoded_Addr ( UChar encoding )
{
if (encoding == DW_EH_PE_omit)
return 0;
}
}
-static Addr read_encoded_address ( UChar* data, UChar encoding, Int *nbytes,
- UChar* ehframe, Addr ehframe_addr )
+static Addr read_encoded_Addr ( UChar* data, UChar encoding, Int *nbytes,
+ UChar* ehframe, Addr ehframe_addr )
{
Addr base;
Int offset;
}
if ((encoding & 0x07) == 0x00)
- encoding |= default_address_encoding();
+ encoding |= default_Addr_encoding();
switch (encoding & 0x0f) {
case DW_EH_PE_udata2:
Returns 0 if the instruction could not be executed.
*/
static Int run_CF_instruction ( /*MOD*/UnwindContext* ctx,
- UChar* instr )
+ UChar* instr,
+ UnwindContext* restore_ctx )
{
Int off, reg, nleb;
UInt delta;
}
if (hi2 == DW_CFA_restore) {
- vg_assert(0);
- VG_(printf)("DW_CFA_restore(%d)\n", (Int)lo6);
+ reg = (Int)lo6;
+ if (reg < 0 || reg >= N_CFI_REGS)
+ return 0; /* fail */
+ if (restore_ctx == NULL)
+ return 0; /* fail */
+ ctx->reg[reg] = restore_ctx->reg[reg];
return i;
}
static
Bool run_CF_instructions ( SegInfo* si,
UnwindContext* ctx, UChar* instrs, Int ilen,
- UWord fde_arange )
+ UWord fde_arange,
+ UnwindContext* restore_ctx )
{
CfiSI cfisi;
loc_prev = ctx->loc;
if (i >= ilen) break;
if (0) (void)show_CF_instruction( &instrs[i] );
- j = run_CF_instruction( ctx, &instrs[i] );
+ j = run_CF_instruction( ctx, &instrs[i], restore_ctx );
if (j == 0)
return False; /* execution failed */
i += j;
void VG_(read_callframe_info_dwarf2)
( /*OUT*/SegInfo* si, UChar* ehframe, Int ehframe_sz, Addr ehframe_addr )
{
- UnwindContext ctx;
+ UnwindContext ctx, restore_ctx;
Int nbytes;
HChar* how = NULL;
Int cie_codeaf = 0;
UChar* cie_instrs = NULL;
Int cie_ilen = 0;
Bool saw_z_augmentation = False;
- UChar address_encoding = default_address_encoding();
+ UChar address_encoding = default_Addr_encoding();
if (VG_(clo_trace_cfi)) {
VG_(printf)("\n-----------------------------------------------\n");
cie_augmentation++;
break;
case 'P':
- data += size_of_encoded_address(address_encoding);
+ data += size_of_encoded_Addr( read_UChar(data) );
+ data++;
cie_augmentation++;
break;
default:
}
Addr fde_initloc
- = read_encoded_address(data, address_encoding,
- &nbytes, ehframe, ehframe_addr);
+ = read_encoded_Addr(data, address_encoding,
+ &nbytes, ehframe, ehframe_addr);
data += nbytes;
if (VG_(clo_trace_cfi))
VG_(printf)("fde.initloc = %p\n", (void*)fde_initloc);
UWord fde_arange
- = read_encoded_address(data, address_encoding & 0xf,
- &nbytes, ehframe, ehframe_addr);
+ = read_encoded_Addr(data, address_encoding & 0xf,
+ &nbytes, ehframe, ehframe_addr);
data += nbytes;
if (VG_(clo_trace_cfi))
VG_(printf)("fde.arangec = %p\n", (void*)fde_arange);
UChar* fde_instrs = data;
Int fde_ilen = ciefde_start + ciefde_len + sizeof(UInt) - data;
- if (VG_(clo_trace_cfi)) VG_(printf)("fde.instrs = %p\n", fde_instrs);
- if (VG_(clo_trace_cfi)) VG_(printf)("fde.ilen = %d\n", (Int)fde_ilen);
+ if (VG_(clo_trace_cfi)) {
+ VG_(printf)("fde.instrs = %p\n", fde_instrs);
+ VG_(printf)("fde.ilen = %d\n", (Int)fde_ilen);
+ }
if (fde_ilen < 0 || fde_ilen > ehframe_sz) {
how = "implausible # fde insns";
ctx.code_a_f = cie_codeaf;
ctx.data_a_f = cie_dataaf;
ctx.initloc = fde_initloc;
- ok = run_CF_instructions(NULL, &ctx, cie_instrs, cie_ilen, 0);
- if (ok)
- ok = run_CF_instructions(si, &ctx, fde_instrs, fde_ilen, fde_arange);
+
+ initUnwindContext(&restore_ctx);
+
+ ok = run_CF_instructions(
+ NULL, &ctx, cie_instrs, cie_ilen, 0, NULL);
+ if (ok) {
+ restore_ctx = ctx;
+ ok = run_CF_instructions(
+ si, &ctx, fde_instrs, fde_ilen, fde_arange,
+ &restore_ctx);
+ }
}
}