]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2005-03-30 Daniel Jacobowitz <dan@codesourcery.com>
authorPaul Brook <paul@codesourcery.com>
Thu, 20 Oct 2005 03:36:28 +0000 (03:36 +0000)
committerPaul Brook <paul@codesourcery.com>
Thu, 20 Oct 2005 03:36:28 +0000 (03:36 +0000)
* 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>

* gdb/Makefile.in: arm-tdep.o depends on $(observer_h).
* gdb/arm-linux-nat.c (fetch_fpregister, fetch_fpregs,
store_fpregister, store_fpregs): Rename...
(fetch_fpa_register, fetch_fpa_regs, store_fpa_register,
store_fpa_regs): ... to this.
* gdb/arm-linux-tdep.c (arm_linux_init_abi): Provide ABI specific
overrides.
* gdb/arm-tdep.c: Include opserver.h.
(struct gdbarch_tdep_info): Add.
(arm_push_dummy_call): Handle doubleword alignment.
(arm_register_type): Handle iWMMXt and VFP regs.
(arm_register_byte): Ditto.
(arm_pseudo_register_read): New function.
(arm_pseudo_register_write): New function.
(arm_dwarf_reg_to_regnum): New function.
(arm_register_sim_regno): Handle iWMMXT regs.
(arm_register_remote_regno): New function.
(arm_extract_return_value): Use new macro names.
(arm_register_name): Handle iWMMXt and VFP registers.
(arm_sim_available_registers): New function.
(arm_update_architecture): New function.
(arm_gdbarch_init): Handle optional register sets.  Register new
hooks.  Fix misleading error message.
(_initialize_arm_tdep): Call observer_attach_inferior_created.
* gdb/arm-tdep.h (ARM_NUM_FP_ARG_REGS, ARM_LAST_FP_ARG_REGNUM,
FP_REGISTER_SIZE, NUM_FREGS): Rename ...
(ARM_NUM_FPA_ARG_REGS, ARM_LAST_FPA_ARG_REGNUM, FPA_REGISTER_SIZE,
NUM_FPA_REGS): ... to this.
(NUM_IWMMXT_COP0REGS, NUM_IWMMXT_COP1REGS, NUM_IWMMXT_REGS,
IWMMXT_COP0_REGSIZE, IWMMXT_COP1_REGSIZE, NUM_VFP_XREGS,
VFP_XREG_SIZE, NUM_VFP_SREGS, VFP_SREG_SIZE, NUM_VFP_PSEUDOS): Define.
(struct gdbarch_tdep): Add target_has_iwmmxt_regs,
target_has_vfp_regs, first_iwmmxt_regnum, target_iwmmxt_regnum,
first_vfp_regnum, first_vfp_pseudo and target_vfp_regnum.
* gdb/gdbarch.c (struct gdbarch): Add remote_num_g_packet_regs,
sim_available_registers and register_remote_regno.
(startup_gdbarch, verify_gdbarch): Ditto.
(gdbarch_dump): Dump new fields.
(gdbarch_remote_num_g_packet_regs_p, gdbarch_remote_num_g_packet_regs,
set_gdbarch_remote_num_g_packet_regs,
gdbarch_sim_available_registers_p, gdbarch_sim_available_registers,
set_gdbarch_sim_available_registers, gdbarch_register_remote_regno_p,
gdbarch_register_remote_regno, set_gdbarch_register_remote_regno):
New functions.
* gdb/gdbarch.h: Add prototypes.
* gdb/gdbarch.sh: Add new fields.
(deprecated_current_gdbarch_select_hack): Call flush_cached_frames.
* gdb/remote-sim.h (gdbsim_create_inferior): Call
observer_notify_inferior_created.
(gdbsim_xfer_partial): New function.
(init_gdbsim_ops): Use it.
* gdb/remote.c (struct remote_state): Add num_g_regs.
(init_remote_state): Only consider hard regs.  Allow target to provide
register mapping.
(packet_reg_from_regnum): Don't check pseudo regs.
(packet_reg_from_pnum): Ditto.
(remote_protocol_qPart_availableRegisters): Add.
(set_remote_protocol_qPart_availableRegisters_packet_cmd,
show_remote_protocol_qPart_availableRegisters_packet_cmd): New
functions.
(fetch_register_using_p, store_register_using_P): Handle arbitrary
register mappings.
(fetch_registers_using_g): New function.
(remote_fetch_registers): Use it.
(store_registers_using_G): New function.
(remote_store_registers): Use it.
(remote_xfer_partial): Handle TARGET_OBJECT_AVAILABLE_REGISTERS.
(show_remote_cmd): Display availableRegisters.
(_initialize_remote): Register qPart_availableRegisters.
* gdb/target.h (enum target_object): Add
TARGET_OBJECT_AVAILABLE_REGISTERS.
* gdb/gdbserver/configure.srv (arm*-*-linux*): set
srv_linux_regsets=yes.
* gdb/gdbserver/linux-arm-low.c (PTRACE_GETWMMXREGS,
PTRACE_SETWMMXREGS): Define.
(arm_fill_gregset, arm_store_gregset, arm_fill_wmmxregset,
arm_store_wmmxregset, arm_available_registers): New functions.
(target_regsets): Add.
(the_low_target): Use arm_available_registers.
* gdb/gdbserver/linux-low.c (linux_available_registers): New function.
(linux_target_op): Use it.
* gdb/gdbserver/linux-low.h (gdbserver/linux-low.h): Add
available_registers.
(use_regsets_p): Declare.
* gdb/gdbserver/regcache.c (g_register_bytes): Add.
(regcache_invalidate, registers_to_string, registers_from_string):
Use it.
(set_register_cache): Set g_register_bytes.
(supply_register_as_string): New function.
* gdb/gdbserver/regcache.h (supply_register_as_string): Add prototype.
* gdb/gdbserver/server.c (handle_query): Handle
qPart:availableRegisters.
(handle_p_packet, handle_P_packet): New functions.
(main): Handle 'p' and 'P' packets.
* gdb/gdbserver/target.h (struct target_ops): Add available_registers.
* gdb/regformats/reg-arm.dat: Add last_g_reg and iWMMXT regs.
* gdb/regformats/regdat.sh: Handle last_g_reg.
* gdb/regformats/regdef.h (set_register_cache): Update prototype.

25 files changed:
ChangeLog.csl
gdb/Makefile.in
gdb/arm-linux-nat.c
gdb/arm-tdep.c
gdb/arm-tdep.h
gdb/config/arm/nm-linux.h
gdb/defs.h
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/gdbserver/configure.srv
gdb/gdbserver/linux-arm-low.c
gdb/gdbserver/linux-low.c
gdb/gdbserver/linux-low.h
gdb/gdbserver/regcache.c
gdb/gdbserver/regcache.h
gdb/gdbserver/server.c
gdb/gdbserver/target.h
gdb/inftarg.c
gdb/regformats/reg-arm.dat
gdb/regformats/regdat.sh
gdb/regformats/regdef.h
gdb/remote-sim.c
gdb/remote.c
gdb/target.h

index c00e1b511ef28910daa31a0ee142f6b622cfba6d..b38fb78b004ced4a0e083294f210799120676dfe 100644 (file)
@@ -1,3 +1,129 @@
+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>
+
+       * gdb/Makefile.in: arm-tdep.o depends on $(observer_h).
+       * gdb/arm-linux-nat.c (fetch_fpregister, fetch_fpregs,
+       store_fpregister, store_fpregs): Rename...
+       (fetch_fpa_register, fetch_fpa_regs, store_fpa_register,
+       store_fpa_regs): ... to this.
+       * gdb/arm-linux-tdep.c (arm_linux_init_abi): Provide ABI specific
+       overrides.
+       * gdb/arm-tdep.c: Include opserver.h.
+       (struct gdbarch_tdep_info): Add.
+       (arm_push_dummy_call): Handle doubleword alignment.
+       (arm_register_type): Handle iWMMXt and VFP regs.
+       (arm_register_byte): Ditto.
+       (arm_pseudo_register_read): New function.
+       (arm_pseudo_register_write): New function.
+       (arm_dwarf_reg_to_regnum): New function.
+       (arm_register_sim_regno): Handle iWMMXT regs.
+       (arm_register_remote_regno): New function.
+       (arm_extract_return_value): Use new macro names.
+       (arm_register_name): Handle iWMMXt and VFP registers.
+       (arm_sim_available_registers): New function.
+       (arm_update_architecture): New function.
+       (arm_gdbarch_init): Handle optional register sets.  Register new
+       hooks.  Fix misleading error message.
+       (_initialize_arm_tdep): Call observer_attach_inferior_created.
+       * gdb/arm-tdep.h (ARM_NUM_FP_ARG_REGS, ARM_LAST_FP_ARG_REGNUM,
+       FP_REGISTER_SIZE, NUM_FREGS): Rename ...
+       (ARM_NUM_FPA_ARG_REGS, ARM_LAST_FPA_ARG_REGNUM, FPA_REGISTER_SIZE,
+       NUM_FPA_REGS): ... to this.
+       (NUM_IWMMXT_COP0REGS, NUM_IWMMXT_COP1REGS, NUM_IWMMXT_REGS,
+       IWMMXT_COP0_REGSIZE, IWMMXT_COP1_REGSIZE, NUM_VFP_XREGS,
+       VFP_XREG_SIZE, NUM_VFP_SREGS, VFP_SREG_SIZE, NUM_VFP_PSEUDOS): Define.
+       (struct gdbarch_tdep): Add target_has_iwmmxt_regs,
+       target_has_vfp_regs, first_iwmmxt_regnum, target_iwmmxt_regnum,
+       first_vfp_regnum, first_vfp_pseudo and target_vfp_regnum.
+       * gdb/gdbarch.c (struct gdbarch): Add remote_num_g_packet_regs,
+       sim_available_registers and register_remote_regno.
+       (startup_gdbarch, verify_gdbarch): Ditto.
+       (gdbarch_dump): Dump new fields.
+       (gdbarch_remote_num_g_packet_regs_p, gdbarch_remote_num_g_packet_regs,
+       set_gdbarch_remote_num_g_packet_regs,
+       gdbarch_sim_available_registers_p, gdbarch_sim_available_registers,
+       set_gdbarch_sim_available_registers, gdbarch_register_remote_regno_p,
+       gdbarch_register_remote_regno, set_gdbarch_register_remote_regno):
+       New functions.
+       * gdb/gdbarch.h: Add prototypes.
+       * gdb/gdbarch.sh: Add new fields.
+       (deprecated_current_gdbarch_select_hack): Call flush_cached_frames.
+       * gdb/remote-sim.h (gdbsim_create_inferior): Call
+       observer_notify_inferior_created.
+       (gdbsim_xfer_partial): New function.
+       (init_gdbsim_ops): Use it.
+       * gdb/remote.c (struct remote_state): Add num_g_regs.
+       (init_remote_state): Only consider hard regs.  Allow target to provide
+       register mapping.
+       (packet_reg_from_regnum): Don't check pseudo regs.
+       (packet_reg_from_pnum): Ditto.
+       (remote_protocol_qPart_availableRegisters): Add.
+       (set_remote_protocol_qPart_availableRegisters_packet_cmd,
+       show_remote_protocol_qPart_availableRegisters_packet_cmd): New
+       functions.
+       (fetch_register_using_p, store_register_using_P): Handle arbitrary
+       register mappings.
+       (fetch_registers_using_g): New function.
+       (remote_fetch_registers): Use it.
+       (store_registers_using_G): New function.
+       (remote_store_registers): Use it.
+       (remote_xfer_partial): Handle TARGET_OBJECT_AVAILABLE_REGISTERS.
+       (show_remote_cmd): Display availableRegisters.
+       (_initialize_remote): Register qPart_availableRegisters.
+       * gdb/target.h (enum target_object): Add
+       TARGET_OBJECT_AVAILABLE_REGISTERS.
+       * gdb/gdbserver/configure.srv (arm*-*-linux*): set
+       srv_linux_regsets=yes.
+       * gdb/gdbserver/linux-arm-low.c (PTRACE_GETWMMXREGS,
+       PTRACE_SETWMMXREGS): Define.
+       (arm_fill_gregset, arm_store_gregset, arm_fill_wmmxregset,
+       arm_store_wmmxregset, arm_available_registers): New functions.
+       (target_regsets): Add.
+       (the_low_target): Use arm_available_registers.
+       * gdb/gdbserver/linux-low.c (linux_available_registers): New function.
+       (linux_target_op): Use it.
+       * gdb/gdbserver/linux-low.h (gdbserver/linux-low.h): Add
+       available_registers.
+       (use_regsets_p): Declare.
+       * gdb/gdbserver/regcache.c (g_register_bytes): Add.
+       (regcache_invalidate, registers_to_string, registers_from_string):
+       Use it.
+       (set_register_cache): Set g_register_bytes.
+       (supply_register_as_string): New function.
+       * gdb/gdbserver/regcache.h (supply_register_as_string): Add prototype.
+       * gdb/gdbserver/server.c (handle_query): Handle
+       qPart:availableRegisters.
+       (handle_p_packet, handle_P_packet): New functions.
+       (main): Handle 'p' and 'P' packets.
+       * gdb/gdbserver/target.h (struct target_ops): Add available_registers.
+       * gdb/regformats/reg-arm.dat: Add last_g_reg and iWMMXT regs.
+       * gdb/regformats/regdat.sh: Handle last_g_reg.
+       * gdb/regformats/regdef.h (set_register_cache): Update prototype.
+
 2005-04-29  Paul Brook  <paul@codesourcery.com>
 
        * gdb/remote-sim.c (SIGTRAP): Provide default defnition.
