[libcxxabi] r197591 - Add a first cut at a Registers_arm class, to be used for 32bit arm EHABI unwinding.

Nico Weber nicolasweber at gmx.de
Wed Dec 18 09:53:55 PST 2013


Author: nico
Date: Wed Dec 18 11:53:55 2013
New Revision: 197591

URL: http://llvm.org/viewvc/llvm-project?rev=197591&view=rev
Log:
Add a first cut at a Registers_arm class, to be used for 32bit arm EHABI unwinding.


Modified:
    libcxxabi/trunk/include/libunwind.h
    libcxxabi/trunk/src/Unwind/Registers.hpp
    libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.S
    libcxxabi/trunk/src/Unwind/UnwindRegistersSave.S

Modified: libcxxabi/trunk/include/libunwind.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/include/libunwind.h?rev=197591&r1=197590&r2=197591&view=diff
==============================================================================
--- libcxxabi/trunk/include/libunwind.h (original)
+++ libcxxabi/trunk/include/libunwind.h Wed Dec 18 11:53:55 2013
@@ -353,4 +353,134 @@ enum {
   UNW_ARM64_D31 = 95,
 };
 
+// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1.
+// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3.
+// In this scheme, even though the 64-bit floating point registers D0-D31
+// overlap physically with the 32-bit floating pointer registers S0-S31,
+// they are given a non-overlapping range of register numbers.
+//
+// Commented out ranges are not preserved during unwinding.
+enum {
+  UNW_ARM_R0  = 0,
+  UNW_ARM_R1  = 1,
+  UNW_ARM_R2  = 2,
+  UNW_ARM_R3  = 3,
+  UNW_ARM_R4  = 4,
+  UNW_ARM_R5  = 5,
+  UNW_ARM_R6  = 6,
+  UNW_ARM_R7  = 7,
+  UNW_ARM_R8  = 8,
+  UNW_ARM_R9  = 9,
+  UNW_ARM_R10 = 10,
+  UNW_ARM_R11 = 11,
+  UNW_ARM_R12 = 12,
+  UNW_ARM_SP  = 13,  // Logical alias for UNW_REG_SP
+  UNW_ARM_R13 = 13,
+  UNW_ARM_LR  = 14,
+  UNW_ARM_R14 = 14,
+  UNW_ARM_IP  = 15,  // Logical alias for UNW_REG_IP
+  UNW_ARM_R15 = 15,
+  // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31.
+  UNW_ARM_S0  = 64,
+  UNW_ARM_S1  = 65,
+  UNW_ARM_S2  = 66,
+  UNW_ARM_S3  = 67,
+  UNW_ARM_S4  = 68,
+  UNW_ARM_S5  = 69,
+  UNW_ARM_S6  = 70,
+  UNW_ARM_S7  = 71,
+  UNW_ARM_S8  = 72,
+  UNW_ARM_S9  = 73,
+  UNW_ARM_S10 = 74,
+  UNW_ARM_S11 = 75,
+  UNW_ARM_S12 = 76,
+  UNW_ARM_S13 = 77,
+  UNW_ARM_S14 = 78,
+  UNW_ARM_S15 = 79,
+  UNW_ARM_S16 = 80,
+  UNW_ARM_S17 = 81,
+  UNW_ARM_S18 = 82,
+  UNW_ARM_S19 = 83,
+  UNW_ARM_S20 = 84,
+  UNW_ARM_S21 = 85,
+  UNW_ARM_S22 = 86,
+  UNW_ARM_S23 = 87,
+  UNW_ARM_S24 = 88,
+  UNW_ARM_S25 = 89,
+  UNW_ARM_S26 = 90,
+  UNW_ARM_S27 = 91,
+  UNW_ARM_S28 = 92,
+  UNW_ARM_S29 = 93,
+  UNW_ARM_S30 = 94,
+  UNW_ARM_S31 = 95,
+  //  96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP.
+  // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX)
+  UNW_ARM_WR0 = 112,
+  UNW_ARM_WR1 = 113,
+  UNW_ARM_WR2 = 114,
+  UNW_ARM_WR3 = 115,
+  UNW_ARM_WR4 = 116,
+  UNW_ARM_WR5 = 117,
+  UNW_ARM_WR6 = 118,
+  UNW_ARM_WR7 = 119,
+  UNW_ARM_WR8 = 120,
+  UNW_ARM_WR9 = 121,
+  UNW_ARM_WR10 = 122,
+  UNW_ARM_WR11 = 123,
+  UNW_ARM_WR12 = 124,
+  UNW_ARM_WR13 = 125,
+  UNW_ARM_WR14 = 126,
+  UNW_ARM_WR15 = 127,
+  // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC}
+  // 134-143 -- Reserved
+  // 144-150 -- R8_USR–R14_USR
+  // 151-157 -- R8_FIQ–R14_FIQ
+  // 158-159 -- R13_IRQ–R14_IRQ
+  // 160-161 -- R13_ABT–R14_ABT
+  // 162-163 -- R13_UND–R14_UND
+  // 164-165 -- R13_SVC–R14_SVC
+  // 166-191 -- Reserved
+  UNW_ARM_WC0 = 192,
+  UNW_ARM_WC1 = 193,
+  UNW_ARM_WC2 = 194,
+  UNW_ARM_WC3 = 195,
+  // 196-199 -- wC4-wC7 (Intel wireless MMX control)
+  // 200-255 -- Reserved
+  UNW_ARM_D0  = 256,
+  UNW_ARM_D1  = 257,
+  UNW_ARM_D2  = 258,
+  UNW_ARM_D3  = 259,
+  UNW_ARM_D4  = 260,
+  UNW_ARM_D5  = 261,
+  UNW_ARM_D6  = 262,
+  UNW_ARM_D7  = 263,
+  UNW_ARM_D8  = 264,
+  UNW_ARM_D9  = 265,
+  UNW_ARM_D10 = 266,
+  UNW_ARM_D11 = 267,
+  UNW_ARM_D12 = 268,
+  UNW_ARM_D13 = 269,
+  UNW_ARM_D14 = 270,
+  UNW_ARM_D15 = 271,
+  UNW_ARM_D16 = 272,
+  UNW_ARM_D17 = 273,
+  UNW_ARM_D18 = 274,
+  UNW_ARM_D19 = 275,
+  UNW_ARM_D20 = 276,
+  UNW_ARM_D21 = 277,
+  UNW_ARM_D22 = 278,
+  UNW_ARM_D23 = 279,
+  UNW_ARM_D24 = 280,
+  UNW_ARM_D25 = 281,
+  UNW_ARM_D26 = 282,
+  UNW_ARM_D27 = 283,
+  UNW_ARM_D28 = 284,
+  UNW_ARM_D29 = 285,
+  UNW_ARM_D30 = 286,
+  UNW_ARM_D31 = 287,
+  // 288-319 -- Reserved for VFP/Neon
+  // 320-8191 -- Reserved
+  // 8192-16383 -- Unspecified vendor co-processor register.
+};
+
 #endif

