diff options
Diffstat (limited to 'debuggerd/libdebuggerd/test')
-rw-r--r-- | debuggerd/libdebuggerd/test/BacktraceMock.h | 106 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/dump_memory_test.cpp | 740 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/elf_fake.cpp | 35 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/elf_fake.h | 24 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/host_signal_fixup.h | 65 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/log_fake.cpp | 94 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/log_fake.h | 26 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/open_files_list_test.cpp | 49 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/property_fake.cpp | 45 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/ptrace_fake.cpp | 53 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/ptrace_fake.h | 24 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/sys/system_properties.h | 38 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/tombstone_test.cpp | 633 |
13 files changed, 1932 insertions, 0 deletions
diff --git a/debuggerd/libdebuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h new file mode 100644 index 000000000..6104f7e0d --- /dev/null +++ b/debuggerd/libdebuggerd/test/BacktraceMock.h @@ -0,0 +1,106 @@ +/* + * 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_BACKTRACE_MOCK_H +#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ucontext.h> + +#include <string> +#include <vector> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +class BacktraceMapMock : public BacktraceMap { + public: + BacktraceMapMock() : BacktraceMap(0) {} + virtual ~BacktraceMapMock() {} + + void AddMap(backtrace_map_t& map) { + maps_.push_back(map); + } +}; + + +class BacktraceMock : public Backtrace { + public: + explicit BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) { + if (map_ == nullptr) { + abort(); + } + } + virtual ~BacktraceMock() {} + + virtual bool Unwind(size_t, ucontext_t*) { return false; } + virtual bool ReadWord(uintptr_t, word_t*) { return false;} + + virtual std::string GetFunctionNameRaw(uintptr_t, uintptr_t*) { return ""; } + + virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { + size_t offset = 0; + if (last_read_addr_ > 0) { + offset = addr - last_read_addr_; + } + size_t bytes_available = buffer_.size() - offset; + + if (do_partial_read_) { + // Do a partial read. + if (bytes > bytes_partial_read_) { + bytes = bytes_partial_read_; + } + bytes_partial_read_ -= bytes; + // Only support a single partial read. + do_partial_read_ = false; + } else if (bytes > bytes_available) { + bytes = bytes_available; + } + + if (bytes > 0) { + memcpy(buffer, buffer_.data() + offset, bytes); + } + + last_read_addr_ = addr; + return bytes; + } + + void SetReadData(uint8_t* buffer, size_t bytes) { + buffer_.resize(bytes); + memcpy(buffer_.data(), buffer, bytes); + bytes_partial_read_ = 0; + do_partial_read_ = false; + last_read_addr_ = 0; + } + + void SetPartialReadAmount(size_t bytes) { + if (bytes > buffer_.size()) { + abort(); + } + bytes_partial_read_ = bytes; + do_partial_read_ = true; + } + + private: + std::vector<uint8_t> buffer_; + size_t bytes_partial_read_ = 0; + uintptr_t last_read_addr_ = 0; + bool do_partial_read_ = false; +}; + +#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp new file mode 100644 index 000000000..49f369018 --- /dev/null +++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp @@ -0,0 +1,740 @@ +/* + * 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 <android-base/file.h> + +#include "BacktraceMock.h" +#include "log_fake.h" +#include "utility.h" + +const char g_expected_full_dump[] = +"\nmemory near r1:\n" +#if defined(__LP64__) +" 0000000012345658 0706050403020100 0f0e0d0c0b0a0908 ................\n" +" 0000000012345668 1716151413121110 1f1e1d1c1b1a1918 ................\n" +" 0000000012345678 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" +" 0000000012345688 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" +" 0000000012345698 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" +" 00000000123456a8 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" +" 00000000123456b8 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" +" 00000000123456c8 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" +" 00000000123456d8 8786858483828180 8f8e8d8c8b8a8988 ................\n" +" 00000000123456e8 9796959493929190 9f9e9d9c9b9a9998 ................\n" +" 00000000123456f8 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" +" 0000000012345708 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" +" 0000000012345718 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" +" 0000000012345728 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" +" 0000000012345738 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" +" 0000000012345748 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; +#else +" 12345658 03020100 07060504 0b0a0908 0f0e0d0c ................\n" +" 12345668 13121110 17161514 1b1a1918 1f1e1d1c ................\n" +" 12345678 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" +" 12345688 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" +" 12345698 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" +" 123456a8 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" +" 123456b8 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" +" 123456c8 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" +" 123456d8 83828180 87868584 8b8a8988 8f8e8d8c ................\n" +" 123456e8 93929190 97969594 9b9a9998 9f9e9d9c ................\n" +" 123456f8 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" +" 12345708 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" +" 12345718 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" +" 12345728 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" +" 12345738 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" +" 12345748 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; +#endif + +const char g_expected_partial_dump[] = \ +"\nmemory near pc:\n" +#if defined(__LP64__) +" 00000000123455e0 0706050403020100 0f0e0d0c0b0a0908 ................\n" +" 00000000123455f0 1716151413121110 1f1e1d1c1b1a1918 ................\n" +" 0000000012345600 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" +" 0000000012345610 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" +" 0000000012345620 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" +" 0000000012345630 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" +" 0000000012345640 6766656463626160 ---------------- `abcdefg........\n" +" 0000000012345650 ---------------- ---------------- ................\n" +" 0000000012345660 ---------------- ---------------- ................\n" +" 0000000012345670 ---------------- ---------------- ................\n" +" 0000000012345680 ---------------- ---------------- ................\n" +" 0000000012345690 ---------------- ---------------- ................\n" +" 00000000123456a0 ---------------- ---------------- ................\n" +" 00000000123456b0 ---------------- ---------------- ................\n" +" 00000000123456c0 ---------------- ---------------- ................\n" +" 00000000123456d0 ---------------- ---------------- ................\n"; +#else +" 123455e0 03020100 07060504 0b0a0908 0f0e0d0c ................\n" +" 123455f0 13121110 17161514 1b1a1918 1f1e1d1c ................\n" +" 12345600 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" +" 12345610 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" +" 12345620 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" +" 12345630 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" +" 12345640 63626160 67666564 -------- -------- `abcdefg........\n" +" 12345650 -------- -------- -------- -------- ................\n" +" 12345660 -------- -------- -------- -------- ................\n" +" 12345670 -------- -------- -------- -------- ................\n" +" 12345680 -------- -------- -------- -------- ................\n" +" 12345690 -------- -------- -------- -------- ................\n" +" 123456a0 -------- -------- -------- -------- ................\n" +" 123456b0 -------- -------- -------- -------- ................\n" +" 123456c0 -------- -------- -------- -------- ................\n" +" 123456d0 -------- -------- -------- -------- ................\n"; +#endif + +class DumpMemoryTest : 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_data = nullptr; + log_.crashed_tid = 12; + log_.current_tid = 12; + log_.should_retrieve_logcat = false; + + resetLogs(); + } + + 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(DumpMemoryTest, aligned_addr) { + uint8_t buffer[256]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + + dump_memory(&log_, backtrace_mock_.get(), 0x12345678, "memory near %.2s:", "r1"); + + std::string tombstone_contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); + ASSERT_STREQ(g_expected_full_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(DumpMemoryTest, partial_read) { + uint8_t buffer[256]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + backtrace_mock_->SetPartialReadAmount(96); + + dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1"); + + std::string tombstone_contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); + ASSERT_STREQ(g_expected_full_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(DumpMemoryTest, unaligned_addr) { + uint8_t buffer[256]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + + dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1"); + + std::string tombstone_contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); + ASSERT_STREQ(g_expected_full_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(DumpMemoryTest, memory_unreadable) { + dump_memory(&log_, backtrace_mock_.get(), 0xa2345678, "memory near pc:"); + + 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 near pc:\n" +#if defined(__LP64__) +" 00000000a2345658 ---------------- ---------------- ................\n" +" 00000000a2345668 ---------------- ---------------- ................\n" +" 00000000a2345678 ---------------- ---------------- ................\n" +" 00000000a2345688 ---------------- ---------------- ................\n" +" 00000000a2345698 ---------------- ---------------- ................\n" +" 00000000a23456a8 ---------------- ---------------- ................\n" +" 00000000a23456b8 ---------------- ---------------- ................\n" +" 00000000a23456c8 ---------------- ---------------- ................\n" +" 00000000a23456d8 ---------------- ---------------- ................\n" +" 00000000a23456e8 ---------------- ---------------- ................\n" +" 00000000a23456f8 ---------------- ---------------- ................\n" +" 00000000a2345708 ---------------- ---------------- ................\n" +" 00000000a2345718 ---------------- ---------------- ................\n" +" 00000000a2345728 ---------------- ---------------- ................\n" +" 00000000a2345738 ---------------- ---------------- ................\n" +" 00000000a2345748 ---------------- ---------------- ................\n"; +#else +" a2345658 -------- -------- -------- -------- ................\n" +" a2345668 -------- -------- -------- -------- ................\n" +" a2345678 -------- -------- -------- -------- ................\n" +" a2345688 -------- -------- -------- -------- ................\n" +" a2345698 -------- -------- -------- -------- ................\n" +" a23456a8 -------- -------- -------- -------- ................\n" +" a23456b8 -------- -------- -------- -------- ................\n" +" a23456c8 -------- -------- -------- -------- ................\n" +" a23456d8 -------- -------- -------- -------- ................\n" +" a23456e8 -------- -------- -------- -------- ................\n" +" a23456f8 -------- -------- -------- -------- ................\n" +" a2345708 -------- -------- -------- -------- ................\n" +" a2345718 -------- -------- -------- -------- ................\n" +" a2345728 -------- -------- -------- -------- ................\n" +" a2345738 -------- -------- -------- -------- ................\n" +" a2345748 -------- -------- -------- -------- ................\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(DumpMemoryTest, memory_partially_unreadable) { + uint8_t buffer[104]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + + dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:"); + + std::string tombstone_contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); + ASSERT_STREQ(g_expected_partial_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(DumpMemoryTest, memory_partially_unreadable_unaligned_return) { + uint8_t buffer[104]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + backtrace_mock_->SetPartialReadAmount(102); + + dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:"); + + std::string tombstone_contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); + ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str()); + +#if defined(__LP64__) + ASSERT_STREQ("6 DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str()); +#else + ASSERT_STREQ("6 DEBUG Bytes read 102, is not a multiple of 4\n", getFakeLogPrint().c_str()); +#endif + + // Verify that the log buf is empty, and no error messages. + ASSERT_STREQ("", getFakeLogBuf().c_str()); +} + +TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) { + uint8_t buffer[106]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + backtrace_mock_->SetPartialReadAmount(45); + + dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:"); + + std::string tombstone_contents; + ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); + ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); + ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str()); + +#if defined(__LP64__) + ASSERT_STREQ("6 DEBUG Bytes read 45, is not a multiple of 8\n" + "6 DEBUG Bytes after second read 106, is not a multiple of 8\n", + getFakeLogPrint().c_str()); +#else + ASSERT_STREQ("6 DEBUG Bytes read 45, is not a multiple of 4\n" + "6 DEBUG Bytes after second read 106, is not a multiple of 4\n", + getFakeLogPrint().c_str()); +#endif + + // Verify that the log buf is empty, and no error messages. + ASSERT_STREQ("", getFakeLogBuf().c_str()); +} + +TEST_F(DumpMemoryTest, address_low_fence) { + uint8_t buffer[256]; + memset(buffer, 0, sizeof(buffer)); + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + + dump_memory(&log_, backtrace_mock_.get(), 0x1000, "memory near %.2s:", "r1"); + + 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 near r1:\n" +#if defined(__LP64__) +" 0000000000001000 0000000000000000 0000000000000000 ................\n" +" 0000000000001010 0000000000000000 0000000000000000 ................\n" +" 0000000000001020 0000000000000000 0000000000000000 ................\n" +" 0000000000001030 0000000000000000 0000000000000000 ................\n" +" 0000000000001040 0000000000000000 0000000000000000 ................\n" +" 0000000000001050 0000000000000000 0000000000000000 ................\n" +" 0000000000001060 0000000000000000 0000000000000000 ................\n" +" 0000000000001070 0000000000000000 0000000000000000 ................\n" +" 0000000000001080 0000000000000000 0000000000000000 ................\n" +" 0000000000001090 0000000000000000 0000000000000000 ................\n" +" 00000000000010a0 0000000000000000 0000000000000000 ................\n" +" 00000000000010b0 0000000000000000 0000000000000000 ................\n" +" 00000000000010c0 0000000000000000 0000000000000000 ................\n" +" 00000000000010d0 0000000000000000 0000000000000000 ................\n" +" 00000000000010e0 0000000000000000 0000000000000000 ................\n" +" 00000000000010f0 0000000000000000 0000000000000000 ................\n"; +#else +" 00001000 00000000 00000000 00000000 00000000 ................\n" +" 00001010 00000000 00000000 00000000 00000000 ................\n" +" 00001020 00000000 00000000 00000000 00000000 ................\n" +" 00001030 00000000 00000000 00000000 00000000 ................\n" +" 00001040 00000000 00000000 00000000 00000000 ................\n" +" 00001050 00000000 00000000 00000000 00000000 ................\n" +" 00001060 00000000 00000000 00000000 00000000 ................\n" +" 00001070 00000000 00000000 00000000 00000000 ................\n" +" 00001080 00000000 00000000 00000000 00000000 ................\n" +" 00001090 00000000 00000000 00000000 00000000 ................\n" +" 000010a0 00000000 00000000 00000000 00000000 ................\n" +" 000010b0 00000000 00000000 00000000 00000000 ................\n" +" 000010c0 00000000 00000000 00000000 00000000 ................\n" +" 000010d0 00000000 00000000 00000000 00000000 ................\n" +" 000010e0 00000000 00000000 00000000 00000000 ................\n" +" 000010f0 00000000 00000000 00000000 00000000 ................\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(DumpMemoryTest, memory_address_too_low) { + uint8_t buffer[256]; + memset(buffer, 0, sizeof(buffer)); + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + + dump_memory(&log_, backtrace_mock_.get(), 0, "memory near %.2s:", "r1"); + + 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()); + + // Verify that the log buf is empty, and no error messages. + ASSERT_STREQ("", getFakeLogBuf().c_str()); + ASSERT_STREQ("", getFakeLogPrint().c_str()); +} + +TEST_F(DumpMemoryTest, memory_address_too_high) { + uint8_t buffer[256]; + memset(buffer, 0, sizeof(buffer)); + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + +#if defined(__LP64__) + dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1"); + dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1"); + dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1"); +#else + dump_memory(&log_, backtrace_mock_.get(), 0xffff0000, "memory near %.2s:", "r1"); + dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1"); + dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1"); +#endif + + 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()); + + // Verify that the log buf is empty, and no error messages. + ASSERT_STREQ("", getFakeLogBuf().c_str()); + ASSERT_STREQ("", getFakeLogPrint().c_str()); +} + +TEST_F(DumpMemoryTest, memory_address_would_overflow) { + uint8_t buffer[256]; + memset(buffer, 0, sizeof(buffer)); + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + +#if defined(__LP64__) + dump_memory(&log_, backtrace_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1"); +#else + dump_memory(&log_, backtrace_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1"); +#endif + + 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()); + + // Verify that the log buf is empty, and no error messages. + ASSERT_STREQ("", getFakeLogBuf().c_str()); + ASSERT_STREQ("", getFakeLogPrint().c_str()); +} + +TEST_F(DumpMemoryTest, memory_address_nearly_too_high) { + uint8_t buffer[256]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + +#if defined(__LP64__) + dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4"); +#else + dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4"); +#endif + + 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 near r4:\n" +#if defined(__LP64__) +" 3fffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n" +" 3fffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n" +" 3fffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" +" 3fffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" +" 3fffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" +" 3fffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" +" 3fffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" +" 3fffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" +" 3fffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n" +" 3fffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n" +" 3fffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" +" 3fffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" +" 3fffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" +" 3fffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" +" 3fffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" +" 3ffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; +#else +" fffeff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n" +" fffeff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n" +" fffeff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" +" fffeff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" +" fffeff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" +" fffeff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" +" fffeff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" +" fffeff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" +" fffeff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n" +" fffeff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n" +" fffeffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" +" fffeffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" +" fffeffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" +" fffeffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" +" fffeffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" +" fffefff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\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(DumpMemoryTest, first_read_empty) { + uint8_t buffer[256]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + backtrace_mock_->SetPartialReadAmount(0); + + size_t page_size = sysconf(_SC_PAGE_SIZE); + uintptr_t addr = 0x10000020 + page_size - 120; + dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); + + 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 near r4:\n" +#if defined(__LP64__) +" 0000000010000f88 ---------------- ---------------- ................\n" +" 0000000010000f98 ---------------- ---------------- ................\n" +" 0000000010000fa8 ---------------- ---------------- ................\n" +" 0000000010000fb8 ---------------- ---------------- ................\n" +" 0000000010000fc8 ---------------- ---------------- ................\n" +" 0000000010000fd8 ---------------- ---------------- ................\n" +" 0000000010000fe8 ---------------- ---------------- ................\n" +" 0000000010000ff8 ---------------- 7f7e7d7c7b7a7978 ........xyz{|}~.\n" +" 0000000010001008 8786858483828180 8f8e8d8c8b8a8988 ................\n" +" 0000000010001018 9796959493929190 9f9e9d9c9b9a9998 ................\n" +" 0000000010001028 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" +" 0000000010001038 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" +" 0000000010001048 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" +" 0000000010001058 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" +" 0000000010001068 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" +" 0000000010001078 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; +#else +" 10000f88 -------- -------- -------- -------- ................\n" +" 10000f98 -------- -------- -------- -------- ................\n" +" 10000fa8 -------- -------- -------- -------- ................\n" +" 10000fb8 -------- -------- -------- -------- ................\n" +" 10000fc8 -------- -------- -------- -------- ................\n" +" 10000fd8 -------- -------- -------- -------- ................\n" +" 10000fe8 -------- -------- -------- -------- ................\n" +" 10000ff8 -------- -------- 7b7a7978 7f7e7d7c ........xyz{|}~.\n" +" 10001008 83828180 87868584 8b8a8988 8f8e8d8c ................\n" +" 10001018 93929190 97969594 9b9a9998 9f9e9d9c ................\n" +" 10001028 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" +" 10001038 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" +" 10001048 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" +" 10001058 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" +" 10001068 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" +" 10001078 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\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(DumpMemoryTest, first_read_empty_second_read_stops) { + uint8_t buffer[224]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + backtrace_mock_->SetPartialReadAmount(0); + + size_t page_size = sysconf(_SC_PAGE_SIZE); + uintptr_t addr = 0x10000020 + page_size - 192; + dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); + + 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 near r4:\n" +#if defined(__LP64__) +" 0000000010000f40 ---------------- ---------------- ................\n" +" 0000000010000f50 ---------------- ---------------- ................\n" +" 0000000010000f60 ---------------- ---------------- ................\n" +" 0000000010000f70 ---------------- ---------------- ................\n" +" 0000000010000f80 ---------------- ---------------- ................\n" +" 0000000010000f90 ---------------- ---------------- ................\n" +" 0000000010000fa0 ---------------- ---------------- ................\n" +" 0000000010000fb0 ---------------- ---------------- ................\n" +" 0000000010000fc0 ---------------- ---------------- ................\n" +" 0000000010000fd0 ---------------- ---------------- ................\n" +" 0000000010000fe0 ---------------- ---------------- ................\n" +" 0000000010000ff0 ---------------- ---------------- ................\n" +" 0000000010001000 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" +" 0000000010001010 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" +" 0000000010001020 ---------------- ---------------- ................\n" +" 0000000010001030 ---------------- ---------------- ................\n"; +#else +" 10000f40 -------- -------- -------- -------- ................\n" +" 10000f50 -------- -------- -------- -------- ................\n" +" 10000f60 -------- -------- -------- -------- ................\n" +" 10000f70 -------- -------- -------- -------- ................\n" +" 10000f80 -------- -------- -------- -------- ................\n" +" 10000f90 -------- -------- -------- -------- ................\n" +" 10000fa0 -------- -------- -------- -------- ................\n" +" 10000fb0 -------- -------- -------- -------- ................\n" +" 10000fc0 -------- -------- -------- -------- ................\n" +" 10000fd0 -------- -------- -------- -------- ................\n" +" 10000fe0 -------- -------- -------- -------- ................\n" +" 10000ff0 -------- -------- -------- -------- ................\n" +" 10001000 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" +" 10001010 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" +" 10001020 -------- -------- -------- -------- ................\n" +" 10001030 -------- -------- -------- -------- ................\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(DumpMemoryTest, first_read_empty_next_page_out_of_range) { + uint8_t buffer[256]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + backtrace_mock_->SetPartialReadAmount(0); + + uintptr_t addr = 0x10000020; + dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); + + 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 near r4:\n" +#if defined(__LP64__) +" 0000000010000000 ---------------- ---------------- ................\n" +" 0000000010000010 ---------------- ---------------- ................\n" +" 0000000010000020 ---------------- ---------------- ................\n" +" 0000000010000030 ---------------- ---------------- ................\n" +" 0000000010000040 ---------------- ---------------- ................\n" +" 0000000010000050 ---------------- ---------------- ................\n" +" 0000000010000060 ---------------- ---------------- ................\n" +" 0000000010000070 ---------------- ---------------- ................\n" +" 0000000010000080 ---------------- ---------------- ................\n" +" 0000000010000090 ---------------- ---------------- ................\n" +" 00000000100000a0 ---------------- ---------------- ................\n" +" 00000000100000b0 ---------------- ---------------- ................\n" +" 00000000100000c0 ---------------- ---------------- ................\n" +" 00000000100000d0 ---------------- ---------------- ................\n" +" 00000000100000e0 ---------------- ---------------- ................\n" +" 00000000100000f0 ---------------- ---------------- ................\n"; +#else +" 10000000 -------- -------- -------- -------- ................\n" +" 10000010 -------- -------- -------- -------- ................\n" +" 10000020 -------- -------- -------- -------- ................\n" +" 10000030 -------- -------- -------- -------- ................\n" +" 10000040 -------- -------- -------- -------- ................\n" +" 10000050 -------- -------- -------- -------- ................\n" +" 10000060 -------- -------- -------- -------- ................\n" +" 10000070 -------- -------- -------- -------- ................\n" +" 10000080 -------- -------- -------- -------- ................\n" +" 10000090 -------- -------- -------- -------- ................\n" +" 100000a0 -------- -------- -------- -------- ................\n" +" 100000b0 -------- -------- -------- -------- ................\n" +" 100000c0 -------- -------- -------- -------- ................\n" +" 100000d0 -------- -------- -------- -------- ................\n" +" 100000e0 -------- -------- -------- -------- ................\n" +" 100000f0 -------- -------- -------- -------- ................\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(DumpMemoryTest, first_read_empty_next_page_out_of_range_fence_post) { + uint8_t buffer[256]; + for (size_t i = 0; i < sizeof(buffer); i++) { + buffer[i] = i; + } + backtrace_mock_->SetReadData(buffer, sizeof(buffer)); + backtrace_mock_->SetPartialReadAmount(0); + + size_t page_size = sysconf(_SC_PAGE_SIZE); + uintptr_t addr = 0x10000020 + page_size - 256; + + dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4"); + + 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 near r4:\n" +#if defined(__LP64__) +" 0000000010000f00 ---------------- ---------------- ................\n" +" 0000000010000f10 ---------------- ---------------- ................\n" +" 0000000010000f20 ---------------- ---------------- ................\n" +" 0000000010000f30 ---------------- ---------------- ................\n" +" 0000000010000f40 ---------------- ---------------- ................\n" +" 0000000010000f50 ---------------- ---------------- ................\n" +" 0000000010000f60 ---------------- ---------------- ................\n" +" 0000000010000f70 ---------------- ---------------- ................\n" +" 0000000010000f80 ---------------- ---------------- ................\n" +" 0000000010000f90 ---------------- ---------------- ................\n" +" 0000000010000fa0 ---------------- ---------------- ................\n" +" 0000000010000fb0 ---------------- ---------------- ................\n" +" 0000000010000fc0 ---------------- ---------------- ................\n" +" 0000000010000fd0 ---------------- ---------------- ................\n" +" 0000000010000fe0 ---------------- ---------------- ................\n" +" 0000000010000ff0 ---------------- ---------------- ................\n"; +#else +" 10000f00 -------- -------- -------- -------- ................\n" +" 10000f10 -------- -------- -------- -------- ................\n" +" 10000f20 -------- -------- -------- -------- ................\n" +" 10000f30 -------- -------- -------- -------- ................\n" +" 10000f40 -------- -------- -------- -------- ................\n" +" 10000f50 -------- -------- -------- -------- ................\n" +" 10000f60 -------- -------- -------- -------- ................\n" +" 10000f70 -------- -------- -------- -------- ................\n" +" 10000f80 -------- -------- -------- -------- ................\n" +" 10000f90 -------- -------- -------- -------- ................\n" +" 10000fa0 -------- -------- -------- -------- ................\n" +" 10000fb0 -------- -------- -------- -------- ................\n" +" 10000fc0 -------- -------- -------- -------- ................\n" +" 10000fd0 -------- -------- -------- -------- ................\n" +" 10000fe0 -------- -------- -------- -------- ................\n" +" 10000ff0 -------- -------- -------- -------- ................\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()); +} diff --git a/debuggerd/libdebuggerd/test/elf_fake.cpp b/debuggerd/libdebuggerd/test/elf_fake.cpp new file mode 100644 index 000000000..bb52b59c9 --- /dev/null +++ b/debuggerd/libdebuggerd/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 <stdint.h> + +#include <string> + +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/libdebuggerd/test/elf_fake.h b/debuggerd/libdebuggerd/test/elf_fake.h new file mode 100644 index 000000000..08a8454a4 --- /dev/null +++ b/debuggerd/libdebuggerd/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 <string> + +void elf_set_fake_build_id(const std::string&); + +#endif // _DEBUGGERD_TEST_ELF_FAKE_H diff --git a/debuggerd/libdebuggerd/test/host_signal_fixup.h b/debuggerd/libdebuggerd/test/host_signal_fixup.h new file mode 100644 index 000000000..762bae5fb --- /dev/null +++ b/debuggerd/libdebuggerd/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 <signal.h> + +#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/libdebuggerd/test/log_fake.cpp b/debuggerd/libdebuggerd/test/log_fake.cpp new file mode 100644 index 000000000..3336bcb50 --- /dev/null +++ b/debuggerd/libdebuggerd/test/log_fake.cpp @@ -0,0 +1,94 @@ +/* + * 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 <errno.h> +#include <stdarg.h> + +#include <string> + +#include <android-base/stringprintf.h> +#include <log/log.h> + +// Forward declarations. +class Backtrace; +struct EventTagMap; +struct AndroidLogEntry; + +std::string g_fake_log_buf; + +std::string g_fake_log_print; + +void resetLogs() { + g_fake_log_buf = ""; + 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 bufId, int prio, const char* tag, const char* msg) { + g_fake_log_buf += std::to_string(bufId) + ' ' + std::to_string(prio) + ' '; + g_fake_log_buf += tag; + g_fake_log_buf += ' '; + g_fake_log_buf += msg; + return 1; +} + +extern "C" int __android_log_print(int prio, const char* tag, const char* fmt, ...) { + g_fake_log_print += std::to_string(prio) + ' '; + g_fake_log_print += tag; + g_fake_log_print += ' '; + + va_list ap; + va_start(ap, fmt); + android::base::StringAppendV(&g_fake_log_print, fmt, ap); + va_end(ap); + + g_fake_log_print += '\n'; + + return 1; +} + +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) { + errno = EACCES; + 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/libdebuggerd/test/log_fake.h b/debuggerd/libdebuggerd/test/log_fake.h new file mode 100644 index 000000000..5418fce64 --- /dev/null +++ b/debuggerd/libdebuggerd/test/log_fake.h @@ -0,0 +1,26 @@ +/* + * 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_LOG_FAKE_H +#define _DEBUGGERD_TEST_LOG_FAKE_H + +#include <string> + +void resetLogs(); +std::string getFakeLogBuf(); +std::string getFakeLogPrint(); + +#endif // _DEBUGGERD_TEST_LOG_FAKE_H diff --git a/debuggerd/libdebuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp new file mode 100644 index 000000000..85e069510 --- /dev/null +++ b/debuggerd/libdebuggerd/test/open_files_list_test.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 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 <string.h> +#include <unistd.h> + +#include <string> + +#include <gtest/gtest.h> + +#include "android-base/test_utils.h" + +#include "open_files_list.h" + +// Check that we can produce a list of open files for the current process, and +// that it includes a known open file. +TEST(OpenFilesListTest, BasicTest) { + // Open a temporary file that we can check for in the list of open files. + TemporaryFile tf; + + // Get the list of open files for this process. + OpenFilesList list; + populate_open_files_list(getpid(), &list); + + // Verify our open file is in the list. + bool found = false; + for (auto& file : list) { + if (file.first == tf.fd) { + EXPECT_EQ(file.second, std::string(tf.path)); + found = true; + break; + } + } + EXPECT_TRUE(found); +} diff --git a/debuggerd/libdebuggerd/test/property_fake.cpp b/debuggerd/libdebuggerd/test/property_fake.cpp new file mode 100644 index 000000000..02069f1af --- /dev/null +++ b/debuggerd/libdebuggerd/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 <string.h> + +#include <string> +#include <unordered_map> + +#include <sys/system_properties.h> + +std::unordered_map<std::string, std::string> 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/libdebuggerd/test/ptrace_fake.cpp b/debuggerd/libdebuggerd/test/ptrace_fake.cpp new file mode 100644 index 000000000..f40cbd429 --- /dev/null +++ b/debuggerd/libdebuggerd/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 <errno.h> +#include <signal.h> +#include <stdarg.h> +#include <sys/ptrace.h> + +#include <string> + +#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/libdebuggerd/test/ptrace_fake.h b/debuggerd/libdebuggerd/test/ptrace_fake.h new file mode 100644 index 000000000..fdbb66361 --- /dev/null +++ b/debuggerd/libdebuggerd/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 <signal.h> + +void ptrace_set_fake_getsiginfo(const siginfo_t&); + +#endif // _DEBUGGERD_TEST_PTRACE_FAKE_H diff --git a/debuggerd/libdebuggerd/test/sys/system_properties.h b/debuggerd/libdebuggerd/test/sys/system_properties.h new file mode 100644 index 000000000..9d4434530 --- /dev/null +++ b/debuggerd/libdebuggerd/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/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp new file mode 100644 index 000000000..5ee07cda1 --- /dev/null +++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp @@ -0,0 +1,633 @@ +/* + * 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 <android-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; + amfd_data_.clear(); + log_.amfd_data = &amfd_data_; + 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_; + std::string amfd_data_; +}; + +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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.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."; + } + + ASSERT_STREQ("", amfd_data_.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, dump_signal_info_error) { + siginfo_t si; + si.si_signo = 0; + ptrace_set_fake_getsiginfo(si); + + dump_signal_info(&log_, 123); + + 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()); + + ASSERT_STREQ("", amfd_data_.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()); + + ASSERT_STREQ("", amfd_data_.c_str()); +} + +TEST_F(TombstoneTest, dump_header_info) { + dump_header_info(&log_); + + std::string expected = "Build fingerprint: 'unknown'\nRevision: 'unknown'\n"; + expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING); + ASSERT_STREQ(expected.c_str(), amfd_data_.c_str()); +} |