From c4b1f0a99c3ada87d2d7f9dce3e126ef17ed7dbe Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 2 Jun 2015 14:52:44 -0700 Subject: [PATCH] Change the 64 bit map address format. Previously, the map printing in tombstones for 64 bit devices uses a variable length value. This means that the maps are not lined up. The new format is to print the map as 00000000'00000000 in all ways. Also fix a bug where the backtrace_map_t did not initialize all parameters. Add unit tests for all of the dump_all_maps function. Bug: 20950813 (cherry picked from commit 862fe029190b6d8344889988fb85526e64b2f4b7) Change-Id: I4269d2b96ebadcc405f478265a07a830aaf9713c --- debuggerd/Android.mk | 53 ++- debuggerd/test/BacktraceMock.h | 4 + debuggerd/test/dump_maps_test.cpp | 571 +++++++++++++++++++++++++ debuggerd/test/elf_fake.cpp | 35 ++ debuggerd/test/elf_fake.h | 24 ++ debuggerd/test/host_signal_fixup.h | 65 +++ debuggerd/test/log_fake.cpp | 44 +- debuggerd/test/property_fake.cpp | 45 ++ debuggerd/test/ptrace_fake.cpp | 53 +++ debuggerd/test/ptrace_fake.h | 24 ++ debuggerd/test/selinux_fake.cpp | 19 + debuggerd/test/sys/system_properties.h | 38 ++ debuggerd/tombstone.cpp | 37 +- include/backtrace/BacktraceMap.h | 12 +- 14 files changed, 979 insertions(+), 45 deletions(-) create mode 100644 debuggerd/test/dump_maps_test.cpp create mode 100644 debuggerd/test/elf_fake.cpp create mode 100644 debuggerd/test/elf_fake.h create mode 100644 debuggerd/test/host_signal_fixup.h create mode 100644 debuggerd/test/property_fake.cpp create mode 100644 debuggerd/test/ptrace_fake.cpp create mode 100644 debuggerd/test/ptrace_fake.h create mode 100644 debuggerd/test/selinux_fake.cpp create mode 100644 debuggerd/test/sys/system_properties.h diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index 1a5f05e35..6cfb5413d 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -75,46 +75,55 @@ LOCAL_MULTILIB := both include $(BUILD_EXECUTABLE) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ +debuggerd_test_src_files := \ utility.cpp \ + test/dump_maps_test.cpp \ test/dump_memory_test.cpp \ + test/elf_fake.cpp \ test/log_fake.cpp \ + test/property_fake.cpp \ + test/ptrace_fake.cpp \ + test/selinux_fake.cpp \ -LOCAL_MODULE := debuggerd_test - -LOCAL_SHARED_LIBRARIES := \ +debuggerd_shared_libraries := \ libbacktrace \ libbase \ + libcutils \ -LOCAL_C_INCLUDES += $(LOCAL_PATH)/test -LOCAL_CPPFLAGS := $(common_cppflags) +debuggerd_c_includes := \ + $(LOCAL_PATH)/test \ + +debuggerd_cpp_flags := \ + $(common_cppflags) \ + -Wno-missing-field-initializers \ + +# Only build the host tests on linux. +ifeq ($(HOST_OS),linux) + +include $(CLEAR_VARS) + +LOCAL_MODULE := debuggerd_test +LOCAL_SRC_FILES := $(debuggerd_test_src_files) +LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries) +LOCAL_C_INCLUDES := $(debuggerd_c_includes) +LOCAL_CPPFLAGS := $(debuggerd_cpp_flags) LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 LOCAL_MULTILIB := both - include $(BUILD_HOST_NATIVE_TEST) +endif + include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - utility.cpp \ - test/dump_memory_test.cpp \ - test/log_fake.cpp \ - LOCAL_MODULE := debuggerd_test - -LOCAL_SHARED_LIBRARIES := \ - libbacktrace \ - libbase \ - -LOCAL_C_INCLUDES += $(LOCAL_PATH)/test -LOCAL_CPPFLAGS := $(common_cppflags) +LOCAL_SRC_FILES := $(debuggerd_test_src_files) +LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries) +LOCAL_C_INCLUDES := $(debuggerd_c_includes) +LOCAL_CPPFLAGS := $(debuggerd_cpp_flags) LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 LOCAL_MULTILIB := both - include $(BUILD_NATIVE_TEST) diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h index 05ad12ba6..5c252ab4d 100644 --- a/debuggerd/test/BacktraceMock.h +++ b/debuggerd/test/BacktraceMock.h @@ -32,6 +32,10 @@ class BacktraceMapMock : public BacktraceMap { public: BacktraceMapMock() : BacktraceMap(0) {} virtual ~BacktraceMapMock() {} + + void AddMap(backtrace_map_t& map) { + maps_.push_back(map); + } }; diff --git a/debuggerd/test/dump_maps_test.cpp b/debuggerd/test/dump_maps_test.cpp new file mode 100644 index 000000000..230f4f521 --- /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 + +#include +#include + +#include +#include + +#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 map_mock_; + std::unique_ptr 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(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(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(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(0x12345a534040UL); +#else + si.si_addr = reinterpret_cast(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(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()); + } +} diff --git a/debuggerd/test/elf_fake.cpp b/debuggerd/test/elf_fake.cpp new file mode 100644 index 000000000..bb52b59c9 --- /dev/null +++ b/debuggerd/test/elf_fake.cpp @@ -0,0 +1,35 @@ +/* + * 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 + +#include + +class Backtrace; + +std::string g_build_id; + +void elf_set_fake_build_id(const std::string& build_id) { + g_build_id = build_id; +} + +bool elf_get_build_id(Backtrace*, uintptr_t, std::string* build_id) { + if (g_build_id != "") { + *build_id = g_build_id; + return true; + } + return false; +} diff --git a/debuggerd/test/elf_fake.h b/debuggerd/test/elf_fake.h new file mode 100644 index 000000000..08a8454a4 --- /dev/null +++ b/debuggerd/test/elf_fake.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#ifndef _DEBUGGERD_TEST_ELF_FAKE_H +#define _DEBUGGERD_TEST_ELF_FAKE_H + +#include + +void elf_set_fake_build_id(const std::string&); + +#endif // _DEBUGGERD_TEST_ELF_FAKE_H diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/test/host_signal_fixup.h new file mode 100644 index 000000000..c7796efed --- /dev/null +++ b/debuggerd/test/host_signal_fixup.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H +#define _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H + +#include + +#if !defined(__BIONIC__) + +// In order to compile parts of debuggerd for the host, we need to +// define these values. + +#if !defined(NSIGILL) +#define NSIGILL ILL_BADSTK +#endif + +#if !defined(BUS_MCEERR_AR) +#define BUS_MCEERR_AR 4 +#endif +#if !defined(BUS_MCEERR_AO) +#define BUS_MCEERR_AO 5 +#endif +#if !defined(NSIGBUS) +#define NSIGBUS BUS_MCEERR_AO +#endif + +#if !defined(NSIGFPE) +#define NSIGFPE FPE_FLTSUB +#endif + +#if !defined(NSIGSEGV) +#define NSIGSEGV SEGV_ACCERR +#endif + +#if !defined(TRAP_BRANCH) +#define TRAP_BRANCH 3 +#endif +#if !defined(TRAP_HWBKPT) +#define TRAP_HWBKPT 4 +#endif +#if !defined(NSIGTRAP) +#define NSIGTRAP TRAP_HWBKPT +#endif + +#if !defined(SI_DETHREAD) +#define SI_DETHREAD -7 +#endif + +#endif + +#endif // _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp index 1161afef5..26523ad59 100644 --- a/debuggerd/test/log_fake.cpp +++ b/debuggerd/test/log_fake.cpp @@ -19,6 +19,13 @@ #include #include +#include +#include + +// Forward declarations. +class Backtrace; +struct EventTagMap; +struct AndroidLogEntry; std::string g_fake_log_buf; @@ -29,6 +36,14 @@ void resetLogs() { g_fake_log_print = ""; } +std::string getFakeLogBuf() { + return g_fake_log_buf; +} + +std::string getFakeLogPrint() { + return g_fake_log_print; +} + extern "C" int __android_log_buf_write(int, int, const char* tag, const char* msg) { g_fake_log_buf += tag; g_fake_log_buf += ' '; @@ -36,10 +51,6 @@ extern "C" int __android_log_buf_write(int, int, const char* tag, const char* ms return 1; } -std::string getFakeLogBuf() { - return g_fake_log_buf; -} - extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) { g_fake_log_print += tag; g_fake_log_print += ' '; @@ -54,6 +65,27 @@ extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) { return 1; } -std::string getFakeLogPrint() { - return g_fake_log_print; +extern "C" log_id_t android_name_to_log_id(const char*) { + return LOG_ID_SYSTEM; +} + +extern "C" struct logger_list* android_logger_list_open(log_id_t, int, unsigned int, pid_t) { + return nullptr; +} + +extern "C" int android_logger_list_read(struct logger_list*, struct log_msg*) { + return 0; +} + +extern "C" EventTagMap* android_openEventTagMap(const char*) { + return nullptr; +} + +extern "C" int android_log_processBinaryLogBuffer( + struct logger_entry*, + AndroidLogEntry*, const EventTagMap*, char*, int) { + return 0; +} + +extern "C" void android_logger_list_free(struct logger_list*) { } diff --git a/debuggerd/test/property_fake.cpp b/debuggerd/test/property_fake.cpp new file mode 100644 index 000000000..02069f1af --- /dev/null +++ b/debuggerd/test/property_fake.cpp @@ -0,0 +1,45 @@ +/* + * 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 + +#include +#include + +#include + +std::unordered_map g_properties; + +extern "C" int property_set(const char* name, const char* value) { + if (g_properties.count(name) != 0) { + g_properties.erase(name); + } + g_properties[name] = value; + return 0; +} + +extern "C" int property_get(const char* key, char* value, const char* default_value) { + if (g_properties.count(key) == 0) { + if (default_value == nullptr) { + return 0; + } + strncpy(value, default_value, PROP_VALUE_MAX-1); + } else { + strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1); + } + value[PROP_VALUE_MAX-1] = '\0'; + return strlen(value); +} diff --git a/debuggerd/test/ptrace_fake.cpp b/debuggerd/test/ptrace_fake.cpp new file mode 100644 index 000000000..f40cbd429 --- /dev/null +++ b/debuggerd/test/ptrace_fake.cpp @@ -0,0 +1,53 @@ +/* + * 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 +#include +#include +#include + +#include + +#include "ptrace_fake.h" + +siginfo_t g_fake_si = {.si_signo = 0}; + +void ptrace_set_fake_getsiginfo(const siginfo_t& si) { + g_fake_si = si; +} + +#if !defined(__BIONIC__) +extern "C" long ptrace_fake(enum __ptrace_request request, ...) { +#else +extern "C" long ptrace_fake(int request, ...) { +#endif + if (request == PTRACE_GETSIGINFO) { + if (g_fake_si.si_signo == 0) { + errno = EFAULT; + return -1; + } + + va_list ap; + va_start(ap, request); + va_arg(ap, int); + va_arg(ap, int); + siginfo_t* si = va_arg(ap, siginfo*); + va_end(ap); + *si = g_fake_si; + return 0; + } + return -1; +} diff --git a/debuggerd/test/ptrace_fake.h b/debuggerd/test/ptrace_fake.h new file mode 100644 index 000000000..fdbb66361 --- /dev/null +++ b/debuggerd/test/ptrace_fake.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#ifndef _DEBUGGERD_TEST_PTRACE_FAKE_H +#define _DEBUGGERD_TEST_PTRACE_FAKE_H + +#include + +void ptrace_set_fake_getsiginfo(const siginfo_t&); + +#endif // _DEBUGGERD_TEST_PTRACE_FAKE_H diff --git a/debuggerd/test/selinux_fake.cpp b/debuggerd/test/selinux_fake.cpp new file mode 100644 index 000000000..acdd0a97c --- /dev/null +++ b/debuggerd/test/selinux_fake.cpp @@ -0,0 +1,19 @@ +/* + * 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. + */ + +extern "C" int selinux_android_restorecon(const char*, unsigned int) { + return 0; +} diff --git a/debuggerd/test/sys/system_properties.h b/debuggerd/test/sys/system_properties.h new file mode 100644 index 000000000..9d4434530 --- /dev/null +++ b/debuggerd/test/sys/system_properties.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H +#define _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H + +// This is just enough to get the property code to compile on +// the host. + +#define PROP_NAME_MAX 32 +#define PROP_VALUE_MAX 92 + +#endif // _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index 614edb6a6..b0ad27402 100644 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp @@ -317,16 +317,28 @@ static void dump_stack(Backtrace* backtrace, log_t* log) { } } +static std::string get_addr_string(uintptr_t addr) { + std::string addr_str; +#if defined(__LP64__) + addr_str = android::base::StringPrintf("%08x'%08x", + static_cast(addr >> 32), + static_cast(addr & 0xffffffff)); +#else + addr_str = android::base::StringPrintf("%08x", addr); +#endif + return addr_str; +} + static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) { bool print_fault_address_marker = false; uintptr_t addr = 0; siginfo_t si; memset(&si, 0, sizeof(si)); - if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) { - _LOG(log, logtype::ERROR, "cannot get siginfo for %d: %s\n", tid, strerror(errno)); - } else { + if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) != -1) { print_fault_address_marker = signal_has_si_addr(si.si_signo); addr = reinterpret_cast(si.si_addr); + } else { + _LOG(log, logtype::ERROR, "Cannot get siginfo for %d: %s\n", tid, strerror(errno)); } _LOG(log, logtype::MAPS, "\n"); @@ -335,8 +347,8 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p } else { _LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n"); if (map->begin() != map->end() && addr < map->begin()->start) { - _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", - addr); + _LOG(log, logtype::MAPS, "--->Fault address falls at %s before any mapped regions\n", + get_addr_string(addr).c_str()); print_fault_address_marker = false; } } @@ -346,15 +358,15 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p line = " "; if (print_fault_address_marker) { if (addr < it->start) { - _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", - addr); + _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n", + get_addr_string(addr).c_str()); print_fault_address_marker = false; } else if (addr >= it->start && addr < it->end) { line = "--->"; print_fault_address_marker = false; } } - line += android::base::StringPrintf("%" PRIPTR "-%" PRIPTR " ", it->start, it->end - 1); + line += get_addr_string(it->start) + '-' + get_addr_string(it->end - 1) + ' '; if (it->flags & PROT_READ) { line += 'r'; } else { @@ -372,7 +384,9 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p } line += android::base::StringPrintf(" %8" PRIxPTR " %8" PRIxPTR, it->offset, it->end - it->start); + bool space_needed = true; if (it->name.length() > 0) { + space_needed = false; line += " " + it->name; std::string build_id; if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) { @@ -380,13 +394,16 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p } } if (it->load_base != 0) { + if (space_needed) { + line += ' '; + } line += android::base::StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base); } _LOG(log, logtype::MAPS, "%s\n", line.c_str()); } if (print_fault_address_marker) { - _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", - addr); + _LOG(log, logtype::MAPS, "--->Fault address falls at %s after any mapped regions\n", + get_addr_string(addr).c_str()); } } diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h index 784bc035c..bb18aa2e2 100644 --- a/include/backtrace/BacktraceMap.h +++ b/include/backtrace/BacktraceMap.h @@ -33,13 +33,11 @@ #include struct backtrace_map_t { - backtrace_map_t(): start(0), end(0), flags(0) {} - - uintptr_t start; - uintptr_t end; - uintptr_t offset; - uintptr_t load_base; - int flags; + uintptr_t start = 0; + uintptr_t end = 0; + uintptr_t offset = 0; + uintptr_t load_base = 0; + int flags = 0; std::string name; };