LLDB mainline
Memory.cpp
Go to the documentation of this file.
1//===-- Memory.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-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Target/Process.h"
12#include "lldb/Utility/Log.h"
14#include "lldb/Utility/State.h"
15
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/Support/MathExtras.h"
18
19#include <algorithm>
20#include <cinttypes>
21#include <memory>
22#include <utility>
23
24using namespace lldb;
25using namespace lldb_private;
26
27llvm::ArrayRef<uint8_t> LineCache::Lookup(addr_t addr) const {
28 const auto pos = m_lines.find(IndexOf(addr));
29 if (pos == m_lines.end())
30 return {};
31 const addr_t line_offset = addr % m_line_byte_size;
32 return llvm::ArrayRef(pos->second.get(), m_line_byte_size)
33 .drop_front(line_offset);
34}
35
36void LineCache::Insert(addr_t addr, llvm::ArrayRef<uint8_t> src) {
37 assert((addr % m_line_byte_size) == 0 &&
38 "whole line inserted at an unaligned address!");
39 assert(src.size() == m_line_byte_size &&
40 "whole line inserted with a partial buffer!");
41 auto line = std::make_unique<uint8_t[]>(m_line_byte_size);
42 std::copy(src.begin(), src.end(), line.get());
43 m_lines[IndexOf(addr)] = std::move(line);
44}
45
47 if (size == 0)
48 return;
49 const addr_t end_addr = llvm::SaturatingAdd(addr, size - 1);
50 const uint64_t first_idx = IndexOf(addr);
51 const uint64_t last_idx = IndexOf(end_addr);
52 m_lines.remove_if([first_idx, last_idx](const auto &entry) {
53 return entry.getFirst() >= first_idx && entry.getFirst() <= last_idx;
54 });
55}
56
57ChunkCache::Collection::const_iterator
59 auto pos = m_chunks.upper_bound(addr);
60 if (pos == m_chunks.begin())
61 return m_chunks.end();
62 --pos;
63 // pos->first + size would overflow for a chunk at the top of the address
64 // space, do subtraction instead.
65 return addr - pos->first < pos->second.size() ? pos : m_chunks.end();
66}
67
68llvm::ArrayRef<uint8_t> ChunkCache::Lookup(addr_t addr) const {
69 auto pos = FindChunkContaining(addr);
70 if (pos == m_chunks.end())
71 return {};
72 return llvm::ArrayRef(pos->second).drop_front(addr - pos->first);
73}
74
75void ChunkCache::InsertMissing(addr_t addr, llvm::ArrayRef<uint8_t> src) {
76 if (src.empty())
77 return;
78 const addr_t last_addr = llvm::SaturatingAdd<addr_t>(addr, src.size() - 1);
79 const uint64_t len = last_addr - addr + 1;
80
81 for (uint64_t offset = 0; offset < len;) {
82 const addr_t curr_addr = addr + offset;
83 if (const llvm::ArrayRef<uint8_t> held = Lookup(curr_addr); !held.empty()) {
84 offset += std::min<uint64_t>(held.size(), len - offset);
85 continue;
86 }
87 // Nothing holds curr_addr, so the gap runs to the next chunk or to the end.
88 auto next = m_chunks.lower_bound(curr_addr);
89 const uint64_t gap_len =
90 next == m_chunks.end()
91 ? len - offset
92 : std::min<uint64_t>(next->first - curr_addr, len - offset);
93 const llvm::ArrayRef<uint8_t> gap_bytes = src.slice(offset, gap_len);
94 m_chunks[curr_addr].assign(gap_bytes.begin(), gap_bytes.end());
95 offset += gap_len;
96 }
97}
98
100 if (size == 0)
101 return;
102 const addr_t end_addr = llvm::SaturatingAdd(addr, size - 1);
103
104 auto pos = m_chunks.lower_bound(addr);
105 // A chunk starting below addr can still reach into the range.
106 if (pos != m_chunks.begin()) {
107 auto prev = std::prev(pos);
108 if (addr - prev->first < prev->second.size())
109 m_chunks.erase(prev);
110 }
111 while (pos != m_chunks.end() && pos->first <= end_addr)
112 pos = m_chunks.erase(pos);
113}
114
115// MemoryCache constructor
119
120// Destructor
121MemoryCache::~MemoryCache() = default;
122
123void MemoryCache::Clear(bool clear_invalid_ranges) {
124 std::lock_guard<std::recursive_mutex> guard(m_mutex);
125 m_L1_cache.Clear();
126 m_L2_cache.Clear(m_process.GetMemoryCacheLineSize());
127 if (clear_invalid_ranges)
128 m_invalid_ranges.Clear();
129}
130
131void MemoryCache::AddCacheData(lldb::addr_t addr, const void *src,
132 size_t src_len) {
133 InsertData(addr, {static_cast<const uint8_t *>(src), src_len});
134}
135
137 llvm::ArrayRef<uint8_t> src) {
138 m_L2_cache.Insert(line_base_addr, src);
139 // The new line holds every byte the L1 entries inside it held.
140 m_L1_cache.EraseRange(line_base_addr, src.size());
141}
142
143void MemoryCache::InsertPartialLine(addr_t addr, llvm::ArrayRef<uint8_t> src) {
144 assert(src.size() <= m_L2_cache.GetLineByteSize() &&
145 addr / m_L2_cache.GetLineByteSize() ==
146 (addr + src.size() - 1) / m_L2_cache.GetLineByteSize() &&
147 "a partial-line insert must not cross a cache line boundary");
148 // L2 holds only whole lines, so a range inside a resident line is held
149 // already.
150 if (m_L2_cache.Holds(addr))
151 return;
152 m_L1_cache.InsertMissing(addr, src);
153}
154
155void MemoryCache::InsertData(addr_t addr, llvm::ArrayRef<uint8_t> src) {
156 if (src.empty())
157 return;
158
159 std::lock_guard<std::recursive_mutex> guard(m_mutex);
160 const addr_t last_addr = llvm::SaturatingAdd<addr_t>(addr, src.size() - 1);
161 src = src.take_front(last_addr - addr + 1);
162 const uint32_t line_size = m_L2_cache.GetLineByteSize();
163
164 // A leading piece, up to the first line boundary.
165 if (const uint64_t line_offset = addr % line_size) {
166 const uint64_t head_len =
167 std::min<uint64_t>(line_size - line_offset, src.size());
168 InsertPartialLine(addr, src.take_front(head_len));
169 addr += head_len;
170 src = src.drop_front(head_len);
171 }
172
173 // Whole, aligned lines.
174 while (src.size() >= line_size) {
175 InsertWholeLine(addr, src.take_front(line_size));
176 addr += line_size;
177 src = src.drop_front(line_size);
178 }
179
180 // A trailing piece, shorter than a line.
181 if (!src.empty())
182 InsertPartialLine(addr, src);
183}
184
186 const DataBufferSP &data_buffer_sp) {
187 InsertData(addr, data_buffer_sp->GetData());
188}
189
190void MemoryCache::Flush(addr_t addr, size_t size) {
191 if (size == 0)
192 return;
193
194 std::lock_guard<std::recursive_mutex> guard(m_mutex);
195
196 m_L1_cache.EraseRange(addr, size);
197 m_L2_cache.EraseRange(addr, size);
198}
199
201 lldb::addr_t byte_size) {
202 if (byte_size > 0) {
203 std::lock_guard<std::recursive_mutex> guard(m_mutex);
204 InvalidRanges::Entry range(base_addr, byte_size);
205 m_invalid_ranges.Append(range);
206 m_invalid_ranges.Sort();
207 }
208}
209
211 lldb::addr_t byte_size) {
212 if (byte_size > 0) {
213 std::lock_guard<std::recursive_mutex> guard(m_mutex);
214 const uint32_t idx = m_invalid_ranges.FindEntryIndexThatContains(base_addr);
215 if (idx != UINT32_MAX) {
216 const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex(idx);
217 if (entry->GetRangeBase() == base_addr &&
218 entry->GetByteSize() == byte_size)
219 return m_invalid_ranges.RemoveEntryAtIndex(idx);
220 }
221 }
222 return false;
223}
224
226 size_t len) const {
227 size_t bytes_filled = 0;
228 // Bytes from addr to the last addressable byte. The walk must not pass
229 // it, or curr_addr wraps to 0.
230 const uint64_t space_to_top = UINT64_MAX - addr;
231 while (bytes_filled < len) {
232 if (bytes_filled > space_to_top)
233 break;
234 const addr_t curr_addr = addr + bytes_filled;
235
236 // At most one of the caches can hold curr_addr.
237 llvm::ArrayRef<uint8_t> cached = m_L2_cache.Lookup(curr_addr);
238 if (cached.empty())
239 cached = m_L1_cache.Lookup(curr_addr);
240 if (cached.empty())
241 break;
242
243 const size_t to_copy = std::min(cached.size(), len - bytes_filled);
244 memcpy(static_cast<uint8_t *>(dst) + bytes_filled, cached.data(), to_copy);
245 bytes_filled += to_copy;
246 }
247 return bytes_filled;
248}
249
251 addr_t caller_end,
252 size_t bytes_filled) const {
253 const uint64_t line_size = m_L2_cache.GetLineByteSize();
254 const addr_t line_base_addr = llvm::alignDown(read_addr, line_size);
255 // Caps read-ahead at this many whole cache lines.
256 static constexpr uint32_t kMaxCacheLinesPerRead = 2;
257 const uint64_t grow_span = kMaxCacheLinesPerRead * line_size;
258
259 // A request already past the cap spans a line, and one whose growth would
260 // wrap cannot be grown, so both are asked for as they stand.
261 if (line_base_addr > UINT64_MAX - grow_span ||
262 caller_end > line_base_addr + grow_span)
263 return AddrRange(read_addr, caller_end - read_addr);
264
265 // Grow down to the line base so the fetch lands in L2 as a whole line rather
266 // than an unaligned L1 fragment.
267 if (!m_invalid_ranges.FindEntryThatIntersects(
268 InvalidRanges::Entry(line_base_addr, read_addr - line_base_addr)) &&
269 (caller_end <= line_base_addr + line_size || bytes_filled == 0))
270 read_addr = line_base_addr;
271
272 // Read up to the last line the request touches, skipping that line when L2
273 // holds it.
274 addr_t last_line_addr = llvm::alignDown(caller_end - 1, line_size);
275 if (last_line_addr > line_base_addr && m_L2_cache.Holds(last_line_addr))
276 last_line_addr -= line_size;
277 const addr_t grow_target = last_line_addr + line_size;
278
279 // Growth stops at the first invalid range among the bytes it adds.
280 addr_t read_end = grow_target;
281 if (grow_target > caller_end) {
282 if (const InvalidRanges::Entry *invalid =
283 m_invalid_ranges.FindEntryThatIntersects(
284 InvalidRanges::Entry(caller_end, grow_target - caller_end)))
285 read_end = invalid->GetRangeBase();
286 }
287 return AddrRange(read_addr, read_end - read_addr);
288}
289
290size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len,
291 Status &error) {
292 if (!dst || dst_len == 0)
293 return 0;
294
295 std::lock_guard<std::recursive_mutex> guard(m_mutex);
296 addr_t invalid_addr = LLDB_INVALID_ADDRESS;
297 if (const InvalidRanges::Entry *invalid =
298 m_invalid_ranges.FindEntryThatIntersects(
299 InvalidRanges::Entry(addr, dst_len))) {
300 invalid_addr = invalid->GetRangeBase();
302 "memory read failed for 0x%" PRIx64, invalid_addr);
303 if (invalid_addr <= addr)
304 return 0;
305 dst_len = invalid_addr - addr;
306 }
307
308 size_t bytes_from_cache = ReadFromCaches(addr, dst, dst_len);
309 if (bytes_from_cache == dst_len)
310 return dst_len;
311
312 addr_t read_addr = addr + bytes_from_cache;
313 addr_t read_end = addr + dst_len;
314 // A request hits the invalid range above, don't grow.
315 if (invalid_addr == LLDB_INVALID_ADDRESS) {
316 const AddrRange grown =
317 GrowReadRange(read_addr, read_end, bytes_from_cache);
318 read_addr = grown.GetRangeBase();
319 read_end = grown.GetRangeEnd();
320 }
321
322 std::vector<uint8_t> read_buf(read_end - read_addr);
323 const size_t bytes_from_inferior = m_process.ReadMemoryFromInferior(
324 read_addr, read_buf.data(), read_buf.size(), error);
325 if (bytes_from_inferior == 0)
326 return bytes_from_cache;
327
328 AddCacheData(read_addr, read_buf.data(), bytes_from_inferior);
329
330 // The grown or clipped fetch may not align with what the caller asked for,
331 // so pull back only the portion contiguous with what dst already holds.
332 uint8_t *dst_tail = static_cast<uint8_t *>(dst) + bytes_from_cache;
333 return bytes_from_cache + ReadFromCaches(addr + bytes_from_cache, dst_tail,
334 dst_len - bytes_from_cache);
335}
336
337llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>
339 llvm::MutableArrayRef<uint8_t> buffer) {
340 // A cache hit writes into `buffer` below, so check its size before that
341 // write. Fail the same way Process::DoReadMemoryRanges does.
342 auto total_ranges_len = llvm::sum_of(
343 llvm::map_range(ranges, [](auto range) { return range.size; }));
344 assert(buffer.size() >= total_ranges_len &&
345 "MemoryCache::ReadRanges: provided buffer is too short");
346 if (buffer.size() < total_ranges_len) {
347 llvm::MutableArrayRef<uint8_t> empty;
348 return {ranges.size(), empty};
349 }
350
351 std::lock_guard<std::recursive_mutex> guard(m_mutex);
352
353 llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results;
354 results.reserve(ranges.size());
355 llvm::SmallVector<Range<lldb::addr_t, size_t>> missed_ranges;
356
357 // Iterate once serving requests from the caches.
358 for (auto range : ranges) {
359 const lldb::addr_t addr = range.GetRangeBase();
360 const size_t len = range.GetByteSize();
361
362 if (m_invalid_ranges.FindEntryThatContains(addr)) {
363 results.push_back(buffer.take_front(0));
364 continue;
365 }
366
367 if (ReadFromCaches(addr, buffer.data(), len) == len) {
368 results.push_back(buffer.take_front(len));
369 buffer = buffer.drop_front(len);
370 continue;
371 }
372
373 // Use a nullptr to denote this needs fetching.
374 results.emplace_back(nullptr, nullptr);
375 missed_ranges.push_back(range);
376 }
377
378 if (missed_ranges.empty())
379 return results;
380
381 llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> fetched_buffers_vec =
382 m_process.DoReadMemoryRanges(missed_ranges, buffer);
383 auto fetched_buffers = llvm::ArrayRef(fetched_buffers_vec);
384
385 for (auto [missed_range, fetched] : llvm::zip(missed_ranges, fetched_buffers))
386 AddCacheData(missed_range.GetRangeBase(), fetched);
387
388 // Use the just-fetched memory to fill in the gaps left by the cache.
389 for (auto &result : results)
390 if (result.data() == nullptr)
391 result = fetched_buffers.consume_front();
392
393 return results;
394}
395
397 uint32_t permissions, uint32_t chunk_size)
398 : m_range(addr, byte_size), m_permissions(permissions),
399 m_chunk_size(chunk_size)
400{
401 // The entire address range is free to start with.
402 m_free_blocks.Append(m_range);
403 assert(byte_size > chunk_size);
404}
405
407
409 // We must return something valid for zero bytes.
410 if (size == 0)
411 size = 1;
413
414 const size_t free_count = m_free_blocks.GetSize();
415 for (size_t i=0; i<free_count; ++i)
416 {
417 auto &free_block = m_free_blocks.GetEntryRef(i);
418 const lldb::addr_t range_size = free_block.GetByteSize();
419 if (range_size >= size)
420 {
421 // We found a free block that is big enough for our data. Figure out how
422 // many chunks we will need and calculate the resulting block size we
423 // will reserve.
424 addr_t addr = free_block.GetRangeBase();
425 size_t num_chunks = CalculateChunksNeededForSize(size);
426 lldb::addr_t block_size = num_chunks * m_chunk_size;
427 lldb::addr_t bytes_left = range_size - block_size;
428 if (bytes_left == 0)
429 {
430 // The newly allocated block will take all of the bytes in this
431 // available block, so we can just add it to the allocated ranges and
432 // remove the range from the free ranges.
433 m_reserved_blocks.Insert(free_block, false);
434 m_free_blocks.RemoveEntryAtIndex(i);
435 }
436 else
437 {
438 // Make the new allocated range and add it to the allocated ranges.
439 Range<lldb::addr_t, uint32_t> reserved_block(free_block);
440 reserved_block.SetByteSize(block_size);
441 // Insert the reserved range and don't combine it with other blocks in
442 // the reserved blocks list.
443 m_reserved_blocks.Insert(reserved_block, false);
444 // Adjust the free range in place since we won't change the sorted
445 // ordering of the m_free_blocks list.
446 free_block.SetRangeBase(reserved_block.GetRangeEnd());
447 free_block.SetByteSize(bytes_left);
448 }
449 LLDB_LOG_VERBOSE(log, "({0}) (size = {1} ({1:x})) => {2:x}", this, size,
450 addr);
451 return addr;
452 }
453 }
454
455 LLDB_LOG_VERBOSE(log, "({0}) (size = {1} ({1:x})) => {2:x}", this, size,
458}
459
461 bool success = false;
462 auto entry_idx = m_reserved_blocks.FindEntryIndexThatContains(addr);
463 if (entry_idx != UINT32_MAX)
464 {
465 m_free_blocks.Insert(m_reserved_blocks.GetEntryRef(entry_idx), true);
466 m_reserved_blocks.RemoveEntryAtIndex(entry_idx);
467 success = true;
468 }
470 LLDB_LOG_VERBOSE(log, "({0}) (addr = {1:x}) => {2}", this, addr, success);
471 return success;
472}
473
476
478
479void AllocatedMemoryCache::Clear(bool deallocate_memory) {
480 std::lock_guard<std::recursive_mutex> guard(m_mutex);
481 if (m_process.IsAlive() && deallocate_memory) {
482 PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
483 for (pos = m_memory_map.begin(); pos != end; ++pos)
484 m_process.DoDeallocateMemory(pos->second->GetBaseAddress());
485 }
486 m_memory_map.clear();
487}
488
490AllocatedMemoryCache::AllocatePage(uint32_t byte_size, uint32_t permissions,
491 uint32_t chunk_size, Status &error) {
492 AllocatedBlockSP block_sp;
493 const size_t page_size = 4096;
494 const size_t num_pages = (byte_size + page_size - 1) / page_size;
495 const size_t page_byte_size = num_pages * page_size;
496
497 addr_t addr = m_process.DoAllocateMemory(page_byte_size, permissions, error);
498
500 LLDB_LOGF(log,
501 "Process::DoAllocateMemory (byte_size = 0x%8.8" PRIx32
502 ", permissions = %s) => 0x%16.16" PRIx64,
503 (uint32_t)page_byte_size, GetPermissionsAsCString(permissions),
504 (uint64_t)addr);
505
506 if (addr != LLDB_INVALID_ADDRESS) {
507 block_sp = std::make_shared<AllocatedBlock>(addr, page_byte_size,
508 permissions, chunk_size);
509 m_memory_map.insert(std::make_pair(permissions, block_sp));
510 }
511 return block_sp;
512}
513
515 uint32_t permissions,
516 Status &error) {
517 std::lock_guard<std::recursive_mutex> guard(m_mutex);
518
520 std::pair<PermissionsToBlockMap::iterator, PermissionsToBlockMap::iterator>
521 range = m_memory_map.equal_range(permissions);
522
523 for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second;
524 ++pos) {
525 addr = (*pos).second->ReserveBlock(byte_size);
526 if (addr != LLDB_INVALID_ADDRESS)
527 break;
528 }
529
530 if (addr == LLDB_INVALID_ADDRESS) {
531 AllocatedBlockSP block_sp(AllocatePage(byte_size, permissions, 16, error));
532
533 if (block_sp)
534 addr = block_sp->ReserveBlock(byte_size);
535 }
537 LLDB_LOGF(log,
538 "AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8" PRIx32
539 ", permissions = %s) => 0x%16.16" PRIx64,
540 (uint32_t)byte_size, GetPermissionsAsCString(permissions),
541 (uint64_t)addr);
542 return addr;
543}
544
546 std::lock_guard<std::recursive_mutex> guard(m_mutex);
547
548 PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
549 bool success = false;
550 for (pos = m_memory_map.begin(); pos != end; ++pos) {
551 if (pos->second->Contains(addr)) {
552 success = pos->second->FreeBlock(addr);
553 break;
554 }
555 }
557 LLDB_LOGF(log,
558 "AllocatedMemoryCache::DeallocateMemory (addr = 0x%16.16" PRIx64
559 ") => %i",
560 (uint64_t)addr, success);
561 return success;
562}
563
565 std::lock_guard<std::recursive_mutex> guard(m_mutex);
566
567 return llvm::any_of(m_memory_map, [addr](const auto &block) {
568 return block.second->Contains(addr);
569 });
570}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:389
#define LLDB_LOG_VERBOSE(log,...)
Definition Log.h:382
uint32_t CalculateChunksNeededForSize(uint32_t size) const
Definition Memory.h:214
bool FreeBlock(lldb::addr_t addr)
Definition Memory.cpp:460
lldb::addr_t ReserveBlock(uint32_t size)
Definition Memory.cpp:408
const uint32_t m_permissions
Definition Memory.h:220
Range< lldb::addr_t, uint32_t > m_range
Definition Memory.h:218
AllocatedBlock(lldb::addr_t addr, uint32_t byte_size, uint32_t permissions, uint32_t chunk_size)
Definition Memory.cpp:396
RangeVector< lldb::addr_t, uint32_t > m_free_blocks
Definition Memory.h:224
RangeVector< lldb::addr_t, uint32_t > m_reserved_blocks
Definition Memory.h:226
const uint32_t m_chunk_size
Definition Memory.h:222
lldb::addr_t AllocateMemory(size_t byte_size, uint32_t permissions, Status &error)
Definition Memory.cpp:514
bool IsInCache(lldb::addr_t addr) const
Definition Memory.cpp:564
AllocatedMemoryCache(Process &process)
Definition Memory.cpp:474
std::recursive_mutex m_mutex
Definition Memory.h:256
void Clear(bool deallocate_memory)
Definition Memory.cpp:479
bool DeallocateMemory(lldb::addr_t ptr)
Definition Memory.cpp:545
std::shared_ptr< AllocatedBlock > AllocatedBlockSP
Definition Memory.h:249
PermissionsToBlockMap m_memory_map
Definition Memory.h:258
AllocatedBlockSP AllocatePage(uint32_t byte_size, uint32_t permissions, uint32_t chunk_size, Status &error)
Definition Memory.cpp:490
llvm::ArrayRef< uint8_t > Lookup(lldb::addr_t addr) const
The cached bytes from addr to the end of the chunk holding it, empty if no chunk holds it.
Definition Memory.cpp:68
Collection::const_iterator FindChunkContaining(lldb::addr_t addr) const
The chunk holding addr, or end().
Definition Memory.cpp:58
void EraseRange(lldb::addr_t addr, lldb::addr_t size)
Drop every chunk that intersects [addr, addr+size).
Definition Memory.cpp:99
void InsertMissing(lldb::addr_t addr, llvm::ArrayRef< uint8_t > src)
Add the bytes of [addr, addr+src.size()) that no chunk holds yet.
Definition Memory.cpp:75
uint64_t IndexOf(lldb::addr_t addr) const
Definition Memory.h:64
uint32_t m_line_byte_size
Definition Memory.h:67
llvm::ArrayRef< uint8_t > Lookup(lldb::addr_t addr) const
The cached bytes from addr to the end of the line holding it, empty if that line is not resident.
Definition Memory.cpp:27
void Insert(lldb::addr_t addr, llvm::ArrayRef< uint8_t > src)
Add one whole line.
Definition Memory.cpp:36
Collection m_lines
Definition Memory.h:66
void EraseRange(lldb::addr_t addr, lldb::addr_t size)
Drop every line that intersects [addr, addr+size).
Definition Memory.cpp:46
uint32_t GetMemoryCacheLineSize() const
Definition Memory.h:127
MemoryCache(Process &process)
Definition Memory.cpp:116
std::recursive_mutex m_mutex
Definition Memory.h:150
void AddCacheData(lldb::addr_t addr, const void *src, size_t src_len)
Allow external sources to populate data into the memory cache.
Definition Memory.cpp:131
bool RemoveInvalidRange(lldb::addr_t base_addr, lldb::addr_t byte_size)
Definition Memory.cpp:210
void Flush(lldb::addr_t addr, size_t size)
Definition Memory.cpp:190
void InsertWholeLine(lldb::addr_t line_base_addr, llvm::ArrayRef< uint8_t > src)
Definition Memory.cpp:136
llvm::SmallVector< llvm::MutableArrayRef< uint8_t > > ReadRanges(llvm::ArrayRef< Range< lldb::addr_t, size_t > > ranges, llvm::MutableArrayRef< uint8_t > buffer)
Reads memory ranges, serving hits from the cache and batching misses through Process::DoReadMemoryRan...
Definition Memory.cpp:338
InvalidRanges m_invalid_ranges
Definition Memory.h:155
void InsertPartialLine(lldb::addr_t addr, llvm::ArrayRef< uint8_t > src)
Definition Memory.cpp:143
void Clear(bool clear_invalid_ranges=false)
Definition Memory.cpp:123
size_t ReadFromCaches(lldb::addr_t addr, void *dst, size_t len) const
Definition Memory.cpp:225
void InsertData(lldb::addr_t addr, llvm::ArrayRef< uint8_t > src)
Definition Memory.cpp:155
AddrRange GrowReadRange(lldb::addr_t read_addr, lldb::addr_t caller_end, size_t bytes_filled) const
Definition Memory.cpp:250
size_t Read(lldb::addr_t addr, void *dst, size_t dst_len, Status &error)
Definition Memory.cpp:290
void AddInvalidRange(lldb::addr_t base_addr, lldb::addr_t byte_size)
Definition Memory.cpp:200
Range< lldb::addr_t, lldb::addr_t > AddrRange
Definition Memory.h:148
A plug-in interface definition class for debugging a process.
Definition Process.h:368
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
#define UINT64_MAX
#define LLDB_INVALID_ADDRESS
#define UINT32_MAX
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
const char * GetPermissionsAsCString(uint32_t permissions)
Definition State.cpp:44
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
BaseType GetRangeBase() const
Definition RangeMap.h:45
SizeType GetByteSize() const
Definition RangeMap.h:87
BaseType GetRangeEnd() const
Definition RangeMap.h:78
void SetByteSize(SizeType s)
Definition RangeMap.h:89