/*
 * 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 <android-base/file.h>
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>

#include "libdebuggerd/utility.h"

#include "log_fake.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 MemoryMock : public unwindstack::Memory {
 public:
  virtual ~MemoryMock() = default;

  virtual size_t Read(uint64_t addr, void* buffer, size_t bytes) override {
    size_t offset = 0;
    if (last_read_addr_ > 0) {
      offset = addr - last_read_addr_;
    }
    size_t bytes_available = buffer_.size() - offset;

    if (partial_read_) {
      bytes = std::min(bytes, bytes_partial_read_);
      bytes_partial_read_ -= bytes;
      partial_read_ = bytes_partial_read_;
    } 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;
    last_read_addr_ = 0;
  }

  void SetPartialReadAmount(size_t bytes) {
    if (bytes > buffer_.size()) {
      abort();
    }
    partial_read_ = true;
    bytes_partial_read_ = bytes;
  }

 private:
  std::vector<uint8_t> buffer_;
  bool partial_read_ = false;
  size_t bytes_partial_read_ = 0;
  uintptr_t last_read_addr_ = 0;
};

class DumpMemoryTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    memory_mock_ = std::make_unique<MemoryMock>();

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

  std::unique_ptr<MemoryMock> memory_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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));

  dump_memory(&log_, memory_mock_.get(), 0x12345678, "memory near 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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));
  memory_mock_->SetPartialReadAmount(96);

  dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near 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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));

  dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near 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_, memory_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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));

  dump_memory(&log_, memory_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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));
  memory_mock_->SetPartialReadAmount(102);

  dump_memory(&log_, memory_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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));
  memory_mock_->SetPartialReadAmount(45);

  dump_memory(&log_, memory_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));
  memory_mock_->SetReadData(buffer, sizeof(buffer));

  dump_memory(&log_, memory_mock_.get(), 0x1000, "memory near 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));
  memory_mock_->SetReadData(buffer, sizeof(buffer));

  dump_memory(&log_, memory_mock_.get(), 0, "memory near 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));
  memory_mock_->SetReadData(buffer, sizeof(buffer));

#if defined(__LP64__)
  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL, "memory near r1");
  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 32, "memory near r1");
  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 216, "memory near r1");
#else
  dump_memory(&log_, memory_mock_.get(), 0xffff0000, "memory near r1");
  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 32, "memory near r1");
  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 220, "memory near 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));
  memory_mock_->SetReadData(buffer, sizeof(buffer));

#if defined(__LP64__)
  dump_memory(&log_, memory_mock_.get(), 0xfffffffffffffff0, "memory near r1");
#else
  dump_memory(&log_, memory_mock_.get(), 0xfffffff0, "memory near 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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));

#if defined(__LP64__)
  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 224, "memory near r4");
#else
  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 224, "memory near 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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));
  memory_mock_->SetPartialReadAmount(0);

  size_t page_size = sysconf(_SC_PAGE_SIZE);
  uintptr_t addr = 0x10000020 + page_size - 120;
  dump_memory(&log_, memory_mock_.get(), addr, "memory near 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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));
  memory_mock_->SetPartialReadAmount(0);

  size_t page_size = sysconf(_SC_PAGE_SIZE);
  uintptr_t addr = 0x10000020 + page_size - 192;
  dump_memory(&log_, memory_mock_.get(), addr, "memory near 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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));
  memory_mock_->SetPartialReadAmount(0);

  uintptr_t addr = 0x10000020;
  dump_memory(&log_, memory_mock_.get(), addr, "memory near 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;
  }
  memory_mock_->SetReadData(buffer, sizeof(buffer));
  memory_mock_->SetPartialReadAmount(0);

  size_t page_size = sysconf(_SC_PAGE_SIZE);
  uintptr_t addr = 0x10000020 + page_size - 256;

  dump_memory(&log_, memory_mock_.get(), addr, "memory near 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());
}
