diff options
author | Peter Collingbourne <pcc@google.com> | 2020-03-20 18:09:00 -0700 |
---|---|---|
committer | Peter Collingbourne <pcc@google.com> | 2020-03-27 20:00:06 -0700 |
commit | f03af8844acbd63f257c51577834d2c126a41f47 (patch) | |
tree | 8cde302d29f6c19ad6da6ed35becb8462dafced3 /debuggerd/libdebuggerd/utility.cpp | |
parent | f3d542fe9fe4b82affada29928921314375d42f8 (diff) |
Read fault address on arm64 using proposed kernel API.
On aarch64, the top 8 bits of the address (i.e. the tag bits) of
the fault address in si_addr are always clear. This isn't ideal for
MTE which will require these bits in order to correctly diagnose
tag mismatches.
A proposed kernel patch [1] exposes the full fault address including
the tag bits as part of the ucontext. Change debuggerd to read this
fault address if available.
[1] https://patchwork.kernel.org/patch/11435077/
Bug: 135772972
Change-Id: Ia05be574113860f4e9ecc36a310c4b740e0c4afb
Diffstat (limited to 'debuggerd/libdebuggerd/utility.cpp')
-rw-r--r-- | debuggerd/libdebuggerd/utility.cpp | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 0a1d2a4da..3bf28b6c2 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -449,3 +449,40 @@ void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* pref _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str()); } } + +#if defined(__aarch64__) +#define FAR_MAGIC 0x46415201 + +struct far_context { + struct _aarch64_ctx head; + __u64 far; +}; +#endif + +uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext) { + (void)ucontext; +#if defined(__aarch64__) + // This relies on a kernel patch: + // https://patchwork.kernel.org/patch/11435077/ + // that hasn't been accepted into the kernel yet. TODO(pcc): Update this to + // use the official interface once it lands. + auto* begin = reinterpret_cast<const char*>(ucontext->uc_mcontext.__reserved); + auto* end = begin + sizeof(ucontext->uc_mcontext.__reserved); + auto* ptr = begin; + while (1) { + auto* ctx = reinterpret_cast<const _aarch64_ctx*>(ptr); + if (ctx->magic == 0) { + break; + } + if (ctx->magic == FAR_MAGIC) { + auto* far_ctx = reinterpret_cast<const far_context*>(ctx); + return far_ctx->far; + } + ptr += ctx->size; + if (ctx->size % sizeof(void*) != 0 || ptr < begin || ptr >= end) { + break; + } + } +#endif + return reinterpret_cast<uintptr_t>(siginfo->si_addr); +} |