summaryrefslogtreecommitdiff
path: root/debuggerd/libdebuggerd/utility.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debuggerd/libdebuggerd/utility.cpp')
-rw-r--r--debuggerd/libdebuggerd/utility.cpp99
1 files changed, 69 insertions, 30 deletions
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 0a1d2a4da2..4e6df09c9a 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,6 +35,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <bionic/mte_kernel.h>
#include <bionic/reserved_signals.h>
#include <debuggerd/handler.h>
#include <log/log.h>
@@ -43,7 +44,6 @@
using android::base::unique_fd;
-// Whitelist output desired in the logcat output.
bool is_allowed_in_logcat(enum logtype ltype) {
if ((ltype == HEADER)
|| (ltype == REGISTERS)
@@ -128,24 +128,23 @@ void _VLOG(log_t* log, enum logtype ltype, const char* fmt, va_list ap) {
#define MEMORY_BYTES_PER_LINE 16
void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const std::string& label) {
- // Align the address to sizeof(long) and start 32 bytes before the address.
- addr &= ~(sizeof(long) - 1);
+ // Align the address to the number of bytes per line to avoid confusing memory tag output if
+ // memory is tagged and we start from a misaligned address. Start 32 bytes before the address.
+ addr &= ~(MEMORY_BYTES_PER_LINE - 1);
if (addr >= 4128) {
addr -= 32;
}
- // Don't bother if the address looks too low, or looks too high.
- if (addr < 4096 ||
-#if defined(__LP64__)
- addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) {
-#else
- addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) {
-#endif
+ // We don't want the address tag to appear in the addresses in the memory dump.
+ addr = untag_address(addr);
+
+ // Don't bother if the address would overflow, taking tag bits into account. Note that
+ // untag_address truncates to 32 bits on 32-bit platforms as a side effect of returning a
+ // uintptr_t, so this also checks for 32-bit overflow.
+ if (untag_address(addr + MEMORY_BYTES_TO_DUMP - 1) < addr) {
return;
}
- _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str());
-
// Dump 256 bytes
uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
memset(data, 0, MEMORY_BYTES_TO_DUMP);
@@ -186,6 +185,15 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s
}
}
+ // If we were unable to read anything, it probably means that the register doesn't contain a
+ // valid pointer. In that case, skip the output for this register entirely rather than emitting 16
+ // lines of dashes.
+ if (bytes == 0) {
+ return;
+ }
+
+ _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str());
+
// Dump the code around memory as:
// addr contents ascii
// 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
@@ -196,8 +204,13 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s
size_t current = 0;
size_t total_bytes = start + bytes;
for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
+ uint64_t tagged_addr = addr;
+ long tag = memory->ReadTag(addr);
+ if (tag >= 0) {
+ tagged_addr |= static_cast<uint64_t>(tag) << 56;
+ }
std::string logline;
- android::base::StringAppendF(&logline, " %" PRIPTR, addr);
+ android::base::StringAppendF(&logline, " %" PRIPTR, tagged_addr);
addr += MEMORY_BYTES_PER_LINE;
std::string ascii;
@@ -225,23 +238,6 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s
}
}
-void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
- unique_fd fd(open(path, O_RDONLY | O_CLOEXEC));
- if (fd != -1) {
- int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1));
- if (rc != -1) {
- buf[rc] = '\0';
-
- // Trim trailing newlines.
- if (rc > 0 && buf[rc - 1] == '\n') {
- buf[rc - 1] = '\0';
- }
- return;
- }
- }
- strcpy(buf, default_value);
-}
-
void drop_capabilities() {
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));
@@ -374,6 +370,12 @@ const char* get_sigcode(const siginfo_t* si) {
return "SEGV_ADIDERR";
case SEGV_ADIPERR:
return "SEGV_ADIPERR";
+#if defined(ANDROID_EXPERIMENTAL_MTE)
+ case SEGV_MTEAERR:
+ return "SEGV_MTEAERR";
+ case SEGV_MTESERR:
+ return "SEGV_MTESERR";
+#endif
}
static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
break;
@@ -449,3 +451,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);
+}