diff options
Diffstat (limited to 'gdb/arm-tdep.c')
-rw-r--r-- | gdb/arm-tdep.c | 392 |
1 files changed, 229 insertions, 163 deletions
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 1ac8817..5a7e76d 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,13 +6436,163 @@ 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; + const struct target_desc *tdesc = info.target_desc; + + /* If we have an object to base this architecture on, try to determine + its ABI. */ + + if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL) + { + int ei_osabi, e_flags; + + switch (bfd_get_flavour (info.abfd)) + { + case bfd_target_aout_flavour: + /* Assume it's an old APCS-style ABI. */ + arm_abi = ARM_ABI_APCS; + break; + + case bfd_target_coff_flavour: + /* Assume it's an old APCS-style ABI. */ + /* XXX WinCE? */ + arm_abi = ARM_ABI_APCS; + break; + + case bfd_target_elf_flavour: + ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI]; + e_flags = elf_elfheader (info.abfd)->e_flags; + + if (ei_osabi == ELFOSABI_ARM) + { + /* GNU tools used to use this value, but do not for EABI + objects. There's nowhere to tag an EABI version + anyway, so assume APCS. */ + arm_abi = ARM_ABI_APCS; + } + else if (ei_osabi == ELFOSABI_NONE) + { + int eabi_ver = EF_ARM_EABI_VERSION (e_flags); + int attr_arch, attr_profile; + + switch (eabi_ver) + { + case EF_ARM_EABI_UNKNOWN: + /* Assume GNU tools. */ + arm_abi = ARM_ABI_APCS; + break; + + case EF_ARM_EABI_VER4: + case EF_ARM_EABI_VER5: + arm_abi = ARM_ABI_AAPCS; + /* EABI binaries default to VFP float ordering. + They may also contain build attributes that can + be used to identify if the VFP argument-passing + ABI is in use. */ + if (fp_model == ARM_FLOAT_AUTO) + { +#ifdef HAVE_ELF + switch (bfd_elf_get_obj_attr_int (info.abfd, + OBJ_ATTR_PROC, + Tag_ABI_VFP_args)) + { + case 0: + /* "The user intended FP parameter/result + passing to conform to AAPCS, base + variant". */ + fp_model = ARM_FLOAT_SOFT_VFP; + break; + case 1: + /* "The user intended FP parameter/result + passing to conform to AAPCS, VFP + variant". */ + fp_model = ARM_FLOAT_VFP; + break; + case 2: + /* "The user intended FP parameter/result + passing to conform to tool chain-specific + conventions" - we don't know any such + conventions, so leave it as "auto". */ + break; + default: + /* Attribute value not mentioned in the + October 2008 ABI, so leave it as + "auto". */ + break; + } +#else + fp_model = ARM_FLOAT_SOFT_VFP; +#endif + } + break; + + default: + /* Leave it as "auto". */ + 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) + { + int e_flags = elf_elfheader (info.abfd)->e_flags; + + switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT)) + { + case 0: + /* Leave it as "auto". Strictly speaking this case + means FPA, but almost nobody uses that now, and + many toolchains fail to set the appropriate bits + for the floating-point model they use. */ + break; + case EF_ARM_SOFT_FLOAT: + fp_model = ARM_FLOAT_SOFT_FPA; + break; + case EF_ARM_VFP_FLOAT: + fp_model = ARM_FLOAT_VFP; + break; + case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT: + fp_model = ARM_FLOAT_SOFT_VFP; + break; + } + } + + if (e_flags & EF_ARM_BE8) + info.byte_order_for_code = BFD_ENDIAN_LITTLE; + + break; + + default: + /* Leave it as "auto". */ + break; + } + } /* Check any target description for validity. */ - if (tdesc_has_registers (info.target_desc)) + 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. */ @@ -6428,10 +6603,17 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) const struct tdesc_feature *feature; int valid_p; - feature = tdesc_find_feature (info.target_desc, + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.arm.core"); if (feature == NULL) - return 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 (); @@ -6448,8 +6630,12 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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 (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) { @@ -6457,7 +6643,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) return NULL; } - feature = tdesc_find_feature (info.target_desc, + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.arm.fpa"); if (feature != NULL) { @@ -6474,7 +6660,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) else have_fpa_registers = 0; - feature = tdesc_find_feature (info.target_desc, + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.xscale.iwmmxt"); if (feature != NULL) { @@ -6512,7 +6698,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* 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, + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.arm.vfp"); if (feature != NULL) { @@ -6549,7 +6735,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* 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, + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.arm.neon"); if (feature != NULL) { @@ -6571,134 +6757,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } } - /* If we have an object to base this architecture on, try to determine - its ABI. */ - - if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL) - { - int ei_osabi, e_flags; - - switch (bfd_get_flavour (info.abfd)) - { - case bfd_target_aout_flavour: - /* Assume it's an old APCS-style ABI. */ - arm_abi = ARM_ABI_APCS; - break; - - case bfd_target_coff_flavour: - /* Assume it's an old APCS-style ABI. */ - /* XXX WinCE? */ - arm_abi = ARM_ABI_APCS; - break; - - case bfd_target_elf_flavour: - ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI]; - e_flags = elf_elfheader (info.abfd)->e_flags; - - if (ei_osabi == ELFOSABI_ARM) - { - /* GNU tools used to use this value, but do not for EABI - objects. There's nowhere to tag an EABI version - anyway, so assume APCS. */ - arm_abi = ARM_ABI_APCS; - } - else if (ei_osabi == ELFOSABI_NONE) - { - int eabi_ver = EF_ARM_EABI_VERSION (e_flags); - - switch (eabi_ver) - { - case EF_ARM_EABI_UNKNOWN: - /* Assume GNU tools. */ - arm_abi = ARM_ABI_APCS; - break; - - case EF_ARM_EABI_VER4: - case EF_ARM_EABI_VER5: - arm_abi = ARM_ABI_AAPCS; - /* EABI binaries default to VFP float ordering. - They may also contain build attributes that can - be used to identify if the VFP argument-passing - ABI is in use. */ - if (fp_model == ARM_FLOAT_AUTO) - { -#ifdef HAVE_ELF - switch (bfd_elf_get_obj_attr_int (info.abfd, - OBJ_ATTR_PROC, - Tag_ABI_VFP_args)) - { - case 0: - /* "The user intended FP parameter/result - passing to conform to AAPCS, base - variant". */ - fp_model = ARM_FLOAT_SOFT_VFP; - break; - case 1: - /* "The user intended FP parameter/result - passing to conform to AAPCS, VFP - variant". */ - fp_model = ARM_FLOAT_VFP; - break; - case 2: - /* "The user intended FP parameter/result - passing to conform to tool chain-specific - conventions" - we don't know any such - conventions, so leave it as "auto". */ - break; - default: - /* Attribute value not mentioned in the - October 2008 ABI, so leave it as - "auto". */ - break; - } -#else - fp_model = ARM_FLOAT_SOFT_VFP; -#endif - } - break; - - default: - /* Leave it as "auto". */ - warning (_("unknown ARM EABI version 0x%x"), eabi_ver); - break; - } - } - - if (fp_model == ARM_FLOAT_AUTO) - { - int e_flags = elf_elfheader (info.abfd)->e_flags; - - switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT)) - { - case 0: - /* Leave it as "auto". Strictly speaking this case - means FPA, but almost nobody uses that now, and - many toolchains fail to set the appropriate bits - for the floating-point model they use. */ - break; - case EF_ARM_SOFT_FLOAT: - fp_model = ARM_FLOAT_SOFT_FPA; - break; - case EF_ARM_VFP_FLOAT: - fp_model = ARM_FLOAT_VFP; - break; - case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT: - fp_model = ARM_FLOAT_SOFT_VFP; - break; - } - } - - if (e_flags & EF_ARM_BE8) - info.byte_order_for_code = BFD_ENDIAN_LITTLE; - - break; - - default: - /* Leave it as "auto". */ - break; - } - } - /* 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 (); |