This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Cortex-M CPSR T-bit fix


GDB can set the T-bit in the CPSR when setting the PC in order to indicate
Thumb mode, e.g. after loading a program and setting the start address.

Unfortunately ARM has broken the mould a bit and the Cortex-M (i.e.
Microcontroller profile) has the T-bit in a different place in the CPSR
(strictly the xPSR for Cortex-M).

Therefore this can cause problems. The attached fix allows GDB to look for
an ARM EABI attribute which indicates that this is at least Architecture v7
and whether this is the Microcontroller profile. Then later, the correct
CPSR T-bit can be determined from what was squirreled away in the struct
gdbarch_tdep.

2008-10-18  Jonathan Larmour <jifl@eCosCentric.com>

	* arm-tdep.h (CPSR_T): define as function-like macro, checking
	for M-profile, which affects T_bit position, e.g. for Cortex-M.
	(struct gdbarch_tdep): add arm_eabi_cpu_arch and
	arm_eabi_cpu_arch_profile members.
	* arm-tdep.c (arm_frame_is_thumb, arm_prologue_prev_register,
	arm_dwarf2_prev_register, arm_write_pc): Get tdep and use with
	updated CPSR_T macro.
	(arm_gdbarch_init): If EABI, extract architecture and profile
	attributes and store in tdep.

Ok?

Jifl
-- 
eCosCentric Limited      http://www.eCosCentric.com/     The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK.       Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.
------["Si fractum non sit, noli id reficere"]------       Opinions==mine
Index: arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.273
diff -u -5 -p -r1.273 arm-tdep.c
--- arm-tdep.c	1 Oct 2008 16:41:27 -0000	1.273
+++ arm-tdep.c	18 Oct 2008 04:08:15 -0000
@@ -255,18 +255,19 @@ int arm_apcs_32 = 1;
 
 static int
 arm_frame_is_thumb (struct frame_info *frame)
 {
   CORE_ADDR cpsr;
+  struct gdbarch_tdep *tdep = gdbarch_tdep(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
      the saved LR (from a prologue or DWARF frame).  So consult it and
      trust the unwinders.  */
   cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
 
-  return (cpsr & CPSR_T) != 0;
+  return (cpsr & CPSR_T(tdep)) != 0;
 }
 
 /* Callback for VEC_lower_bound.  */
 
 static inline int
@@ -1091,10 +1092,11 @@ static struct value *
 arm_prologue_prev_register (struct frame_info *this_frame,
 			    void **this_cache,
 			    int prev_regnum)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   struct arm_prologue_cache *cache;
 
   if (*this_cache == NULL)
     *this_cache = arm_make_prologue_cache (this_frame);
   cache = *this_cache;
@@ -1132,13 +1134,13 @@ arm_prologue_prev_register (struct frame
       CORE_ADDR lr, cpsr;
 
       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 |= CPSR_T (tdep);
       else
-	cpsr &= ~CPSR_T;
+	cpsr &= ~CPSR_T (tdep);
       return frame_unwind_got_constant (this_frame, prev_regnum, cpsr);
     }
 
   return trad_frame_get_prev_register (this_frame, cache->saved_regs,
 				       prev_regnum);
@@ -1260,10 +1262,11 @@ arm_unwind_sp (struct gdbarch *gdbarch, 
 static struct value *
 arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
 			  int regnum)
 {
   struct gdbarch * gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep(gdbarch);
   CORE_ADDR lr, cpsr;
 
   switch (regnum)
     {
     case ARM_PC_REGNUM:
@@ -1278,13 +1281,13 @@ arm_dwarf2_prev_register (struct frame_i
     case ARM_PS_REGNUM:
       /* Reconstruct the T bit; see arm_prologue_prev_register for details.  */
       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 |= CPSR_T (tdep);
       else
-	cpsr &= ~CPSR_T;
+	cpsr &= ~CPSR_T (tdep);
       return frame_unwind_got_constant (this_frame, regnum, cpsr);
 
     default:
       internal_error (__FILE__, __LINE__,
 		      _("Unexpected register %d"), regnum);
@@ -2943,22 +2946,24 @@ arm_record_special_symbol (struct gdbarc
 }
 
 static void
 arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep(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;
       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);
+	regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
+					val | CPSR_T (tdep));
       else
 	regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
-					val & ~(ULONGEST) CPSR_T);
+					val & ~(ULONGEST) CPSR_T (tdep));
     }
 }
 
 static struct value *
 value_of_arm_user_reg (struct frame_info *frame, const void *baton)
@@ -3003,10 +3008,12 @@ 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 have_fpa_registers = 1;
+  int arm_eabi_cpu_arch = -1;
+  int arm_eabi_cpu_arch_profile = -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
@@ -3155,10 +3162,29 @@ arm_gdbarch_init (struct gdbarch_info in
 		  warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
 		  break;
 		}
 	    }
 
+	  /* Cortex-M has different CPSR layout. Use object tags to
+	     determine if this was generated for the
+	     Microcontroller (M) profile.
+	     Cortex-A has a CPSR like previous ARM cores.
+	     Cortex-R is unknown. */
+
+	  attr = bfd_elf_get_obj_attr_int(info.abfd, OBJ_ATTR_PROC,
+					  Tag_CPU_arch);
+	  if (attr > 0)
+	      arm_eabi_cpu_arch = attr;
+	  if (arm_eabi_cpu_arch >= TAG_CPU_ARCH_V7) /* Profile n/a before V7 */
+	    {
+	      attr = bfd_elf_get_obj_attr_int(info.abfd, OBJ_ATTR_PROC,
+					      Tag_CPU_arch_profile);
+	      if (attr > 0)
+		arm_eabi_cpu_arch_profile = attr;
+	    }
+	}
+
 	  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))
@@ -3222,10 +3248,12 @@ arm_gdbarch_init (struct gdbarch_info in
   /* Record additional information about the architecture we are defining.
      These are gdbarch discriminators, like the OSABI.  */
   tdep->arm_abi = arm_abi;
   tdep->fp_model = fp_model;
   tdep->have_fpa_registers = have_fpa_registers;
+  tdep->arm_eabi_cpu_arch = arm_eabi_cpu_arch;
+  tdep->arm_eabi_cpu_arch_profile = arm_eabi_cpu_arch_profile;
 
   /* Breakpoints.  */
   switch (info.byte_order_for_code)
     {
     case BFD_ENDIAN_BIG:
Index: arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.32
diff -u -5 -p -r1.32 arm-tdep.h
--- arm-tdep.h	3 May 2008 22:20:13 -0000	1.32
+++ arm-tdep.h	18 Oct 2008 04:08:15 -0000
@@ -101,11 +101,14 @@ enum gdb_regnum {
 #define FLAG_N		0x80000000
 #define FLAG_Z		0x40000000
 #define FLAG_C		0x20000000
 #define FLAG_V		0x10000000
 
-#define CPSR_T		0x20
+/* CPSR T-bit for Architecture v7 Microcontroller Profile is different from
+   others */
+#define CPSR_T(tdep)	((tdep)->arm_eabi_cpu_arch_profile==(int)'M' ? \
+			 0x01000000 : 0x20)
 
 /* 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
    functions are passed in floating-point registers.  
@@ -169,10 +172,14 @@ struct gdbarch_tdep
   /* Convention for returning structures.  */
   enum struct_return struct_return;
 
   /* Cached core file helpers.  */
   struct regset *gregset, *fpregset;
+
+    /* Architecture version and profile from EABI attribute (-1 == unknown) */
+  int arm_eabi_cpu_arch;
+  int arm_eabi_cpu_arch_profile;
 };
 
 
 CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
 CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]