blob: 8263a209b88b31b624cad0e22548baade9b5bd2f [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/client/minidump_memory.h"
#include <string.h>
#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include "lib/syslog/cpp/macros.h"
#include "src/developer/debug/unwinder/error.h"
namespace zxdb {
namespace {
class MockMemoryRegion : public MinidumpMemory::Region {
public:
MockMemoryRegion(uint64_t load_address, std::vector<uint8_t> data)
: load_address_(load_address), data_(std::move(data)) {}
unwinder::Error ReadBytes(uint64_t addr, uint64_t size, void* dst) override {
FX_CHECK(addr >= load_address_);
FX_CHECK(addr + size <= load_address_ + data_.size());
memcpy(dst, data_.data() + (addr - load_address_), size);
return unwinder::Success();
}
private:
uint64_t load_address_;
std::vector<uint8_t> data_;
};
TEST(MinidumpMemory, ReadMemoryBlocks) {
MinidumpMemory memory({
{0x1000, 0x1100,
std::make_shared<MockMemoryRegion>(0x1000, std::vector<uint8_t>(0x100, 0xCC))},
{0x2000, 0x2100,
std::make_shared<MockMemoryRegion>(0x2000, std::vector<uint8_t>(0x100, 0xCC))},
});
// Read empty.
auto res = memory.ReadMemoryBlocks(0x1000, 0);
ASSERT_EQ(0u, res.size());
res = memory.ReadMemoryBlocks(0x0200, 0);
ASSERT_EQ(0u, res.size());
// Read valid region.
res = memory.ReadMemoryBlocks(0x1000, 0x10);
ASSERT_EQ(1u, res.size());
ASSERT_EQ(0x1000u, res[0].address);
ASSERT_EQ(0x10u, res[0].size);
ASSERT_EQ(true, res[0].valid);
ASSERT_EQ(0x10u, res[0].data.size());
// Read invalid region.
res = memory.ReadMemoryBlocks(0x0200, 0x10);
ASSERT_EQ(1u, res.size());
ASSERT_EQ(0x0200u, res[0].address);
ASSERT_EQ(0x10u, res[0].size);
ASSERT_EQ(false, res[0].valid);
ASSERT_EQ(0u, res[0].data.size());
// Read invalid region.
res = memory.ReadMemoryBlocks(0x0200, 0x10);
ASSERT_EQ(1u, res.size());
ASSERT_EQ(0x0200u, res[0].address);
ASSERT_EQ(0x10u, res[0].size);
ASSERT_EQ(false, res[0].valid);
ASSERT_EQ(0u, res[0].data.size());
// Read invalid region + valid region.
res = memory.ReadMemoryBlocks(0x0FF0, 0x20);
ASSERT_EQ(2u, res.size());
ASSERT_EQ(0x0FF0u, res[0].address);
ASSERT_EQ(0x10u, res[0].size);
ASSERT_EQ(false, res[0].valid);
ASSERT_EQ(0x1000u, res[1].address);
ASSERT_EQ(0x10u, res[1].size);
ASSERT_EQ(true, res[1].valid);
// Read one valid region + one invalid region.
res = memory.ReadMemoryBlocks(0x10F0, 0x20);
ASSERT_EQ(2u, res.size());
ASSERT_EQ(0x10F0u, res[0].address);
ASSERT_EQ(0x10u, res[0].size);
ASSERT_EQ(true, res[0].valid);
ASSERT_EQ(0x1100u, res[1].address);
ASSERT_EQ(0x10u, res[1].size);
ASSERT_EQ(false, res[1].valid);
// Read invalid region + valid region + invalid region.
res = memory.ReadMemoryBlocks(0x1FF0, 0x120);
ASSERT_EQ(3u, res.size());
ASSERT_EQ(0x1FF0u, res[0].address);
ASSERT_EQ(0x10u, res[0].size);
ASSERT_EQ(false, res[0].valid);
ASSERT_EQ(0x2000u, res[1].address);
ASSERT_EQ(0x100u, res[1].size);
ASSERT_EQ(true, res[1].valid);
ASSERT_EQ(0x2100u, res[2].address);
ASSERT_EQ(0x10u, res[2].size);
ASSERT_EQ(false, res[2].valid);
// Read valid region + invalid region + valid region.
res = memory.ReadMemoryBlocks(0x1000, 0x1100);
ASSERT_EQ(3u, res.size());
ASSERT_EQ(0x1000u, res[0].address);
ASSERT_EQ(0x100u, res[0].size);
ASSERT_EQ(true, res[0].valid);
ASSERT_EQ(0x1100u, res[1].address);
ASSERT_EQ(0xF00u, res[1].size);
ASSERT_EQ(false, res[1].valid);
ASSERT_EQ(0x2000u, res[2].address);
ASSERT_EQ(0x100u, res[2].size);
ASSERT_EQ(true, res[2].valid);
}
} // namespace
} // namespace zxdb