summaryrefslogtreecommitdiff
path: root/gdb/dwarf2-frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/dwarf2-frame.c')
-rw-r--r--gdb/dwarf2-frame.c60
1 files changed, 59 insertions, 1 deletions
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 668500d26c9..4301dac5fb5 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -69,6 +69,9 @@ struct dwarf2_cie
/* True if a 'z' augmentation existed. */
unsigned char saw_z_augmentation;
+ /* The version recorded in the CIE. */
+ unsigned char version;
+
struct dwarf2_cie *next;
};
@@ -130,6 +133,16 @@ struct dwarf2_frame_state
LONGEST data_align;
ULONGEST code_align;
ULONGEST retaddr_column;
+
+ /* Flags for known producer quirks. */
+
+ /* The ARM compilers, in DWARF2 mode, assume that DW_CFA_def_cfa
+ and DW_CFA_def_cfa_offset takes a factored offset. */
+ int armcc_cfa_offsets_sf;
+
+ /* The ARM compilers, in DWARF2 or DWARF3 mode, assume that
+ the CFA is defined as REG - OFFSET rather than REG + OFFSET. */
+ int armcc_cfa_offsets_reversed;
};
/* Store the length the expression for the CFA in the `cfa_reg' field,
@@ -399,6 +412,10 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc));
case DW_CFA_def_cfa:
insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+
+ if (fs->armcc_cfa_offsets_sf)
+ utmp *= fs->data_align;
+
fs->cfa_offset = utmp;
fs->cfa_how = CFA_REG_OFFSET;
break;
@@ -410,6 +427,10 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc));
case DW_CFA_def_cfa_offset:
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+
+ if (fs->armcc_cfa_offsets_sf)
+ utmp *= fs->data_align;
+
fs->cfa_offset = utmp;
/* cfa_how deliberately not set. */
break;
@@ -614,6 +635,36 @@ dwarf2_frame_signal_frame_p (struct gdbarch *gdbarch,
return 0;
return ops->signal_frame_p (gdbarch, next_frame);
}
+
+static void
+dwarf2_frame_find_quirks (struct dwarf2_frame_state *fs,
+ struct dwarf2_fde *fde)
+{
+ static const char *arm_idents[] = {
+ "ARM C Compiler, ADS",
+ "Thumb C Compiler, ADS",
+ "ARM C++ Compiler, ADS",
+ "Thumb C++ Compiler, ADS",
+ "ARM/Thumb C/C++ Compiler, RVCT"
+ };
+ int i;
+
+ struct symtab *s;
+
+ s = find_pc_symtab (fs->pc);
+ if (s == NULL || s->producer == NULL)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE (arm_idents); i++)
+ if (strncmp (s->producer, arm_idents[i], strlen (arm_idents[i])) == 0)
+ {
+ if (fde->cie->version == 1)
+ fs->armcc_cfa_offsets_sf = 1;
+
+ if (fde->cie->version == 1 || fde->cie->version == 3)
+ fs->armcc_cfa_offsets_reversed = 1;
+ }
+}
struct dwarf2_frame_cache
@@ -680,6 +731,9 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
fs->code_align = fde->cie->code_alignment_factor;
fs->retaddr_column = fde->cie->return_address_register;
+ /* Check for "quirks" - known bugs in producers. */
+ dwarf2_frame_find_quirks (fs, fde);
+
/* First decode all the insns in the CIE. */
execute_cfa_program (fde->cie->initial_instructions,
fde->cie->end, next_frame, fs);
@@ -696,7 +750,10 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
{
case CFA_REG_OFFSET:
cache->cfa = read_reg (next_frame, fs->cfa_reg);
- cache->cfa += fs->cfa_offset;
+ if (fs->armcc_cfa_offsets_reversed)
+ cache->cfa -= fs->cfa_offset;
+ else
+ cache->cfa += fs->cfa_offset;
break;
case CFA_EXP:
@@ -1454,6 +1511,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)
cie_version = read_1_byte (unit->abfd, buf);
if (cie_version != 1 && cie_version != 3)
return NULL;
+ cie->version = cie_version;
buf += 1;
/* Interpret the interesting bits of the augmentation. */