C++程序  |  826行  |  33.5 KB

/*
 * 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 <sys/mman.h>
#include <time.h>

#include <memory>
#include <string>

#include <android-base/file.h>
#include <android-base/properties.h>
#include <gtest/gtest.h>

#include "libdebuggerd/utility.h"

#include "UnwinderMock.h"
#include "host_signal_fixup.h"
#include "log_fake.h"

#include "tombstone.cpp"

class TombstoneTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    unwinder_mock_.reset(new UnwinderMock());

    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();
  }

  virtual void TearDown() {
    if (log_.tfd >= 0) {
      close(log_.tfd);
    }
  }

  std::unique_ptr<UnwinderMock> unwinder_mock_;

  log_t log_;
  std::string amfd_data_;
};

TEST_F(TombstoneTest, single_map) {
#if defined(__LP64__)
  unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0);
#else
  unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0);
#endif

  dump_all_maps(&log_, unwinder_mock_.get(), 0);

  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 (1 entry):\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) {
  uint64_t build_id_offset;
#if defined(__LP64__)
  build_id_offset = 0x123456789abcd000UL;
  unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ,
                             "/system/lib/libfake.so", 0);
#else
  build_id_offset = 0x1234000;
  unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0);
#endif

  unwinder_mock_->MockSetBuildID(
      build_id_offset,
      std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef),
                  static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56),
                  static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab),
                  static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12),
                  static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78),
                  static_cast<char>(0x90)});
  dump_all_maps(&log_, unwinder_mock_.get(), 0);

  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 (1 entry):\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());
}

TEST_F(TombstoneTest, multiple_maps) {
  unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0);
  unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0);
  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                             "/system/lib/fake.so", 0);

  dump_all_maps(&log_, unwinder_mock_.get(), 0);

  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 (5 entries):\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 bias 0xd000)\n"
      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 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 bias 0xd000)\n"
      "    0a534000-0a534fff --x      3000      1000  (load bias 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) {
  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                             "/system/lib/fake.so", 0);

  dump_all_maps(&log_, unwinder_mock_.get(), 0x1000);

  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 (3 entries):\n"
#if defined(__LP64__)
      "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 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 bias 0xd000)\n"
      "    0a534000-0a534fff --x      3000      1000  (load bias 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) {
  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                             "/system/lib/fake.so", 0);

  dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000);

  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 (3 entries): (fault address prefixed with --->)\n"
#if defined(__LP64__)
      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
      "--->Fault address falls at 00000000'0a533000 between mapped regions\n"
      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
      "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
#else
      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
      "--->Fault address falls at 0a533000 between mapped regions\n"
      "    0a534000-0a534fff --x      3000      1000  (load bias 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) {
  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                             "/system/lib/fake.so", 0);

  dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040);

  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 (3 entries): (fault address prefixed with --->)\n"
#if defined(__LP64__)
      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
      "--->00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
      "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
#else
      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
      "--->0a534000-0a534fff --x      3000      1000  (load bias 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) {
  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                             "/system/lib/fake.so", 0);

#if defined(__LP64__)
  uint64_t addr = 0x12345a534040UL;
#else
  uint64_t addr = 0xf534040UL;
#endif
  dump_all_maps(&log_, unwinder_mock_.get(), addr);

  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 (3 entries): (fault address prefixed with --->)\n"
#if defined(__LP64__)
      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 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 bias 0xd000)\n"
      "    0a534000-0a534fff --x      3000      1000  (load bias 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, 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 = android::base::StringPrintf(
      "Build fingerprint: '%s'\nRevision: '%s'\n",
      android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
      android::base::GetProperty("ro.revision", "unknown").c_str());
  expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
  ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}

TEST_F(TombstoneTest, dump_thread_info_uid) {
  dump_thread_info(&log_, ThreadInfo{.uid = 1,
                                     .pid = 2,
                                     .tid = 3,
                                     .thread_name = "some_thread",
                                     .process_name = "some_process"});
  std::string expected = "pid: 2, tid: 3, name: some_thread  >>> some_process <<<\nuid: 1\n";
  ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}

TEST_F(TombstoneTest, dump_timestamp) {
  setenv("TZ", "UTC", 1);
  tzset();
  dump_timestamp(&log_, 0);
  ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
}

class MemoryPattern : public unwindstack::Memory {
 public:
  MemoryPattern() = default;
  virtual ~MemoryPattern() = default;

  size_t Read(uint64_t, void* dst, size_t size) override {
    uint8_t* data = reinterpret_cast<uint8_t*>(dst);
    for (size_t i = 0; i < size; i++) {
      data[i] = (i % 0xff);
    }
    return size;
  }
};

TEST_F(TombstoneTest, dump_stack_single_frame) {
  std::vector<unwindstack::FrameData> frames;
  unwindstack::Maps maps;
  MemoryPattern memory;

  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
  dump_stack(&log_, frames, &maps, &memory);

  std::string contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));

  std::string expected =
#if defined(__LP64__)
      "         0000000000001f80  0706050403020100\n"
      "         0000000000001f88  0f0e0d0c0b0a0908\n"
      "         0000000000001f90  1716151413121110\n"
      "         0000000000001f98  1f1e1d1c1b1a1918\n"
      "         0000000000001fa0  2726252423222120\n"
      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
      "         0000000000001fb0  3736353433323130\n"
      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
      "         0000000000001fc0  4746454443424140\n"
      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
      "         0000000000001fd0  5756555453525150\n"
      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
      "         0000000000001fe0  6766656463626160\n"
      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
      "         0000000000001ff0  7776757473727170\n"
      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
      "    #00  0000000000002000  0706050403020100\n"
      "         0000000000002008  0f0e0d0c0b0a0908\n"
      "         0000000000002010  1716151413121110\n"
      "         0000000000002018  1f1e1d1c1b1a1918\n"
      "         0000000000002020  2726252423222120\n"
      "         0000000000002028  2f2e2d2c2b2a2928\n"
      "         0000000000002030  3736353433323130\n"
      "         0000000000002038  3f3e3d3c3b3a3938\n"
      "         0000000000002040  4746454443424140\n"
      "         0000000000002048  4f4e4d4c4b4a4948\n"
      "         0000000000002050  5756555453525150\n"
      "         0000000000002058  5f5e5d5c5b5a5958\n"
      "         0000000000002060  6766656463626160\n"
      "         0000000000002068  6f6e6d6c6b6a6968\n"
      "         0000000000002070  7776757473727170\n"
      "         0000000000002078  7f7e7d7c7b7a7978\n";
#else
      "         00001fc0  03020100\n"
      "         00001fc4  07060504\n"
      "         00001fc8  0b0a0908\n"
      "         00001fcc  0f0e0d0c\n"
      "         00001fd0  13121110\n"
      "         00001fd4  17161514\n"
      "         00001fd8  1b1a1918\n"
      "         00001fdc  1f1e1d1c\n"
      "         00001fe0  23222120\n"
      "         00001fe4  27262524\n"
      "         00001fe8  2b2a2928\n"
      "         00001fec  2f2e2d2c\n"
      "         00001ff0  33323130\n"
      "         00001ff4  37363534\n"
      "         00001ff8  3b3a3938\n"
      "         00001ffc  3f3e3d3c\n"
      "    #00  00002000  03020100\n"
      "         00002004  07060504\n"
      "         00002008  0b0a0908\n"
      "         0000200c  0f0e0d0c\n"
      "         00002010  13121110\n"
      "         00002014  17161514\n"
      "         00002018  1b1a1918\n"
      "         0000201c  1f1e1d1c\n"
      "         00002020  23222120\n"
      "         00002024  27262524\n"
      "         00002028  2b2a2928\n"
      "         0000202c  2f2e2d2c\n"
      "         00002030  33323130\n"
      "         00002034  37363534\n"
      "         00002038  3b3a3938\n"
      "         0000203c  3f3e3d3c\n";
#endif
  EXPECT_EQ(expected, contents);
}

TEST_F(TombstoneTest, dump_stack_multiple_frames_same_sp) {
  std::vector<unwindstack::FrameData> frames;
  unwindstack::Maps maps;
  MemoryPattern memory;

  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2000});
  dump_stack(&log_, frames, &maps, &memory);

  std::string contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));

  std::string expected =
#if defined(__LP64__)
      "         0000000000001f80  0706050403020100\n"
      "         0000000000001f88  0f0e0d0c0b0a0908\n"
      "         0000000000001f90  1716151413121110\n"
      "         0000000000001f98  1f1e1d1c1b1a1918\n"
      "         0000000000001fa0  2726252423222120\n"
      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
      "         0000000000001fb0  3736353433323130\n"
      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
      "         0000000000001fc0  4746454443424140\n"
      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
      "         0000000000001fd0  5756555453525150\n"
      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
      "         0000000000001fe0  6766656463626160\n"
      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
      "         0000000000001ff0  7776757473727170\n"
      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
      "    #00  0000000000002000  0706050403020100\n"
      "         ................  ................\n"
      "    #01  0000000000002000  0706050403020100\n"
      "         0000000000002008  0f0e0d0c0b0a0908\n"
      "         0000000000002010  1716151413121110\n"
      "         0000000000002018  1f1e1d1c1b1a1918\n"
      "         0000000000002020  2726252423222120\n"
      "         0000000000002028  2f2e2d2c2b2a2928\n"
      "         0000000000002030  3736353433323130\n"
      "         0000000000002038  3f3e3d3c3b3a3938\n"
      "         0000000000002040  4746454443424140\n"
      "         0000000000002048  4f4e4d4c4b4a4948\n"
      "         0000000000002050  5756555453525150\n"
      "         0000000000002058  5f5e5d5c5b5a5958\n"
      "         0000000000002060  6766656463626160\n"
      "         0000000000002068  6f6e6d6c6b6a6968\n"
      "         0000000000002070  7776757473727170\n"
      "         0000000000002078  7f7e7d7c7b7a7978\n";
#else
      "         00001fc0  03020100\n"
      "         00001fc4  07060504\n"
      "         00001fc8  0b0a0908\n"
      "         00001fcc  0f0e0d0c\n"
      "         00001fd0  13121110\n"
      "         00001fd4  17161514\n"
      "         00001fd8  1b1a1918\n"
      "         00001fdc  1f1e1d1c\n"
      "         00001fe0  23222120\n"
      "         00001fe4  27262524\n"
      "         00001fe8  2b2a2928\n"
      "         00001fec  2f2e2d2c\n"
      "         00001ff0  33323130\n"
      "         00001ff4  37363534\n"
      "         00001ff8  3b3a3938\n"
      "         00001ffc  3f3e3d3c\n"
      "    #00  00002000  03020100\n"
      "         ........  ........\n"
      "    #01  00002000  03020100\n"
      "         00002004  07060504\n"
      "         00002008  0b0a0908\n"
      "         0000200c  0f0e0d0c\n"
      "         00002010  13121110\n"
      "         00002014  17161514\n"
      "         00002018  1b1a1918\n"
      "         0000201c  1f1e1d1c\n"
      "         00002020  23222120\n"
      "         00002024  27262524\n"
      "         00002028  2b2a2928\n"
      "         0000202c  2f2e2d2c\n"
      "         00002030  33323130\n"
      "         00002034  37363534\n"
      "         00002038  3b3a3938\n"
      "         0000203c  3f3e3d3c\n";
#endif
  EXPECT_EQ(expected, contents);
}

TEST_F(TombstoneTest, dump_stack_multiple_frames) {
  std::vector<unwindstack::FrameData> frames;
  unwindstack::Maps maps;
  MemoryPattern memory;

  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2100});
  dump_stack(&log_, frames, &maps, &memory);

  std::string contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));

  std::string expected =
#if defined(__LP64__)
      "         0000000000001f80  0706050403020100\n"
      "         0000000000001f88  0f0e0d0c0b0a0908\n"
      "         0000000000001f90  1716151413121110\n"
      "         0000000000001f98  1f1e1d1c1b1a1918\n"
      "         0000000000001fa0  2726252423222120\n"
      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
      "         0000000000001fb0  3736353433323130\n"
      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
      "         0000000000001fc0  4746454443424140\n"
      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
      "         0000000000001fd0  5756555453525150\n"
      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
      "         0000000000001fe0  6766656463626160\n"
      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
      "         0000000000001ff0  7776757473727170\n"
      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
      "    #00  0000000000002000  0706050403020100\n"
      "         0000000000002008  0f0e0d0c0b0a0908\n"
      "    #01  0000000000002010  0706050403020100\n"
      "         0000000000002018  0f0e0d0c0b0a0908\n"
      "         0000000000002020  1716151413121110\n"
      "         0000000000002028  1f1e1d1c1b1a1918\n"
      "         0000000000002030  2726252423222120\n"
      "         0000000000002038  2f2e2d2c2b2a2928\n"
      "         0000000000002040  3736353433323130\n"
      "         0000000000002048  3f3e3d3c3b3a3938\n"
      "         0000000000002050  4746454443424140\n"
      "         0000000000002058  4f4e4d4c4b4a4948\n"
      "         0000000000002060  5756555453525150\n"
      "         0000000000002068  5f5e5d5c5b5a5958\n"
      "         0000000000002070  6766656463626160\n"
      "         0000000000002078  6f6e6d6c6b6a6968\n"
      "         0000000000002080  7776757473727170\n"
      "         0000000000002088  7f7e7d7c7b7a7978\n"
      "         ................  ................\n"
      "    #02  0000000000002100  0706050403020100\n"
      "         0000000000002108  0f0e0d0c0b0a0908\n"
      "         0000000000002110  1716151413121110\n"
      "         0000000000002118  1f1e1d1c1b1a1918\n"
      "         0000000000002120  2726252423222120\n"
      "         0000000000002128  2f2e2d2c2b2a2928\n"
      "         0000000000002130  3736353433323130\n"
      "         0000000000002138  3f3e3d3c3b3a3938\n"
      "         0000000000002140  4746454443424140\n"
      "         0000000000002148  4f4e4d4c4b4a4948\n"
      "         0000000000002150  5756555453525150\n"
      "         0000000000002158  5f5e5d5c5b5a5958\n"
      "         0000000000002160  6766656463626160\n"
      "         0000000000002168  6f6e6d6c6b6a6968\n"
      "         0000000000002170  7776757473727170\n"
      "         0000000000002178  7f7e7d7c7b7a7978\n";
#else
      "         00001fc0  03020100\n"
      "         00001fc4  07060504\n"
      "         00001fc8  0b0a0908\n"
      "         00001fcc  0f0e0d0c\n"
      "         00001fd0  13121110\n"
      "         00001fd4  17161514\n"
      "         00001fd8  1b1a1918\n"
      "         00001fdc  1f1e1d1c\n"
      "         00001fe0  23222120\n"
      "         00001fe4  27262524\n"
      "         00001fe8  2b2a2928\n"
      "         00001fec  2f2e2d2c\n"
      "         00001ff0  33323130\n"
      "         00001ff4  37363534\n"
      "         00001ff8  3b3a3938\n"
      "         00001ffc  3f3e3d3c\n"
      "    #00  00002000  03020100\n"
      "         00002004  07060504\n"
      "         00002008  0b0a0908\n"
      "         0000200c  0f0e0d0c\n"
      "    #01  00002010  03020100\n"
      "         00002014  07060504\n"
      "         00002018  0b0a0908\n"
      "         0000201c  0f0e0d0c\n"
      "         00002020  13121110\n"
      "         00002024  17161514\n"
      "         00002028  1b1a1918\n"
      "         0000202c  1f1e1d1c\n"
      "         00002030  23222120\n"
      "         00002034  27262524\n"
      "         00002038  2b2a2928\n"
      "         0000203c  2f2e2d2c\n"
      "         00002040  33323130\n"
      "         00002044  37363534\n"
      "         00002048  3b3a3938\n"
      "         0000204c  3f3e3d3c\n"
      "         ........  ........\n"
      "    #02  00002100  03020100\n"
      "         00002104  07060504\n"
      "         00002108  0b0a0908\n"
      "         0000210c  0f0e0d0c\n"
      "         00002110  13121110\n"
      "         00002114  17161514\n"
      "         00002118  1b1a1918\n"
      "         0000211c  1f1e1d1c\n"
      "         00002120  23222120\n"
      "         00002124  27262524\n"
      "         00002128  2b2a2928\n"
      "         0000212c  2f2e2d2c\n"
      "         00002130  33323130\n"
      "         00002134  37363534\n"
      "         00002138  3b3a3938\n"
      "         0000213c  3f3e3d3c\n";
#endif
  EXPECT_EQ(expected, contents);
}

TEST_F(TombstoneTest, dump_stack_multiple_frames_disjoint_frames) {
  std::vector<unwindstack::FrameData> frames;
  unwindstack::Maps maps;
  MemoryPattern memory;

  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1000});
  frames.push_back(
      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1030});
  dump_stack(&log_, frames, &maps, &memory);

  std::string contents;
  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));

  std::string expected =
#if defined(__LP64__)
      "         0000000000001f80  0706050403020100\n"
      "         0000000000001f88  0f0e0d0c0b0a0908\n"
      "         0000000000001f90  1716151413121110\n"
      "         0000000000001f98  1f1e1d1c1b1a1918\n"
      "         0000000000001fa0  2726252423222120\n"
      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
      "         0000000000001fb0  3736353433323130\n"
      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
      "         0000000000001fc0  4746454443424140\n"
      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
      "         0000000000001fd0  5756555453525150\n"
      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
      "         0000000000001fe0  6766656463626160\n"
      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
      "         0000000000001ff0  7776757473727170\n"
      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
      "    #00  0000000000002000  0706050403020100\n"
      "         0000000000002008  0f0e0d0c0b0a0908\n"
      "    #01  0000000000002010  0706050403020100\n"
      "         0000000000002018  0f0e0d0c0b0a0908\n"
      "         0000000000002020  1716151413121110\n"
      "         0000000000002028  1f1e1d1c1b1a1918\n"
      "         0000000000002030  2726252423222120\n"
      "         0000000000002038  2f2e2d2c2b2a2928\n"
      "         0000000000002040  3736353433323130\n"
      "         0000000000002048  3f3e3d3c3b3a3938\n"
      "         0000000000002050  4746454443424140\n"
      "         0000000000002058  4f4e4d4c4b4a4948\n"
      "         0000000000002060  5756555453525150\n"
      "         0000000000002068  5f5e5d5c5b5a5958\n"
      "         0000000000002070  6766656463626160\n"
      "         0000000000002078  6f6e6d6c6b6a6968\n"
      "         0000000000002080  7776757473727170\n"
      "         0000000000002088  7f7e7d7c7b7a7978\n"
      "         ................  ................\n"
      "    #02  0000000000001000  0706050403020100\n"
      "         0000000000001008  0f0e0d0c0b0a0908\n"
      "         0000000000001010  1716151413121110\n"
      "         0000000000001018  1f1e1d1c1b1a1918\n"
      "         0000000000001020  2726252423222120\n"
      "         0000000000001028  2f2e2d2c2b2a2928\n"
      "    #03  0000000000001030  0706050403020100\n"
      "         0000000000001038  0f0e0d0c0b0a0908\n"
      "         0000000000001040  1716151413121110\n"
      "         0000000000001048  1f1e1d1c1b1a1918\n"
      "         0000000000001050  2726252423222120\n"
      "         0000000000001058  2f2e2d2c2b2a2928\n"
      "         0000000000001060  3736353433323130\n"
      "         0000000000001068  3f3e3d3c3b3a3938\n"
      "         0000000000001070  4746454443424140\n"
      "         0000000000001078  4f4e4d4c4b4a4948\n"
      "         0000000000001080  5756555453525150\n"
      "         0000000000001088  5f5e5d5c5b5a5958\n"
      "         0000000000001090  6766656463626160\n"
      "         0000000000001098  6f6e6d6c6b6a6968\n"
      "         00000000000010a0  7776757473727170\n"
      "         00000000000010a8  7f7e7d7c7b7a7978\n";
#else
      "         00001fc0  03020100\n"
      "         00001fc4  07060504\n"
      "         00001fc8  0b0a0908\n"
      "         00001fcc  0f0e0d0c\n"
      "         00001fd0  13121110\n"
      "         00001fd4  17161514\n"
      "         00001fd8  1b1a1918\n"
      "         00001fdc  1f1e1d1c\n"
      "         00001fe0  23222120\n"
      "         00001fe4  27262524\n"
      "         00001fe8  2b2a2928\n"
      "         00001fec  2f2e2d2c\n"
      "         00001ff0  33323130\n"
      "         00001ff4  37363534\n"
      "         00001ff8  3b3a3938\n"
      "         00001ffc  3f3e3d3c\n"
      "    #00  00002000  03020100\n"
      "         00002004  07060504\n"
      "         00002008  0b0a0908\n"
      "         0000200c  0f0e0d0c\n"
      "    #01  00002010  03020100\n"
      "         00002014  07060504\n"
      "         00002018  0b0a0908\n"
      "         0000201c  0f0e0d0c\n"
      "         00002020  13121110\n"
      "         00002024  17161514\n"
      "         00002028  1b1a1918\n"
      "         0000202c  1f1e1d1c\n"
      "         00002030  23222120\n"
      "         00002034  27262524\n"
      "         00002038  2b2a2928\n"
      "         0000203c  2f2e2d2c\n"
      "         00002040  33323130\n"
      "         00002044  37363534\n"
      "         00002048  3b3a3938\n"
      "         0000204c  3f3e3d3c\n"
      "         ........  ........\n"
      "    #02  00001000  03020100\n"
      "         00001004  07060504\n"
      "         00001008  0b0a0908\n"
      "         0000100c  0f0e0d0c\n"
      "         00001010  13121110\n"
      "         00001014  17161514\n"
      "         00001018  1b1a1918\n"
      "         0000101c  1f1e1d1c\n"
      "         00001020  23222120\n"
      "         00001024  27262524\n"
      "         00001028  2b2a2928\n"
      "         0000102c  2f2e2d2c\n"
      "    #03  00001030  03020100\n"
      "         00001034  07060504\n"
      "         00001038  0b0a0908\n"
      "         0000103c  0f0e0d0c\n"
      "         00001040  13121110\n"
      "         00001044  17161514\n"
      "         00001048  1b1a1918\n"
      "         0000104c  1f1e1d1c\n"
      "         00001050  23222120\n"
      "         00001054  27262524\n"
      "         00001058  2b2a2928\n"
      "         0000105c  2f2e2d2c\n"
      "         00001060  33323130\n"
      "         00001064  37363534\n"
      "         00001068  3b3a3938\n"
      "         0000106c  3f3e3d3c\n";
#endif
  EXPECT_EQ(expected, contents);
}