Merge "Add fault address marker in proto to tombstone."

This commit is contained in:
Christopher Ferris 2021-08-24 01:00:09 +00:00 committed by Gerrit Code Review
commit a90757251d
2 changed files with 220 additions and 2 deletions

View file

@ -1889,3 +1889,178 @@ TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
ConsumeFd(std::move(output_fd), &result);
ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
}
static std::string format_pointer(uintptr_t ptr) {
#if defined(__LP64__)
return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
static_cast<uint32_t>(ptr & 0xffffffff));
#else
return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
#endif
}
static std::string format_pointer(void* ptr) {
return format_pointer(reinterpret_cast<uintptr_t>(ptr));
}
static std::string format_full_pointer(uintptr_t ptr) {
#if defined(__LP64__)
return android::base::StringPrintf("%016" PRIx64, ptr);
#else
return android::base::StringPrintf("%08x", ptr);
#endif
}
static std::string format_full_pointer(void* ptr) {
return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
}
__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
int* crash_ptr = reinterpret_cast<int*>(ptr);
*crash_ptr = 1;
return *crash_ptr;
}
// Verify that a fault address before the first map is properly handled.
TEST_F(CrasherTest, fault_address_before_first_map) {
StartProcess([]() {
ASSERT_EQ(0, crash_call(0x1024));
_exit(0);
});
unique_fd output_fd;
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGSEGV);
int intercept_result;
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x1024)");
ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
std::string match_str = android::base::StringPrintf(
R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
format_pointer(0x1024).c_str());
ASSERT_MATCH(result, match_str);
}
// Verify that a fault address after the last map is properly handled.
TEST_F(CrasherTest, fault_address_after_last_map) {
uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
StartProcess([crash_uptr]() {
ASSERT_EQ(0, crash_call(crash_uptr));
_exit(0);
});
unique_fd output_fd;
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGSEGV);
int intercept_result;
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
std::string result;
ConsumeFd(std::move(output_fd), &result);
std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
match_str += android::base::StringPrintf("0x%" PRIxPTR, crash_uptr);
ASSERT_MATCH(result, match_str);
ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
// Assumes that the open files section comes after the map section.
// If that assumption changes, the regex below needs to change.
match_str = android::base::StringPrintf(
R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
format_pointer(crash_uptr).c_str());
ASSERT_MATCH(result, match_str);
}
// Verify that a fault address between maps is properly handled.
TEST_F(CrasherTest, fault_address_between_maps) {
// Create a map before the fork so it will be present in the child.
void* start_ptr =
mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_NE(MAP_FAILED, start_ptr);
// Unmap the page in the middle.
void* middle_ptr =
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
StartProcess([middle_ptr]() {
ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
_exit(0);
});
// Unmap the two maps.
ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
void* end_ptr =
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
unique_fd output_fd;
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGSEGV);
int intercept_result;
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
std::string result;
ConsumeFd(std::move(output_fd), &result);
std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
match_str += android::base::StringPrintf("%p", middle_ptr);
ASSERT_MATCH(result, match_str);
ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
match_str = android::base::StringPrintf(
R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
format_pointer(end_ptr).c_str());
ASSERT_MATCH(result, match_str);
}
// Verify that a fault address happens in the correct map.
TEST_F(CrasherTest, fault_address_in_map) {
// Create a map before the fork so it will be present in the child.
void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_NE(MAP_FAILED, ptr);
StartProcess([ptr]() {
ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
_exit(0);
});
ASSERT_EQ(0, munmap(ptr, getpagesize()));
unique_fd output_fd;
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGSEGV);
int intercept_result;
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
std::string result;
ConsumeFd(std::move(output_fd), &result);
std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr )";
match_str += android::base::StringPrintf("%p", ptr);
ASSERT_MATCH(result, match_str);
ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
ASSERT_MATCH(result, match_str);
}

View file

@ -362,8 +362,13 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
print_thread_memory_dump(callback, tombstone, thread);
CBS("");
CBS("memory map (%d %s):", tombstone.memory_mappings().size(),
tombstone.memory_mappings().size() == 1 ? "entry" : "entries");
// No memory maps to print.
if (tombstone.memory_mappings().empty()) {
CBS("No memory maps found");
return;
}
int word_size = pointer_width(tombstone);
const auto format_pointer = [word_size](uint64_t ptr) -> std::string {
if (word_size == 8) {
@ -375,8 +380,41 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
return StringPrintf("%0*" PRIx64, word_size * 2, ptr);
};
std::string memory_map_header =
StringPrintf("memory map (%d %s):", tombstone.memory_mappings().size(),
tombstone.memory_mappings().size() == 1 ? "entry" : "entries");
bool has_fault_address = signal_info.has_fault_address();
uint64_t fault_address = untag_address(signal_info.fault_address());
bool preamble_printed = false;
bool printed_fault_address_marker = false;
for (const auto& map : tombstone.memory_mappings()) {
if (!preamble_printed) {
preamble_printed = true;
if (has_fault_address) {
if (fault_address < map.begin_address()) {
memory_map_header +=
StringPrintf("\n--->Fault address falls at %s before any mapped regions",
format_pointer(fault_address).c_str());
printed_fault_address_marker = true;
} else {
memory_map_header += " (fault address prefixed with --->)";
}
}
CBS("%s", memory_map_header.c_str());
}
std::string line = " ";
if (has_fault_address && !printed_fault_address_marker) {
if (fault_address < map.begin_address()) {
printed_fault_address_marker = true;
CBS("--->Fault address falls at %s between mapped regions",
format_pointer(fault_address).c_str());
} else if (fault_address >= map.begin_address() && fault_address < map.end_address()) {
printed_fault_address_marker = true;
line = "--->";
}
}
StringAppendF(&line, "%s-%s", format_pointer(map.begin_address()).c_str(),
format_pointer(map.end_address() - 1).c_str());
StringAppendF(&line, " %s%s%s", map.read() ? "r" : "-", map.write() ? "w" : "-",
@ -398,6 +436,11 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
CBS("%s", line.c_str());
}
if (has_fault_address && !printed_fault_address_marker) {
CBS("--->Fault address falls at %s after any mapped regions",
format_pointer(fault_address).c_str());
}
}
void print_logs(CallbackType callback, const Tombstone& tombstone, int tail) {