index 02bfcef36c120af721211ac26626002b0659ab9f..9130b564edc2982d2ee9dad1276e34298e9ab83e 100644 (file)
@@ -1749,7 +1749,7 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \
        $(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(arm_tdep_h) \
        $(gdb_sim_arm_h) $(elf_bfd_h) $(coff_internal_h) $(elf_arm_h) \
        $(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \
-       $(dwarf2_frame_h)
+       $(dwarf2_frame_h) $(observer_h)
 auxv.o: auxv.c $(defs_h) $(target_h) $(gdbtypes_h) $(command_h) \
        $(inferior_h) $(valprint_h) $(gdb_assert_h) $(auxv_h) \
        $(elf_common_h)
index c29c783074dee581649e89ec926343046cfbb36f..480a10d9c8f39bc310a8693acf49233ed798b84b 100644 (file)
@@ -26,6 +26,7 @@
 #include "regcache.h"
 #include "target.h"
 #include "linux-nat.h"
+#include "gdb_assert.h"
 
 #include "arm-tdep.h"
 
 #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
@@ -234,7 +242,7 @@ store_nwfpe_register (int regno, FPA11 * fpa11)
    state of the process and store it into regcache.  */
 
 static void
-fetch_fpregister (int regno)
+fetch_fpa_register (int regno)
 {
   int ret, tid;
   FPA11 fp;
@@ -283,7 +291,7 @@ fetch_fpregister (int regno)
    into regcache.  */
 
 static void
-fetch_fpregs (void)
+fetch_fpa_regs (void)
 {
   int ret, regno, tid;
   FPA11 fp;
@@ -331,7 +339,7 @@ fetch_fpregs (void)
    process using the contents from regcache.  */
 
 static void
-store_fpregister (int regno)
+store_fpa_register (int regno)
 {
   int ret, tid;
   FPA11 fp;
@@ -369,7 +377,7 @@ store_fpregister (int regno)
    the contents from regcache.  */
 
 static void
-store_fpregs (void)
+store_fpa_regs (void)
 {
   int ret, regno, tid;
   FPA11 fp;
@@ -553,6 +561,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.  */
@@ -563,15 +662,22 @@ arm_linux_fetch_inferior_registers (int regno)
   if (-1 == regno)
     {
       fetch_regs ();
-      fetch_fpregs ();
+      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)
-        fetch_fpregister (regno);
+      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 ();
+       }
     }
 }
 
@@ -585,15 +691,22 @@ arm_linux_store_inferior_registers (int regno)
   if (-1 == regno)
     {
       store_regs ();
-      store_fpregs ();
+      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_fpregister (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 ();
+       }
     }
 }
 
@@ -745,6 +858,50 @@ get_linux_version (unsigned int *vmajor,
 
 void _initialize_arm_linux_nat (void);
 
+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 ba713f21419cd5e4f2611fb111e701e6a120acad..90dbbae47464611e1d9f506d14a5a46c8481f2f3 100644 (file)
@@ -39,6 +39,7 @@
 #include "trad-frame.h"
 #include "objfiles.h"
 #include "dwarf2-frame.h"
+#include "observer.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
 
 static int arm_debug;
 
+/* Extra information which ARM uses to select the appropriate GDB
+   architecture.  */
+
+struct gdbarch_tdep_info
+{
+  /* See the descriptions of these fields in struct gdbarch_tdep.  */
+
+  int target_has_iwmmxt_regs;
+  int target_iwmmxt_regnum;
+  int target_has_vfp_regs;
+  int target_vfp_regnum;
+};
+
 /* Each OS has a different mechanism for accessing the various
    registers stored in the sigcontext structure.
 
@@ -1450,7 +1464,42 @@ arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
 static struct type *
 arm_register_type (struct gdbarch *gdbarch, int regnum)
 {
-  if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
+  int first;
+
+  first = gdbarch_tdep (gdbarch)->first_iwmmxt_regnum;
+  if (first != -1)
+    {
+      if (regnum >= first && regnum < first + NUM_IWMMXT_COP0REGS)
+       return builtin_type_vec64i;
+
+      first += NUM_IWMMXT_COP0REGS;
+
+      if (regnum >= first && regnum < first + NUM_IWMMXT_COP1REGS)
+       return builtin_type_int32;
+    }
+
+  first = gdbarch_tdep (gdbarch)->first_vfp_regnum;
+  if (first != -1)
+    {
+      if (regnum >= first && regnum < first + NUM_VFP_XREGS)
+       return builtin_type_int32;
+
+      first += NUM_VFP_XREGS;
+
+      if (regnum >= first && regnum < first + NUM_VFP_SREGS)
+       return builtin_type_float;
+    }
+
+  first = gdbarch_tdep (gdbarch)->first_vfp_pseudo;
+  if (first != -1)
+    {
+      first += gdbarch_num_regs (gdbarch);
+
+      if (regnum >= first && regnum < first + NUM_VFP_PSEUDOS)
+       return builtin_type_double;
+    }
+
+  if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FPA_REGS)
     {
       if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
        return builtin_type_arm_ext_big;
@@ -1467,15 +1516,162 @@ arm_register_type (struct gdbarch *gdbarch, int regnum)
 static int
 arm_register_byte (int regnum)
 {
+  int offset;
+  int first;
+
+  offset = 0;
+  first = 0;
   if (regnum < ARM_F0_REGNUM)
     return regnum * INT_REGISTER_SIZE;
-  else if (regnum < ARM_PS_REGNUM)
-    return (NUM_GREGS * INT_REGISTER_SIZE
-           + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
-  else
-    return (NUM_GREGS * INT_REGISTER_SIZE
-           + NUM_FREGS * FP_REGISTER_SIZE
-           + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
+  offset += NUM_GREGS * INT_REGISTER_SIZE;
+  first += NUM_GREGS;
+
+  if (regnum < first + NUM_FPA_REGS)
+    return offset + (regnum - first) * FPA_REGISTER_SIZE;
+  offset += NUM_FPA_REGS * FPA_REGISTER_SIZE;
+  first += NUM_FPA_REGS;
+
+  if (regnum < first + NUM_SREGS)
+    return offset + (regnum - first) * STATUS_REGISTER_SIZE;
+  offset += NUM_SREGS * STATUS_REGISTER_SIZE;
+  
+  first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+  if (first != -1)
+    {
+      if (regnum >= first && regnum < first + NUM_IWMMXT_COP0REGS)
+       return offset + (regnum - first) * IWMMXT_COP0_REGSIZE;
+
+      offset += NUM_IWMMXT_COP0REGS * IWMMXT_COP0_REGSIZE;
+      first += NUM_IWMMXT_COP0REGS;
+
+      if (regnum >= first && regnum < first + NUM_IWMMXT_COP1REGS)
+       return offset + (regnum - first) * IWMMXT_COP1_REGSIZE;
+
+      offset += NUM_IWMMXT_COP1REGS * IWMMXT_COP1_REGSIZE;
+    }
+
+  first = gdbarch_tdep (current_gdbarch)->first_vfp_regnum;
+  if (first != -1)
+    {
+      if (regnum >= first && regnum < first + NUM_VFP_XREGS)
+       return offset + (regnum - first) * VFP_XREG_SIZE;
+
+      offset += NUM_VFP_XREGS * VFP_XREG_SIZE;
+      first += NUM_VFP_XREGS;
+
+      if (regnum >= first && regnum < first + NUM_VFP_SREGS)
+       return offset + (regnum - first) * VFP_SREG_SIZE;
+    }
+  internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
+}
+
+static void
+arm_pseudo_register_read (struct gdbarch *gdbarch,
+                         struct regcache *regcache,
+                         int regnum, void *buf)
+{
+  int first;
+  int low_regnum;
+  int high_regnum;
+
+  first = gdbarch_tdep (current_gdbarch)->first_vfp_pseudo;
+  if (first != -1)
+    {
+      first += gdbarch_num_regs (gdbarch);
+
+      if (regnum >= first && regnum < first + NUM_VFP_PSEUDOS)
+       {
+         regnum = gdbarch_tdep (current_gdbarch)->first_vfp_regnum
+           + NUM_VFP_XREGS + 2 * (regnum - first);
+         if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+           {
+             low_regnum = regnum;
+             high_regnum = regnum + 1;
+           }
+         else
+           {
+             low_regnum = regnum + 1;
+             high_regnum = regnum;
+           }
+         regcache_raw_read (regcache, low_regnum, buf);
+         regcache_raw_read (regcache, high_regnum, ((char *)buf) + 4);
+         return;
+       }
+    }
+  internal_error (__FILE__, __LINE__, _("Bad pseudo %d"), regnum);
+}
+
+static void
+arm_pseudo_register_write (struct gdbarch *gdbarch,
+                          struct regcache *regcache,
+                          int regnum, const void *buf)
+{
+  int first;
+  int low_regnum;
+  int high_regnum;
+
+  first = gdbarch_tdep (current_gdbarch)->first_vfp_pseudo;
+  if (first != -1)
+    {
+      first += gdbarch_num_regs (gdbarch);
+
+      if (regnum >= first && regnum < first + NUM_VFP_PSEUDOS)
+       {
+         regnum = gdbarch_tdep (current_gdbarch)->first_vfp_regnum
+           + NUM_VFP_XREGS + 2 * (regnum - first);
+         if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+           {
+             low_regnum = regnum;
+             high_regnum = regnum + 1;
+           }
+         else
+           {
+             low_regnum = regnum + 1;
+             high_regnum = regnum;
+           }
+         regcache_raw_write (regcache, low_regnum, buf);
+         regcache_raw_write (regcache, high_regnum + 1, ((char *)buf) + 4);
+         return;
+       }
+    }
+  internal_error (__FILE__, __LINE__, _("Bad pseudo %d"), regnum);
+}
+
+/* Map DWARF register numbers onto internal GDB register numbers.  */
+static int
+arm_dwarf_reg_to_regnum (int reg)
+{
+  int first;
+  if (reg >= 0 && reg <= 16)
+    return reg; /* Core integer regs.  */
+  if (reg >= 16 && reg <= 23)
+    return ARM_F0_REGNUM + reg - 16; /* Legacy FPA encoding.  */
+  if (reg >= 96 && reg <= 103)
+    return ARM_F0_REGNUM + reg - 96; /* FPA regs.  */
+
+  /* VFP regs.  */
+  first = gdbarch_tdep (current_gdbarch)->first_vfp_regnum;
+  if (first != -1 && reg >= 64 && reg <= 95);
+      return first + NUM_VFP_XREGS + reg - 64;;
+
+  /* iWMMXt regs.  */
+  first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+  if (first != -1)
+    {
+      if (reg >= 112 && reg <= 127) /* wr0-wr15 */
+       return first + reg - 112;
+      first += NUM_IWMMXT_COP0REGS;
+      if (reg >= 192 && reg <= 199) /* wc0-wc7 */
+       return first + reg - 104;
+      first += 8;
+      if (reg >= 104 && reg <= 111) /*wcgr0-wcgr7 */
+       return first + reg - 104;
+    }
+
+  warning (_("Unmapped DWARF Register #%d encountered."), reg);
+
+  return -1;
 }
 
 /* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
@@ -1485,13 +1681,21 @@ arm_register_sim_regno (int regnum)
   int reg = regnum;
   gdb_assert (reg >= 0 && reg < NUM_REGS);
 
+  if (gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum != -1)
+    {
+      int first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+
+      if (regnum >= first && regnum < first + NUM_IWMMXT_REGS)
+       return SIM_ARM_IWMMXT_COP0R0_REGNUM + (regnum - first);
+    }
+
   if (reg < NUM_GREGS)
     return SIM_ARM_R0_REGNUM + reg;
   reg -= NUM_GREGS;
 
-  if (reg < NUM_FREGS)
+  if (reg < NUM_FPA_REGS)
     return SIM_ARM_FP0_REGNUM + reg;
-  reg -= NUM_FREGS;
+  reg -= NUM_FPA_REGS;
 
   if (reg < NUM_SREGS)
     return SIM_ARM_FPS_REGNUM + reg;
@@ -1500,6 +1704,35 @@ arm_register_sim_regno (int regnum)
   internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
 }
 
+/* Map GDB internal REGNUM onto the current remote protocol
+   register numbers.  */
+
+static int
+arm_register_remote_regno (int regnum)
+{
+  gdb_assert (regnum >= 0 && regnum < NUM_REGS);
+
+  if (gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum != -1)
+    {
+      int first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+
+      if (regnum >= first && regnum < first + NUM_IWMMXT_REGS)
+       return gdbarch_tdep (current_gdbarch)->target_iwmmxt_regnum
+                            + (regnum - first);
+    }
+
+  if (gdbarch_tdep (current_gdbarch)->first_vfp_regnum != -1)
+    {
+      int first = gdbarch_tdep (current_gdbarch)->first_vfp_regnum;
+
+      if (regnum >= first && regnum < first + NUM_VFP_XREGS + NUM_VFP_SREGS)
+       return gdbarch_tdep (current_gdbarch)->target_vfp_regnum
+                            + (regnum - first);
+    }
+
+  return regnum;
+}
+
 /* NOTE: cagney/2001-08-20: Both convert_from_extended() and
    convert_to_extended() use floatformat_arm_ext_littlebyte_bigword.
    It is thought that this is is the floating-point register format on
@@ -2103,7 +2336,7 @@ arm_extract_return_value (struct type *type, struct regcache *regs,
            /* The value is in register F0 in internal format.  We need to
               extract the raw value and then convert it to the desired
               internal type.  */
-           bfd_byte tmpbuf[FP_REGISTER_SIZE];
+           bfd_byte tmpbuf[FPA_REGISTER_SIZE];
 
            regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
            convert_from_extended (floatformat_from_type (type), tmpbuf,
@@ -2571,9 +2804,59 @@ set_disassembly_style_sfunc (char *args, int from_tty,
 \f
 /* Return the ARM register name corresponding to register I.  */
 static const char *
-arm_register_name (int i)
+arm_register_name (int regnum)
 {
-  return arm_register_names[i];
+  int first;
+
+  first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+  if (first != -1)
+    {
+      static const char *const iwmmxt_register_names[] = 
+       {
+         "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+         "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
+         "wcid", "wcon", "wcssf", "wcasf", "", "", "", "",
+         "wcgr0", "wcgr1", "wcgr2", "wcgr3", "", "", "", ""
+       };
+
+      if (regnum >= first && regnum < first + NUM_IWMMXT_REGS)
+       return iwmmxt_register_names[regnum - first];
+    }
+
+  first = gdbarch_tdep (current_gdbarch)->first_vfp_regnum;
+  if (first != -1)
+    {
+      static const char *const vfp_register_names[] = 
+       {
+         "fpsid", "fpscr", "", "", "", "", "", "",
+         "fpexc", "", "", "", "", "", "", "",
+         "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
+         "s8",  "s9",  "s10", "s11", "s12", "s13", "s14", "s15",
+         "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+         "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
+       };
+
+      if (regnum >= first && regnum < first + NUM_VFP_XREGS + NUM_VFP_SREGS)
+       return vfp_register_names[regnum - first];
+    }
+
+  first = gdbarch_tdep (current_gdbarch)->first_vfp_pseudo;
+  if (first != -1)
+    {
+      static const char *const vfp_pseudo_names[] = 
+       {
+         "d0", "d1", "d2",  "d3",  "d4",  "d5",  "d6",  "d7",
+         "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+       };
+
+      first += gdbarch_num_regs (current_gdbarch);
+
+      if (regnum >= first && regnum < first + NUM_VFP_PSEUDOS)
+       return vfp_pseudo_names[regnum - first];
+    }
+
+  gdb_assert (regnum < NUM_GREGS + NUM_FPA_REGS + NUM_SREGS);
+  return arm_register_names[regnum];
 }
 
 static void
@@ -2681,6 +2964,70 @@ arm_elf_osabi_sniffer (bfd *abfd)
   /* Anything else will be handled by the generic ELF sniffer.  */
   return osabi;
 }
+\f
+/* */
+
+static char *
+arm_sim_available_registers (struct gdbarch *gdbarch,
+                            const struct target_ops *target)
+{
+  /* The built-in simulator supports iWMMXt.  */
+  return xstrdup ("iwmmxt");
+}
+
+/* Update the current architecture based on architecture features.  */
+
+static void
+arm_update_architecture (struct target_ops *target, int from_tty)
+{
+  struct gdbarch_tdep_info tdep;
+  struct gdbarch_info info;
+  char buf[64];
+  int bytes_read;
+
+  memset (&tdep, 0, sizeof (tdep));
+
+  /* FIXME: Define TARGET_READ_FULL which allocates the buffer large
+     enough, modelled on auxv.c.  */
+  bytes_read = target_read_partial (target, TARGET_OBJECT_AVAILABLE_REGISTERS,
+                                   "", buf, 0, 64);
+
+  /* "Parse" the response.  */
+  if (bytes_read == 6 && strncmp (buf, "iwmmxt", 6) == 0)
+    {
+      tdep.target_has_iwmmxt_regs = 1;
+      tdep.target_iwmmxt_regnum = -1;
+    }
+  else if (bytes_read > 6 && strncmp (buf, "iwmmxt:", 7) == 0)
+    {
+      char *end;
+      tdep.target_has_iwmmxt_regs = 1;
+      tdep.target_iwmmxt_regnum = strtol (buf + 7, &end, 16);
+    }
+  else
+    {
+      tdep.target_has_iwmmxt_regs = 0;
+      tdep.target_iwmmxt_regnum = -1;
+    }
+
+  if (bytes_read > 3 && strncmp (buf, "vfp:", 4) == 0)
+    {
+      char *end;
+      tdep.target_has_vfp_regs = 1;
+      tdep.target_vfp_regnum = strtol (buf + 4, &end, 16);
+    }
+  else
+    {
+      tdep.target_has_vfp_regs = 0;
+      tdep.target_vfp_regnum = -1;
+    }
+
+  /* Update the architecture.  */
+  gdbarch_info_init (&info);
+  info.tdep_info = &tdep;
+  if (!gdbarch_update_p (info))
+    internal_error (__FILE__, __LINE__, "could not update architecture");
+}
 
 \f
 /* Initialize the current architecture based on INFO.  If possible,
@@ -2698,6 +3045,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   struct gdbarch_list *best_arch;
   enum arm_abi_kind arm_abi = arm_abi_global;
   enum arm_float_model fp_model = arm_fp_model;
+  int nregs;
+  int pseudos;
 
   /* If we have an object to base this architecture on, try to determine
      its ABI.  */
@@ -2792,6 +3141,25 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        best_arch != NULL;
        best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
     {
+      /* If we have target-specific bits in INFO, then make sure
+        they match.  */
+      if (info.tdep_info)
+       {
+         if (gdbarch_tdep (best_arch->gdbarch)->target_has_iwmmxt_regs
+             != info.tdep_info->target_has_iwmmxt_regs)
+           continue;
+         if (gdbarch_tdep (best_arch->gdbarch)->target_iwmmxt_regnum
+             != info.tdep_info->target_iwmmxt_regnum)
+           continue;
+
+         if (gdbarch_tdep (best_arch->gdbarch)->target_has_vfp_regs
+             != info.tdep_info->target_has_vfp_regs)
+           continue;
+         if (gdbarch_tdep (best_arch->gdbarch)->target_vfp_regnum
+             != info.tdep_info->target_vfp_regnum)
+           continue;
+       }
+
       if (arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
        continue;
 
@@ -2813,6 +3181,35 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->arm_abi = arm_abi;
   tdep->fp_model = fp_model;
 
+  if (info.tdep_info)
+    {
+      /* If specific target capabilities were requested, use them.  */
+      tdep->target_has_iwmmxt_regs = info.tdep_info->target_has_iwmmxt_regs;
+      tdep->target_iwmmxt_regnum = info.tdep_info->target_iwmmxt_regnum;
+      tdep->target_has_vfp_regs = info.tdep_info->target_has_vfp_regs;
+      tdep->target_vfp_regnum = info.tdep_info->target_vfp_regnum;
+    }
+  else if (arches)
+    {
+      /* Otherwise, inherit from the last ARM architecture, if any.  */
+      tdep->target_has_iwmmxt_regs
+       = gdbarch_tdep (arches->gdbarch)->target_has_iwmmxt_regs;
+      tdep->target_iwmmxt_regnum
+       = gdbarch_tdep (arches->gdbarch)->target_iwmmxt_regnum;
+      tdep->target_has_vfp_regs
+       = gdbarch_tdep (arches->gdbarch)->target_has_vfp_regs;
+      tdep->target_vfp_regnum
+       = gdbarch_tdep (arches->gdbarch)->target_vfp_regnum;
+    }
+  else
+    {
+      /* Set defaults.  */
+      tdep->target_has_iwmmxt_regs = 0;
+      tdep->target_iwmmxt_regnum = -1;
+      tdep->target_has_vfp_regs = 0;
+      tdep->target_vfp_regnum = -1;
+    }
+
   /* Breakpoints.  */
   switch (info.byte_order)
     {
@@ -2877,12 +3274,49 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
   set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
   set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
-  set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
   set_gdbarch_register_type (gdbarch, arm_register_type);
 
+  nregs = NUM_GREGS + NUM_FPA_REGS + NUM_SREGS;
+  pseudos = 0;
+  if (tdep->target_has_iwmmxt_regs)
+    {
+      tdep->first_iwmmxt_regnum = nregs;
+      nregs += NUM_IWMMXT_REGS;
+    }
+  else
+    tdep->first_iwmmxt_regnum = -1;
+
+  if (tdep->target_has_vfp_regs)
+    {
+      tdep->first_vfp_regnum = nregs;
+      nregs += NUM_VFP_XREGS + NUM_VFP_SREGS;
+      tdep->first_vfp_pseudo = pseudos;
+      pseudos += NUM_VFP_PSEUDOS;
+    }
+  else
+    {
+      tdep->first_vfp_regnum = -1;
+      tdep->first_vfp_pseudo = -1;
+    }
+
+  set_gdbarch_num_regs (gdbarch, nregs);
+  set_gdbarch_num_pseudo_regs (gdbarch, pseudos);
+  set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_register_write);
+
+  /* The FPA registers are included in the remote 'g' packet for
+     historic reasons.  */
+  set_gdbarch_remote_num_g_packet_regs (gdbarch,
+                                       NUM_GREGS + NUM_FPA_REGS + NUM_SREGS);
+
   /* Internal <-> external register number maps.  */
+  set_gdbarch_dwarf_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
   set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
 
+  set_gdbarch_sim_available_registers (gdbarch, arm_sim_available_registers);
+  set_gdbarch_register_remote_regno (gdbarch, arm_register_remote_regno);
+
   /* Integer registers are 4 bytes.  */
   set_gdbarch_deprecated_register_size (gdbarch, 4);
   set_gdbarch_register_name (gdbarch, arm_register_name);
@@ -3078,4 +3512,6 @@ vfp - VFP co-processor."),
                           NULL,
                           NULL, /* FIXME: i18n: "ARM debugging is %s.  */
                           &setdebuglist, &showdebuglist);
+
+  observer_attach_inferior_created (arm_update_architecture);
 }
index 5217ff6a3dd91cf884d06a691bf4ce349d5f51b5..6eed14cb66702a3dc9f0d5dc0a7bff7dc9f5a947 100644 (file)
@@ -41,17 +41,17 @@ enum gdb_regnum {
   THUMB_FP_REGNUM = 7,         /* Frame register in Thumb code, if used.  */
   ARM_NUM_ARG_REGS = 4, 
   ARM_LAST_ARG_REGNUM = ARM_A4_REGNUM,
-  ARM_NUM_FP_ARG_REGS = 4,
-  ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM
+  ARM_NUM_FPA_ARG_REGS = 4,
+  ARM_LAST_FPA_ARG_REGNUM = ARM_F3_REGNUM,
 };
 
 /* Size of integer registers.  */
 #define INT_REGISTER_SIZE              4
 
-/* Say how long FP registers are.  Used for documentation purposes and
+/* Say how long FPA registers are.  Used for documentation purposes and
    code readability in this header.  IEEE extended doubles are 80
    bits.  DWORD aligned they use 96 bits.  */
-#define FP_REGISTER_SIZE       12
+#define FPA_REGISTER_SIZE      12
 
 /* Status registers are the same size as general purpose registers.
    Used for documentation purposes and code readability in this
@@ -65,10 +65,31 @@ enum gdb_regnum {
    (and called PS for processor status) so the status bits can be cleared
    from the PC (register 15).  For 32 bit ARM code, a copy of CPSR is placed
    in PS.  */
-#define NUM_FREGS      8       /* Number of floating point registers.  */
+#define NUM_FPA_REGS   8       /* Number of FPA floating point registers.  */
 #define NUM_SREGS      2       /* Number of status registers.  */
 #define NUM_GREGS      16      /* Number of general purpose registers.  */
 
+/* Optional supported coprocessors.  */
+enum
+{
+  NUM_IWMMXT_COP0REGS = 16,
+  NUM_IWMMXT_COP1REGS = 16,
+  NUM_IWMMXT_REGS = NUM_IWMMXT_COP0REGS + NUM_IWMMXT_COP1REGS,
+  IWMMXT_COP0_REGSIZE = 8,
+  IWMMXT_COP1_REGSIZE = 4
+};
+
+enum
+{
+  /* Status registers.  */
+  NUM_VFP_XREGS = 16,
+  VFP_XREG_SIZE = 4,
+  /* Single precision registers.  */
+  NUM_VFP_SREGS = 32,
+  VFP_SREG_SIZE = 4,
+  /* Pseudo regs for access to double precision values.  */
+  NUM_VFP_PSEUDOS = 16
+};
 
 /* Instruction condition field values.  */
 #define INST_EQ                0x0
@@ -125,6 +146,16 @@ enum arm_abi_kind
 /* Target-dependent structure in gdbarch.  */
 struct gdbarch_tdep
 {
+  /* These fields are architecture-specific properties of the target.
+     After connecting to a new target, we check the target's properties,
+     and switch to a new gdbarch if necessary.   */
+
+  int target_has_iwmmxt_regs;    /* Does the target have iWMMXt registers?  */
+
+  int target_has_vfp_regs;     /* Does the target have VFP registers?  */
+
+  /* End of target properties.  */
+
   /* The ABI for this architecture.  It should never be set to
      ARM_ABI_AUTO.  */
   enum arm_abi_kind arm_abi;
@@ -143,6 +174,17 @@ struct gdbarch_tdep
                                   If this is negative, longjmp support
                                   will be disabled.  */
   size_t jb_elt_size;          /* And the size of each entry in the buf.  */
+
+  int first_iwmmxt_regnum;     /* The first iWMMXt register, or -1 if none.  */
+
+  int target_iwmmxt_regnum;    /* The target-supplied numbering for the
+                                  iWMMXt registers, or -1 if none.  */
+  int first_vfp_regnum;                /* The first VFP register, or -1 if none.  */
+  int first_vfp_pseudo;                /* The first VFP pseudoreg, or -1 if none.  
+                                  This is an offset from NUM_REGS.  */
+
+  int target_vfp_regnum;       /* The target-supplied numbering for the
+                                  VFP registers, or -1 if none.  */
 };
 
 #ifndef LOWEST_PC
index 1d7bbaa86506f3119ca08f8a57bfb576b3c64bef..2ad3968f636b9ee8adff0c200c81bfd5b94dd156 100644 (file)
@@ -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 2f0e2e62f6931ac8f8ded2305945d9390ed1fd35..197545a18ac678dce466d0187e829c67fa4764f0 100644 (file)
@@ -1156,6 +1156,10 @@ extern int use_windows;
 #define SLASH_STRING "/"
 #endif
 
+#if defined(__WIN32__) && !defined(__CYGWIN__)
+#define WINAPI
+#endif
+
 /* Provide default definitions of PIDGET, TIDGET, and MERGEPID.
    The name ``TIDGET'' is a historical accident.  Many uses of TIDGET
    in the code actually refer to a lightweight process id, i.e,
index 527fe177d3914cf954da14bd303ea75cd5d124b1..e24987a775cbf9c9d3e1c074155b051c7927b2ad 100644 (file)
@@ -152,6 +152,7 @@ struct gdbarch
   gdbarch_pseudo_register_write_ftype *pseudo_register_write;
   int num_regs;
   int num_pseudo_regs;
+  int remote_num_g_packet_regs;
   int sp_regnum;
   int pc_regnum;
   int ps_regnum;
@@ -177,6 +178,8 @@ struct gdbarch
   gdbarch_register_bytes_ok_ftype *register_bytes_ok;
   gdbarch_cannot_fetch_register_ftype *cannot_fetch_register;
   gdbarch_cannot_store_register_ftype *cannot_store_register;
+  gdbarch_sim_available_registers_ftype *sim_available_registers;
+  gdbarch_register_remote_regno_ftype *register_remote_regno;
   gdbarch_get_longjmp_target_ftype *get_longjmp_target;
   int believe_pcc_promotion;
   gdbarch_convert_register_p_ftype *convert_register_p;
@@ -278,6 +281,7 @@ struct gdbarch startup_gdbarch =
   0,  /* pseudo_register_write */
   0,  /* num_regs */
   0,  /* num_pseudo_regs */
+  0,  /* remote_num_g_packet_regs */
   -1,  /* sp_regnum */
   -1,  /* pc_regnum */
   -1,  /* ps_regnum */
@@ -303,6 +307,8 @@ struct gdbarch startup_gdbarch =
   0,  /* register_bytes_ok */
   0,  /* cannot_fetch_register */
   0,  /* cannot_store_register */
+  0,  /* sim_available_registers */
+  0,  /* register_remote_regno */
   0,  /* get_longjmp_target */
   0,  /* believe_pcc_promotion */
   0,  /* convert_register_p */
@@ -536,6 +542,7 @@ verify_gdbarch (struct gdbarch *current_gdbarch)
   if (current_gdbarch->num_regs == -1)
     fprintf_unfiltered (log, "\n\tnum_regs");
   /* Skip verify of num_pseudo_regs, invalid_p == 0 */
+  /* Skip verify of remote_num_g_packet_regs, has predicate */
   /* Skip verify of sp_regnum, invalid_p == 0 */
   /* Skip verify of pc_regnum, invalid_p == 0 */
   /* Skip verify of ps_regnum, invalid_p == 0 */
@@ -559,6 +566,8 @@ verify_gdbarch (struct gdbarch *current_gdbarch)
   /* Skip verify of register_bytes_ok, has predicate */
   /* Skip verify of cannot_fetch_register, invalid_p == 0 */
   /* Skip verify of cannot_store_register, invalid_p == 0 */
+  /* Skip verify of sim_available_registers, has predicate */
+  /* Skip verify of register_remote_regno, has predicate */
   /* Skip verify of get_longjmp_target, has predicate */
   /* Skip verify of convert_register_p, invalid_p == 0 */
   /* Skip verify of pointer_to_address, invalid_p == 0 */
@@ -1444,6 +1453,12 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: register_reggroup_p = <0x%lx>\n",
                       (long) current_gdbarch->register_reggroup_p);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_register_remote_regno_p() = %d\n",
+                      gdbarch_register_remote_regno_p (current_gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: register_remote_regno = <0x%lx>\n",
+                      (long) current_gdbarch->register_remote_regno);
 #ifdef REGISTER_SIM_REGNO
   fprintf_unfiltered (file,
                       "gdbarch_dump: %s # %s\n",
@@ -1474,6 +1489,12 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: regset_from_core_section = <0x%lx>\n",
                       (long) current_gdbarch->regset_from_core_section);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_remote_num_g_packet_regs_p() = %d\n",
+                      gdbarch_remote_num_g_packet_regs_p (current_gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: remote_num_g_packet_regs = %s\n",
+                      paddr_d (current_gdbarch->remote_num_g_packet_regs));
   fprintf_unfiltered (file,
                       "gdbarch_dump: remote_translate_xfer_address = <0x%lx>\n",
                       (long) current_gdbarch->remote_translate_xfer_address);
@@ -1500,6 +1521,12 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: short_bit = %s\n",
                       paddr_d (current_gdbarch->short_bit));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_sim_available_registers_p() = %d\n",
+                      gdbarch_sim_available_registers_p (current_gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: sim_available_registers = <0x%lx>\n",
+                      (long) current_gdbarch->sim_available_registers);
   fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_single_step_through_delay_p() = %d\n",
                       gdbarch_single_step_through_delay_p (current_gdbarch));
@@ -2070,6 +2097,29 @@ set_gdbarch_num_pseudo_regs (struct gdbarch *gdbarch,
   gdbarch->num_pseudo_regs = num_pseudo_regs;
 }
 
+int
+gdbarch_remote_num_g_packet_regs_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->remote_num_g_packet_regs != 0;
+}
+
+int
+gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_remote_num_g_packet_regs called\n");
+  return gdbarch->remote_num_g_packet_regs;
+}
+
+void
+set_gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch,
+                                      int remote_num_g_packet_regs)
+{
+  gdbarch->remote_num_g_packet_regs = remote_num_g_packet_regs;
+}
+
 int
 gdbarch_sp_regnum (struct gdbarch *gdbarch)
 {
@@ -2551,6 +2601,54 @@ set_gdbarch_cannot_store_register (struct gdbarch *gdbarch,
   gdbarch->cannot_store_register = cannot_store_register;
 }
 
+int
+gdbarch_sim_available_registers_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->sim_available_registers != NULL;
+}
+
+char *
+gdbarch_sim_available_registers (struct gdbarch *gdbarch, const struct target_ops *target)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->sim_available_registers != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_sim_available_registers called\n");
+  return gdbarch->sim_available_registers (gdbarch, target);
+}
+
+void
+set_gdbarch_sim_available_registers (struct gdbarch *gdbarch,
+                                     gdbarch_sim_available_registers_ftype sim_available_registers)
+{
+  gdbarch->sim_available_registers = sim_available_registers;
+}
+
+int
+gdbarch_register_remote_regno_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->register_remote_regno != NULL;
+}
+
+int
+gdbarch_register_remote_regno (struct gdbarch *gdbarch, int reg_nr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->register_remote_regno != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_register_remote_regno called\n");
+  return gdbarch->register_remote_regno (reg_nr);
+}
+
+void
+set_gdbarch_register_remote_regno (struct gdbarch *gdbarch,
+                                   gdbarch_register_remote_regno_ftype register_remote_regno)
+{
+  gdbarch->register_remote_regno = register_remote_regno;
+}
+
 int
 gdbarch_get_longjmp_target_p (struct gdbarch *gdbarch)
 {
index 434966f0b33141cbd79b3d92e69619a521630399..d1e8ef7f7f05beaadb4c7535534f08a899aea147 100644 (file)
@@ -355,6 +355,11 @@ extern void set_gdbarch_num_pseudo_regs (struct gdbarch *gdbarch, int num_pseudo
 #define NUM_PSEUDO_REGS (gdbarch_num_pseudo_regs (current_gdbarch))
 #endif
 
+extern int gdbarch_remote_num_g_packet_regs_p (struct gdbarch *gdbarch);
+
+extern int gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch);
+extern void set_gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch, int remote_num_g_packet_regs);
+
 /* GDB's standard (or well known) register numbers.  These can map onto
    a real register or a pseudo (computed) register or not be defined at
    all (-1).
@@ -633,6 +638,22 @@ extern void set_gdbarch_cannot_store_register (struct gdbarch *gdbarch, gdbarch_
 #define CANNOT_STORE_REGISTER(regnum) (gdbarch_cannot_store_register (current_gdbarch, regnum))
 #endif
 
+/* Describe the optional registers provided by the simulator target. */
+
+extern int gdbarch_sim_available_registers_p (struct gdbarch *gdbarch);
+
+typedef char * (gdbarch_sim_available_registers_ftype) (struct gdbarch *gdbarch, const struct target_ops *target);
+extern char * gdbarch_sim_available_registers (struct gdbarch *gdbarch, const struct target_ops *target);
+extern void set_gdbarch_sim_available_registers (struct gdbarch *gdbarch, gdbarch_sim_available_registers_ftype *sim_available_registers);
+
+/* Describe the register numbering used by the remote protocol. */
+
+extern int gdbarch_register_remote_regno_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_register_remote_regno_ftype) (int reg_nr);
+extern int gdbarch_register_remote_regno (struct gdbarch *gdbarch, int reg_nr);
+extern void set_gdbarch_register_remote_regno (struct gdbarch *gdbarch, gdbarch_register_remote_regno_ftype *register_remote_regno);
+
 /* setjmp/longjmp support. */
 
 #if defined (GET_LONGJMP_TARGET)
