@@ -2915,19 +2915,6 @@ std::optional<lldb::addr_t> SwiftLanguageRuntime::TrySkipVirtualParentProlog(
29152915 return pc_value;
29162916}
29172917
2918- // / Attempts to read the memory location at `task_addr_location`, producing
2919- // / the Task pointer if possible.
2920- static llvm::Expected<lldb::addr_t >
2921- ReadTaskAddr (lldb::addr_t task_addr_location, Process &process) {
2922- Status status;
2923- addr_t task_addr = process.ReadPointerFromMemory (task_addr_location, status);
2924- if (status.Fail ())
2925- return llvm::joinErrors (
2926- llvm::createStringError (" could not get current task from thread" ),
2927- status.takeError ());
2928- return task_addr;
2929- }
2930-
29312918// / Compute the location where the Task pointer for `real_thread` is stored by
29322919// / the runtime.
29332920static llvm::Expected<lldb::addr_t >
@@ -2955,48 +2942,133 @@ ComputeTaskAddrLocationFromThreadLocalStorage(Thread &real_thread) {
29552942#endif
29562943}
29572944
2945+ // / Helper function to read all `pointers` from process memory at once.
2946+ // / Consumes any errors from the input by propagating them to the output.
2947+ static llvm::SmallVector<llvm::Expected<addr_t >> MultiReadPointers (
2948+ Process &process,
2949+ llvm::MutableArrayRef<llvm::Expected<addr_t >> maybe_pointers) {
2950+ llvm::SmallVector<llvm::Expected<addr_t >> final_results;
2951+ llvm::SmallVector<addr_t > to_read;
2952+
2953+ for (llvm::Expected<addr_t > &maybe_ptr : maybe_pointers) {
2954+ if (!maybe_ptr)
2955+ final_results.emplace_back (maybe_ptr.takeError ());
2956+ else {
2957+ final_results.push_back (LLDB_INVALID_ADDRESS);
2958+ to_read.push_back (*maybe_ptr);
2959+ }
2960+ }
2961+
2962+ // / TODO: convert this loop into a call to the vectorized memory read, once
2963+ // / that is available in Process.
2964+ llvm::SmallVector<llvm::Expected<addr_t >> read_results;
2965+ for (addr_t pointer : to_read) {
2966+ Status status;
2967+ addr_t result = process.ReadPointerFromMemory (pointer, status);
2968+ if (status.Fail ())
2969+ read_results.push_back (status.takeError ());
2970+ else
2971+ read_results.push_back (result);
2972+ }
2973+
2974+ llvm::MutableArrayRef<llvm::Expected<addr_t >> results_ref = read_results;
2975+ for (llvm::Expected<addr_t > &maybe_result : final_results) {
2976+ // Skip over errors propagated from the input.
2977+ if (!maybe_result)
2978+ continue ;
2979+ maybe_result = std::move (results_ref.consume_front ());
2980+ }
2981+
2982+ return final_results;
2983+ }
2984+
2985+ // / Helper function to read `addr` from process memory. Errors in the input are
2986+ // / propagated to to the output.
2987+ static llvm::Expected<addr_t > ReadPointer (Process &process,
2988+ llvm::Expected<addr_t > addr) {
2989+ auto read_result = MultiReadPointers (process, addr);
2990+ return std::move (read_result[0 ]);
2991+ }
2992+
29582993llvm::Expected<lldb::addr_t >
29592994TaskInspector::GetTaskAddrFromThreadLocalStorage (Thread &thread) {
2960- // Look through backing threads when inspecting TLS.
2961- Thread &real_thread =
2962- thread.GetBackingThread () ? *thread.GetBackingThread () : thread;
2995+ return std::move (GetTaskAddrFromThreadLocalStorage (&thread)[0 ]);
2996+ }
2997+
2998+ llvm::SmallVector<llvm::Expected<lldb::addr_t >>
2999+ TaskInspector::GetTaskAddrLocations (llvm::ArrayRef<Thread *> threads) {
3000+ llvm::SmallVector<llvm::Expected<addr_t >> addr_locations;
3001+ addr_locations.reserve (threads.size ());
29633002
2964- if (auto it = m_tid_to_task_addr_location.find (real_thread.GetID ());
2965- it != m_tid_to_task_addr_location.end ()) {
3003+ for (auto [idx, thread] : llvm::enumerate (threads)) {
3004+ Thread &real_thread =
3005+ thread->GetBackingThread () ? *thread->GetBackingThread () : *thread;
3006+
3007+ auto it = m_tid_to_task_addr_location.find (real_thread.GetID ());
3008+ if (it != m_tid_to_task_addr_location.end ()) {
3009+ addr_locations.push_back (it->second );
29663010#ifndef NDEBUG
2967- // In assert builds, check that caching did not produce incorrect results.
2968- llvm::Expected<lldb::addr_t > task_addr_location =
2969- ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
2970- assert (task_addr_location);
2971- assert (it->second == *task_addr_location);
3011+ // In assert builds, check that caching did not produce incorrect results.
3012+ llvm::Expected<lldb::addr_t > task_addr_location =
3013+ ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
3014+ assert (task_addr_location);
3015+ assert (it->second == *task_addr_location);
29723016#endif
2973- llvm::Expected<lldb::addr_t > task_addr =
2974- ReadTaskAddr (it->second , *thread.GetProcess ());
2975- if (task_addr)
2976- return task_addr;
2977- // If the cached task addr location became invalid, invalidate the cache.
2978- m_tid_to_task_addr_location.erase (it);
2979- LLDB_LOG_ERROR (GetLog (LLDBLog::OS), task_addr.takeError (),
3017+ continue ;
3018+ }
3019+ addr_locations.push_back (
3020+ ComputeTaskAddrLocationFromThreadLocalStorage (real_thread));
3021+ }
3022+ return addr_locations;
3023+ }
3024+
3025+ llvm::SmallVector<llvm::Expected<addr_t >>
3026+ TaskInspector::GetTaskAddrFromThreadLocalStorage (
3027+ llvm::ArrayRef<Thread *> threads) {
3028+ if (threads.empty ())
3029+ return {};
3030+
3031+ llvm::SmallVector<llvm::Expected<addr_t >> addr_locations =
3032+ GetTaskAddrLocations (threads);
3033+
3034+ Process &process = *threads[0 ]->GetProcess ();
3035+ llvm::SmallVector<llvm::Expected<addr_t >> mem_read_results =
3036+ MultiReadPointers (process, addr_locations);
3037+
3038+ for (auto [idx, thread] : llvm::enumerate (threads)) {
3039+ Thread &real_thread =
3040+ thread->GetBackingThread () ? *thread->GetBackingThread () : *thread;
3041+ user_id_t tid = real_thread.GetID ();
3042+
3043+ // If the read was successful, cache the address.
3044+ if (mem_read_results[idx]) {
3045+ m_tid_to_task_addr_location[tid] = *addr_locations[idx];
3046+ continue ;
3047+ }
3048+
3049+ // For unsuccessful reads whose address was not cached, don't try again.
3050+ if (!m_tid_to_task_addr_location.erase (tid))
3051+ continue ;
3052+
3053+ LLDB_LOG_ERROR (GetLog (LLDBLog::OS), mem_read_results[idx].takeError (),
29803054 " TaskInspector: evicted task location address due to "
29813055 " invalid memory read: {0}" );
2982- }
29833056
2984- llvm::Expected<lldb::addr_t > task_addr_location =
2985- ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
2986- if (!task_addr_location)
2987- return task_addr_location;
3057+ // The cached address could not be loaded. "This should never happen", but
3058+ // recompute the address and try again for completeness.
3059+ llvm::Expected<addr_t > task_addr_loc =
3060+ ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
3061+ if (!task_addr_loc) {
3062+ mem_read_results[idx] = std::move (task_addr_loc);
3063+ continue ;
3064+ }
29883065
2989- llvm::Expected<lldb::addr_t > task_addr =
2990- ReadTaskAddr (*task_addr_location, *thread.GetProcess ());
3066+ mem_read_results[idx] = ReadPointer (process, *task_addr_loc);
3067+ if (mem_read_results[idx])
3068+ m_tid_to_task_addr_location[tid] = *task_addr_loc;
3069+ }
29913070
2992- // If the read from this TLS address is successful, cache the TLS address.
2993- // Caching without a valid read is dangerous: earlier in the thread
2994- // lifetime, the result of GetExtendedInfo can be invalid.
2995- if (task_addr &&
2996- real_thread.GetProcess ()->GetTarget ().GetSwiftCacheTaskPointerLocation ())
2997- m_tid_to_task_addr_location.try_emplace (real_thread.GetID (),
2998- *task_addr_location);
2999- return task_addr;
3071+ return mem_read_results;
30003072}
30013073
30023074namespace {
0 commit comments