[csl-arm] VFP and iWMMXt support

Paul Brook
2005-03-29T02:52:39Z

[-- Attachment #1: Type: text/plain, Size: 5004 bytes --]

I've applied the attached patch to the csl-arm-20050325-branch.

It adds support for the iWMMXt and VFP Arm coprocessors.
This includes a new extension to the remote protocol to handle optional
register sets. The extension may need some more work before it's ready for
mainline.

Tested with cross to arm-none-eabi.

Paul

2005-03-28 Paul Brook <paul@codesourcery.com>
Daniel Jacobowitz <dan@codesourcery.com>

* Makefile.in: arm-tdep.o depends on $(observer_h).
* 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.
* arm-linux-tdep.c (arm_linux_init_abi): Provide ABI specific
overrides.
* 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.
* 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.
* 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.
* gdbarch.h: Add prototypes.
* gdbarch.sh: Add new fields.
(deprecated_current_gdbarch_select_hack): Call flush_cached_frames.
* remote-sim.h (gdbsim_create_inferior): Call
observer_notify_inferior_created.
(gdbsim_xfer_partial): New function.
(init_gdbsim_ops): Use it.
* 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.
* target.h (enum target_object): Add
TARGET_OBJECT_AVAILABLE_REGISTERS.
* gdbserver/configure.srv (arm*-*-linux*): set srv_linux_regsets=yes.
* 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.
* gdbserver/linux-low.c (linux_available_registers): New function.
(linux_target_op): Use it.
* gdbserver/linux-low.h (gdbserver/linux-low.h): Add
available_registers.
(use_regsets_p): Declare.
* 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.
* gdbserver/regcache.h (supply_register_as_string): Add prototype.
* gdbserver/server.c (handle_query): Handle qPart:availableRegisters.
(handle_p_packet, handle_P_packet): New functions.
(main): Handle 'p' and 'P' packets.
* gdbserver/target.h (struct target_ops): Add available_registers.
* regformats/reg-arm.dat: Add last_g_reg and iWMMXT regs.
* regformats/regdat.sh: Handle last_g_reg.
* regformats/regdef.h (set_register_cache): Update prototype.

[-- Attachment #2: patch.gdb_vfp --]
[-- Type: text/x-diff, Size: 73038 bytes --]

? p
? bfd/doc/bfd.info
? gdb/p
? gdb/testsuite/config/simstub.exp
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.707.2.3
diff -u -p -r1.707.2.3 Makefile.in
--- gdb/Makefile.in 28 Mar 2005 18:31:41 -0000 1.707.2.3
+++ gdb/Makefile.in 29 Mar 2005 02:49:24 -0000
@@ -1747,7 +1747,7 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame
$(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)
+ $(observer_h) $(dwarf2_frame_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: gdb/arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.22.2.2
diff -u -p -r1.22.2.2 arm-linux-nat.c
--- gdb/arm-linux-nat.c 25 Mar 2005 22:20:48 -0000 1.22.2.2
+++ gdb/arm-linux-nat.c 29 Mar 2005 02:49:24 -0000
@@ -231,7 +231,7 @@ store_nwfpe_register (int regno, 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;
@@ -280,7 +280,7 @@ fetch_fpregister (int regno)
into regcache. */

static void
-fetch_fpregs (void)
+fetch_fpa_regs (void)
{
int ret, regno, tid;
FPA11 fp;
@@ -328,7 +328,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;
@@ -366,7 +366,7 @@ store_fpregister (int regno)
the contents from regcache. */

static void
-store_fpregs (void)
+store_fpa_regs (void)
{
int ret, regno, tid;
FPA11 fp;
@@ -560,7 +560,7 @@ fetch_inferior_registers (int regno)
if (-1 == regno)
{
fetch_regs ();
- fetch_fpregs ();
+ fetch_fpa_regs ();
}
else
{
@@ -568,7 +568,7 @@ fetch_inferior_registers (int regno)
fetch_register (regno);

if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
- fetch_fpregister (regno);
+ fetch_fpa_register (regno);
}
}

@@ -582,7 +582,7 @@ store_inferior_registers (int regno)
if (-1 == regno)
{
store_regs ();
- store_fpregs ();
+ store_fpa_regs ();
}
else
{
@@ -590,7 +590,7 @@ store_inferior_registers (int regno)
store_register (regno);

if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
- store_fpregister (regno);
+ store_fpa_register (regno);
}
}

Index: gdb/arm-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-tdep.c,v
retrieving revision 1.44.2.2
diff -u -p -r1.44.2.2 arm-linux-tdep.c
--- gdb/arm-linux-tdep.c 25 Mar 2005 22:02:36 -0000 1.44.2.2
+++ gdb/arm-linux-tdep.c 29 Mar 2005 02:49:24 -0000
@@ -481,9 +481,21 @@ arm_linux_init_abi (struct gdbarch_info
tdep->arm_breakpoint_size = sizeof (arm_linux_arm_le_breakpoint);
tdep->thumb_breakpoint_size = sizeof (arm_linux_thumb_le_breakpoint);

- tdep->fp_model = ARM_FLOAT_FPA;
+ if (tdep->abi == ARM_ABI_APCS_GNU)
+ {
+ /* The following two overrides shouldn't be needed. */
+ set_gdbarch_deprecated_extract_return_value (gdbarch,
+ arm_linux_extract_return_value);
+ set_gdbarch_deprecated_push_arguments (gdbarch,
+ arm_linux_push_arguments);

- tdep->jb_pc = ARM_LINUX_JB_PC;
+ tdep->fp_model = ARM_FLOAT_FPA;
+ tdep->jb_pc = ARM_LINUX_JB_PC;
+ }
+ else
+ {
+ tdep->jb_pc = ARM_LINUX_EABI_JB_PC;
+ }
tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE;

set_solib_svr4_fetch_link_map_offsets
Index: gdb/arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.194.2.3
diff -u -p -r1.194.2.3 arm-tdep.c
--- gdb/arm-tdep.c 25 Mar 2005 22:02:37 -0000 1.194.2.3
+++ gdb/arm-tdep.c 29 Mar 2005 02:49:24 -0000
@@ -38,6 +38,7 @@
#include "frame-base.h"
#include "trad-frame.h"
#include "objfiles.h"
+#include "observer.h"
#include "dwarf2-frame.h"

#include "arm-tdep.h"
@@ -51,6 +52,19 @@

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.

@@ -1301,23 +1315,23 @@ arm_push_dummy_call (struct gdbarch *gdb
typecode = TYPE_CODE (arg_type);
val = value_contents_writeable (args[argnum]);

+ align = arm_type_align (arg_type);
+ /* Round alignment up to a whole number of words. */
+ align = (align + INT_REGISTER_SIZE - 1) & ~(INT_REGISTER_SIZE - 1);
+ /* Different ABIs have different maximum alignments. */
if (gdbarch_tdep (gdbarch)->abi == ARM_ABI_APCS_GNU)
{
- /* The old APCS ABI does not require doubleword alignment. */
+ /* The APCS ABI only requires word alignment. */
align = INT_REGISTER_SIZE;
}
else
{
- align = arm_type_align (arg_type);
-
- /* Round alignment up to one or two words. */
- align = (align + INT_REGISTER_SIZE - 1) & ~(INT_REGISTER_SIZE - 1);
-
- gdb_assert (align == INT_REGISTER_SIZE
- || align == INT_REGISTER_SIZE * 2);
+ /* The AAPCS requires at most doubleword alignment. */
+ if (align > INT_REGISTER_SIZE * 2)
+ align = INT_REGISTER_SIZE * 2;
}

- /* Push stack padding for dowubleword alignment. */
+ /* Push stack padding for doubleword alignment. */
if (nstack & (align - 1))
{
si = push_stack_item (si, val, INT_REGISTER_SIZE);
@@ -1447,7 +1461,42 @@ arm_print_float_info (struct gdbarch *gd
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;
@@ -1464,15 +1513,162 @@ arm_register_type (struct gdbarch *gdbar
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. */
@@ -1482,13 +1678,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;
@@ -1497,6 +1701,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 *t
/* 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,
@@ -2550,9 +2783,59 @@ set_disassembly_style_sfunc (char *args,
\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
@@ -2727,6 +3010,70 @@ arm_elf_osabi_sniffer: Unknown ARM EABI

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,
@@ -2741,12 +3088,15 @@ arm_gdbarch_init (struct gdbarch_info in
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
+ struct gdbarch_list *best_arch;
+ int nregs;
+ int pseudos;

/* Try to deterimine the ABI of the object we are loading. */

if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
{
- switch (bfd_get_flavour (info.abfd))
+ switch (bfd_get_flavour (info.abfd))
{
case bfd_target_aout_flavour:
/* Assume it's an old APCS-style ABI. */
@@ -2765,15 +3115,45 @@ arm_gdbarch_init (struct gdbarch_info in
}
}

+ /* FIXME drow/2005-03-11: For consistency, if there is not a BFD,
+ should we inherit info.osabi from the last ARM architecture? */
+
/* If there is already a candidate, use it. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return arches->gdbarch;
+ for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+ 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;
+ }
+
+ /* Found a match. */
+ break;
+ }
+
+ if (best_arch != NULL)
+ return best_arch->gdbarch;

- tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);

- if (info.osabi == GDB_OSABI_ARM_EABI_V4 || info.osabi == GDB_OSABI_ARM_EABI_V4_LINUX)
+ if (info.osabi == GDB_OSABI_ARM_EABI_V4
+ || info.osabi == GDB_OSABI_ARM_EABI_V4_LINUX)
{
/* Default EABI targets to soft-vfp. */
tdep->fp_model = ARM_FLOAT_SOFT_VFP;
@@ -2788,6 +3168,35 @@ arm_gdbarch_init (struct gdbarch_info in
tdep->abi = ARM_ABI_APCS_GNU;
}

+ 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)
{
@@ -2809,7 +3218,7 @@ arm_gdbarch_init (struct gdbarch_info in

default:
internal_error (__FILE__, __LINE__,
- _("arm_gdbarch_init: bad byte order for float format"));
+ _("arm_gdbarch_init: bad byte order"));
}

/* On ARM targets char defaults to unsigned. */
@@ -2853,12 +3262,49 @@ arm_gdbarch_init (struct gdbarch_info in
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);
@@ -3074,4 +3520,6 @@ vfp - VFP co-processor."),
NULL,
NULL, /* FIXME: i18n: "ARM debugging is %s. */
&setdebuglist, &showdebuglist);
+
+ observer_attach_inferior_created (arm_update_architecture);
}
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.12.8.1
diff -u -p -r1.12.8.1 arm-tdep.h
--- gdb/arm-tdep.h 25 Mar 2005 22:02:37 -0000 1.12.8.1
+++ gdb/arm-tdep.h 29 Mar 2005 02:49:24 -0000
@@ -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_variant
/* 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. */
+
enum arm_float_model fp_model; /* Floating point calling conventions. */

CORE_ADDR lowest_pc; /* Lowest address at which instructions
@@ -141,6 +172,17 @@ struct gdbarch_tdep
size_t jb_elt_size; /* And the size of each entry in the buf. */

enum arm_abi_variant abi; /* Which abi variant is in use. */
+
+ 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: gdb/gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.321
diff -u -p -r1.321 gdbarch.c
--- gdb/gdbarch.c 24 Feb 2005 13:51:31 -0000 1.321
+++ gdb/gdbarch.c 29 Mar 2005 02:49:24 -0000
@@ -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;
@@ -178,6 +179,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 */
@@ -304,6 +308,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_
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 */
@@ -560,6 +567,8 @@ verify_gdbarch (struct gdbarch *current_
/* 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_gd
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",
@@ -1475,6 +1490,12 @@ gdbarch_dump (struct gdbarch *current_gd
"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);
fprintf_unfiltered (file,
@@ -1501,6 +1522,12 @@ gdbarch_dump (struct gdbarch *current_gd
"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));
fprintf_unfiltered (file,
@@ -2071,6 +2098,29 @@ set_gdbarch_num_pseudo_regs (struct gdba
}

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)
{
gdb_assert (gdbarch != NULL);
@@ -2576,6 +2626,54 @@ set_gdbarch_cannot_store_register (struc
}

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)
{
gdb_assert (gdbarch != NULL);
@@ -4196,6 +4294,7 @@ deprecated_current_gdbarch_select_hack (
current_gdbarch_swap_out_hack ();
current_gdbarch_swap_in_hack (new_gdbarch);
architecture_changed_event ();
+ flush_cached_frames (); /* FIXME should this be attached to an observer? */
}

extern void _initialize_gdbarch (void);
Index: gdb/gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.278
diff -u -p -r1.278 gdbarch.h
--- gdb/gdbarch.h 27 Jan 2005 21:00:56 -0000 1.278
+++ gdb/gdbarch.h 29 Mar 2005 02:49:24 -0000
@@ -355,6 +355,11 @@ extern void set_gdbarch_num_pseudo_regs
#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).
@@ -661,6 +666,22 @@ extern void set_gdbarch_cannot_store_reg
#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: gdb/gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.356
diff -u -p -r1.356 gdbarch.sh
--- gdb/gdbarch.sh 24 Feb 2005 13:51:31 -0000 1.356
+++ gdb/gdbarch.sh 29 Mar 2005 02:49:24 -0000
@@ -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).
@@ -488,6 +490,10 @@ f:=:int:register_sim_regno:int reg_nr:re
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
#
@@ -2213,6 +2219,7 @@ deprecated_current_gdbarch_select_hack (
current_gdbarch_swap_out_hack ();
current_gdbarch_swap_in_hack (new_gdbarch);
architecture_changed_event ();
+ flush_cached_frames (); /* FIXME should this be attached to an observer? */
}

extern void _initialize_gdbarch (void);
Index: gdb/remote-sim.c
===================================================================
RCS file: /cvs/src/src/gdb/remote-sim.c,v
retrieving revision 1.46
diff -u -p -r1.46 remote-sim.c
--- gdb/remote-sim.c 15 Feb 2005 15:49:15 -0000 1.46
+++ gdb/remote-sim.c 29 Mar 2005 02:49:24 -0000
@@ -459,6 +459,12 @@ gdbsim_create_inferior (char *exec_file,
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 */

@@ -773,6 +779,69 @@ gdbsim_xfer_inferior_memory (CORE_ADDR m
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)
{
@@ -863,7 +932,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: gdb/remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.178
diff -u -p -r1.178 remote.c
--- gdb/remote.c 13 Mar 2005 22:06:10 -0000 1.178
+++ gdb/remote.c 29 Mar 2005 02:49:24 -0000
@@ -214,9 +214,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''
@@ -247,29 +248,39 @@ init_remote_state (struct gdbarch *gdbar
{
int regnum;
struct remote_state *rs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_state);
+ int num_g_regs;

- if (deprecated_register_bytes () != 0)
- rs->sizeof_g_packet = deprecated_register_bytes ();
+ if (gdbarch_remote_num_g_packet_regs_p (gdbarch))
+ num_g_regs = gdbarch_remote_num_g_packet_regs (gdbarch);
else
- rs->sizeof_g_packet = 0;
+ 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 (deprecated_register_bytes () == 0)
- rs->sizeof_g_packet += register_size (current_gdbarch, regnum);
+ rs->sizeof_g_packet += register_size (current_gdbarch, regnum);
}

+ if (!gdbarch_remote_num_g_packet_regs_p (gdbarch)
+ && deprecated_register_bytes () != 0)
+ gdb_assert (rs->sizeof_g_packet == deprecated_register_bytes ());
+
/* Default maximum number of characters in a packet body. Many
remote stubs have a hardwired buffer size of 400 bytes
(c.f. BUFMAX in m68k-stub.c and i386-stub.c). BUFMAX-1 is used
@@ -297,7 +308,7 @@ init_remote_state (struct gdbarch *gdbar
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
{
@@ -311,7 +322,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)
@@ -982,6 +993,26 @@ show_remote_protocol_qPart_auxv_packet_c
show_packet_config_cmd (&remote_protocol_qPart_auxv);
}

+/* 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
@@ -2111,6 +2142,7 @@ init_all_packet_configs (void)
downloading. */
update_packet_config (&remote_protocol_binary_download);
update_packet_config (&remote_protocol_qPart_auxv);
+ update_packet_config (&remote_protocol_qPart_availableRegisters);
}

/* Symbol look-up. */
@@ -3218,60 +3250,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);
@@ -3281,41 +3322,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));

@@ -3376,7 +3382,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)
@@ -3403,6 +3409,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. */
@@ -3433,31 +3471,46 @@ 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;
int i;

+ if (remote_protocol_P.support == PACKET_DISABLE)
+ return 0;
+
sprintf (buf, "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;
@@ -3465,44 +3518,13 @@ remote_store_registers (int regnum)
int i;
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, rs->sizeof_g_packet, 0);
- 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)
@@ -4463,6 +4485,41 @@ extended_remote_async_create_inferior (c
/* 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
@@ -5041,6 +5098,44 @@ remote_xfer_partial (struct target_ops *
}
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;
}
@@ -5544,6 +5639,7 @@ show_remote_cmd (char *args, int from_tt
show_remote_protocol_vcont_packet_cmd (gdb_stdout, from_tty, NULL, NULL);
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_qPart_availableRegisters_packet_cmd (gdb_stdout, from_tty, NULL, NULL);
}

static void
@@ -5774,6 +5870,13 @@ Show the maximum size of the address (in
&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: gdb/symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.157
diff -u -p -r1.157 symfile.c
--- gdb/symfile.c 8 Mar 2005 21:40:46 -0000 1.157
+++ gdb/symfile.c 29 Mar 2005 02:49:25 -0000
@@ -1500,7 +1500,7 @@ load_section_callback (bfd *abfd, asecti
while (sent < size);

if (err != 0)
- error (_("Memory access error while loading section %s."), sect_name);
+ error (_("Memory access error %d while loading section %s."), err, sect_name);

do_cleanups (old_chain);
}
Index: gdb/target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.68
diff -u -p -r1.68 target.h
--- gdb/target.h 27 Jan 2005 20:09:10 -0000 1.68
+++ gdb/target.h 29 Mar 2005 02:49:25 -0000
@@ -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, ... */
};
Index: gdb/gdbserver/configure.srv
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.srv,v
retrieving revision 1.8
diff -u -p -r1.8 configure.srv
--- gdb/gdbserver/configure.srv 21 Nov 2004 03:09:39 -0000 1.8
+++ gdb/gdbserver/configure.srv 29 Mar 2005 02:49:25 -0000
@@ -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
;;
i[34567]86-*-linux*) srv_regobj=reg-i386-linux.o
Index: gdb/gdbserver/linux-arm-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-arm-low.c,v
retrieving revision 1.7.14.1
diff -u -p -r1.7.14.1 linux-arm-low.c
--- gdb/gdbserver/linux-arm-low.c 25 Mar 2005 22:20:48 -0000 1.7.14.1
+++ gdb/gdbserver/linux-arm-low.c 29 Mar 2005 02:49:25 -0000
@@ -42,6 +42,9 @@
#define PTRACE_GET_THREAD_AREA 22
#endif

