X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fdwarf2-frame.c;h=33d001c799109b47bea2f55ad782ad53ecc4dec8;hb=dde59185267c8f3df6c3aa19d132277f45143c79;hp=ef0d6266fd83179886f0bd21a584f06ec6a523e7;hpb=77e0b926c11f74a3f7d4029dcdde8e5e722f0cae;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index ef0d6266fd..33d001c799 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -1,6 +1,7 @@ /* Frame unwinder for frames with DWARF Call Frame Information. - Copyright 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Contributed by Mark Kettenis. @@ -8,7 +9,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,13 +18,11 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "dwarf2expr.h" -#include "elf/dwarf2.h" +#include "dwarf2.h" #include "frame.h" #include "frame-base.h" #include "frame-unwind.h" @@ -32,6 +31,7 @@ #include "symtab.h" #include "objfiles.h" #include "regcache.h" +#include "value.h" #include "gdb_assert.h" #include "gdb_string.h" @@ -39,12 +39,17 @@ #include "complaints.h" #include "dwarf2-frame.h" +struct comp_unit; + /* Call Frame Information (CFI). */ /* Common Information Entry (CIE). */ struct dwarf2_cie { + /* Computation Unit for this CIE. */ + struct comp_unit *unit; + /* Offset into the .debug_frame section where this CIE was found. Used to identify this CIE. */ ULONGEST cie_pointer; @@ -63,13 +68,32 @@ 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; + /* Target address size in bytes. */ + int addr_size; + /* True if a 'z' augmentation existed. */ unsigned char saw_z_augmentation; - struct dwarf2_cie *next; + /* True if an 'S' augmentation existed. */ + unsigned char signal_frame; + + /* The version recorded in the CIE. */ + unsigned char version; + + /* The segment size. */ + unsigned char segment_size; +}; + +struct dwarf2_cie_table +{ + int num_entries; + struct dwarf2_cie **entries; }; /* Frame Description Entry (FDE). */ @@ -89,10 +113,52 @@ struct dwarf2_fde gdb_byte *instructions; gdb_byte *end; - struct dwarf2_fde *next; + /* True if this FDE is read from a .eh_frame instead of a .debug_frame + section. */ + unsigned char eh_frame_p; +}; + +struct dwarf2_fde_table +{ + int num_entries; + struct dwarf2_fde **entries; +}; + +/* A minimal decoding of DWARF2 compilation units. We only decode + what's needed to get to the call frame information. */ + +struct comp_unit +{ + /* Keep the bfd convenient. */ + bfd *abfd; + + struct objfile *objfile; + + /* Pointer to the .debug_frame section loaded into memory. */ + gdb_byte *dwarf_frame_buffer; + + /* Length of the loaded .debug_frame section. */ + bfd_size_type dwarf_frame_size; + + /* Pointer to the .debug_frame section. */ + asection *dwarf_frame_section; + + /* Base for DW_EH_PE_datarel encodings. */ + bfd_vma dbase; + + /* Base for DW_EH_PE_textrel encodings. */ + bfd_vma tbase; }; static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc); + +static int dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, + int eh_frame_p); + +static CORE_ADDR read_encoded_value (struct comp_unit *unit, gdb_byte encoding, + int ptr_len, gdb_byte *buf, + unsigned int *bytes_read_ptr, + CORE_ADDR func_base); /* Structure describing a frame state. */ @@ -106,19 +172,19 @@ struct dwarf2_frame_state struct dwarf2_frame_state_reg *reg; int num_regs; + LONGEST cfa_offset; + ULONGEST cfa_reg; + enum { + CFA_UNSET, + CFA_REG_OFFSET, + CFA_EXP + } cfa_how; + gdb_byte *cfa_exp; + /* Used to implement DW_CFA_remember_state. */ struct dwarf2_frame_state_reg_info *prev; } regs; - LONGEST cfa_offset; - ULONGEST cfa_reg; - gdb_byte *cfa_exp; - enum { - CFA_UNSET, - CFA_REG_OFFSET, - CFA_EXP - } cfa_how; - /* The PC described by the current frame state. */ CORE_ADDR pc; @@ -130,13 +196,23 @@ 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, which is unused in that case. */ #define cfa_exp_len cfa_reg -/* Assert that the register set RS is large enough to store NUM_REGS +/* Assert that the register set RS is large enough to store gdbarch_num_regs columns. If necessary, enlarge the register set. */ static void @@ -205,16 +281,22 @@ dwarf2_frame_state_free (void *p) static CORE_ADDR read_reg (void *baton, int reg) { - struct frame_info *next_frame = (struct frame_info *) baton; - struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct frame_info *this_frame = (struct frame_info *) baton; + struct gdbarch *gdbarch = get_frame_arch (this_frame); int regnum; gdb_byte *buf; - regnum = DWARF2_REG_TO_REGNUM (reg); + regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg); buf = alloca (register_size (gdbarch, regnum)); - frame_unwind_register (next_frame, regnum, buf); - return extract_typed_address (buf, builtin_type_void_data_ptr); + get_frame_register (this_frame, regnum, buf); + + /* Convert the register to an integer. This returns a LONGEST + rather than a CORE_ADDR, but unpack_pointer does the same thing + under the covers, and this makes more sense for non-pointer + registers. Maybe read_reg and the associated interfaces should + deal with "struct value" instead of CORE_ADDR. */ + return unpack_long (register_type (gdbarch, regnum), buf); } static void @@ -230,6 +312,15 @@ no_get_frame_base (void *baton, gdb_byte **start, size_t *length) _("Support for DW_OP_fbreg is unimplemented")); } +/* Helper function for execute_stack_op. */ + +static CORE_ADDR +no_get_frame_cfa (void *baton) +{ + internal_error (__FILE__, __LINE__, + _("Support for DW_OP_call_frame_cfa is unimplemented")); +} + static CORE_ADDR no_get_tls_address (void *baton, CORE_ADDR offset) { @@ -237,40 +328,87 @@ no_get_tls_address (void *baton, CORE_ADDR offset) _("Support for DW_OP_GNU_push_tls_address is unimplemented")); } +/* Execute the required actions for both the DW_CFA_restore and +DW_CFA_restore_extended instructions. */ +static void +dwarf2_restore_rule (struct gdbarch *gdbarch, ULONGEST reg_num, + struct dwarf2_frame_state *fs, int eh_frame_p) +{ + ULONGEST reg; + + gdb_assert (fs->initial.reg); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg_num, eh_frame_p); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + + /* Check if this register was explicitly initialized in the + CIE initial instructions. If not, default the rule to + UNSPECIFIED. */ + if (reg < fs->initial.num_regs) + fs->regs.reg[reg] = fs->initial.reg[reg]; + else + fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNSPECIFIED; + + if (fs->regs.reg[reg].how == DWARF2_FRAME_REG_UNSPECIFIED) + complaint (&symfile_complaints, _("\ +incomplete CFI data; DW_CFA_restore unspecified\n\ +register %s (#%d) at %s"), + gdbarch_register_name + (gdbarch, gdbarch_dwarf2_reg_to_regnum (gdbarch, reg)), + gdbarch_dwarf2_reg_to_regnum (gdbarch, reg), + paddress (gdbarch, fs->pc)); +} + static CORE_ADDR -execute_stack_op (gdb_byte *exp, ULONGEST len, - struct frame_info *next_frame, CORE_ADDR initial) +execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size, + struct frame_info *this_frame, CORE_ADDR initial, + int initial_in_stack_memory) { struct dwarf_expr_context *ctx; CORE_ADDR result; + struct cleanup *old_chain; ctx = new_dwarf_expr_context (); - ctx->baton = next_frame; + old_chain = make_cleanup_free_dwarf_expr_context (ctx); + + ctx->gdbarch = get_frame_arch (this_frame); + ctx->addr_size = addr_size; + ctx->baton = this_frame; ctx->read_reg = read_reg; ctx->read_mem = read_mem; ctx->get_frame_base = no_get_frame_base; + ctx->get_frame_cfa = no_get_frame_cfa; ctx->get_tls_address = no_get_tls_address; - dwarf_expr_push (ctx, initial); + dwarf_expr_push (ctx, initial, initial_in_stack_memory); dwarf_expr_eval (ctx, exp, len); result = dwarf_expr_fetch (ctx, 0); - if (ctx->in_reg) - result = read_reg (next_frame, result); + if (ctx->location == DWARF_VALUE_REGISTER) + result = read_reg (this_frame, result); + else if (ctx->location != DWARF_VALUE_MEMORY) + { + /* This is actually invalid DWARF, but if we ever do run across + it somehow, we might as well support it. So, instead, report + it as unimplemented. */ + error (_("Not implemented: computing unwound register using explicit value operator")); + } - free_dwarf_expr_context (ctx); + do_cleanups (old_chain); return result; } static void -execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end, - struct frame_info *next_frame, +execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr, + gdb_byte *insn_end, struct frame_info *this_frame, struct dwarf2_frame_state *fs) { - CORE_ADDR pc = frame_pc_unwind (next_frame); + int eh_frame_p = fde->eh_frame_p; + CORE_ADDR pc = get_frame_pc (this_frame); int bytes_read; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); while (insn_ptr < insn_end && fs->pc <= pc) { @@ -283,6 +421,7 @@ execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end, else if ((insn & 0xc0) == DW_CFA_offset) { reg = insn & 0x3f; + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); offset = utmp * fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); @@ -291,38 +430,42 @@ execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end, } else if ((insn & 0xc0) == DW_CFA_restore) { - gdb_assert (fs->initial.reg); reg = insn & 0x3f; - dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - fs->regs.reg[reg] = fs->initial.reg[reg]; + dwarf2_restore_rule (gdbarch, reg, fs, eh_frame_p); } else { switch (insn) { case DW_CFA_set_loc: - fs->pc = dwarf2_read_address (insn_ptr, insn_end, &bytes_read); + fs->pc = read_encoded_value (fde->cie->unit, fde->cie->encoding, + fde->cie->addr_size, insn_ptr, + &bytes_read, fde->initial_location); + /* Apply the objfile offset for relocatable objects. */ + fs->pc += ANOFFSET (fde->cie->unit->objfile->section_offsets, + SECT_OFF_TEXT (fde->cie->unit->objfile)); insn_ptr += bytes_read; break; case DW_CFA_advance_loc1: - utmp = extract_unsigned_integer (insn_ptr, 1); + utmp = extract_unsigned_integer (insn_ptr, 1, byte_order); fs->pc += utmp * fs->code_align; insn_ptr++; break; case DW_CFA_advance_loc2: - utmp = extract_unsigned_integer (insn_ptr, 2); + utmp = extract_unsigned_integer (insn_ptr, 2, byte_order); fs->pc += utmp * fs->code_align; insn_ptr += 2; break; case DW_CFA_advance_loc4: - utmp = extract_unsigned_integer (insn_ptr, 4); + utmp = extract_unsigned_integer (insn_ptr, 4, byte_order); fs->pc += utmp * fs->code_align; insn_ptr += 4; break; case DW_CFA_offset_extended: insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); offset = utmp * fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); @@ -331,27 +474,29 @@ execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end, break; case DW_CFA_restore_extended: - gdb_assert (fs->initial.reg); insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); - dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - fs->regs.reg[reg] = fs->initial.reg[reg]; + dwarf2_restore_rule (gdbarch, reg, fs, eh_frame_p); break; case DW_CFA_undefined: insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNDEFINED; break; case DW_CFA_same_value: insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAME_VALUE; break; case DW_CFA_register: insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + utmp = dwarf2_frame_adjust_regnum (gdbarch, utmp, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG; fs->regs.reg[reg].loc.reg = utmp; @@ -375,7 +520,8 @@ execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end, if (old_rs == NULL) { complaint (&symfile_complaints, _("\ -bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); +bad CFI data; mismatched DW_CFA_restore_state at %s"), + paddress (gdbarch, fs->pc)); } else { @@ -387,20 +533,31 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); break; case DW_CFA_def_cfa: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->regs.cfa_reg); insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); - fs->cfa_offset = utmp; - fs->cfa_how = CFA_REG_OFFSET; + + if (fs->armcc_cfa_offsets_sf) + utmp *= fs->data_align; + + fs->regs.cfa_offset = utmp; + fs->regs.cfa_how = CFA_REG_OFFSET; break; case DW_CFA_def_cfa_register: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg); - fs->cfa_how = CFA_REG_OFFSET; + insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->regs.cfa_reg); + fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, + fs->regs.cfa_reg, + eh_frame_p); + fs->regs.cfa_how = CFA_REG_OFFSET; break; case DW_CFA_def_cfa_offset: insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); - fs->cfa_offset = utmp; + + if (fs->armcc_cfa_offsets_sf) + utmp *= fs->data_align; + + fs->regs.cfa_offset = utmp; /* cfa_how deliberately not set. */ break; @@ -408,14 +565,16 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); break; case DW_CFA_def_cfa_expression: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_exp_len); - fs->cfa_exp = insn_ptr; - fs->cfa_how = CFA_EXP; - insn_ptr += fs->cfa_exp_len; + insn_ptr = read_uleb128 (insn_ptr, insn_end, + &fs->regs.cfa_exp_len); + fs->regs.cfa_exp = insn_ptr; + fs->regs.cfa_how = CFA_EXP; + insn_ptr += fs->regs.cfa_exp_len; break; case DW_CFA_expression: insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); fs->regs.reg[reg].loc.exp = insn_ptr; @@ -426,6 +585,7 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); case DW_CFA_offset_extended_sf: insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); offset *= fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); @@ -433,16 +593,47 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); fs->regs.reg[reg].loc.offset = offset; break; + case DW_CFA_val_offset: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + offset = utmp * fs->data_align; + fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_OFFSET; + fs->regs.reg[reg].loc.offset = offset; + break; + + case DW_CFA_val_offset_sf: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); + offset *= fs->data_align; + fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_OFFSET; + fs->regs.reg[reg].loc.offset = offset; + break; + + case DW_CFA_val_expression: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + fs->regs.reg[reg].loc.exp = insn_ptr; + fs->regs.reg[reg].exp_len = utmp; + fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_EXP; + insn_ptr += utmp; + break; + case DW_CFA_def_cfa_sf: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->regs.cfa_reg); + fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, + fs->regs.cfa_reg, + eh_frame_p); insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); - fs->cfa_offset = offset * fs->data_align; - fs->cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_offset = offset * fs->data_align; + fs->regs.cfa_how = CFA_REG_OFFSET; break; case DW_CFA_def_cfa_offset_sf: insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); - fs->cfa_offset = offset * fs->data_align; + fs->regs.cfa_offset = offset * fs->data_align; /* cfa_how deliberately not set. */ break; @@ -455,8 +646,7 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); Incidentally that's what GCC does too in its unwinder. */ { - struct gdbarch *gdbarch = get_frame_arch (next_frame); - int size = register_size(gdbarch, 0); + int size = register_size (gdbarch, 0); dwarf2_frame_state_alloc_regs (&fs->regs, 32); for (reg = 8; reg < 16; reg++) { @@ -476,6 +666,16 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); break; + case DW_CFA_GNU_negative_offset_extended: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &offset); + offset *= fs->data_align; + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; + fs->regs.reg[reg].loc.offset = -offset; + break; + default: internal_error (__FILE__, __LINE__, _("Unknown CFI encountered.")); } @@ -496,11 +696,15 @@ static struct gdbarch_data *dwarf2_frame_data; struct dwarf2_frame_ops { /* Pre-initialize the register state REG for register REGNUM. */ - void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *); + void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *, + struct frame_info *); - /* Check whether the frame preceding NEXT_FRAME will be a signal - trampoline. */ + /* Check whether the THIS_FRAME is a signal trampoline. */ int (*signal_frame_p) (struct gdbarch *, struct frame_info *); + + /* Convert .eh_frame register number to DWARF register number, or + adjust .debug_frame register number. */ + int (*adjust_regnum) (struct gdbarch *, int, int); }; /* Default architecture-specific register state initialization @@ -508,7 +712,8 @@ struct dwarf2_frame_ops static void dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum, - struct dwarf2_frame_state_reg *reg) + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) { /* If we have a register that acts as a program counter, mark it as a destination for the return address. If we have a register that @@ -536,9 +741,9 @@ dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum, (e.g. IBM S/390 and zSeries). Those architectures should provide their own architecture-specific initialization function. */ - if (regnum == PC_REGNUM) + if (regnum == gdbarch_pc_regnum (gdbarch)) reg->how = DWARF2_FRAME_REG_RA; - else if (regnum == SP_REGNUM) + else if (regnum == gdbarch_sp_regnum (gdbarch)) reg->how = DWARF2_FRAME_REG_CFA; } @@ -560,7 +765,8 @@ dwarf2_frame_init (struct obstack *obstack) void dwarf2_frame_set_init_reg (struct gdbarch *gdbarch, void (*init_reg) (struct gdbarch *, int, - struct dwarf2_frame_state_reg *)) + struct dwarf2_frame_state_reg *, + struct frame_info *)) { struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); @@ -571,11 +777,12 @@ dwarf2_frame_set_init_reg (struct gdbarch *gdbarch, static void dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, - struct dwarf2_frame_state_reg *reg) + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) { struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); - ops->init_reg (gdbarch, regnum, reg); + ops->init_reg (gdbarch, regnum, reg, this_frame); } /* Set the architecture-specific signal trampoline recognition @@ -592,17 +799,76 @@ dwarf2_frame_set_signal_frame_p (struct gdbarch *gdbarch, } /* Query the architecture-specific signal frame recognizer for - NEXT_FRAME. */ + THIS_FRAME. */ static int dwarf2_frame_signal_frame_p (struct gdbarch *gdbarch, - struct frame_info *next_frame) + struct frame_info *this_frame) { struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); if (ops->signal_frame_p == NULL) return 0; - return ops->signal_frame_p (gdbarch, next_frame); + return ops->signal_frame_p (gdbarch, this_frame); +} + +/* Set the architecture-specific adjustment of .eh_frame and .debug_frame + register numbers. */ + +void +dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch, + int (*adjust_regnum) (struct gdbarch *, + int, int)) +{ + struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); + + ops->adjust_regnum = adjust_regnum; +} + +/* Translate a .eh_frame register to DWARF register, or adjust a .debug_frame + register. */ + +static int +dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, int eh_frame_p) +{ + struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); + + if (ops->adjust_regnum == NULL) + return regnum; + return ops->adjust_regnum (gdbarch, regnum, eh_frame_p); +} + +static void +dwarf2_frame_find_quirks (struct dwarf2_frame_state *fs, + struct dwarf2_fde *fde) +{ + struct symtab *s; + + s = find_pc_symtab (fs->pc); + if (s == NULL) + return; + + if (producer_is_realview (s->producer)) + { + 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; + } } @@ -620,14 +886,18 @@ struct dwarf2_frame_cache /* Return address register. */ struct dwarf2_frame_state_reg retaddr_reg; + + /* Target address size in bytes. */ + int addr_size; }; static struct dwarf2_frame_cache * -dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) +dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) { struct cleanup *old_chain; - struct gdbarch *gdbarch = get_frame_arch (next_frame); - const int num_regs = NUM_REGS + NUM_PSEUDO_REGS; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + const int num_regs = gdbarch_num_regs (gdbarch) + + gdbarch_num_pseudo_regs (gdbarch); struct dwarf2_frame_cache *cache; struct dwarf2_frame_state *fs; struct dwarf2_fde *fde; @@ -646,9 +916,9 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) /* Unwind the PC. - Note that if NEXT_FRAME is never supposed to return (i.e. a call + Note that if the next frame is never supposed to return (i.e. a call to abort), the compiler might optimize away the instruction at - NEXT_FRAME's return address. As a result the return address will + its return address. As a result the return address will point at some random instruction, and the CFI for that instruction is probably worthless to us. GCC's unwinder solves this problem by substracting 1 from the return address to get an @@ -656,10 +926,10 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) instruction in the associated delay slot). This should only be done for "normal" frames and not for resume-type frames (signal handlers, sentinel frames, dummy frames). The function - frame_unwind_address_in_block does just this. It's not clear how + get_frame_address_in_block does just this. It's not clear how reliable the method is though; there is the potential for the register state pre-call being different to that on return. */ - fs->pc = frame_unwind_address_in_block (next_frame); + fs->pc = get_frame_address_in_block (this_frame); /* Find the correct FDE. */ fde = dwarf2_frame_find_fde (&fs->pc); @@ -669,29 +939,37 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) fs->data_align = fde->cie->data_alignment_factor; fs->code_align = fde->cie->code_alignment_factor; fs->retaddr_column = fde->cie->return_address_register; + cache->addr_size = fde->cie->addr_size; + + /* 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); + execute_cfa_program (fde, fde->cie->initial_instructions, + fde->cie->end, this_frame, fs); /* Save the initialized register set. */ fs->initial = fs->regs; fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs); /* Then decode the insns in the FDE up to our target PC. */ - execute_cfa_program (fde->instructions, fde->end, next_frame, fs); + execute_cfa_program (fde, fde->instructions, fde->end, this_frame, fs); - /* Caclulate the CFA. */ - switch (fs->cfa_how) + /* Calculate the CFA. */ + switch (fs->regs.cfa_how) { case CFA_REG_OFFSET: - cache->cfa = read_reg (next_frame, fs->cfa_reg); - cache->cfa += fs->cfa_offset; + cache->cfa = read_reg (this_frame, fs->regs.cfa_reg); + if (fs->armcc_cfa_offsets_reversed) + cache->cfa -= fs->regs.cfa_offset; + else + cache->cfa += fs->regs.cfa_offset; break; case CFA_EXP: cache->cfa = - execute_stack_op (fs->cfa_exp, fs->cfa_exp_len, next_frame, 0); + execute_stack_op (fs->regs.cfa_exp, fs->regs.cfa_exp_len, + cache->addr_size, this_frame, 0, 0); break; default: @@ -703,7 +981,7 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) int regnum; for (regnum = 0; regnum < num_regs; regnum++) - dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum]); + dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum], this_frame); } /* Go through the DWARF2 CFI generated table and save its register @@ -711,15 +989,15 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) return address column; it's perfectly all right for it to correspond to a real register. If it doesn't correspond to a real register, or if we shouldn't treat it as such, - DWARF2_REG_TO_REGNUM should be defined to return a number outside - the range [0, NUM_REGS). */ + gdbarch_dwarf2_reg_to_regnum should be defined to return a number outside + the range [0, gdbarch_num_regs). */ { int column; /* CFI speak for "register number". */ for (column = 0; column < fs->regs.num_regs; column++) { /* Use the GDB register number as the destination index. */ - int regnum = DWARF2_REG_TO_REGNUM (column); + int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, column); /* If there's no corresponding GDB register, ignore it. */ if (regnum < 0 || regnum >= num_regs) @@ -740,9 +1018,9 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) { if (cache->reg[regnum].how == DWARF2_FRAME_REG_UNSPECIFIED) complaint (&symfile_complaints, _("\ -incomplete CFI data; unspecified registers (e.g., %s) at 0x%s"), +incomplete CFI data; unspecified registers (e.g., %s) at %s"), gdbarch_register_name (gdbarch, regnum), - paddr_nz (fs->pc)); + paddress (gdbarch, fs->pc)); } else cache->reg[regnum] = fs->regs.reg[column]; @@ -806,80 +1084,59 @@ incomplete CFI data; unspecified registers (e.g., %s) at 0x%s"), } static void -dwarf2_frame_this_id (struct frame_info *next_frame, void **this_cache, +dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id) { struct dwarf2_frame_cache *cache = - dwarf2_frame_cache (next_frame, this_cache); + dwarf2_frame_cache (this_frame, this_cache); if (cache->undefined_retaddr) return; - (*this_id) = frame_id_build (cache->cfa, frame_func_unwind (next_frame)); + (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); } -static void -dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, gdb_byte *valuep) +static struct value * +dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, + int regnum) { - struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct dwarf2_frame_cache *cache = - dwarf2_frame_cache (next_frame, this_cache); + dwarf2_frame_cache (this_frame, this_cache); + CORE_ADDR addr; + int realnum; switch (cache->reg[regnum].how) { case DWARF2_FRAME_REG_UNDEFINED: /* If CFI explicitly specified that the value isn't defined, mark it as optimized away; the value isn't available. */ - *optimizedp = 1; - *lvalp = not_lval; - *addrp = 0; - *realnump = -1; - if (valuep) - { - /* In some cases, for example %eflags on the i386, we have - to provide a sane value, even though this register wasn't - saved. Assume we can get it from NEXT_FRAME. */ - frame_unwind_register (next_frame, regnum, valuep); - } - break; + return frame_unwind_got_optimized (this_frame, regnum); case DWARF2_FRAME_REG_SAVED_OFFSET: - *optimizedp = 0; - *lvalp = lval_memory; - *addrp = cache->cfa + cache->reg[regnum].loc.offset; - *realnump = -1; - if (valuep) - { - /* Read the value in from memory. */ - read_memory (*addrp, valuep, register_size (gdbarch, regnum)); - } - break; + addr = cache->cfa + cache->reg[regnum].loc.offset; + return frame_unwind_got_memory (this_frame, regnum, addr); case DWARF2_FRAME_REG_SAVED_REG: - *optimizedp = 0; - *lvalp = lval_register; - *addrp = 0; - *realnump = DWARF2_REG_TO_REGNUM (cache->reg[regnum].loc.reg); - if (valuep) - frame_unwind_register (next_frame, (*realnump), valuep); - break; + realnum + = gdbarch_dwarf2_reg_to_regnum (gdbarch, cache->reg[regnum].loc.reg); + return frame_unwind_got_register (this_frame, regnum, realnum); case DWARF2_FRAME_REG_SAVED_EXP: - *optimizedp = 0; - *lvalp = lval_memory; - *addrp = execute_stack_op (cache->reg[regnum].loc.exp, - cache->reg[regnum].exp_len, - next_frame, cache->cfa); - *realnump = -1; - if (valuep) - { - /* Read the value in from memory. */ - read_memory (*addrp, valuep, register_size (gdbarch, regnum)); - } - break; + addr = execute_stack_op (cache->reg[regnum].loc.exp, + cache->reg[regnum].exp_len, + cache->addr_size, this_frame, cache->cfa, 1); + return frame_unwind_got_memory (this_frame, regnum, addr); + + case DWARF2_FRAME_REG_SAVED_VAL_OFFSET: + addr = cache->cfa + cache->reg[regnum].loc.offset; + return frame_unwind_got_constant (this_frame, regnum, addr); + + case DWARF2_FRAME_REG_SAVED_VAL_EXP: + addr = execute_stack_op (cache->reg[regnum].loc.exp, + cache->reg[regnum].exp_len, + cache->addr_size, this_frame, cache->cfa, 1); + return frame_unwind_got_constant (this_frame, regnum, addr); case DWARF2_FRAME_REG_UNSPECIFIED: /* GCC, in its infinite wisdom decided to not provide unwind @@ -889,88 +1146,86 @@ dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache, "undefined"). Code above issues a complaint about this. Here just fudge the books, assume GCC, and that the value is more inner on the stack. */ - *optimizedp = 0; - *lvalp = lval_register; - *addrp = 0; - *realnump = regnum; - if (valuep) - frame_unwind_register (next_frame, (*realnump), valuep); - break; + return frame_unwind_got_register (this_frame, regnum, regnum); case DWARF2_FRAME_REG_SAME_VALUE: - *optimizedp = 0; - *lvalp = lval_register; - *addrp = 0; - *realnump = regnum; - if (valuep) - frame_unwind_register (next_frame, (*realnump), valuep); - break; + return frame_unwind_got_register (this_frame, regnum, regnum); case DWARF2_FRAME_REG_CFA: - *optimizedp = 0; - *lvalp = not_lval; - *addrp = 0; - *realnump = -1; - if (valuep) - { - /* Store the value. */ - store_typed_address (valuep, builtin_type_void_data_ptr, cache->cfa); - } - break; + return frame_unwind_got_address (this_frame, regnum, cache->cfa); + + case DWARF2_FRAME_REG_CFA_OFFSET: + addr = cache->cfa + cache->reg[regnum].loc.offset; + return frame_unwind_got_address (this_frame, regnum, addr); case DWARF2_FRAME_REG_RA_OFFSET: - *optimizedp = 0; - *lvalp = not_lval; - *addrp = 0; - *realnump = -1; - if (valuep) - { - CORE_ADDR pc = cache->reg[regnum].loc.offset; + addr = cache->reg[regnum].loc.offset; + regnum = gdbarch_dwarf2_reg_to_regnum + (gdbarch, cache->retaddr_reg.loc.reg); + addr += get_frame_register_unsigned (this_frame, regnum); + return frame_unwind_got_address (this_frame, regnum, addr); - regnum = DWARF2_REG_TO_REGNUM (cache->retaddr_reg.loc.reg); - pc += frame_unwind_register_unsigned (next_frame, regnum); - store_typed_address (valuep, builtin_type_void_func_ptr, pc); - } - break; + case DWARF2_FRAME_REG_FN: + return cache->reg[regnum].loc.fn (this_frame, this_cache, regnum); default: internal_error (__FILE__, __LINE__, _("Unknown register rule.")); } } +static int +dwarf2_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, void **this_cache) +{ + /* Grab an address that is guarenteed to reside somewhere within the + function. get_frame_pc(), with a no-return next function, can + end up returning something past the end of this function's body. + If the frame we're sniffing for is a signal frame whose start + address is placed on the stack by the OS, its FDE must + extend one byte before its start address or we could potentially + select the FDE of the previous function. */ + CORE_ADDR block_addr = get_frame_address_in_block (this_frame); + struct dwarf2_fde *fde = dwarf2_frame_find_fde (&block_addr); + if (!fde) + return 0; + + /* On some targets, signal trampolines may have unwind information. + We need to recognize them so that we set the frame type + correctly. */ + + if (fde->cie->signal_frame + || dwarf2_frame_signal_frame_p (get_frame_arch (this_frame), + this_frame)) + return self->type == SIGTRAMP_FRAME; + + return self->type != SIGTRAMP_FRAME; +} + static const struct frame_unwind dwarf2_frame_unwind = { NORMAL_FRAME, dwarf2_frame_this_id, - dwarf2_frame_prev_register + dwarf2_frame_prev_register, + NULL, + dwarf2_frame_sniffer }; static const struct frame_unwind dwarf2_signal_frame_unwind = { SIGTRAMP_FRAME, dwarf2_frame_this_id, - dwarf2_frame_prev_register + dwarf2_frame_prev_register, + NULL, + dwarf2_frame_sniffer }; -const struct frame_unwind * -dwarf2_frame_sniffer (struct frame_info *next_frame) -{ - /* Grab an address that is guarenteed to reside somewhere within the - function. frame_pc_unwind(), for a no-return next function, can - end up returning something past the end of this function's body. */ - CORE_ADDR block_addr = frame_unwind_address_in_block (next_frame); - if (!dwarf2_frame_find_fde (&block_addr)) - return NULL; +/* Append the DWARF-2 frame unwinders to GDBARCH's list. */ - /* On some targets, signal trampolines may have unwind information. - We need to recognize them so that we set the frame type - correctly. */ - - if (dwarf2_frame_signal_frame_p (get_frame_arch (next_frame), - next_frame)) - return &dwarf2_signal_frame_unwind; - - return &dwarf2_frame_unwind; +void +dwarf2_append_unwinders (struct gdbarch *gdbarch) +{ + frame_unwind_append_unwinder (gdbarch, &dwarf2_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &dwarf2_signal_frame_unwind); } @@ -981,10 +1236,10 @@ dwarf2_frame_sniffer (struct frame_info *next_frame) response to the "info frame" command. */ static CORE_ADDR -dwarf2_frame_base_address (struct frame_info *next_frame, void **this_cache) +dwarf2_frame_base_address (struct frame_info *this_frame, void **this_cache) { struct dwarf2_frame_cache *cache = - dwarf2_frame_cache (next_frame, this_cache); + dwarf2_frame_cache (this_frame, this_cache); return cache->cfa; } @@ -998,44 +1253,32 @@ static const struct frame_base dwarf2_frame_base = }; const struct frame_base * -dwarf2_frame_base_sniffer (struct frame_info *next_frame) +dwarf2_frame_base_sniffer (struct frame_info *this_frame) { - CORE_ADDR pc = frame_pc_unwind (next_frame); - if (dwarf2_frame_find_fde (&pc)) + CORE_ADDR block_addr = get_frame_address_in_block (this_frame); + if (dwarf2_frame_find_fde (&block_addr)) return &dwarf2_frame_base; return NULL; } - -/* A minimal decoding of DWARF2 compilation units. We only decode - what's needed to get to the call frame information. */ - -struct comp_unit -{ - /* Keep the bfd convenient. */ - bfd *abfd; - - struct objfile *objfile; - - /* Linked list of CIEs for this object. */ - struct dwarf2_cie *cie; - - /* Pointer to the .debug_frame section loaded into memory. */ - gdb_byte *dwarf_frame_buffer; - - /* Length of the loaded .debug_frame section. */ - unsigned long dwarf_frame_size; - /* Pointer to the .debug_frame section. */ - asection *dwarf_frame_section; - - /* Base for DW_EH_PE_datarel encodings. */ - bfd_vma dbase; - - /* Base for DW_EH_PE_textrel encodings. */ - bfd_vma tbase; -}; +/* Compute the CFA for THIS_FRAME, but only if THIS_FRAME came from + the DWARF unwinder. This is used to implement + DW_OP_call_frame_cfa. */ +CORE_ADDR +dwarf2_frame_cfa (struct frame_info *this_frame) +{ + while (get_frame_type (this_frame) == INLINE_FRAME) + this_frame = get_prev_frame (this_frame); + /* This restriction could be lifted if other unwinders are known to + compute the frame base in a way compatible with the DWARF + unwinder. */ + if (! frame_unwinder_is (this_frame, &dwarf2_frame_unwind)) + error (_("can't compute CFA for this frame")); + return get_frame_base (this_frame); +} + const struct objfile_data *dwarf2_frame_objfile_data; static unsigned int @@ -1163,32 +1406,11 @@ encoding_for_size (unsigned int size) } } -static unsigned int -size_of_encoded_value (gdb_byte encoding) -{ - if (encoding == DW_EH_PE_omit) - return 0; - - switch (encoding & 0x07) - { - case DW_EH_PE_absptr: - return TYPE_LENGTH (builtin_type_void_data_ptr); - case DW_EH_PE_udata2: - return 2; - case DW_EH_PE_udata4: - return 4; - case DW_EH_PE_udata8: - return 8; - default: - internal_error (__FILE__, __LINE__, _("Invalid or unsupported encoding")); - } -} - static CORE_ADDR read_encoded_value (struct comp_unit *unit, gdb_byte encoding, - gdb_byte *buf, unsigned int *bytes_read_ptr) + int ptr_len, gdb_byte *buf, unsigned int *bytes_read_ptr, + CORE_ADDR func_base) { - int ptr_len = size_of_encoded_value (DW_EH_PE_absptr); ptrdiff_t offset; CORE_ADDR base; @@ -1206,7 +1428,7 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, base = 0; break; case DW_EH_PE_pcrel: - base = bfd_get_section_vma (unit->bfd, unit->dwarf_frame_section); + base = bfd_get_section_vma (unit->abfd, unit->dwarf_frame_section); base += (buf - unit->dwarf_frame_buffer); break; case DW_EH_PE_datarel: @@ -1216,12 +1438,7 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, base = unit->tbase; break; case DW_EH_PE_funcrel: - /* FIXME: kettenis/20040501: For now just pretend - DW_EH_PE_funcrel is equivalent to DW_EH_PE_absptr. For - reading the initial location of an FDE it should be treated - as such, and currently that's the only place where this code - is used. */ - base = 0; + base = func_base; break; case DW_EH_PE_aligned: base = 0; @@ -1237,7 +1454,11 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, } if ((encoding & 0x07) == 0x00) - encoding |= encoding_for_size (ptr_len); + { + encoding |= encoding_for_size (ptr_len); + if (bfd_get_sign_extend_vma (unit->abfd)) + encoding |= DW_EH_PE_signed; + } switch (encoding & 0x0f) { @@ -1279,30 +1500,64 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, } -/* GCC uses a single CIE for all FDEs in a .debug_frame section. - That's why we use a simple linked list here. */ +static int +bsearch_cie_cmp (const void *key, const void *element) +{ + ULONGEST cie_pointer = *(ULONGEST *) key; + struct dwarf2_cie *cie = *(struct dwarf2_cie **) element; + + if (cie_pointer == cie->cie_pointer) + return 0; + return (cie_pointer < cie->cie_pointer) ? -1 : 1; +} + +/* Find CIE with the given CIE_POINTER in CIE_TABLE. */ static struct dwarf2_cie * -find_cie (struct comp_unit *unit, ULONGEST cie_pointer) +find_cie (struct dwarf2_cie_table *cie_table, ULONGEST cie_pointer) { - struct dwarf2_cie *cie = unit->cie; + struct dwarf2_cie **p_cie; - while (cie) + /* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to + bsearch be non-NULL. */ + if (cie_table->entries == NULL) { - if (cie->cie_pointer == cie_pointer) - return cie; - - cie = cie->next; + gdb_assert (cie_table->num_entries == 0); + return NULL; } + p_cie = bsearch (&cie_pointer, cie_table->entries, cie_table->num_entries, + sizeof (cie_table->entries[0]), bsearch_cie_cmp); + if (p_cie != NULL) + return *p_cie; return NULL; } +/* Add a pointer to new CIE to the CIE_TABLE, allocating space for it. */ static void -add_cie (struct comp_unit *unit, struct dwarf2_cie *cie) +add_cie (struct dwarf2_cie_table *cie_table, struct dwarf2_cie *cie) { - cie->next = unit->cie; - unit->cie = cie; + const int n = cie_table->num_entries; + + gdb_assert (n < 1 + || cie_table->entries[n - 1]->cie_pointer < cie->cie_pointer); + + cie_table->entries = + xrealloc (cie_table->entries, (n + 1) * sizeof (cie_table->entries[0])); + cie_table->entries[n] = cie; + cie_table->num_entries = n + 1; +} + +static int +bsearch_fde_cmp (const void *key, const void *element) +{ + CORE_ADDR seek_pc = *(CORE_ADDR *) key; + struct dwarf2_fde *fde = *(struct dwarf2_fde **) element; + if (seek_pc < fde->initial_location) + return -1; + if (seek_pc < fde->initial_location + fde->address_range) + return 0; + return 1; } /* Find the FDE for *PC. Return a pointer to the FDE, and store the @@ -1315,37 +1570,54 @@ dwarf2_frame_find_fde (CORE_ADDR *pc) ALL_OBJFILES (objfile) { - struct dwarf2_fde *fde; + struct dwarf2_fde_table *fde_table; + struct dwarf2_fde **p_fde; CORE_ADDR offset; + CORE_ADDR seek_pc; + + fde_table = objfile_data (objfile, dwarf2_frame_objfile_data); + if (fde_table == NULL) + { + dwarf2_build_frame_info (objfile); + fde_table = objfile_data (objfile, dwarf2_frame_objfile_data); + } + gdb_assert (fde_table != NULL); - fde = objfile_data (objfile, dwarf2_frame_objfile_data); - if (fde == NULL) + if (fde_table->num_entries == 0) continue; gdb_assert (objfile->section_offsets); offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - while (fde) - { - if (*pc >= fde->initial_location + offset - && *pc < fde->initial_location + offset + fde->address_range) - { - *pc = fde->initial_location + offset; - return fde; - } + gdb_assert (fde_table->num_entries > 0); + if (*pc < offset + fde_table->entries[0]->initial_location) + continue; - fde = fde->next; - } + seek_pc = *pc - offset; + p_fde = bsearch (&seek_pc, fde_table->entries, fde_table->num_entries, + sizeof (fde_table->entries[0]), bsearch_fde_cmp); + if (p_fde != NULL) + { + *pc = (*p_fde)->initial_location + offset; + return *p_fde; + } } - return NULL; } +/* Add a pointer to new FDE to the FDE_TABLE, allocating space for it. */ static void -add_fde (struct comp_unit *unit, struct dwarf2_fde *fde) +add_fde (struct dwarf2_fde_table *fde_table, struct dwarf2_fde *fde) { - fde->next = objfile_data (unit->objfile, dwarf2_frame_objfile_data); - set_objfile_data (unit->objfile, dwarf2_frame_objfile_data, fde); + if (fde->address_range == 0) + /* Discard useless FDEs. */ + return; + + fde_table->num_entries += 1; + fde_table->entries = + xrealloc (fde_table->entries, + fde_table->num_entries * sizeof (fde_table->entries[0])); + fde_table->entries[fde_table->num_entries - 1] = fde; } #ifdef CC_HAS_LONG_LONG @@ -1355,13 +1627,18 @@ add_fde (struct comp_unit *unit, struct dwarf2_fde *fde) #endif static gdb_byte *decode_frame_entry (struct comp_unit *unit, gdb_byte *start, - int eh_frame_p); + int eh_frame_p, + struct dwarf2_cie_table *cie_table, + struct dwarf2_fde_table *fde_table); /* Decode the next CIE or FDE. Return NULL if invalid input, otherwise the next byte to be processed. */ static gdb_byte * -decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) +decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, + struct dwarf2_cie_table *cie_table, + struct dwarf2_fde_table *fde_table) { + struct gdbarch *gdbarch = get_objfile_arch (unit->objfile); gdb_byte *buf, *end; LONGEST length; unsigned int bytes_read; @@ -1414,7 +1691,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) cie_pointer = start - unit->dwarf_frame_buffer; /* Check whether we've already read it. */ - if (find_cie (unit, cie_pointer)) + if (find_cie (cie_table, cie_pointer)) return end; cie = (struct dwarf2_cie *) @@ -1427,26 +1704,57 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) depends on the target address size. */ cie->encoding = DW_EH_PE_absptr; + /* The target address size. For .eh_frame FDEs this is considered + equal to the size of a target pointer. For .dwarf_frame FDEs, + this is supposed to be the target address size from the associated + CU header. FIXME: We do not have a good way to determine the + latter. Always use the target pointer size for now. */ + cie->addr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; + + /* We'll determine the final value later, but we need to + initialize it conservatively. */ + cie->signal_frame = 0; + /* Check version number. */ cie_version = read_1_byte (unit->abfd, buf); - if (cie_version != 1 && cie_version != 3) + if (cie_version != 1 && cie_version != 3 && cie_version != 4) 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. */ if (augmentation[0] == 'e' && augmentation[1] == 'h') { /* Skip. */ - buf += TYPE_LENGTH (builtin_type_void_data_ptr); + buf += gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; augmentation += 2; } + if (cie->version >= 4) + { + /* FIXME: check that this is the same as from the CU header. */ + cie->addr_size = read_1_byte (unit->abfd, buf); + ++buf; + cie->segment_size = read_1_byte (unit->abfd, buf); + ++buf; + } + else + { + cie->addr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; + cie->segment_size = 0; + } + cie->code_alignment_factor = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); buf += bytes_read; @@ -1463,6 +1771,11 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) else cie->return_address_register = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); + cie->return_address_register + = dwarf2_frame_adjust_regnum (gdbarch, + cie->return_address_register, + eh_frame_p); + buf += bytes_read; cie->saw_z_augmentation = (*augmentation == 'z'); @@ -1500,28 +1813,38 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) { /* Skip. Avoid indirection since we throw away the result. */ gdb_byte encoding = (*buf++) & ~DW_EH_PE_indirect; - read_encoded_value (unit, encoding, buf, &bytes_read); + read_encoded_value (unit, encoding, cie->addr_size, + buf, &bytes_read, 0); buf += bytes_read; augmentation++; } - /* Otherwise we have an unknown augmentation. - Bail out unless we saw a 'z' prefix. */ - else + /* "S" indicates a signal frame, such that the return + address must not be decremented to locate the call frame + info for the previous frame; it might even be the first + instruction of a function, so decrementing it would take + us to a different function. */ + else if (*augmentation == 'S') { - if (cie->initial_instructions == NULL) - return end; + cie->signal_frame = 1; + augmentation++; + } - /* Skip unknown augmentations. */ - buf = cie->initial_instructions; + /* Otherwise we have an unknown augmentation. Assume that either + there is no augmentation data, or we saw a 'z' prefix. */ + else + { + if (cie->initial_instructions) + buf = cie->initial_instructions; break; } } cie->initial_instructions = buf; cie->end = end; + cie->unit = unit; - add_cie (unit, cie); + add_cie (cie_table, cie); } else { @@ -1545,22 +1868,24 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) fde = (struct dwarf2_fde *) obstack_alloc (&unit->objfile->objfile_obstack, sizeof (struct dwarf2_fde)); - fde->cie = find_cie (unit, cie_pointer); + fde->cie = find_cie (cie_table, cie_pointer); if (fde->cie == NULL) { decode_frame_entry (unit, unit->dwarf_frame_buffer + cie_pointer, - eh_frame_p); - fde->cie = find_cie (unit, cie_pointer); + eh_frame_p, cie_table, fde_table); + fde->cie = find_cie (cie_table, cie_pointer); } gdb_assert (fde->cie != NULL); fde->initial_location = - read_encoded_value (unit, fde->cie->encoding, buf, &bytes_read); + read_encoded_value (unit, fde->cie->encoding, fde->cie->addr_size, + buf, &bytes_read, 0); buf += bytes_read; fde->address_range = - read_encoded_value (unit, fde->cie->encoding & 0x0f, buf, &bytes_read); + read_encoded_value (unit, fde->cie->encoding & 0x0f, + fde->cie->addr_size, buf, &bytes_read, 0); buf += bytes_read; /* A 'z' augmentation in the CIE implies the presence of an @@ -1580,7 +1905,9 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) fde->instructions = buf; fde->end = end; - add_fde (unit, fde); + fde->eh_frame_p = eh_frame_p; + + add_fde (fde_table, fde); } return end; @@ -1588,7 +1915,9 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) /* Read a CIE or FDE in BUF and decode it. */ static gdb_byte * -decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) +decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, + struct dwarf2_cie_table *cie_table, + struct dwarf2_fde_table *fde_table) { enum { NONE, ALIGN4, ALIGN8, FAIL } workaround = NONE; gdb_byte *ret; @@ -1597,7 +1926,8 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) while (1) { - ret = decode_frame_entry_1 (unit, start, eh_frame_p); + ret = decode_frame_entry_1 (unit, start, eh_frame_p, + cie_table, fde_table); if (ret != NULL) break; @@ -1679,72 +2009,182 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) } -/* FIXME: kettenis/20030504: This still needs to be integrated with - dwarf2read.c in a better way. */ - /* Imported from dwarf2read.c. */ -extern asection *dwarf_frame_section; -extern asection *dwarf_eh_frame_section; +extern void dwarf2_get_section_info (struct objfile *, const char *, asection **, + gdb_byte **, bfd_size_type *); -/* Imported from dwarf2read.c. */ -extern char *dwarf2_read_section (struct objfile *objfile, asection *sectp); +static int +qsort_fde_cmp (const void *a, const void *b) +{ + struct dwarf2_fde *aa = *(struct dwarf2_fde **)a; + struct dwarf2_fde *bb = *(struct dwarf2_fde **)b; + + if (aa->initial_location == bb->initial_location) + { + if (aa->address_range != bb->address_range + && aa->eh_frame_p == 0 && bb->eh_frame_p == 0) + /* Linker bug, e.g. gold/10400. + Work around it by keeping stable sort order. */ + return (a < b) ? -1 : 1; + else + /* Put eh_frame entries after debug_frame ones. */ + return aa->eh_frame_p - bb->eh_frame_p; + } + + return (aa->initial_location < bb->initial_location) ? -1 : 1; +} void dwarf2_build_frame_info (struct objfile *objfile) { - struct comp_unit unit; + struct comp_unit *unit; gdb_byte *frame_ptr; + struct dwarf2_cie_table cie_table; + struct dwarf2_fde_table fde_table; + struct dwarf2_fde_table *fde_table2; + + cie_table.num_entries = 0; + cie_table.entries = NULL; + + fde_table.num_entries = 0; + fde_table.entries = NULL; /* Build a minimal decoding of the DWARF2 compilation unit. */ - unit.abfd = objfile->obfd; - unit.objfile = objfile; - unit.dbase = 0; - unit.tbase = 0; - - /* First add the information from the .eh_frame section. That way, - the FDEs from that section are searched last. */ - if (dwarf_eh_frame_section) + unit = (struct comp_unit *) obstack_alloc (&objfile->objfile_obstack, + sizeof (struct comp_unit)); + unit->abfd = objfile->obfd; + unit->objfile = objfile; + unit->dbase = 0; + unit->tbase = 0; + + dwarf2_get_section_info (objfile, ".eh_frame", + &unit->dwarf_frame_section, + &unit->dwarf_frame_buffer, + &unit->dwarf_frame_size); + if (unit->dwarf_frame_size) { asection *got, *txt; - unit.cie = NULL; - unit.dwarf_frame_buffer = dwarf2_read_section (objfile, - dwarf_eh_frame_section); - - unit.dwarf_frame_size = bfd_get_section_size (dwarf_eh_frame_section); - unit.dwarf_frame_section = dwarf_eh_frame_section; - /* FIXME: kettenis/20030602: This is the DW_EH_PE_datarel base that is used for the i386/amd64 target, which currently is the only target in GCC that supports/uses the DW_EH_PE_datarel encoding. */ - got = bfd_get_section_by_name (unit.abfd, ".got"); + got = bfd_get_section_by_name (unit->abfd, ".got"); if (got) - unit.dbase = got->vma; + unit->dbase = got->vma; /* GCC emits the DW_EH_PE_textrel encoding type on sh and ia64 so far. */ - txt = bfd_get_section_by_name (unit.abfd, ".text"); + txt = bfd_get_section_by_name (unit->abfd, ".text"); if (txt) - unit.tbase = txt->vma; + unit->tbase = txt->vma; + + frame_ptr = unit->dwarf_frame_buffer; + while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size) + frame_ptr = decode_frame_entry (unit, frame_ptr, 1, + &cie_table, &fde_table); + + if (cie_table.num_entries != 0) + { + /* Reinit cie_table: debug_frame has different CIEs. */ + xfree (cie_table.entries); + cie_table.num_entries = 0; + cie_table.entries = NULL; + } + } + + dwarf2_get_section_info (objfile, ".debug_frame", + &unit->dwarf_frame_section, + &unit->dwarf_frame_buffer, + &unit->dwarf_frame_size); + if (unit->dwarf_frame_size) + { + frame_ptr = unit->dwarf_frame_buffer; + while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size) + frame_ptr = decode_frame_entry (unit, frame_ptr, 0, + &cie_table, &fde_table); + } - frame_ptr = unit.dwarf_frame_buffer; - while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size) - frame_ptr = decode_frame_entry (&unit, frame_ptr, 1); + /* Discard the cie_table, it is no longer needed. */ + if (cie_table.num_entries != 0) + { + xfree (cie_table.entries); + cie_table.entries = NULL; /* Paranoia. */ + cie_table.num_entries = 0; /* Paranoia. */ } - if (dwarf_frame_section) + /* Copy fde_table to obstack: it is needed at runtime. */ + fde_table2 = (struct dwarf2_fde_table *) + obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2)); + + if (fde_table.num_entries == 0) { - unit.cie = NULL; - unit.dwarf_frame_buffer = dwarf2_read_section (objfile, - dwarf_frame_section); - unit.dwarf_frame_size = bfd_get_section_size (dwarf_frame_section); - unit.dwarf_frame_section = dwarf_frame_section; - - frame_ptr = unit.dwarf_frame_buffer; - while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size) - frame_ptr = decode_frame_entry (&unit, frame_ptr, 0); + fde_table2->entries = NULL; + fde_table2->num_entries = 0; + } + else + { + struct dwarf2_fde *fde_prev = NULL; + struct dwarf2_fde *first_non_zero_fde = NULL; + int i; + + /* Prepare FDE table for lookups. */ + qsort (fde_table.entries, fde_table.num_entries, + sizeof (fde_table.entries[0]), qsort_fde_cmp); + + /* Check for leftovers from --gc-sections. The GNU linker sets + the relevant symbols to zero, but doesn't zero the FDE *end* + ranges because there's no relocation there. It's (offset, + length), not (start, end). On targets where address zero is + just another valid address this can be a problem, since the + FDEs appear to be non-empty in the output --- we could pick + out the wrong FDE. To work around this, when overlaps are + detected, we prefer FDEs that do not start at zero. + + Start by finding the first FDE with non-zero start. Below + we'll discard all FDEs that start at zero and overlap this + one. */ + for (i = 0; i < fde_table.num_entries; i++) + { + struct dwarf2_fde *fde = fde_table.entries[i]; + + if (fde->initial_location != 0) + { + first_non_zero_fde = fde; + break; + } + } + + /* Since we'll be doing bsearch, squeeze out identical (except + for eh_frame_p) fde entries so bsearch result is predictable. + Also discard leftovers from --gc-sections. */ + fde_table2->num_entries = 0; + for (i = 0; i < fde_table.num_entries; i++) + { + struct dwarf2_fde *fde = fde_table.entries[i]; + + if (fde->initial_location == 0 + && first_non_zero_fde != NULL + && (first_non_zero_fde->initial_location + < fde->initial_location + fde->address_range)) + continue; + + if (fde_prev != NULL + && fde_prev->initial_location == fde->initial_location) + continue; + + obstack_grow (&objfile->objfile_obstack, &fde_table.entries[i], + sizeof (fde_table.entries[0])); + ++fde_table2->num_entries; + fde_prev = fde; + } + fde_table2->entries = obstack_finish (&objfile->objfile_obstack); + + /* Discard the original fde_table. */ + xfree (fde_table.entries); } + + set_objfile_data (objfile, dwarf2_frame_objfile_data, fde_table2); } /* Provide a prototype to silence -Wmissing-prototypes. */