brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.1 KiB · 131a3ca Raw
437 lines · cpp
1//===-- MemoryTest.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/Memory.h"10#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"11#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"12#include "lldb/Core/Debugger.h"13#include "lldb/Host/FileSystem.h"14#include "lldb/Host/HostInfo.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/ArchSpec.h"18#include "lldb/Utility/DataBufferHeap.h"19#include "gtest/gtest.h"20#include <cstdint>21 22using namespace lldb_private;23using namespace lldb;24 25namespace {26class MemoryTest : public ::testing::Test {27public:28  void SetUp() override {29    FileSystem::Initialize();30    HostInfo::Initialize();31    PlatformMacOSX::Initialize();32  }33  void TearDown() override {34    PlatformMacOSX::Terminate();35    HostInfo::Terminate();36    FileSystem::Terminate();37  }38};39 40class DummyProcess : public Process {41public:42  DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)43      : Process(target_sp, listener_sp), m_bytes_left(0) {}44 45  // Required overrides46  bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {47    return true;48  }49  Status DoDestroy() override { return {}; }50  void RefreshStateAfterStop() override {}51  // Required by Target::ReadMemory() to call Process::ReadMemory()52  bool IsAlive() override { return true; }53  size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,54                      Status &error) override {55    if (m_bytes_left == 0)56      return 0;57 58    size_t num_bytes_to_write = size;59    if (m_bytes_left < size) {60      num_bytes_to_write = m_bytes_left;61      m_bytes_left = 0;62    } else {63      m_bytes_left -= size;64    }65 66    memset(buf, m_filler, num_bytes_to_write);67    return num_bytes_to_write;68  }69  bool DoUpdateThreadList(ThreadList &old_thread_list,70                          ThreadList &new_thread_list) override {71    return false;72  }73  llvm::StringRef GetPluginName() override { return "Dummy"; }74 75  // Test-specific additions76  size_t m_bytes_left;77  int m_filler = 'B';78  MemoryCache &GetMemoryCache() { return m_memory_cache; }79  void SetMaxReadSize(size_t size) { m_bytes_left = size; }80  void SetFiller(int filler) { m_filler = filler; }81};82} // namespace83 84TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {85  PlatformSP platform_sp;86  TargetSP target_sp;87  debugger_sp->GetTargetList().CreateTarget(88      *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);89  return target_sp;90}91 92static ProcessSP CreateProcess(lldb::TargetSP target_sp) {93  ListenerSP listener_sp(Listener::MakeListener("dummy"));94  ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);95 96  struct TargetHack : public Target {97    void SetProcess(ProcessSP process) { m_process_sp = process; }98  };99  static_cast<TargetHack *>(target_sp.get())->SetProcess(process_sp);100 101  return process_sp;102}103 104TEST_F(MemoryTest, TesetMemoryCacheRead) {105  ArchSpec arch("x86_64-apple-macosx-");106 107  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));108 109  DebuggerSP debugger_sp = Debugger::CreateInstance();110  ASSERT_TRUE(debugger_sp);111 112  TargetSP target_sp = CreateTarget(debugger_sp, arch);113  ASSERT_TRUE(target_sp);114 115  ProcessSP process_sp = CreateProcess(target_sp);116  ASSERT_TRUE(process_sp);117 118  DummyProcess *process = static_cast<DummyProcess *>(process_sp.get());119  MemoryCache &mem_cache = process->GetMemoryCache();120  const uint64_t l2_cache_size = process->GetMemoryCacheLineSize();121  Status error;122  auto data_sp = std::make_shared<DataBufferHeap>(l2_cache_size * 2, '\0');123  size_t bytes_read = 0;124 125  // Cache empty, memory read fails, size > l2 cache size126  process->SetMaxReadSize(0);127  bytes_read = mem_cache.Read(0x1000, data_sp->GetBytes(),128                              data_sp->GetByteSize(), error);129  ASSERT_TRUE(bytes_read == 0);130 131  // Cache empty, memory read fails, size <= l2 cache size132  data_sp->SetByteSize(l2_cache_size);133  bytes_read = mem_cache.Read(0x1000, data_sp->GetBytes(),134                              data_sp->GetByteSize(), error);135  ASSERT_TRUE(bytes_read == 0);136 137  // Cache empty, memory read succeeds, size > l2 cache size138  process->SetMaxReadSize(l2_cache_size * 4);139  data_sp->SetByteSize(l2_cache_size * 2);140  bytes_read = mem_cache.Read(0x1000, data_sp->GetBytes(),141                              data_sp->GetByteSize(), error);142  ASSERT_TRUE(bytes_read == data_sp->GetByteSize());143  ASSERT_TRUE(process->m_bytes_left == l2_cache_size * 2);144 145  // Reading data previously cached (not in L2 cache).146  data_sp->SetByteSize(l2_cache_size + 1);147  bytes_read = mem_cache.Read(0x1000, data_sp->GetBytes(),148                              data_sp->GetByteSize(), error);149  ASSERT_TRUE(bytes_read == data_sp->GetByteSize());150  ASSERT_TRUE(process->m_bytes_left == l2_cache_size * 2); // Verify we didn't151                                                           // read from the152                                                           // inferior.153 154  // Read from a different address, but make the size == l2 cache size.155  // This should fill in a the L2 cache.156  data_sp->SetByteSize(l2_cache_size);157  bytes_read = mem_cache.Read(0x2000, data_sp->GetBytes(),158                              data_sp->GetByteSize(), error);159  ASSERT_TRUE(bytes_read == data_sp->GetByteSize());160  ASSERT_TRUE(process->m_bytes_left == l2_cache_size);161 162  // Read from that L2 cache entry but read less than size of the cache line.163  // Additionally, read from an offset.164  data_sp->SetByteSize(l2_cache_size - 5);165  bytes_read = mem_cache.Read(0x2001, data_sp->GetBytes(),166                              data_sp->GetByteSize(), error);167  ASSERT_TRUE(bytes_read == data_sp->GetByteSize());168  ASSERT_TRUE(process->m_bytes_left == l2_cache_size); // Verify we didn't read169                                                       // from the inferior.170 171  // What happens if we try to populate an L2 cache line but the read gives less172  // than the size of a cache line?173  process->SetMaxReadSize(l2_cache_size - 10);174  data_sp->SetByteSize(l2_cache_size - 5);175  bytes_read = mem_cache.Read(0x3000, data_sp->GetBytes(),176                              data_sp->GetByteSize(), error);177  ASSERT_TRUE(bytes_read == l2_cache_size - 10);178  ASSERT_TRUE(process->m_bytes_left == 0);179 180  // What happens if we have a partial L2 cache line filled in and we try to181  // read the part that isn't filled in?182  data_sp->SetByteSize(10);183  bytes_read = mem_cache.Read(0x3000 + l2_cache_size - 10, data_sp->GetBytes(),184                              data_sp->GetByteSize(), error);185  ASSERT_TRUE(bytes_read == 0); // The last 10 bytes from this line are186                                // missing and we should be reading nothing187                                // here.188 189  // What happens when we try to straddle 2 cache lines?190  process->SetMaxReadSize(l2_cache_size * 2);191  data_sp->SetByteSize(l2_cache_size);192  bytes_read = mem_cache.Read(0x4001, data_sp->GetBytes(),193                              data_sp->GetByteSize(), error);194  ASSERT_TRUE(bytes_read == l2_cache_size);195  ASSERT_TRUE(process->m_bytes_left == 0);196 197  // What happens when we try to straddle 2 cache lines where the first one is198  // only partially filled?199  process->SetMaxReadSize(l2_cache_size - 1);200  data_sp->SetByteSize(l2_cache_size);201  bytes_read = mem_cache.Read(0x5005, data_sp->GetBytes(),202                              data_sp->GetByteSize(), error);203  ASSERT_TRUE(bytes_read == l2_cache_size - 6); // Ignoring the first 5 bytes,204                                                // missing the last byte205  ASSERT_TRUE(process->m_bytes_left == 0);206 207  // What happens if we add an invalid range and try to do a read larger than208  // a cache line?209  mem_cache.AddInvalidRange(0x6000, l2_cache_size * 2);210  process->SetMaxReadSize(l2_cache_size * 2);211  data_sp->SetByteSize(l2_cache_size * 2);212  bytes_read = mem_cache.Read(0x6000, data_sp->GetBytes(),213                              data_sp->GetByteSize(), error);214  ASSERT_TRUE(bytes_read == 0);215  ASSERT_TRUE(process->m_bytes_left == l2_cache_size * 2);216 217  // What happens if we add an invalid range and try to do a read lt/eq a218  // cache line?219  mem_cache.AddInvalidRange(0x7000, l2_cache_size);220  process->SetMaxReadSize(l2_cache_size);221  data_sp->SetByteSize(l2_cache_size);222  bytes_read = mem_cache.Read(0x7000, data_sp->GetBytes(),223                              data_sp->GetByteSize(), error);224  ASSERT_TRUE(bytes_read == 0);225  ASSERT_TRUE(process->m_bytes_left == l2_cache_size);226 227  // What happens if we remove the invalid range and read again?228  mem_cache.RemoveInvalidRange(0x7000, l2_cache_size);229  bytes_read = mem_cache.Read(0x7000, data_sp->GetBytes(),230                              data_sp->GetByteSize(), error);231  ASSERT_TRUE(bytes_read == l2_cache_size);232  ASSERT_TRUE(process->m_bytes_left == 0);233 234  // What happens if we flush and read again?235  process->SetMaxReadSize(l2_cache_size * 2);236  mem_cache.Flush(0x7000, l2_cache_size);237  bytes_read = mem_cache.Read(0x7000, data_sp->GetBytes(),238                              data_sp->GetByteSize(), error);239  ASSERT_TRUE(bytes_read == l2_cache_size);240  ASSERT_TRUE(process->m_bytes_left == l2_cache_size); // Verify that we re-read241                                                       // instead of using an242                                                       // old cache243}244 245TEST_F(MemoryTest, TestReadInteger) {246  ArchSpec arch("x86_64-apple-macosx-");247 248  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));249 250  DebuggerSP debugger_sp = Debugger::CreateInstance();251  ASSERT_TRUE(debugger_sp);252 253  TargetSP target_sp = CreateTarget(debugger_sp, arch);254  ASSERT_TRUE(target_sp);255 256  ProcessSP process_sp = CreateProcess(target_sp);257  ASSERT_TRUE(process_sp);258 259  DummyProcess *process = static_cast<DummyProcess *>(process_sp.get());260  Status error;261 262  process->SetFiller(0xff);263  process->SetMaxReadSize(256);264  // The ReadSignedIntegerFromMemory() methods return int64_t. Check that they265  // extend the sign correctly when reading 32-bit values.266  EXPECT_EQ(-1,267            target_sp->ReadSignedIntegerFromMemory(Address(0), 4, 0, error));268  EXPECT_EQ(-1, process->ReadSignedIntegerFromMemory(0, 4, 0, error));269  // Check reading 64-bit values as well.270  EXPECT_EQ(-1,271            target_sp->ReadSignedIntegerFromMemory(Address(0), 8, 0, error));272  EXPECT_EQ(-1, process->ReadSignedIntegerFromMemory(0, 8, 0, error));273 274  // ReadUnsignedIntegerFromMemory() should not extend the sign.275  EXPECT_EQ(0xffffffffULL,276            target_sp->ReadUnsignedIntegerFromMemory(Address(0), 4, 0, error));277  EXPECT_EQ(0xffffffffULL,278            process->ReadUnsignedIntegerFromMemory(0, 4, 0, error));279  EXPECT_EQ(0xffffffffffffffffULL,280            target_sp->ReadUnsignedIntegerFromMemory(Address(0), 8, 0, error));281  EXPECT_EQ(0xffffffffffffffffULL,282            process->ReadUnsignedIntegerFromMemory(0, 8, 0, error));283 284  // Check reading positive values.285  process->GetMemoryCache().Clear();286  process->SetFiller(0x7f);287  process->SetMaxReadSize(256);288  EXPECT_EQ(0x7f7f7f7fLL,289            target_sp->ReadSignedIntegerFromMemory(Address(0), 4, 0, error));290  EXPECT_EQ(0x7f7f7f7fLL, process->ReadSignedIntegerFromMemory(0, 4, 0, error));291  EXPECT_EQ(0x7f7f7f7f7f7f7f7fLL,292            target_sp->ReadSignedIntegerFromMemory(Address(0), 8, 0, error));293  EXPECT_EQ(0x7f7f7f7f7f7f7f7fLL,294            process->ReadSignedIntegerFromMemory(0, 8, 0, error));295}296 297/// A process class that, when asked to read memory from some address X, returns298/// the least significant byte of X.299class DummyReaderProcess : public Process {300public:301  // If true, `DoReadMemory` will not return all requested bytes.302  // It's not possible to control exactly how many bytes will be read, because303  // Process::ReadMemoryFromInferior tries to fulfill the entire request by304  // reading smaller chunks until it gets nothing back.305  bool read_less_than_requested = false;306  bool read_more_than_requested = false;307 308  size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,309                      Status &error) override {310    if (read_less_than_requested && size > 0)311      size--;312    if (read_more_than_requested)313      size *= 2;314    uint8_t *buffer = static_cast<uint8_t *>(buf);315    for (lldb::addr_t addr = vm_addr; addr < vm_addr + size; addr++)316      buffer[addr - vm_addr] = static_cast<uint8_t>(addr); // LSB of addr.317    return size;318  }319  // Boilerplate, nothing interesting below.320  DummyReaderProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)321      : Process(target_sp, listener_sp) {}322  bool CanDebug(lldb::TargetSP, bool) override { return true; }323  Status DoDestroy() override { return {}; }324  void RefreshStateAfterStop() override {}325  bool DoUpdateThreadList(ThreadList &, ThreadList &) override { return false; }326  llvm::StringRef GetPluginName() override { return "Dummy"; }327};328 329TEST_F(MemoryTest, TestReadMemoryRanges) {330  ArchSpec arch("x86_64-apple-macosx-");331 332  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));333 334  DebuggerSP debugger_sp = Debugger::CreateInstance();335  ASSERT_TRUE(debugger_sp);336 337  TargetSP target_sp = CreateTarget(debugger_sp, arch);338  ASSERT_TRUE(target_sp);339 340  ListenerSP listener_sp(Listener::MakeListener("dummy"));341  ProcessSP process_sp =342      std::make_shared<DummyReaderProcess>(target_sp, listener_sp);343  ASSERT_TRUE(process_sp);344 345  {346    llvm::SmallVector<uint8_t, 0> buffer(1024, 0);347    // Read 8 ranges of 128 bytes with arbitrary base addresses.348    llvm::SmallVector<Range<addr_t, size_t>> ranges = {349        {0x12345, 128},      {0x11112222, 128}, {0x77777777, 128},350        {0xffaabbccdd, 128}, {0x0, 128},        {0x4242424242, 128},351        {0x17171717, 128},   {0x99999, 128}};352 353    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results =354        process_sp->ReadMemoryRanges(ranges, buffer);355 356    for (auto [range, memory] : llvm::zip(ranges, read_results)) {357      ASSERT_EQ(memory.size(), 128u);358      addr_t range_base = range.GetRangeBase();359      for (auto [idx, byte] : llvm::enumerate(memory))360        ASSERT_EQ(byte, static_cast<uint8_t>(range_base + idx));361    }362  }363 364  auto &dummy_process = static_cast<DummyReaderProcess &>(*process_sp);365  dummy_process.read_less_than_requested = true;366  {367    llvm::SmallVector<uint8_t, 0> buffer(1024, 0);368    llvm::SmallVector<Range<addr_t, size_t>> ranges = {369        {0x12345, 128}, {0x11112222, 128}, {0x77777777, 128}};370    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results =371        dummy_process.ReadMemoryRanges(ranges, buffer);372    for (auto [range, memory] : llvm::zip(ranges, read_results)) {373      ASSERT_LT(memory.size(), 128u);374      addr_t range_base = range.GetRangeBase();375      for (auto [idx, byte] : llvm::enumerate(memory))376        ASSERT_EQ(byte, static_cast<uint8_t>(range_base + idx));377    }378  }379}380 381using MemoryDeathTest = MemoryTest;382 383TEST_F(MemoryDeathTest, TestReadMemoryRangesReturnsTooMuch) {384  ArchSpec arch("x86_64-apple-macosx-");385  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));386  DebuggerSP debugger_sp = Debugger::CreateInstance();387  ASSERT_TRUE(debugger_sp);388  TargetSP target_sp = CreateTarget(debugger_sp, arch);389  ASSERT_TRUE(target_sp);390  ListenerSP listener_sp(Listener::MakeListener("dummy"));391  ProcessSP process_sp =392      std::make_shared<DummyReaderProcess>(target_sp, listener_sp);393  ASSERT_TRUE(process_sp);394 395  auto &dummy_process = static_cast<DummyReaderProcess &>(*process_sp);396  dummy_process.read_more_than_requested = true;397  llvm::SmallVector<uint8_t, 0> buffer(1024, 0);398  llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0x12345, 128}};399 400  llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results;401  ASSERT_DEBUG_DEATH(402      { read_results = process_sp->ReadMemoryRanges(ranges, buffer); },403      "read more than requested bytes");404#ifdef NDEBUG405  // With asserts off, the read should return empty ranges.406  ASSERT_EQ(read_results.size(), 1u);407  ASSERT_TRUE(read_results[0].empty());408#endif409}410 411TEST_F(MemoryDeathTest, TestReadMemoryRangesWithShortBuffer) {412  ArchSpec arch("x86_64-apple-macosx-");413  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));414  DebuggerSP debugger_sp = Debugger::CreateInstance();415  ASSERT_TRUE(debugger_sp);416  TargetSP target_sp = CreateTarget(debugger_sp, arch);417  ASSERT_TRUE(target_sp);418  ListenerSP listener_sp(Listener::MakeListener("dummy"));419  ProcessSP process_sp =420      std::make_shared<DummyReaderProcess>(target_sp, listener_sp);421  ASSERT_TRUE(process_sp);422 423  llvm::SmallVector<uint8_t, 0> short_buffer(10, 0);424  llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0x12345, 128},425                                                     {0x11, 128}};426  llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results;427  ASSERT_DEBUG_DEATH(428      { read_results = process_sp->ReadMemoryRanges(ranges, short_buffer); },429      "provided buffer is too short");430#ifdef NDEBUG431  // With asserts off, the read should return empty ranges.432  ASSERT_EQ(read_results.size(), ranges.size());433  for (llvm::MutableArrayRef<uint8_t> result : read_results)434    ASSERT_TRUE(result.empty());435#endif436}437