aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Target
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Target')
-rw-r--r--lldb/source/Target/Process.cpp43
-rw-r--r--lldb/source/Target/StopInfo.cpp13
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;
};