Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Unwinding support for arm (#6251)
Browse files Browse the repository at this point in the history
* Registers_arm_rt :wrapper class around RT's VRS

RT uses REGDISPlAY structure for virtual registers set (VRS) representation.
The libunwind uses Registers_* classes to hold VRS.
The new class connects REGDISPlAY with libunwind Registers_* API.
Also the new class reuses validRegister, validFloatRegister,
getRegisterName methods from libunwind::Registres_arm class.

* Methods implementation for Registers_arm_rt class

* Avoid PORTABILITY_ASSERT() in StepFrame for ARM

The DoTheStep accepts 3 input parameters:

pc - it could be taken for regs input parameter
UnwindInfoSections - is not needed in case ARM, it will be located by
 libunwind later, before unwinding
regs - pointer to REGDISPLAY that represents RT's VRS

* Remove PORTABILITY_ASSERT() in DoTheStep()

SetInfoBaseOnIPRegister - sets unwind info for libunwind::UnwindCursor
 see UnwindCursor.hpp:1228 for additional comments

* libunwind API is updated: unw_set_reg sets pointer to register value

Since the unwinder must provide pointer to pc, setting only pc value
in the REGDISPLAY is not enough. For this reason the libunwind should
set pointers to registers to set pIP pointer.

* Clean up libunwind config file

The libunwind uses "if defined()" not "!()"

* Initialize Registers_arm_rt with REGDISPLAY

The pointer to REGDISPLAY is passed to Registers_arm_rt constructor
  • Loading branch information
iarischenko authored and jkotas committed Aug 24, 2018
1 parent e2df352 commit b059615
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/Native/Runtime/unix/UnixContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,11 @@ int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*)
static void RegDisplayToUnwindCursor(REGDISPLAY* regDisplay, unw_cursor_t *cursor)
{
#define ASSIGN_REG(regName1, regName2) \
unw_set_reg(cursor, regName1, regDisplay->regName2);
unw_set_reg(cursor, regName1, regDisplay->regName2, 0);

#define ASSIGN_REG_PTR(regName1, regName2) \
if (regDisplay->p##regName2 != NULL) \
unw_set_reg(cursor, regName1, *(regDisplay->p##regName2));
unw_set_reg(cursor, regName1, *(regDisplay->p##regName2), 0);

#if defined(_AMD64_)
ASSIGN_REG(UNW_REG_SP, SP)
Expand Down
162 changes: 154 additions & 8 deletions src/Native/Runtime/unix/UnwindHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,152 @@ struct Registers_REGDISPLAY : REGDISPLAY
};

#endif // _TARGET_AMD64_
#if defined(_TARGET_ARM_)

class Registers_arm_rt: public libunwind::Registers_arm {
public:
Registers_arm_rt() { abort(); };
Registers_arm_rt(void *registers) { regs = (REGDISPLAY *)registers; };
uint32_t getRegister(int num);
void setRegister(int num, uint32_t value, uint32_t location);
uint32_t getRegisterLocation(int regNum) const { abort();}
unw_fpreg_t getFloatRegister(int num) { abort();}
void setFloatRegister(int num, unw_fpreg_t value) {abort();}
bool validVectorRegister(int num) const { abort();}
uint32_t getVectorRegister(int num) const {abort();};
void setVectorRegister(int num, uint32_t value) {abort();};
void jumpto() { abort();};
uint32_t getSP() const { return regs->SP;}
void setSP(uint32_t value, uint32_t location) { regs->SP = value;}
uint32_t getIP() const { return regs->IP;}
void setIP(uint32_t value, uint32_t location)
{ regs->IP = value; regs->pIP = (PTR_UIntNative)location; }
void saveVFPAsX() {abort();};
private:
REGDISPLAY *regs;
};

inline uint32_t Registers_arm_rt::getRegister(int regNum) {
if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
return regs->SP;

if (regNum == UNW_ARM_LR)
return *regs->pLR;

if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
return regs->IP;

switch (regNum)
{
case (UNW_ARM_R0):
return *regs->pR0;
case (UNW_ARM_R1):
return *regs->pR1;
case (UNW_ARM_R2):
return *regs->pR2;
case (UNW_ARM_R3):
return *regs->pR3;
case (UNW_ARM_R4):
return *regs->pR4;
case (UNW_ARM_R5):
return *regs->pR5;
case (UNW_ARM_R6):
return *regs->pR6;
case (UNW_ARM_R7):
return *regs->pR7;
case (UNW_ARM_R8):
return *regs->pR8;
case (UNW_ARM_R9):
return *regs->pR9;
case (UNW_ARM_R10):
return *regs->pR10;
case (UNW_ARM_R11):
return *regs->pR11;
case (UNW_ARM_R12):
return *regs->pR12;
}

PORTABILITY_ASSERT("unsupported arm register");
}

void Registers_arm_rt::setRegister(int num, uint32_t value, uint32_t location)
{

if (num == UNW_REG_SP || num == UNW_ARM_SP) {
regs->SP = (UIntNative )value;
return;
}

if (num == UNW_ARM_LR) {
regs->pLR = (PTR_UIntNative)location;
return;
}

if (num == UNW_REG_IP || num == UNW_ARM_IP) {
regs->IP = value;
/* the location could be NULL, we could try to recover
pointer to value in stack from pLR */
if ((!location) && (regs->pLR) && (*regs->pLR == value))
regs->pIP = regs->pLR;
else
regs->pIP = (PTR_UIntNative)location;
return;
}

switch (num)
{
case (UNW_ARM_R0):
regs->pR0 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R1):
regs->pR1 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R2):
regs->pR2 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R3):
regs->pR3 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R4):
regs->pR4 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R5):
regs->pR5 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R6):
regs->pR6 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R7):
regs->pR7 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R8):
regs->pR8 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R9):
regs->pR9 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R10):
regs->pR10 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R11):
regs->pR11 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R12):
regs->pR12 = (PTR_UIntNative)location;
break;
default:
PORTABILITY_ASSERT("unsupported arm register");
}
}