index fdbc70b2977e761b425dd2cfb347fc577af7b9e0..78804f37d86b92d04f77a698bb90fc0065826e5a 100755 (executable)
@@ -433,6 +433,8 @@ v:=:int:num_regs:::0:-1
 # combinations of other registers, or they may be computed by GDB.
 v:=:int:num_pseudo_regs:::0:0::0
 
+V::int:remote_num_g_packet_regs
+
 # GDB's standard (or well known) register numbers.  These can map onto
 # a real register or a pseudo (computed) register or not be defined at
 # all (-1).
@@ -485,6 +487,10 @@ f:=:int:register_sim_regno:int reg_nr:reg_nr::legacy_register_sim_regno::0
 F:=:int:register_bytes_ok:long nr_bytes:nr_bytes
 f:=:int:cannot_fetch_register:int regnum:regnum::cannot_register_not::0
 f:=:int:cannot_store_register:int regnum:regnum::cannot_register_not::0
+# Describe the optional registers provided by the simulator target.
+M::char *:sim_available_registers:const struct target_ops *target:target
+# Describe the register numbering used by the remote protocol.
+F::int:register_remote_regno:int reg_nr:reg_nr
 # setjmp/longjmp support.
 F:=:int:get_longjmp_target:CORE_ADDR *pc:pc
 #
