diff options
-rw-r--r-- | gnu/usr.bin/binutils/gdb/ppc-tdep.h | 308 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/gdb/ppcobsd-nat.c | 92 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/gdb/ppcobsd-tdep.c | 192 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/gdb/ppcobsd-tdep.h | 8 |
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) ®s, 0) == -1) perror_with_name (_("Couldn't get registers")); - ppcobsd_supply_gregset (&ppcobsd_gregset, current_regcache, -1, - ®s, sizeof regs); + ppc_supply_gregset (&ppcobsd_gregset, current_regcache, -1, + ®s, sizeof regs); +#ifndef PT_GETFPREGS + ppc_supply_fpregset (&ppcobsd_gregset, current_regcache, -1, + ®s, 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) ®s, 0) == -1) perror_with_name (_("Couldn't get registers")); - ppcobsd_collect_gregset (&ppcobsd_gregset, current_regcache, - regnum, ®s, sizeof regs); + ppc_collect_gregset (&ppcobsd_gregset, current_regcache, + regnum, ®s, sizeof regs); +#ifndef PT_GETFPREGS + ppc_collect_fpregset (&ppcobsd_gregset, current_regcache, + regnum, ®s, sizeof regs); +#endif if (ptrace (PT_SETREGS, PIDGET (inferior_ptid), (PTRACE_TYPE_ARG3) ®s, 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 |