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.cpp147
1 files changed, 68 insertions, 79 deletions
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 2c645b542..0a1d2a4da 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -30,11 +30,11 @@
#include <string>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <async_safe/log.h>
#include <bionic/reserved_signals.h>
#include <debuggerd/handler.h>
#include <log/log.h>
@@ -43,6 +43,7 @@
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)
@@ -125,57 +126,58 @@ void _VLOG(log_t* log, enum logtype ltype, const char* fmt, va_list ap) {
#define MEMORY_BYTES_TO_DUMP 256
#define MEMORY_BYTES_PER_LINE 16
-static_assert(MEMORY_BYTES_PER_LINE == kTagGranuleSize);
-
-ssize_t dump_memory(void* out, size_t len, uint8_t* tags, size_t tags_len, uint64_t* addr,
- unwindstack::Memory* memory) {
- // 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;
- }
- // We don't want the address tag to appear in the addresses in the memory dump.
- *addr = untag_address(*addr);
+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);
+ if (addr >= 4128) {
+ addr -= 32;
+ }
- // 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 -1;
+ // 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
+ return;
}
- memset(out, 0, len);
+ _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str());
- size_t bytes = memory->Read(*addr, reinterpret_cast<uint8_t*>(out), len);
+ // Dump 256 bytes
+ uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
+ memset(data, 0, MEMORY_BYTES_TO_DUMP);
+ size_t bytes = memory->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
if (bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but just in case.
ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
bytes &= ~(sizeof(uintptr_t) - 1);
}
+ uint64_t start = 0;
bool skip_2nd_read = false;
if (bytes == 0) {
// In this case, we might want to try another read at the beginning of
// the next page only if it's within the amount of memory we would have
// read.
size_t page_size = sysconf(_SC_PAGE_SIZE);
- uint64_t next_page = (*addr + (page_size - 1)) & ~(page_size - 1);
- if (next_page == *addr || next_page >= *addr + len) {
+ start = ((addr + (page_size - 1)) & ~(page_size - 1)) - addr;
+ if (start == 0 || start >= MEMORY_BYTES_TO_DUMP) {
skip_2nd_read = true;
}
- *addr = next_page;
}
- if (bytes < len && !skip_2nd_read) {
+ if (bytes < MEMORY_BYTES_TO_DUMP && !skip_2nd_read) {
// Try to do one more read. This could happen if a read crosses a map,
// but the maps do not have any break between them. Or it could happen
// if reading from an unreadable map, but the read would cross back
// into a readable map. Only requires one extra read because a map has
// to contain at least one page, and the total number of bytes to dump
// is smaller than a page.
- size_t bytes2 = memory->Read(*addr + bytes, static_cast<uint8_t*>(out) + bytes, len - bytes);
+ size_t bytes2 = memory->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
+ sizeof(data) - bytes - start);
bytes += bytes2;
if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but we'll try and continue any way.
@@ -184,36 +186,6 @@ ssize_t dump_memory(void* out, size_t len, uint8_t* tags, size_t tags_len, uint6
}
}
- // If we were unable to read anything, it probably means that the register doesn't contain a
- // valid pointer.
- if (bytes == 0) {
- return -1;
- }
-
- for (uint64_t tag_granule = 0; tag_granule < bytes / kTagGranuleSize; ++tag_granule) {
- long tag = memory->ReadTag(*addr + kTagGranuleSize * tag_granule);
- if (tag_granule < tags_len) {
- tags[tag_granule] = tag >= 0 ? tag : 0;
- } else {
- ALOGE("Insufficient space for tags");
- }
- }
-
- return bytes;
-}
-
-void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const std::string& label) {
- // Dump 256 bytes
- uintptr_t data[MEMORY_BYTES_TO_DUMP / sizeof(uintptr_t)];
- uint8_t tags[MEMORY_BYTES_TO_DUMP / kTagGranuleSize];
-
- ssize_t bytes = dump_memory(data, sizeof(data), tags, sizeof(tags), &addr, memory);
- if (bytes == -1) {
- return;
- }
-
- _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str());
-
// Dump the code around memory as:
// addr contents ascii
// 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
@@ -221,32 +193,55 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s
// On 32-bit machines, there are still 16 bytes per line but addresses and
// words are of course presented differently.
uintptr_t* data_ptr = data;
- uint8_t* tags_ptr = tags;
- for (size_t line = 0; line < static_cast<size_t>(bytes) / MEMORY_BYTES_PER_LINE; line++) {
- uint64_t tagged_addr = addr | static_cast<uint64_t>(*tags_ptr++) << 56;
+ 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++) {
std::string logline;
- android::base::StringAppendF(&logline, " %" PRIPTR, tagged_addr);
+ android::base::StringAppendF(&logline, " %" PRIPTR, addr);
addr += MEMORY_BYTES_PER_LINE;
std::string ascii;
for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++) {
- android::base::StringAppendF(&logline, " %" PRIPTR, static_cast<uint64_t>(*data_ptr));
-
- // Fill out the ascii string from the data.
- uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
- for (size_t val = 0; val < sizeof(uintptr_t); val++, ptr++) {
- if (*ptr >= 0x20 && *ptr < 0x7f) {
- ascii += *ptr;
- } else {
- ascii += '.';
+ if (current >= start && current + sizeof(uintptr_t) <= total_bytes) {
+ android::base::StringAppendF(&logline, " %" PRIPTR, static_cast<uint64_t>(*data_ptr));
+
+ // Fill out the ascii string from the data.
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
+ for (size_t val = 0; val < sizeof(uintptr_t); val++, ptr++) {
+ if (*ptr >= 0x20 && *ptr < 0x7f) {
+ ascii += *ptr;
+ } else {
+ ascii += '.';
+ }
}
+ data_ptr++;
+ } else {
+ logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
+ ascii += std::string(sizeof(uintptr_t), '.');
}
- data_ptr++;
+ current += sizeof(uintptr_t);
}
_LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
}
}
+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));
@@ -257,11 +252,11 @@ void drop_capabilities() {
memset(&capdata, 0, sizeof(capdata));
if (capset(&capheader, &capdata[0]) == -1) {
- async_safe_fatal("failed to drop capabilities: %s", strerror(errno));
+ PLOG(FATAL) << "failed to drop capabilities";
}
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
- async_safe_fatal("failed to set PR_SET_NO_NEW_PRIVS: %s", strerror(errno));
+ PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS";
}
}
@@ -379,20 +374,14 @@ const char* get_sigcode(const siginfo_t* si) {
return "SEGV_ADIDERR";
case SEGV_ADIPERR:
return "SEGV_ADIPERR";
- case SEGV_MTEAERR:
- return "SEGV_MTEAERR";
- case SEGV_MTESERR:
- return "SEGV_MTESERR";
}
- static_assert(NSIGSEGV == SEGV_MTESERR, "missing SEGV_* si_code");
+ static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
break;
case SIGSYS:
switch (si->si_code) {
case SYS_SECCOMP: return "SYS_SECCOMP";
- case SYS_USER_DISPATCH:
- return "SYS_USER_DISPATCH";
}
- static_assert(NSIGSYS == SYS_USER_DISPATCH, "missing SYS_* si_code");
+ static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
break;
case SIGTRAP:
switch (si->si_code) {