index f0e4dd368b9680489e9b6724724ed059b955db0c..42e08996eaf538d336f7b53fa2997bf1ecf176e1 100644 (file)
@@ -21,6 +21,7 @@ case "${target}" in
   arm*-*-linux*)       srv_regobj=reg-arm.o
                        srv_tgtobj="linux-low.o linux-arm-low.o"
                        srv_linux_usrregs=yes
+                       srv_linux_regsets=yes
                        srv_linux_thread_db=yes
                        ;;
   crisv32-*-linux*)    srv_regobj=reg-crisv32.o
index 2cbccd9af525b629ee996371179a5217a4c59d2d..9792e2cb472164f734001dcf5766edf39f2f7dd4 100644 (file)
 #define PTRACE_GET_THREAD_AREA 22
 #endif
 
+#include <sys/ptrace.h>
+
+/* Correct for all GNU/Linux targets (for quite some time).  */
+#define GDB_GREGSET_T elf_gregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
+
+#ifndef HAVE_ELF_FPREGSET_T
+/* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
+   via <sys/procfs.h>.  */
+#ifdef HAVE_LINUX_ELF_H   
+#include <linux/elf.h>    
+#endif
+#endif
+   
+#define PTRACE_GETWMMXREGS 18
+#define PTRACE_SETWMMXREGS 19
+
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
 #endif
