summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gnu/usr.bin/binutils/gdb/ppc-tdep.h308
-rw-r--r--gnu/usr.bin/binutils/gdb/ppcobsd-nat.c92
-rw-r--r--gnu/usr.bin/binutils/gdb/ppcobsd-tdep.c192
-rw-r--r--gnu/usr.bin/binutils/gdb/ppcobsd-tdep.h8
4 files changed, 560 insertions, 40 deletions
diff --git a/gnu/usr.bin/binutils/gdb/ppc-tdep.h b/gnu/usr.bin/binutils/gdb/ppc-tdep.h
index 1c1c9ef21a3..d36ec766fc1 100644
--- a/gnu/usr.bin/binutils/gdb/ppc-tdep.h
+++ b/gnu/usr.bin/binutils/gdb/ppc-tdep.h
@@ -1,6 +1,7 @@
/* Target-dependent code for GDB, the GNU debugger.
- Copyright 2000, 2001, 2002, 2003
- Free Software Foundation, Inc.
+
+ Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation,
+ Inc.
This file is part of GDB.
@@ -29,11 +30,6 @@ struct regcache;
struct type;
/* From ppc-linux-tdep.c... */
-CORE_ADDR ppc_linux_frame_saved_pc (struct frame_info *fi);
-void ppc_linux_init_extra_frame_info (int fromleaf, struct frame_info *);
-int ppc_linux_frameless_function_invocation (struct frame_info *);
-void ppc_linux_frame_init_saved_regs (struct frame_info *);
-CORE_ADDR ppc_linux_frame_chain (struct frame_info *);
enum return_value_convention ppc_sysv_abi_return_value (struct gdbarch *gdbarch,
struct type *valtype,
struct regcache *regcache,
@@ -45,14 +41,14 @@ enum return_value_convention ppc_sysv_abi_broken_return_value (struct gdbarch *g
void *readbuf,
const void *writebuf);
CORE_ADDR ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
- CORE_ADDR func_addr,
+ struct value *function,
struct regcache *regcache,
CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp,
int struct_return,
CORE_ADDR struct_addr);
CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
- CORE_ADDR func_addr,
+ struct value *function,
struct regcache *regcache,
CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp,
@@ -62,8 +58,12 @@ CORE_ADDR ppc64_sysv_abi_adjust_breakpoint_address (struct gdbarch *gdbarch,
CORE_ADDR bpaddr);
int ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache);
struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
-void ppc_linux_supply_gregset (char *buf);
-void ppc_linux_supply_fpregset (char *buf);
+void ppc_linux_supply_gregset (struct regcache *regcache,
+ int regnum, const void *gregs, size_t size,
+ int wordsize);
+void ppc_linux_supply_fpregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs, size_t size);
enum return_value_convention ppc64_sysv_abi_return_value (struct gdbarch *gdbarch,
struct type *valtype,
@@ -72,42 +72,308 @@ enum return_value_convention ppc64_sysv_abi_return_value (struct gdbarch *gdbarc
const void *writebuf);
/* From rs6000-tdep.c... */
-CORE_ADDR rs6000_frame_saved_pc (struct frame_info *fi);
-void rs6000_init_extra_frame_info (int fromleaf, struct frame_info *);
-int rs6000_frameless_function_invocation (struct frame_info *);
-void rs6000_frame_init_saved_regs (struct frame_info *);
-CORE_ADDR rs6000_frame_chain (struct frame_info *);
int altivec_register_p (int regno);
+int spe_register_p (int regno);
-
-/* Return non-zero when the architecture has an FPU (or at least when
- the ABI is using the FPU). */
+/* Return non-zero if the architecture described by GDBARCH has
+ floating-point registers (f0 --- f31 and fpscr). */
int ppc_floating_point_unit_p (struct gdbarch *gdbarch);
+/* Register set description. */
+
+struct ppc_reg_offsets
+{
+ /* General-purpose registers. */
+ int r0_offset;
+ int pc_offset;
+ int ps_offset;
+ int cr_offset;
+ int lr_offset;
+ int ctr_offset;
+ int xer_offset;
+ int mq_offset;
+
+ /* Floating-point registers. */
+ int f0_offset;
+ int fpscr_offset;
+
+ /* AltiVec registers. */
+ int vr0_offset;
+ int vscr_offset;
+ int vrsave_offset;
+};
+
+/* Supply register REGNUM in the general-purpose register set REGSET
+ from the buffer specified by GREGS and LEN to register cache
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
+
+extern void ppc_supply_gregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs, size_t len);
+
+/* Supply register REGNUM in the floating-point register set REGSET
+ from the buffer specified by FPREGS and LEN to register cache
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
+
+extern void ppc_supply_fpregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len);
+
+/* Collect register REGNUM in the general-purpose register set
+ REGSET. from register cache REGCACHE into the buffer specified by
+ GREGS and LEN. If REGNUM is -1, do this for all registers in
+ REGSET. */
+
+extern void ppc_collect_gregset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *gregs, size_t len);
+
+/* Collect register REGNUM in the floating-point register set
+ REGSET. from register cache REGCACHE into the buffer specified by
+ FPREGS and LEN. If REGNUM is -1, do this for all registers in
+ REGSET. */
+
+extern void ppc_collect_fpregset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *fpregs, size_t len);
+
/* Private data that this module attaches to struct gdbarch. */
struct gdbarch_tdep
{
int wordsize; /* size in bytes of fixed-point word */
- int *regoff; /* byte offsets in register arrays */
const struct reg *regs; /* from current variant */
int ppc_gp0_regnum; /* GPR register 0 */
- int ppc_gplast_regnum; /* GPR register 31 */
int ppc_toc_regnum; /* TOC register */
int ppc_ps_regnum; /* Processor (or machine) status (%msr) */
int ppc_cr_regnum; /* Condition register */
int ppc_lr_regnum; /* Link register */
int ppc_ctr_regnum; /* Count register */
int ppc_xer_regnum; /* Integer exception register */
+
+ /* On PPC and RS6000 variants that have no floating-point
+ registers, the next two members will be -1. */
+ int ppc_fp0_regnum; /* floating-point register 0 */
int ppc_fpscr_regnum; /* Floating point status and condition
register */
+
+ int ppc_sr0_regnum; /* segment register 0, or -1 on
+ variants that have no segment
+ registers. */
+
int ppc_mq_regnum; /* Multiply/Divide extension register */
int ppc_vr0_regnum; /* First AltiVec register */
int ppc_vrsave_regnum; /* Last AltiVec register */
+ int ppc_ev0_upper_regnum; /* First GPR upper half register */
int ppc_ev0_regnum; /* First ev register */
int ppc_ev31_regnum; /* Last ev register */
+ int ppc_acc_regnum; /* SPE 'acc' register */
+ int ppc_spefscr_regnum; /* SPE 'spefscr' register */
int lr_frame_offset; /* Offset to ABI specific location where
link register is saved. */
+
+ /* An array of integers, such that sim_regno[I] is the simulator
+ register number for GDB register number I, or -1 if the
+ simulator does not implement that register. */
+ int *sim_regno;
};
+
+/* Constants for register set sizes. */
+enum
+ {
+ ppc_num_gprs = 32, /* 32 general-purpose registers */
+ ppc_num_fprs = 32, /* 32 floating-point registers */
+ ppc_num_srs = 16, /* 16 segment registers */
+ ppc_num_vrs = 32 /* 32 Altivec vector registers */
+ };
+
+
+/* Constants for SPR register numbers. These are *not* GDB register
+ numbers: they are the numbers used in the PowerPC ISA itself to
+ refer to these registers.
+
+ This table includes all the SPRs from all the variants I could find
+ documentation for.
+
+ There may be registers from different PowerPC variants assigned the
+ same number, but that's fine: GDB and the SIM always use the
+ numbers in the context of a particular variant, so it's not
+ ambiguous.
+
+ We need to deviate from the naming pattern when variants have
+ special-purpose registers of the same name, but with different
+ numbers. Fortunately, this is rare: look below to see how we
+ handle the 'tcr' registers on the 403/403GX and 602. */
+
+enum
+ {
+ ppc_spr_mq = 0,
+ ppc_spr_xer = 1,
+ ppc_spr_rtcu = 4,
+ ppc_spr_rtcl = 5,
+ ppc_spr_lr = 8,
+ ppc_spr_ctr = 9,
+ ppc_spr_cnt = 9,
+ ppc_spr_dsisr = 18,
+ ppc_spr_dar = 19,
+ ppc_spr_dec = 22,
+ ppc_spr_sdr1 = 25,
+ ppc_spr_srr0 = 26,
+ ppc_spr_srr1 = 27,
+ ppc_spr_eie = 80,
+ ppc_spr_eid = 81,
+ ppc_spr_nri = 82,
+ ppc_spr_sp = 102,
+ ppc_spr_cmpa = 144,
+ ppc_spr_cmpb = 145,
+ ppc_spr_cmpc = 146,
+ ppc_spr_cmpd = 147,
+ ppc_spr_icr = 148,
+ ppc_spr_der = 149,
+ ppc_spr_counta = 150,
+ ppc_spr_countb = 151,
+ ppc_spr_cmpe = 152,
+ ppc_spr_cmpf = 153,
+ ppc_spr_cmpg = 154,
+ ppc_spr_cmph = 155,
+ ppc_spr_lctrl1 = 156,
+ ppc_spr_lctrl2 = 157,
+ ppc_spr_ictrl = 158,
+ ppc_spr_bar = 159,
+ ppc_spr_vrsave = 256,
+ ppc_spr_sprg0 = 272,
+ ppc_spr_sprg1 = 273,
+ ppc_spr_sprg2 = 274,
+ ppc_spr_sprg3 = 275,
+ ppc_spr_asr = 280,
+ ppc_spr_ear = 282,
+ ppc_spr_tbl = 284,
+ ppc_spr_tbu = 285,
+ ppc_spr_pvr = 287,
+ ppc_spr_spefscr = 512,
+ ppc_spr_ibat0u = 528,
+ ppc_spr_ibat0l = 529,
+ ppc_spr_ibat1u = 530,
+ ppc_spr_ibat1l = 531,
+ ppc_spr_ibat2u = 532,
+ ppc_spr_ibat2l = 533,
+ ppc_spr_ibat3u = 534,
+ ppc_spr_ibat3l = 535,
+ ppc_spr_dbat0u = 536,
+ ppc_spr_dbat0l = 537,
+ ppc_spr_dbat1u = 538,
+ ppc_spr_dbat1l = 539,
+ ppc_spr_dbat2u = 540,
+ ppc_spr_dbat2l = 541,
+ ppc_spr_dbat3u = 542,
+ ppc_spr_dbat3l = 543,
+ ppc_spr_ic_cst = 560,
+ ppc_spr_ic_adr = 561,
+ ppc_spr_ic_dat = 562,
+ ppc_spr_dc_cst = 568,
+ ppc_spr_dc_adr = 569,
+ ppc_spr_dc_dat = 570,
+ ppc_spr_dpdr = 630,
+ ppc_spr_dpir = 631,
+ ppc_spr_immr = 638,
+ ppc_spr_mi_ctr = 784,
+ ppc_spr_mi_ap = 786,
+ ppc_spr_mi_epn = 787,
+ ppc_spr_mi_twc = 789,
+ ppc_spr_mi_rpn = 790,
+ ppc_spr_mi_cam = 816,
+ ppc_spr_mi_ram0 = 817,
+ ppc_spr_mi_ram1 = 818,
+ ppc_spr_md_ctr = 792,
+ ppc_spr_m_casid = 793,
+ ppc_spr_md_ap = 794,
+ ppc_spr_md_epn = 795,
+ ppc_spr_m_twb = 796,
+ ppc_spr_md_twc = 797,
+ ppc_spr_md_rpn = 798,
+ ppc_spr_m_tw = 799,
+ ppc_spr_mi_dbcam = 816,
+ ppc_spr_mi_dbram0 = 817,
+ ppc_spr_mi_dbram1 = 818,
+ ppc_spr_md_dbcam = 824,
+ ppc_spr_md_cam = 824,
+ ppc_spr_md_dbram0 = 825,
+ ppc_spr_md_ram0 = 825,
+ ppc_spr_md_dbram1 = 826,
+ ppc_spr_md_ram1 = 826,
+ ppc_spr_ummcr0 = 936,
+ ppc_spr_upmc1 = 937,
+ ppc_spr_upmc2 = 938,
+ ppc_spr_usia = 939,
+ ppc_spr_ummcr1 = 940,
+ ppc_spr_upmc3 = 941,
+ ppc_spr_upmc4 = 942,
+ ppc_spr_zpr = 944,
+ ppc_spr_pid = 945,
+ ppc_spr_mmcr0 = 952,
+ ppc_spr_pmc1 = 953,
+ ppc_spr_sgr = 953,
+ ppc_spr_pmc2 = 954,
+ ppc_spr_dcwr = 954,
+ ppc_spr_sia = 955,
+ ppc_spr_mmcr1 = 956,
+ ppc_spr_pmc3 = 957,
+ ppc_spr_pmc4 = 958,
+ ppc_spr_sda = 959,
+ ppc_spr_tbhu = 972,
+ ppc_spr_tblu = 973,
+ ppc_spr_dmiss = 976,
+ ppc_spr_dcmp = 977,
+ ppc_spr_hash1 = 978,
+ ppc_spr_hash2 = 979,
+ ppc_spr_icdbdr = 979,
+ ppc_spr_imiss = 980,
+ ppc_spr_esr = 980,
+ ppc_spr_icmp = 981,
+ ppc_spr_dear = 981,
+ ppc_spr_rpa = 982,
+ ppc_spr_evpr = 982,
+ ppc_spr_cdbcr = 983,
+ ppc_spr_tsr = 984,
+ ppc_spr_602_tcr = 984,
+ ppc_spr_403_tcr = 986,
+ ppc_spr_ibr = 986,
+ ppc_spr_pit = 987,
+ ppc_spr_esasrr = 988,
+ ppc_spr_tbhi = 988,
+ ppc_spr_tblo = 989,
+ ppc_spr_srr2 = 990,
+ ppc_spr_sebr = 990,
+ ppc_spr_srr3 = 991,
+ ppc_spr_ser = 991,
+ ppc_spr_hid0 = 1008,
+ ppc_spr_dbsr = 1008,
+ ppc_spr_hid1 = 1009,
+ ppc_spr_iabr = 1010,
+ ppc_spr_dbcr = 1010,
+ ppc_spr_iac1 = 1012,
+ ppc_spr_dabr = 1013,
+ ppc_spr_iac2 = 1013,
+ ppc_spr_dac1 = 1014,
+ ppc_spr_dac2 = 1015,
+ ppc_spr_l2cr = 1017,
+ ppc_spr_dccr = 1018,
+ ppc_spr_ictc = 1019,
+ ppc_spr_iccr = 1019,
+ ppc_spr_thrm1 = 1020,
+ ppc_spr_pbl1 = 1020,
+ ppc_spr_thrm2 = 1021,
+ ppc_spr_pbu1 = 1021,
+ ppc_spr_thrm3 = 1022,
+ ppc_spr_pbl2 = 1022,
+ ppc_spr_fpecr = 1022,
+ ppc_spr_lt = 1022,
+ ppc_spr_pir = 1023,
+ ppc_spr_pbu2 = 1023
+ };
+
+/* Instruction size. */
+#define PPC_INSN_SIZE 4
+
#endif
diff --git a/gnu/usr.bin/binutils/gdb/ppcobsd-nat.c b/gnu/usr.bin/binutils/gdb/ppcobsd-nat.c
index db85407574e..5acfbb35e4d 100644
--- a/gnu/usr.bin/binutils/gdb/ppcobsd-nat.c
+++ b/gnu/usr.bin/binutils/gdb/ppcobsd-nat.c
@@ -1,6 +1,6 @@
/* Native-dependent code for OpenBSD/powerpc.
- Copyright 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GDB.
@@ -16,14 +16,15 @@
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 "gdbcore.h"
#include "inferior.h"
#include "regcache.h"
+#include "gdb_assert.h"
#include <stddef.h>
#include <sys/types.h>
#include <sys/ptrace.h>
@@ -37,8 +38,37 @@
#include "inf-ptrace.h"
#include "bsd-kvm.h"
-/* OpenBSD/powerpc doesn't have PT_GETFPREGS/PT_SETFPREGS like
- NetBSD/powerpc and FreeBSD/powerpc. */
+/* OpenBSD/powerpc didn't have PT_GETFPREGS/PT_SETFPREGS until release
+ 4.0. On older releases the floating-point registers are handled by
+ PT_GETREGS/PT_SETREGS, but fpscr wasn't available.. */
+
+#ifdef PT_GETFPREGS
+
+/* Returns true if PT_GETFPREGS fetches this register. */
+
+static int
+getfpregs_supplies (int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+ point registers. Traditionally, GDB's register set has still
+ listed the floating point registers for such machines, so this
+ code is harmless. However, the new E500 port actually omits the
+ floating point registers entirely from the register set --- they
+ don't even have register numbers assigned to them.
+
+ It's not clear to me how best to update this code, so this assert
+ will alert the first person to encounter the NetBSD/E500
+ combination to the problem. */
+ gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
+
+ return ((regnum >= tdep->ppc_fp0_regnum
+ && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs)
+ || regnum == tdep->ppc_fpscr_regnum);
+}
+
+#endif /* PT_GETFPREGS */
/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
for all registers. */
@@ -52,8 +82,26 @@ ppcobsd_fetch_registers (int regnum)
(PTRACE_TYPE_ARG3) &regs, 0) == -1)
perror_with_name (_("Couldn't get registers"));
- ppcobsd_supply_gregset (&ppcobsd_gregset, current_regcache, -1,
- &regs, sizeof regs);
+ ppc_supply_gregset (&ppcobsd_gregset, current_regcache, -1,
+ &regs, sizeof regs);
+#ifndef PT_GETFPREGS
+ ppc_supply_fpregset (&ppcobsd_gregset, current_regcache, -1,
+ &regs, sizeof regs);
+#endif
+
+#ifdef PT_GETFPREGS
+ if (regnum == -1 || getfpregs_supplies (regnum))
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+ perror_with_name (_("Couldn't get floating point status"));
+
+ ppc_supply_fpregset (&ppcobsd_fpregset, current_regcache, -1,
+ &fpregs, sizeof fpregs);
+ }
+#endif
}
/* Store register REGNUM back into the inferior. If REGNUM is -1, do
@@ -68,12 +116,34 @@ ppcobsd_store_registers (int regnum)
(PTRACE_TYPE_ARG3) &regs, 0) == -1)
perror_with_name (_("Couldn't get registers"));
- ppcobsd_collect_gregset (&ppcobsd_gregset, current_regcache,
- regnum, &regs, sizeof regs);
+ ppc_collect_gregset (&ppcobsd_gregset, current_regcache,
+ regnum, &regs, sizeof regs);
+#ifndef PT_GETFPREGS
+ ppc_collect_fpregset (&ppcobsd_gregset, current_regcache,
+ regnum, &regs, sizeof regs);
+#endif
if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
(PTRACE_TYPE_ARG3) &regs, 0) == -1)
perror_with_name (_("Couldn't write registers"));
+
+#ifdef PT_GETFPREGS
+ if (regnum == -1 || getfpregs_supplies (regnum))
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+ perror_with_name (_("Couldn't get floating point status"));
+
+ ppc_collect_fpregset (&ppcobsd_fpregset, current_regcache,
+ regnum, &fpregs, sizeof fpregs);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+ perror_with_name (_("Couldn't write floating point status"));
+ }
+#endif
}
@@ -141,6 +211,10 @@ _initialize_ppcobsd_nat (void)
/* Floating-point registers. */
ppcobsd_reg_offsets.f0_offset = offsetof (struct reg, fpr);
ppcobsd_reg_offsets.fpscr_offset = -1;
+#ifdef PT_GETFPREGS
+ ppcobsd_fpreg_offsets.f0_offset = offsetof (struct fpreg, fpr);
+ ppcobsd_fpreg_offsets.fpscr_offset = offsetof (struct fpreg, fpscr);
+#endif
/* AltiVec registers. */
ppcobsd_reg_offsets.vr0_offset = offsetof (struct vreg, vreg);
diff --git a/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.c b/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.c
index 8a0a9c41717..410852ddca2 100644
--- a/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.c
+++ b/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.c
@@ -1,6 +1,6 @@
/* Target-dependent code for OpenBSD/powerpc.
- Copyright 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GDB.
@@ -16,16 +16,21 @@
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 "arch-utils.h"
+#include "floatformat.h"
+#include "frame.h"
+#include "frame-unwind.h"
#include "osabi.h"
#include "regcache.h"
#include "regset.h"
-#include "gdb_assert.h"
+#include "symtab.h"
+#include "trad-frame.h"
+#include "gdb_assert.h"
#include "gdb_string.h"
#include "ppc-tdep.h"
@@ -34,6 +39,7 @@
/* Register offsets from <machine/reg.h>. */
struct ppc_reg_offsets ppcobsd_reg_offsets;
+struct ppc_reg_offsets ppcobsd_fpreg_offsets;
/* Core file support. */
@@ -89,7 +95,7 @@ ppcobsd_collect_gregset (const struct regset *regset,
ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
}
-/* OpenBS/powerpc register set. */
+/* OpenBSD/powerpc register set. */
struct regset ppcobsd_gregset =
{
@@ -97,6 +103,12 @@ struct regset ppcobsd_gregset =
ppcobsd_supply_gregset
};
+struct regset ppcobsd_fpregset =
+{
+ &ppcobsd_fpreg_offsets,
+ ppc_supply_fpregset
+};
+
/* Return the appropriate register set for the core section identified
by SECT_NAME and SECT_SIZE. */
@@ -111,17 +123,176 @@ ppcobsd_regset_from_core_section (struct gdbarch *gdbarch,
}
+/* Signal trampolines. */
+
+/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
+ in virtual memory. The randomness makes it somewhat tricky to
+ detect it, but fortunately we can rely on the fact that the start
+ of the sigtramp routine is page-aligned. We recognize the
+ trampoline by looking for the code that invokes the sigreturn
+ system call. The offset where we can find that code varies from
+ release to release.
+
+ By the way, the mapping mentioned above is read-only, so you cannot
+ place a breakpoint in the signal trampoline. */
+
+/* Default page size. */
+static const int ppcobsd_page_size = 4096;
+
+/* Offset for sigreturn(2). */
+static const int ppcobsd_sigreturn_offset[] = {
+ 0x98, /* OpenBSD 3.8 */
+ 0x0c, /* OpenBSD 3.2 */
+ -1
+};
+
+static int
+ppcobsd_sigtramp_p (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ CORE_ADDR start_pc = (pc & ~(ppcobsd_page_size - 1));
+ const int *offset;
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (name)
+ return 0;
+
+ for (offset = ppcobsd_sigreturn_offset; *offset != -1; offset++)
+ {
+ char buf[2 * PPC_INSN_SIZE];
+ unsigned long insn;
+
+ if (!safe_frame_unwind_memory (next_frame, start_pc + *offset,
+ buf, sizeof buf))
+ continue;
+
+ /* Check for "li r0,SYS_sigreturn". */
+ insn = extract_unsigned_integer (buf, PPC_INSN_SIZE);
+ if (insn != 0x38000067)
+ continue;
+
+ /* Check for "sc". */
+ insn = extract_unsigned_integer (buf + PPC_INSN_SIZE, PPC_INSN_SIZE);
+ if (insn != 0x44000002)
+ continue;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct trad_frame_cache *
+ppcobsd_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ struct trad_frame_cache *cache;
+ CORE_ADDR addr, base, func;
+ char buf[PPC_INSN_SIZE];
+ unsigned long insn, sigcontext_offset;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = trad_frame_cache_zalloc (next_frame);
+ *this_cache = cache;
+
+ func = frame_pc_unwind (next_frame);
+ func &= ~(ppcobsd_page_size - 1);
+ if (!safe_frame_unwind_memory (next_frame, func, buf, sizeof buf))
+ return cache;
+
+ /* Calculate the offset where we can find `struct sigcontext'. We
+ base our calculation on the amount of stack space reserved by the
+ first instruction of the signal trampoline. */
+ insn = extract_unsigned_integer (buf, PPC_INSN_SIZE);
+ sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8;
+
+ base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+ addr = base + sigcontext_offset + 2 * tdep->wordsize;
+ for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
+ {
+ int regnum = i + tdep->ppc_gp0_regnum;
+ trad_frame_set_reg_addr (cache, regnum, addr);
+ }
+ trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
+ addr += tdep->wordsize;
+ trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
+ addr += tdep->wordsize;
+ trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
+ addr += tdep->wordsize;
+ trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
+ addr += tdep->wordsize;
+ trad_frame_set_reg_addr (cache, PC_REGNUM, addr); /* SRR0? */
+ addr += tdep->wordsize;
+
+ /* Construct the frame ID using the function start. */
+ trad_frame_set_id (cache, frame_id_build (base, func));
+
+ return cache;
+}
+
+static void
+ppcobsd_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ ppcobsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static void
+ppcobsd_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache, int regnum,
+ int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump,
+ char *valuep)
+{
+ struct trad_frame_cache *cache =
+ ppcobsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ trad_frame_get_register (cache, next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ ppcobsd_sigtramp_frame_this_id,
+ ppcobsd_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+ppcobsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ if (ppcobsd_sigtramp_p (next_frame))
+ return &ppcobsd_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+
static void
ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
+ /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
+
+ /* OpenBSD currently uses a broken GCC. */
+ set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
+
/* OpenBSD uses SVR4-style shared libraries. */
- set_gdbarch_in_solib_call_trampoline
- (gdbarch, generic_in_solib_call_trampoline);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
set_gdbarch_regset_from_core_section
(gdbarch, ppcobsd_regset_from_core_section);
+
+ frame_unwind_append_sniffer (gdbarch, ppcobsd_sigtramp_frame_sniffer);
}
@@ -177,4 +348,11 @@ _initialize_ppcobsd_tdep (void)
ppcobsd_reg_offsets.vscr_offset = 512;
ppcobsd_reg_offsets.vrsave_offset = 520;
}
+
+ if (ppcobsd_fpreg_offsets.fpscr_offset == 0)
+ {
+ /* Floating-point registers. */
+ ppcobsd_reg_offsets.f0_offset = 0;
+ ppcobsd_reg_offsets.fpscr_offset = 256;
+ }
}
diff --git a/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.h b/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.h
index 8f29aaa32ea..b1a7f8b7330 100644
--- a/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.h
+++ b/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.h
@@ -1,6 +1,6 @@
/* Target-dependent code for OpenBSD/powerpc.
- Copyright 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GDB.
@@ -16,8 +16,8 @@
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. */
#ifndef PPCOBSD_TDEP_H
#define PPCOBSD_TDEP_H
@@ -29,9 +29,11 @@ struct regcache;
/* Register offsets for OpenBSD/powerpc. */
extern struct ppc_reg_offsets ppcobsd_reg_offsets;
+extern struct ppc_reg_offsets ppcobsd_fpreg_offsets;
/* Register sets for OpenBSD/powerpc. */
extern struct regset ppcobsd_gregset;
+extern struct regset ppcobsd_fpregset;
/* Supply register REGNUM in the general-purpose register set REGSET