};
static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc);
+
+static int dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum,
+ int eh_frame_p);
\f
/* Structure describing a frame state. */
else if ((insn & 0xc0) == DW_CFA_offset)
{
reg = insn & 0x3f;
- if (eh_frame_p)
- reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+ reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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);
+ reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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);
+ reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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);
+ reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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);
+ 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, ®);
- if (eh_frame_p)
- reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+ 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, ®);
- if (eh_frame_p)
- reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+ reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
- if (eh_frame_p)
- utmp = dwarf2_frame_eh_frame_regnum (gdbarch, 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;
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_reg = dwarf2_frame_adjust_regnum (gdbarch, fs->cfa_reg,
+ eh_frame_p);
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);
+ 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);
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);
+ reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
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);
+ fs->cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, fs->cfa_reg,
+ eh_frame_p);
insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
fs->cfa_offset = offset * fs->data_align;
fs->cfa_how = CFA_REG_OFFSET;
case DW_CFA_GNU_negative_offset_extended:
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
- if (eh_frame_p)
- reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+ reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
insn_ptr = read_uleb128 (insn_ptr, insn_end, &offset);
offset *= fs->data_align;
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
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);
+ /* Convert .eh_frame register number to DWARF register number, or
+ adjust .debug_frame register number. */
+ int (*adjust_regnum) (struct gdbarch *, int, int);
};
/* Default architecture-specific register state initialization
return ops->signal_frame_p (gdbarch, next_frame);
}
-/* Set the architecture-specific mapping of .eh_frame register numbers to
- DWARF register numbers. */
+/* Set the architecture-specific adjustment of .eh_frame and .debug_frame
+ register numbers. */
void
-dwarf2_frame_set_eh_frame_regnum (struct gdbarch *gdbarch,
- int (*eh_frame_regnum) (struct gdbarch *,
- int))
+dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch,
+ int (*adjust_regnum) (struct gdbarch *,
+ int, int))
{
struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
- ops->eh_frame_regnum = eh_frame_regnum;
+ ops->adjust_regnum = adjust_regnum;
}
-/* Translate a .eh_frame register to DWARF register. */
+/* Translate a .eh_frame register to DWARF register, or adjust a .debug_frame
+ register. */
-int
-dwarf2_frame_eh_frame_regnum (struct gdbarch *gdbarch, int regnum)
+static int
+dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, int eh_frame_p)
{
struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
- if (ops->eh_frame_regnum == NULL)
+ if (ops->adjust_regnum == NULL)
return regnum;
- return ops->eh_frame_regnum (gdbarch, regnum);
+ return ops->adjust_regnum (gdbarch, regnum, eh_frame_p);
}
static void
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);
+ cie->return_address_register
+ = dwarf2_frame_adjust_regnum (current_gdbarch,
+ cie->return_address_register,
+ eh_frame_p);
buf += bytes_read;
#include "sim-regno.h"
#include "gdb/sim-ppc.h"
#include "reggroups.h"
+#include "dwarf2-frame.h"
#include "libbfd.h" /* for bfd_default_set_arch_mach */
#include "coff/internal.h" /* for libcoff.h */
}
}
+/* Translate a .eh_frame register to DWARF register, or adjust a
+ .debug_frame register. */
+
+static int
+rs6000_adjust_frame_regnum (struct gdbarch *gdbarch, int num, int eh_frame_p)
+{
+ /* GCC releases before 3.4 use GCC internal register numbering in
+ .debug_frame (and .debug_info, et cetera). The numbering is
+ different from the standard SysV numbering for everything except
+ for GPRs and FPRs. We can not detect this problem in most cases
+ - to get accurate debug info for variables living in lr, ctr, v0,
+ et cetera, use a newer version of GCC. But we must detect
+ one important case - lr is in column 65 in .debug_frame output,
+ instead of 108.
+
+ GCC 3.4, and the "hammer" branch, have a related problem. They
+ record lr register saves in .debug_frame as 108, but still record
+ the return column as 65. We fix that up too.
+
+ We can do this because 65 is assigned to fpsr, and GCC never
+ generates debug info referring to it. To add support for
+ handwritten debug info that restores fpsr, we would need to add a
+ producer version check to this. */
+ if (!eh_frame_p)
+ {
+ if (num == 65)
+ return 108;
+ else
+ return num;
+ }
+
+ /* .eh_frame is GCC specific. For binary compatibility, it uses GCC
+ internal register numbering; translate that to the standard DWARF2
+ register numbering. */
+ if (0 <= num && num <= 63) /* r0-r31,fp0-fp31 */
+ return num;
+ else if (68 <= num && num <= 75) /* cr0-cr8 */
+ return num - 68 + 86;
+ else if (77 <= num && num <= 108) /* vr0-vr31 */
+ return num - 77 + 1124;
+ else
+ switch (num)
+ {
+ case 64: /* mq */
+ return 100;
+ case 65: /* lr */
+ return 108;
+ case 66: /* ctr */
+ return 109;
+ case 76: /* xer */
+ return 101;
+ case 109: /* vrsave */
+ return 356;
+ case 110: /* vscr */
+ return 67;
+ case 111: /* spe_acc */
+ return 99;
+ case 112: /* spefscr */
+ return 612;
+ default:
+ return num;
+ }
+}
\f
/* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG).
(gdbarch, rs6000_in_solib_return_trampoline);
set_gdbarch_skip_trampoline_code (gdbarch, rs6000_skip_trampoline_code);
+ /* Hook in the DWARF CFI frame unwinder. */
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+ dwarf2_frame_set_adjust_regnum (gdbarch, rs6000_adjust_frame_regnum);
+
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);