diff options
Diffstat (limited to 'gdb/dwarf2-frame.c')
-rw-r--r-- | gdb/dwarf2-frame.c | 60 |
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. */ |