Merge "Add fault address marker in proto to tombstone."
This commit is contained in:
commit
a90757251d
2 changed files with 220 additions and 2 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue