/* Frame unwinder for frames with DWARF Call Frame Information.
- Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Contributed by Mark Kettenis.
#include "complaints.h"
#include "dwarf2-frame.h"
+#include "ax.h"
+#include "dwarf2loc.h"
+#include "exceptions.h"
struct comp_unit;
/* Target address size in bytes. */
int addr_size;
- /* Target pointer size in bytes. */
+ /* Target pointer size in bytes. */
int ptr_size;
/* True if a 'z' augmentation existed. */
_("Support for DW_OP_call_frame_cfa is unimplemented"));
}
+/* Helper function for execute_stack_op. */
+
+static CORE_ADDR
+no_get_frame_pc (void *baton)
+{
+ internal_error (__FILE__, __LINE__, _("\
+Support for DW_OP_GNU_implicit_pointer is unimplemented"));
+}
+
static CORE_ADDR
no_get_tls_address (void *baton, CORE_ADDR offset)
{
- internal_error (__FILE__, __LINE__,
- _("Support for DW_OP_GNU_push_tls_address is unimplemented"));
+ internal_error (__FILE__, __LINE__, _("\
+Support for DW_OP_GNU_push_tls_address is unimplemented"));
}
/* Helper function for execute_stack_op. */
ctx->read_mem = read_mem;
ctx->get_frame_base = no_get_frame_base;
ctx->get_frame_cfa = no_get_frame_cfa;
+ ctx->get_frame_pc = no_get_frame_pc;
ctx->get_tls_address = no_get_tls_address;
ctx->dwarf_call = no_dwarf_call;
/* 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);
static void
execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
- const gdb_byte *insn_end, struct frame_info *this_frame,
- struct dwarf2_frame_state *fs)
+ 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);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
while (insn_ptr < insn_end && fs->pc <= pc)
break;
default:
- internal_error (__FILE__, __LINE__, _("Unknown CFI encountered."));
+ internal_error (__FILE__, __LINE__,
+ _("Unknown CFI encountered."));
}
}
}
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);
}
\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)
+{
+ const int num_regs = gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch);
+ struct dwarf2_fde *fde;
+ CORE_ADDR text_offset, cfa;
+ 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:
+ {
+ 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);
+
+ 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);
+ }
+ }
+ 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;
+
+ default:
+ internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+ }
+}
+
+\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;
struct dwarf2_frame_cache *cache;
struct dwarf2_frame_state *fs;
struct dwarf2_fde *fde;
+ volatile struct gdb_exception ex;
if (*this_cache)
return *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;
/* Allocate and initialize the frame state. */
- fs = XMALLOC (struct dwarf2_frame_state);
- memset (fs, 0, sizeof (struct dwarf2_frame_state));
+ fs = XZALLOC (struct dwarf2_frame_state);
old_chain = make_cleanup (dwarf2_frame_state_free, fs);
/* Unwind the PC.
/* First decode all the insns in the CIE. */
execute_cfa_program (fde, fde->cie->initial_instructions,
- fde->cie->end, this_frame, fs);
+ fde->cie->end, gdbarch, get_frame_pc (this_frame), 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, this_frame, fs);
+ execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,
+ get_frame_pc (this_frame), fs);
- /* Calculate the CFA. */
- switch (fs->regs.cfa_how)
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
{
- 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, cache->text_offset,
- this_frame, 0, 0);
- break;
+ /* Calculate the CFA. */
+ switch (fs->regs.cfa_how)
+ {
+ 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, cache->text_offset,
+ this_frame, 0, 0);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+ }
+ }
+ if (ex.reason < 0)
+ {
+ if (ex.error == NOT_AVAILABLE_ERROR)
+ {
+ cache->unavailable_retaddr = 1;
+ return cache;
+ }
- default:
- internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+ throw_exception (ex);
}
/* Initialize the register state. */
do_cleanups (old_chain);
- *this_cache = cache;
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->unavailable_retaddr)
+ return;
+
if (cache->undefined_retaddr)
return;
static const struct frame_unwind dwarf2_frame_unwind =
{
NORMAL_FRAME,
+ dwarf2_frame_unwind_stop_reason,
dwarf2_frame_this_id,
dwarf2_frame_prev_register,
NULL,
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,
}
break;
default:
- internal_error (__FILE__, __LINE__, _("Invalid or unsupported encoding"));
+ internal_error (__FILE__, __LINE__,
+ _("Invalid or unsupported encoding"));
}
if ((encoding & 0x07) == 0x00)
*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
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;
/* 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. */
+ section exists as well. */
if (eh_frame_p)
cie->ptr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
else
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;
\f
/* Imported from dwarf2read.c. */
-extern void dwarf2_get_section_info (struct objfile *, const char *, asection **,
- gdb_byte **, bfd_size_type *);
+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)