Add fault address marker in proto to tombstone.
When the switch was made to dump the tombstone from the protobuf, the fault address marker in the maps section went missing. Re-add that logic and add new unit tests to verify all of the different behaviors. Bug: 193935960 Test: All unit tests pass. Test: All unit tests pass when setprop debug.debuggerd.translate_proto_to_text 0 Test: The above on cuttlefish, 32 bit and 64 bit. Test: The above on a flame, 32 bit and 64 bit. Change-Id: I098bb6ab4bacacae2ca0fc5ec9a73549ed0b9489
This commit is contained in:
parent
c1c2b4f816
commit
7e4c2a8ccc
|
@ -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 New Issue