@@ -89,6 +106,85 @@ arm_breakpoint_at (CORE_ADDR where)
      one.  */
   return 0;
 }
+  
+static void
+arm_fill_gregset (void *buf)
+{
+  int i;
+
+  for (i = 0; i < arm_num_regs; i++)
+    if (arm_regmap[i] != -1)
+      collect_register (i, ((char *) buf) + arm_regmap[i]);
+}
+static void
+arm_store_gregset (const void *buf)
+{
+  int i;
+  char zerobuf[8];
+
+  memset (zerobuf, 0, 8); 
+  for (i = 0; i < arm_num_regs; i++)
+    if (arm_regmap[i] != -1)
+      supply_register (i, ((char *) buf) + arm_regmap[i]);
+    else
+      supply_register (i, zerobuf);
+}
+static void
+arm_fill_wmmxregset (void *buf)
+{
+  int i;
+
+  for (i = 0; i < 16; i++)
+    collect_register (arm_num_regs + i, ((char *) buf) + i * 8);
+  for (i = 0; i < 2; i++)
+    collect_register (arm_num_regs + i + 16 + 2, ((char *) buf) + 16 * 8 + i * 4);
+  for (i = 0; i < 4; i++)
+    collect_register (arm_num_regs + i + 16 + 8, ((char *) buf) + 16 * 8 + 8 + i * 4);
+}
+static void
+arm_store_wmmxregset (const void *buf)
+{
+  int i;
+
+  for (i = 0; i < 16; i++)
+    supply_register (arm_num_regs + i, ((char *) buf) + i * 8);
+  
+  for (i = 0; i < 2; i++)
+    supply_register (arm_num_regs + i + 16 + 2, ((char *) buf) + 16 * 8 + i * 4);
+  for (i = 0; i < 4; i++)
+    supply_register (arm_num_regs + i + 16 + 8, ((char *) buf) + 16 * 8 + 8 + i * 4);
+}
+
+char *
+arm_available_registers (void)
+{
+  char buf[64];
+
+  if (use_regsets_p && target_regsets[1].size > 0)
+    {
+      int wr0 = find_regno ("wr0");
+      sprintf (buf, "iwmmxt:%x", wr0);
+      return strdup (buf);
+    }
+
+  return NULL;
+}
+
+struct regset_info target_regsets[] = {
+  { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+    GENERAL_REGS,
+    arm_fill_gregset, arm_store_gregset },
+  { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
+    EXTENDED_REGS,
+    arm_fill_wmmxregset, arm_store_wmmxregset },
+  { 0, 0, -1, -1, NULL, NULL }
+};
 
 /* We only place breakpoints in empty marker functions, and thread locking
    is outside of the function.  So rather than importing software single-step,
@@ -130,4 +226,5 @@ struct linux_target_ops the_low_target = {
   arm_reinsert_addr,
   0,
   arm_breakpoint_at,
+  arm_available_registers
 };
index 70fab4ffd1f080c4a0237f91513a766ae7f1efe2..7de6fada5c4cfc96c438e91e2e4357ac227464fb 100644 (file)
@@ -68,7 +68,7 @@ struct pending_signals
 #define PTRACE_XFER_TYPE long
 
 #ifdef HAVE_LINUX_REGSETS
-static int use_regsets_p = 1;
+int use_regsets_p = 1;
 #endif
 
 int debug_threads = 0;
@@ -1355,6 +1355,15 @@ linux_store_registers (int regno)
 #endif
 }
 
+static char *
+linux_available_registers (void)
+{
+  if (the_low_target.available_registers == NULL)
+    return NULL;
+  else
+    return (*the_low_target.available_registers) ();
+}
+
 
 /* Copy LEN bytes from inferior's memory starting at MEMADDR
    to debugger memory starting at MYADDR.  */
