summaryrefslogtreecommitdiffstats
path: root/debuggerd/libdebuggerd/test
diff options
context:
space:
mode:
Diffstat (limited to 'debuggerd/libdebuggerd/test')
-rw-r--r--debuggerd/libdebuggerd/test/BacktraceMock.h106
-rw-r--r--debuggerd/libdebuggerd/test/dump_memory_test.cpp740
-rw-r--r--debuggerd/libdebuggerd/test/elf_fake.cpp35
-rw-r--r--debuggerd/libdebuggerd/test/elf_fake.h24
-rw-r--r--debuggerd/libdebuggerd/test/host_signal_fixup.h65
-rw-r--r--debuggerd/libdebuggerd/test/log_fake.cpp94
-rw-r--r--debuggerd/libdebuggerd/test/log_fake.h26
-rw-r--r--debuggerd/libdebuggerd/test/open_files_list_test.cpp49
-rw-r--r--debuggerd/libdebuggerd/test/property_fake.cpp45
-rw-r--r--debuggerd/libdebuggerd/test/ptrace_fake.cpp53
-rw-r--r--debuggerd/libdebuggerd/test/ptrace_fake.h24
-rw-r--r--debuggerd/libdebuggerd/test/sys/system_properties.h38
-rw-r--r--debuggerd/libdebuggerd/test/tombstone_test.cpp633
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());
+}