diff options
author | Soby Mathew <soby.mathew@arm.com> | 2019-07-17 10:49:26 +0000 |
---|---|---|
committer | TrustedFirmware Code Review <review@review.trustedfirmware.org> | 2019-07-17 10:49:26 +0000 |
commit | 7871fff2a2a7459db89bea85e82b8ced09025fbe (patch) | |
tree | 95c85d963ceeb8068b9052e46767c682f010fb9d /common | |
parent | 7a8ef89f97720fcded620e8a18ac831281392239 (diff) | |
parent | b8b31ad00046e163c40427758ec8cf976008e99b (diff) | |
download | trusted-firmware-a-7871fff2a2a7459db89bea85e82b8ced09025fbe.tar.gz |
Merge "backtrace: Strip PAC field when PAUTH is enabled" into integration
Diffstat (limited to 'common')
-rw-r--r-- | common/backtrace/backtrace.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/common/backtrace/backtrace.c b/common/backtrace/backtrace.c index ecc65c92e1..53f8b0719d 100644 --- a/common/backtrace/backtrace.c +++ b/common/backtrace/backtrace.c @@ -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. |