@@ -1555,6 +1564,7 @@ static struct target_ops linux_target_ops = {
   linux_remove_watchpoint,
   linux_stopped_by_watchpoint,
   linux_stopped_data_address,
+  linux_available_registers,
 };
 
 static void
index 79b1bb71de0d24192f5d32a814beb135fa514c93..80695a2014f8c29cbdbe90aea843edcc2284f064 100644 (file)
@@ -67,10 +67,16 @@ struct linux_target_ops
   /* Whether to left-pad registers for PEEKUSR/POKEUSR if they are smaller
      than an xfer unit.  */
   int left_pad_xfer;
+
+  char *(*available_registers) (void);
 };
 
 extern struct linux_target_ops the_low_target;
 
+#ifdef HAVE_LINUX_REGSETS
+extern int use_regsets_p;
+#endif
+
 #define get_process(inf) ((struct process_info *)(inf))
 #define get_thread_process(thr) (get_process (inferior_target_data (thr)))
 #define get_process_thread(proc) ((struct thread_info *) \
index f1d0fe51f14efe838b67fa953153576bb237f108..ee5591b2e5b60b1e7d6249b0a196e1417b835bc7 100644 (file)
@@ -35,10 +35,10 @@ struct inferior_regcache_data
   unsigned char *registers;
 };
 
-static int register_bytes;
+static int register_bytes, g_register_bytes;
 
 static struct reg *reg_defs;
-static int num_registers;
+int num_registers;
 
 const char **gdbserver_expedite_regs;
 
@@ -91,7 +91,7 @@ regcache_invalidate ()
 int
 registers_length (void)
 {
-  return 2 * register_bytes;
+  return 2 * g_register_bytes;
 }
 
 void *
@@ -124,7 +124,7 @@ free_register_cache (void *regcache_p)
 }
 
 void
-set_register_cache (struct reg *regs, int n)
+set_register_cache (struct reg *regs, const char *last_g_reg, int n)
 {
   int offset, i;
   
@@ -139,6 +139,14 @@ set_register_cache (struct reg *regs, int n)
     }
 
   register_bytes = offset / 8;
+
+  if (last_g_reg == NULL)
+    g_register_bytes = register_bytes;
+  else
+    {
+      int n = find_regno (last_g_reg);
+      g_register_bytes = regs[n].offset + regs[n].size / 8;
+    }
 }
 
 void
@@ -146,7 +154,7 @@ registers_to_string (char *buf)
 {
   unsigned char *registers = get_regcache (current_inferior, 1)->registers;
 
-  convert_int_to_ascii (registers, buf, register_bytes);
+  convert_int_to_ascii (registers, buf, g_register_bytes);
 }
 
 void
@@ -155,11 +163,11 @@ registers_from_string (char *buf)
   int len = strlen (buf);
   unsigned char *registers = get_regcache (current_inferior, 1)->registers;
 
-  if (len != register_bytes * 2)
+  if (len != g_register_bytes * 2)
     {
-      warning ("Wrong sized register packet (expected %d bytes, got %d)", 2*register_bytes, len);
-      if (len > register_bytes * 2)
-       len = register_bytes * 2;
+      warning ("Wrong sized register packet (expected %d bytes, got %d)", 2*g_register_bytes, len);
+      if (len > g_register_bytes * 2)
+       len = g_register_bytes * 2;
     }
   convert_ascii_to_int (buf, registers, len / 2);
 }
@@ -215,6 +223,12 @@ supply_register (int n, const void *buf)
   memcpy (register_data (n, 0), buf, register_size (n));
 }
 
+void
+supply_register_as_string (int n, const char *buf)
+{
+  convert_ascii_to_int (buf, register_data (n, 0), register_size (n));
+}
+
 void
 supply_register_by_name (const char *name, const void *buf)
 {
index 930bd9cbfe6a8b36ee2ebbebfb0f457da6394d01..be4b328f81324afd839ba2fe5325007ccef2778d 100644 (file)
@@ -61,6 +61,8 @@ extern const char **gdbserver_expedite_regs;
 
 void supply_register (int n, const void *buf);
 
+void supply_register_as_string (int n, const char *buf);
+
 void supply_register_by_name (const char *name, const void *buf);
 
 void collect_register (int n, void *buf);
index dfefe2b52a96ee65d523837389ac293f9c4e721f..316dcab3e8c8121ef30f6ce4d41d65f23902af2f 100644 (file)
@@ -143,6 +143,26 @@ handle_query (char *own_buf)
       return;
     }
 
+  if (the_target->available_registers != NULL
+      && strncmp ("qPart:availableRegisters:read::", own_buf, 31) == 0)
+    {
+      char *data;
+      CORE_ADDR ofs;
+      unsigned int len;
+      decode_m_packet (&own_buf[31], &ofs, &len); /* "OFS,LEN" */
+      if (len > sizeof data)
+       len = sizeof data;
+      /* FIXME: Handle OFS, LEN */
+      data = (*the_target->available_registers) ();
+      if (data == NULL || *data == 0)
+       write_ok (own_buf);
+      else
+       convert_int_to_ascii (data, own_buf, strlen (data));
+      if (data)
+       free (data);
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -283,6 +303,41 @@ handle_v_requests (char *own_buf, char *status, int *signal)
   return;
 }
 
+extern int num_registers;
+
+/* Handle a register fetch ('p') request.  */
+void
+handle_p_packet (char *own_buf)
+{
+  char *end = own_buf + 1;
+  int regnum = strtol (own_buf + 1, &end, 16);
+
+  if (*end || regnum < 0 || regnum >= num_registers)
+    {
+      write_enn (own_buf);
+      return;
+    }
+
+  collect_register_as_string (regnum, own_buf);
+  own_buf[2 * register_size (regnum)] = 0;
+}
+
+void
+handle_P_packet (char *own_buf)
+{
+  char *end = own_buf + 1;
+  int regnum = strtol (own_buf + 1, &end, 16);
+
+  if (*end != '=' || regnum < 0 || regnum >= num_registers)
+    {
+      write_enn (own_buf);
+      return;
+    }
+
+  supply_register_as_string (regnum, end + 1);
+  write_ok (own_buf);
+}
+
 void
 myresume (int step, int sig)
 {
@@ -479,6 +534,15 @@ main (int argc, char *argv[])
              registers_from_string (&own_buf[1]);
              write_ok (own_buf);
              break;
+           case 'p':
+             set_desired_inferior (1);
+             handle_p_packet (own_buf);
+             break;
+           case 'P':
+             set_desired_inferior (1);
+             handle_P_packet (own_buf);
+             write_ok (own_buf);
+             break;
            case 'm':
              decode_m_packet (&own_buf[1], &mem_addr, &len);
              if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
index e3a183a9b9cd2e3f4f10356f40e1c3bc0bce0def..dfff3f8eaba36c9ec40bc215533909616005a36d 100644 (file)
@@ -156,6 +156,9 @@ struct target_ops
 
   CORE_ADDR (*stopped_data_address) (void);
 
+  /* Return a string describing the optional available registers,
+     or NULL if there are none.  */
+  char *(*available_registers) (void);
 };
 
 extern struct target_ops *the_target;
index 5d7750d65bd152ac4f5853d38ddf96b45eecea85..836c77d2792554bcbbb1a64d8ae10983cf9a82cd 100644 (file)
@@ -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;
     }
index 5a600258239325204cc46db56d42ff23bf68e9e4..9edba2fb4550996a6592b1d76e17ba686c5a899f 100644 (file)
@@ -1,5 +1,6 @@
 name:arm
 expedite:r11,sp,pc
+last_g_reg:cpsr
 32:r0
 32:r1
 32:r2
@@ -26,3 +27,35 @@ expedite:r11,sp,pc
 96:f7
 32:fps
 32:cpsr
+64:wr0
+64:wr1
+64:wr2
+64:wr3
+64:wr4
+64:wr5
+64:wr6
+64:wr7
+64:wr8
+64:wr9
+64:wr10
+64:wr11
+64:wr12
+64:wr13
+64:wr14
+64:wr15
+32:wcid
+32:wcon
+32:wcssf
+32:wcasf
+32:
+32:
+32:
+32:
+32:wcgr0
+32:wcgr1
+32:wcgr2
+32:wcgr3
+32:
+32:
+32:
+32:
index 9035b3dc90d7367e14467b4dd1fec2700fd75b52..d779f4d695465abf42038b6cb94be54917bf0e42 100755 (executable)
@@ -129,6 +129,7 @@ offset=0
 i=0
 name=x
 expedite=x
+last_g_reg=NULL
 exec < $1
 while do_read
 do
@@ -139,6 +140,9 @@ do
   elif test "${type}" = "expedite"; then
     expedite="${entry}"
     continue
+  elif test "${type}" = "last_g_reg"; then
+    last_g_reg="\"${entry}\""
+    continue
   elif test "${name}" = x; then
     echo "$0: $1 does not specify \`\`name''." 1>&2
     exit 1
@@ -152,13 +156,14 @@ done
 echo "};"
 echo
 echo "const char *expedite_regs_${name}[] = { \"`echo ${expedite} | sed 's/,/", "/g'`\", 0 };"
