X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fdwarf2-frame.c;h=5e9be2ccb2cc7ae896725ade66755e5c79672362;hb=240e538ad8ae0d7cbb6e0c22c3bed49717027ac0;hp=be61a0eca894b14fdb51c2a07b73fa866ce23758;hpb=93d42b302eb91d758191675dcaf3bd90323b5224;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index be61a0eca8..5e9be2ccb2 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 (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 + 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., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, 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" @@ -40,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; @@ -70,6 +74,9 @@ struct dwarf2_cie /* 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; @@ -78,8 +85,12 @@ struct dwarf2_cie /* The version recorded in the CIE. */ unsigned char version; +}; - struct dwarf2_cie *next; +struct dwarf2_cie_table +{ + int num_entries; + struct dwarf2_cie **entries; }; /* Frame Description Entry (FDE). */ @@ -102,11 +113,49 @@ struct dwarf2_fde /* 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; - struct dwarf2_fde *next; + /* 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. */ @@ -120,19 +169,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; @@ -160,7 +209,7 @@ struct dwarf2_frame_state 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 @@ -229,15 +278,15 @@ 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); + 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 @@ -260,6 +309,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) { @@ -267,41 +325,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, - struct dwarf2_frame_state *fs, int eh_frame_p) +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 (next_frame); + 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) { @@ -314,8 +418,7 @@ execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end, else if ((insn & 0xc0) == DW_CFA_offset) { reg = insn & 0x3f; - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + 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); @@ -324,52 +427,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; - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); - dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - 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 0x%s"), - REGISTER_NAME(DWARF2_REG_TO_REGNUM(reg)), - DWARF2_REG_TO_REGNUM(reg), paddr (fs->pc)); + 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, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + 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); @@ -378,37 +471,29 @@ register %s (#%d) at 0x%s"), break; case DW_CFA_restore_extended: - gdb_assert (fs->initial.reg); insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); - 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, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + 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, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + 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, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); - if (eh_frame_p) - utmp = dwarf2_frame_eh_frame_regnum (gdbarch, 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; @@ -432,7 +517,8 @@ register %s (#%d) at 0x%s"), 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 { @@ -444,22 +530,22 @@ 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); if (fs->armcc_cfa_offsets_sf) utmp *= fs->data_align; - fs->cfa_offset = utmp; - fs->cfa_how = CFA_REG_OFFSET; + 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); - if (eh_frame_p) - fs->cfa_reg = dwarf2_frame_eh_frame_regnum (gdbarch, - 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: @@ -468,7 +554,7 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); if (fs->armcc_cfa_offsets_sf) utmp *= fs->data_align; - fs->cfa_offset = utmp; + fs->regs.cfa_offset = utmp; /* cfa_how deliberately not set. */ break; @@ -476,16 +562,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, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + 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; @@ -496,8 +582,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, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + 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); @@ -534,18 +619,18 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); break; case DW_CFA_def_cfa_sf: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg); - if (eh_frame_p) - fs->cfa_reg = dwarf2_frame_eh_frame_regnum (gdbarch, - 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; @@ -558,8 +643,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++) { @@ -581,8 +665,7 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc)); case DW_CFA_GNU_negative_offset_extended: insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); - if (eh_frame_p) - reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg); + 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); @@ -613,12 +696,12 @@ struct dwarf2_frame_ops 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. */ - int (*eh_frame_regnum) (struct gdbarch *, int); + /* 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 @@ -627,7 +710,7 @@ struct dwarf2_frame_ops static void dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum, struct dwarf2_frame_state_reg *reg, - struct frame_info *next_frame) + 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 @@ -655,9 +738,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; } @@ -692,11 +775,11 @@ 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 frame_info *next_frame) + struct frame_info *this_frame) { struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); - ops->init_reg (gdbarch, regnum, reg, next_frame); + ops->init_reg (gdbarch, regnum, reg, this_frame); } /* Set the architecture-specific signal trampoline recognition @@ -713,42 +796,43 @@ 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 mapping of .eh_frame register numbers to - DWARF register numbers. */ +/* Set the architecture-specific adjustment of .eh_frame and .debug_frame + register numbers. */ void -dwarf2_frame_set_eh_frame_regnum (struct gdbarch *gdbarch, - int (*eh_frame_regnum) (struct gdbarch *, - int)) +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->eh_frame_regnum = eh_frame_regnum; + ops->adjust_regnum = adjust_regnum; } -/* Translate a .eh_frame register to DWARF register. */ +/* Translate a .eh_frame register to DWARF register, or adjust a .debug_frame + register. */ -int -dwarf2_frame_eh_frame_regnum (struct gdbarch *gdbarch, int regnum) +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->eh_frame_regnum == NULL) + if (ops->adjust_regnum == NULL) return regnum; - return ops->eh_frame_regnum (gdbarch, regnum); + return ops->adjust_regnum (gdbarch, regnum, eh_frame_p); } static void @@ -809,14 +893,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; @@ -835,9 +923,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 @@ -845,10 +933,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, NORMAL_FRAME); + fs->pc = get_frame_address_in_block (this_frame); /* Find the correct FDE. */ fde = dwarf2_frame_find_fde (&fs->pc); @@ -858,36 +946,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, fde->eh_frame_p); + 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, - fde->eh_frame_p); + 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 = read_reg (this_frame, fs->regs.cfa_reg); if (fs->armcc_cfa_offsets_reversed) - cache->cfa -= fs->cfa_offset; + cache->cfa -= fs->regs.cfa_offset; else - cache->cfa += fs->cfa_offset; + 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: @@ -899,7 +988,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], next_frame); + dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum], this_frame); } /* Go through the DWARF2 CFI generated table and save its register @@ -907,15 +996,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) @@ -936,9 +1025,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]; @@ -1002,117 +1091,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, NORMAL_FRAME)); + (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); } -static void -dwarf2_signal_frame_this_id (struct frame_info *next_frame, void **this_cache, - struct frame_id *this_id) +static struct value * +dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, + int regnum) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct dwarf2_frame_cache *cache = - dwarf2_frame_cache (next_frame, this_cache); - - if (cache->undefined_retaddr) - return; - - (*this_id) = frame_id_build (cache->cfa, - frame_func_unwind (next_frame, SIGTRAMP_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) -{ - struct gdbarch *gdbarch = get_frame_arch (next_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: - *optimizedp = 0; - *lvalp = not_lval; - *addrp = 0; - *realnump = -1; - if (valuep) - store_unsigned_integer (valuep, register_size (gdbarch, regnum), - cache->cfa + cache->reg[regnum].loc.offset); - break; + addr = cache->cfa + cache->reg[regnum].loc.offset; + return frame_unwind_got_constant (this_frame, regnum, addr); case DWARF2_FRAME_REG_SAVED_VAL_EXP: - *optimizedp = 0; - *lvalp = not_lval; - *addrp = 0; - *realnump = -1; - if (valuep) - store_unsigned_integer (valuep, register_size (gdbarch, regnum), - execute_stack_op (cache->reg[regnum].loc.exp, - cache->reg[regnum].exp_len, - next_frame, cache->cfa)); - 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_constant (this_frame, regnum, addr); case DWARF2_FRAME_REG_UNSPECIFIED: /* GCC, in its infinite wisdom decided to not provide unwind @@ -1122,107 +1153,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: - *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 + cache->reg[regnum].loc.offset); - } - break; + 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 const struct frame_unwind dwarf2_frame_unwind = -{ - NORMAL_FRAME, - dwarf2_frame_this_id, - dwarf2_frame_prev_register -}; - -static const struct frame_unwind dwarf2_signal_frame_unwind = -{ - SIGTRAMP_FRAME, - dwarf2_signal_frame_this_id, - dwarf2_frame_prev_register -}; - -const struct frame_unwind * -dwarf2_frame_sniffer (struct frame_info *next_frame) +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. frame_pc_unwind(), for a no-return next function, can + 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 will miss it. */ - CORE_ADDR block_addr = frame_unwind_address_in_block (next_frame, - NORMAL_FRAME); + 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 NULL; + 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 (next_frame), - next_frame)) - return &dwarf2_signal_frame_unwind; + || dwarf2_frame_signal_frame_p (get_frame_arch (this_frame), + this_frame)) + return self->type == SIGTRAMP_FRAME; - return &dwarf2_frame_unwind; + return self->type != SIGTRAMP_FRAME; +} + +static const struct frame_unwind dwarf2_frame_unwind = +{ + NORMAL_FRAME, + dwarf2_frame_this_id, + 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, + NULL, + dwarf2_frame_sniffer +}; + +/* Append the DWARF-2 frame unwinders to GDBARCH's list. */ + +void +dwarf2_append_unwinders (struct gdbarch *gdbarch) +{ + frame_unwind_append_unwinder (gdbarch, &dwarf2_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &dwarf2_signal_frame_unwind); } @@ -1233,10 +1243,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; } @@ -1250,45 +1260,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 block_addr = frame_unwind_address_in_block (next_frame, - NORMAL_FRAME); + 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 @@ -1416,32 +1413,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; @@ -1459,7 +1435,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: @@ -1469,12 +1445,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; @@ -1490,7 +1461,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) { @@ -1532,30 +1507,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 @@ -1568,37 +1577,47 @@ 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 = objfile_data (objfile, dwarf2_frame_objfile_data); - if (fde == NULL) + fde_table = objfile_data (objfile, dwarf2_frame_objfile_data); + if (fde_table == NULL) 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 @@ -1608,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; @@ -1667,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 *) @@ -1680,6 +1704,13 @@ 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; @@ -1706,7 +1737,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) 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; } @@ -1726,10 +1757,10 @@ 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); - if (eh_frame_p) - cie->return_address_register - = dwarf2_frame_eh_frame_regnum (current_gdbarch, - cie->return_address_register); + cie->return_address_register + = dwarf2_frame_adjust_regnum (gdbarch, + cie->return_address_register, + eh_frame_p); buf += bytes_read; @@ -1768,7 +1799,8 @@ 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++; } @@ -1796,8 +1828,9 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) cie->initial_instructions = buf; cie->end = end; + cie->unit = unit; - add_cie (unit, cie); + add_cie (cie_table, cie); } else { @@ -1821,22 +1854,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 @@ -1858,7 +1893,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) fde->eh_frame_p = eh_frame_p; - add_fde (unit, fde); + add_fde (fde_table, fde); } return end; @@ -1866,7 +1901,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; @@ -1875,7 +1912,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; @@ -1957,71 +1995,141 @@ 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 gdb_byte *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; + + 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); - 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); + 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); + } + + /* 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) + 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); + struct dwarf2_fde_table *fde_table2; + int i, j; + + /* Prepare FDE table for lookups. */ + qsort (fde_table.entries, fde_table.num_entries, + sizeof (fde_table.entries[0]), qsort_fde_cmp); + + /* Copy fde_table to obstack: it is needed at runtime. */ + fde_table2 = (struct dwarf2_fde_table *) + obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2)); + + /* Since we'll be doing bsearch, squeeze out identical (except for + eh_frame_p) fde entries so bsearch result is predictable. */ + for (i = 0, j = 0; j < fde_table.num_entries; ++i) + { + const int k = j; + + obstack_grow (&objfile->objfile_obstack, &fde_table.entries[j], + sizeof (fde_table.entries[0])); + while (++j < fde_table.num_entries + && (fde_table.entries[k]->initial_location + == fde_table.entries[j]->initial_location)) + /* Skip. */; + } + fde_table2->entries = obstack_finish (&objfile->objfile_obstack); + fde_table2->num_entries = i; + set_objfile_data (objfile, dwarf2_frame_objfile_data, fde_table2); + + /* Discard the original fde_table. */ + xfree (fde_table.entries); } }