/* Frame unwinder for frames with DWARF Call Frame Information.
- Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2014 Free Software Foundation, Inc.
Contributed by Mark Kettenis.
#include "value.h"
#include "gdb_assert.h"
-#include "gdb_string.h"
+#include <string.h>
#include "complaints.h"
#include "dwarf2-frame.h"
#include "ax.h"
#include "dwarf2loc.h"
#include "exceptions.h"
+#include "dwarf2-frame-tailcall.h"
struct comp_unit;
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;
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. */
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;
/* 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);
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 unpack_pointer (register_type (gdbarch, regnum), buf);
}
-static void
-read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len)
-{
- read_memory (addr, buf, len);
-}
-
-static void
-no_get_frame_base (void *baton, const gdb_byte **start, size_t *length)
-{
- internal_error (__FILE__, __LINE__,
- _("Support for DW_OP_fbreg is unimplemented"));
-}
-
-/* Helper function for execute_stack_op. */
+/* Implement struct dwarf_expr_context_funcs' "get_reg_value" callback. */
-static CORE_ADDR
-no_get_frame_cfa (void *baton)
-{
- internal_error (__FILE__, __LINE__,
- _("Support for DW_OP_call_frame_cfa is unimplemented"));
-}
-
-/* Helper function for execute_stack_op. */
-
-static CORE_ADDR
-no_get_frame_pc (void *baton)
+static struct value *
+get_reg_value (void *baton, struct type *type, int reg)
{
- internal_error (__FILE__, __LINE__, _("\
-Support for DW_OP_GNU_implicit_pointer is unimplemented"));
-}
+ struct frame_info *this_frame = (struct frame_info *) baton;
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
-static CORE_ADDR
-no_get_tls_address (void *baton, CORE_ADDR offset)
-{
- internal_error (__FILE__, __LINE__, _("\
-Support for DW_OP_GNU_push_tls_address is unimplemented"));
+ return value_from_register (type, regnum, this_frame);
}
-/* Helper function for execute_stack_op. */
-
static void
-no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
-{
- internal_error (__FILE__, __LINE__,
- _("Support for DW_OP_call* is invalid in CFI"));
-}
-
-/* Helper function for execute_stack_op. */
-
-static struct type *
-no_base_type (struct dwarf_expr_context *ctx, size_t die)
+read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len)
{
- error (_("Support for typed DWARF is not supported in CFI"));
+ read_memory (addr, buf, len);
}
/* Execute the required actions for both the DW_CFA_restore and
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 (const gdb_byte *exp, ULONGEST len, int addr_size,
CORE_ADDR offset, struct frame_info *this_frame,
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_frame_pc = no_get_frame_pc;
- ctx->get_tls_address = no_get_tls_address;
- ctx->dwarf_call = no_dwarf_call;
- ctx->get_base_type = no_base_type;
+ ctx->funcs = &dwarf2_frame_ctx_funcs;
dwarf_expr_push_address (ctx, initial, initial_in_stack_memory);
dwarf_expr_eval (ctx, exp, len);
if (ctx->location == DWARF_VALUE_MEMORY)
result = dwarf_expr_fetch_address (ctx, 0);
else if (ctx->location == DWARF_VALUE_REGISTER)
- result = read_reg (this_frame, value_as_long (dwarf_expr_fetch (ctx, 0)));
+ 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
}
\f
-static void
+/* 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;
- int bytes_read;
+ 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;
{
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;
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;
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;
{
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;
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;
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;
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;
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;
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;
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;
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;
}
}
- /* 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;
}
\f
CORE_ADDR pc,
struct dwarf2_per_cu_data *data)
{
- const int num_regs = gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch);
struct dwarf2_fde *fde;
- CORE_ADDR text_offset, cfa;
+ CORE_ADDR text_offset;
struct dwarf2_frame_state fs;
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 = 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_state *fs;
struct dwarf2_fde *fde;
volatile struct gdb_exception ex;
+ CORE_ADDR entry_pc;
+ const gdb_byte *instr;
if (*this_cache)
return *this_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 = XZALLOC (struct dwarf2_frame_state);
+ fs = XCNEW (struct dwarf2_frame_state);
old_chain = make_cleanup (dwarf2_frame_state_free, fs);
/* Unwind the PC.
/* First decode all the insns in the CIE. */
execute_cfa_program (fde, fde->cie->initial_instructions,
- fde->cie->end, gdbarch, get_frame_pc (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
+ && (gdbarch_dwarf2_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, gdbarch,
- get_frame_pc (this_frame), fs);
+ execute_cfa_program (fde, instr, fde->end, gdbarch,
+ get_frame_address_in_block (this_frame), fs);
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
switch (fs->regs.cfa_how)
{
case CFA_REG_OFFSET:
- cache->cfa = read_reg (this_frame, fs->regs.cfa_reg);
+ 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
if (ex.error == NOT_AVAILABLE_ERROR)
{
cache->unavailable_retaddr = 1;
+ do_cleanups (old_chain);
+ discard_cleanups (reset_cache_cleanup);
return cache;
}
cache->undefined_retaddr = 1;
do_cleanups (old_chain);
-
+ discard_cleanups (reset_cache_cleanup);
return cache;
}
dwarf2_frame_cache (this_frame, this_cache);
if (cache->unavailable_retaddr)
+ (*this_id) = frame_id_build_unavailable_stack (get_frame_func (this_frame));
+ else if (cache->undefined_retaddr)
return;
-
- 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 *
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:
}
}
+/* 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)
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 =
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 =
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. */
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);
}
/* 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))
+ if (!frame_unwinder_is (this_frame, &dwarf2_frame_unwind)
+ && !frame_unwinder_is (this_frame, &dwarf2_tailcall_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"));
return get_frame_base (this_frame);
}
\f
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;
{
case DW_EH_PE_uleb128:
{
- ULONGEST value;
+ uint64_t value;
const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7;
- *bytes_read_ptr += read_uleb128 (buf, end_buf, &value) - buf;
+ *bytes_read_ptr += safe_read_uleb128 (buf, end_buf, &value) - buf;
return base + value;
}
case DW_EH_PE_udata2:
return (base + bfd_get_64 (unit->abfd, (bfd_byte *) buf));
case DW_EH_PE_sleb128:
{
- LONGEST value;
+ int64_t value;
const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7;
- *bytes_read_ptr += read_sleb128 (buf, end_buf, &value) - buf;
+ *bytes_read_ptr += safe_read_sleb128 (buf, end_buf, &value) - buf;
return base + value;
}
case DW_EH_PE_sdata2:
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);
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;
else
cie->ptr_size = cie->addr_size;
- cie->code_alignment_factor =
- read_unsigned_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;
- cie->data_alignment_factor =
- read_signed_leb128 (unit->abfd, buf, &bytes_read);
- buf += bytes_read;
+ 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++;
/* This is a FDE. */
struct dwarf2_fde *fde;
+ /* 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
address of the CIE. Convert it to an offset into the .eh_frame
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);
}
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;
}
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 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;
return ret;
}
\f
-
-/* 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)
{
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;
+ volatile struct gdb_exception e;
cie_table.num_entries = 0;
cie_table.entries = NULL;
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_CATCH (e, RETURN_MASK_ERROR)
+ {
+ 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);
+ }
+
+ if (e.reason < 0)
+ {
+ 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. */
+ }
+
+ 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_CATCH (e, RETURN_MASK_ERROR)
+ {
+ 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);
+ }
+ if (e.reason < 0)
+ {
+ 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 = xrealloc (fde_table.entries,
+ fde_table.num_entries *
+ sizeof (fde_table.entries[0]));
+ }
+ }
+ fde_table.num_entries = num_old_fde_entries;
+ /* The cie_table is discarded by the next if. */
+ }
}
/* Discard the cie_table, it is no longer needed. */