Skip to content

Commit aeffdf3

Browse files
authored
Merge pull request #11697 from felipepiovezan/felipe/multimem_cherry_picks_p2_62
2 parents 4b59eaa + 46e82ad commit aeffdf3

File tree

11 files changed

+783
-110
lines changed

11 files changed

+783
-110
lines changed

lldb/include/lldb/Target/Process.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,28 @@ class Process : public std::enable_shared_from_this<Process>,
15741574
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
15751575
Status &error);
15761576

1577+
/// Read from multiple memory ranges and write the results into buffer.
1578+
/// This calls ReadMemoryFromInferior multiple times, once per range,
1579+
/// bypassing the read cache. Process implementations that can perform this
1580+
/// operation more efficiently should override this.
1581+
///
1582+
/// \param[in] ranges
1583+
/// A collection of ranges (base address + size) to read from.
1584+
///
1585+
/// \param[out] buffer
1586+
/// A buffer where the read memory will be written to. It must be at least
1587+
/// as long as the sum of the sizes of each range.
1588+
///
1589+
/// \return
1590+
/// A vector of MutableArrayRef, where each MutableArrayRef is a slice of
1591+
/// the input buffer into which the memory contents were copied. The size
1592+
/// of the slice indicates how many bytes were read successfully. Partial
1593+
/// reads are always performed from the start of the requested range,
1594+
/// never from the middle or end.
1595+
virtual llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>
1596+
ReadMemoryRanges(llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges,
1597+
llvm::MutableArrayRef<uint8_t> buffer);
1598+
15771599
/// Read of memory from a process.
15781600
///
15791601
/// This function has the same semantics of ReadMemory except that it
@@ -1647,11 +1669,24 @@ class Process : public std::enable_shared_from_this<Process>,
16471669
size_t byte_size, uint64_t fail_value,
16481670
Status &error);
16491671

1672+
/// Use Process::ReadMemoryRanges to efficiently read multiple unsigned
1673+
/// integers from memory at once.
1674+
/// TODO: this should be upstream once there is a use for it there.
1675+
llvm::SmallVector<std::optional<uint64_t>>
1676+
ReadUnsignedIntegersFromMemory(llvm::ArrayRef<lldb::addr_t> addresses,
1677+
unsigned byte_size);
1678+
16501679
int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size,
16511680
int64_t fail_value, Status &error);
16521681

16531682
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error);
16541683

