From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7886 invoked by alias); 26 Jan 2002 22:24:17 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 7774 invoked from network); 26 Jan 2002 22:24:10 -0000 Received: from unknown (HELO Cantor.suse.de) (213.95.15.193) by sources.redhat.com with SMTP; 26 Jan 2002 22:24:10 -0000 Received: from Hermes.suse.de (Hermes.suse.de [213.95.15.136]) by Cantor.suse.de (Postfix) with ESMTP id 59B311E7DE; Sat, 26 Jan 2002 23:24:09 +0100 (MET) X-Authentication-Warning: sykes.suse.de: schwab set sender to schwab@suse.de using -f To: Andrew Cagney Cc: gdb-patches@sources.redhat.com Subject: Re: Updates for m68k-linux target References: <3C5049BD.6070407@cygnus.com> X-Yow: TAILFINS!! ...click... From: Andreas Schwab Date: Sat, 26 Jan 2002 14:24:00 -0000 In-Reply-To: <3C5049BD.6070407@cygnus.com> (Andrew Cagney's message of "Thu, 24 Jan 2002 12:51:57 -0500") Message-ID: User-Agent: Gnus/5.090005 (Oort Gnus v0.05) Emacs/21.2.50 (ia64-suse-linux) MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-15 Content-Transfer-Encoding: quoted-printable X-SW-Source: 2002-01/txt/msg00739.txt.bz2 Andrew Cagney writes: |> > This patch updates the ptrace interface for the m68k-linux target. |> > Ok to check in? |>=20 |>=20 |> Just a few tweeks, otherwize yes. I wrote this stuff already long ago, but didn't find the time to submit, so it suffered from bit rot. While looking over it again, I noticed that the support for PTRACE_GETREGS wasn't actually complete. Here is a new version that finishes it and addresses your remarks. Committed. Andreas. 2002-01-26 Andreas Schwab * config/m68k/nm-linux.h (FETCH_INFERIOR_REGISTERS): Define. * m68klinux-nat.c: Update ptrace interface for fetching/storing registers and add support for PTRACE_GETREGS. Index: gdb/m68klinux-nat.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/m68klinux-nat.c,v retrieving revision 1.6 diff -u -a -u -r1.6 gdb/m68klinux-nat.c --- gdb/m68klinux-nat.c 2001/07/11 18:39:11 1.6 +++ gdb/m68klinux-nat.c 2002/01/26 22:20:25 @@ -32,11 +32,16 @@ #include #include #include +#include #include #include #include #include =20 +#ifdef HAVE_SYS_REG_H +#include +#endif + #include #include "gdb_stat.h" =20 @@ -57,6 +62,34 @@ 45, 46, 47 }; =20 +/* Which ptrace request retrieves which registers? + These apply to the corresponding SET requests as well. */ +#define NUM_GREGS (18) +#define MAX_NUM_REGS (NUM_GREGS + 11) + +int +getregs_supplies (int regno) +{ + return 0 <=3D regno && regno < NUM_GREGS; +} + +int +getfpregs_supplies (int regno) +{ + return FP0_REGNUM <=3D regno && regno <=3D FPI_REGNUM; +} + +/* Does the current host support the GETREGS request? */ +int have_ptrace_getregs =3D +#ifdef HAVE_PTRACE_GETREGS + 1 +#else + 0 +#endif +; + +=0C + /* BLOCKEND is the value of u.u_ar0, and points to the place where GS is stored. */ =20 @@ -65,7 +98,151 @@ { return (blockend + 4 * regmap[regnum]); } +=0C + +/* Fetching registers directly from the U area, one at a time. */ + +/* FIXME: This duplicates code from `inptrace.c'. The problem is that we + define FETCH_INFERIOR_REGISTERS since we want to use our own versions + of {fetch,store}_inferior_registers that use the GETREGS request. This + means that the code in `infptrace.c' is #ifdef'd out. But we need to + fall back on that code when GDB is running on top of a kernel that + doesn't support the GETREGS request. */ + +#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 + +/* Fetch one register. */ + +static void +fetch_register (int regno) +{ + /* This isn't really an address. But ptrace thinks of it as one. */ + CORE_ADDR regaddr; + char mess[128]; /* For messages */ + register int i; + unsigned int offset; /* Offset of registers within the u area. */ + char buf[MAX_REGISTER_RAW_SIZE]; + int tid; + + if (CANNOT_FETCH_REGISTER (regno)) + { + memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ + supply_register (regno, buf); + return; + } + + /* Overload thread id onto process id */ + if ((tid =3D TIDGET (inferior_ptid)) =3D=3D 0) + tid =3D PIDGET (inferior_ptid); /* no thread id, just use process id */ + + offset =3D U_REGS_OFFSET; + + regaddr =3D register_addr (regno, offset); + for (i =3D 0; i < REGISTER_RAW_SIZE (regno); i +=3D sizeof (PTRACE_XFER_= TYPE)) + { + errno =3D 0; + *(PTRACE_XFER_TYPE *) & buf[i] =3D ptrace (PT_READ_U, tid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr +=3D sizeof (PTRACE_XFER_TYPE); + if (errno !=3D 0) + { + sprintf (mess, "reading register %s (#%d)",=20 + REGISTER_NAME (regno), regno); + perror_with_name (mess); + } + } + supply_register (regno, buf); +} =20 +/* Fetch register values from the inferior. + If REGNO is negative, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +old_fetch_inferior_registers (int regno) +{ + if (regno >=3D 0) + { + fetch_register (regno); + } + else + { + for (regno =3D 0; regno < NUM_REGS; regno++) + { + 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; + char mess[128]; /* For messages */ + register int i; + unsigned int offset; /* Offset of registers within the u area. */ + int tid; + + if (CANNOT_STORE_REGISTER (regno)) + { + return; + } + + /* Overload thread id onto process id */ + if ((tid =3D TIDGET (inferior_ptid)) =3D=3D 0) + tid =3D PIDGET (inferior_ptid); /* no thread id, just use process id */ + + offset =3D U_REGS_OFFSET; + + regaddr =3D register_addr (regno, offset); + for (i =3D 0; i < REGISTER_RAW_SIZE (regno); i +=3D sizeof (PTRACE_XFER_= TYPE)) + { + errno =3D 0; + ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) & registers[REGISTER_BYTE (regno) + i]); + regaddr +=3D sizeof (PTRACE_XFER_TYPE); + if (errno !=3D 0) + { + sprintf (mess, "writing register %s (#%d)",=20 + REGISTER_NAME (regno), regno); + perror_with_name (mess); + } + } +} + +/* Store our register values back into the inferior. + If REGNO is negative, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +old_store_inferior_registers (int regno) +{ + if (regno >=3D 0) + { + store_register (regno); + } + else + { + for (regno =3D 0; regno < NUM_REGS; regno++) + { + store_register (regno); + } + } +} +=0C /* Given a pointer to a general register set in /proc format (elf_gregset_t *), unpack the register contents and supply them as gdb's idea of the current register values. */ @@ -87,32 +264,268 @@ void supply_gregset (elf_gregset_t *gregsetp) { + elf_greg_t *regp =3D (elf_greg_t *) gregsetp; int regi; =20 for (regi =3D D0_REGNUM; regi <=3D SP_REGNUM; regi++) - supply_register (regi, (char *) (*gregsetp + regmap[regi])); - supply_register (PS_REGNUM, (char *) (*gregsetp + PT_SR)); - supply_register (PC_REGNUM, (char *) (*gregsetp + PT_PC)); + supply_register (regi, (char *) ®p[regmap[regi]]); + supply_register (PS_REGNUM, (char *) ®p[PT_SR]); + supply_register (PC_REGNUM, (char *) ®p[PT_PC]); } + +/* Fill register REGNO (if it is a general-purpose register) in + *GREGSETPS with the value in GDB's register array. If REGNO is -1, + do this for all registers. */ +void +fill_gregset (elf_gregset_t *gregsetp, int regno) +{ + elf_greg_t *regp =3D (elf_greg_t *) gregsetp; + int i; + + for (i =3D 0; i < NUM_GREGS; i++) + if ((regno =3D=3D -1 || regno =3D=3D i)) + regcache_collect (i, regp + regmap[i]); +} + +#ifdef HAVE_PTRACE_GETREGS =20 -/* Given a pointer to a floating point register set in /proc format - (fpregset_t *), unpack the register contents and supply them as gdb's - idea of the current floating point register values. */ +/* Fetch all general-purpose registers from process/thread TID and + store their values in GDB's register array. */ + +static void +fetch_regs (int tid) +{ + elf_gregset_t regs; + + if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0) + { + if (errno =3D=3D EIO) + { + /* The kernel we're running on doesn't support the GETREGS + request. Reset `have_ptrace_getregs'. */ + have_ptrace_getregs =3D 0; + return; + } + + perror_with_name ("Couldn't get registers"); + } + + supply_gregset (®s); +} =20 +/* Store all valid general-purpose registers in GDB's register array + into the process/thread specified by TID. */ + +static void +store_regs (int tid, int regno) +{ + elf_gregset_t regs; + + if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0) + perror_with_name ("Couldn't get registers"); + + fill_gregset (®s, regno); + + if (ptrace (PTRACE_SETREGS, tid, 0, (int) ®s) < 0) + perror_with_name ("Couldn't write registers"); +} + +#else + +static void fetch_regs (int tid) {} +static void store_regs (int tid, int regno) {} + +#endif + +=0C +/* Transfering floating-point registers between GDB, inferiors and cores. = */ + +/* What is the address of fpN within the floating-point register set F? */ +#define FPREG_ADDR(f, n) ((char *) &(f)->fpregs[(n) * 3]) + +/* Fill GDB's register array with the floating-point register values in + *FPREGSETP. */ + void supply_fpregset (elf_fpregset_t *fpregsetp) { int regi; =20 for (regi =3D FP0_REGNUM; regi < FPC_REGNUM; regi++) - supply_register (regi, (char *) &fpregsetp->fpregs[(regi - FP0_REGNUM)= * 3]); + supply_register (regi, FPREG_ADDR (fpregsetp, regi - FP0_REGNUM)); supply_register (FPC_REGNUM, (char *) &fpregsetp->fpcntl[0]); supply_register (FPS_REGNUM, (char *) &fpregsetp->fpcntl[1]); supply_register (FPI_REGNUM, (char *) &fpregsetp->fpcntl[2]); } =20 +/* Fill register REGNO (if it is a floating-point register) in + *FPREGSETP with the value in GDB's register array. If REGNO is -1, + do this for all registers. */ + +void +fill_fpregset (elf_fpregset_t *fpregsetp, int regno) +{ + int i; + + /* Fill in the floating-point registers. */ + for (i =3D FP0_REGNUM; i < FP0_REGNUM + 8; i++) + if (regno =3D=3D -1 || regno =3D=3D i) + memcpy (FPREG_ADDR (fpregsetp, regno - FP0_REGNUM), + ®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE(regno)); + + /* Fill in the floating-point control registers. */ + for (i =3D FPC_REGNUM; i <=3D FPI_REGNUM; i++) + if (regno =3D=3D -1 || regno =3D=3D i) + fpregsetp->fpcntl[regno - FPC_REGNUM] + =3D *(int *) ®isters[REGISTER_BYTE (regno)]; +} + +#ifdef HAVE_PTRACE_GETREGS + +/* Fetch all floating-point registers from process/thread TID and store + thier values in GDB's register array. */ + +static void +fetch_fpregs (int tid) +{ + elf_fpregset_t fpregs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0) + perror_with_name ("Couldn't get floating point status"); + + supply_fpregset (&fpregs); +} + +/* Store all valid floating-point registers in GDB's register array + into the process/thread specified by TID. */ + +static void +store_fpregs (int tid, int regno) +{ + elf_fpregset_t fpregs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0) + perror_with_name ("Couldn't get floating point status"); + + fill_fpregset (&fpregs, regno); + + if (ptrace (PTRACE_SETFPREGS, tid, 0, (int) &fpregs) < 0) + perror_with_name ("Couldn't write floating point status"); +} + +#else + +static void fetch_fpregs (int tid) {} +static void store_fpregs (int tid, int regno) {} + +#endif + #endif +=0C +/* Transferring arbitrary registers between GDB and inferior. */ + +/* Fetch register REGNO from the child process. If REGNO is -1, do + this for all registers (including the floating point and SSE + registers). */ =20 +void +fetch_inferior_registers (int regno) +{ + int tid; + + /* Use the old method of peeking around in `struct user' if the + GETREGS request isn't available. */ + if (! have_ptrace_getregs) + { + old_fetch_inferior_registers (regno); + return; + } + + /* Linux LWP ID's are process ID's. */ + if ((tid =3D TIDGET (inferior_ptid)) =3D=3D 0) + tid =3D PIDGET (inferior_ptid); /* Not a threaded program. */ + + /* Use the PTRACE_GETFPXREGS request whenever possible, since it + transfers more registers in one system call, and we'll cache the + results. But remember that fetch_fpxregs can fail, and return + zero. */ + if (regno =3D=3D -1) + { + fetch_regs (tid); + + /* The call above might reset `have_ptrace_getregs'. */ + if (! have_ptrace_getregs) + { + old_fetch_inferior_registers (-1); + return; + } + + fetch_fpregs (tid); + return; + } + + if (getregs_supplies (regno)) + { + fetch_regs (tid); + return; + } + + if (getfpregs_supplies (regno)) + { + fetch_fpregs (tid); + return; + } + + internal_error (__FILE__, __LINE__, + "Got request for bad register number %d.", regno); +} + +/* Store register REGNO back into the child process. If REGNO is -1, + do this for all registers (including the floating point and SSE + registers). */ +void +store_inferior_registers (int regno) +{ + int tid; + + /* Use the old method of poking around in `struct user' if the + SETREGS request isn't available. */ + if (! have_ptrace_getregs) + { + old_store_inferior_registers (regno); + return; + } + + /* Linux LWP ID's are process ID's. */ + if ((tid =3D TIDGET (inferior_ptid)) =3D=3D 0) + tid =3D PIDGET (inferior_ptid); /* Not a threaded program. */ + + /* Use the PTRACE_SETFPREGS requests whenever possible, since it + transfers more registers in one system call. But remember that + store_fpregs can fail, and return zero. */ + if (regno =3D=3D -1) + { + store_regs (tid, regno); + store_fpregs (tid, regno); + return; + } + + if (getregs_supplies (regno)) + { + store_regs (tid, regno); + return; + } + + if (getfpregs_supplies (regno)) + { + store_fpregs (tid, regno); + return; + } + + internal_error (__FILE__, __LINE__, + "Got request to store bad register number %d.", regno); +} =0C /* Interpreting register set info found in core files. */ =20 Index: gdb/config/m68k/nm-linux.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/config/m68k/nm-linux.h,v retrieving revision 1.3 diff -u -a -r1.3 gdb/config/m68k/nm-linux.h --- gdb/config/m68k/nm-linux.h 2001/03/06 08:21:30 1.3 +++ gdb/config/m68k/nm-linux.h 2002/01/26 19:23:31 @@ -35,4 +35,7 @@ =20 extern int m68k_linux_register_u_addr (int, int); =20 +/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. = */ +#define FETCH_INFERIOR_REGISTERS + #endif /* #ifndef NM_LINUX_H */ --=20 Andreas Schwab, SuSE Labs, schwab@suse.de SuSE GmbH, Deutschherrnstr. 15-19, D-90429 N=FCrnberg Key fingerprint =3D 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."