forked from OSchip/llvm-project
Add a first cut at a Registers_arm class, to be used for 32bit arm EHABI unwinding.
llvm-svn: 197591
This commit is contained in:
parent
b96aae233c
commit
1c9ff122b6
|
@ -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
|
||||
|
|
|
@ -1273,6 +1273,296 @@ inline void Registers_arm64::setVectorRegister(int, v128) {
|
|||
_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__
|
||||
|
|
|
@ -307,4 +307,23 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue