* 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.
This commit is contained in:
parent
b8fa875047
commit
9779414d4e
@ -1,3 +1,22 @@
|
||||
2010-08-24 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
Kazu Hirata <kazu@codesourcery.com>
|
||||
Jonathan Larmour <jifl@eCosCentric.com>
|
||||
|
||||
* 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 <dje@google.com>
|
||||
|
||||
* dwarf2read.c (read_structure_type): Add comment.
|
||||
|
428
gdb/arm-tdep.c
428
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 ();
|
||||
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2010-08-24 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (ARM Features): Document
|
||||
org.gnu.gdb.arm.m-profile.
|
||||
|
||||
2010-08-23 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
PR python/11145:
|
||||
|
@ -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}.
|
||||
|
||||
|
27
gdb/features/arm-m-profile.xml
Normal file
27
gdb/features/arm-m-profile.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.arm.m-profile">
|
||||
<reg name="r0" bitsize="32"/>
|
||||
<reg name="r1" bitsize="32"/>
|
||||
<reg name="r2" bitsize="32"/>
|
||||
<reg name="r3" bitsize="32"/>
|
||||
<reg name="r4" bitsize="32"/>
|
||||
<reg name="r5" bitsize="32"/>
|
||||
<reg name="r6" bitsize="32"/>
|
||||
<reg name="r7" bitsize="32"/>
|
||||
<reg name="r8" bitsize="32"/>
|
||||
<reg name="r9" bitsize="32"/>
|
||||
<reg name="r10" bitsize="32"/>
|
||||
<reg name="r11" bitsize="32"/>
|
||||
<reg name="r12" bitsize="32"/>
|
||||
<reg name="sp" bitsize="32" type="data_ptr"/>
|
||||
<reg name="lr" bitsize="32"/>
|
||||
<reg name="pc" bitsize="32" type="code_ptr"/>
|
||||
<reg name="xpsr" bitsize="32" regnum="25"/>
|
||||
</feature>
|
35
gdb/features/arm-with-m.c
Normal file
35
gdb/features/arm-with-m.c
Normal file
@ -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;
|
||||
}
|
11
gdb/features/arm-with-m.xml
Normal file
11
gdb/features/arm-with-m.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||||
<target>
|
||||
<xi:include href="arm-m-profile.xml"/>
|
||||
</target>
|
Loading…
Reference in New Issue
Block a user