diff options
Diffstat (limited to 'lldb/source/Target')
-rw-r--r-- | lldb/source/Target/Process.cpp | 43 | ||||
-rw-r--r-- | lldb/source/Target/StopInfo.cpp | 13 |
2 files changed, 54 insertions, 2 deletions
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 3176852..fb9e7eb 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1971,6 +1971,49 @@ size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) { } } +llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> +Process::ReadMemoryRanges(llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges, + llvm::MutableArrayRef<uint8_t> buffer) { + auto total_ranges_len = llvm::sum_of( + llvm::map_range(ranges, [](auto range) { return range.size; })); + // If the buffer is not large enough, this is a programmer error. + // In production builds, gracefully fail by returning a length of 0 for all + // ranges. + assert(buffer.size() >= total_ranges_len && "provided buffer is too short"); + if (buffer.size() < total_ranges_len) { + llvm::MutableArrayRef<uint8_t> empty; + return {ranges.size(), empty}; + } + + llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results; + + // While `buffer` has space, take the next requested range and read + // memory into a `buffer` piece, then slice it to remove the used memory. + for (auto [addr, range_len] : ranges) { + Status status; + size_t num_bytes_read = + ReadMemoryFromInferior(addr, buffer.data(), range_len, status); + // FIXME: ReadMemoryFromInferior promises to return 0 in case of errors, but + // it doesn't; it never checks for errors. + if (status.Fail()) + num_bytes_read = 0; + + assert(num_bytes_read <= range_len && "read more than requested bytes"); + if (num_bytes_read > range_len) { + // In production builds, gracefully fail by returning length zero for this + // range. + results.emplace_back(); + continue; + } + + results.push_back(buffer.take_front(num_bytes_read)); + // Slice buffer to remove the used memory. + buffer = buffer.drop_front(num_bytes_read); + } + + return results; +} + void Process::DoFindInMemory(lldb::addr_t start_addr, lldb::addr_t end_addr, const uint8_t *buf, size_t size, AddressRanges &matches, size_t alignment, diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 7fa1fc5..e9e534a 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -87,11 +87,15 @@ bool StopInfo::HasTargetRunSinceMe() { namespace lldb_private { class StopInfoBreakpoint : public StopInfo { public: + // We use a "breakpoint preserving BreakpointLocationCollection because we + // may need to hand out the "breakpoint hit" list as any point, potentially + // after the breakpoint has been deleted. But we still need to refer to them. StopInfoBreakpoint(Thread &thread, break_id_t break_id) : StopInfo(thread, break_id), m_should_stop(false), m_should_stop_is_valid(false), m_should_perform_action(true), m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), - m_was_all_internal(false), m_was_one_shot(false) { + m_was_all_internal(false), m_was_one_shot(false), + m_async_stopped_locs(true) { StoreBPInfo(); } @@ -99,7 +103,8 @@ public: : StopInfo(thread, break_id), m_should_stop(should_stop), m_should_stop_is_valid(true), m_should_perform_action(true), m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), - m_was_all_internal(false), m_was_one_shot(false) { + m_was_all_internal(false), m_was_one_shot(false), + m_async_stopped_locs(true) { StoreBPInfo(); } @@ -699,6 +704,10 @@ private: lldb::break_id_t m_break_id; bool m_was_all_internal; bool m_was_one_shot; + /// The StopInfoBreakpoint lives after the stop, and could get queried + /// at any time so we need to make sure that it keeps the breakpoints for + /// each of the locations it records alive while it is around. That's what + /// The BreakpointPreservingLocationCollection does. BreakpointLocationCollection m_async_stopped_locs; }; |