+echo "const char *last_g_reg_${name} = $last_g_reg;"
 echo
 
 cat <<EOF
 void
 init_registers ()
 {
-    set_register_cache (regs_${name},
+    set_register_cache (regs_${name}, last_g_reg_${name},
                        sizeof (regs_${name}) / sizeof (regs_${name}[0]));
     gdbserver_expedite_regs = expedite_regs_${name};
 }
index c1f862cc356ee89018daf3e4f6014d960ece9799..8d5d3cb0f5198ba4225a3182e89011f035748aed 100644 (file)
@@ -39,8 +39,9 @@ struct reg
 };
 
 /* Set the current remote protocol and register cache according to the array
-   ``regs'', with ``n'' elements.  */
+   ``regs'', with ``n'' elements.  If non-NULL, LAST_G_REG is the last
+   register to include in g/G packets.  */
 
-void set_register_cache (struct reg *regs, int n);
+void set_register_cache (struct reg *regs, const char *last_g_reg, int n);
 
 #endif /* REGDEF_H */
index d54bcfb8379a9450c1a5f1bc5a0b33cb4aa0978a..2d8ef7e513a1f0f4486749638f7749131c91dded 100644 (file)
@@ -458,6 +458,12 @@ gdbsim_create_inferior (char *exec_file, char *args, char **env, int from_tty)
     argv = NULL;
   sim_create_inferior (gdbsim_desc, exec_bfd, argv, env);
 
+  /* This doesn't seem like quite the right place... it would
+     be nice to have an inferior_created in a central location,
+     and a separate "target connected" observer for the ARM
+     registers hook.  */
+  observer_notify_inferior_created (current_target, from_tty);
+
   inferior_ptid = pid_to_ptid (42);
   insert_breakpoints ();       /* Needed to get correct instruction in cache */
 
@@ -772,6 +778,69 @@ gdbsim_xfer_inferior_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
   return len;
 }
 
+/* Implement xfer_partial for the simulator.  */
+static LONGEST
+gdbsim_xfer_partial (struct target_ops *ops, enum target_object object,
+                    const char *annex, void *readbuf, const void *writebuf,
+                    ULONGEST offset, LONGEST len)
+{
+  /* Handle memory using remote_xfer_memory.  */
+  if (object == TARGET_OBJECT_MEMORY)
+    {
+      int xfered;
+      errno = 0;
+
+      if (writebuf != NULL)
+       {
+         void *buffer = xmalloc (len);
+         struct cleanup *cleanup = make_cleanup (xfree, buffer);
+         memcpy (buffer, writebuf, len);
+         xfered = gdbsim_xfer_inferior_memory (offset, buffer, len, 1, NULL, ops);
+         do_cleanups (cleanup);
+       }
+      else
+       xfered = gdbsim_xfer_inferior_memory (offset, readbuf, len, 0, NULL, ops);
+
+      if (xfered > 0)
+       return xfered;
+      else if (xfered == 0 && errno == 0)
+       return 0;
+      else
+       return -1;
+    }
+
+  /* Only handle reads.  */
+  if (writebuf != NULL || readbuf == NULL)
+    return -1;
+
+  switch (object)
+    {
+    case TARGET_OBJECT_AVAILABLE_REGISTERS:
+      /* FIXME: Should this be a NULL terminated string or a binary blob
+        without trailing NUL?  */
+      if (gdbarch_sim_available_registers_p (current_gdbarch))
+       {
+         char *result = gdbarch_sim_available_registers (current_gdbarch, ops);
+         int total_len = strlen (result);
+         int bytes_read;
+
+         if (total_len > offset)
+           {
+             bytes_read = min (total_len - offset, len);
+             memcpy (readbuf, result + offset, bytes_read);
+             xfree (result);
+             return bytes_read;
+           }
+
+         xfree (result);
+         return 0;
+       }
+
+    default:
+      return -1;
+    }
+}
+
 static void
 gdbsim_files_info (struct target_ops *target)
 {
@@ -862,7 +931,8 @@ init_gdbsim_ops (void)
   gdbsim_ops.to_fetch_registers = gdbsim_fetch_register;
   gdbsim_ops.to_store_registers = gdbsim_store_register;
   gdbsim_ops.to_prepare_to_store = gdbsim_prepare_to_store;
-  gdbsim_ops.deprecated_xfer_memory = gdbsim_xfer_inferior_memory;
+  /* gdbsim_ops.deprecated_xfer_memory = gdbsim_xfer_inferior_memory; */
+  gdbsim_ops.to_xfer_partial = gdbsim_xfer_partial;
   gdbsim_ops.to_files_info = gdbsim_files_info;
   gdbsim_ops.to_insert_breakpoint = gdbsim_insert_breakpoint;
   gdbsim_ops.to_remove_breakpoint = gdbsim_remove_breakpoint;
index 8113674f55508b193310f4960d43053576254859..846e329fd63307ba2fb421cfed6fba86ea5a5308 100644 (file)
@@ -210,9 +210,10 @@ struct remote_state
 {
   /* Description of the remote protocol registers.  */
   long sizeof_g_packet;
+  long num_g_regs;
 
   /* Description of the remote protocol registers indexed by REGNUM
-     (making an array of NUM_REGS + NUM_PSEUDO_REGS in size).  */
+     (making an array NUM_REGS in size).  */
   struct packet_reg *regs;
 
   /* This is the size (in chars) of the first response to the ``g''
@@ -243,24 +244,33 @@ init_remote_state (struct gdbarch *gdbarch)
 {
   int regnum;
   struct remote_state *rs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_state);
+  int num_g_regs;
+
+  if (gdbarch_remote_num_g_packet_regs_p (gdbarch))
+    num_g_regs = gdbarch_remote_num_g_packet_regs (gdbarch);
+  else
+    num_g_regs = NUM_REGS;
 
   rs->sizeof_g_packet = 0;
 
   /* Assume a 1:1 regnum<->pnum table.  */
-  rs->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS + NUM_PSEUDO_REGS,
-                                    struct packet_reg);
-  for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+  rs->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS, struct packet_reg);
+  for (regnum = 0; regnum < NUM_REGS; regnum++)
     {
       struct packet_reg *r = &rs->regs[regnum];
-      r->pnum = regnum;
+
+      if (gdbarch_register_remote_regno_p (gdbarch))
+       r->pnum = gdbarch_register_remote_regno (gdbarch, regnum);
+      else
+       r->pnum = regnum;
+
       r->regnum = regnum;
       r->offset = DEPRECATED_REGISTER_BYTE (regnum);
-      r->in_g_packet = (regnum < NUM_REGS);
+      r->in_g_packet = (regnum < num_g_regs);
       /* ...name = REGISTER_NAME (regnum); */
 
       /* Compute packet size by accumulating the size of all registers.  */
-      if (regnum < NUM_REGS)
-       rs->sizeof_g_packet += register_size (current_gdbarch, regnum);
+      rs->sizeof_g_packet += register_size (current_gdbarch, regnum);
     }
 
   /* Default maximum number of characters in a packet body. Many
@@ -290,7 +300,7 @@ init_remote_state (struct gdbarch *gdbarch)
 static struct packet_reg *
 packet_reg_from_regnum (struct remote_state *rs, long regnum)
 {
-  if (regnum < 0 && regnum >= NUM_REGS + NUM_PSEUDO_REGS)
+  if (regnum < 0 && regnum >= NUM_REGS)
     return NULL;
   else
     {
@@ -304,7 +314,7 @@ static struct packet_reg *
 packet_reg_from_pnum (struct remote_state *rs, LONGEST pnum)
 {
   int i;
-  for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+  for (i = 0; i < NUM_REGS; i++)
     {
       struct packet_reg *r = &rs->regs[i];
       if (r->pnum == pnum)
@@ -978,6 +988,26 @@ show_remote_protocol_qGetTLSAddr_packet_cmd (struct ui_file *file, int from_tty,
   show_packet_config_cmd (&remote_protocol_qGetTLSAddr);
 }
 
+/* FIXME: Kill these duplicated functions.  */
+/* Should we try the 'qPart:availableRegisters' request? */
+static struct packet_config remote_protocol_qPart_availableRegisters;
+
+static void
+set_remote_protocol_qPart_availableRegisters_packet_cmd (char *args, int from_tty,
+                                          struct cmd_list_element *c)
+{
+  update_packet_config (&remote_protocol_qPart_availableRegisters);
+}
+
+static void
+show_remote_protocol_qPart_availableRegisters_packet_cmd (struct ui_file *file, int from_tty,
+                                           struct cmd_list_element *c,
+                                           const char * value)
+{
+  deprecated_show_value_hack (file, from_tty, c, value);
+  show_packet_config_cmd (&remote_protocol_qPart_availableRegisters);
+}
+
 static struct packet_config remote_protocol_p;
 
 static void
@@ -2109,6 +2139,7 @@ init_all_packet_configs (void)
   update_packet_config (&remote_protocol_binary_download);
   update_packet_config (&remote_protocol_qPart_auxv);
   update_packet_config (&remote_protocol_qGetTLSAddr);
+  update_packet_config (&remote_protocol_qPart_availableRegisters);
 }
 
 /* Symbol look-up.  */
@@ -3213,60 +3244,69 @@ got_status:
   return inferior_ptid;
 }
 
-/* Number of bytes of registers this stub implements.  */
-
-static int register_bytes_found;
-
-/* Read the remote registers into the block REGS.  */
-/* Currently we just read all the registers, so we don't use regnum.  */
+/* Fetch a single register using a 'p' packet.  */
 
 static int
-fetch_register_using_p (int regnum)
+fetch_register_using_p (struct packet_reg *reg)
 {
   struct remote_state *rs = get_remote_state ();
   char *buf = alloca (rs->remote_packet_size), *p;
   char regp[MAX_REGISTER_SIZE];
   int i;
 
+  if (remote_protocol_p.support == PACKET_DISABLE)
+    return 0;
+
   p = buf;
   *p++ = 'p';
-  p += hexnumstr (p, regnum);
+  p += hexnumstr (p, reg->pnum);
   *p++ = '\0';
   remote_send (buf, rs->remote_packet_size);
 
-  /* If the stub didn't recognize the packet, or if we got an error,
-     tell our caller.  */
-  if (buf[0] == '\0' || buf[0] == 'E')
-    return 0;
+  if (buf[0] == 0)
+    {
+      if (remote_protocol_p.support == PACKET_ENABLE)
+       error ("Protocol error: p packet enabled but not recognized by stub");
+      else
+       {
+         /* The stub does not support the 'P' packet.  Use 'G'
+            instead, and don't try using 'P' in the future (it
+            will just waste our time).  */
+         remote_protocol_p.support = PACKET_DISABLE;
+         return 0;
+       }
+      }
+  
+  remote_protocol_p.support = PACKET_ENABLE;
 
-  /* If this register is unfetchable, tell the regcache.  */
   if (buf[0] == 'x')
     {
-      regcache_raw_supply (current_regcache, regnum, NULL);
-      set_register_cached (regnum, -1);
+      regcache_raw_supply (current_regcache, reg->regnum, NULL);
+      set_register_cached (reg->regnum, -1);
       return 1;
     }
 
-  /* Otherwise, parse and supply the value.  */
   p = buf;
   i = 0;
   while (p[0] != 0)
     {
       if (p[1] == 0)
-        {
-          error (_("fetch_register_using_p: early buf termination"));
-          return 0;
-        }
-
+       error("fetch_register_using_p: early buf termination");
       regp[i++] = fromhex (p[0]) * 16 + fromhex (p[1]);
       p += 2;
     }
-  regcache_raw_supply (current_regcache, regnum, regp);
+  regcache_raw_supply (current_regcache, reg->regnum, regp);
   return 1;
 }
 