Modified: libcxxabi/trunk/src/Unwind/Registers.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/Registers.hpp?rev=197591&r1=197590&r2=197591&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/Registers.hpp (original)
+++ libcxxabi/trunk/src/Unwind/Registers.hpp Wed Dec 18 11:53:55 2013
@@ -1273,6 +1273,296 @@ inline void Registers_arm64::setVectorRe
   _LIBUNWIND_ABORT("no arm64 vector register support yet");
 }
 
+/// Registers_arm holds the register state of a thread in a 32-bit arm
+/// process.
+///
+/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit,
+/// this uses more memory than required.
+///
+/// FIXME: Support MMX Data Registers, Control registers, and load/stores
+/// for different representations in the VFP registers as listed in
+/// Table 1 of EHABI #7.5.2
+class _LIBUNWIND_HIDDEN Registers_arm {
+public:
+  Registers_arm();
+  Registers_arm(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  // FIXME: Due to ARM VRS's support for reading/writing different
+  // representations into the VFP registers this set of accessors seem wrong.
+  // If {get,set}FloatRegister() is the backing store for
+  // _Unwind_VRS_{Get,Set} then it might be best to return a tagged union
+  // with types for each representation in _Unwind_VRS_DataRepresentation.
+  // Similarly, unw_{get,set}_fpreg in the public libunwind API may want to
+  // use a similar tagged union to back the unw_fpreg_t output parameter type.
+  bool        validFloatRegister(int num) const;
+  unw_fpreg_t getFloatRegister(int num) const;
+  void        setFloatRegister(int num, unw_fpreg_t value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto();
+
+  uint32_t  getSP() const         { return _registers.__sp; }
+  void      setSP(uint32_t value) { _registers.__sp = value; }
+  uint32_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint32_t value) { _registers.__pc = value; }
+
+private:
+  struct GPRs {
+    uint32_t __r[13]; // r0-r12
+    uint32_t __sp;    // Stack pointer r13
+    uint32_t __lr;    // Link register r14
+    uint32_t __pc;    // Program counter r15
+  };
+
+  GPRs    _registers;
+};
+
+inline Registers_arm::Registers_arm(const void *registers) {
+  static_assert(sizeof(Registers_arm) < sizeof(unw_context_t),
+                    "arm registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_arm::Registers_arm() {
+  bzero(&_registers, sizeof(_registers));
+}
+
+inline bool Registers_arm::validRegister(int regNum) const {
+  // Returns true for all non-VFP registers supported by the EHABI
+  // virtual register set (VRS).
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R15))
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_arm::getRegister(int regNum) const {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    return _registers.__sp;
+  if (regNum == UNW_ARM_LR)
+    return _registers.__lr;
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    return _registers.__pc;
+  if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12))
+    return _registers.__r[regNum];
+  _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline void Registers_arm::setRegister(int regNum, uint32_t value) {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    _registers.__sp = value;
+  else if (regNum == UNW_ARM_LR)
+    _registers.__lr = value;
+  else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    _registers.__pc = value;
+  else if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12))
+    _registers.__r[regNum] = value;
+  else
+    _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline const char *Registers_arm::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+  case UNW_ARM_IP: // UNW_ARM_R15 is alias
+    return "pc";
+  case UNW_ARM_LR: // UNW_ARM_R14 is alias
+    return "lr";
+  case UNW_REG_SP:
+  case UNW_ARM_SP: // UNW_ARM_R13 is alias
+    return "sp";
+  case UNW_ARM_R0:
+    return "r0";
+  case UNW_ARM_R1:
+    return "r1";
+  case UNW_ARM_R2:
+    return "r2";
+  case UNW_ARM_R3:
+    return "r3";
+  case UNW_ARM_R4:
+    return "r4";
+  case UNW_ARM_R5:
+    return "r5";
+  case UNW_ARM_R6:
+    return "r6";
+  case UNW_ARM_R7:
+    return "r7";
+  case UNW_ARM_R8:
+    return "r8";
+  case UNW_ARM_R9:
+    return "r9";
+  case UNW_ARM_R10:
+    return "r10";
+  case UNW_ARM_R11:
+    return "r11";
+  case UNW_ARM_R12:
+    return "r12";
+  case UNW_ARM_S0:
+    return "s0";
+  case UNW_ARM_S1:
+    return "s1";
+  case UNW_ARM_S2:
+    return "s2";
+  case UNW_ARM_S3:
+    return "s3";
+  case UNW_ARM_S4:
+    return "s4";
+  case UNW_ARM_S5:
+    return "s5";
+  case UNW_ARM_S6:
+    return "s6";
+  case UNW_ARM_S7:
+    return "s7";
+  case UNW_ARM_S8:
+    return "s8";
+  case UNW_ARM_S9:
+    return "s9";
+  case UNW_ARM_S10:
+    return "s10";
+  case UNW_ARM_S11:
+    return "s11";
+  case UNW_ARM_S12:
+    return "s12";
+  case UNW_ARM_S13:
+    return "s13";
+  case UNW_ARM_S14:
+    return "s14";
+  case UNW_ARM_S15:
+    return "s15";
+  case UNW_ARM_S16:
+    return "s16";
+  case UNW_ARM_S17:
+    return "s17";
+  case UNW_ARM_S18:
+    return "s18";
+  case UNW_ARM_S19:
+    return "s19";
+  case UNW_ARM_S20:
+    return "s20";
+  case UNW_ARM_S21:
+    return "s21";
+  case UNW_ARM_S22:
+    return "s22";
+  case UNW_ARM_S23:
+    return "s23";
+  case UNW_ARM_S24:
+    return "s24";
+  case UNW_ARM_S25:
+    return "s25";
+  case UNW_ARM_S26:
+    return "s26";
+  case UNW_ARM_S27:
+    return "s27";
+  case UNW_ARM_S28:
+    return "s28";
+  case UNW_ARM_S29:
+    return "s29";
+  case UNW_ARM_S30:
+    return "s30";
+  case UNW_ARM_S31:
+    return "s31";
+  case UNW_ARM_D0:
+    return "d0";
+  case UNW_ARM_D1:
+    return "d1";
+  case UNW_ARM_D2:
+    return "d2";
+  case UNW_ARM_D3:
+    return "d3";
+  case UNW_ARM_D4:
+    return "d4";
+  case UNW_ARM_D5:
+    return "d5";
+  case UNW_ARM_D6:
+    return "d6";
+  case UNW_ARM_D7:
+    return "d7";
+  case UNW_ARM_D8:
+    return "d8";
+  case UNW_ARM_D9:
+    return "d9";
+  case UNW_ARM_D10:
+    return "d10";
+  case UNW_ARM_D11:
+    return "d11";
+  case UNW_ARM_D12:
+    return "d12";
+  case UNW_ARM_D13:
+    return "d13";
+  case UNW_ARM_D14:
+    return "d14";
+  case UNW_ARM_D15:
+    return "d15";
+  case UNW_ARM_D16:
+    return "d16";
+  case UNW_ARM_D17:
+    return "d17";
+  case UNW_ARM_D18:
+    return "d18";
+  case UNW_ARM_D19:
+    return "d19";
+  case UNW_ARM_D20:
+    return "d20";
+  case UNW_ARM_D21:
+    return "d21";
+  case UNW_ARM_D22:
+    return "d22";
+  case UNW_ARM_D23:
+    return "d23";
+  case UNW_ARM_D24:
+    return "d24";
+  case UNW_ARM_D25:
+    return "d25";
+  case UNW_ARM_D26:
+    return "d26";
+  case UNW_ARM_D27:
+    return "d27";
+  case UNW_ARM_D28:
+    return "d28";
+  case UNW_ARM_D29:
+    return "d29";
+  case UNW_ARM_D30:
+    return "d30";
+  case UNW_ARM_D31:
+    return "d31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_arm::validFloatRegister(int) const {
+  // FIXME: Implement float register support.
+  return false;
+}
+
+inline unw_fpreg_t Registers_arm::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("ARM float register support not yet implemented");
+}
+
+inline void Registers_arm::setFloatRegister(int, unw_fpreg_t) {
+  _LIBUNWIND_ABORT("ARM float register support not yet implemented");
+}
+
+inline bool Registers_arm::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_arm::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+inline void Registers_arm::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
 } // namespace libunwind
 
 #endif // __REGISTERS_HPP__

