aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.csl24
-rw-r--r--gdb/Makefile.in2
-rw-r--r--gdb/arm-linux-nat.c173
-rw-r--r--gdb/config/arm/nm-linux.h16
-rw-r--r--gdb/gdbserver/linux-arm-low.c12
-rw-r--r--gdb/gdbserver/regcache.c2
-rw-r--r--gdb/gdbserver/server.c6
-rw-r--r--gdb/inftarg.c7
8 files changed, 219 insertions, 23 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl
index 57842ed..2d493e7 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,27 @@
+2005-03-30 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * gdb/Makefile.in (arm-linux-nat.o): Update dependencies.
+ * gdb/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.
+ * gdb/inftarg.c (child_xfer_partial): Handle
+ TARGET_OBJECT_AVAILABLE_REGISTERS.
+ * gdb/config/arm/nm-linux.h (arm_linux_available_registers): Add
+ prototype.
+ (NATIVE_XFER_AVAILABLE_REGISTERS): Define.
+
+ * gdb/gdbserver/linux-arm-low.c (arm_fill_wmmxregset)
+ (arm_store_wmmxregset): Remove stray text.
+ (arm_available_registers): Remove debugging output. Use hex.
+ * gdb/gdbserver/regcache.c (num_registers): Make global.
+ * gdb/gdbserver/server.c (handle_p_packet, handle_P_packet): Check
+ the value of regnum.
+
2005-03-28 Paul Brook <paul@codesourcery.com>
Daniel Jacobowitz <dan@codesourcery.com>
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4a6e971..b126430 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1732,7 +1732,7 @@ arch-utils.o: arch-utils.c $(defs_h) $(arch_utils_h) $(buildsym_h) \
$(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) \
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index cd9d5ff..59377be 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -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,
+ &regbuf[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,
+ &regbuf[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,
+ &regbuf[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,
+ &regbuf[regno * 8]);
+
+ first += 18;
+ for (regno = 0; regno < 2; regno++)
+ if (register_cached (first + regno))
+ regcache_raw_collect (current_regcache, first + regno,
+ &regbuf[16 * 8 + regno * 4]);
+
+ first += 6;
+ for (regno = 0; regno < 4; regno++)
+ if (register_cached (first + regno))
+ regcache_raw_collect (current_regcache, first + regno,
+ &regbuf[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)
{
diff --git a/gdb/config/arm/nm-linux.h b/gdb/config/arm/nm-linux.h
index 1d7bbaa..2ad3968 100644
--- a/gdb/config/arm/nm-linux.h
+++ b/gdb/config/arm/nm-linux.h
@@ -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 */
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index e49c86e..606a666 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -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);
}
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index 011fac1..8bfb3ec 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -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;
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 1389231..1c5f767 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -295,6 +295,8 @@ handle_v_requests (char *own_buf, char *status, unsigned char *signal)
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;
diff --git a/gdb/inftarg.c b/gdb/inftarg.c
index cd8674d..15dd8eb 100644
--- a/gdb/inftarg.c
+++ b/gdb/inftarg.c
@@ -559,6 +559,13 @@ child_xfer_partial (struct target_ops *ops, enum target_object object,
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;
}