diff options
author | Daniel Jacobowitz <drow@false.org> | 2007-01-04 20:26:42 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2007-01-04 20:26:42 +0000 |
commit | 303b6f5dea757484ac8074bee1b4d5f7c897a997 (patch) | |
tree | 0ae6c7a147525bc1204424559e035ade47febafe /gdb/dwarf2-frame.c | |
parent | 2d0720d988230d947d5eee9245a7d2fc3f0eeb0a (diff) | |
download | gdb-303b6f5dea757484ac8074bee1b4d5f7c897a997.zip gdb-303b6f5dea757484ac8074bee1b4d5f7c897a997.tar.gz gdb-303b6f5dea757484ac8074bee1b4d5f7c897a997.tar.bz2 |
* buildsym.c (start_subfile): Handle producer.
(record_producer): New function.
* buildsym.h (struct subfile): Include producer.
(record_producer): New prototype.
* dwarf2-frame.c (struct dwarf2_cie): Add version and augmentation.
(struct dwarf2_frame_state): Add armcc_cfa_offsets_sf and
armcc_cfa_offsets_reversed.
(execute_cfa_program): Handle armcc_cfa_offsets_sf.
(dwarf2_frame_find_quirks): New function.
(dwarf2_frame_cache): Call it. Handle armcc_cfa_offsets_reversed.
(decode_frame_entry_1): Record the CIE version. Record the
augmentation. Skip armcc augmentations.
* dwarf2read.c (read_file_scope): Save the producer.
* symtab.h (struct symtab): Rename unused version member to
producer.
Diffstat (limited to 'gdb/dwarf2-frame.c')
-rw-r--r-- | gdb/dwarf2-frame.c | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 861e19d..2f3751b 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -64,6 +64,9 @@ struct dwarf2_cie gdb_byte *initial_instructions; gdb_byte *end; + /* Saved augmentation, in case it's needed later. */ + char *augmentation; + /* Encoding of addresses. */ gdb_byte encoding; @@ -73,6 +76,9 @@ struct dwarf2_cie /* True if an 'S' augmentation existed. */ unsigned char signal_frame; + /* The version recorded in the CIE. */ + unsigned char version; + struct dwarf2_cie *next; }; @@ -138,6 +144,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, may 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, @@ -430,6 +446,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; @@ -444,6 +464,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; @@ -715,6 +739,49 @@ dwarf2_frame_eh_frame_regnum (struct gdbarch *gdbarch, int regnum) return regnum; return ops->eh_frame_regnum (gdbarch, regnum); } + +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) + fs->armcc_cfa_offsets_reversed = 1; + + /* The reversed offset problem is present in some compilers + using DWARF3, but it was eventually fixed. Check the ARM + defined augmentations, which are in the format "armcc" followed + by a list of one-character options. The "+" option means + this problem is fixed (no quirk needed). If the armcc + augmentation is missing, the quirk is needed. */ + if (fde->cie->version == 3 + && (strncmp (fde->cie->augmentation, "armcc", 5) != 0 + || strchr (fde->cie->augmentation + 5, '+') == NULL)) + fs->armcc_cfa_offsets_reversed = 1; + + return; + } +} struct dwarf2_frame_cache @@ -781,6 +848,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, fde->eh_frame_p); @@ -798,7 +868,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: @@ -1584,12 +1657,18 @@ 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. */ - augmentation = (char *) buf; + cie->augmentation = augmentation = (char *) buf; buf += (strlen (augmentation) + 1); + /* Ignore armcc augmentations. We only use them for quirks, + and that doesn't happen until later. */ + if (strncmp (augmentation, "armcc", 5) == 0) + augmentation += strlen (augmentation); + /* The GCC 2.x "eh" augmentation has a pointer immediately following the augmentation string, so it must be handled first. */ |