Modified: libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.S
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.S?rev=197591&r1=197590&r2=197591&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.S (original)
+++ libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.S Wed Dec 18 11:53:55 2013
@@ -307,4 +307,23 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9li
   ldp    x0, x1,  [x0, #0x000]  ; restore x0,x1
   ret    lr            ; jump to pc
 
+#elif __arm__
+
+@
+@ void libunwind::Registers_arm::jumpto()
+@
+@ On entry:
+@  thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm6jumptoEv)
+  @ Use lr as base so that r0 can be restored.
+  mov lr, r0
+  @ 32bit thumb-2 restrictions for ldm:
+  @ . the sp (r13) cannot be in the list
+  @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
+  ldm lr, {r0-r12}
+  ldr sp, [lr, #52]
+  ldr lr, [lr, #60]  @ restore pc into lr
+  mov pc, lr
+
 #endif

Modified: libcxxabi/trunk/src/Unwind/UnwindRegistersSave.S
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindRegistersSave.S?rev=197591&r1=197590&r2=197591&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindRegistersSave.S (original)
+++ libcxxabi/trunk/src/Unwind/UnwindRegistersSave.S Wed Dec 18 11:53:55 2013
@@ -279,4 +279,23 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext
   ldr    x0, #0      ; return UNW_ESUCCESS
   ret
 
+#elif __arm__ && !__APPLE__
+
+@
+@ extern int unw_getcontext(unw_context_t* thread_state)
+@
+@ On entry:
+@  thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+  @ 32bit thumb-2 restrictions for stm:
+  @ . the sp (r13) cannot be in the list
+  @ . the pc (r15) cannot be in the list in an STM instruction
+  stm r0, {r0-r12}
+  str sp, [r0, #52]
+  str lr, [r0, #56]
+  str lr, [r0, #60]  @ store return address as pc
+  mov r0, #0      @ return UNW_ESUCCESS
+  mov pc, lr
+
 #endif





More information about the cfe-commits mailing list