* 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-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.
$(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)
#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
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;
into regcache. */
static void
-fetch_fpregs (void)
+fetch_fpa_regs (void)
{
int ret, regno, tid;
FPA11 fp;
process using the contents from regcache. */
static void
-store_fpregister (int regno)
+store_fpa_register (int regno)
{
int ret, tid;
FPA11 fp;
the contents from regcache. */
static void
-store_fpregs (void)
+store_fpa_regs (void)
{
int ret, regno, tid;
FPA11 fp;
}
}
+/* Fetch all WMMX registers of the process and store into
+ regcache. */
+
+#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
+
+static void
+fetch_wmmx_regs (void)
+{
+ char regbuf[IWMMXT_REGS_SIZE];
+ int ret, regno, tid, first;
+
+ /* Get the thread id for the ptrace call. */
+ tid = GET_THREAD_ID (inferior_ptid);
+
+ ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
+ if (ret < 0)
+ {
+ warning (_("Unable to fetch WMMX registers."));
+ return;
+ }
+
+ first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+
+ for (regno = 0; regno < NUM_IWMMXT_COP0REGS; regno++)
+ regcache_raw_supply (current_regcache, first + regno,
+ ®buf[regno * 8]);
+
+ first += NUM_IWMMXT_COP0REGS;
+
+ for (regno = 0; regno < 2; regno++)
+ regcache_raw_supply (current_regcache, first + regno, NULL);
+
+ for (regno = 2; regno < 4; regno++)
+ regcache_raw_supply (current_regcache, first + regno,
+ ®buf[16 * 8 + (regno - 2) * 4]);
+
+ for (regno = 4; regno < 8; regno++)
+ regcache_raw_supply (current_regcache, first + regno, NULL);
+
+ for (regno = 8; regno < 12; regno++)
+ regcache_raw_supply (current_regcache, first + regno,
+ ®buf[16 * 8 + 2 * 4 + (regno - 8) * 4]);
+
+ for (regno = 12; regno < 16; regno++)
+ regcache_raw_supply (current_regcache, first + regno, NULL);
+}
+
+static void
+store_wmmx_regs (void)
+{
+ char regbuf[IWMMXT_REGS_SIZE];
+ int ret, regno, tid, first;
+
+ /* Get the thread id for the ptrace call. */
+ tid = GET_THREAD_ID (inferior_ptid);
+
+ ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
+ if (ret < 0)
+ {
+ warning (_("Unable to fetch WMMX registers."));
+ return;
+ }
+
+ first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+
+ for (regno = 0; regno < NUM_IWMMXT_COP0REGS; regno++)
+ if (register_cached (first + regno))
+ regcache_raw_collect (current_regcache, first + regno,
+ ®buf[regno * 8]);
+
+ first += 18;
+ for (regno = 0; regno < 2; regno++)
+ if (register_cached (first + regno))
+ regcache_raw_collect (current_regcache, first + regno,
+ ®buf[16 * 8 + regno * 4]);
+
+ first += 6;
+ for (regno = 0; regno < 4; regno++)
+ if (register_cached (first + regno))
+ regcache_raw_collect (current_regcache, first + regno,
+ ®buf[16 * 8 + 2 * 4 + regno * 4]);
+
+ ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
+
+ if (ret < 0)
+ {
+ warning (_("Unable to store WMMX registers."));
+ return;
+ }
+}
+
/* Fetch registers from the child process. Fetch all registers if
regno == -1, otherwise fetch all general registers or all floating
point registers depending upon the value of regno. */
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 ();
+ }
}
}
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 ();
+ }
}
}
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)
{
#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.
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;
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. */
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;
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
/* 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,
\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
/* 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,
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. */
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;
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)
{
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);
NULL,
NULL, /* FIXME: i18n: "ARM debugging is %s. */
&setdebuglist, &showdebuglist);
+
+ observer_attach_inferior_created (arm_update_architecture);
}
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
(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
/* 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;
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
/* 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 */
#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,
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;
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;
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 */
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 */
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 */
/* 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 */
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",
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);
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));
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)
{
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)
{
#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).
#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)
# 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).
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
#
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
#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
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,
arm_reinsert_addr,
0,
arm_breakpoint_at,
+ arm_available_registers
};
#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;
#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. */
linux_remove_watchpoint,
linux_stopped_by_watchpoint,
linux_stopped_data_address,
+ linux_available_registers,
};
static void
/* 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 *) \
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;
int
registers_length (void)
{
- return 2 * register_bytes;
+ return 2 * g_register_bytes;
}
void *
}
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;
}
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
{
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
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);
}
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)
{
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);
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;
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)
{
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)
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;
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;
}
name:arm
expedite:r11,sp,pc
+last_g_reg:cpsr
32:r0
32:r1
32:r2
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:
i=0
name=x
expedite=x
+last_g_reg=NULL
exec < $1
while do_read
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
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};
}
};
/* 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 */
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 */
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)
{
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;
{
/* 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''
{
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
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
{
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)
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
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. */
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);
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));
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)
}
}
+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. */
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)
/* 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
}
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;
}
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
&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, _("\
/* 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, ... */
};