backtrace: Strip PAC field when PAUTH is enabled

When pointer authentication is enabled, the LR value saved on the stack
contains a Pointer Authentication Code (PAC). It must be stripped to
retrieve the return address.

The PAC field is stored on the high bits of the address and defined as:
- PAC field = Xn[54:bottom_PAC_bit], when address tagging is used.
- PAC field = Xn[63:56, 54:bottom_PAC_bit], without address tagging.

With bottom_PAC_bit = 64 - TCR_ELx.TnSZ

Change-Id: I21d804e58200dfeca1da4c2554690bed5d191936
Signed-off-by: Louis Mayencourt <louis.mayencourt@arm.com>
This commit is contained in:
Louis Mayencourt 2019-07-09 11:40:55 +01:00
parent 2cbeee4d51
commit b8b31ad000
1 changed files with 59 additions and 0 deletions

View File

@ -37,6 +37,47 @@ struct frame_record {
uintptr_t return_addr;
};
/*
* Strip the Pointer Authentication Code (PAC) from the address to retrieve the
* original one.
*
* The PAC field is stored on the high bits of the address and defined as:
* - PAC field = Xn[54:bottom_PAC_bit], when address tagging is used.
* - PAC field = Xn[63:56, 54:bottom_PAC_bit], without address tagging.
*
* With bottom_PAC_bit = 64 - TCR_ELx.TnSZ
*/
#if ENABLE_PAUTH
static uintptr_t demangle_address(uintptr_t addr)
{
unsigned int el, t0sz, bottom_pac_bit;
uint64_t tcr, pac_mask;
/*
* Different virtual address space size can be defined for each EL.
* Ensure that we use the proper one by reading the corresponding
* TCR_ELx register.
*/
el = get_current_el();
if (el == 3U) {
tcr = read_tcr_el3();
} else if (el == 2U) {
tcr = read_tcr_el2();
} else {
tcr = read_tcr_el1();
}
/* T0SZ = TCR_ELx[5:0] */
t0sz = tcr & 0x1f;
bottom_pac_bit = 64 - t0sz;
pac_mask = (1ULL << bottom_pac_bit) - 1;
/* demangle the address with the computed mask */
return (addr & pac_mask);
}
#endif /* ENABLE_PAUTH */
static const char *get_el_str(unsigned int el)
{
if (el == 3U) {
@ -57,6 +98,15 @@ static bool is_address_readable(uintptr_t addr)
{
unsigned int el = get_current_el();
#if ENABLE_PAUTH
/*
* When pointer authentication is enabled, the LR value saved on the
* stack contains a PAC. It must be stripped to retrieve the return
* address.
*/
addr = demangle_address(addr);
#endif
if (el == 3U) {
ats1e3r(addr);
} else if (el == 2U) {
@ -201,6 +251,15 @@ static void unwind_stack(struct frame_record *fr, uintptr_t current_pc,
*/
call_site = fr->return_addr - 4U;
#if ENABLE_PAUTH
/*
* When pointer authentication is enabled, the LR value saved on
* the stack contains a PAC. It must be stripped to retrieve the
* return address.
*/
call_site = demangle_address(call_site);
#endif
/*
* If the address is invalid it means that the frame record is
* probably corrupted.