@@ -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.
29532941static 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 >
29793010TaskInspector::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
30223108namespace {
0 commit comments