android_system_core/debuggerd/test/tombstone_test.cpp
Elliott Hughes f39383103b bionic no longer sends SIGPIPE to debuggerd.
Static binaries don't get the signal handler installed (that's done by the
dynamic linker) so we don't need to worry about seeing SIGPIPE crashes from
old binaries.

Bug: http://b/20659371
Change-Id: I3b5566634fadd3e822262561188d29814bccd1fd
2015-07-30 08:15:57 -07:00

599 lines
19 KiB
C++

/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <memory>
#include <string>
#include <gtest/gtest.h>
#include <base/file.h>
#include "utility.h"
#include "BacktraceMock.h"
#include "elf_fake.h"
#include "host_signal_fixup.h"
#include "log_fake.h"
#include "ptrace_fake.h"
// In order to test this code, we need to include the tombstone.cpp code.
// Including it, also allows us to override the ptrace function.
#define ptrace ptrace_fake
#include "tombstone.cpp"
void dump_registers(log_t*, pid_t) {
}
void dump_memory_and_code(log_t*, Backtrace*) {
}
void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
}
class TombstoneTest : public ::testing::Test {
protected:
virtual void SetUp() {
map_mock_.reset(new BacktraceMapMock());
backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
char tmp_file[256];
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, data_template, sizeof(data_template));
int tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, tmp_template, sizeof(tmp_template));
tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
abort();
}
}
if (unlink(tmp_file) == -1) {
abort();
}
log_.tfd = tombstone_fd;
log_.amfd = -1;
log_.crashed_tid = 12;
log_.current_tid = 12;
log_.should_retrieve_logcat = false;
resetLogs();
elf_set_fake_build_id("");
siginfo_t si;
si.si_signo = SIGABRT;
ptrace_set_fake_getsiginfo(si);
}
virtual void TearDown() {
if (log_.tfd >= 0) {
close(log_.tfd);
}
}
std::unique_ptr<BacktraceMapMock> map_mock_;
std::unique_ptr<BacktraceMock> backtrace_mock_;
log_t log_;
};
TEST_F(TombstoneTest, single_map) {
backtrace_map_t map;
#if defined(__LP64__)
map.start = 0x123456789abcd000UL;
map.end = 0x123456789abdf000UL;
#else
map.start = 0x1234000;
map.end = 0x1235000;
#endif
map_mock_->AddMap(map);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff --- 0 12000\n";
#else
" 01234000-01234fff --- 0 1000\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, single_map_elf_build_id) {
backtrace_map_t map;
#if defined(__LP64__)
map.start = 0x123456789abcd000UL;
map.end = 0x123456789abdf000UL;
#else
map.start = 0x1234000;
map.end = 0x1235000;
#endif
map.flags = PROT_READ;
map.name = "/system/lib/libfake.so";
map_mock_->AddMap(map);
elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
#else
" 01234000-01234fff r-- 0 1000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
// Even though build id is present, it should not be printed in either of
// these cases.
TEST_F(TombstoneTest, single_map_no_build_id) {
backtrace_map_t map;
#if defined(__LP64__)
map.start = 0x123456789abcd000UL;
map.end = 0x123456789abdf000UL;
#else
map.start = 0x1234000;
map.end = 0x1235000;
#endif
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.name = "/system/lib/libfake.so";
map_mock_->AddMap(map);
elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n"
" 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n";
#else
" 01234000-01234fff -w- 0 1000\n"
" 01234000-01234fff -w- 0 1000 /system/lib/libfake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps) {
backtrace_map_t map;
map.start = 0xa234000;
map.end = 0xa235000;
map_mock_->AddMap(map);
map.start = 0xa334000;
map.end = 0xa335000;
map.offset = 0xf000;
map.flags = PROT_READ;
map_mock_->AddMap(map);
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
" 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
" 0a234000-0a234fff --- 0 1000\n"
" 0a334000-0a334fff r-- f000 1000\n"
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
si.si_addr = reinterpret_cast<void*>(0x1000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
"--->Fault address falls at 00001000 before any mapped regions\n"
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
si.si_addr = reinterpret_cast<void*>(0xa533000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->Fault address falls at 0a533000 between mapped regions\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
si.si_addr = reinterpret_cast<void*>(0xa534040);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
#if defined(__LP64__)
si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
#else
si.si_addr = reinterpret_cast<void*>(0xf534040UL);
#endif
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n"
"--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n"
"--->Fault address falls at 0f534040 after any mapped regions\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_getsiginfo_fail) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = 0;
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG Cannot get siginfo for 100: Bad address\n\n", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_check_signal_has_si_addr) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
for (int i = 1; i < 255; i++) {
ASSERT_TRUE(ftruncate(log_.tfd, 0) == 0);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
siginfo_t si;
si.si_signo = i;
si.si_addr = reinterpret_cast<void*>(0x1000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
bool has_addr = false;
switch (si.si_signo) {
case SIGBUS:
case SIGFPE:
case SIGILL:
case SIGSEGV:
case SIGTRAP:
has_addr = true;
break;
}
const char* expected_addr_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
#else
"--->Fault address falls at 00001000 before any mapped regions\n"
" 0a434000-0a434fff -w- 0 1000\n";
#endif
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
#else
" 0a434000-0a434fff -w- 0 1000\n";
#endif
if (has_addr) {
ASSERT_STREQ(expected_addr_dump, tombstone_contents.c_str())
<< "Signal " << si.si_signo << " expected to include an address.";
} else {
ASSERT_STREQ(expected_dump, tombstone_contents.c_str())
<< "Signal " << si.si_signo << " is not expected to include an address.";
}
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
}
TEST_F(TombstoneTest, dump_signal_info_error) {
siginfo_t si;
si.si_signo = 0;
ptrace_set_fake_getsiginfo(si);
dump_signal_info(&log_, 123, SIGSEGV, 10);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ("", tombstone_contents.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, dump_log_file_error) {
log_.should_retrieve_logcat = true;
dump_log_file(&log_, 123, "/fake/filename", 10);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ("", tombstone_contents.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
getFakeLogPrint().c_str());
}