diff options
Diffstat (limited to 'debuggerd/test/dump_maps_test.cpp')
-rw-r--r-- | debuggerd/test/dump_maps_test.cpp | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/debuggerd/test/dump_maps_test.cpp b/debuggerd/test/dump_maps_test.cpp new file mode 100644 index 0000000..230f4f5 --- /dev/null +++ b/debuggerd/test/dump_maps_test.cpp @@ -0,0 +1,571 @@ +/* + * 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 DumpMapsTest : 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 = SIGPIPE; + 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(DumpMapsTest, 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(DumpMapsTest, 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(DumpMapsTest, 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(DumpMapsTest, 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(DumpMapsTest, 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(DumpMapsTest, 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(DumpMapsTest, 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(DumpMapsTest, 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(DumpMapsTest, 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 = \ +"Cannot get siginfo for 100: Bad address\n" +"\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("DEBUG Cannot get siginfo for 100: Bad address\n", + getFakeLogBuf().c_str()); + ASSERT_STREQ("", getFakeLogPrint().c_str()); +} + +TEST_F(DumpMapsTest, 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()); + } +} |