+#define PTRACE_GETWMMXREGS 18
+#define PTRACE_SETWMMXREGS 19
+
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
#endif
@@ -114,7 +117,96 @@ arm_reinsert_addr ()
collect_register_by_name ("lr", &pc);
return pc;
}
+
+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);
+
+ ((int*)buf)[0],
+ ((int*)buf)[1],
+ ((int*)buf)[2],
+ ((int*)buf)[3]);
+}
+
+static void
+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);
+
+ 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];
+
+ 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);
+ 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 }
+};
+
/* Fetch the thread-local storage pointer for libthread_db. */

ps_err_e
@@ -144,4 +236,5 @@ struct linux_target_ops the_low_target =
arm_reinsert_addr,
0,
arm_breakpoint_at,
+ arm_available_registers
};
Index: gdb/gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.34
diff -u -p -r1.34 linux-low.c
--- gdb/gdbserver/linux-low.c 3 Mar 2005 16:56:53 -0000 1.34
+++ gdb/gdbserver/linux-low.c 29 Mar 2005 02:49:25 -0000
@@ -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;
@@ -1467,6 +1467,15 @@ linux_read_auxv (CORE_ADDR offset, char
return n;
}

+static char *
+linux_available_registers (void)
+{
+ if (the_low_target.available_registers == NULL)
+ return NULL;
+ else
+ return (*the_low_target.available_registers) ();
+}
+
\f
static struct target_ops linux_target_ops = {
linux_create_inferior,
@@ -1483,6 +1492,7 @@ static struct target_ops linux_target_op
linux_look_up_symbols,
linux_send_signal,
linux_read_auxv,
+ linux_available_registers,
};