+/* Number of bytes of registers this stub implements.  */
+
+static int register_bytes_found;
+
+/* Fetch the registers included in the target's 'g' packet.  */
+
 static void
-remote_fetch_registers (int regnum)
+fetch_registers_using_g (void)
 {
   struct remote_state *rs = get_remote_state ();
   char *buf = alloca (rs->remote_packet_size);
@@ -3276,41 +3316,6 @@ remote_fetch_registers (int regnum)
 
   set_thread (PIDGET (inferior_ptid), 1);
 
-  if (regnum >= 0)
-    {
-      struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
-      gdb_assert (reg != NULL);
-      if (!reg->in_g_packet)
-       internal_error (__FILE__, __LINE__,
-                       _("Attempt to fetch a non G-packet register when this "
-                       "remote.c does not support the p-packet."));
-    }
-      switch (remote_protocol_p.support)
-       {
-       case PACKET_DISABLE:
-         break;
-       case PACKET_ENABLE:
-         if (fetch_register_using_p (regnum))
-           return;
-         else
-           error (_("Protocol error: p packet not recognized by stub"));
-       case PACKET_SUPPORT_UNKNOWN:
-         if (fetch_register_using_p (regnum))
-           {
-             /* The stub recognized the 'p' packet.  Remember this.  */
-             remote_protocol_p.support = PACKET_ENABLE;
-             return;
-           }
-         else
-           {
-             /* The stub does not support the 'P' packet.  Use 'G'
-                instead, and don't try using 'P' in the future (it
-                will just waste our time).  */
-             remote_protocol_p.support = PACKET_DISABLE;
-             break;
-           }
-       }
-
   sprintf (buf, "g");
   remote_send (buf, (rs->remote_packet_size));
 
@@ -3371,7 +3376,7 @@ remote_fetch_registers (int regnum)
  supply_them:
   {
     int i;
-    for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+    for (i = 0; i < NUM_REGS; i++)
       {
        struct packet_reg *r = &rs->regs[i];
        if (r->in_g_packet)
@@ -3398,6 +3403,38 @@ remote_fetch_registers (int regnum)
   }
 }
 
+static void
+remote_fetch_registers (int regnum)
+{
+  struct remote_state *rs = get_remote_state ();
+  int i;
+
+  set_thread (PIDGET (inferior_ptid), 1);
+
+  if (regnum >= 0)
+    {
+      struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
+      gdb_assert (reg != NULL);
+
+      if (fetch_register_using_p (reg))
+       return;
+
+      if (!reg->in_g_packet)
+       error ("Protocol error: register %ld not supported by stub", reg->regnum);
+
+      fetch_registers_using_g ();
+      return;
+    }
+
+  fetch_registers_using_g ();
+
+  for (i = 0; i < NUM_REGS; i++)
+    if (!rs->regs[i].in_g_packet)
+      if (!fetch_register_using_p (&rs->regs[i]))
+       error ("Protocol error: register %ld not supported by stub",
+              rs->regs[i].regnum);
+}
+
 /* Prepare to store registers.  Since we may send them all (using a
    'G' request), we have to read out the ones we don't want to change
    first.  */
@@ -3428,74 +3465,58 @@ remote_prepare_to_store (void)
    packet was not recognized.  */
 
 static int
-store_register_using_P (int regnum)
+store_register_using_P (struct packet_reg *reg)
 {
   struct remote_state *rs = get_remote_state ();
-  struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
   /* Try storing a single register.  */
   char *buf = alloca (rs->remote_packet_size);
   char regp[MAX_REGISTER_SIZE];
   char *p;
 
+  if (remote_protocol_P.support == PACKET_DISABLE)
+    return 0;
+
   xsnprintf (buf, rs->remote_packet_size, "P%s=", phex_nz (reg->pnum, 0));
   p = buf + strlen (buf);
   regcache_raw_collect (current_regcache, reg->regnum, regp);
   bin2hex (regp, p, register_size (current_gdbarch, reg->regnum));
   remote_send (buf, rs->remote_packet_size);
 
-  return buf[0] != '\0';
+  if (buf[0] == 0)
+    {
+      if (remote_protocol_P.support == PACKET_ENABLE)
+       error ("Protocol error: P packet enabled but not recognized by stub");
+      else
+       {
+         /* The stub does not support the 'P' packet.  Use 'G'
+            instead, and don't try using 'P' in the future (it
+            will just waste our time).  */
+         remote_protocol_P.support = PACKET_DISABLE;
+         return 0;
+       }
+    }
+  
+  return 1;
 }
 
-
 /* Store register REGNUM, or all registers if REGNUM == -1, from the
    contents of the register cache buffer.  FIXME: ignores errors.  */
 
-static void
-remote_store_registers (int regnum)
+void
+store_registers_using_G (void)
 {
   struct remote_state *rs = get_remote_state ();
   char *buf;
   char *regs;
   char *p;
 
-  set_thread (PIDGET (inferior_ptid), 1);
-
-  if (regnum >= 0)
-    {
-      switch (remote_protocol_P.support)
-       {
-       case PACKET_DISABLE:
-         break;
-       case PACKET_ENABLE:
-         if (store_register_using_P (regnum))
-           return;
-         else
-           error (_("Protocol error: P packet not recognized by stub"));
-       case PACKET_SUPPORT_UNKNOWN:
-         if (store_register_using_P (regnum))
-           {
-             /* The stub recognized the 'P' packet.  Remember this.  */
-             remote_protocol_P.support = PACKET_ENABLE;
-             return;
-           }
-         else
-           {
-             /* The stub does not support the 'P' packet.  Use 'G'
-                instead, and don't try using 'P' in the future (it
-                will just waste our time).  */
-             remote_protocol_P.support = PACKET_DISABLE;
-             break;
-           }
-       }
-    }
-
   /* Extract all the registers in the regcache copying them into a
      local buffer.  */
   {
     int i;
     regs = alloca (rs->sizeof_g_packet);
     memset (regs, 0, rs->sizeof_g_packet);
-    for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+    for (i = 0; i < NUM_REGS; i++)
       {
        struct packet_reg *r = &rs->regs[i];
        if (r->in_g_packet)
@@ -4456,6 +4477,41 @@ extended_remote_async_create_inferior (char *exec_file, char *args,
   /* Let the remote process run.  */
   proceed (-1, TARGET_SIGNAL_0, 0);
 }
+
+/* Store register REGNUM, or all registers if REGNUM == -1, from the contents
+   of the register cache buffer.  FIXME: ignores errors.  */
+
+static void
+remote_store_registers (int regnum)
+{
+  struct remote_state *rs = get_remote_state ();
+  int i;
+
+  set_thread (PIDGET (inferior_ptid), 1);
+
+  if (regnum >= 0)
+    {
+      struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
+      gdb_assert (reg != NULL);
+
+      if (store_register_using_P (reg))
+       return;
+
+      if (!reg->in_g_packet)
+       error ("Protocol error: register %ld not supported by stub", reg->regnum);
+
+      store_registers_using_G ();
+      return;
+    }
+
+  store_registers_using_G ();
+
+  for (i = 0; i < NUM_REGS; i++)
+    if (!rs->regs[i].in_g_packet)
+      if (!store_register_using_P (&rs->regs[i]))
+       error ("Protocol error: register %ld not supported by stub",
+              rs->regs[i].regnum);
+}
 \f
 
 /* On some machines, e.g. 68k, we may use a different breakpoint
@@ -5035,6 +5091,44 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
        }
       return -1;
 
+      /* FIXME:
+        - Currently hex encoded.  Should this be just a string?
+        - One way or another remove the copy/paste.
+      */
+    case TARGET_OBJECT_AVAILABLE_REGISTERS:
+      if (remote_protocol_qPart_availableRegisters.support != PACKET_DISABLE)
+       {
+         unsigned int total = 0;
+         while (len > 0)
+           {
+             LONGEST n = min ((rs->remote_packet_size - 2) / 2, len);
+             snprintf (buf2, rs->remote_packet_size,
+                       "qPart:availableRegisters:read::%s,%s",
+                       phex_nz (offset, sizeof offset),
+                       phex_nz (n, sizeof n));
+             i = putpkt (buf2);
+             if (i < 0)
+               return total > 0 ? total : i;
+             buf2[0] = '\0';
+             getpkt (buf2, rs->remote_packet_size, 0);
+             if (packet_ok (buf2, &remote_protocol_qPart_availableRegisters) != PACKET_OK)
+               return total > 0 ? total : -1;
+             if (buf2[0] == 'O' && buf2[1] == 'K' && buf2[2] == '\0')
+               break;          /* Got EOF indicator.  */
+             /* Got some data.  */
+             i = hex2bin (buf2, readbuf, len);
+             if (i > 0)
+               {
+                 readbuf = (void *) ((char *) readbuf + i);
+                 offset += i;
+                 len -= i;
+                 total += i;
+               }
+           }
+         return total;
+       }
+      return -1;
+
     default:
       return -1;
     }
@@ -5583,6 +5677,7 @@ show_remote_cmd (char *args, int from_tty)
   show_remote_protocol_binary_download_cmd (gdb_stdout, from_tty, NULL, NULL);
   show_remote_protocol_qPart_auxv_packet_cmd (gdb_stdout, from_tty, NULL, NULL);
   show_remote_protocol_qGetTLSAddr_packet_cmd (gdb_stdout, from_tty, NULL, NULL);
+  show_remote_protocol_qPart_availableRegisters_packet_cmd (gdb_stdout, from_tty, NULL, NULL);
 }
 
 static void
@@ -5819,6 +5914,13 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
                         &remote_set_cmdlist, &remote_show_cmdlist,
                         0);
 
+  add_packet_config_cmd (&remote_protocol_qPart_availableRegisters,
+                        "qPart_availableRegisters", "available-registers",
+                        set_remote_protocol_qPart_availableRegisters_packet_cmd,
+                        show_remote_protocol_qPart_availableRegisters_packet_cmd,
+                        &remote_set_cmdlist, &remote_show_cmdlist,
+                        0);
+
   /* Keep the old ``set remote Z-packet ...'' working.  */
   add_setshow_auto_boolean_cmd ("Z-packet", class_obscure,
                                &remote_Z_packet_detect, _("\
index f1de230c4632c1b606600a7b711b32febdebc58f..fd565ac86342dc2246e56129fb16471ffe8a0c26 100644 (file)
@@ -229,7 +229,10 @@ enum target_object
   /* Transfer auxilliary vector.  */
   TARGET_OBJECT_AUXV,
   /* StackGhost cookie.  See "sparc-tdep.c".  */
-  TARGET_OBJECT_WCOOKIE
+  TARGET_OBJECT_WCOOKIE,
+  /* A target-specific description of the available registers on
+     the target.  */
+  TARGET_OBJECT_AVAILABLE_REGISTERS
 
   /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
 };