From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11093 invoked by alias); 30 Mar 2005 15:01:54 -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 10819 invoked from network); 30 Mar 2005 15:01:20 -0000 Received: from unknown (HELO nevyn.them.org) (66.93.172.17) by sourceware.org with SMTP; 30 Mar 2005 15:01:20 -0000 Received: from drow by nevyn.them.org with local (Exim 4.50 #1 (Debian)) id 1DGeiE-0001r0-05; Wed, 30 Mar 2005 10:02:30 -0500 Date: Wed, 30 Mar 2005 15:01:00 -0000 From: Daniel Jacobowitz To: Paul Brook Cc: gdb-patches@sources.redhat.com Subject: Re: [csl-arm] VFP and iWMMXt support Message-ID: <20050330150229.GA7075@nevyn.them.org> Mail-Followup-To: Paul Brook , gdb-patches@sources.redhat.com References: <200503290351.51527.paul@codesourcery.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <200503290351.51527.paul@codesourcery.com> User-Agent: Mutt/1.5.6+20040907i X-SW-Source: 2005-03/txt/msg00387.txt.bz2 On Tue, Mar 29, 2005 at 03:51:51AM +0100, Paul Brook wrote: > I've applied the attached patch to the csl-arm-20050325-branch. > > It adds support for the iWMMXt and VFP Arm coprocessors. > This includes a new extension to the remote protocol to handle optional > register sets. The extension may need some more work before it's ready for > mainline. > > Tested with cross to arm-none-eabi. This patch, also applied to the branch, adds native support for iWMMXt registers on arm-linux. It requires a brand new kernel. I didn't do VFP, because no one's implemented the necessary kernel primitives yet. The principle is the same as in the previous patch. Before this moves to mainline I intend to finish converting Linux to inf-ptrace, and then NATIVE_XFER_AVAILABLE_REGISTERS will not be necessary. -- Daniel Jacobowitz CodeSourcery, LLC 2005-03-30 Daniel Jacobowitz * Makefile.in (arm-linux-nat.o): Update dependencies. * arm-linux-nat.c: Include "gdb_assert.h". (PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS): Define. (arm_linux_has_wmmx_registers): New flag. (GET_THREAD_ID): Remove stray punctuation. (IWMMXT_REGS_SIZE): Define. (fetch_wmmx_regs, store_wmmx_regs): New functions. (fetch_inferior_registers, store_inferior_registers): Call them. (arm_linux_available_registers): New function. * inftarg.c (child_xfer_partial): Handle TARGET_OBJECT_AVAILABLE_REGISTERS. * config/arm/nm-linux.h (arm_linux_available_registers): Add prototype. (NATIVE_XFER_AVAILABLE_REGISTERS): Define. 2005-03-30 Daniel Jacobowitz * linux-arm-low.c (arm_fill_wmmxregset, arm_store_wmmxregset): Remove stray text. (arm_available_registers): Remove debugging output. Use hex. * regcache.c (num_registers): Make global. * server.c (handle_p_packet, handle_P_packet): Check the value of regnum. Index: gdb/Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/Makefile.in,v retrieving revision 1.707.2.4 diff -u -p -r1.707.2.4 Makefile.in --- gdb/Makefile.in 29 Mar 2005 02:52:04 -0000 1.707.2.4 +++ gdb/Makefile.in 30 Mar 2005 14:53:20 -0000 @@ -1732,7 +1732,7 @@ arch-utils.o: arch-utils.c $(defs_h) $(a $(floatformat_h) arm-linux-nat.o: arm-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \ $(gdb_string_h) $(regcache_h) $(arm_tdep_h) $(gregset_h)\ - $(gdb_proc_service_h) + $(gdb_proc_service_h) $(gdb_assert_h) arm-linux-tdep.o: arm-linux-tdep.c $(defs_h) $(target_h) $(value_h) \ $(gdbtypes_h) $(floatformat_h) $(gdbcore_h) $(frame_h) $(regcache_h) \ $(doublest_h) $(solib_svr4_h) $(osabi_h) $(arm_tdep_h) \ Index: gdb/arm-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v retrieving revision 1.22.2.3 diff -u -p -r1.22.2.3 arm-linux-nat.c --- gdb/arm-linux-nat.c 29 Mar 2005 02:52:04 -0000 1.22.2.3 +++ gdb/arm-linux-nat.c 30 Mar 2005 14:53:20 -0000 @@ -23,6 +23,7 @@ #include "gdbcore.h" #include "gdb_string.h" #include "regcache.h" +#include "gdb_assert.h" #include "arm-tdep.h" @@ -41,6 +42,13 @@ #define PTRACE_GET_THREAD_AREA 22 #endif +#ifndef PTRACE_GETWMMXREGS +#define PTRACE_GETWMMXREGS 18 +#define PTRACE_SETWMMXREGS 19 +#endif + +static int arm_linux_has_wmmx_registers = 1; + extern int arm_apcs_32; #define typeNone 0x00 @@ -99,7 +107,7 @@ get_thread_id (ptid_t ptid) tid = PIDGET (ptid); return tid; } -#define GET_THREAD_ID(PTID) get_thread_id ((PTID)); +#define GET_THREAD_ID(PTID) get_thread_id (PTID) static void fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11) @@ -550,6 +558,97 @@ store_regs (void) } } +/* Fetch all WMMX registers of the process and store into + regcache. */ + +#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4) + +static void +fetch_wmmx_regs (void) +{ + char regbuf[IWMMXT_REGS_SIZE]; + int ret, regno, tid, first; + + /* Get the thread id for the ptrace call. */ + tid = GET_THREAD_ID (inferior_ptid); + + ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf); + if (ret < 0) + { + warning (_("Unable to fetch WMMX registers.")); + return; + } + + first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum; + + for (regno = 0; regno < NUM_IWMMXT_COP0REGS; regno++) + regcache_raw_supply (current_regcache, first + regno, + ®buf[regno * 8]); + + first += NUM_IWMMXT_COP0REGS; + + for (regno = 0; regno < 2; regno++) + regcache_raw_supply (current_regcache, first + regno, NULL); + + for (regno = 2; regno < 4; regno++) + regcache_raw_supply (current_regcache, first + regno, + ®buf[16 * 8 + (regno - 2) * 4]); + + for (regno = 4; regno < 8; regno++) + regcache_raw_supply (current_regcache, first + regno, NULL); + + for (regno = 8; regno < 12; regno++) + regcache_raw_supply (current_regcache, first + regno, + ®buf[16 * 8 + 2 * 4 + (regno - 8) * 4]); + + for (regno = 12; regno < 16; regno++) + regcache_raw_supply (current_regcache, first + regno, NULL); +} + +static void +store_wmmx_regs (void) +{ + char regbuf[IWMMXT_REGS_SIZE]; + int ret, regno, tid, first; + + /* Get the thread id for the ptrace call. */ + tid = GET_THREAD_ID (inferior_ptid); + + ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf); + if (ret < 0) + { + warning (_("Unable to fetch WMMX registers.")); + return; + } + + first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum; + + for (regno = 0; regno < NUM_IWMMXT_COP0REGS; regno++) + if (register_cached (first + regno)) + regcache_raw_collect (current_regcache, first + regno, + ®buf[regno * 8]); + + first += 18; + for (regno = 0; regno < 2; regno++) + if (register_cached (first + regno)) + regcache_raw_collect (current_regcache, first + regno, + ®buf[16 * 8 + regno * 4]); + + first += 6; + for (regno = 0; regno < 4; regno++) + if (register_cached (first + regno)) + regcache_raw_collect (current_regcache, first + regno, + ®buf[16 * 8 + 2 * 4 + regno * 4]); + + ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf); + + if (ret < 0) + { + warning (_("Unable to store WMMX registers.")); + return; + } +} + /* 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. */ @@ -561,14 +660,21 @@ fetch_inferior_registers (int regno) { fetch_regs (); fetch_fpa_regs (); + if (arm_linux_has_wmmx_registers) + fetch_wmmx_regs (); } else { - if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) + if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM) fetch_register (regno); - - if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM) + else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM) fetch_fpa_register (regno); + else if (arm_linux_has_wmmx_registers) + { + int first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum; + if (regno >= first && regno < first + NUM_IWMMXT_REGS) + fetch_wmmx_regs (); + } } } @@ -583,14 +689,21 @@ store_inferior_registers (int regno) { store_regs (); store_fpa_regs (); + if (arm_linux_has_wmmx_registers) + store_wmmx_regs (); } else { - if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM)) + if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM) store_register (regno); - - if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM)) - store_fpa_register (regno); + else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM)) + store_fpa_register (regno); + else if (arm_linux_has_wmmx_registers) + { + int first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum; + if (regno >= first && regno < first + NUM_IWMMXT_REGS) + store_wmmx_regs (); + } } } @@ -740,6 +853,50 @@ get_linux_version (unsigned int *vmajor, return ((*vmajor << 16) | (*vminor << 8) | *vrelease); } +LONGEST +arm_linux_available_registers (struct target_ops *ops, + int /* enum target_object */ object, + const char *annex, + void *readbuf, + const void *writebuf, + ULONGEST offset, + LONGEST len) +{ + char *result = NULL; + int total_len; + + gdb_assert (object == TARGET_OBJECT_AVAILABLE_REGISTERS); + gdb_assert (readbuf && !writebuf); + + if (arm_linux_has_wmmx_registers) + { + int ret; + char regbuf[IWMMXT_REGS_SIZE]; + + ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid), 0, + regbuf); + if (ret < 0) + /* Should we be checking the error code? */ + arm_linux_has_wmmx_registers = 0; + } + + if (arm_linux_has_wmmx_registers) + result = "iwmmxt"; + + if (result == NULL) + return 0; + + total_len = strlen (result); + if (total_len > offset) + { + int bytes_read = min (total_len - offset, len); + memcpy (readbuf, result + offset, bytes_read); + return bytes_read; + } + + return 0; +} + void _initialize_arm_linux_nat (void) { Index: gdb/inftarg.c =================================================================== RCS file: /cvs/src/src/gdb/inftarg.c,v retrieving revision 1.41 diff -u -p -r1.41 inftarg.c --- gdb/inftarg.c 12 Feb 2005 00:39:19 -0000 1.41 +++ gdb/inftarg.c 30 Mar 2005 14:53:20 -0000 @@ -559,6 +559,13 @@ child_xfer_partial (struct target_ops *o return NATIVE_XFER_AUXV (ops, object, annex, readbuf, writebuf, offset, len); + case TARGET_OBJECT_AVAILABLE_REGISTERS: +#ifndef NATIVE_XFER_AVAILABLE_REGISTERS +#define NATIVE_XFER_AVAILABLE_REGISTERS(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1) +#endif + return NATIVE_XFER_AVAILABLE_REGISTERS (ops, object, annex, readbuf, + writebuf, offset, len); + default: return -1; } Index: gdb/config/arm/nm-linux.h =================================================================== RCS file: /cvs/src/src/gdb/config/arm/nm-linux.h,v retrieving revision 1.10 diff -u -p -r1.10 nm-linux.h --- gdb/config/arm/nm-linux.h 29 Jul 2004 20:22:49 -0000 1.10 +++ gdb/config/arm/nm-linux.h 30 Mar 2005 14:53:20 -0000 @@ -38,4 +38,20 @@ extern int kernel_u_size (void); /* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ #define FETCH_INFERIOR_REGISTERS +/* This function is called like a to_xfer_partial hook, + but must be called with TARGET_OBJECT_AVAILABLE_REGISTERS. */ + +struct target_ops; + +extern LONGEST arm_linux_available_registers + (struct target_ops *ops, + int /* enum target_object */ object, + const char *annex, + void *readbuf, + const void *writebuf, + ULONGEST offset, + LONGEST len); + +#define NATIVE_XFER_AVAILABLE_REGISTERS arm_linux_available_registers + #endif /* NM_ARMLINUX_H */ Index: gdb/gdbserver/linux-arm-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-arm-low.c,v retrieving revision 1.7.14.2 diff -u -p -r1.7.14.2 linux-arm-low.c --- gdb/gdbserver/linux-arm-low.c 29 Mar 2005 02:52:06 -0000 1.7.14.2 +++ gdb/gdbserver/linux-arm-low.c 30 Mar 2005 14:53:20 -0000 @@ -155,11 +155,6 @@ arm_fill_wmmxregset (void *buf) for (i = 0; i < 4; i++) collect_register (arm_num_regs + i + 16 + 8, ((char *) buf) + 16 * 8 + 8 + i * 4); - - ((int*)buf)[0], - ((int*)buf)[1], - ((int*)buf)[2], - ((int*)buf)[3]); } static void @@ -167,10 +162,6 @@ arm_store_wmmxregset (const void *buf) { int i; - ((int*)buf)[0], - ((int*)buf)[1], - ((int*)buf)[2], - ((int*)buf)[3]); for (i = 0; i < 16; i++) supply_register (arm_num_regs + i, ((char *) buf) + i * 8); @@ -186,11 +177,10 @@ arm_available_registers (void) { char buf[64]; - printf ("use_regsets %d target_regsets %d\n", use_regsets_p, target_regsets[1].size); if (use_regsets_p && target_regsets[1].size > 0) { int wr0 = find_regno ("wr0"); - sprintf (buf, "iwmmxt:%d", wr0); + sprintf (buf, "iwmmxt:%x", wr0); return strdup (buf); } Index: gdb/gdbserver/regcache.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/regcache.c,v retrieving revision 1.7.18.1 diff -u -p -r1.7.18.1 regcache.c --- gdb/gdbserver/regcache.c 29 Mar 2005 02:52:06 -0000 1.7.18.1 +++ gdb/gdbserver/regcache.c 30 Mar 2005 14:53:20 -0000 @@ -38,7 +38,7 @@ struct inferior_regcache_data static int register_bytes, g_register_bytes; static struct reg *reg_defs; -static int num_registers; +int num_registers; const char **gdbserver_expedite_regs; Index: gdb/gdbserver/server.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/server.c,v retrieving revision 1.23.2.1 diff -u -p -r1.23.2.1 server.c --- gdb/gdbserver/server.c 29 Mar 2005 02:52:06 -0000 1.23.2.1 +++ gdb/gdbserver/server.c 30 Mar 2005 14:53:21 -0000 @@ -295,6 +295,8 @@ handle_v_requests (char *own_buf, char * return; } +extern int num_registers; + /* Handle a register fetch ('p') request. */ void handle_p_packet (char *own_buf) @@ -302,7 +304,7 @@ handle_p_packet (char *own_buf) char *end = own_buf + 1; int regnum = strtol (own_buf + 1, &end, 16); - if (*end) + if (*end || regnum < 0 || regnum >= num_registers) { write_enn (own_buf); return; @@ -318,7 +320,7 @@ handle_P_packet (char *own_buf) char *end = own_buf + 1; int regnum = strtol (own_buf + 1, &end, 16); - if (*end != '=') + if (*end != '=' || regnum < 0 || regnum >= num_registers) { write_enn (own_buf); return;