X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fdwarf2-frame.c;h=2f6355ae512346aaeb66b10b88707f917fdfd90a;hb=5fe966540d6b748f825774868463003700f0c878;hp=f9ca067dfe163e5acaf9c52437a48b6902fd230c;hpb=e78022079ce4c50f042bb5287665a4f38704a71b;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index f9ca067dfe..2f6355ae51 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -1,7 +1,6 @@ /* Frame unwinder for frames with DWARF Call Frame Information. - Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 2003-2016 Free Software Foundation, Inc. Contributed by Mark Kettenis. @@ -32,12 +31,13 @@ #include "objfiles.h" #include "regcache.h" #include "value.h" - -#include "gdb_assert.h" -#include "gdb_string.h" +#include "record.h" #include "complaints.h" #include "dwarf2-frame.h" +#include "ax.h" +#include "dwarf2loc.h" +#include "dwarf2-frame-tailcall.h" struct comp_unit; @@ -65,8 +65,8 @@ struct dwarf2_cie ULONGEST return_address_register; /* Instruction sequence to initialize a register set. */ - gdb_byte *initial_instructions; - gdb_byte *end; + const gdb_byte *initial_instructions; + const gdb_byte *end; /* Saved augmentation, in case it's needed later. */ char *augmentation; @@ -77,6 +77,9 @@ struct dwarf2_cie /* Target address size in bytes. */ int addr_size; + /* Target pointer size in bytes. */ + int ptr_size; + /* True if a 'z' augmentation existed. */ unsigned char saw_z_augmentation; @@ -85,6 +88,9 @@ struct dwarf2_cie /* The version recorded in the CIE. */ unsigned char version; + + /* The segment size. */ + unsigned char segment_size; }; struct dwarf2_cie_table @@ -107,8 +113,8 @@ struct dwarf2_fde CORE_ADDR address_range; /* Instruction sequence. */ - gdb_byte *instructions; - gdb_byte *end; + const gdb_byte *instructions; + const gdb_byte *end; /* True if this FDE is read from a .eh_frame instead of a .debug_frame section. */ @@ -132,7 +138,7 @@ struct comp_unit struct objfile *objfile; /* Pointer to the .debug_frame section loaded into memory. */ - gdb_byte *dwarf_frame_buffer; + const gdb_byte *dwarf_frame_buffer; /* Length of the loaded .debug_frame section. */ bfd_size_type dwarf_frame_size; @@ -147,40 +153,46 @@ struct comp_unit bfd_vma tbase; }; -static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc); +static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc, + CORE_ADDR *out_offset); 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, + int ptr_len, const gdb_byte *buf, unsigned int *bytes_read_ptr, CORE_ADDR func_base); +enum cfa_how_kind +{ + CFA_UNSET, + CFA_REG_OFFSET, + CFA_EXP +}; + +struct dwarf2_frame_state_reg_info +{ + struct dwarf2_frame_state_reg *reg; + int num_regs; + + LONGEST cfa_offset; + ULONGEST cfa_reg; + enum cfa_how_kind cfa_how; + const gdb_byte *cfa_exp; + + /* Used to implement DW_CFA_remember_state. */ + struct dwarf2_frame_state_reg_info *prev; +}; + /* Structure describing a frame state. */ struct dwarf2_frame_state { /* Each register save state can be described in terms of a CFA slot, another register, or a location expression. */ - struct dwarf2_frame_state_reg_info - { - 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; + struct dwarf2_frame_state_reg_info regs; /* The PC described by the current frame state. */ CORE_ADDR pc; @@ -263,7 +275,7 @@ dwarf2_frame_state_free_regs (struct dwarf2_frame_state_reg_info *rs) static void dwarf2_frame_state_free (void *p) { - struct dwarf2_frame_state *fs = p; + struct dwarf2_frame_state *fs = (struct dwarf2_frame_state *) p; dwarf2_frame_state_free_regs (fs->initial.prev); dwarf2_frame_state_free_regs (fs->regs.prev); @@ -276,53 +288,31 @@ dwarf2_frame_state_free (void *p) /* Helper functions for execute_stack_op. */ static CORE_ADDR -read_reg (void *baton, int reg) +read_addr_from_reg (void *baton, int reg) { struct frame_info *this_frame = (struct frame_info *) baton; struct gdbarch *gdbarch = get_frame_arch (this_frame); - int regnum; - gdb_byte *buf; + int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg); - regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg); - - buf = alloca (register_size (gdbarch, regnum)); - 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); + return address_from_register (regnum, this_frame); } -static void -read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len) -{ - read_memory (addr, buf, len); -} +/* Implement struct dwarf_expr_context_funcs' "get_reg_value" callback. */ -static void -no_get_frame_base (void *baton, gdb_byte **start, size_t *length) +static struct value * +get_reg_value (void *baton, struct type *type, int reg) { - internal_error (__FILE__, __LINE__, - _("Support for DW_OP_fbreg is unimplemented")); -} - -/* Helper function for execute_stack_op. */ + struct frame_info *this_frame = (struct frame_info *) baton; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg); -static CORE_ADDR -no_get_frame_cfa (void *baton) -{ - internal_error (__FILE__, __LINE__, - _("Support for DW_OP_call_frame_cfa is unimplemented")); + return value_from_register (type, regnum, this_frame); } -static CORE_ADDR -no_get_tls_address (void *baton, CORE_ADDR offset) +static void +read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len) { - internal_error (__FILE__, __LINE__, - _("Support for DW_OP_GNU_push_tls_address is unimplemented")); + read_memory (addr, buf, len); } /* Execute the required actions for both the DW_CFA_restore and @@ -346,18 +336,38 @@ dwarf2_restore_rule (struct gdbarch *gdbarch, ULONGEST reg_num, fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNSPECIFIED; if (fs->regs.reg[reg].how == DWARF2_FRAME_REG_UNSPECIFIED) - complaint (&symfile_complaints, _("\ + { + int regnum = dwarf_reg_to_regnum (gdbarch, reg); + + 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)); + gdbarch_register_name (gdbarch, regnum), regnum, + paddress (gdbarch, fs->pc)); + } } +/* Virtual method table for execute_stack_op below. */ + +static const struct dwarf_expr_context_funcs dwarf2_frame_ctx_funcs = +{ + read_addr_from_reg, + get_reg_value, + read_mem, + ctx_no_get_frame_base, + ctx_no_get_frame_cfa, + ctx_no_get_frame_pc, + ctx_no_get_tls_address, + ctx_no_dwarf_call, + ctx_no_get_base_type, + ctx_no_push_dwarf_reg_entry_value, + ctx_no_get_addr_index +}; + static CORE_ADDR -execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size, - struct frame_info *this_frame, CORE_ADDR initial) +execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size, + CORE_ADDR offset, struct frame_info *this_frame, + CORE_ADDR initial, int initial_in_stack_memory) { struct dwarf_expr_context *ctx; CORE_ADDR result; @@ -365,22 +375,31 @@ execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size, ctx = new_dwarf_expr_context (); old_chain = make_cleanup_free_dwarf_expr_context (ctx); + make_cleanup_value_free_to_mark (value_mark ()); ctx->gdbarch = get_frame_arch (this_frame); ctx->addr_size = addr_size; + ctx->ref_addr_size = -1; + ctx->offset = offset; 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; + ctx->funcs = &dwarf2_frame_ctx_funcs; - dwarf_expr_push (ctx, initial); + dwarf_expr_push_address (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 (this_frame, result); + if (ctx->location == DWARF_VALUE_MEMORY) + result = dwarf_expr_fetch_address (ctx, 0); + else if (ctx->location == DWARF_VALUE_REGISTER) + result = read_addr_from_reg (this_frame, + value_as_long (dwarf_expr_fetch (ctx, 0))); + else + { + /* 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")); + } do_cleanups (old_chain); @@ -388,22 +407,24 @@ execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size, } -static void -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) +/* Execute FDE program from INSN_PTR possibly up to INSN_END or up to inferior + PC. Modify FS state accordingly. Return current INSN_PTR where the + execution has stopped, one can resume it on the next call. */ + +static const gdb_byte * +execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr, + const gdb_byte *insn_end, struct gdbarch *gdbarch, + CORE_ADDR pc, struct dwarf2_frame_state *fs) { 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); + unsigned int bytes_read; enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); while (insn_ptr < insn_end && fs->pc <= pc) { gdb_byte insn = *insn_ptr++; - ULONGEST utmp, reg; - LONGEST offset; + uint64_t utmp, reg; + int64_t offset; if ((insn & 0xc0) == DW_CFA_advance_loc) fs->pc += (insn & 0x3f) * fs->code_align; @@ -411,7 +432,7 @@ execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr, { reg = insn & 0x3f; reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); offset = utmp * fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; @@ -428,7 +449,7 @@ execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr, { case DW_CFA_set_loc: fs->pc = read_encoded_value (fde->cie->unit, fde->cie->encoding, - fde->cie->addr_size, insn_ptr, + fde->cie->ptr_size, insn_ptr, &bytes_read, fde->initial_location); /* Apply the objfile offset for relocatable objects. */ fs->pc += ANOFFSET (fde->cie->unit->objfile->section_offsets, @@ -453,9 +474,9 @@ execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr, break; case DW_CFA_offset_extended: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_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); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); offset = utmp * fs->data_align; dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; @@ -463,28 +484,28 @@ execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr, break; case DW_CFA_restore_extended: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_restore_rule (gdbarch, reg, fs, eh_frame_p); break; case DW_CFA_undefined: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_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, ®); + insn_ptr = safe_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, ®); + insn_ptr = safe_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); + insn_ptr = safe_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; @@ -495,7 +516,7 @@ execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr, { struct dwarf2_frame_state_reg_info *new_rs; - new_rs = XMALLOC (struct dwarf2_frame_state_reg_info); + new_rs = XNEW (struct dwarf2_frame_state_reg_info); *new_rs = fs->regs; fs->regs.reg = dwarf2_frame_state_copy_regs (&fs->regs); fs->regs.prev = new_rs; @@ -522,8 +543,9 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa: - insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->regs.cfa_reg); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); + fs->regs.cfa_reg = reg; + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); if (fs->armcc_cfa_offsets_sf) utmp *= fs->data_align; @@ -533,15 +555,14 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa_register: - 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, + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); + fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, 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); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); if (fs->armcc_cfa_offsets_sf) utmp *= fs->data_align; @@ -554,18 +575,18 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa_expression: - insn_ptr = read_uleb128 (insn_ptr, insn_end, - &fs->regs.cfa_exp_len); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); + fs->regs.cfa_exp_len = utmp; 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, ®); + insn_ptr = safe_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); + insn_ptr = safe_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_EXP; @@ -573,9 +594,9 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_offset_extended_sf: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_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); + insn_ptr = safe_read_sleb128 (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; @@ -583,27 +604,27 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_val_offset: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_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, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); + insn_ptr = safe_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, ®); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_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; @@ -611,17 +632,16 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), break; case DW_CFA_def_cfa_sf: - 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, + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®); + fs->regs.cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p); - insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset); + insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &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); + insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &offset); fs->regs.cfa_offset = offset * fs->data_align; /* cfa_how deliberately not set. */ break; @@ -636,6 +656,7 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), unwinder. */ { int size = register_size (gdbarch, 0); + dwarf2_frame_state_alloc_regs (&fs->regs, 32); for (reg = 8; reg < 16; reg++) { @@ -652,28 +673,34 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), case DW_CFA_GNU_args_size: /* Ignored. */ - insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); break; case DW_CFA_GNU_negative_offset_extended: - insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = safe_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; + insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp); + offset = utmp * 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.")); + internal_error (__FILE__, __LINE__, + _("Unknown CFI encountered.")); } } } - /* Don't allow remember/restore between CIE and FDE programs. */ - dwarf2_frame_state_free_regs (fs->regs.prev); - fs->regs.prev = NULL; + if (fs->initial.reg == NULL) + { + /* Don't allow remember/restore between CIE and FDE programs. */ + dwarf2_frame_state_free_regs (fs->regs.prev); + fs->regs.prev = NULL; + } + + return insn_ptr; } @@ -757,7 +784,8 @@ dwarf2_frame_set_init_reg (struct gdbarch *gdbarch, struct dwarf2_frame_state_reg *, struct frame_info *)) { - struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); + struct dwarf2_frame_ops *ops + = (struct dwarf2_frame_ops *) gdbarch_data (gdbarch, dwarf2_frame_data); ops->init_reg = init_reg; } @@ -769,7 +797,8 @@ dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, struct dwarf2_frame_state_reg *reg, struct frame_info *this_frame) { - struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); + struct dwarf2_frame_ops *ops + = (struct dwarf2_frame_ops *) gdbarch_data (gdbarch, dwarf2_frame_data); ops->init_reg (gdbarch, regnum, reg, this_frame); } @@ -782,7 +811,8 @@ dwarf2_frame_set_signal_frame_p (struct gdbarch *gdbarch, int (*signal_frame_p) (struct gdbarch *, struct frame_info *)) { - struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); + struct dwarf2_frame_ops *ops + = (struct dwarf2_frame_ops *) gdbarch_data (gdbarch, dwarf2_frame_data); ops->signal_frame_p = signal_frame_p; } @@ -794,7 +824,8 @@ static int dwarf2_frame_signal_frame_p (struct gdbarch *gdbarch, struct frame_info *this_frame) { - struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); + struct dwarf2_frame_ops *ops + = (struct dwarf2_frame_ops *) gdbarch_data (gdbarch, dwarf2_frame_data); if (ops->signal_frame_p == NULL) return 0; @@ -809,7 +840,8 @@ 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); + struct dwarf2_frame_ops *ops + = (struct dwarf2_frame_ops *) gdbarch_data (gdbarch, dwarf2_frame_data); ops->adjust_regnum = adjust_regnum; } @@ -818,9 +850,11 @@ dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch, register. */ static int -dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, int eh_frame_p) +dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, + int regnum, int eh_frame_p) { - struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data); + struct dwarf2_frame_ops *ops + = (struct dwarf2_frame_ops *) gdbarch_data (gdbarch, dwarf2_frame_data); if (ops->adjust_regnum == NULL) return regnum; @@ -831,51 +865,116 @@ static void dwarf2_frame_find_quirks (struct dwarf2_frame_state *fs, struct dwarf2_fde *fde) { - static const char *arm_idents[] = { - "ARM C Compiler, ADS", - "Thumb C Compiler, ADS", - "ARM C++ Compiler, ADS", - "Thumb C++ Compiler, ADS", - "ARM/Thumb C/C++ Compiler, RVCT" - }; - int i; - - struct symtab *s; - - s = find_pc_symtab (fs->pc); - if (s == NULL || s->producer == NULL) + struct compunit_symtab *cust; + + cust = find_pc_compunit_symtab (fs->pc); + if (cust == NULL) return; - for (i = 0; i < ARRAY_SIZE (arm_idents); i++) - if (strncmp (s->producer, arm_idents[i], strlen (arm_idents[i])) == 0) + if (producer_is_realview (COMPUNIT_PRODUCER (cust))) + { + 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 + && (!startswith (fde->cie->augmentation, "armcc") + || strchr (fde->cie->augmentation + 5, '+') == NULL)) + fs->armcc_cfa_offsets_reversed = 1; + + return; + } +} + + +/* See dwarf2-frame.h. */ + +int +dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc, + struct dwarf2_per_cu_data *data, + int *regnum_out, LONGEST *offset_out, + CORE_ADDR *text_offset_out, + const gdb_byte **cfa_start_out, + const gdb_byte **cfa_end_out) +{ + struct dwarf2_fde *fde; + CORE_ADDR text_offset; + struct dwarf2_frame_state fs; + int addr_size; + + memset (&fs, 0, sizeof (struct dwarf2_frame_state)); + + fs.pc = pc; + + /* Find the correct FDE. */ + fde = dwarf2_frame_find_fde (&fs.pc, &text_offset); + if (fde == NULL) + error (_("Could not compute CFA; needed to translate this expression")); + + /* Extract any interesting information from the CIE. */ + fs.data_align = fde->cie->data_alignment_factor; + fs.code_align = fde->cie->code_alignment_factor; + fs.retaddr_column = fde->cie->return_address_register; + 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, fde->cie->initial_instructions, + fde->cie->end, gdbarch, pc, &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, fde->instructions, fde->end, gdbarch, pc, &fs); + + /* Calculate the CFA. */ + switch (fs.regs.cfa_how) + { + case CFA_REG_OFFSET: { - 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; + int regnum = dwarf_reg_to_regnum_or_error (gdbarch, fs.regs.cfa_reg); + + *regnum_out = regnum; + if (fs.armcc_cfa_offsets_reversed) + *offset_out = -fs.regs.cfa_offset; + else + *offset_out = fs.regs.cfa_offset; + return 1; } + + case CFA_EXP: + *text_offset_out = text_offset; + *cfa_start_out = fs.regs.cfa_exp; + *cfa_end_out = fs.regs.cfa_exp + fs.regs.cfa_exp_len; + return 0; + + default: + internal_error (__FILE__, __LINE__, _("Unknown CFA rule.")); + } } - + struct dwarf2_frame_cache { /* DWARF Call Frame Address. */ CORE_ADDR cfa; + /* Set if the return address column was marked as unavailable + (required non-collected memory or registers to compute). */ + int unavailable_retaddr; + /* Set if the return address column was marked as undefined. */ int undefined_retaddr; @@ -888,29 +987,62 @@ struct dwarf2_frame_cache /* Target address size in bytes. */ int addr_size; + + /* The .text offset. */ + CORE_ADDR text_offset; + + /* True if we already checked whether this frame is the bottom frame + of a virtual tail call frame chain. */ + int checked_tailcall_bottom; + + /* If not NULL then this frame is the bottom frame of a TAILCALL_FRAME + sequence. If NULL then it is a normal case with no TAILCALL_FRAME + involved. Non-bottom frames of a virtual tail call frames chain use + dwarf2_tailcall_frame_unwind unwinder so this field does not apply for + them. */ + void *tailcall_cache; + + /* The number of bytes to subtract from TAILCALL_FRAME frames frame + base to get the SP, to simulate the return address pushed on the + stack. */ + LONGEST entry_cfa_sp_offset; + int entry_cfa_sp_offset_p; }; +/* A cleanup that sets a pointer to NULL. */ + +static void +clear_pointer_cleanup (void *arg) +{ + void **ptr = (void **) arg; + + *ptr = NULL; +} + static struct dwarf2_frame_cache * dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) { - struct cleanup *old_chain; + struct cleanup *reset_cache_cleanup, *old_chain; 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; + CORE_ADDR entry_pc; + const gdb_byte *instr; if (*this_cache) - return *this_cache; + return (struct dwarf2_frame_cache *) *this_cache; /* Allocate a new cache. */ cache = FRAME_OBSTACK_ZALLOC (struct dwarf2_frame_cache); cache->reg = FRAME_OBSTACK_CALLOC (num_regs, struct dwarf2_frame_state_reg); + *this_cache = cache; + reset_cache_cleanup = make_cleanup (clear_pointer_cleanup, this_cache); /* Allocate and initialize the frame state. */ - fs = XMALLOC (struct dwarf2_frame_state); - memset (fs, 0, sizeof (struct dwarf2_frame_state)); + fs = XCNEW (struct dwarf2_frame_state); old_chain = make_cleanup (dwarf2_frame_state_free, fs); /* Unwind the PC. @@ -931,7 +1063,7 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) fs->pc = get_frame_address_in_block (this_frame); /* Find the correct FDE. */ - fde = dwarf2_frame_find_fde (&fs->pc); + fde = dwarf2_frame_find_fde (&fs->pc, &cache->text_offset); gdb_assert (fde != NULL); /* Extract any interesting information from the CIE. */ @@ -945,35 +1077,71 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) /* First decode all the insns in the CIE. */ execute_cfa_program (fde, fde->cie->initial_instructions, - fde->cie->end, this_frame, fs); + fde->cie->end, gdbarch, + get_frame_address_in_block (this_frame), fs); /* Save the initialized register set. */ fs->initial = fs->regs; fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs); + if (get_frame_func_if_available (this_frame, &entry_pc)) + { + /* Decode the insns in the FDE up to the entry PC. */ + instr = execute_cfa_program (fde, fde->instructions, fde->end, gdbarch, + entry_pc, fs); + + if (fs->regs.cfa_how == CFA_REG_OFFSET + && (dwarf_reg_to_regnum (gdbarch, fs->regs.cfa_reg) + == gdbarch_sp_regnum (gdbarch))) + { + cache->entry_cfa_sp_offset = fs->regs.cfa_offset; + cache->entry_cfa_sp_offset_p = 1; + } + } + else + instr = fde->instructions; + /* Then decode the insns in the FDE up to our target PC. */ - execute_cfa_program (fde, fde->instructions, fde->end, this_frame, fs); + execute_cfa_program (fde, instr, fde->end, gdbarch, + get_frame_address_in_block (this_frame), fs); - /* Calculate the CFA. */ - switch (fs->regs.cfa_how) + TRY { - case CFA_REG_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->regs.cfa_exp, fs->regs.cfa_exp_len, - cache->addr_size, this_frame, 0); - break; + /* Calculate the CFA. */ + switch (fs->regs.cfa_how) + { + case CFA_REG_OFFSET: + cache->cfa = read_addr_from_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->regs.cfa_exp, fs->regs.cfa_exp_len, + cache->addr_size, cache->text_offset, + this_frame, 0, 0); + break; + + default: + internal_error (__FILE__, __LINE__, _("Unknown CFA rule.")); + } + } + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error == NOT_AVAILABLE_ERROR) + { + cache->unavailable_retaddr = 1; + do_cleanups (old_chain); + discard_cleanups (reset_cache_cleanup); + return cache; + } - default: - internal_error (__FILE__, __LINE__, _("Unknown CFA rule.")); + throw_exception (ex); } + END_CATCH /* Initialize the register state. */ { @@ -986,19 +1154,16 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) /* Go through the DWARF2 CFI generated table and save its register location information in the cache. Note that we don't skip the 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, - gdbarch_dwarf2_reg_to_regnum should be defined to return a number outside - the range [0, gdbarch_num_regs). */ + correspond to a real register. */ { 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 = gdbarch_dwarf2_reg_to_regnum (gdbarch, column); + int regnum = dwarf_reg_to_regnum (gdbarch, column); - /* If there's no corresponding GDB register, ignore it. */ + /* Protect against a target returning a bad register. */ if (regnum < 0 || regnum >= num_regs) continue; @@ -1077,11 +1242,26 @@ incomplete CFI data; unspecified registers (e.g., %s) at %s"), cache->undefined_retaddr = 1; do_cleanups (old_chain); - - *this_cache = cache; + discard_cleanups (reset_cache_cleanup); return cache; } +static enum unwind_stop_reason +dwarf2_frame_unwind_stop_reason (struct frame_info *this_frame, + void **this_cache) +{ + struct dwarf2_frame_cache *cache + = dwarf2_frame_cache (this_frame, this_cache); + + if (cache->unavailable_retaddr) + return UNWIND_UNAVAILABLE; + + if (cache->undefined_retaddr) + return UNWIND_OUTERMOST; + + return UNWIND_NO_REASON; +} + static void dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id) @@ -1089,10 +1269,12 @@ dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache, struct dwarf2_frame_cache *cache = dwarf2_frame_cache (this_frame, this_cache); - if (cache->undefined_retaddr) + if (cache->unavailable_retaddr) + (*this_id) = frame_id_build_unavailable_stack (get_frame_func (this_frame)); + else if (cache->undefined_retaddr) return; - - (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); + else + (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); } static struct value * @@ -1105,6 +1287,32 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, CORE_ADDR addr; int realnum; + /* Check whether THIS_FRAME is the bottom frame of a virtual tail + call frame chain. */ + if (!cache->checked_tailcall_bottom) + { + cache->checked_tailcall_bottom = 1; + dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache, + (cache->entry_cfa_sp_offset_p + ? &cache->entry_cfa_sp_offset : NULL)); + } + + /* Non-bottom frames of a virtual tail call frames chain use + dwarf2_tailcall_frame_unwind unwinder so this code does not apply for + them. If dwarf2_tailcall_prev_register_first does not have specific value + unwind the register, tail call frames are assumed to have the register set + of the top caller. */ + if (cache->tailcall_cache) + { + struct value *val; + + val = dwarf2_tailcall_prev_register_first (this_frame, + &cache->tailcall_cache, + regnum); + if (val) + return val; + } + switch (cache->reg[regnum].how) { case DWARF2_FRAME_REG_UNDEFINED: @@ -1117,14 +1325,15 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, return frame_unwind_got_memory (this_frame, regnum, addr); case DWARF2_FRAME_REG_SAVED_REG: - realnum - = gdbarch_dwarf2_reg_to_regnum (gdbarch, cache->reg[regnum].loc.reg); + realnum = dwarf_reg_to_regnum_or_error + (gdbarch, cache->reg[regnum].loc.reg); return frame_unwind_got_register (this_frame, regnum, realnum); case DWARF2_FRAME_REG_SAVED_EXP: addr = execute_stack_op (cache->reg[regnum].loc.exp, cache->reg[regnum].exp_len, - cache->addr_size, this_frame, cache->cfa); + cache->addr_size, cache->text_offset, + this_frame, cache->cfa, 1); return frame_unwind_got_memory (this_frame, regnum, addr); case DWARF2_FRAME_REG_SAVED_VAL_OFFSET: @@ -1134,7 +1343,8 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, 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); + cache->addr_size, cache->text_offset, + this_frame, cache->cfa, 1); return frame_unwind_got_constant (this_frame, regnum, addr); case DWARF2_FRAME_REG_UNSPECIFIED: @@ -1159,7 +1369,7 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, case DWARF2_FRAME_REG_RA_OFFSET: addr = cache->reg[regnum].loc.offset; - regnum = gdbarch_dwarf2_reg_to_regnum + regnum = dwarf_reg_to_regnum_or_error (gdbarch, cache->retaddr_reg.loc.reg); addr += get_frame_register_unsigned (this_frame, regnum); return frame_unwind_got_address (this_frame, regnum, addr); @@ -1172,6 +1382,18 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, } } +/* Proxy for tailcall_frame_dealloc_cache for bottom frame of a virtual tail + call frames chain. */ + +static void +dwarf2_frame_dealloc_cache (struct frame_info *self, void *this_cache) +{ + struct dwarf2_frame_cache *cache = dwarf2_frame_cache (self, &this_cache); + + if (cache->tailcall_cache) + dwarf2_tailcall_frame_unwind.dealloc_cache (self, cache->tailcall_cache); +} + static int dwarf2_frame_sniffer (const struct frame_unwind *self, struct frame_info *this_frame, void **this_cache) @@ -1184,7 +1406,8 @@ dwarf2_frame_sniffer (const struct frame_unwind *self, 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); + struct dwarf2_fde *fde = dwarf2_frame_find_fde (&block_addr, NULL); + if (!fde) return 0; @@ -1197,25 +1420,34 @@ dwarf2_frame_sniffer (const struct frame_unwind *self, this_frame)) return self->type == SIGTRAMP_FRAME; - return self->type != SIGTRAMP_FRAME; + if (self->type != NORMAL_FRAME) + return 0; + + return 1; } static const struct frame_unwind dwarf2_frame_unwind = { NORMAL_FRAME, + dwarf2_frame_unwind_stop_reason, dwarf2_frame_this_id, dwarf2_frame_prev_register, NULL, - dwarf2_frame_sniffer + dwarf2_frame_sniffer, + dwarf2_frame_dealloc_cache }; static const struct frame_unwind dwarf2_signal_frame_unwind = { SIGTRAMP_FRAME, + dwarf2_frame_unwind_stop_reason, dwarf2_frame_this_id, dwarf2_frame_prev_register, NULL, - dwarf2_frame_sniffer + dwarf2_frame_sniffer, + + /* TAILCALL_CACHE can never be in such frame to need dealloc_cache. */ + NULL }; /* Append the DWARF-2 frame unwinders to GDBARCH's list. */ @@ -1223,6 +1455,10 @@ static const struct frame_unwind dwarf2_signal_frame_unwind = void dwarf2_append_unwinders (struct gdbarch *gdbarch) { + /* TAILCALL_FRAME must be first to find the record by + dwarf2_tailcall_sniffer_first. */ + frame_unwind_append_unwinder (gdbarch, &dwarf2_tailcall_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &dwarf2_frame_unwind); frame_unwind_append_unwinder (gdbarch, &dwarf2_signal_frame_unwind); } @@ -1255,7 +1491,8 @@ const struct frame_base * dwarf2_frame_base_sniffer (struct frame_info *this_frame) { CORE_ADDR block_addr = get_frame_address_in_block (this_frame); - if (dwarf2_frame_find_fde (&block_addr)) + + if (dwarf2_frame_find_fde (&block_addr, NULL)) return &dwarf2_frame_base; return NULL; @@ -1268,95 +1505,49 @@ dwarf2_frame_base_sniffer (struct frame_info *this_frame) CORE_ADDR dwarf2_frame_cfa (struct frame_info *this_frame) { + if (frame_unwinder_is (this_frame, &record_btrace_tailcall_frame_unwind) + || frame_unwinder_is (this_frame, &record_btrace_frame_unwind)) + throw_error (NOT_AVAILABLE_ERROR, + _("cfa not available for record btrace target")); + 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")); + if (get_frame_unwind_stop_reason (this_frame) == UNWIND_UNAVAILABLE) + throw_error (NOT_AVAILABLE_ERROR, + _("can't compute CFA for this frame: " + "required registers or memory are unavailable")); + + if (get_frame_id (this_frame).stack_status != FID_STACK_VALID) + throw_error (NOT_AVAILABLE_ERROR, + _("can't compute CFA for this frame: " + "frame base not available")); + return get_frame_base (this_frame); } const struct objfile_data *dwarf2_frame_objfile_data; static unsigned int -read_1_byte (bfd *abfd, gdb_byte *buf) +read_1_byte (bfd *abfd, const gdb_byte *buf) { return bfd_get_8 (abfd, buf); } static unsigned int -read_4_bytes (bfd *abfd, gdb_byte *buf) +read_4_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_32 (abfd, buf); } static ULONGEST -read_8_bytes (bfd *abfd, gdb_byte *buf) +read_8_bytes (bfd *abfd, const gdb_byte *buf) { return bfd_get_64 (abfd, buf); } static ULONGEST -read_unsigned_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) -{ - ULONGEST result; - unsigned int num_read; - int shift; - gdb_byte byte; - - result = 0; - shift = 0; - num_read = 0; - - do - { - byte = bfd_get_8 (abfd, (bfd_byte *) buf); - buf++; - num_read++; - result |= ((byte & 0x7f) << shift); - shift += 7; - } - while (byte & 0x80); - - *bytes_read_ptr = num_read; - - return result; -} - -static LONGEST -read_signed_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) -{ - LONGEST result; - int shift; - unsigned int num_read; - gdb_byte byte; - - result = 0; - shift = 0; - num_read = 0; - - do - { - byte = bfd_get_8 (abfd, (bfd_byte *) buf); - buf++; - num_read++; - result |= ((byte & 0x7f) << shift); - shift += 7; - } - while (byte & 0x80); - - if (shift < 8 * sizeof (result) && (byte & 0x40)) - result |= -(((LONGEST)1) << shift); - - *bytes_read_ptr = num_read; - - return result; -} - -static ULONGEST -read_initial_length (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) +read_initial_length (bfd *abfd, const gdb_byte *buf, + unsigned int *bytes_read_ptr) { LONGEST result; @@ -1407,7 +1598,8 @@ encoding_for_size (unsigned int size) static CORE_ADDR read_encoded_value (struct comp_unit *unit, gdb_byte encoding, - int ptr_len, gdb_byte *buf, unsigned int *bytes_read_ptr, + int ptr_len, const gdb_byte *buf, + unsigned int *bytes_read_ptr, CORE_ADDR func_base) { ptrdiff_t offset; @@ -1449,7 +1641,8 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, } break; default: - internal_error (__FILE__, __LINE__, _("Invalid or unsupported encoding")); + internal_error (__FILE__, __LINE__, + _("Invalid or unsupported encoding")); } if ((encoding & 0x07) == 0x00) @@ -1463,9 +1656,10 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, { case DW_EH_PE_uleb128: { - ULONGEST value; - gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7; - *bytes_read_ptr += read_uleb128 (buf, end_buf, &value) - buf; + uint64_t value; + const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7; + + *bytes_read_ptr += safe_read_uleb128 (buf, end_buf, &value) - buf; return base + value; } case DW_EH_PE_udata2: @@ -1479,9 +1673,10 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, return (base + bfd_get_64 (unit->abfd, (bfd_byte *) buf)); case DW_EH_PE_sleb128: { - LONGEST value; - gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7; - *bytes_read_ptr += read_sleb128 (buf, end_buf, &value) - buf; + int64_t value; + const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7; + + *bytes_read_ptr += safe_read_sleb128 (buf, end_buf, &value) - buf; return base + value; } case DW_EH_PE_sdata2: @@ -1494,7 +1689,8 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding, *bytes_read_ptr += 8; return (base + bfd_get_signed_64 (unit->abfd, (bfd_byte *) buf)); default: - internal_error (__FILE__, __LINE__, _("Invalid or unsupported encoding")); + internal_error (__FILE__, __LINE__, + _("Invalid or unsupported encoding")); } } @@ -1517,8 +1713,17 @@ find_cie (struct dwarf2_cie_table *cie_table, ULONGEST cie_pointer) { struct dwarf2_cie **p_cie; - p_cie = bsearch (&cie_pointer, cie_table->entries, cie_table->num_entries, - sizeof (cie_table->entries[0]), bsearch_cie_cmp); + /* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to + bsearch be non-NULL. */ + if (cie_table->entries == NULL) + { + gdb_assert (cie_table->num_entries == 0); + return NULL; + } + + p_cie = ((struct dwarf2_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; @@ -1533,8 +1738,8 @@ add_cie (struct dwarf2_cie_table *cie_table, struct dwarf2_cie *cie) 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 + = XRESIZEVEC (struct dwarf2_cie *, cie_table->entries, n + 1); cie_table->entries[n] = cie; cie_table->num_entries = n + 1; } @@ -1544,6 +1749,7 @@ 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) @@ -1555,7 +1761,7 @@ bsearch_fde_cmp (const void *key, const void *element) inital location associated with it into *PC. */ static struct dwarf2_fde * -dwarf2_frame_find_fde (CORE_ADDR *pc) +dwarf2_frame_find_fde (CORE_ADDR *pc, CORE_ADDR *out_offset) { struct objfile *objfile; @@ -1566,8 +1772,17 @@ dwarf2_frame_find_fde (CORE_ADDR *pc) CORE_ADDR offset; CORE_ADDR seek_pc; - fde_table = objfile_data (objfile, dwarf2_frame_objfile_data); + fde_table = ((struct dwarf2_fde_table *) + objfile_data (objfile, dwarf2_frame_objfile_data)); if (fde_table == NULL) + { + dwarf2_build_frame_info (objfile); + fde_table = ((struct dwarf2_fde_table *) + objfile_data (objfile, dwarf2_frame_objfile_data)); + } + gdb_assert (fde_table != NULL); + + if (fde_table->num_entries == 0) continue; gdb_assert (objfile->section_offsets); @@ -1578,11 +1793,14 @@ dwarf2_frame_find_fde (CORE_ADDR *pc) continue; seek_pc = *pc - offset; - p_fde = bsearch (&seek_pc, fde_table->entries, fde_table->num_entries, - sizeof (fde_table->entries[0]), bsearch_fde_cmp); + p_fde = ((struct dwarf2_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; + if (out_offset) + *out_offset = offset; return *p_fde; } } @@ -1598,44 +1816,56 @@ add_fde (struct dwarf2_fde_table *fde_table, struct dwarf2_fde *fde) 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 = XRESIZEVEC (struct dwarf2_fde *, fde_table->entries, + fde_table->num_entries); fde_table->entries[fde_table->num_entries - 1] = fde; } -#ifdef CC_HAS_LONG_LONG #define DW64_CIE_ID 0xffffffffffffffffULL -#else -#define DW64_CIE_ID ~0 -#endif - -static gdb_byte *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); - -/* 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, + +/* Defines the type of eh_frames that are expected to be decoded: CIE, FDE + or any of them. */ + +enum eh_frame_type +{ + EH_CIE_TYPE_ID = 1 << 0, + EH_FDE_TYPE_ID = 1 << 1, + EH_CIE_OR_FDE_TYPE_ID = EH_CIE_TYPE_ID | EH_FDE_TYPE_ID +}; + +static const gdb_byte *decode_frame_entry (struct comp_unit *unit, + const gdb_byte *start, + int eh_frame_p, + struct dwarf2_cie_table *cie_table, + struct dwarf2_fde_table *fde_table, + enum eh_frame_type entry_type); + +/* Decode the next CIE or FDE, entry_type specifies the expected type. + Return NULL if invalid input, otherwise the next byte to be processed. */ + +static const gdb_byte * +decode_frame_entry_1 (struct comp_unit *unit, const gdb_byte *start, + int eh_frame_p, struct dwarf2_cie_table *cie_table, - struct dwarf2_fde_table *fde_table) + struct dwarf2_fde_table *fde_table, + enum eh_frame_type entry_type) { struct gdbarch *gdbarch = get_objfile_arch (unit->objfile); - gdb_byte *buf, *end; + const gdb_byte *buf, *end; LONGEST length; unsigned int bytes_read; int dwarf64_p; ULONGEST cie_id; ULONGEST cie_pointer; + int64_t sleb128; + uint64_t uleb128; buf = start; length = read_initial_length (unit->abfd, buf, &bytes_read); buf += bytes_read; end = buf + length; - /* Are we still within the section? */ + /* Are we still within the section? */ if (end > unit->dwarf_frame_buffer + unit->dwarf_frame_size) return NULL; @@ -1671,6 +1901,10 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, char *augmentation; unsigned int cie_version; + /* Check that a CIE was expected. */ + if ((entry_type & EH_CIE_TYPE_ID) == 0) + error (_("Found a CIE when not expecting it.")); + /* Record the offset into the .debug_frame section of this CIE. */ cie_pointer = start - unit->dwarf_frame_buffer; @@ -1678,9 +1912,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, if (find_cie (cie_table, cie_pointer)) return end; - cie = (struct dwarf2_cie *) - obstack_alloc (&unit->objfile->objfile_obstack, - sizeof (struct dwarf2_cie)); + cie = XOBNEW (&unit->objfile->objfile_obstack, struct dwarf2_cie); cie->initial_instructions = NULL; cie->cie_pointer = cie_pointer; @@ -1688,20 +1920,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; /* 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; @@ -1712,7 +1937,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, /* Ignore armcc augmentations. We only use them for quirks, and that doesn't happen until later. */ - if (strncmp (augmentation, "armcc", 5) == 0) + if (startswith (augmentation, "armcc")) augmentation += strlen (augmentation); /* The GCC 2.x "eh" augmentation has a pointer immediately @@ -1725,37 +1950,63 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, augmentation += 2; } - cie->code_alignment_factor = - read_unsigned_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read; + 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_dwarf2_addr_size (gdbarch); + cie->segment_size = 0; + } + /* Address values in .eh_frame sections are defined to have the + target's pointer size. Watchout: This breaks frame info for + targets with pointer size < address size, unless a .debug_frame + section exists as well. */ + if (eh_frame_p) + cie->ptr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; + else + cie->ptr_size = cie->addr_size; - cie->data_alignment_factor = - read_signed_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read; + buf = gdb_read_uleb128 (buf, end, &uleb128); + if (buf == NULL) + return NULL; + cie->code_alignment_factor = uleb128; + + buf = gdb_read_sleb128 (buf, end, &sleb128); + if (buf == NULL) + return NULL; + cie->data_alignment_factor = sleb128; if (cie_version == 1) { cie->return_address_register = read_1_byte (unit->abfd, buf); - bytes_read = 1; + ++buf; } else - cie->return_address_register = read_unsigned_leb128 (unit->abfd, buf, - &bytes_read); + { + buf = gdb_read_uleb128 (buf, end, &uleb128); + if (buf == NULL) + return NULL; + cie->return_address_register = uleb128; + } + 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'); if (cie->saw_z_augmentation) { - ULONGEST length; + uint64_t length; - length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read; - if (buf > end) + buf = gdb_read_uleb128 (buf, end, &length); + if (buf == NULL) return NULL; cie->initial_instructions = buf + length; augmentation++; @@ -1783,7 +2034,7 @@ 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, cie->addr_size, + read_encoded_value (unit, encoding, cie->ptr_size, buf, &bytes_read, 0); buf += bytes_read; augmentation++; @@ -1820,6 +2071,11 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, { /* This is a FDE. */ struct dwarf2_fde *fde; + CORE_ADDR addr; + + /* Check that an FDE was expected. */ + if ((entry_type & EH_FDE_TYPE_ID) == 0) + error (_("Found an FDE when not expecting it.")); /* In an .eh_frame section, the CIE pointer is the delta between the address within the FDE where the CIE pointer is stored and the @@ -1835,27 +2091,28 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, if (cie_pointer >= unit->dwarf_frame_size) return NULL; - fde = (struct dwarf2_fde *) - obstack_alloc (&unit->objfile->objfile_obstack, - sizeof (struct dwarf2_fde)); + fde = XOBNEW (&unit->objfile->objfile_obstack, struct dwarf2_fde); 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, cie_table, fde_table); + eh_frame_p, cie_table, fde_table, + EH_CIE_TYPE_ID); fde->cie = find_cie (cie_table, cie_pointer); } gdb_assert (fde->cie != NULL); - fde->initial_location = - read_encoded_value (unit, fde->cie->encoding, fde->cie->addr_size, - buf, &bytes_read, 0); + addr = read_encoded_value (unit, fde->cie->encoding, fde->cie->ptr_size, + buf, &bytes_read, 0); + fde->initial_location = gdbarch_adjust_dwarf2_addr (gdbarch, addr); buf += bytes_read; fde->address_range = read_encoded_value (unit, fde->cie->encoding & 0x0f, - fde->cie->addr_size, buf, &bytes_read, 0); + fde->cie->ptr_size, buf, &bytes_read, 0); + addr = gdbarch_adjust_dwarf2_addr (gdbarch, addr + fde->address_range); + fde->address_range = addr - fde->initial_location; buf += bytes_read; /* A 'z' augmentation in the CIE implies the presence of an @@ -1864,10 +2121,12 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, can skip the whole thing. */ if (fde->cie->saw_z_augmentation) { - ULONGEST length; + uint64_t length; - length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); - buf += bytes_read + length; + buf = gdb_read_uleb128 (buf, end, &length); + if (buf == NULL) + return NULL; + buf += length; if (buf > end) return NULL; } @@ -1883,21 +2142,24 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, return end; } -/* 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, +/* Read a CIE or FDE in BUF and decode it. Entry_type specifies whether we + expect an FDE or a CIE. */ + +static const gdb_byte * +decode_frame_entry (struct comp_unit *unit, const gdb_byte *start, + int eh_frame_p, struct dwarf2_cie_table *cie_table, - struct dwarf2_fde_table *fde_table) + struct dwarf2_fde_table *fde_table, + enum eh_frame_type entry_type) { enum { NONE, ALIGN4, ALIGN8, FAIL } workaround = NONE; - gdb_byte *ret; - const char *msg; + const gdb_byte *ret; ptrdiff_t start_offset; while (1) { ret = decode_frame_entry_1 (unit, start, eh_frame_p, - cie_table, fde_table); + cie_table, fde_table, entry_type); if (ret != NULL) break; @@ -1954,15 +2216,15 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, break; case ALIGN4: - complaint (&symfile_complaints, - _("Corrupt data in %s:%s; align 4 workaround apparently succeeded"), + complaint (&symfile_complaints, _("\ +Corrupt data in %s:%s; align 4 workaround apparently succeeded"), unit->dwarf_frame_section->owner->filename, unit->dwarf_frame_section->name); break; case ALIGN8: - complaint (&symfile_complaints, - _("Corrupt data in %s:%s; align 8 workaround apparently succeeded"), + complaint (&symfile_complaints, _("\ +Corrupt data in %s:%s; align 8 workaround apparently succeeded"), unit->dwarf_frame_section->owner->filename, unit->dwarf_frame_section->name); break; @@ -1978,11 +2240,6 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, return ret; } - -/* Imported from dwarf2read.c. */ -extern void dwarf2_get_section_info (struct objfile *, const char *, asection **, - gdb_byte **, bfd_size_type *); - static int qsort_fde_cmp (const void *a, const void *b) { @@ -2008,9 +2265,10 @@ void dwarf2_build_frame_info (struct objfile *objfile) { struct comp_unit *unit; - gdb_byte *frame_ptr; + const 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; @@ -2026,52 +2284,106 @@ dwarf2_build_frame_info (struct 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) + if (objfile->separate_debug_objfile_backlink == NULL) { - asection *got, *txt; - - /* 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"); - if (got) - 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"); - if (txt) - 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) + /* Do not read .eh_frame from separate file as they must be also + present in the main file. */ + dwarf2_get_section_info (objfile, DWARF2_EH_FRAME, + &unit->dwarf_frame_section, + &unit->dwarf_frame_buffer, + &unit->dwarf_frame_size); + if (unit->dwarf_frame_size) { - /* Reinit cie_table: debug_frame has different CIEs. */ - xfree (cie_table.entries); - cie_table.num_entries = 0; - cie_table.entries = NULL; + asection *got, *txt; + + /* 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"); + if (got) + 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"); + if (txt) + unit->tbase = txt->vma; + + TRY + { + 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, + EH_CIE_OR_FDE_TYPE_ID); + } + + CATCH (e, RETURN_MASK_ERROR) + { + warning (_("skipping .eh_frame info of %s: %s"), + objfile_name (objfile), e.message); + + if (fde_table.num_entries != 0) + { + xfree (fde_table.entries); + fde_table.entries = NULL; + fde_table.num_entries = 0; + } + /* The cie_table is discarded by the next if. */ + } + END_CATCH + + 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", + dwarf2_get_section_info (objfile, DWARF2_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); + int num_old_fde_entries = fde_table.num_entries; + + TRY + { + 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, + EH_CIE_OR_FDE_TYPE_ID); + } + CATCH (e, RETURN_MASK_ERROR) + { + warning (_("skipping .debug_frame info of %s: %s"), + objfile_name (objfile), e.message); + + if (fde_table.num_entries != 0) + { + fde_table.num_entries = num_old_fde_entries; + if (num_old_fde_entries == 0) + { + xfree (fde_table.entries); + fde_table.entries = NULL; + } + else + { + fde_table.entries + = XRESIZEVEC (struct dwarf2_fde *, fde_table.entries, + fde_table.num_entries); + } + } + fde_table.num_entries = num_old_fde_entries; + /* The cie_table is discarded by the next if. */ + } + END_CATCH } /* Discard the cie_table, it is no longer needed. */ @@ -2082,39 +2394,78 @@ dwarf2_build_frame_info (struct objfile *objfile) cie_table.num_entries = 0; /* Paranoia. */ } - if (fde_table.num_entries != 0) + /* Copy fde_table to obstack: it is needed at runtime. */ + fde_table2 = XOBNEW (&objfile->objfile_obstack, struct dwarf2_fde_table); + + if (fde_table.num_entries == 0) + { + fde_table2->entries = NULL; + fde_table2->num_entries = 0; + } + else { - struct dwarf2_fde_table *fde_table2; - int i, j; + 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); - /* Copy fde_table to obstack: it is needed at runtime. */ - fde_table2 = (struct dwarf2_fde_table *) - obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2)); + /* 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]; - /* 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); + 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 + = (struct dwarf2_fde **) 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. */