From 58d6951de562a3ef2214927006541fc16f0e5bd0 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Tue, 28 Jul 2009 18:26:51 +0000 Subject: [PATCH] * NEWS: Mention ARM VFP support. * target-descriptions.c (tdesc_register_type): Make public. (tdesc_unnumbered_register): New function. (tdesc_register_reggroup_p): Allow missing pseudo_register_reggroup_p. * target-descriptions.h (tdesc_register_type): Declare. (tdesc_unnumbered_register): Declare. * arm-tdep.c (arm_neon_quad_read, arm_neon_quad_write): New functions. (arm_push_dummy_call): Use arm_neon_quad_write. (arm_neon_double_type, arm_neon_quad_type): New functions. (arm_register_type): Handle VFP and NEON registers. Override the types of double-precision registers for NEON. Disable FPA registers if they are not present. (arm_dwarf_reg_to_regnum): Add current VFP and NEON register numbers. (arm_return_value): Use arm_neon_quad_write and arm_neon_quad_read. (arm_register_name): Handle VFP single and NEON quad registers. (arm_pseudo_read, arm_pseudo_write): New functions. (arm_gdbarch_init): Check for VFP and NEON in the target description. Assign numbers to double-precision registers. Register VFP and NEON pseudo registers. Remove a shadowed "i" variable. * arm-tdep.h (enum gdb_regnum): Add ARM_D0_REGNUM and ARM_D31_REGNUM. (struct gdbarch_tdep): Add have_neon_pseudos, have_neon, have_vfp_registers, have_vfp_pseudos, neon_double_type, and neon_quad_type. * features/Makefile: Make expedite settings only architecture specific. (WHICH): Add new ARM descriptions. * features/arm-with-neon.xml, features/arm-with-vfpv2.c, features/arm-with-vfpv3.c, features/arm-vfpv2.xml, features/arm-vfpv3.xml, features/arm-with-vfpv2.xml, features/arm-with-vfpv3.xml, features/arm-with-neon.c: New files. * regformats/arm-with-neon.dat, regformats/arm-with-vfpv2.dat, regformats/arm-with-vfpv3.dat: Generate. doc/ * gdb.texinfo (ARM Features): Document org.gnu.gdb.arm.vfp and org.gnu.gdb.arm.neon. gdbserver/ * linux-low.c (linux_write_memory): Update debugging output. * Makefile.in (clean): Add new descriptions. (arm-with-vfpv2.o, arm-with-vfpv2.c, arm-with-vfpv3.o) (arm-with-vfpv3.c, arm-with-neon.o, arm-with-neon.c): New rules. * configure.srv: Add new files for arm*-*-linux*. * linux-arm-low.c: Add new declarations. (PTRACE_GETVFPREGS, PTRACE_SETVFPREGS): Define if undefined. (arm_hwcap, HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3) (HWCAP_VFPv3D16): New. (arm_fill_wmmxregset, arm_store_wmmxregset): Check HWCAP_IWMMXT instead of __IWMMXT__. (arm_fill_vfpregset, arm_store_vfpregset, arm_get_hwcap) (arm_arch_setup): New. (target_regsets): Remove #ifdef. Add VFP regset. (the_low_target): Use arm_arch_setup. testsuite/ * gdb.base/float.exp: Handle VFP registers. --- gdb/ChangeLog | 38 +++ gdb/NEWS | 9 +- gdb/arm-tdep.c | 446 ++++++++++++++++++++++++++++-- gdb/arm-tdep.h | 11 + gdb/doc/ChangeLog | 5 + gdb/doc/gdb.texinfo | 13 + gdb/features/Makefile | 25 +- gdb/features/arm-vfpv2.xml | 28 ++ gdb/features/arm-vfpv3.xml | 44 +++ gdb/features/arm-with-neon.c | 72 +++++ gdb/features/arm-with-neon.xml | 13 + gdb/features/arm-with-vfpv2.c | 54 ++++ gdb/features/arm-with-vfpv2.xml | 12 + gdb/features/arm-with-vfpv3.c | 70 +++++ gdb/features/arm-with-vfpv3.xml | 12 + gdb/gdbserver/ChangeLog | 18 ++ gdb/gdbserver/Makefile.in | 13 +- gdb/gdbserver/configure.srv | 8 + gdb/gdbserver/linux-arm-low.c | 153 +++++++++- gdb/gdbserver/linux-low.c | 11 +- gdb/regformats/arm-with-neon.dat | 63 +++++ gdb/regformats/arm-with-vfpv2.dat | 47 ++++ gdb/regformats/arm-with-vfpv3.dat | 63 +++++ gdb/target-descriptions.c | 22 +- gdb/target-descriptions.h | 11 + gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.base/float.exp | 5 + 27 files changed, 1215 insertions(+), 55 deletions(-) create mode 100644 gdb/features/arm-vfpv2.xml create mode 100644 gdb/features/arm-vfpv3.xml create mode 100644 gdb/features/arm-with-neon.c create mode 100644 gdb/features/arm-with-neon.xml create mode 100644 gdb/features/arm-with-vfpv2.c create mode 100644 gdb/features/arm-with-vfpv2.xml create mode 100644 gdb/features/arm-with-vfpv3.c create mode 100644 gdb/features/arm-with-vfpv3.xml create mode 100644 gdb/regformats/arm-with-neon.dat create mode 100644 gdb/regformats/arm-with-vfpv2.dat create mode 100644 gdb/regformats/arm-with-vfpv3.dat diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 019d4416dc5..1beccaab0b0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,41 @@ +2009-07-28 Daniel Jacobowitz + + * NEWS: Mention ARM VFP support. + * target-descriptions.c (tdesc_register_type): Make public. + (tdesc_unnumbered_register): New function. + (tdesc_register_reggroup_p): Allow missing + pseudo_register_reggroup_p. + * target-descriptions.h (tdesc_register_type): Declare. + (tdesc_unnumbered_register): Declare. + * arm-tdep.c (arm_neon_quad_read, arm_neon_quad_write): New functions. + (arm_push_dummy_call): Use arm_neon_quad_write. + (arm_neon_double_type, arm_neon_quad_type): New functions. + (arm_register_type): Handle VFP and NEON registers. Override the + types of double-precision registers for NEON. Disable FPA registers + if they are not present. + (arm_dwarf_reg_to_regnum): Add current VFP and NEON register numbers. + (arm_return_value): Use arm_neon_quad_write and arm_neon_quad_read. + (arm_register_name): Handle VFP single and NEON quad registers. + (arm_pseudo_read, arm_pseudo_write): New functions. + (arm_gdbarch_init): Check for VFP and NEON in the target description. + Assign numbers to double-precision registers. Register VFP and NEON + pseudo registers. Remove a shadowed "i" variable. + * arm-tdep.h (enum gdb_regnum): Add ARM_D0_REGNUM and + ARM_D31_REGNUM. + (struct gdbarch_tdep): Add have_neon_pseudos, have_neon, + have_vfp_registers, have_vfp_pseudos, neon_double_type, + and neon_quad_type. + + * features/Makefile: Make expedite settings only architecture + specific. + (WHICH): Add new ARM descriptions. + * features/arm-with-neon.xml, features/arm-with-vfpv2.c, + features/arm-with-vfpv3.c, features/arm-vfpv2.xml, + features/arm-vfpv3.xml, features/arm-with-vfpv2.xml, + features/arm-with-vfpv3.xml, features/arm-with-neon.c: New files. + * regformats/arm-with-neon.dat, regformats/arm-with-vfpv2.dat, + regformats/arm-with-vfpv3.dat: Generate. + 2009-07-28 Daniel Jacobowitz * infrun.c (handle_inferior_event): Clear trap_expected after diff --git a/gdb/NEWS b/gdb/NEWS index 7dcc8fc7d3f..1e359a0c05c 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -64,8 +64,13 @@ operators when expanding macros. It also supports variable-arity macros. * GDB now supports inspecting extra signal information, exported by - the new $_siginfo convenience variable. The feature is currently - implemented on linux ARM, i386 and amd64. +the new $_siginfo convenience variable. The feature is currently +implemented on linux ARM, i386 and amd64. + +* GDB can now display the VFP floating point registers and NEON vector +registers on ARM targets. Both ARM GNU/Linux native GDB and gdbserver +can provide these registers (requires Linux 2.6.30 or later). Remote +and simulator targets may also provide them. * New remote packets diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 733318d1d90..3cc8d016a5f 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -208,6 +208,13 @@ static void convert_from_extended (const struct floatformat *, const void *, static void convert_to_extended (const struct floatformat *, void *, const void *, int); +static void arm_neon_quad_read (struct gdbarch *gdbarch, + struct regcache *regcache, + int regnum, gdb_byte *buf); +static void arm_neon_quad_write (struct gdbarch *gdbarch, + struct regcache *regcache, + int regnum, const gdb_byte *buf); + struct arm_prologue_cache { /* The stack pointer at the time this frame was created; i.e. the @@ -1709,11 +1716,17 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function, { char name_buf[4]; int regnum; - sprintf (name_buf, "%c%d", reg_char, reg_scaled + i); - regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, - strlen (name_buf)); - regcache_cooked_write (regcache, regnum, + if (reg_char == 'q') + arm_neon_quad_write (gdbarch, regcache, reg_scaled + i, val + i * unit_length); + else + { + sprintf (name_buf, "%c%d", reg_char, reg_scaled + i); + regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + regcache_cooked_write (regcache, regnum, + val + i * unit_length); + } } continue; } @@ -1874,14 +1887,115 @@ arm_ext_type (struct gdbarch *gdbarch) return tdep->arm_ext_type; } +static struct type * +arm_neon_double_type (struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->neon_double_type == NULL) + { + struct type *t, *elem; + + t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_d", + TYPE_CODE_UNION); + elem = builtin_type (gdbarch)->builtin_uint8; + append_composite_type_field (t, "u8", init_vector_type (elem, 8)); + elem = builtin_type (gdbarch)->builtin_uint16; + append_composite_type_field (t, "u16", init_vector_type (elem, 4)); + elem = builtin_type (gdbarch)->builtin_uint32; + append_composite_type_field (t, "u32", init_vector_type (elem, 2)); + elem = builtin_type (gdbarch)->builtin_uint64; + append_composite_type_field (t, "u64", elem); + elem = builtin_type (gdbarch)->builtin_float; + append_composite_type_field (t, "f32", init_vector_type (elem, 2)); + elem = builtin_type (gdbarch)->builtin_double; + append_composite_type_field (t, "f64", elem); + + TYPE_VECTOR (t) = 1; + TYPE_NAME (t) = "neon_d"; + tdep->neon_double_type = t; + } + + return tdep->neon_double_type; +} + +/* FIXME: The vector types are not correctly ordered on big-endian + targets. Just as s0 is the low bits of d0, d0[0] is also the low + bits of d0 - regardless of what unit size is being held in d0. So + the offset of the first uint8 in d0 is 7, but the offset of the + first float is 4. This code works as-is for little-endian + targets. */ + +static struct type * +arm_neon_quad_type (struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->neon_quad_type == NULL) + { + struct type *t, *elem; + + t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_q", + TYPE_CODE_UNION); + elem = builtin_type (gdbarch)->builtin_uint8; + append_composite_type_field (t, "u8", init_vector_type (elem, 16)); + elem = builtin_type (gdbarch)->builtin_uint16; + append_composite_type_field (t, "u16", init_vector_type (elem, 8)); + elem = builtin_type (gdbarch)->builtin_uint32; + append_composite_type_field (t, "u32", init_vector_type (elem, 4)); + elem = builtin_type (gdbarch)->builtin_uint64; + append_composite_type_field (t, "u64", init_vector_type (elem, 2)); + elem = builtin_type (gdbarch)->builtin_float; + append_composite_type_field (t, "f32", init_vector_type (elem, 4)); + elem = builtin_type (gdbarch)->builtin_double; + append_composite_type_field (t, "f64", init_vector_type (elem, 2)); + + TYPE_VECTOR (t) = 1; + TYPE_NAME (t) = "neon_q"; + tdep->neon_quad_type = t; + } + + return tdep->neon_quad_type; +} + /* Return the GDB type object for the "standard" data type of data in register N. */ static struct type * arm_register_type (struct gdbarch *gdbarch, int regnum) { + int num_regs = gdbarch_num_regs (gdbarch); + + if (gdbarch_tdep (gdbarch)->have_vfp_pseudos + && regnum >= num_regs && regnum < num_regs + 32) + return builtin_type (gdbarch)->builtin_float; + + if (gdbarch_tdep (gdbarch)->have_neon_pseudos + && regnum >= num_regs + 32 && regnum < num_regs + 32 + 16) + return arm_neon_quad_type (gdbarch); + + /* If the target description has register information, we are only + in this function so that we can override the types of + double-precision registers for NEON. */ + if (tdesc_has_registers (gdbarch_target_desc (gdbarch))) + { + struct type *t = tdesc_register_type (gdbarch, regnum); + + if (regnum >= ARM_D0_REGNUM && regnum < ARM_D0_REGNUM + 32 + && TYPE_CODE (t) == TYPE_CODE_FLT + && gdbarch_tdep (gdbarch)->have_neon) + return arm_neon_double_type (gdbarch); + else + return t; + } + if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS) - return arm_ext_type (gdbarch); + { + if (!gdbarch_tdep (gdbarch)->have_fpa_registers) + return builtin_type (gdbarch)->builtin_void; + + return arm_ext_type (gdbarch); + } else if (regnum == ARM_SP_REGNUM) return builtin_type (gdbarch)->builtin_data_ptr; else if (regnum == ARM_PC_REGNUM) @@ -1925,6 +2039,34 @@ arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) if (reg >= 192 && reg <= 199) return ARM_WC0_REGNUM + reg - 192; + /* VFP v2 registers. A double precision value is actually + in d1 rather than s2, but the ABI only defines numbering + for the single precision registers. This will "just work" + in GDB for little endian targets (we'll read eight bytes, + starting in s0 and then progressing to s1), but will be + reversed on big endian targets with VFP. This won't + be a problem for the new Neon quad registers; you're supposed + to use DW_OP_piece for those. */ + if (reg >= 64 && reg <= 95) + { + char name_buf[4]; + + sprintf (name_buf, "s%d", reg - 64); + return user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + } + + /* VFP v3 / Neon registers. This range is also used for VFP v2 + registers, except that it now describes d0 instead of s0. */ + if (reg >= 256 && reg <= 287) + { + char name_buf[4]; + + sprintf (name_buf, "d%d", reg - 256); + return user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + } + return -1; } @@ -2874,17 +3016,31 @@ arm_return_value (struct gdbarch *gdbarch, struct type *func_type, int i; for (i = 0; i < vfp_base_count; i++) { - char name_buf[4]; - int regnum; - sprintf (name_buf, "%c%d", reg_char, i); - regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, - strlen (name_buf)); - if (writebuf) - regcache_cooked_write (regcache, regnum, - writebuf + i * unit_length); - if (readbuf) - regcache_cooked_read (regcache, regnum, - readbuf + i * unit_length); + if (reg_char == 'q') + { + if (writebuf) + arm_neon_quad_write (gdbarch, regcache, i, + writebuf + i * unit_length); + + if (readbuf) + arm_neon_quad_read (gdbarch, regcache, i, + readbuf + i * unit_length); + } + else + { + char name_buf[4]; + int regnum; + + sprintf (name_buf, "%c%d", reg_char, i); + regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + if (writebuf) + regcache_cooked_write (regcache, regnum, + writebuf + i * unit_length); + if (readbuf) + regcache_cooked_read (regcache, regnum, + readbuf + i * unit_length); + } } return RETURN_VALUE_REGISTER_CONVENTION; } @@ -3141,6 +3297,32 @@ set_disassembly_style_sfunc (char *args, int from_tty, static const char * arm_register_name (struct gdbarch *gdbarch, int i) { + const int num_regs = gdbarch_num_regs (gdbarch); + + if (gdbarch_tdep (gdbarch)->have_vfp_pseudos + && i >= num_regs && i < num_regs + 32) + { + static const char *const vfp_pseudo_names[] = { + "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", + }; + + return vfp_pseudo_names[i - num_regs]; + } + + if (gdbarch_tdep (gdbarch)->have_neon_pseudos + && i >= num_regs + 32 && i < num_regs + 32 + 16) + { + static const char *const neon_pseudo_names[] = { + "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", + "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", + }; + + return neon_pseudo_names[i - num_regs - 32]; + } + if (i >= ARRAY_SIZE (arm_register_names)) /* These registers are only supported on targets which supply an XML description. */ @@ -3278,6 +3460,140 @@ arm_write_pc (struct regcache *regcache, CORE_ADDR pc) } } +/* Read the contents of a NEON quad register, by reading from two + double registers. This is used to implement the quad pseudo + registers, and for argument passing in case the quad registers are + missing; vectors are passed in quad registers when using the VFP + ABI, even if a NEON unit is not present. REGNUM is the index of + the quad register, in [0, 15]. */ + +static void +arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, gdb_byte *buf) +{ + char name_buf[4]; + gdb_byte reg_buf[8]; + int offset, double_regnum; + + sprintf (name_buf, "d%d", regnum << 1); + double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + + /* d0 is always the least significant half of q0. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + offset = 8; + else + offset = 0; + + regcache_raw_read (regcache, double_regnum, reg_buf); + memcpy (buf + offset, reg_buf, 8); + + offset = 8 - offset; + regcache_raw_read (regcache, double_regnum + 1, reg_buf); + memcpy (buf + offset, reg_buf, 8); +} + +static void +arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, gdb_byte *buf) +{ + const int num_regs = gdbarch_num_regs (gdbarch); + char name_buf[4]; + gdb_byte reg_buf[8]; + int offset, double_regnum; + + gdb_assert (regnum >= num_regs); + regnum -= num_regs; + + if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48) + /* Quad-precision register. */ + arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf); + else + { + /* Single-precision register. */ + gdb_assert (regnum < 32); + + /* s0 is always the least significant half of d0. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + offset = (regnum & 1) ? 0 : 4; + else + offset = (regnum & 1) ? 4 : 0; + + sprintf (name_buf, "d%d", regnum >> 1); + double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + + regcache_raw_read (regcache, double_regnum, reg_buf); + memcpy (buf, reg_buf + offset, 4); + } +} + +/* Store the contents of BUF to a NEON quad register, by writing to + two double registers. This is used to implement the quad pseudo + registers, and for argument passing in case the quad registers are + missing; vectors are passed in quad registers when using the VFP + ABI, even if a NEON unit is not present. REGNUM is the index + of the quad register, in [0, 15]. */ + +static void +arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, const gdb_byte *buf) +{ + char name_buf[4]; + gdb_byte reg_buf[8]; + int offset, double_regnum; + + sprintf (name_buf, "d%d", regnum << 1); + double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + + /* d0 is always the least significant half of q0. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + offset = 8; + else + offset = 0; + + regcache_raw_write (regcache, double_regnum, buf + offset); + offset = 8 - offset; + regcache_raw_write (regcache, double_regnum + 1, buf + offset); +} + +static void +arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache, + int regnum, const gdb_byte *buf) +{ + const int num_regs = gdbarch_num_regs (gdbarch); + char name_buf[4]; + gdb_byte reg_buf[8]; + int offset, double_regnum; + + gdb_assert (regnum >= num_regs); + regnum -= num_regs; + + if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48) + /* Quad-precision register. */ + arm_neon_quad_write (gdbarch, regcache, regnum - 32, buf); + else + { + /* Single-precision register. */ + gdb_assert (regnum < 32); + + /* s0 is always the least significant half of d0. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + offset = (regnum & 1) ? 0 : 4; + else + offset = (regnum & 1) ? 4 : 0; + + sprintf (name_buf, "d%d", regnum >> 1); + double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + + regcache_raw_read (regcache, double_regnum, reg_buf); + memcpy (reg_buf + offset, buf, 4); + regcache_raw_write (regcache, double_regnum, reg_buf); + } +} + static struct value * value_of_arm_user_reg (struct frame_info *frame, const void *baton) { @@ -3322,6 +3638,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) enum arm_float_model fp_model = arm_fp_model; struct tdesc_arch_data *tdesc_data = NULL; int i; + int have_vfp_registers = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0; + int have_neon = 0; int have_fpa_registers = 1; /* Check any target description for validity. */ @@ -3334,7 +3652,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) static const char *const arm_pc_names[] = { "r15", "pc", NULL }; const struct tdesc_feature *feature; - int i, valid_p; + int valid_p; feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.arm.core"); @@ -3416,6 +3734,67 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) return NULL; } } + + /* If we have a VFP unit, check whether the single precision registers + are present. If not, then we will synthesize them as pseudo + registers. */ + feature = tdesc_find_feature (info.target_desc, + "org.gnu.gdb.arm.vfp"); + if (feature != NULL) + { + static const char *const vfp_double_names[] = { + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", + "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", + "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", + }; + + /* Require the double precision registers. There must be either + 16 or 32. */ + valid_p = 1; + for (i = 0; i < 32; i++) + { + valid_p &= tdesc_numbered_register (feature, tdesc_data, + ARM_D0_REGNUM + i, + vfp_double_names[i]); + if (!valid_p) + break; + } + + if (!valid_p && i != 16) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + + if (tdesc_unnumbered_register (feature, "s0") == 0) + have_vfp_pseudos = 1; + + have_vfp_registers = 1; + + /* If we have VFP, also check for NEON. The architecture allows + NEON without VFP (integer vector operations only), but GDB + does not support that. */ + feature = tdesc_find_feature (info.target_desc, + "org.gnu.gdb.arm.neon"); + if (feature != NULL) + { + /* NEON requires 32 double-precision registers. */ + if (i != 32) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + + /* If there are quad registers defined by the stub, use + their type; otherwise (normally) provide them with + the default type. */ + if (tdesc_unnumbered_register (feature, "q0") == 0) + have_neon_pseudos = 1; + + have_neon = 1; + } + } } /* If we have an object to base this architecture on, try to determine @@ -3559,6 +3938,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) && fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model) continue; + /* There are various other properties in tdep that we do not + need to check here: those derived from a target description, + since gdbarches with a different target description are + automatically disqualified. */ + /* Found a match. */ break; } @@ -3578,6 +3962,10 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->arm_abi = arm_abi; tdep->fp_model = fp_model; tdep->have_fpa_registers = have_fpa_registers; + tdep->have_vfp_registers = have_vfp_registers; + tdep->have_vfp_pseudos = have_vfp_pseudos; + tdep->have_neon_pseudos = have_neon_pseudos; + tdep->have_neon = have_neon; /* Breakpoints. */ switch (info.byte_order_for_code) @@ -3717,8 +4105,30 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double); } + if (have_vfp_pseudos) + { + /* NOTE: These are the only pseudo registers used by + the ARM target at the moment. If more are added, a + little more care in numbering will be needed. */ + + int num_pseudos = 32; + if (have_neon_pseudos) + num_pseudos += 16; + set_gdbarch_num_pseudo_regs (gdbarch, num_pseudos); + set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_read); + set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_write); + } + if (tdesc_data) - tdesc_use_registers (gdbarch, info.target_desc, tdesc_data); + { + set_tdesc_pseudo_register_name (gdbarch, arm_register_name); + + tdesc_use_registers (gdbarch, info.target_desc, tdesc_data); + + /* Override tdesc_register_type to adjust the types of VFP + registers for NEON. */ + set_gdbarch_register_type (gdbarch, arm_register_type); + } /* Add standard register aliases. We add aliases even for those nanes which are used by the current architecture - it's simpler, diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h index 9af94ceb23a..968c4f28df1 100644 --- a/gdb/arm-tdep.h +++ b/gdb/arm-tdep.h @@ -47,6 +47,8 @@ enum gdb_regnum { ARM_WCGR0_REGNUM, /* WMMX general purpose registers. */ ARM_WCGR3_REGNUM = ARM_WCGR0_REGNUM + 3, ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7, + ARM_D0_REGNUM, /* VFP double-precision registers. */ + ARM_D31_REGNUM = ARM_D0_REGNUM + 31, ARM_NUM_REGS, @@ -151,6 +153,13 @@ struct gdbarch_tdep enum arm_float_model fp_model; /* Floating point calling conventions. */ int have_fpa_registers; /* Does the target report the FPA registers? */ + int have_vfp_registers; /* Does the target report the VFP registers? */ + int have_vfp_pseudos; /* Are we synthesizing the single precision + VFP registers? */ + int have_neon_pseudos; /* Are we synthesizing the quad precision + NEON registers? Requires + have_vfp_pseudos. */ + int have_neon; /* Do we have a NEON unit? */ CORE_ADDR lowest_pc; /* Lowest address at which instructions will appear. */ @@ -173,6 +182,8 @@ struct gdbarch_tdep /* ISA-specific data types. */ struct type *arm_ext_type; + struct type *neon_double_type; + struct type *neon_quad_type; }; diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index c0279a7c376..a544bc1f8fe 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2009-07-28 Daniel Jacobowitz + + * gdb.texinfo (ARM Features): Document org.gnu.gdb.arm.vfp and + org.gnu.gdb.arm.neon. + 2009-07-20 Pedro Alves * gdb.texinfo (Target Description Format): Mention the new diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index c3693fae702..3bb35b60117 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -31092,6 +31092,19 @@ it should contain at least registers @samp{wR0} through @samp{wR15} and @samp{wCGR0} through @samp{wCGR3}. The @samp{wCID}, @samp{wCon}, @samp{wCSSF}, and @samp{wCASF} registers are optional. +The @samp{org.gnu.gdb.arm.vfp} feature is optional. If present, it +should contain at least registers @samp{d0} through @samp{d15}. If +they are present, @samp{d16} through @samp{d31} should also be included. +@value{GDBN} will synthesize the single-precision registers from +halves of the double-precision registers. + +The @samp{org.gnu.gdb.arm.neon} feature is optional. It does not +need to contain registers; it instructs @value{GDBN} to display the +VFP double-precision registers as vectors and to synthesize the +quad-precision registers from pairs of double-precision registers. +If this feature is present, @samp{org.gnu.gdb.arm.vfp} must also +be present and include 32 double-precision registers. + @node MIPS Features @subsection MIPS Features @cindex target descriptions, MIPS features diff --git a/gdb/features/Makefile b/gdb/features/Makefile index d70f15427db..0a0a9b21b90 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -31,28 +31,17 @@ # in the GDB repository. To generate C files: # make GDB=/path/to/gdb XMLTOC="xml files" cfiles -WHICH = arm-with-iwmmxt mips-linux mips64-linux \ +WHICH = arm-with-iwmmxt arm-with-vfpv2 arm-with-vfpv3 arm-with-neon \ + mips-linux mips64-linux \ rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \ rs6000/powerpc-64l rs6000/powerpc-altivec64l rs6000/powerpc-vsx32l \ rs6000/powerpc-vsx64l # Record which registers should be sent to GDB by default after stop. -arm-with-iwmmxt-expedite = r11,sp,pc -mips-linux-expedite = r29,pc -mips64-linux-expedite = r29,pc -rs6000/powerpc-32l-expedite = r1,pc -rs6000/powerpc-altivec32l-expedite = r1,pc -rs6000/powerpc-vsx32l-expedite = r1,pc -rs6000/powerpc-isa205-32l-expedite = r1,pc -rs6000/powerpc-isa205-altivec32l-expedite = r1,pc -rs6000/powerpc-isa205-vsx32l-expedite = r1,pc -rs6000/powerpc-e500l-expedite = r1,pc -rs6000/powerpc-64l-expedite = r1,pc -rs6000/powerpc-altivec64l-expedite = r1,pc -rs6000/powerpc-vsx64l-expedite = r1,pc -rs6000/powerpc-isa205-64l-expedite = r1,pc -rs6000/powerpc-isa205-altivec64l-expedite = r1,pc -rs6000/powerpc-isa205-vsx64l-expedite = r1,pc +arm-expedite = r11,sp,pc +mips-expedite = r29,pc +mips64-expedite = r29,pc +powerpc-expedite = r1,pc XSLTPROC = xsltproc @@ -69,7 +58,7 @@ $(outdir)/%.dat: %.xml number-regs.xsl sort-regs.xsl gdbserver-regs.xsl echo "# DO NOT EDIT: generated from $<" > $(outdir)/$*.tmp echo "name:`echo $(notdir $*) | sed 's/-/_/g'`" >> $(outdir)/$*.tmp echo "xmltarget:$(> $(outdir)/$*.tmp - echo "expedite:$($*-expedite)" >> $(outdir)/$*.tmp + echo "expedite:$($(firstword $(subst -, ,$(notdir $*)))-expedite)" >> $(outdir)/$*.tmp $(XSLTPROC) --path "$(PWD)" --xinclude number-regs.xsl $< | \ $(XSLTPROC) sort-regs.xsl - | \ $(XSLTPROC) gdbserver-regs.xsl - >> $(outdir)/$*.tmp diff --git a/gdb/features/arm-vfpv2.xml b/gdb/features/arm-vfpv2.xml new file mode 100644 index 00000000000..4c1d25dcb96 --- /dev/null +++ b/gdb/features/arm-vfpv2.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/arm-vfpv3.xml b/gdb/features/arm-vfpv3.xml new file mode 100644 index 00000000000..80433d1d6d0 --- /dev/null +++ b/gdb/features/arm-vfpv3.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/arm-with-neon.c b/gdb/features/arm-with-neon.c new file mode 100644 index 00000000000..d669d08b05b --- /dev/null +++ b/gdb/features/arm-with-neon.c @@ -0,0 +1,72 @@ +/* THIS FILE IS GENERATED. Original: arm-with-neon.xml */ + +#include "defs.h" +#include "gdbtypes.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_arm_with_neon; +static void +initialize_tdesc_arm_with_neon (void) +{ + struct target_desc *result = allocate_target_description (); + struct tdesc_feature *feature; + struct type *field_type, *type; + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int"); + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp"); + tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d16", 42, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d17", 43, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d18", 44, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d19", 45, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d20", 46, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d21", 47, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d22", 48, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d23", 49, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d24", 50, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d25", 51, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d26", 52, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d27", 53, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d28", 54, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d29", 55, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d30", 56, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d31", 57, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "fpscr", 58, 1, "float", 32, "int"); + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.neon"); + + tdesc_arm_with_neon = result; +} diff --git a/gdb/features/arm-with-neon.xml b/gdb/features/arm-with-neon.xml new file mode 100644 index 00000000000..8b7e49724de --- /dev/null +++ b/gdb/features/arm-with-neon.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/gdb/features/arm-with-vfpv2.c b/gdb/features/arm-with-vfpv2.c new file mode 100644 index 00000000000..687e1405715 --- /dev/null +++ b/gdb/features/arm-with-vfpv2.c @@ -0,0 +1,54 @@ +/* THIS FILE IS GENERATED. Original: arm-with-vfpv2.xml */ + +#include "defs.h" +#include "gdbtypes.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_arm_with_vfpv2; +static void +initialize_tdesc_arm_with_vfpv2 (void) +{ + struct target_desc *result = allocate_target_description (); + struct tdesc_feature *feature; + struct type *field_type, *type; + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int"); + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp"); + tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "fpscr", 42, 1, "float", 32, "int"); + + tdesc_arm_with_vfpv2 = result; +} diff --git a/gdb/features/arm-with-vfpv2.xml b/gdb/features/arm-with-vfpv2.xml new file mode 100644 index 00000000000..c64e4df0248 --- /dev/null +++ b/gdb/features/arm-with-vfpv2.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gdb/features/arm-with-vfpv3.c b/gdb/features/arm-with-vfpv3.c new file mode 100644 index 00000000000..efb851d6df1 --- /dev/null +++ b/gdb/features/arm-with-vfpv3.c @@ -0,0 +1,70 @@ +/* THIS FILE IS GENERATED. Original: arm-with-vfpv3.xml */ + +#include "defs.h" +#include "gdbtypes.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_arm_with_vfpv3; +static void +initialize_tdesc_arm_with_vfpv3 (void) +{ + struct target_desc *result = allocate_target_description (); + struct tdesc_feature *feature; + struct type *field_type, *type; + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int"); + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp"); + tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d16", 42, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d17", 43, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d18", 44, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d19", 45, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d20", 46, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d21", 47, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d22", 48, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d23", 49, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d24", 50, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d25", 51, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d26", 52, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d27", 53, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d28", 54, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d29", 55, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d30", 56, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "d31", 57, 1, NULL, 64, "ieee_double"); + tdesc_create_reg (feature, "fpscr", 58, 1, "float", 32, "int"); + + tdesc_arm_with_vfpv3 = result; +} diff --git a/gdb/features/arm-with-vfpv3.xml b/gdb/features/arm-with-vfpv3.xml new file mode 100644 index 00000000000..9658b0244ba --- /dev/null +++ b/gdb/features/arm-with-vfpv3.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index b878baf59f7..27838a56daa 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,21 @@ +2009-07-28 Daniel Jacobowitz + + * linux-low.c (linux_write_memory): Update debugging output. + * Makefile.in (clean): Add new descriptions. + (arm-with-vfpv2.o, arm-with-vfpv2.c, arm-with-vfpv3.o) + (arm-with-vfpv3.c, arm-with-neon.o, arm-with-neon.c): New rules. + * configure.srv: Add new files for arm*-*-linux*. + * linux-arm-low.c: Add new declarations. + (PTRACE_GETVFPREGS, PTRACE_SETVFPREGS): Define if undefined. + (arm_hwcap, HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3) + (HWCAP_VFPv3D16): New. + (arm_fill_wmmxregset, arm_store_wmmxregset): Check HWCAP_IWMMXT + instead of __IWMMXT__. + (arm_fill_vfpregset, arm_store_vfpregset, arm_get_hwcap) + (arm_arch_setup): New. + (target_regsets): Remove #ifdef. Add VFP regset. + (the_low_target): Use arm_arch_setup. + 2009-07-28 Daniel Jacobowitz * linux-low.c (linux_kill_one_lwp): Adjust kernel workaround to skip diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 37d6095922e..eea59a1a176 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -205,7 +205,9 @@ clean: rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m32r.c reg-m68k.c rm -f reg-sh.c reg-sparc.c reg-spu.c reg-x86-64.c reg-i386-linux.c rm -f reg-cris.c reg-crisv32.c reg-x86-64-linux.c reg-xtensa.c - rm -f arm-with-iwmmxt.c mips-linux.c mips64-linux.c + rm -f arm-with-iwmmxt.c + rm -f arm-with-vfpv2.c arm-with-vfpv3.c arm-with-neon.c + rm -f mips-linux.c mips64-linux.c rm -f powerpc-32l.c powerpc-64l.c powerpc-e500l.c rm -f powerpc-altivec32l.c powerpc-vsx32l.c powerpc-altivec64l.c rm -f powerpc-vsx64l.c @@ -326,6 +328,15 @@ reg-arm.c : $(srcdir)/../regformats/reg-arm.dat $(regdat_sh) arm-with-iwmmxt.o : arm-with-iwmmxt.c $(regdef_h) arm-with-iwmmxt.c : $(srcdir)/../regformats/arm-with-iwmmxt.dat $(regdat_sh) $(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-iwmmxt.dat arm-with-iwmmxt.c +arm-with-vfpv2.o : arm-with-vfpv2.c $(regdef_h) +arm-with-vfpv2.c : $(srcdir)/../regformats/arm-with-vfpv2.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-vfpv2.dat arm-with-vfpv2.c +arm-with-vfpv3.o : arm-with-vfpv3.c $(regdef_h) +arm-with-vfpv3.c : $(srcdir)/../regformats/arm-with-vfpv3.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-vfpv3.dat arm-with-vfpv3.c +arm-with-neon.o : arm-with-neon.c $(regdef_h) +arm-with-neon.c : $(srcdir)/../regformats/arm-with-neon.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-neon.dat arm-with-neon.c reg-cris.o : reg-cris.c $(regdef_h) reg-cris.c : $(srcdir)/../regformats/reg-cris.dat $(regdat_sh) $(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-cris.dat reg-cris.c diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index b3ab6228e04..900b5656b2f 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -26,10 +26,18 @@ srv_hostio_err_objs="hostio-errno.o" case "${target}" in arm*-*-linux*) srv_regobj="reg-arm.o arm-with-iwmmxt.o" + srv_regobj="${srv_regobj} arm-with-vfpv2.o" + srv_regobj="${srv_regobj} arm-with-vfpv3.o" + srv_regobj="${srv_regobj} arm-with-neon.o" srv_tgtobj="linux-low.o linux-arm-low.o" srv_xmlfiles="arm-with-iwmmxt.xml" + srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml" + srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml" + srv_xmlfiles="${srv_xmlfiles} arm-with-neon.xml" srv_xmlfiles="${srv_xmlfiles} arm-core.xml" srv_xmlfiles="${srv_xmlfiles} xscale-iwmmxt.xml" + srv_xmlfiles="${srv_xmlfiles} arm-vfpv2.xml" + srv_xmlfiles="${srv_xmlfiles} arm-vfpv3.xml" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index 70597fc2aab..d47ee977311 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -20,14 +20,17 @@ #include "server.h" #include "linux-low.h" +#include #include #include "gdb_proc_service.h" -/* Defined in auto-generated file reg-arm.c. */ +/* Defined in auto-generated files. */ void init_registers_arm (void); -/* Defined in auto-generated file arm-with-iwmmxt.c. */ void init_registers_arm_with_iwmmxt (void); +void init_registers_arm_with_vfpv2 (void); +void init_registers_arm_with_vfpv3 (void); +void init_registers_arm_with_neon (void); #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA 22 @@ -38,6 +41,20 @@ void init_registers_arm_with_iwmmxt (void); # define PTRACE_SETWMMXREGS 19 #endif +#ifndef PTRACE_GETVFPREGS +# define PTRACE_GETVFPREGS 27 +# define PTRACE_SETVFPREGS 28 +#endif + +static unsigned long arm_hwcap; + +/* These are in in current kernels. */ +#define HWCAP_VFP 64 +#define HWCAP_IWMMXT 512 +#define HWCAP_NEON 4096 +#define HWCAP_VFPv3 8192 +#define HWCAP_VFPv3D16 16384 + #ifdef HAVE_SYS_REG_H #include #endif @@ -87,13 +104,14 @@ arm_store_gregset (const void *buf) supply_register (i, zerobuf); } -#ifdef __IWMMXT__ - static void arm_fill_wmmxregset (void *buf) { int i; + if (!(arm_hwcap & HWCAP_IWMMXT)) + return; + for (i = 0; i < 16; i++) collect_register (arm_num_regs + i, (char *) buf + i * 8); @@ -107,6 +125,9 @@ arm_store_wmmxregset (const void *buf) { int i; + if (!(arm_hwcap & HWCAP_IWMMXT)) + return; + for (i = 0; i < 16; i++) supply_register (arm_num_regs + i, (char *) buf + i * 8); @@ -115,7 +136,45 @@ arm_store_wmmxregset (const void *buf) supply_register (arm_num_regs + i + 16, (char *) buf + 16 * 8 + i * 4); } -#endif /* __IWMMXT__ */ +static void +arm_fill_vfpregset (void *buf) +{ + int i, num, base; + + if (!(arm_hwcap & HWCAP_VFP)) + return; + + if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) + num = 32; + else + num = 16; + + base = find_regno ("d0"); + for (i = 0; i < num; i++) + collect_register (base + i, (char *) buf + i * 8); + + collect_register_by_name ("fpscr", (char *) buf + 32 * 8); +} + +static void +arm_store_vfpregset (const void *buf) +{ + int i, num, base; + + if (!(arm_hwcap & HWCAP_VFP)) + return; + + if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) + num = 32; + else + num = 16; + + base = find_regno ("d0"); + for (i = 0; i < num; i++) + supply_register (base + i, (char *) buf + i * 8); + + supply_register_by_name ("fpscr", (char *) buf + 32 * 8); +} extern int debug_threads; @@ -208,24 +267,94 @@ ps_get_thread_area (const struct ps_prochandle *ph, return PS_OK; } +static int +arm_get_hwcap (unsigned long *valp) +{ + unsigned char *data = alloca (8); + int offset = 0; + + while ((*the_target->read_auxv) (offset, data, 8) == 8) + { + unsigned int *data_p = (unsigned int *)data; + if (data_p[0] == AT_HWCAP) + { + *valp = data_p[1]; + return 1; + } + + offset += 8; + } + + *valp = 0; + return 0; +} + +static void +arm_arch_setup (void) +{ + arm_hwcap = 0; + if (arm_get_hwcap (&arm_hwcap) == 0) + { + init_registers_arm (); + return; + } + + if (arm_hwcap & HWCAP_IWMMXT) + { + init_registers_arm_with_iwmmxt (); + return; + } + + if (arm_hwcap & HWCAP_VFP) + { + int pid; + char *buf; + + /* NEON implies either no VFP, or VFPv3-D32. We only support + it with VFP. */ + if (arm_hwcap & HWCAP_NEON) + init_registers_arm_with_neon (); + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) + init_registers_arm_with_vfpv3 (); + else + init_registers_arm_with_vfpv2 (); + + /* Now make sure that the kernel supports reading these + registers. Support was added in 2.6.30. */ + pid = lwpid_of (get_thread_lwp (current_inferior)); + errno = 0; + buf = malloc (32 * 8 + 4); + if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0 + && errno == EIO) + { + arm_hwcap = 0; + init_registers_arm (); + } + free (buf); + + return; + } + + /* The default configuration uses legacy FPA registers, probably + simulated. */ + init_registers_arm (); +} + struct regset_info target_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4, GENERAL_REGS, arm_fill_gregset, arm_store_gregset }, -#ifdef __IWMMXT__ { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4, EXTENDED_REGS, arm_fill_wmmxregset, arm_store_wmmxregset }, -#endif + { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 32 * 8 + 4, + EXTENDED_REGS, + arm_fill_vfpregset, arm_store_vfpregset }, { 0, 0, -1, -1, NULL, NULL } }; struct linux_target_ops the_low_target = { -#ifdef __IWMMXT__ - init_registers_arm_with_iwmmxt, -#else - init_registers_arm, -#endif + arm_arch_setup, arm_num_regs, arm_regmap, arm_cannot_fetch_register, diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 6d677f259e3..5edc4730846 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -2394,7 +2394,16 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) if (debug_threads) { - fprintf (stderr, "Writing %02x to %08lx\n", (unsigned)myaddr[0], (long)memaddr); + /* Dump up to four bytes. */ + unsigned int val = * (unsigned int *) myaddr; + if (len == 1) + val = val & 0xff; + else if (len == 2) + val = val & 0xffff; + else if (len == 3) + val = val & 0xffffff; + fprintf (stderr, "Writing %0*x to 0x%08lx\n", 2 * ((len < 4) ? len : 4), + val, (long)memaddr); } /* Fill start and end extra bytes of buffer with existing memory data. */ diff --git a/gdb/regformats/arm-with-neon.dat b/gdb/regformats/arm-with-neon.dat new file mode 100644 index 00000000000..84694dce764 --- /dev/null +++ b/gdb/regformats/arm-with-neon.dat @@ -0,0 +1,63 @@ +# DO NOT EDIT: generated from arm-with-neon.xml +name:arm_with_neon +xmltarget:arm-with-neon.xml +expedite:r11,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:sp +32:lr +32:pc +0: +0: +0: +0: +0: +0: +0: +0: +0: +32:cpsr +64:d0 +64:d1 +64:d2 +64:d3 +64:d4 +64:d5 +64:d6 +64:d7 +64:d8 +64:d9 +64:d10 +64:d11 +64:d12 +64:d13 +64:d14 +64:d15 +64:d16 +64:d17 +64:d18 +64:d19 +64:d20 +64:d21 +64:d22 +64:d23 +64:d24 +64:d25 +64:d26 +64:d27 +64:d28 +64:d29 +64:d30 +64:d31 +32:fpscr diff --git a/gdb/regformats/arm-with-vfpv2.dat b/gdb/regformats/arm-with-vfpv2.dat new file mode 100644 index 00000000000..7c2780aff12 --- /dev/null +++ b/gdb/regformats/arm-with-vfpv2.dat @@ -0,0 +1,47 @@ +# DO NOT EDIT: generated from arm-with-vfpv2.xml +name:arm_with_vfpv2 +xmltarget:arm-with-vfpv2.xml +expedite:r11,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:sp +32:lr +32:pc +0: +0: +0: +0: +0: +0: +0: +0: +0: +32:cpsr +64:d0 +64:d1 +64:d2 +64:d3 +64:d4 +64:d5 +64:d6 +64:d7 +64:d8 +64:d9 +64:d10 +64:d11 +64:d12 +64:d13 +64:d14 +64:d15 +32:fpscr diff --git a/gdb/regformats/arm-with-vfpv3.dat b/gdb/regformats/arm-with-vfpv3.dat new file mode 100644 index 00000000000..9bb1e90ddd8 --- /dev/null +++ b/gdb/regformats/arm-with-vfpv3.dat @@ -0,0 +1,63 @@ +# DO NOT EDIT: generated from arm-with-vfpv3.xml +name:arm_with_vfpv3 +xmltarget:arm-with-vfpv3.xml +expedite:r11,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:sp +32:lr +32:pc +0: +0: +0: +0: +0: +0: +0: +0: +0: +32:cpsr +64:d0 +64:d1 +64:d2 +64:d3 +64:d4 +64:d5 +64:d6 +64:d7 +64:d8 +64:d9 +64:d10 +64:d11 +64:d12 +64:d13 +64:d14 +64:d15 +64:d16 +64:d17 +64:d18 +64:d19 +64:d20 +64:d21 +64:d22 +64:d23 +64:d24 +64:d25 +64:d26 +64:d27 +64:d28 +64:d29 +64:d30 +64:d31 +32:fpscr diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 88cc7e0442d..024257b7340 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -633,6 +633,21 @@ tdesc_numbered_register (const struct tdesc_feature *feature, return 1; } +/* Search FEATURE for a register named NAME, but do not assign a fixed + register number to it. */ + +int +tdesc_unnumbered_register (const struct tdesc_feature *feature, + const char *name) +{ + struct tdesc_reg *reg = tdesc_find_register_early (feature, name); + + if (reg == NULL) + return 0; + + return 1; +} + /* Search FEATURE for a register whose name is in NAMES and assign REGNO to it. */ @@ -708,7 +723,7 @@ tdesc_register_name (struct gdbarch *gdbarch, int regno) return ""; } -static struct type * +struct type * tdesc_register_type (struct gdbarch *gdbarch, int regno) { struct tdesc_arch_reg *arch_reg = tdesc_find_arch_register (gdbarch, regno); @@ -856,8 +871,9 @@ tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno, if (regno >= num_regs && regno < num_regs + num_pseudo_regs) { struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); - gdb_assert (data->pseudo_register_reggroup_p != NULL); - return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup); + if (data->pseudo_register_reggroup_p != NULL) + return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup); + /* Otherwise fall through to the default reggroup_p. */ } ret = tdesc_register_in_reggroup_p (gdbarch, regno, reggroup); diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h index 6553fc3440a..899f1197e27 100644 --- a/gdb/target-descriptions.h +++ b/gdb/target-descriptions.h @@ -98,6 +98,12 @@ int tdesc_numbered_register (const struct tdesc_feature *feature, struct tdesc_arch_data *data, int regno, const char *name); +/* Search FEATURE for a register named NAME, but do not assign a fixed + register number to it. */ + +int tdesc_unnumbered_register (const struct tdesc_feature *feature, + const char *name); + /* Search FEATURE for a register named NAME, and return its size in bits. The register must exist. */ @@ -159,6 +165,11 @@ struct tdesc_type *tdesc_named_type (const struct tdesc_feature *feature, const char *tdesc_register_name (struct gdbarch *gdbarch, int regno); +/* Return the type of register REGNO, from the target description or + from an architecture-provided pseudo_register_type method. */ + +struct type *tdesc_register_type (struct gdbarch *gdbarch, int regno); + /* Check whether REGNUM is a member of REGGROUP using the target description. Return -1 if the target description does not specify a group. */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index c2ae2f898cd..aaaa84eeed1 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2009-07-28 Daniel Jacobowitz + + * gdb.base/float.exp: Handle VFP registers. + 2009-07-14 Michael Snyder * gdb.reverse/finish-reverse.exp: Do not expect reverse-finish diff --git a/gdb/testsuite/gdb.base/float.exp b/gdb/testsuite/gdb.base/float.exp index a14a91548eb..09a02cad731 100644 --- a/gdb/testsuite/gdb.base/float.exp +++ b/gdb/testsuite/gdb.base/float.exp @@ -51,6 +51,11 @@ if { [istarget "alpha*-*-*"] } then { -re "Software FPU type.*mask:.*flags:.*$gdb_prompt $" { pass "info float (FPA)" } + -re "fpscr.*s0.*s1.*s31.*$gdb_prompt $" { + # Only check for single precision; d0 might be a vector register + # if we have NEON. + pass "info float (VFP)" + } -re "No floating.point info available for this processor.*" { pass "info float (without FPU)" } -- 2.30.2