#endif // _TARGET_ARM_

bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs)
{
#if defined(_TARGET_AMD64_)
libunwind::UnwindCursor<LocalAddressSpace, Registers_x86_64> uc(_addressSpace);
#elif defined(_TARGET_ARM_)
libunwind::UnwindCursor<LocalAddressSpace, Registers_arm> uc(_addressSpace);
libunwind::UnwindCursor<LocalAddressSpace, Registers_arm_rt> uc(_addressSpace, regs);
#else
#error "Unwinding is not implemented for this architecture yet."
#endif
Expand All @@ -322,8 +461,13 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs
}

regs->pIP = PTR_PCODE(regs->SP - sizeof(TADDR));
#else
PORTABILITY_ASSERT("DoTheStep");
#elif defined(_LIBUNWIND_ARM_EHABI)
uc.setInfoBasedOnIPRegister(true);
int stepRet = uc.step();
if ((stepRet != UNW_STEP_SUCCESS) && (stepRet != UNW_STEP_END))
{
return false;
}
#endif

return true;
Expand Down Expand Up @@ -365,18 +509,20 @@ UnwindInfoSections LocateUnwindSections(uintptr_t pc)

bool UnwindHelpers::StepFrame(REGDISPLAY *regs)
{
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
uintptr_t pc = regs->GetIP();

UnwindInfoSections uwInfoSections = LocateUnwindSections(pc);

#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
if (uwInfoSections.dwarf_section == NULL)
{
return false;
}
return DoTheStep(pc, uwInfoSections, regs);
#elif defined(_LIBUNWIND_ARM_EHABI)
// unwind section is located later for ARM
// pc will be taked from regs parameter
UnwindInfoSections uwInfoSections;
return DoTheStep(0, uwInfoSections, regs);
#else
PORTABILITY_ASSERT("StepFrame");
#endif

return DoTheStep(pc, uwInfoSections, regs);
}
2 changes: 1 addition & 1 deletion src/Native/libunwind/include/libunwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL;
extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL;
extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL;
extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL;
extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t, unw_word_t *) LIBUNWIND_AVAIL;
extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL;
extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;

Expand Down
10 changes: 5 additions & 5 deletions src/Native/libunwind/include/unwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ _Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
extern _Unwind_VRS_Result
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
void *valuep);
void *valuep, uint32_t *pos);

extern _Unwind_VRS_Result
_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
Expand All @@ -212,7 +212,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,

extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
uintptr_t new_value);
uintptr_t new_value, uintptr_t *pos);
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);

Expand Down Expand Up @@ -240,8 +240,8 @@ uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) {

_LIBUNWIND_EXPORT_UNWIND_LEVEL1
void _Unwind_SetGR(struct _Unwind_Context *context, int index,
uintptr_t value) {
_Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
uintptr_t value,uintptr_t *pos) {
_Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value, pos);
}

