/* Frame unwinder for frames with DWARF Call Frame Information.
- Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2015 Free Software Foundation, Inc.
Contributed by Mark Kettenis.
#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;
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;
/* 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;
/* The version recorded in the CIE. */
unsigned char version;
+
+ /* The segment size. */
+ unsigned char segment_size;
};
struct dwarf2_cie_table
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;
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);
\f
+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;
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);
/* 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;
-
- regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
+ int 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 = gdbarch_dwarf2_reg_to_regnum (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
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;
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->location == DWARF_VALUE_REGISTER)
- result = read_reg (this_frame, result);
- else if (ctx->location != DWARF_VALUE_MEMORY)
+ 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"));
+ error (_("\
+Not implemented: computing unwound register using explicit value operator"));
}
do_cleanups (old_chain);
}
\f
-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;
{
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;
{
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,
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;
unwinder. */
{
int size = register_size (gdbarch, 0);
+
dwarf2_frame_state_alloc_regs (&fs->regs, 32);
for (reg = 8; reg < 16; reg++)
{
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;
}
\f
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;
}
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);
}
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;
}
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;
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;
}
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;
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;
+ }
+}
+\f
+
+/* 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 = gdbarch_dwarf2_reg_to_regnum (gdbarch, fs.regs.cfa_reg);
+
+ if (regnum == -1)
+ error (_("Unable to access DWARF register number %d"),
+ (int) fs.regs.cfa_reg); /* FIXME */
+
+ *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."));
+ }
}
-\f
+\f
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;
/* 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.
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. */
/* 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
+ && (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, 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. */
{
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)
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 *
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:
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:
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:
}
}
+/* 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)
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;
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. */
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);
}
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;
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);
}
\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;
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;
}
break;
default:
- internal_error (__FILE__, __LINE__, _("Invalid or unsupported encoding"));
+ internal_error (__FILE__, __LINE__,
+ _("Invalid or unsupported encoding"));
}
if ((encoding & 0x07) == 0x00)
{
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:
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:
*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"));
}
}
\f
{
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;
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;
}
{
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)
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;
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);
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;
}
}
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;
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;
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;
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;
/* 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
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++;
{
/* 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++;
{
/* 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
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
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 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;
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;
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;
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
+ {
+ 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. */
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. */