diff options
author | Elena Zannoni <ezannoni@kwikemart.cygnus.com> | 2001-12-20 23:31:27 +0000 |
---|---|---|
committer | Elena Zannoni <ezannoni@kwikemart.cygnus.com> | 2001-12-20 23:31:27 +0000 |
commit | 3ae71a67b655e1a55f4fd534e71bcfd8d45215b9 (patch) | |
tree | 6275bb4cb75efb7967c7ad1aa7c64283013a3c19 /gdb/ppc-linux-nat.c | |
parent | df8bde479459203934655336e44b4122454365bf (diff) | |
download | gdb-3ae71a67b655e1a55f4fd534e71bcfd8d45215b9.tar.gz |
2001-12-20 Elena Zannoni <ezannoni@redhat.com>
* ppc-linux-nat.c (ppc_ptrace_cannot_fetch_store_register):
New function.
(fetch_register): New function.
(fetch_ppc_registers): New function.
(fetch_inferior_registers): New function.
(store_register): New function.
(store_ppc_registers): New function.
(store_inferior_registers): New function.
(ppc_register_u_addr): Eliminate ustart parameter and its
uses. Make static.
(PT_READ_U, PT_WRITE_U, PTRACE_XFER_TYPE): Define if needed.
Include sys/ptrace.h.
* config/powerpc/nm-linux.h (FETCH_INFERIOR_REGISTERS): Define.
(U_REGS_OFFSET, REGISTER_U_ADDR): Delete.
* config/powerpc/linux.mh (NATDEPFILES): Delete core-aout.o.
Diffstat (limited to 'gdb/ppc-linux-nat.c')
-rw-r--r-- | gdb/ppc-linux-nat.c | 158 |
1 files changed, 146 insertions, 12 deletions
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index 1d57a9a13e6..a967f486b66 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -32,11 +32,24 @@ #include <sys/wait.h> #include <fcntl.h> #include <sys/procfs.h> +#include <sys/ptrace.h> /* Prototypes for supply_gregset etc. */ #include "gregset.h" #include "ppc-tdep.h" +#ifndef PT_READ_U +#define PT_READ_U PTRACE_PEEKUSR +#endif +#ifndef PT_WRITE_U +#define PT_WRITE_U PTRACE_POKEUSR +#endif + +/* Default the type of the ptrace transfer to int. */ +#ifndef PTRACE_XFER_TYPE +#define PTRACE_XFER_TYPE int +#endif + int kernel_u_size (void) { @@ -56,39 +69,161 @@ PT_FPR0 + 48, PT_FPR0 + 50, PT_FPR0 + 52, PT_FPR0 + 54, PT_FPR0 + 56, PT_FPR0 + PT_NIP, PT_MSR, PT_CCR, PT_LNK, PT_CTR, PT_XER, PT_MQ */ /* *INDENT_ON * */ -int -ppc_register_u_addr (int ustart, int regno) +static int +ppc_register_u_addr (int regno) { int u_addr = -1; /* General purpose registers occupy 1 slot each in the buffer */ if (regno >= gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum && regno <= gdbarch_tdep (current_gdbarch)->ppc_gplast_regnum ) - u_addr = (ustart + (PT_R0 + regno) * 4); + u_addr = ((PT_R0 + regno) * 4); /* Floating point regs: 2 slots each */ if (regno >= FP0_REGNUM && regno <= FPLAST_REGNUM) - u_addr = (ustart + (PT_FPR0 + (regno - FP0_REGNUM) * 2) * 4); + u_addr = ((PT_FPR0 + (regno - FP0_REGNUM) * 2) * 4); /* UISA special purpose registers: 1 slot each */ if (regno == PC_REGNUM) - u_addr = ustart + PT_NIP * 4; + u_addr = PT_NIP * 4; if (regno == gdbarch_tdep (current_gdbarch)->ppc_lr_regnum) - u_addr = ustart + PT_LNK * 4; + u_addr = PT_LNK * 4; if (regno == gdbarch_tdep (current_gdbarch)->ppc_cr_regnum) - u_addr = ustart + PT_CCR * 4; + u_addr = PT_CCR * 4; if (regno == gdbarch_tdep (current_gdbarch)->ppc_xer_regnum) - u_addr = ustart + PT_XER * 4; + u_addr = PT_XER * 4; if (regno == gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum) - u_addr = ustart + PT_CTR * 4; + u_addr = PT_CTR * 4; if (regno == gdbarch_tdep (current_gdbarch)->ppc_mq_regnum) - u_addr = ustart + PT_MQ * 4; + u_addr = PT_MQ * 4; if (regno == gdbarch_tdep (current_gdbarch)->ppc_ps_regnum) - u_addr = ustart + PT_MSR * 4; + u_addr = PT_MSR * 4; return u_addr; } +static int +ppc_ptrace_cannot_fetch_store_register (int regno) +{ + return (ppc_register_u_addr (regno) == -1); +} + +static void +fetch_register (int regno) +{ + /* This isn't really an address. But ptrace thinks of it as one. */ + char mess[128]; /* For messages */ + register int i; + unsigned int offset; /* Offset of registers within the u area. */ + char *buf = alloca (MAX_REGISTER_RAW_SIZE); + int tid; + CORE_ADDR regaddr = ppc_register_u_addr (regno); + + if (regaddr == -1) + { + memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ + supply_register (regno, buf); + return; + } + + /* Overload thread id onto process id */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* no thread id, just use process id */ + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", + REGISTER_NAME (regno), regno); + perror_with_name (mess); + } + } + supply_register (regno, buf); +} + +static void +fetch_ppc_registers (void) +{ + int i; + int last_register = gdbarch_tdep (current_gdbarch)->ppc_mq_regnum; + + for (i = 0; i <= last_register; i++) + fetch_register (i); +} + +/* Fetch registers from the child process. Fetch all registers if + regno == -1, otherwise fetch all general registers or all floating + point registers depending upon the value of regno. */ +void +fetch_inferior_registers (int regno) +{ + if (regno == -1) + fetch_ppc_registers (); + else + fetch_register (regno); +} + +/* Store one register. */ +static void +store_register (int regno) +{ + /* 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; + unsigned int offset; /* Offset of registers within the u area. */ + int tid; + char *buf = alloca (MAX_REGISTER_RAW_SIZE); + + if (regaddr == -1) + { + return; + } + + /* Overload thread id onto process id */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* no thread id, just use process id */ + + regcache_collect (regno, buf); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) & buf[i]); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + sprintf (mess, "writing register %s (#%d)", + REGISTER_NAME (regno), regno); + perror_with_name (mess); + } + } +} + +static void +store_ppc_registers (void) +{ + int i; + int last_register = gdbarch_tdep (current_gdbarch)->ppc_mq_regnum; + + for (i = 0; i <= last_register; i++) + store_register (i); +} + +void +store_inferior_registers (int regno) +{ + if (regno >= 0) + store_register (regno); + else + store_ppc_registers (); +} + void supply_gregset (gdb_gregset_t *gregsetp) { @@ -111,7 +246,6 @@ supply_gregset (gdb_gregset_t *gregsetp) (char *) (regp + PT_MQ)); supply_register (gdbarch_tdep (current_gdbarch)->ppc_ps_regnum, (char *) (regp + PT_MSR)); - } void |