| 
17 | 17 | #include "lldb/Utility/ArchSpec.h"  | 
18 | 18 | #include "lldb/Utility/DataBufferHeap.h"  | 
19 | 19 | #include "gtest/gtest.h"  | 
 | 20 | +#include <cstdint>  | 
20 | 21 | 
 
  | 
21 | 22 | using namespace lldb_private;  | 
22 | 23 | using namespace lldb;  | 
@@ -225,3 +226,144 @@ TEST_F(MemoryTest, TesetMemoryCacheRead) {  | 
225 | 226 |                                                        // instead of using an  | 
226 | 227 |                                                        // old cache  | 
227 | 228 | }  | 
 | 229 | + | 
 | 230 | +/// A process class that, when asked to read memory from some address X, returns  | 
 | 231 | +/// the least significant byte of X.  | 
 | 232 | +class DummyReaderProcess : public Process {  | 
 | 233 | +public:  | 
 | 234 | +  // If true, `DoReadMemory` will not return all requested bytes.  | 
 | 235 | +  // It's not possible to control exactly how many bytes will be read, because  | 
 | 236 | +  // Process::ReadMemoryFromInferior tries to fulfill the entire request by  | 
 | 237 | +  // reading smaller chunks until it gets nothing back.  | 
 | 238 | +  bool read_less_than_requested = false;  | 
 | 239 | +  bool read_more_than_requested = false;  | 
 | 240 | + | 
 | 241 | +  size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,  | 
 | 242 | +                      Status &error) override {  | 
 | 243 | +    if (read_less_than_requested && size > 0)  | 
 | 244 | +      size--;  | 
 | 245 | +    if (read_more_than_requested)  | 
 | 246 | +      size *= 2;  | 
 | 247 | +    uint8_t *buffer = static_cast<uint8_t *>(buf);  | 
 | 248 | +    for (size_t addr = vm_addr; addr < vm_addr + size; addr++)  | 
 | 249 | +      buffer[addr - vm_addr] = static_cast<uint8_t>(addr); // LSB of addr.  | 
 | 250 | +    return size;  | 
 | 251 | +  }  | 
 | 252 | +  // Boilerplate, nothing interesting below.  | 
 | 253 | +  DummyReaderProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)  | 
 | 254 | +      : Process(target_sp, listener_sp) {}  | 
 | 255 | +  bool CanDebug(lldb::TargetSP, bool) override { return true; }  | 
 | 256 | +  Status DoDestroy() override { return {}; }  | 
 | 257 | +  void RefreshStateAfterStop() override {}  | 
 | 258 | +  bool DoUpdateThreadList(ThreadList &, ThreadList &) override { return false; }  | 
 | 259 | +  llvm::StringRef GetPluginName() override { return "Dummy"; }  | 
 | 260 | +};  | 
 | 261 | + | 
 | 262 | +TEST_F(MemoryTest, TestReadMemoryRanges) {  | 
 | 263 | +  ArchSpec arch("x86_64-apple-macosx-");  | 
 | 264 | + | 
 | 265 | +  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));  | 
 | 266 | + | 
 | 267 | +  DebuggerSP debugger_sp = Debugger::CreateInstance();  | 
 | 268 | +  ASSERT_TRUE(debugger_sp);  | 
 | 269 | + | 
 | 270 | +  TargetSP target_sp = CreateTarget(debugger_sp, arch);  | 
 | 271 | +  ASSERT_TRUE(target_sp);  | 
 | 272 | + | 
 | 273 | +  ListenerSP listener_sp(Listener::MakeListener("dummy"));  | 
 | 274 | +  ProcessSP process_sp =  | 
 | 275 | +      std::make_shared<DummyReaderProcess>(target_sp, listener_sp);  | 
 | 276 | +  ASSERT_TRUE(process_sp);  | 
 | 277 | + | 
 | 278 | +  {  | 
 | 279 | +    llvm::SmallVector<uint8_t, 0> buffer(1024, 0);  | 
 | 280 | +    // Read 8 ranges of 128 bytes with arbitrary base addresses.  | 
 | 281 | +    llvm::SmallVector<Range<addr_t, size_t>> ranges = {  | 
 | 282 | +        {0x12345, 128},      {0x11112222, 128}, {0x77777777, 128},  | 
 | 283 | +        {0xffaabbccdd, 128}, {0x0, 128},        {0x4242424242, 128},  | 
 | 284 | +        {0x17171717, 128},   {0x99999, 128}};  | 
 | 285 | + | 
 | 286 | +    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results =  | 
 | 287 | +        process_sp->ReadMemoryRanges(ranges, buffer);  | 
 | 288 | + | 
 | 289 | +    for (auto [range, memory] : llvm::zip(ranges, read_results)) {  | 
 | 290 | +      ASSERT_EQ(memory.size(), 128u);  | 
 | 291 | +      addr_t range_base = range.GetRangeBase();  | 
 | 292 | +      for (auto [idx, byte] : llvm::enumerate(memory))  | 
 | 293 | +        ASSERT_EQ(byte, static_cast<uint8_t>(range_base + idx));  | 
 | 294 | +    }  | 
 | 295 | +  }  | 
 | 296 | + | 
 | 297 | +  auto &dummy_process = static_cast<DummyReaderProcess &>(*process_sp);  | 
 | 298 | +  dummy_process.read_less_than_requested = true;  | 
 | 299 | +  {  | 
 | 300 | +    llvm::SmallVector<uint8_t, 0> buffer(1024, 0);  | 
 | 301 | +    llvm::SmallVector<Range<addr_t, size_t>> ranges = {  | 
 | 302 | +        {0x12345, 128}, {0x11112222, 128}, {0x77777777, 128}};  | 
 | 303 | +    llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results =  | 
 | 304 | +        dummy_process.ReadMemoryRanges(ranges, buffer);  | 
 | 305 | +    for (auto [range, memory] : llvm::zip(ranges, read_results)) {  | 
 | 306 | +      ASSERT_LT(memory.size(), 128u);  | 
 | 307 | +      addr_t range_base = range.GetRangeBase();  | 
 | 308 | +      for (auto [idx, byte] : llvm::enumerate(memory))  | 
 | 309 | +        ASSERT_EQ(byte, static_cast<uint8_t>(range_base + idx));  | 
 | 310 | +    }  | 
 | 311 | +  }  | 
 | 312 | +}  | 
 | 313 | + | 
 | 314 | +using MemoryDeathTest = MemoryTest;  | 
 | 315 | + | 
 | 316 | +TEST_F(MemoryDeathTest, TestReadMemoryRangesReturnsTooMuch) {  | 
 | 317 | +  ArchSpec arch("x86_64-apple-macosx-");  | 
 | 318 | +  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));  | 
 | 319 | +  DebuggerSP debugger_sp = Debugger::CreateInstance();  | 
 | 320 | +  ASSERT_TRUE(debugger_sp);  | 
 | 321 | +  TargetSP target_sp = CreateTarget(debugger_sp, arch);  | 
 | 322 | +  ASSERT_TRUE(target_sp);  | 
 | 323 | +  ListenerSP listener_sp(Listener::MakeListener("dummy"));  | 
 | 324 | +  ProcessSP process_sp =  | 
 | 325 | +      std::make_shared<DummyReaderProcess>(target_sp, listener_sp);  | 
 | 326 | +  ASSERT_TRUE(process_sp);  | 
 | 327 | + | 
 | 328 | +  auto &dummy_process = static_cast<DummyReaderProcess &>(*process_sp);  | 
 | 329 | +  dummy_process.read_more_than_requested = true;  | 
 | 330 | +  llvm::SmallVector<uint8_t, 0> buffer(1024, 0);  | 
 | 331 | +  llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0x12345, 128}};  | 
 | 332 | + | 
 | 333 | +  llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results;  | 
 | 334 | +  ASSERT_DEBUG_DEATH(  | 
 | 335 | +      { read_results = process_sp->ReadMemoryRanges(ranges, buffer); },  | 
 | 336 | +      "read more than requested bytes");  | 
 | 337 | +#ifdef NDEBUG  | 
 | 338 | +  // With asserts off, the read should return empty ranges.  | 
 | 339 | +  ASSERT_EQ(read_results.size(), 1u);  | 
 | 340 | +  ASSERT_TRUE(read_results[0].empty());  | 
 | 341 | +#endif  | 
 | 342 | +}  | 
 | 343 | + | 
 | 344 | +TEST_F(MemoryDeathTest, TestReadMemoryRangesWithShortBuffer) {  | 
 | 345 | +  ArchSpec arch("x86_64-apple-macosx-");  | 
 | 346 | +  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));  | 
 | 347 | +  DebuggerSP debugger_sp = Debugger::CreateInstance();  | 
 | 348 | +  ASSERT_TRUE(debugger_sp);  | 
 | 349 | +  TargetSP target_sp = CreateTarget(debugger_sp, arch);  | 
 | 350 | +  ASSERT_TRUE(target_sp);  | 
 | 351 | +  ListenerSP listener_sp(Listener::MakeListener("dummy"));  | 
 | 352 | +  ProcessSP process_sp =  | 
 | 353 | +      std::make_shared<DummyReaderProcess>(target_sp, listener_sp);  | 
 | 354 | +  ASSERT_TRUE(process_sp);  | 
 | 355 | + | 
 | 356 | +  llvm::SmallVector<uint8_t, 0> short_buffer(10, 0);  | 
 | 357 | +  llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0x12345, 128},  | 
 | 358 | +                                                     {0x11, 128}};  | 
 | 359 | +  llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results;  | 
 | 360 | +  ASSERT_DEBUG_DEATH(  | 
 | 361 | +      { read_results = process_sp->ReadMemoryRanges(ranges, short_buffer); },  | 
 | 362 | +      "provided buffer is too short");  | 
 | 363 | +#ifdef NDEBUG  | 
 | 364 | +  // With asserts off, the read should return empty ranges.  | 
 | 365 | +  ASSERT_EQ(read_results.size(), ranges.size());  | 
 | 366 | +  for (llvm::MutableArrayRef<uint8_t> result : read_results)  | 
 | 367 | +    ASSERT_TRUE(result.empty());  | 
 | 368 | +#endif  | 
 | 369 | +}  | 
0 commit comments