_LIBUNWIND_EXPORT_UNWIND_LEVEL1
Expand All @@ -253,7 +253,7 @@ uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) {
uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
_Unwind_SetGR(context, 15, value | thumb_bit);
_Unwind_SetGR(context, 15, value | thumb_bit, NULL);
}
#endif // _LIBUNWIND_ARM_EHABI

Expand Down
24 changes: 13 additions & 11 deletions src/Native/libunwind/src/Unwind-EHABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
sp -= (((uint32_t)byte & 0x3f) << 2) + 4;
else
sp += ((uint32_t)byte << 2) + 4;
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp, NULL);
} else {
switch (byte & 0xf0) {
case 0x80: {
Expand All @@ -283,7 +283,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg,
_UVRSD_UINT32, &sp);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
&sp);
&sp, NULL);
break;
}
case 0xa0: {
Expand Down Expand Up @@ -325,7 +325,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
&sp);
sp += 0x204 + (addend << 2);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
&sp);
&sp, NULL);
break;
}
case 0xb3: {
Expand Down Expand Up @@ -411,7 +411,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
if (!wrotePC) {
uint32_t lr;
_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr, NULL);
}
return _URC_CONTINUE_UNWIND;
}
Expand Down Expand Up @@ -559,7 +559,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
//
// See #7.4.6 for details.
unw_set_reg(cursor, UNW_REG_IP,
exception_object->unwinder_cache.reserved2);
exception_object->unwinder_cache.reserved2, NULL);
resume = false;
}

Expand Down Expand Up @@ -753,7 +753,7 @@ static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,
_LIBUNWIND_EXPORT _Unwind_VRS_Result
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
void *valuep) {
void *valuep, unw_word_t *pos) {
_LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, "
"rep=%d, value=0x%llX)",
static_cast<void *>(context), regclass, regno,
Expand All @@ -765,7 +765,7 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
if (representation != _UVRSD_UINT32 || regno > 15)
return _UVRSR_FAILED;
return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),
*(unw_word_t *)valuep) == UNW_ESUCCESS
*(unw_word_t *)valuep,(unw_word_t *)pos) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
case _UVRSC_VFP:
Expand Down Expand Up @@ -897,24 +897,26 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
// computed new stack location. See EHABI #7.5.4 table 3.
bool poppedSP = false;
uint32_t* sp;
uint32_t* pos;
if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,
_UVRSD_UINT32, &sp) != _UVRSR_OK) {
return _UVRSR_FAILED;
}
for (uint32_t i = 0; i < 16; ++i) {
if (!(discriminator & static_cast<uint32_t>(1 << i)))
continue;
pos = sp;
uint32_t value = *sp++;
if (regclass == _UVRSC_CORE && i == 13)
poppedSP = true;
if (_Unwind_VRS_Set(context, regclass, i,
_UVRSD_UINT32, &value) != _UVRSR_OK) {
_UVRSD_UINT32, &value, pos) != _UVRSR_OK) {
return _UVRSR_FAILED;
}
}
if (!poppedSP) {
return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP,
_UVRSD_UINT32, &sp);
_UVRSD_UINT32, &sp, NULL);
}
return _UVRSR_OK;
}
Expand All @@ -939,14 +941,14 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
// SP is only 32-bit aligned so don't copy 64-bit at a time.
uint64_t value = *sp++;
value |= ((uint64_t)(*sp++)) << 32;
if (_Unwind_VRS_Set(context, regclass, i, representation, &value) !=
if (_Unwind_VRS_Set(context, regclass, i, representation, &value, NULL) !=
_UVRSR_OK)
return _UVRSR_FAILED;
}
if (representation == _UVRSD_VFPX)
++sp;
return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
&sp);
&sp, NULL);
}
}
_LIBUNWIND_ABORT("unsupported register class");
Expand Down
6 changes: 4 additions & 2 deletions src/Native/libunwind/src/UnwindCursor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,11 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
}

template <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(A &as, void *)
: _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
UnwindCursor<A, R>::UnwindCursor(A &as, void *arg)
: _addressSpace(as),_registers(arg), _unwindInfoMissing(false),
_isSignalFrame(false) {
memset(&_info, 0, sizeof(_info));

// FIXME
// fill in _registers from thread arg
}
Expand Down
5 changes: 0 additions & 5 deletions src/Native/libunwind/src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,8 @@
#endif
#else
#if defined(__ARM_DWARF_EH__) || !defined(__arm__)
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
#else
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
#endif
#endif

Expand Down
Loading

0 comments on commit b059615

Please sign in to comment.