1684+
/// Use Process::ReadMemoryRanges to efficiently read multiple pointers from
1685+
/// memory at once.
1686+
/// TODO: this should be upstream once there is a use for it there.
1687+
llvm::SmallVector<std::optional<lldb::addr_t>>
1688+
ReadPointersFromMemory(llvm::ArrayRef<lldb::addr_t> ptr_locs);
1689+
16551690
bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
16561691
Status &error);
16571692

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -279,22 +279,23 @@ ClassDescriptorV2::ReadMethods(llvm::ArrayRef<lldb::addr_t> addresses,
279279
const size_t num_methods = addresses.size();
280280

281281
llvm::SmallVector<uint8_t, 0> buffer(num_methods * size, 0);
282-
llvm::DenseSet<uint32_t> failed_indices;
283282

284-
for (auto [idx, addr] : llvm::enumerate(addresses)) {
285-
Status error;
286-
process->ReadMemory(addr, buffer.data() + idx * size, size, error);
287-
if (error.Fail())
288-
failed_indices.insert(idx);
289-
}
283+
llvm::SmallVector<Range<addr_t, size_t>> mem_ranges =
284+
llvm::to_vector(llvm::map_range(llvm::seq(num_methods), [&](size_t idx) {
285+
return Range<addr_t, size_t>(addresses[idx], size);
286+
}));
287+
288+
llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results =
289+
process->ReadMemoryRanges(mem_ranges, buffer);
290290

291291
llvm::SmallVector<method_t, 0> methods;
292292
methods.reserve(num_methods);
293-
for (auto [idx, addr] : llvm::enumerate(addresses)) {
294-
if (failed_indices.contains(idx))
293+
for (auto [addr, memory] : llvm::zip(addresses, read_results)) {
294+
// Ignore partial reads.
295+
if (memory.size() != size)
295296
continue;
296-
DataExtractor extractor(buffer.data() + idx * size, size,
297-
process->GetByteOrder(),
297+
298+
DataExtractor extractor(memory.data(), size, process->GetByteOrder(),
298299
process->GetAddressByteSize());
299300
methods.push_back(method_t());
300301
methods.back().Read(extractor, process, addr, relative_selector_base_addr,

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp

Lines changed: 141 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,14 +2337,15 @@ class CommandObjectLanguageSwiftTaskInfo final : public CommandObjectParsed {
23372337
}
23382338

23392339
TaskInspector task_inspector;
2340-
auto task_addr_or_err = task_inspector.GetTaskAddrFromThreadLocalStorage(
2341-
m_exe_ctx.GetThreadRef());
2342-
if (auto error = task_addr_or_err.takeError()) {
2343-
result.AppendError(toString(std::move(error)));
2340+
std::optional<lldb::addr_t> maybe_task_addr =
2341+
task_inspector.GetTaskAddrFromThreadLocalStorage(
2342+
m_exe_ctx.GetThreadRef());
2343+
if (!task_addr) {
2344+
result.AppendError("could find the task address");
23442345
return;
23452346
}
23462347

2347-
task_addr = task_addr_or_err.get();
2348+
task_addr = *maybe_task_addr;
23482349
}
23492350

23502351
auto ts_or_err = m_exe_ctx.GetTargetRef().GetScratchTypeSystemForLanguage(
@@ -2935,19 +2936,6 @@ std::optional<lldb::addr_t> SwiftLanguageRuntime::TrySkipVirtualParentProlog(
29352936
return pc_value;
29362937
}
29372938

2938-
/// Attempts to read the memory location at `task_addr_location`, producing
2939-
/// the Task pointer if possible.
2940-
static llvm::Expected<lldb::addr_t>
2941-
ReadTaskAddr(lldb::addr_t task_addr_location, Process &process) {
2942-
Status status;
2943-
addr_t task_addr = process.ReadPointerFromMemory(task_addr_location, status);
2944-
if (status.Fail())
2945-
return llvm::joinErrors(
2946-
llvm::createStringError("could not get current task from thread"),
2947-
status.takeError());
2948-
return task_addr;
2949-
}
2950-
29512939
/// Compute the location where the Task pointer for `real_thread` is stored by
29522940
/// the runtime.
29532941
static llvm::Expected<lldb::addr_t>
@@ -2975,48 +2963,146 @@ ComputeTaskAddrLocationFromThreadLocalStorage(Thread &real_thread) {
29752963
#endif
29762964
}
29772965

2978-
llvm::Expected<lldb::addr_t>
2966+
/// Helper function to read all `pointers` from process memory at once.
2967+
/// Consumes any errors from the input by propagating them to the output.
2968+
static llvm::SmallVector<std::optional<addr_t>>
2969+
MultiReadPointers(Process &process,
2970+
llvm::MutableArrayRef<std::optional<addr_t>> maybe_pointers) {
2971+
llvm::SmallVector<std::optional<addr_t>> final_results;
2972+
llvm::SmallVector<addr_t> to_read;
2973+
final_results.reserve(maybe_pointers.size());
2974+
to_read.reserve(maybe_pointers.size());
2975+
2976+
/// Filter the input: propagate input errors directly to the output, forward
2977+
/// proper inputs to `to_read`.
2978+
for (std::optional<addr_t> &maybe_ptr : maybe_pointers) {
2979+
if (!maybe_ptr)
2980+
final_results.emplace_back(std::nullopt);
2981+
else {
2982+
final_results.push_back(LLDB_INVALID_ADDRESS);
2983+
to_read.push_back(*maybe_ptr);
2984+
}
2985+
}
2986+
2987+
llvm::SmallVector<std::optional<addr_t>> read_results =
2988+
process.ReadPointersFromMemory(to_read);
2989+
llvm::MutableArrayRef<std::optional<addr_t>> results_ref = read_results;
2990+
2991+
// Move the results in the slots not filled by errors from the input.
2992+
for (std::optional<addr_t> &maybe_result : final_results)
2993+
if (maybe_result) {
2994+
maybe_result = results_ref.front();
2995+
results_ref = results_ref.drop_front();
2996+
}
2997+
2998+
assert(results_ref.empty());
2999+
return final_results;
3000+
}
3001+
3002+
/// Helper function to read `addr` from process memory. Errors in the input are
3003+
/// propagated to to the output.
3004+
static std::optional<addr_t> ReadPointer(Process &process,
3005+
std::optional<addr_t> addr) {
3006+
return MultiReadPointers(process, addr)[0];
3007+
}
3008+
3009+
std::optional<lldb::addr_t>
29793010
TaskInspector::GetTaskAddrFromThreadLocalStorage(Thread &thread) {
2980-
// Look through backing threads when inspecting TLS.
2981-
Thread &real_thread =
2982-
thread.GetBackingThread() ? *thread.GetBackingThread() : thread;
3011+
return GetTaskAddrFromThreadLocalStorage(&thread)[0];
3012+
}
29833013

2984-
if (auto it = m_tid_to_task_addr_location.find(real_thread.GetID());
2985-
it != m_tid_to_task_addr_location.end()) {
3014+
llvm::SmallVector<std::optional<lldb::addr_t>>
3015+
TaskInspector::GetTaskAddrLocations(llvm::ArrayRef<Thread *> threads) {
3016+
llvm::SmallVector<std::optional<addr_t>> addr_locations;
3017+
addr_locations.reserve(threads.size());
3018+
3019+
for (auto [idx, thread] : llvm::enumerate(threads)) {
3020+
Thread &real_thread =
3021+
thread->GetBackingThread() ? *thread->GetBackingThread() : *thread;
3022+
3023+
auto it = m_tid_to_task_addr_location.find(real_thread.GetID());
3024+
if (it != m_tid_to_task_addr_location.end()) {
3025+
addr_locations.push_back(it->second);
29863026
#ifndef NDEBUG
2987-
// In assert builds, check that caching did not produce incorrect results.
2988-
llvm::Expected<lldb::addr_t> task_addr_location =
2989-
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
2990-
assert(task_addr_location);
2991-
assert(it->second == *task_addr_location);
3027+
// In assert builds, check that caching did not produce incorrect results.
3028+
llvm::Expected<lldb::addr_t> task_addr_location =
3029+
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
3030+
assert(task_addr_location);
3031+
assert(it->second == *task_addr_location);
29923032
#endif
2993-
llvm::Expected<lldb::addr_t> task_addr =
2994-
ReadTaskAddr(it->second, *thread.GetProcess());
2995-
if (task_addr)
2996-
return task_addr;
2997-
// If the cached task addr location became invalid, invalidate the cache.
2998-
m_tid_to_task_addr_location.erase(it);
2999-
LLDB_LOG_ERROR(GetLog(LLDBLog::OS), task_addr.takeError(),
3000-
"TaskInspector: evicted task location address due to "
3001-
"invalid memory read: {0}");
3002-
}
3003-
3004-
llvm::Expected<lldb::addr_t> task_addr_location =
3033+
continue;
3034+
}
3035+
llvm::Expected<addr_t> addr_loc =
3036+
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
3037+
if (!addr_loc) {
3038+
LLDB_LOG_ERROR(GetLog(LLDBLog::OS), addr_loc.takeError(),
3039+
"TaskInspector: failed to compute task address location "
3040+
"from TLS: {0}");
3041+
addr_locations.push_back(std::nullopt);
3042+
} else
3043+
addr_locations.push_back(*addr_loc);
3044+
}
3045+
return addr_locations;
3046+
}
3047+
3048+
std::optional<addr_t> TaskInspector::RetryRead(Thread &thread,
3049+
addr_t task_addr_location) {
3050+
Thread &real_thread =
3051+
thread.GetBackingThread() ? *thread.GetBackingThread() : thread;
3052+
user_id_t tid = real_thread.GetID();
3053+
3054+
// For unsuccessful reads whose address was not cached, don't try again.
3055+
if (!m_tid_to_task_addr_location.erase(tid))
3056+
return std::nullopt;
3057+
3058+
LLDB_LOG(GetLog(LLDBLog::OS), "TaskInspector: evicted task location "
3059+
"address due to invalid memory read");
3060+
3061+
// The cached address could not be loaded. "This should never happen", but
3062+
// recompute the address and try again for completeness.
3063+
llvm::Expected<addr_t> task_addr_loc =
30053064
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
3006-
if (!task_addr_location)
3007-
return task_addr_location;
3008-
3009-
llvm::Expected<lldb::addr_t> task_addr =
3010-
ReadTaskAddr(*task_addr_location, *thread.GetProcess());
3011-
3012-
// If the read from this TLS address is successful, cache the TLS address.
3013-
// Caching without a valid read is dangerous: earlier in the thread
3014-
// lifetime, the result of GetExtendedInfo can be invalid.
3015-
if (task_addr &&
3016-
real_thread.GetProcess()->GetTarget().GetSwiftCacheTaskPointerLocation())
3017-
m_tid_to_task_addr_location.try_emplace(real_thread.GetID(),
3018-
*task_addr_location);
3019-
return task_addr;
3065+
if (!task_addr_loc) {
3066+
LLDB_LOG_ERROR(GetLog(LLDBLog::OS), task_addr_loc.takeError(),
3067+
"TaskInspector: failed to compute task address location "
3068+
"from TLS: {0}");
3069+
return std::nullopt;
3070+
}
3071+
3072+
std::optional<addr_t> read_retry_result =
3073+
ReadPointer(*thread.GetProcess(), *task_addr_loc);
3074+
if (read_retry_result)
3075+
m_tid_to_task_addr_location[tid] = *task_addr_loc;
3076+
return read_retry_result;
3077+
}
3078+
3079+
llvm::SmallVector<std::optional<addr_t>>
3080+
TaskInspector::GetTaskAddrFromThreadLocalStorage(
3081+
llvm::ArrayRef<Thread *> threads) {
3082+
if (threads.empty())
3083+
return {};
3084+
3085+
llvm::SmallVector<std::optional<addr_t>> addr_locations =
3086+
GetTaskAddrLocations(threads);
3087+
3088+
Process &process = *threads[0]->GetProcess();
3089+
llvm::SmallVector<std::optional<addr_t>> mem_read_results =
3090+
MultiReadPointers(process, addr_locations);
3091+
3092+
for (auto [idx, thread] : llvm::enumerate(threads)) {
3093+
if (!addr_locations[idx])
3094+
continue;
3095+
// If the read was successful, cache the address.
3096+
if (mem_read_results[idx]) {
3097+
Thread &real_thread =
3098+
thread->GetBackingThread() ? *thread->GetBackingThread() : *thread;
3099+
m_tid_to_task_addr_location[real_thread.GetID()] = *addr_locations[idx];
3100+
continue;
3101+
}
3102+
mem_read_results[idx] = RetryRead(*thread, *addr_locations[idx]);
3103+
}
3104+
3105+
return mem_read_results;
30203106
}
30213107

30223108
namespace {

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -934,10 +934,24 @@ class TaskInspector {
934934
public:
935935
/// Inspects thread local storage to find the address of the currently
936936
/// executing task, if any.
937-
llvm::Expected<lldb::addr_t>
938-
GetTaskAddrFromThreadLocalStorage(Thread &thread);
937+
std::optional<lldb::addr_t> GetTaskAddrFromThreadLocalStorage(Thread &thread);
938+
939+
/// Inspects thread local storage to find the address of the currently
940+
/// executing task, if any.
941+
llvm::SmallVector<std::optional<lldb::addr_t>>
942+
GetTaskAddrFromThreadLocalStorage(llvm::ArrayRef<Thread *> threads);
939943

940944
private:
945+
/// For each thread in `threads`, return the location of the its task
946+
/// pointer, if it exists.
947+
llvm::SmallVector<std::optional<lldb::addr_t>>
948+
GetTaskAddrLocations(llvm::ArrayRef<Thread *> threads);
949+
950+
/// If reading from a cached task address location failed, invalidate the
951+
/// cache and try again.
952+
std::optional<lldb::addr_t> RetryRead(Thread &thread,
953+
lldb::addr_t task_addr_location);
954+
941955
llvm::DenseMap<uint64_t, lldb::addr_t> m_tid_to_task_addr_location;
942956
};
943957

0 commit comments

Comments
 (0)