From 9779414d4e6816b221518d110f2157c60a5c83e9 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Tue, 24 Aug 2010 15:56:15 +0000 Subject: [PATCH] * arm-tdep.c: Include features/arm-with-m.c. (arm_psr_thumb_bit): New. Update all uses of CPSR_T to call this function. (arm_pc_is_thumb): Add a gdbarch argument. Update all callers. Check is_m after force-mode. (arm_gdbarch_init): Check the binary before the target description. Add check for M profile attribute. If we have an M-profile device, but no target register description, use arm-with-m. Recognize the new org.gnu.gdb.arm.m-profile feature and its xpsr register. (_initialize_arm_tdep): Call initialize_tdesc_arm_with_m. * arm-tdep.h (XPSR_T): Define. (struct gdbarch_tdep): Add is_m member. * features/arm-m-profile.xml, features/arm-with-m.c, features/arm-with-m.xml: New files. doc/ * gdb.texinfo (ARM Features): Document org.gnu.gdb.arm.m-profile. --- gdb/ChangeLog | 19 ++ gdb/arm-tdep.c | 428 +++++++++++++++++++-------------- gdb/arm-tdep.h | 3 + gdb/doc/ChangeLog | 5 + gdb/doc/gdb.texinfo | 8 +- gdb/features/arm-m-profile.xml | 27 +++ gdb/features/arm-with-m.c | 35 +++ gdb/features/arm-with-m.xml | 11 + 8 files changed, 354 insertions(+), 182 deletions(-) create mode 100644 gdb/features/arm-m-profile.xml create mode 100644 gdb/features/arm-with-m.c create mode 100644 gdb/features/arm-with-m.xml diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9d8af7754d..19416118ef 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,22 @@ +2010-08-24 Daniel Jacobowitz + Kazu Hirata + Jonathan Larmour + + * arm-tdep.c: Include features/arm-with-m.c. + (arm_psr_thumb_bit): New. Update all uses of CPSR_T to + call this function. + (arm_pc_is_thumb): Add a gdbarch argument. Update all callers. + Check is_m after force-mode. + (arm_gdbarch_init): Check the binary before the target description. + Add check for M profile attribute. If we have an M-profile device, + but no target register description, use arm-with-m. Recognize the + new org.gnu.gdb.arm.m-profile feature and its xpsr register. + (_initialize_arm_tdep): Call initialize_tdesc_arm_with_m. + * arm-tdep.h (XPSR_T): Define. + (struct gdbarch_tdep): Add is_m member. + * features/arm-m-profile.xml, features/arm-with-m.c, + features/arm-with-m.xml: New files. + 2010-08-23 Doug Evans * dwarf2read.c (read_structure_type): Add comment. diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 1ac8817f28..5a7e76d711 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -53,6 +53,8 @@ #include "gdb_assert.h" #include "vec.h" +#include "features/arm-with-m.c" + static int arm_debug; /* Macros for setting and testing a bit in a minimal symbol that marks @@ -255,12 +257,24 @@ static CORE_ADDR arm_analyze_prologue (struct gdbarch *gdbarch, int arm_apcs_32 = 1; +/* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */ + +static int +arm_psr_thumb_bit (struct gdbarch *gdbarch) +{ + if (gdbarch_tdep (gdbarch)->is_m) + return XPSR_T; + else + return CPSR_T; +} + /* Determine if FRAME is executing in Thumb mode. */ static int arm_frame_is_thumb (struct frame_info *frame) { CORE_ADDR cpsr; + ULONGEST t_bit = arm_psr_thumb_bit (get_frame_arch (frame)); /* Every ARM frame unwinder can unwind the T bit of the CPSR, either directly (from a signal frame or dummy frame) or by interpreting @@ -268,7 +282,7 @@ arm_frame_is_thumb (struct frame_info *frame) trust the unwinders. */ cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM); - return (cpsr & CPSR_T) != 0; + return (cpsr & t_bit) != 0; } /* Callback for VEC_lower_bound. */ @@ -347,7 +361,7 @@ static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame, any executing frame; otherwise, prefer arm_frame_is_thumb. */ static int -arm_pc_is_thumb (CORE_ADDR memaddr) +arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr) { struct obj_section *sec; struct minimal_symbol *sym; @@ -363,6 +377,10 @@ arm_pc_is_thumb (CORE_ADDR memaddr) if (strcmp (arm_force_mode_string, "thumb") == 0) return 1; + /* ARM v6-M and v7-M are always in Thumb mode. */ + if (gdbarch_tdep (gdbarch)->is_m) + return 1; + /* If there are mapping symbols, consult them. */ type = arm_find_mapping_symbol (memaddr, NULL); if (type) @@ -815,7 +833,7 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) associate prologue code with the opening brace; so this lets us skip the first line if we think it is the opening brace. */ - if (arm_pc_is_thumb (func_addr)) + if (arm_pc_is_thumb (gdbarch, func_addr)) analyzed_limit = thumb_analyze_prologue (gdbarch, func_addr, post_prologue_pc, NULL); else @@ -842,7 +860,7 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) /* Check if this is Thumb code. */ - if (arm_pc_is_thumb (pc)) + if (arm_pc_is_thumb (gdbarch, pc)) return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL); for (skip_pc = pc; skip_pc < limit_pc; skip_pc += 4) @@ -1507,13 +1525,14 @@ arm_prologue_prev_register (struct frame_info *this_frame, if (prev_regnum == ARM_PS_REGNUM) { CORE_ADDR lr, cpsr; + ULONGEST t_bit = arm_psr_thumb_bit (gdbarch); cpsr = get_frame_register_unsigned (this_frame, prev_regnum); lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM); if (IS_THUMB_ADDR (lr)) - cpsr |= CPSR_T; + cpsr |= t_bit; else - cpsr &= ~CPSR_T; + cpsr &= ~t_bit; return frame_unwind_got_constant (this_frame, prev_regnum, cpsr); } @@ -1640,6 +1659,7 @@ arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache, { struct gdbarch * gdbarch = get_frame_arch (this_frame); CORE_ADDR lr, cpsr; + ULONGEST t_bit = arm_psr_thumb_bit (gdbarch); switch (regnum) { @@ -1657,9 +1677,9 @@ arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache, cpsr = get_frame_register_unsigned (this_frame, regnum); lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM); if (IS_THUMB_ADDR (lr)) - cpsr |= CPSR_T; + cpsr |= t_bit; else - cpsr &= ~CPSR_T; + cpsr &= ~t_bit; return frame_unwind_got_constant (this_frame, regnum, cpsr); default: @@ -2008,7 +2028,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Set the return address. For the ARM, the return breakpoint is always at BP_ADDR. */ - if (arm_pc_is_thumb (bp_addr)) + if (arm_pc_is_thumb (gdbarch, bp_addr)) bp_addr |= 1; regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr); @@ -2147,7 +2167,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function, && TYPE_CODE_FUNC == TYPE_CODE (check_typedef (target_type))) { CORE_ADDR regval = extract_unsigned_integer (val, len, byte_order); - if (arm_pc_is_thumb (regval)) + if (arm_pc_is_thumb (gdbarch, regval)) { bfd_byte *copy = alloca (len); store_unsigned_integer (copy, len, byte_order, @@ -3352,7 +3372,7 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr) return bpaddr; /* ARM mode does not have this problem. */ - if (!arm_pc_is_thumb (bpaddr)) + if (!arm_pc_is_thumb (gdbarch, bpaddr)) return bpaddr; /* We are setting a breakpoint in Thumb code that could potentially @@ -3543,10 +3563,11 @@ static int displaced_in_arm_mode (struct regcache *regs) { ULONGEST ps; + ULONGEST t_bit = arm_psr_thumb_bit (get_regcache_arch (regs)); regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps); - return (ps & CPSR_T) == 0; + return (ps & t_bit) == 0; } /* Write to the PC as from a branch instruction. */ @@ -3568,18 +3589,18 @@ static void bx_write_pc (struct regcache *regs, ULONGEST val) { ULONGEST ps; + ULONGEST t_bit = arm_psr_thumb_bit (get_regcache_arch (regs)); regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps); if ((val & 1) == 1) { - regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps | CPSR_T); + regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps | t_bit); regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val & 0xfffffffe); } else if ((val & 2) == 0) { - regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, - ps & ~(ULONGEST) CPSR_T); + regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps & ~t_bit); regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val); } else @@ -3587,8 +3608,7 @@ bx_write_pc (struct regcache *regs, ULONGEST val) /* Unpredictable behaviour. Try to do something sensible (switch to ARM mode, align dest to 4 bytes). */ warning (_("Single-stepping BX to non-word-aligned ARM instruction.")); - regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, - ps & ~(ULONGEST) CPSR_T); + regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps & ~t_bit); regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val & 0xfffffffc); } } @@ -5345,7 +5365,9 @@ arm_displaced_step_fixup (struct gdbarch *gdbarch, static int gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info) { - if (arm_pc_is_thumb (memaddr)) + struct gdbarch *gdbarch = info->application_data; + + if (arm_pc_is_thumb (gdbarch, memaddr)) { static asymbol *asym; static combined_entry_type ce; @@ -5435,7 +5457,7 @@ arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); - if (arm_pc_is_thumb (*pcptr)) + if (arm_pc_is_thumb (gdbarch, *pcptr)) { *pcptr = UNMAKE_THUMB_ADDR (*pcptr); @@ -5474,7 +5496,7 @@ arm_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, arm_breakpoint_from_pc (gdbarch, pcptr, kindptr); - if (arm_pc_is_thumb (*pcptr) && *kindptr == 4) + if (arm_pc_is_thumb (gdbarch, *pcptr) && *kindptr == 4) /* The documented magic value for a 32-bit Thumb-2 breakpoint, so that this is not confused with a 32-bit ARM breakpoint. */ *kindptr = 3; @@ -6219,18 +6241,21 @@ arm_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, static void arm_write_pc (struct regcache *regcache, CORE_ADDR pc) { + struct gdbarch *gdbarch = get_regcache_arch (regcache); regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc); /* If necessary, set the T bit. */ if (arm_apcs_32) { - ULONGEST val; + ULONGEST val, t_bit; regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val); - if (arm_pc_is_thumb (pc)) - regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | CPSR_T); + t_bit = arm_psr_thumb_bit (gdbarch); + if (arm_pc_is_thumb (gdbarch, pc)) + regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, + val | t_bit); else regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, - val & ~(ULONGEST) CPSR_T); + val & ~t_bit); } } @@ -6411,165 +6436,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) enum arm_abi_kind arm_abi = arm_abi_global; enum arm_float_model fp_model = arm_fp_model; struct tdesc_arch_data *tdesc_data = NULL; - int i; + int i, is_m = 0; 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. */ - if (tdesc_has_registers (info.target_desc)) - { - /* For most registers we require GDB's default names; but also allow - the numeric names for sp / lr / pc, as a convenience. */ - static const char *const arm_sp_names[] = { "r13", "sp", NULL }; - static const char *const arm_lr_names[] = { "r14", "lr", NULL }; - static const char *const arm_pc_names[] = { "r15", "pc", NULL }; - - const struct tdesc_feature *feature; - int valid_p; - - feature = tdesc_find_feature (info.target_desc, - "org.gnu.gdb.arm.core"); - if (feature == NULL) - return NULL; - - tdesc_data = tdesc_data_alloc (); - - valid_p = 1; - for (i = 0; i < ARM_SP_REGNUM; i++) - valid_p &= tdesc_numbered_register (feature, tdesc_data, i, - arm_register_names[i]); - valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, - ARM_SP_REGNUM, - arm_sp_names); - valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, - ARM_LR_REGNUM, - arm_lr_names); - valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, - ARM_PC_REGNUM, - arm_pc_names); - valid_p &= tdesc_numbered_register (feature, tdesc_data, - ARM_PS_REGNUM, "cpsr"); - - if (!valid_p) - { - tdesc_data_cleanup (tdesc_data); - return NULL; - } - - feature = tdesc_find_feature (info.target_desc, - "org.gnu.gdb.arm.fpa"); - if (feature != NULL) - { - valid_p = 1; - for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++) - valid_p &= tdesc_numbered_register (feature, tdesc_data, i, - arm_register_names[i]); - if (!valid_p) - { - tdesc_data_cleanup (tdesc_data); - return NULL; - } - } - else - have_fpa_registers = 0; - - feature = tdesc_find_feature (info.target_desc, - "org.gnu.gdb.xscale.iwmmxt"); - if (feature != NULL) - { - static const char *const iwmmxt_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", "", "", "", "", - }; - - valid_p = 1; - for (i = ARM_WR0_REGNUM; i <= ARM_WR15_REGNUM; i++) - valid_p - &= tdesc_numbered_register (feature, tdesc_data, i, - iwmmxt_names[i - ARM_WR0_REGNUM]); - - /* Check for the control registers, but do not fail if they - are missing. */ - for (i = ARM_WC0_REGNUM; i <= ARM_WCASF_REGNUM; i++) - tdesc_numbered_register (feature, tdesc_data, i, - iwmmxt_names[i - ARM_WR0_REGNUM]); - - for (i = ARM_WCGR0_REGNUM; i <= ARM_WCGR3_REGNUM; i++) - valid_p - &= tdesc_numbered_register (feature, tdesc_data, i, - iwmmxt_names[i - ARM_WR0_REGNUM]); - - if (!valid_p) - { - tdesc_data_cleanup (tdesc_data); - 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; - } - } - } + const struct target_desc *tdesc = info.target_desc; /* If we have an object to base this architecture on, try to determine its ABI. */ @@ -6605,6 +6476,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) else if (ei_osabi == ELFOSABI_NONE) { int eabi_ver = EF_ARM_EABI_VERSION (e_flags); + int attr_arch, attr_profile; switch (eabi_ver) { @@ -6662,6 +6534,26 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) warning (_("unknown ARM EABI version 0x%x"), eabi_ver); break; } + +#ifdef HAVE_ELF + /* Detect M-profile programs. This only works if the + executable file includes build attributes; GCC does + copy them to the executable, but e.g. RealView does + not. */ + attr_arch = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, + Tag_CPU_arch); + attr_profile = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, + Tag_CPU_arch_profile); + /* GCC specifies the profile for v6-M; RealView only + specifies the profile for architectures starting with + V7 (as opposed to architectures with a tag + numerically greater than TAG_CPU_ARCH_V7). */ + if (!tdesc_has_registers (tdesc) + && (attr_arch == TAG_CPU_ARCH_V6_M + || attr_arch == TAG_CPU_ARCH_V6S_M + || attr_profile == 'M')) + tdesc = tdesc_arm_with_m; +#endif } if (fp_model == ARM_FLOAT_AUTO) @@ -6699,6 +6591,172 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } } + /* Check any target description for validity. */ + if (tdesc_has_registers (tdesc)) + { + /* For most registers we require GDB's default names; but also allow + the numeric names for sp / lr / pc, as a convenience. */ + static const char *const arm_sp_names[] = { "r13", "sp", NULL }; + static const char *const arm_lr_names[] = { "r14", "lr", NULL }; + static const char *const arm_pc_names[] = { "r15", "pc", NULL }; + + const struct tdesc_feature *feature; + int valid_p; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.arm.core"); + if (feature == NULL) + { + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.arm.m-profile"); + if (feature == NULL) + return NULL; + else + is_m = 1; + } + + tdesc_data = tdesc_data_alloc (); + + valid_p = 1; + for (i = 0; i < ARM_SP_REGNUM; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + arm_register_names[i]); + valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, + ARM_SP_REGNUM, + arm_sp_names); + valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, + ARM_LR_REGNUM, + arm_lr_names); + valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, + ARM_PC_REGNUM, + arm_pc_names); + if (is_m) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + ARM_PS_REGNUM, "xpsr"); + else + valid_p &= tdesc_numbered_register (feature, tdesc_data, + ARM_PS_REGNUM, "cpsr"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.arm.fpa"); + if (feature != NULL) + { + valid_p = 1; + for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + arm_register_names[i]); + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + } + else + have_fpa_registers = 0; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.xscale.iwmmxt"); + if (feature != NULL) + { + static const char *const iwmmxt_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", "", "", "", "", + }; + + valid_p = 1; + for (i = ARM_WR0_REGNUM; i <= ARM_WR15_REGNUM; i++) + valid_p + &= tdesc_numbered_register (feature, tdesc_data, i, + iwmmxt_names[i - ARM_WR0_REGNUM]); + + /* Check for the control registers, but do not fail if they + are missing. */ + for (i = ARM_WC0_REGNUM; i <= ARM_WCASF_REGNUM; i++) + tdesc_numbered_register (feature, tdesc_data, i, + iwmmxt_names[i - ARM_WR0_REGNUM]); + + for (i = ARM_WCGR0_REGNUM; i <= ARM_WCGR3_REGNUM; i++) + valid_p + &= tdesc_numbered_register (feature, tdesc_data, i, + iwmmxt_names[i - ARM_WR0_REGNUM]); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + 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 (tdesc, + "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 (tdesc, + "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 there is already a candidate, use it. */ for (best_arch = gdbarch_list_lookup_by_info (arches, &info); best_arch != NULL; @@ -6717,6 +6775,10 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) since gdbarches with a different target description are automatically disqualified. */ + /* Do check is_m, though, since it might come from the binary. */ + if (is_m != gdbarch_tdep (best_arch->gdbarch)->is_m) + continue; + /* Found a match. */ break; } @@ -6735,6 +6797,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) These are gdbarch discriminators, like the OSABI. */ tdep->arm_abi = arm_abi; tdep->fp_model = fp_model; + tdep->is_m = is_m; tdep->have_fpa_registers = have_fpa_registers; tdep->have_vfp_registers = have_vfp_registers; tdep->have_vfp_pseudos = have_vfp_pseudos; @@ -6908,7 +6971,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { set_tdesc_pseudo_register_name (gdbarch, arm_register_name); - tdesc_use_registers (gdbarch, info.target_desc, tdesc_data); + tdesc_use_registers (gdbarch, tdesc, tdesc_data); /* Override tdesc_register_type to adjust the types of VFP registers for NEON. */ @@ -6963,6 +7026,9 @@ _initialize_arm_tdep (void) bfd_target_elf_flavour, arm_elf_osabi_sniffer); + /* Initialize the standard target descriptions. */ + initialize_tdesc_arm_with_m (); + /* Get the number of possible sets of register names defined in opcodes. */ num_disassembly_options = get_arm_regname_num_options (); diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h index b6283efb91..87387aabb6 100644 --- a/gdb/arm-tdep.h +++ b/gdb/arm-tdep.h @@ -108,6 +108,8 @@ enum gdb_regnum { #define CPSR_T 0x20 +#define XPSR_T 0x01000000 + /* Type of floating-point code in use by inferior. There are really 3 models that are traditionally supported (plus the endianness issue), but gcc can only generate 2 of those. The third is APCS_FLOAT, where arguments to @@ -163,6 +165,7 @@ struct gdbarch_tdep have_vfp_pseudos. */ int have_neon; /* Do we have a NEON unit? */ + int is_m; /* Does the target follow the "M" profile. */ CORE_ADDR lowest_pc; /* Lowest address at which instructions will appear. */ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index a864e2f5c7..d66b613e56 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2010-08-24 Daniel Jacobowitz + + * gdb.texinfo (ARM Features): Document + org.gnu.gdb.arm.m-profile. + 2010-08-23 Tom Tromey PR python/11145: diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index d0c7dddac4..3418eb2fc6 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -35647,10 +35647,16 @@ registers using the capitalization used in the description. @subsection ARM Features @cindex target descriptions, ARM features -The @samp{org.gnu.gdb.arm.core} feature is required for ARM targets. +The @samp{org.gnu.gdb.arm.core} feature is required for non-M-profile +ARM targets. It should contain registers @samp{r0} through @samp{r13}, @samp{sp}, @samp{lr}, @samp{pc}, and @samp{cpsr}. +For M-profile targets (e.g. Cortex-M3), the @samp{org.gnu.gdb.arm.core} +feature is replaced by @samp{org.gnu.gdb.arm.m-profile}. It should contain +registers @samp{r0} through @samp{r13}, @samp{sp}, @samp{lr}, @samp{pc}, +and @samp{xpsr}. + The @samp{org.gnu.gdb.arm.fpa} feature is optional. If present, it should contain registers @samp{f0} through @samp{f7} and @samp{fps}. diff --git a/gdb/features/arm-m-profile.xml b/gdb/features/arm-m-profile.xml new file mode 100644 index 0000000000..b88e9e60ac --- /dev/null +++ b/gdb/features/arm-m-profile.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/arm-with-m.c b/gdb/features/arm-with-m.c new file mode 100644 index 0000000000..b188f5732a --- /dev/null +++ b/gdb/features/arm-with-m.c @@ -0,0 +1,35 @@ +/* THIS FILE IS GENERATED. Original: arm-with-m.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_arm_with_m; +static void +initialize_tdesc_arm_with_m (void) +{ + struct target_desc *result = allocate_target_description (); + struct tdesc_feature *feature; + struct tdesc_type *field_type, *type; + + feature = tdesc_create_feature (result, "org.gnu.gdb.arm.m-profile"); + 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, "xpsr", 25, 1, NULL, 32, "int"); + + tdesc_arm_with_m = result; +} diff --git a/gdb/features/arm-with-m.xml b/gdb/features/arm-with-m.xml new file mode 100644 index 0000000000..227b920498 --- /dev/null +++ b/gdb/features/arm-with-m.xml @@ -0,0 +1,11 @@ + + + + + + +