[patch] Add support for ARMv7M devices.

Kazu Hirata
2010-06-09T14:03:38Z

Hi,

Attached is a patch to add support for ARMv7M devices.

The patch is bigger than it really is due to the signature change to
arm_pc_is_thumb.

Here are some highlights:

- arm_pc_is_thumb always returns 1 if the target is an ARMv7M device.

- arm_write_pc is adjusted so that it will set the Thumb bit in XPSR
for an ARMv7M device. Note that the position of Thumb bit in the
status register is different between ARMv7M devices and older
devices.

- arm_gdbarch_init looks for "org.gnu.gdb.arm.core-v7m".

Tested by running Hello, world on a Cortex-M3 device. OK to apply?

Kazu Hirata

2010-06-08 Daniel Jacobowitz <dan@codesourcery.com>
Kazu Hirata <kazu@codesourcery.com>

* arm-tdep.c (arm_pc_is_thumb): Return 1 if the target is an
M-profile device.
(arm_write_pc): Handle an M-profile device.
(arm_gdbarch_init): Handle an M-profile device.
* arm-tdep.h (XPSR_T): New.
(gdbarch_tdep): Add is_m.

Index: gdb/arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.304
diff -u -d -p -r1.304 arm-tdep.c
--- gdb/arm-tdep.c 27 May 2010 19:06:12 -0000 1.304
+++ gdb/arm-tdep.c 9 Jun 2010 03:12:16 -0000
@@ -347,12 +347,16 @@ static CORE_ADDR arm_get_next_pc_raw (st
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;
char type;

+ /* ARMv7M is always in Thumb mode. */
+ if (gdbarch_tdep (gdbarch)->is_m)
+ return 1;
+
/* If bit 0 of the address is set, assume this is a Thumb address. */
if (IS_THUMB_ADDR (memaddr))
return 1;
@@ -815,7 +819,7 @@ arm_skip_prologue (struct gdbarch *gdbar
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 +846,7 @@ arm_skip_prologue (struct gdbarch *gdbar

/* 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)
@@ -2008,7 +2012,7 @@ arm_push_dummy_call (struct gdbarch *gdb

/* 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 +2151,7 @@ arm_push_dummy_call (struct gdbarch *gdb
&& TYPE_CODE_FUNC == TYPE_CODE (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 +3356,7 @@ arm_adjust_breakpoint_address (struct gd
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
@@ -5345,7 +5349,9 @@ arm_displaced_step_fixup (struct 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 +5441,7 @@ arm_breakpoint_from_pc (struct gdbarch *
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 +5480,7 @@ arm_remote_breakpoint_from_pc (struct gd

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,6 +6225,7 @@ arm_record_special_symbol (struct gdbarc
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. */
@@ -6226,11 +6233,18 @@ arm_write_pc (struct regcache *regcache,
{
ULONGEST val;
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);
+ if (!gdbarch_tdep (gdbarch)->is_m)
+ {
+ if (arm_pc_is_thumb (gdbarch, pc))
+ regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
+ val | CPSR_T);
+ else
+ regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
+ val & ~(ULONGEST) CPSR_T);
+ }
else
regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
- val & ~(ULONGEST) CPSR_T);
+ val | XPSR_T);
}
}

@@ -6411,7 +6425,7 @@ arm_gdbarch_init (struct gdbarch_info in
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;
@@ -6431,7 +6445,14 @@ arm_gdbarch_init (struct gdbarch_info in
feature = tdesc_find_feature (info.target_desc,
"org.gnu.gdb.arm.core");
if (feature == NULL)
- return NULL;
+ {
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.arm.core-v7m");
+ if (feature == NULL)
+ return NULL;
+ else
+ is_m = 1;
+ }

tdesc_data = tdesc_data_alloc ();

@@ -6448,8 +6469,12 @@ arm_gdbarch_init (struct gdbarch_info in
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)
{
@@ -6735,6 +6760,7 @@ arm_gdbarch_init (struct gdbarch_info in
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;
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.40
diff -u -d -p -r1.40 arm-tdep.h
--- gdb/arm-tdep.h 12 Apr 2010 13:52:43 -0000 1.40
+++ gdb/arm-tdep.h 9 Jun 2010 03:12:16 -0000
@@ -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. */