/* Frame unwinder for frames with DWARF Call Frame Information.
- Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ Copyright (C) 2003-2019 Free Software Foundation, Inc.
Contributed by Mark Kettenis.
#include "complaints.h"
#include "dwarf2-frame.h"
+#include "dwarf2read.h"
#include "ax.h"
#include "dwarf2loc.h"
#include "dwarf2-frame-tailcall.h"
#if GDB_SELF_TEST
-#include "selftest.h"
+#include "common/selftest.h"
#include "selftest-arch.h"
#endif
CORE_ADDR func_base);
\f
+/* See dwarf2-frame.h. */
+int dwarf2_frame_unwinders_enabled_p = 1;
+
/* 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
{
ULONGEST reg;
- gdb_assert (fs->initial.reg);
reg = dwarf2_frame_adjust_regnum (gdbarch, reg_num, eh_frame_p);
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;
{
int regnum = dwarf_reg_to_regnum (gdbarch, reg);
- complaint (&symfile_complaints, _("\
+ complaint (_("\
incomplete CFI data; DW_CFA_restore unspecified\n\
register %s (#%d) at %s"),
gdbarch_register_name (gdbarch, regnum), regnum,
struct frame_info *this_frame;
- CORE_ADDR read_addr_from_reg (int reg) OVERRIDE
+ 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 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
+ 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
+ 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
+ int deref_size) override
{
invalid ("DW_OP_entry_value");
}
- CORE_ADDR get_object_address () OVERRIDE
+ CORE_ADDR get_object_address () override
{
invalid ("DW_OP_push_object_address");
}
- CORE_ADDR get_frame_cfa () OVERRIDE
+ CORE_ADDR get_frame_cfa () override
{
invalid ("DW_OP_call_frame_cfa");
}
- CORE_ADDR get_tls_address (CORE_ADDR offset) OVERRIDE
+ CORE_ADDR get_tls_address (CORE_ADDR offset) override
{
invalid ("DW_OP_form_tls_address");
}
- void dwarf_call (cu_offset die_offset) OVERRIDE
+ void dwarf_call (cu_offset die_offset) override
{
invalid ("DW_OP_call*");
}
- CORE_ADDR get_addr_index (unsigned int index)
+ 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_GNU_addr_index");
+ invalid ("DW_OP_addrx or DW_OP_GNU_addr_index");
}
private:
if (old_rs == NULL)
{
- complaint (&symfile_complaints, _("\
+ complaint (_("\
bad CFI data; mismatched DW_CFA_restore_state at %s"),
paddress (gdbarch, fs->pc));
}
}
}
- if (fs->initial.reg == NULL)
+ if (fs->initial.reg.empty ())
{
/* Don't allow remember/restore between CIE and FDE programs. */
delete fs->regs.prev;
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.num_regs == (std::max (r1, r2) + 1));
+ 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.num_regs; i++)
+ for (auto i = 0; i < fs.regs.reg.size (); i++)
if (i != r2)
SELF_CHECK (fs.regs.reg[i].how == DWARF2_FRAME_REG_UNSPECIFIED);
dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
{
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_fde *fde;
CORE_ADDR entry_pc;
execute_cfa_program (fde, instr, fde->end, gdbarch,
get_frame_address_in_block (this_frame), &fs);
- TRY
+ try
{
/* Calculate the CFA. */
switch (fs.regs.cfa_how)
internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
}
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == NOT_AVAILABLE_ERROR)
{
return cache;
}
- throw_exception (ex);
+ throw;
}
- END_CATCH
/* Initialize the register state. */
{
{
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 = dwarf_reg_to_regnum (gdbarch, column);
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));
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 (fs.retaddr_column < fs.regs.num_regs
+ if (fs.retaddr_column < fs.regs.reg.size ()
&& fs.regs.reg[fs.retaddr_column].how == DWARF2_FRAME_REG_UNDEFINED)
cache->undefined_retaddr = 1;
dwarf2_frame_sniffer (const struct frame_unwind *self,
struct frame_info *this_frame, void **this_cache)
{
+ if (!dwarf2_frame_unwinders_enabled_p)
+ return 0;
+
/* Grab an address that is guarenteed 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.
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)
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;
{
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);
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++;
}
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;
}
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;
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
+ try
{
frame_ptr = unit->dwarf_frame_buffer;
while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
EH_CIE_OR_FDE_TYPE_ID);
}
- CATCH (e, RETURN_MASK_ERROR)
+ 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)
{
}
/* The cie_table is discarded by the next if. */
}
- END_CATCH
if (cie_table.num_entries != 0)
{
{
int num_old_fde_entries = fde_table.num_entries;
- TRY
+ try
{
frame_ptr = unit->dwarf_frame_buffer;
while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
&cie_table, &fde_table,
EH_CIE_OR_FDE_TYPE_ID);
}
- CATCH (e, RETURN_MASK_ERROR)
+ 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)
{
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. */
set_objfile_data (objfile, dwarf2_frame_objfile_data, 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 (selftests::execute_cfa_program_test);
+ selftests::register_test_foreach_arch ("execute_cfa_program",
+ selftests::execute_cfa_program_test);
#endif
}