/* Frame unwinder for frames with DWARF Call Frame Information.
- Copyright (C) 2003-2013 Free Software Foundation, Inc.
+ Copyright (C) 2003-2020 Free Software Foundation, Inc.
Contributed by Mark Kettenis.
#include "objfiles.h"
#include "regcache.h"
#include "value.h"
-
-#include "gdb_assert.h"
-#include <string.h>
+#include "record.h"
#include "complaints.h"
#include "dwarf2-frame.h"
+#include "dwarf2read.h"
#include "ax.h"
#include "dwarf2loc.h"
-#include "exceptions.h"
#include "dwarf2-frame-tailcall.h"
+#include "gdbsupport/gdb_binary_search.h"
+#if GDB_SELF_TEST
+#include "gdbsupport/selftest.h"
+#include "selftest-arch.h"
+#endif
+#include <unordered_map>
+
+#include <algorithm>
struct comp_unit;
unsigned char segment_size;
};
-struct dwarf2_cie_table
-{
- int num_entries;
- struct dwarf2_cie **entries;
-};
+/* The CIE table is used to find CIEs during parsing, but then
+ discarded. It maps from the CIE's offset to the CIE. */
+typedef std::unordered_map<ULONGEST, dwarf2_cie *> dwarf2_cie_table;
/* Frame Description Entry (FDE). */
CORE_ADDR func_base);
\f
-/* 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;
- const gdb_byte *cfa_exp;
-
- /* Used to implement DW_CFA_remember_state. */
- struct dwarf2_frame_state_reg_info *prev;
- } regs;
-
- /* The PC described by the current frame state. */
- CORE_ADDR pc;
-
- /* Initial register set from the CIE.
- Used to implement DW_CFA_restore. */
- struct dwarf2_frame_state_reg_info initial;
-
- /* The information we care about from the CIE. */
- LONGEST data_align;
- ULONGEST code_align;
- ULONGEST retaddr_column;
-
- /* Flags for known producer quirks. */
-
- /* The ARM compilers, in DWARF2 mode, assume that DW_CFA_def_cfa
- and DW_CFA_def_cfa_offset takes a factored offset. */
- int armcc_cfa_offsets_sf;
-
- /* The ARM compilers, in DWARF2 or DWARF3 mode, may assume that
- the CFA is defined as REG - OFFSET rather than REG + OFFSET. */
- int armcc_cfa_offsets_reversed;
-};
+/* See dwarf2-frame.h. */
+bool dwarf2_frame_unwinders_enabled_p = true;
/* Store the length the expression for the CFA in the `cfa_reg' field,
which is unused in that case. */
#define cfa_exp_len cfa_reg
-/* Assert that the register set RS is large enough to store gdbarch_num_regs
- columns. If necessary, enlarge the register set. */
-
-static void
-dwarf2_frame_state_alloc_regs (struct dwarf2_frame_state_reg_info *rs,
- int num_regs)
-{
- size_t size = sizeof (struct dwarf2_frame_state_reg);
-
- if (num_regs <= rs->num_regs)
- return;
-
- rs->reg = (struct dwarf2_frame_state_reg *)
- xrealloc (rs->reg, num_regs * size);
-
- /* Initialize newly allocated registers. */
- memset (rs->reg + rs->num_regs, 0, (num_regs - rs->num_regs) * size);
- rs->num_regs = num_regs;
-}
-
-/* Copy the register columns in register set RS into newly allocated
- memory and return a pointer to this newly created copy. */
-
-static struct dwarf2_frame_state_reg *
-dwarf2_frame_state_copy_regs (struct dwarf2_frame_state_reg_info *rs)
-{
- size_t size = rs->num_regs * sizeof (struct dwarf2_frame_state_reg);
- struct dwarf2_frame_state_reg *reg;
-
- reg = (struct dwarf2_frame_state_reg *) xmalloc (size);
- memcpy (reg, rs->reg, size);
-
- return reg;
-}
-
-/* Release the memory allocated to register set RS. */
-
-static void
-dwarf2_frame_state_free_regs (struct dwarf2_frame_state_reg_info *rs)
+dwarf2_frame_state::dwarf2_frame_state (CORE_ADDR pc_, struct dwarf2_cie *cie)
+ : pc (pc_), data_align (cie->data_alignment_factor),
+ code_align (cie->code_alignment_factor),
+ retaddr_column (cie->return_address_register)
{
- if (rs)
- {
- dwarf2_frame_state_free_regs (rs->prev);
-
- xfree (rs->reg);
- xfree (rs);
- }
-}
-
-/* Release the memory allocated to the frame state FS. */
-
-static void
-dwarf2_frame_state_free (void *p)
-{
- struct dwarf2_frame_state *fs = p;
-
- dwarf2_frame_state_free_regs (fs->initial.prev);
- dwarf2_frame_state_free_regs (fs->regs.prev);
- xfree (fs->initial.reg);
- xfree (fs->regs.reg);
- xfree (fs);
}
\f
/* Helper functions for execute_stack_op. */
static CORE_ADDR
-read_addr_from_reg (void *baton, int reg)
+read_addr_from_reg (struct frame_info *this_frame, 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);
-
- buf = alloca (register_size (gdbarch, regnum));
- get_frame_register (this_frame, regnum, buf);
+ int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg);
- return unpack_pointer (register_type (gdbarch, regnum), buf);
-}
-
-/* Implement struct dwarf_expr_context_funcs' "get_reg_value" callback. */
-
-static struct value *
-get_reg_value (void *baton, struct type *type, int reg)
-{
- 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);
-
- return value_from_register (type, regnum, this_frame);
-}
-
-static void
-read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len)
-{
- read_memory (addr, buf, len);
+ return address_from_register (regnum, this_frame);
}
/* Execute the required actions for both the DW_CFA_restore and
{
ULONGEST reg;
- gdb_assert (fs->initial.reg);
reg = dwarf2_frame_adjust_regnum (gdbarch, reg_num, eh_frame_p);
- dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.alloc_regs (reg + 1);
/* Check if this register was explicitly initialized in the
CIE initial instructions. If not, default the rule to
UNSPECIFIED. */
- if (reg < fs->initial.num_regs)
+ if (reg < fs->initial.reg.size ())
fs->regs.reg[reg] = fs->initial.reg[reg];
else
fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNSPECIFIED;
if (fs->regs.reg[reg].how == DWARF2_FRAME_REG_UNSPECIFIED)
- complaint (&symfile_complaints, _("\
+ {
+ int regnum = dwarf_reg_to_regnum (gdbarch, reg);
+
+ complaint (_("\
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 =
+class dwarf_expr_executor : public dwarf_expr_context
{
- 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
+ public:
+
+ struct frame_info *this_frame;
+
+ CORE_ADDR read_addr_from_reg (int reg) override
+ {
+ return ::read_addr_from_reg (this_frame, reg);
+ }
+
+ struct value *get_reg_value (struct type *type, int reg) override
+ {
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg);
+
+ return value_from_register (type, regnum, this_frame);
+ }
+
+ void read_mem (gdb_byte *buf, CORE_ADDR addr, size_t len) override
+ {
+ read_memory (addr, buf, len);
+ }
+
+ void get_frame_base (const gdb_byte **start, size_t *length) override
+ {
+ invalid ("DW_OP_fbreg");
+ }
+
+ void push_dwarf_reg_entry_value (enum call_site_parameter_kind kind,
+ union call_site_parameter_u kind_u,
+ int deref_size) override
+ {
+ invalid ("DW_OP_entry_value");
+ }
+
+ CORE_ADDR get_object_address () override
+ {
+ invalid ("DW_OP_push_object_address");
+ }
+
+ CORE_ADDR get_frame_cfa () override
+ {
+ invalid ("DW_OP_call_frame_cfa");
+ }
+
+ CORE_ADDR get_tls_address (CORE_ADDR offset) override
+ {
+ invalid ("DW_OP_form_tls_address");
+ }
+
+ void dwarf_call (cu_offset die_offset) override
+ {
+ invalid ("DW_OP_call*");
+ }
+
+ struct value *dwarf_variable_value (sect_offset sect_off) override
+ {
+ invalid ("DW_OP_GNU_variable_value");
+ }
+
+ CORE_ADDR get_addr_index (unsigned int index) override
+ {
+ invalid ("DW_OP_addrx or DW_OP_GNU_addr_index");
+ }
+
+ private:
+
+ void invalid (const char *op) ATTRIBUTE_NORETURN
+ {
+ error (_("%s is invalid in this context"), op);
+ }
};
static CORE_ADDR
CORE_ADDR offset, struct frame_info *this_frame,
CORE_ADDR initial, int initial_in_stack_memory)
{
- struct dwarf_expr_context *ctx;
CORE_ADDR result;
- struct cleanup *old_chain;
-
- ctx = new_dwarf_expr_context ();
- 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->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_addr_from_reg (this_frame,
- value_as_long (dwarf_expr_fetch (ctx, 0)));
+
+ dwarf_expr_executor ctx;
+ scoped_value_mark free_values;
+
+ ctx.this_frame = this_frame;
+ ctx.gdbarch = get_frame_arch (this_frame);
+ ctx.addr_size = addr_size;
+ ctx.ref_addr_size = -1;
+ ctx.offset = offset;
+
+ ctx.push_address (initial, initial_in_stack_memory);
+ ctx.eval (exp, len);
+
+ if (ctx.location == DWARF_VALUE_MEMORY)
+ result = ctx.fetch_address (0);
+ else if (ctx.location == DWARF_VALUE_REGISTER)
+ result = ctx.read_addr_from_reg (value_as_long (ctx.fetch (0)));
else
{
/* This is actually invalid DWARF, but if we ever do run across
Not implemented: computing unwound register using explicit value operator"));
}
- do_cleanups (old_chain);
-
return result;
}
\f
reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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.alloc_regs (reg + 1);
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
fs->regs.reg[reg].loc.offset = offset;
}
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,
- SECT_OFF_TEXT (fde->cie->unit->objfile));
+ fs->pc += fde->cie->unit->objfile->section_offsets[SECT_OFF_TEXT (fde->cie->unit->objfile)];
insn_ptr += bytes_read;
break;
reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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.alloc_regs (reg + 1);
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
fs->regs.reg[reg].loc.offset = offset;
break;
case DW_CFA_undefined:
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.alloc_regs (reg + 1);
fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNDEFINED;
break;
case DW_CFA_same_value:
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.alloc_regs (reg + 1);
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAME_VALUE;
break;
reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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.alloc_regs (reg + 1);
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
fs->regs.reg[reg].loc.reg = utmp;
break;
{
struct dwarf2_frame_state_reg_info *new_rs;
- new_rs = XMALLOC (struct dwarf2_frame_state_reg_info);
- *new_rs = fs->regs;
- fs->regs.reg = dwarf2_frame_state_copy_regs (&fs->regs);
+ new_rs = new dwarf2_frame_state_reg_info (fs->regs);
fs->regs.prev = new_rs;
}
break;
if (old_rs == NULL)
{
- complaint (&symfile_complaints, _("\
+ complaint (_("\
bad CFI data; mismatched DW_CFA_restore_state at %s"),
paddress (gdbarch, fs->pc));
}
else
- {
- xfree (fs->regs.reg);
- fs->regs = *old_rs;
- xfree (old_rs);
- }
+ fs->regs = std::move (*old_rs);
}
break;
case DW_CFA_expression:
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.alloc_regs (reg + 1);
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].loc.exp.start = insn_ptr;
+ fs->regs.reg[reg].loc.exp.len = utmp;
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_EXP;
insn_ptr += utmp;
break;
reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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.alloc_regs (reg + 1);
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
fs->regs.reg[reg].loc.offset = offset;
break;
case DW_CFA_val_offset:
insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®);
- dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.alloc_regs (reg + 1);
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;
case DW_CFA_val_offset_sf:
insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®);
- dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.alloc_regs (reg + 1);
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;
case DW_CFA_val_expression:
insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, ®);
- dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+ fs->regs.alloc_regs (reg + 1);
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].loc.exp.start = insn_ptr;
+ fs->regs.reg[reg].loc.exp.len = utmp;
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
insn_ptr += utmp;
break;
/* cfa_how deliberately not set. */
break;
- case DW_CFA_GNU_window_save:
- /* This is SPARC-specific code, and contains hard-coded
- constants for the register numbering scheme used by
- GCC. Rather than having a architecture-specific
- operation that's only ever used by a single
- architecture, we provide the implementation here.
- Incidentally that's what GCC does too in its
- unwinder. */
- {
- int size = register_size (gdbarch, 0);
-
- dwarf2_frame_state_alloc_regs (&fs->regs, 32);
- for (reg = 8; reg < 16; reg++)
- {
- fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
- fs->regs.reg[reg].loc.reg = reg + 16;
- }
- for (reg = 16; reg < 32; reg++)
- {
- fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
- fs->regs.reg[reg].loc.offset = (reg - 16) * size;
- }
- }
- break;
-
case DW_CFA_GNU_args_size:
/* Ignored. */
insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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.alloc_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."));
+ if (insn >= DW_CFA_lo_user && insn <= DW_CFA_hi_user)
+ {
+ /* Handle vendor-specific CFI for different architectures. */
+ if (!gdbarch_execute_dwarf_cfa_vendor_op (gdbarch, insn, fs))
+ error (_("Call Frame Instruction op %d in vendor extension "
+ "space is not handled on this architecture."),
+ insn);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ _("Unknown CFI encountered."));
}
}
}
- if (fs->initial.reg == NULL)
+ if (fs->initial.reg.empty ())
{
/* Don't allow remember/restore between CIE and FDE programs. */
- dwarf2_frame_state_free_regs (fs->regs.prev);
+ delete fs->regs.prev;
fs->regs.prev = NULL;
}
return insn_ptr;
}
+
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+/* Unit test to function execute_cfa_program. */
+
+static void
+execute_cfa_program_test (struct gdbarch *gdbarch)
+{
+ struct dwarf2_fde fde;
+ struct dwarf2_cie cie;
+
+ memset (&fde, 0, sizeof fde);
+ memset (&cie, 0, sizeof cie);
+
+ cie.data_alignment_factor = -4;
+ cie.code_alignment_factor = 2;
+ fde.cie = &cie;
+
+ dwarf2_frame_state fs (0, fde.cie);
+
+ gdb_byte insns[] =
+ {
+ DW_CFA_def_cfa, 1, 4, /* DW_CFA_def_cfa: r1 ofs 4 */
+ DW_CFA_offset | 0x2, 1, /* DW_CFA_offset: r2 at cfa-4 */
+ DW_CFA_remember_state,
+ DW_CFA_restore_state,
+ };
+
+ const gdb_byte *insn_end = insns + sizeof (insns);
+ const gdb_byte *out = execute_cfa_program (&fde, insns, insn_end, gdbarch,
+ 0, &fs);
+
+ SELF_CHECK (out == insn_end);
+ SELF_CHECK (fs.pc == 0);
+
+ /* The instructions above only use r1 and r2, but the register numbers
+ used are adjusted by dwarf2_frame_adjust_regnum. */
+ auto r1 = dwarf2_frame_adjust_regnum (gdbarch, 1, fde.eh_frame_p);
+ auto r2 = dwarf2_frame_adjust_regnum (gdbarch, 2, fde.eh_frame_p);
+
+ SELF_CHECK (fs.regs.reg.size () == (std::max (r1, r2) + 1));
+
+ SELF_CHECK (fs.regs.reg[r2].how == DWARF2_FRAME_REG_SAVED_OFFSET);
+ SELF_CHECK (fs.regs.reg[r2].loc.offset == -4);
+
+ for (auto i = 0; i < fs.regs.reg.size (); i++)
+ if (i != r2)
+ SELF_CHECK (fs.regs.reg[i].how == DWARF2_FRAME_REG_UNSPECIFIED);
+
+ SELF_CHECK (fs.regs.cfa_reg == 1);
+ SELF_CHECK (fs.regs.cfa_offset == 4);
+ SELF_CHECK (fs.regs.cfa_how == CFA_REG_OFFSET);
+ SELF_CHECK (fs.regs.cfa_exp == NULL);
+ SELF_CHECK (fs.regs.prev == NULL);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
\f
/* Architecture-specific operations. */
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;
}
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)
{
- struct symtab *s;
+ struct compunit_symtab *cust;
- s = find_pc_symtab (fs->pc);
- if (s == NULL)
+ cust = find_pc_compunit_symtab (fs->pc);
+ if (cust == NULL)
return;
- if (producer_is_realview (s->producer))
+ if (producer_is_realview (COMPUNIT_PRODUCER (cust)))
{
if (fde->cie->version == 1)
fs->armcc_cfa_offsets_sf = 1;
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
+ && (!startswith (fde->cie->augmentation, "armcc")
|| strchr (fde->cie->augmentation + 5, '+') == NULL))
fs->armcc_cfa_offsets_reversed = 1;
}
\f
-void
-dwarf2_compile_cfa_to_ax (struct agent_expr *expr, struct axs_value *loc,
- struct gdbarch *gdbarch,
- CORE_ADDR pc,
- struct dwarf2_per_cu_data *data)
+/* 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;
+ CORE_ADDR pc1 = pc;
/* Find the correct FDE. */
- fde = dwarf2_frame_find_fde (&fs.pc, &text_offset);
+ fde = dwarf2_frame_find_fde (&pc1, &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;
+ dwarf2_frame_state fs (pc1, fde->cie);
/* Check for "quirks" - known bugs in producers. */
dwarf2_frame_find_quirks (&fs, fde);
/* 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);
{
case CFA_REG_OFFSET:
{
- 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 */
- ax_reg (expr, regnum);
+ int regnum = dwarf_reg_to_regnum_or_error (gdbarch, fs.regs.cfa_reg);
- if (fs.regs.cfa_offset != 0)
- {
- if (fs.armcc_cfa_offsets_reversed)
- ax_const_l (expr, -fs.regs.cfa_offset);
- else
- ax_const_l (expr, fs.regs.cfa_offset);
- ax_simple (expr, aop_add);
- }
+ *regnum_out = regnum;
+ if (fs.armcc_cfa_offsets_reversed)
+ *offset_out = -fs.regs.cfa_offset;
+ else
+ *offset_out = fs.regs.cfa_offset;
+ return 1;
}
- break;
case CFA_EXP:
- ax_const_l (expr, text_offset);
- dwarf2_compile_expr_to_ax (expr, loc, gdbarch, addr_size,
- fs.regs.cfa_exp,
- fs.regs.cfa_exp + fs.regs.cfa_exp_len,
- data);
- break;
+ *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."));
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 *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);
+ const int num_regs = gdbarch_num_cooked_regs (gdbarch);
struct dwarf2_frame_cache *cache;
- 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;
+ 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 = XZALLOC (struct dwarf2_frame_state);
- old_chain = make_cleanup (dwarf2_frame_state_free, fs);
/* Unwind the PC.
get_frame_address_in_block does just this. It's not clear how
reliable the method is though; there is the potential for the
register state pre-call being different to that on return. */
- fs->pc = get_frame_address_in_block (this_frame);
+ CORE_ADDR pc1 = get_frame_address_in_block (this_frame);
/* Find the correct FDE. */
- fde = dwarf2_frame_find_fde (&fs->pc, &cache->text_offset);
+ fde = dwarf2_frame_find_fde (&pc1, &cache->text_offset);
gdb_assert (fde != NULL);
- /* 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;
+ /* Allocate and initialize the frame state. */
+ struct dwarf2_frame_state fs (pc1, fde->cie);
+
cache->addr_size = fde->cie->addr_size;
/* Check for "quirks" - known bugs in producers. */
- dwarf2_frame_find_quirks (fs, fde);
+ 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,
- get_frame_address_in_block (this_frame), fs);
+ 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);
+ fs.initial = fs.regs;
- if (get_frame_func_if_available (this_frame, &entry_pc))
+ /* Fetching the entry pc for THIS_FRAME won't necessarily result
+ in an address that's within the range of FDE locations. This
+ is due to the possibility of the function occupying non-contiguous
+ ranges. */
+ if (get_frame_func_if_available (this_frame, &entry_pc)
+ && fde->initial_location <= entry_pc
+ && entry_pc < fde->initial_location + fde->address_range)
{
/* Decode the insns in the FDE up to the entry PC. */
instr = execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,
- entry_pc, fs);
+ entry_pc, &fs);
- if (fs->regs.cfa_how == CFA_REG_OFFSET
- && (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg)
+ 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 = fs.regs.cfa_offset;
cache->entry_cfa_sp_offset_p = 1;
}
}
/* Then decode the insns in the FDE up to our target PC. */
execute_cfa_program (fde, instr, fde->end, gdbarch,
- get_frame_address_in_block (this_frame), fs);
+ get_frame_address_in_block (this_frame), &fs);
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ try
{
/* Calculate the CFA. */
- switch (fs->regs.cfa_how)
+ 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;
+ 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;
+ cache->cfa += fs.regs.cfa_offset;
break;
case CFA_EXP:
cache->cfa =
- execute_stack_op (fs->regs.cfa_exp, fs->regs.cfa_exp_len,
+ execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
cache->addr_size, cache->text_offset,
this_frame, 0, 0);
break;
internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
}
}
- if (ex.reason < 0)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == NOT_AVAILABLE_ERROR)
{
cache->unavailable_retaddr = 1;
- do_cleanups (old_chain);
- discard_cleanups (reset_cache_cleanup);
return cache;
}
- throw_exception (ex);
+ throw;
}
/* Initialize the register state. */
/* 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++)
+ for (column = 0; column < fs.regs.reg.size (); 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;
problems when a debug info register falls outside of the
table. We need a way of iterating through all the valid
DWARF2 register numbers. */
- if (fs->regs.reg[column].how == DWARF2_FRAME_REG_UNSPECIFIED)
+ if (fs.regs.reg[column].how == DWARF2_FRAME_REG_UNSPECIFIED)
{
if (cache->reg[regnum].how == DWARF2_FRAME_REG_UNSPECIFIED)
- complaint (&symfile_complaints, _("\
+ complaint (_("\
incomplete CFI data; unspecified registers (e.g., %s) at %s"),
gdbarch_register_name (gdbarch, regnum),
- paddress (gdbarch, fs->pc));
+ paddress (gdbarch, fs.pc));
}
else
- cache->reg[regnum] = fs->regs.reg[column];
+ cache->reg[regnum] = fs.regs.reg[column];
}
}
if (cache->reg[regnum].how == DWARF2_FRAME_REG_RA
|| cache->reg[regnum].how == DWARF2_FRAME_REG_RA_OFFSET)
{
- struct dwarf2_frame_state_reg *retaddr_reg =
- &fs->regs.reg[fs->retaddr_column];
+ const std::vector<struct dwarf2_frame_state_reg> ®s
+ = fs.regs.reg;
+ ULONGEST retaddr_column = fs.retaddr_column;
/* It seems rather bizarre to specify an "empty" column as
the return adress column. However, this is exactly
register corresponding to the return address column.
Incidentally, that's how we should treat a return
address column specifying "same value" too. */
- if (fs->retaddr_column < fs->regs.num_regs
- && retaddr_reg->how != DWARF2_FRAME_REG_UNSPECIFIED
- && retaddr_reg->how != DWARF2_FRAME_REG_SAME_VALUE)
+ if (fs.retaddr_column < fs.regs.reg.size ()
+ && regs[retaddr_column].how != DWARF2_FRAME_REG_UNSPECIFIED
+ && regs[retaddr_column].how != DWARF2_FRAME_REG_SAME_VALUE)
{
if (cache->reg[regnum].how == DWARF2_FRAME_REG_RA)
- cache->reg[regnum] = *retaddr_reg;
+ cache->reg[regnum] = regs[retaddr_column];
else
- cache->retaddr_reg = *retaddr_reg;
+ cache->retaddr_reg = regs[retaddr_column];
}
else
{
if (cache->reg[regnum].how == DWARF2_FRAME_REG_RA)
{
- cache->reg[regnum].loc.reg = fs->retaddr_column;
+ cache->reg[regnum].loc.reg = fs.retaddr_column;
cache->reg[regnum].how = DWARF2_FRAME_REG_SAVED_REG;
}
else
{
- cache->retaddr_reg.loc.reg = fs->retaddr_column;
+ cache->retaddr_reg.loc.reg = fs.retaddr_column;
cache->retaddr_reg.how = DWARF2_FRAME_REG_SAVED_REG;
}
}
}
}
- if (fs->retaddr_column < fs->regs.num_regs
- && fs->regs.reg[fs->retaddr_column].how == DWARF2_FRAME_REG_UNDEFINED)
+ if (fs.retaddr_column < fs.regs.reg.size ()
+ && fs.regs.reg[fs.retaddr_column].how == DWARF2_FRAME_REG_UNDEFINED)
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 *
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,
+ addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
+ cache->reg[regnum].loc.exp.len,
cache->addr_size, cache->text_offset,
this_frame, cache->cfa, 1);
return frame_unwind_got_memory (this_frame, regnum, addr);
return frame_unwind_got_constant (this_frame, regnum, addr);
case DWARF2_FRAME_REG_SAVED_VAL_EXP:
- addr = execute_stack_op (cache->reg[regnum].loc.exp,
- cache->reg[regnum].exp_len,
+ addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
+ cache->reg[regnum].loc.exp.len,
cache->addr_size, cache->text_offset,
this_frame, cache->cfa, 1);
return frame_unwind_got_constant (this_frame, regnum, addr);
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);
dwarf2_frame_sniffer (const struct frame_unwind *self,
struct frame_info *this_frame, void **this_cache)
{
- /* Grab an address that is guarenteed to reside somewhere within the
+ if (!dwarf2_frame_unwinders_enabled_p)
+ return 0;
+
+ /* Grab an address that is guaranteed to reside somewhere within the
function. get_frame_pc(), with a no-return next function, can
end up returning something past the end of this function's body.
If the frame we're sniffing for is a signal frame whose start
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)
- && !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"));
+ _("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;
+const struct objfile_key<dwarf2_fde_table,
+ gdb::noop_deleter<dwarf2_fde_table>>
+ dwarf2_frame_objfile_data;
static unsigned int
read_1_byte (bfd *abfd, const gdb_byte *buf)
read_initial_length (bfd *abfd, const gdb_byte *buf,
unsigned int *bytes_read_ptr)
{
- LONGEST result;
+ ULONGEST result;
result = bfd_get_32 (abfd, buf);
if (result == 0xffffffff)
base = 0;
break;
case DW_EH_PE_pcrel:
- base = bfd_get_section_vma (unit->abfd, unit->dwarf_frame_section);
+ base = bfd_section_vma (unit->dwarf_frame_section);
base += (buf - unit->dwarf_frame_buffer);
break;
case DW_EH_PE_datarel:
}
\f
-static int
-bsearch_cie_cmp (const void *key, const void *element)
-{
- ULONGEST cie_pointer = *(ULONGEST *) key;
- struct dwarf2_cie *cie = *(struct dwarf2_cie **) element;
-
- if (cie_pointer == cie->cie_pointer)
- return 0;
-
- return (cie_pointer < cie->cie_pointer) ? -1 : 1;
-}
-
/* Find CIE with the given CIE_POINTER in CIE_TABLE. */
static struct dwarf2_cie *
-find_cie (struct dwarf2_cie_table *cie_table, ULONGEST cie_pointer)
+find_cie (const dwarf2_cie_table &cie_table, ULONGEST cie_pointer)
{
- struct dwarf2_cie **p_cie;
-
- /* 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 = 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;
+ auto iter = cie_table.find (cie_pointer);
+ if (iter != cie_table.end ())
+ return iter->second;
return NULL;
}
-/* Add a pointer to new CIE to the CIE_TABLE, allocating space for it. */
-static void
-add_cie (struct dwarf2_cie_table *cie_table, struct dwarf2_cie *cie)
+static inline int
+bsearch_fde_cmp (const dwarf2_fde *fde, CORE_ADDR seek_pc)
{
- const int n = cie_table->num_entries;
-
- gdb_assert (n < 1
- || cie_table->entries[n - 1]->cie_pointer < cie->cie_pointer);
-
- cie_table->entries =
- xrealloc (cie_table->entries, (n + 1) * sizeof (cie_table->entries[0]));
- cie_table->entries[n] = cie;
- cie_table->num_entries = n + 1;
-}
-
-static int
-bsearch_fde_cmp (const void *key, const void *element)
-{
- CORE_ADDR seek_pc = *(CORE_ADDR *) key;
- struct dwarf2_fde *fde = *(struct dwarf2_fde **) element;
-
- if (seek_pc < fde->initial_location)
+ if (fde->initial_location + fde->address_range <= seek_pc)
return -1;
- if (seek_pc < fde->initial_location + fde->address_range)
+ if (fde->initial_location <= seek_pc)
return 0;
return 1;
}
/* Find the FDE for *PC. Return a pointer to the FDE, and store the
- inital location associated with it into *PC. */
+ initial location associated with it into *PC. */
static struct dwarf2_fde *
dwarf2_frame_find_fde (CORE_ADDR *pc, CORE_ADDR *out_offset)
{
- struct objfile *objfile;
-
- ALL_OBJFILES (objfile)
+ for (objfile *objfile : current_program_space->objfiles ())
{
struct dwarf2_fde_table *fde_table;
- struct dwarf2_fde **p_fde;
CORE_ADDR offset;
CORE_ADDR seek_pc;
- fde_table = objfile_data (objfile, dwarf2_frame_objfile_data);
+ fde_table = dwarf2_frame_objfile_data.get (objfile);
if (fde_table == NULL)
{
dwarf2_build_frame_info (objfile);
- fde_table = objfile_data (objfile, dwarf2_frame_objfile_data);
+ fde_table = dwarf2_frame_objfile_data.get (objfile);
}
gdb_assert (fde_table != NULL);
if (fde_table->num_entries == 0)
continue;
- gdb_assert (objfile->section_offsets);
- offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ gdb_assert (!objfile->section_offsets.empty ());
+ offset = objfile->section_offsets[SECT_OFF_TEXT (objfile)];
gdb_assert (fde_table->num_entries > 0);
if (*pc < offset + fde_table->entries[0]->initial_location)
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);
- if (p_fde != NULL)
+ auto end = fde_table->entries + fde_table->num_entries;
+ auto it = gdb::binary_search (fde_table->entries, end, seek_pc, bsearch_fde_cmp);
+ if (it != end)
{
- *pc = (*p_fde)->initial_location + offset;
+ *pc = (*it)->initial_location + offset;
if (out_offset)
*out_offset = offset;
- return *p_fde;
+ return *it;
}
}
return NULL;
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;
}
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,
+ dwarf2_cie_table &cie_table,
struct dwarf2_fde_table *fde_table,
enum eh_frame_type entry_type);
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,
+ dwarf2_cie_table &cie_table,
struct dwarf2_fde_table *fde_table,
enum eh_frame_type entry_type)
{
struct gdbarch *gdbarch = get_objfile_arch (unit->objfile);
const gdb_byte *buf, *end;
- LONGEST length;
+ ULONGEST length;
unsigned int bytes_read;
int dwarf64_p;
ULONGEST cie_id;
buf = start;
length = read_initial_length (unit->abfd, buf, &bytes_read);
buf += bytes_read;
- end = buf + length;
-
- /* Are we still within the section? */
- if (end > unit->dwarf_frame_buffer + unit->dwarf_frame_size)
- return NULL;
+ end = buf + (size_t) length;
if (length == 0)
return end;
+ /* Are we still within the section? */
+ if (end <= buf || end > unit->dwarf_frame_buffer + unit->dwarf_frame_size)
+ return NULL;
+
/* Distinguish between 32 and 64-bit encoded frame info. */
dwarf64_p = (bytes_read == 12);
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;
/* 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
cie->saw_z_augmentation = (*augmentation == 'z');
if (cie->saw_z_augmentation)
{
- uint64_t length;
+ uint64_t uleb_length;
- buf = gdb_read_uleb128 (buf, end, &length);
+ buf = gdb_read_uleb128 (buf, end, &uleb_length);
if (buf == NULL)
return NULL;
- cie->initial_instructions = buf + length;
+ cie->initial_instructions = buf + uleb_length;
augmentation++;
}
cie->end = end;
cie->unit = unit;
- add_cie (cie_table, cie);
+ cie_table[cie->cie_pointer] = cie;
}
else
{
/* 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)
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)
{
gdb_assert (fde->cie != NULL);
- fde->initial_location =
- read_encoded_value (unit, fde->cie->encoding, fde->cie->ptr_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->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)
{
- uint64_t length;
+ uint64_t uleb_length;
- buf = gdb_read_uleb128 (buf, end, &length);
+ buf = gdb_read_uleb128 (buf, end, &uleb_length);
if (buf == NULL)
return NULL;
- buf += length;
+ buf += uleb_length;
if (buf > end)
return NULL;
}
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,
+ dwarf2_cie_table &cie_table,
struct dwarf2_fde_table *fde_table,
enum eh_frame_type entry_type)
{
break;
case ALIGN4:
- complaint (&symfile_complaints, _("\
+ complaint (_("\
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, _("\
+ complaint (_("\
Corrupt data in %s:%s; align 8 workaround apparently succeeded"),
unit->dwarf_frame_section->owner->filename,
unit->dwarf_frame_section->name);
break;
default:
- complaint (&symfile_complaints,
- _("Corrupt data in %s:%s"),
+ complaint (_("Corrupt data in %s:%s"),
unit->dwarf_frame_section->owner->filename,
unit->dwarf_frame_section->name);
break;
return ret;
}
\f
-static int
-qsort_fde_cmp (const void *a, const void *b)
+static bool
+fde_is_less_than (const dwarf2_fde *aa, const dwarf2_fde *bb)
{
- struct dwarf2_fde *aa = *(struct dwarf2_fde **)a;
- struct dwarf2_fde *bb = *(struct dwarf2_fde **)b;
-
if (aa->initial_location == bb->initial_location)
{
if (aa->address_range != bb->address_range
&& aa->eh_frame_p == 0 && bb->eh_frame_p == 0)
/* Linker bug, e.g. gold/10400.
Work around it by keeping stable sort order. */
- return (a < b) ? -1 : 1;
+ return aa < bb;
else
/* Put eh_frame entries after debug_frame ones. */
- return aa->eh_frame_p - bb->eh_frame_p;
+ return aa->eh_frame_p < bb->eh_frame_p;
}
- return (aa->initial_location < bb->initial_location) ? -1 : 1;
+ return aa->initial_location < bb->initial_location;
}
void
{
struct comp_unit *unit;
const gdb_byte *frame_ptr;
- struct dwarf2_cie_table cie_table;
+ 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;
fde_table.num_entries = 0;
fde_table.entries = NULL;
/* Build a minimal decoding of the DWARF2 compilation unit. */
- unit = (struct comp_unit *) obstack_alloc (&objfile->objfile_obstack,
- sizeof (struct comp_unit));
+ unit = XOBNEW (&objfile->objfile_obstack, comp_unit);
unit->abfd = objfile->obfd;
unit->objfile = objfile;
unit->dbase = 0;
if (txt)
unit->tbase = txt->vma;
- TRY_CATCH (e, RETURN_MASK_ERROR)
+ 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,
+ cie_table, &fde_table,
EH_CIE_OR_FDE_TYPE_ID);
}
- if (e.reason < 0)
+ catch (const gdb_exception_error &e)
{
warning (_("skipping .eh_frame info of %s: %s"),
- objfile_name (objfile), e.message);
+ objfile_name (objfile), e.what ());
if (fde_table.num_entries != 0)
{
fde_table.entries = NULL;
fde_table.num_entries = 0;
}
- /* The cie_table is discarded by the next if. */
+ /* The cie_table is discarded below. */
}
- 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;
- }
+ cie_table.clear ();
}
}
{
int num_old_fde_entries = fde_table.num_entries;
- TRY_CATCH (e, RETURN_MASK_ERROR)
+ 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,
+ cie_table, &fde_table,
EH_CIE_OR_FDE_TYPE_ID);
}
- if (e.reason < 0)
+ catch (const gdb_exception_error &e)
{
warning (_("skipping .debug_frame info of %s: %s"),
- objfile_name (objfile), e.message);
+ objfile_name (objfile), e.what ());
if (fde_table.num_entries != 0)
{
}
else
{
- 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.num_entries = num_old_fde_entries;
- /* The cie_table is discarded by the next if. */
}
}
- /* Discard the cie_table, it is no longer needed. */
- if (cie_table.num_entries != 0)
- {
- xfree (cie_table.entries);
- cie_table.entries = NULL; /* Paranoia. */
- cie_table.num_entries = 0; /* Paranoia. */
- }
-
/* Copy fde_table to obstack: it is needed at runtime. */
- fde_table2 = (struct dwarf2_fde_table *)
- obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2));
+ fde_table2 = XOBNEW (&objfile->objfile_obstack, struct dwarf2_fde_table);
if (fde_table.num_entries == 0)
{
int i;
/* Prepare FDE table for lookups. */
- qsort (fde_table.entries, fde_table.num_entries,
- sizeof (fde_table.entries[0]), qsort_fde_cmp);
+ std::sort (fde_table.entries, fde_table.entries + fde_table.num_entries,
+ fde_is_less_than);
/* Check for leftovers from --gc-sections. The GNU linker sets
the relevant symbols to zero, but doesn't zero the FDE *end*
++fde_table2->num_entries;
fde_prev = fde;
}
- fde_table2->entries = obstack_finish (&objfile->objfile_obstack);
+ 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);
+ dwarf2_frame_objfile_data.set (objfile, fde_table2);
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-void _initialize_dwarf2_frame (void);
+/* Handle 'maintenance show dwarf unwinders'. */
+
+static void
+show_dwarf_unwinders_enabled_p (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file,
+ _("The DWARF stack unwinders are currently %s.\n"),
+ value);
+}
void
_initialize_dwarf2_frame (void)
{
dwarf2_frame_data = gdbarch_data_register_pre_init (dwarf2_frame_init);
- dwarf2_frame_objfile_data = register_objfile_data ();
+
+ add_setshow_boolean_cmd ("unwinders", class_obscure,
+ &dwarf2_frame_unwinders_enabled_p , _("\
+Set whether the DWARF stack frame unwinders are used."), _("\
+Show whether the DWARF stack frame unwinders are used."), _("\
+When enabled the DWARF stack frame unwinders can be used for architectures\n\
+that support the DWARF unwinders. Enabling the DWARF unwinders for an\n\
+architecture that doesn't support them will have no effect."),
+ NULL,
+ show_dwarf_unwinders_enabled_p,
+ &set_dwarf_cmdlist,
+ &show_dwarf_cmdlist);
+
+#if GDB_SELF_TEST
+ selftests::register_test_foreach_arch ("execute_cfa_program",
+ selftests::execute_cfa_program_test);
+#endif
}