/* Frame unwinder for frames with DWARF Call Frame Information.
- Copyright 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Mark Kettenis.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "dwarf2expr.h"
gdb_byte *instructions;
gdb_byte *end;
+ /* True if this FDE is read from a .eh_frame instead of a .debug_frame
+ section. */
+ unsigned char eh_frame_p;
+
struct dwarf2_fde *next;
};
static void
execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end,
struct frame_info *next_frame,
- struct dwarf2_frame_state *fs)
+ struct dwarf2_frame_state *fs, int eh_frame_p)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
int bytes_read;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
while (insn_ptr < insn_end && fs->pc <= pc)
{
else if ((insn & 0xc0) == DW_CFA_offset)
{
reg = insn & 0x3f;
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
offset = utmp * fs->data_align;
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
{
gdb_assert (fs->initial.reg);
reg = insn & 0x3f;
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
if (reg < fs->initial.num_regs)
fs->regs.reg[reg] = fs->initial.reg[reg];
case DW_CFA_offset_extended:
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
offset = utmp * fs->data_align;
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
case DW_CFA_restore_extended:
gdb_assert (fs->initial.reg);
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
fs->regs.reg[reg] = fs->initial.reg[reg];
break;
case DW_CFA_undefined:
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
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, ®);
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
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, ®);
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
+ if (eh_frame_p)
+ utmp = dwarf2_frame_eh_frame_regnum (gdbarch, utmp);
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
fs->regs.reg[reg].loc.reg = utmp;
case DW_CFA_def_cfa_register:
insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
+ if (eh_frame_p)
+ fs->cfa_reg = dwarf2_frame_eh_frame_regnum (gdbarch,
+ fs->cfa_reg);
fs->cfa_how = CFA_REG_OFFSET;
break;
case DW_CFA_expression:
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
fs->regs.reg[reg].loc.exp = insn_ptr;
case DW_CFA_offset_extended_sf:
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
+ if (eh_frame_p)
+ reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
offset *= fs->data_align;
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
case DW_CFA_def_cfa_sf:
insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
+ if (eh_frame_p)
+ fs->cfa_reg = dwarf2_frame_eh_frame_regnum (gdbarch,
+ fs->cfa_reg);
insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
fs->cfa_offset = offset * fs->data_align;
fs->cfa_how = CFA_REG_OFFSET;
struct dwarf2_frame_ops
{
/* Pre-initialize the register state REG for register REGNUM. */
- void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *);
+ void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *,
+ struct frame_info *);
/* Check whether the frame preceding NEXT_FRAME will be a signal
trampoline. */
int (*signal_frame_p) (struct gdbarch *, struct frame_info *);
+
+ /* Convert .eh_frame register number to DWARF register number. */
+ int (*eh_frame_regnum) (struct gdbarch *, int);
};
/* Default architecture-specific register state initialization
static void
dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *next_frame)
{
/* If we have a register that acts as a program counter, mark it as
a destination for the return address. If we have a register that
void
dwarf2_frame_set_init_reg (struct gdbarch *gdbarch,
void (*init_reg) (struct gdbarch *, int,
- struct dwarf2_frame_state_reg *))
+ struct dwarf2_frame_state_reg *,
+ struct frame_info *))
{
struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
static void
dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *next_frame)
{
struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
- ops->init_reg (gdbarch, regnum, reg);
+ ops->init_reg (gdbarch, regnum, reg, next_frame);
}
/* Set the architecture-specific signal trampoline recognition
return 0;
return ops->signal_frame_p (gdbarch, next_frame);
}
+
+/* Set the architecture-specific mapping of .eh_frame register numbers to
+ DWARF register numbers. */
+
+void
+dwarf2_frame_set_eh_frame_regnum (struct gdbarch *gdbarch,
+ int (*eh_frame_regnum) (struct gdbarch *,
+ int))
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ ops->eh_frame_regnum = eh_frame_regnum;
+}
+
+/* Translate a .eh_frame register to DWARF register. */
+
+int
+dwarf2_frame_eh_frame_regnum (struct gdbarch *gdbarch, int regnum)
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ if (ops->eh_frame_regnum == NULL)
+ return regnum;
+ return ops->eh_frame_regnum (gdbarch, regnum);
+}
\f
struct dwarf2_frame_cache
/* First decode all the insns in the CIE. */
execute_cfa_program (fde->cie->initial_instructions,
- fde->cie->end, next_frame, fs);
+ fde->cie->end, next_frame, fs, fde->eh_frame_p);
/* 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->instructions, fde->end, next_frame, fs);
+ execute_cfa_program (fde->instructions, fde->end, next_frame, fs,
+ fde->eh_frame_p);
/* Caclulate the CFA. */
switch (fs->cfa_how)
int regnum;
for (regnum = 0; regnum < num_regs; regnum++)
- dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum]);
+ dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum], next_frame);
}
/* Go through the DWARF2 CFI generated table and save its register
}
break;
+ case DWARF2_FRAME_REG_CFA_OFFSET:
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Store the value. */
+ store_typed_address (valuep, builtin_type_void_data_ptr,
+ cache->cfa + cache->reg[regnum].loc.offset);
+ }
+ break;
+
case DWARF2_FRAME_REG_RA_OFFSET:
*optimizedp = 0;
*lvalp = not_lval;
else
cie->return_address_register = read_unsigned_leb128 (unit->abfd, buf,
&bytes_read);
+ if (eh_frame_p)
+ cie->return_address_register
+ = dwarf2_frame_eh_frame_regnum (current_gdbarch,
+ cie->return_address_register);
+
buf += bytes_read;
cie->saw_z_augmentation = (*augmentation == 'z');
fde->instructions = buf;
fde->end = end;
+ fde->eh_frame_p = eh_frame_p;
+
add_fde (unit, fde);
}
extern asection *dwarf_eh_frame_section;
/* Imported from dwarf2read.c. */
-extern char *dwarf2_read_section (struct objfile *objfile, asection *sectp);
+extern gdb_byte *dwarf2_read_section (struct objfile *objfile, asection *sectp);
void
dwarf2_build_frame_info (struct objfile *objfile)