/* PPC GNU/Linux native support.
- Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002
- Free Software Foundation, Inc.
+
+ Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
+ 2003 Free Software Foundation, Inc.
This file is part of GDB.
#include <signal.h>
#include <sys/user.h>
#include <sys/ioctl.h>
-#include <sys/wait.h>
+#include "gdb_wait.h"
#include <fcntl.h>
#include <sys/procfs.h>
#include <sys/ptrace.h>
{
int u_addr = -1;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
+ interface, and not the wordsize of the program's ABI. */
+ int wordsize = sizeof (PTRACE_XFER_TYPE);
/* General purpose registers occupy 1 slot each in the buffer */
if (regno >= tdep->ppc_gp0_regnum && regno <= tdep->ppc_gplast_regnum )
- u_addr = ((PT_R0 + regno) * 4);
+ u_addr = ((PT_R0 + regno) * wordsize);
- /* Floating point regs: 2 slots each */
+ /* Floating point regs: eight bytes each in both 32- and 64-bit
+ ptrace interfaces. Thus, two slots each in 32-bit interface, one
+ slot each in 64-bit interface. */
if (regno >= FP0_REGNUM && regno <= FPLAST_REGNUM)
- u_addr = ((PT_FPR0 + (regno - FP0_REGNUM) * 2) * 4);
+ u_addr = (PT_FPR0 * wordsize) + ((regno - FP0_REGNUM) * 8);
/* UISA special purpose registers: 1 slot each */
if (regno == PC_REGNUM)
- u_addr = PT_NIP * 4;
+ u_addr = PT_NIP * wordsize;
if (regno == tdep->ppc_lr_regnum)
- u_addr = PT_LNK * 4;
+ u_addr = PT_LNK * wordsize;
if (regno == tdep->ppc_cr_regnum)
- u_addr = PT_CCR * 4;
+ u_addr = PT_CCR * wordsize;
if (regno == tdep->ppc_xer_regnum)
- u_addr = PT_XER * 4;
+ u_addr = PT_XER * wordsize;
if (regno == tdep->ppc_ctr_regnum)
- u_addr = PT_CTR * 4;
+ u_addr = PT_CTR * wordsize;
+#ifdef PT_MQ
if (regno == tdep->ppc_mq_regnum)
- u_addr = PT_MQ * 4;
+ u_addr = PT_MQ * wordsize;
+#endif
if (regno == tdep->ppc_ps_regnum)
- u_addr = PT_MSR * 4;
+ u_addr = PT_MSR * wordsize;
if (regno == tdep->ppc_fpscr_regnum)
- u_addr = PT_FPSCR * 4;
+ u_addr = PT_FPSCR * wordsize;
return u_addr;
}
-static int
-ppc_ptrace_cannot_fetch_store_register (int regno)
-{
- return (ppc_register_u_addr (regno) == -1);
-}
-
/* The Linux kernel ptrace interface for AltiVec registers uses the
registers set mechanism, as opposed to the interface for all the
other registers, that stores/fetches each register individually. */
int offset = 0;
gdb_vrregset_t regs;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
+ int vrregsize = DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
if (ret < 0)
vector. VRSAVE is at the end of the array in a 4 bytes slot, so
there is no need to define an offset for it. */
if (regno == (tdep->ppc_vrsave_regnum - 1))
- offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
+ offset = vrregsize - DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
supply_register (regno,
regs + (regno - tdep->ppc_vr0_regnum) * vrregsize + offset);
{
/* This isn't really an address. But ptrace thinks of it as one. */
char mess[128]; /* For messages */
- register int i;
+ int i;
unsigned int offset; /* Offset of registers within the u area. */
- char *buf = alloca (MAX_REGISTER_RAW_SIZE);
+ char buf[MAX_REGISTER_SIZE];
CORE_ADDR regaddr = ppc_register_u_addr (regno);
if (altivec_register_p (regno))
if (regaddr == -1)
{
- memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */
+ memset (buf, '\0', DEPRECATED_REGISTER_RAW_SIZE (regno)); /* Supply zeroes */
supply_register (regno, buf);
return;
}
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+ /* Read the raw register using PTRACE_XFER_TYPE sized chunks. On a
+ 32-bit platform, 64-bit floating-point registers will require two
+ transfers. */
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
{
errno = 0;
*(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
perror_with_name (mess);
}
}
- supply_register (regno, buf);
+
+ /* Now supply the register. Be careful to map between ptrace's and
+ the current_regcache's idea of the current wordsize. */
+ if ((regno >= FP0_REGNUM && regno < FP0_REGNUM +32)
+ || gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
+ /* FPs are always 64 bits. Little endian values are always found
+ at the left-hand end of the register. */
+ regcache_raw_supply (current_regcache, regno, buf);
+ else
+ /* Big endian register, need to fetch the right-hand end. */
+ regcache_raw_supply (current_regcache, regno,
+ (buf + sizeof (PTRACE_XFER_TYPE)
+ - register_size (current_gdbarch, regno)));
}
static void
int i;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
- int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
- int offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
+ int vrregsize = DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
+ int offset = vrregsize - DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
for (i = 0; i < num_of_vrregs; i++)
{
int offset = 0;
gdb_vrregset_t regs;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
+ int vrregsize = DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
if (ret < 0)
/* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes
long on the hardware. */
if (regno == (tdep->ppc_vrsave_regnum - 1))
- offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
+ offset = vrregsize - DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
regcache_collect (regno,
regs + (regno - tdep->ppc_vr0_regnum) * vrregsize + offset);
/* This isn't really an address. But ptrace thinks of it as one. */
CORE_ADDR regaddr = ppc_register_u_addr (regno);
char mess[128]; /* For messages */
- register int i;
+ int i;
unsigned int offset; /* Offset of registers within the u area. */
- char *buf = alloca (MAX_REGISTER_RAW_SIZE);
+ char buf[MAX_REGISTER_SIZE];
if (altivec_register_p (regno))
{
if (regaddr == -1)
return;
- regcache_collect (regno, buf);
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+ /* First collect the register value from the regcache. Be careful
+ to to convert the regcache's wordsize into ptrace's wordsize. */
+ memset (buf, 0, sizeof buf);
+ if ((regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+ || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ /* Floats are always 64-bit. Little endian registers are always
+ at the left-hand end of the register cache. */
+ regcache_raw_collect (current_regcache, regno, buf);
+ else
+ /* Big-endian registers belong at the right-hand end of the
+ buffer. */
+ regcache_raw_collect (current_regcache, regno,
+ (buf + sizeof (PTRACE_XFER_TYPE)
+ - register_size (current_gdbarch, regno)));
+
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
{
errno = 0;
ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
int i;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
- int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
- int offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
+ int vrregsize = DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum);
+ int offset = vrregsize - DEPRECATED_REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum);
for (i = 0; i < num_of_vrregs; i++)
{
int ret;
gdb_vrregset_t regs;
- ret = ptrace (PTRACE_GETVRREGS, tid, 0, (int) ®s);
+ ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
if (ret < 0)
{
if (errno == EIO)
fill_vrregset (®s);
- if (ptrace (PTRACE_SETVRREGS, tid, 0, (int) ®s) < 0)
+ if (ptrace (PTRACE_SETVRREGS, tid, 0, ®s) < 0)
perror_with_name ("Couldn't write AltiVec registers");
}
void
supply_gregset (gdb_gregset_t *gregsetp)
{
- ppc_linux_supply_gregset ((char *) gregsetp);
+ /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
+ interface, and not the wordsize of the program's ABI. */
+ int wordsize = sizeof (PTRACE_XFER_TYPE);
+ ppc_linux_supply_gregset (current_regcache, -1, gregsetp,
+ sizeof (gdb_gregset_t), wordsize);
+}
+
+static void
+right_fill_reg (int regnum, void *reg)
+{
+ /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
+ interface, and not the wordsize of the program's ABI. */
+ int wordsize = sizeof (PTRACE_XFER_TYPE);
+ /* Right fill the register. */
+ regcache_raw_collect (current_regcache, regnum,
+ ((bfd_byte *) reg
+ + wordsize
+ - register_size (current_gdbarch, regnum)));
}
void
int regi;
elf_greg_t *regp = (elf_greg_t *) gregsetp;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ const int elf_ngreg = 48;
+
+
+ /* Start with zeros. */
+ memset (regp, 0, elf_ngreg * sizeof (*regp));
for (regi = 0; regi < 32; regi++)
{
if ((regno == -1) || regno == regi)
- regcache_collect (regi, regp + PT_R0 + regi);
+ right_fill_reg (regi, (regp + PT_R0 + regi));
}
if ((regno == -1) || regno == PC_REGNUM)
- regcache_collect (PC_REGNUM, regp + PT_NIP);
+ right_fill_reg (PC_REGNUM, regp + PT_NIP);
if ((regno == -1) || regno == tdep->ppc_lr_regnum)
- regcache_collect (tdep->ppc_lr_regnum, regp + PT_LNK);
+ right_fill_reg (tdep->ppc_lr_regnum, regp + PT_LNK);
if ((regno == -1) || regno == tdep->ppc_cr_regnum)
regcache_collect (tdep->ppc_cr_regnum, regp + PT_CCR);
if ((regno == -1) || regno == tdep->ppc_xer_regnum)
regcache_collect (tdep->ppc_xer_regnum, regp + PT_XER);
if ((regno == -1) || regno == tdep->ppc_ctr_regnum)
- regcache_collect (tdep->ppc_ctr_regnum, regp + PT_CTR);
+ right_fill_reg (tdep->ppc_ctr_regnum, regp + PT_CTR);
+#ifdef PT_MQ
if (((regno == -1) || regno == tdep->ppc_mq_regnum)
&& (tdep->ppc_mq_regnum != -1))
- regcache_collect (tdep->ppc_mq_regnum, regp + PT_MQ);
+ right_fill_reg (tdep->ppc_mq_regnum, regp + PT_MQ);
+#endif
if ((regno == -1) || regno == tdep->ppc_ps_regnum)
- regcache_collect (tdep->ppc_ps_regnum, regp + PT_MSR);
+ right_fill_reg (tdep->ppc_ps_regnum, regp + PT_MSR);
}
void
supply_fpregset (gdb_fpregset_t * fpregsetp)
{
- ppc_linux_supply_fpregset ((char *) fpregsetp);
+ ppc_linux_supply_fpregset (NULL, current_regcache, -1, fpregsetp,
+ sizeof (gdb_fpregset_t));
}
/* Given a pointer to a floating point register set in /proc format
{
int regi;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ bfd_byte *fpp = (void *) fpregsetp;
for (regi = 0; regi < 32; regi++)
{
if ((regno == -1) || (regno == FP0_REGNUM + regi))
- regcache_collect (FP0_REGNUM + regi, (char *) (*fpregsetp + regi));
+ regcache_collect (FP0_REGNUM + regi, fpp + 8 * regi);
}
if ((regno == -1) || regno == tdep->ppc_fpscr_regnum)
- regcache_collect (tdep->ppc_fpscr_regnum, (char *) (*fpregsetp + regi));
+ right_fill_reg (tdep->ppc_fpscr_regnum, (fpp + 8 * 32));
}