static void
Index: gdb/gdbserver/linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.8
diff -u -p -r1.8 linux-low.h
--- gdb/gdbserver/linux-low.h 3 Mar 2005 16:56:53 -0000 1.8
+++ gdb/gdbserver/linux-low.h 29 Mar 2005 02:49:25 -0000
@@ -57,10 +57,16 @@ struct linux_target_ops

int decr_pc_after_break;
int (*breakpoint_at) (CORE_ADDR pc);
+
+ 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: gdb/gdbserver/regcache.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/regcache.c,v
retrieving revision 1.7
diff -u -p -r1.7 regcache.c
--- gdb/gdbserver/regcache.c 30 Jan 2004 15:08:57 -0000 1.7
+++ gdb/gdbserver/regcache.c 29 Mar 2005 02:49:25 -0000
@@ -35,7 +35,7 @@ struct inferior_regcache_data
char *registers;
};

-static int register_bytes;
+static int register_bytes, g_register_bytes;

static struct reg *reg_defs;
static int num_registers;
@@ -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, in
}

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)
{
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);
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)
}

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)
{
supply_register (find_regno (name), buf);
Index: gdb/gdbserver/regcache.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/regcache.h,v
retrieving revision 1.5
diff -u -p -r1.5 regcache.h
--- gdb/gdbserver/regcache.h 11 Jun 2002 17:32:39 -0000 1.5
+++ gdb/gdbserver/regcache.h 29 Mar 2005 02:49:25 -0000
@@ -61,6 +61,8 @@ extern const char **gdbserver_expedite_r

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: gdb/gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.23
diff -u -p -r1.23 server.c
--- gdb/gdbserver/server.c 3 Mar 2005 16:56:53 -0000 1.23
+++ gdb/gdbserver/server.c 29 Mar 2005 02:49:25 -0000
@@ -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;
@@ -275,6 +295,39 @@ handle_v_requests (char *own_buf, char *
return;
}

+/* 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)
+ {
+ 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 != '=')
+ {
+ write_enn (own_buf);
+ return;
+ }
+
+ supply_register_as_string (regnum, end + 1);
+ write_ok (own_buf);
+}
+
void
myresume (int step, int sig)
{
@@ -461,6 +514,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: gdb/gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.12
diff -u -p -r1.12 target.h
--- gdb/gdbserver/target.h 3 Mar 2005 16:56:53 -0000 1.12
+++ gdb/gdbserver/target.h 29 Mar 2005 02:49:25 -0000
@@ -133,6 +133,10 @@ struct target_ops
Read LEN bytes at OFFSET into a buffer at MYADDR. */

int (*read_auxv) (CORE_ADDR offset, char *myaddr, unsigned int len);
+
+ /* 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: gdb/regformats/reg-arm.dat
===================================================================
RCS file: /cvs/src/src/gdb/regformats/reg-arm.dat,v
retrieving revision 1.1
diff -u -p -r1.1 reg-arm.dat
--- gdb/regformats/reg-arm.dat 1 Feb 2002 22:05:28 -0000 1.1
+++ gdb/regformats/reg-arm.dat 29 Mar 2005 02:49:25 -0000
@@ -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: gdb/regformats/regdat.sh
===================================================================
RCS file: /cvs/src/src/gdb/regformats/regdat.sh,v
retrieving revision 1.3
diff -u -p -r1.3 regdat.sh
--- gdb/regformats/regdat.sh 14 Feb 2002 06:21:23 -0000 1.3
+++ gdb/regformats/regdat.sh 29 Mar 2005 02:49:25 -0000
@@ -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: gdb/regformats/regdef.h
===================================================================
RCS file: /cvs/src/src/gdb/regformats/regdef.h,v
retrieving revision 1.3
diff -u -p -r1.3 regdef.h
--- gdb/regformats/regdef.h 14 Feb 2002 06:21:24 -0000 1.3
+++ gdb/regformats/regdef.h 29 Mar 2005 02:49:25 -0000
@@ -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 */