@@ -2317,14 +2317,15 @@ class CommandObjectLanguageSwiftTaskInfo final : public CommandObjectParsed {
23172317 }
23182318
23192319 TaskInspector task_inspector;
2320- auto task_addr_or_err = task_inspector.GetTaskAddrFromThreadLocalStorage (
2321- m_exe_ctx.GetThreadRef ());
2322- if (auto error = task_addr_or_err.takeError ()) {
2323- result.AppendError (toString (std::move (error)));
2320+ std::optional<lldb::addr_t > maybe_task_addr =
2321+ task_inspector.GetTaskAddrFromThreadLocalStorage (
2322+ m_exe_ctx.GetThreadRef ());
2323+ if (!task_addr) {
2324+ result.AppendError (" could find the task address" );
23242325 return ;
23252326 }
23262327
2327- task_addr = task_addr_or_err. get () ;
2328+ task_addr = *maybe_task_addr ;
23282329 }
23292330
23302331 auto ts_or_err = m_exe_ctx.GetTargetRef ().GetScratchTypeSystemForLanguage (
@@ -2915,19 +2916,6 @@ std::optional<lldb::addr_t> SwiftLanguageRuntime::TrySkipVirtualParentProlog(
29152916 return pc_value;
29162917}
29172918
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-
29312919// / Compute the location where the Task pointer for `real_thread` is stored by
29322920// / the runtime.
29332921static llvm::Expected<lldb::addr_t >
@@ -2955,48 +2943,155 @@ ComputeTaskAddrLocationFromThreadLocalStorage(Thread &real_thread) {
29552943#endif
29562944}
29572945
2958- llvm::Expected<lldb::addr_t >
2946+ // / Helper function to read all `pointers` from process memory at once.
2947+ // / Consumes any errors from the input by propagating them to the output.
2948+ static llvm::SmallVector<std::optional<addr_t >>
2949+ MultiReadPointers (Process &process,
2950+ llvm::MutableArrayRef<std::optional<addr_t >> maybe_pointers) {
2951+ llvm::SmallVector<std::optional<addr_t >> final_results;
2952+ llvm::SmallVector<addr_t > to_read;
2953+ final_results.reserve (maybe_pointers.size ());
2954+ to_read.reserve (maybe_pointers.size ());
2955+
2956+ // / Filter the input: propagate input errors directly to the output, forward
2957+ // / proper inputs to `to_read`.
2958+ for (std::optional<addr_t > &maybe_ptr : maybe_pointers) {
2959+ if (!maybe_ptr)
2960+ final_results.emplace_back (std::nullopt );
2961+ else {
2962+ final_results.push_back (LLDB_INVALID_ADDRESS);
2963+ to_read.push_back (*maybe_ptr);
2964+ }
2965+ }
2966+
2967+ // / TODO: convert this loop into a call to the vectorized memory read, once
2968+ // / that is available in Process.
2969+ llvm::SmallVector<std::optional<addr_t >> read_results;
2970+ for (addr_t pointer : to_read) {
2971+ Status status;
2972+ addr_t result = process.ReadPointerFromMemory (pointer, status);
2973+ if (status.Fail ())
2974+ read_results.push_back (std::nullopt );
2975+ else
2976+ read_results.push_back (result);
2977+ }
2978+
2979+ llvm::MutableArrayRef<std::optional<addr_t >> results_ref = read_results;
2980+
2981+ // Move the results in the slots not filled by errors from the input.
2982+ for (std::optional<addr_t > maybe_result : final_results)
2983+ if (maybe_result)
2984+ maybe_result = results_ref.consume_front ();
2985+
2986+ assert (results_ref.empty ());
2987+ return final_results;
2988+ }
2989+
2990+ // / Helper function to read `addr` from process memory. Errors in the input are
2991+ // / propagated to to the output.
2992+ static std::optional<addr_t > ReadPointer (Process &process,
2993+ std::optional<addr_t > addr) {
2994+ return MultiReadPointers (process, addr)[0 ];
2995+ }
2996+
2997+ std::optional<lldb::addr_t >
29592998TaskInspector::GetTaskAddrFromThreadLocalStorage (Thread &thread) {
2960- // Look through backing threads when inspecting TLS.
2961- Thread &real_thread =
2962- thread.GetBackingThread () ? *thread.GetBackingThread () : thread;
2999+ return GetTaskAddrFromThreadLocalStorage (&thread)[0 ];
3000+ }
3001+
3002+ llvm::SmallVector<std::optional<lldb::addr_t >>
3003+ TaskInspector::GetTaskAddrLocations (llvm::ArrayRef<Thread *> threads) {
3004+ llvm::SmallVector<std::optional<addr_t >> addr_locations;
3005+ addr_locations.reserve (threads.size ());
29633006
2964- if (auto it = m_tid_to_task_addr_location.find (real_thread.GetID ());
2965- it != m_tid_to_task_addr_location.end ()) {
3007+ for (auto [idx, thread] : llvm::enumerate (threads)) {
3008+ Thread &real_thread =
3009+ thread->GetBackingThread () ? *thread->GetBackingThread () : *thread;
3010+
3011+ auto it = m_tid_to_task_addr_location.find (real_thread.GetID ());
3012+ if (it != m_tid_to_task_addr_location.end ()) {
3013+ addr_locations.push_back (it->second );
29663014#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);
3015+ // In assert builds, check that caching did not produce incorrect results.
3016+ llvm::Expected<lldb::addr_t > task_addr_location =
3017+ ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
3018+ assert (task_addr_location);
3019+ assert (it->second == *task_addr_location);
29723020#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 (),
2980- " TaskInspector: evicted task location address due to "
2981- " invalid memory read: {0}" );
2982- }
2983-
2984- llvm::Expected<lldb::addr_t > task_addr_location =
3021+ continue ;
3022+ }
3023+ llvm::Expected<addr_t > addr_loc =
3024+ ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
3025+ if (!addr_loc) {
3026+ LLDB_LOG_ERROR (GetLog (LLDBLog::OS), addr_loc.takeError (),
3027+ " TaskInspector: failed to compute task address location "
3028+ " from TLS: {0}" );
3029+ addr_locations.push_back (std::nullopt );
3030+ } else
3031+ addr_locations.push_back (*addr_loc);
3032+ }
3033+ return addr_locations;
3034+ }
3035+
3036+ std::optional<addr_t > TaskInspector::UpdateTaskAddrLocationCacheAndRetryRead (
3037+ Thread &thread, addr_t task_addr_location,
3038+ std::optional<addr_t > read_result) {
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 (read_result) {
3045+ m_tid_to_task_addr_location[tid] = task_addr_location;
3046+ return read_result;
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+ return std::nullopt ;
3052+
3053+ LLDB_LOG (GetLog (LLDBLog::OS), " TaskInspector: evicted task location "
3054+ " address due to invalid memory read" );
3055+
3056+ // The cached address could not be loaded. "This should never happen", but
3057+ // recompute the address and try again for completeness.
3058+ llvm::Expected<addr_t > task_addr_loc =
29853059 ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
2986- if (!task_addr_location)
2987- return task_addr_location;
2988-
2989- llvm::Expected<lldb::addr_t > task_addr =
2990- ReadTaskAddr (*task_addr_location, *thread.GetProcess ());
2991-
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;
3060+ if (!task_addr_loc) {
3061+ LLDB_LOG_ERROR (GetLog (LLDBLog::OS), task_addr_loc.takeError (),
3062+ " TaskInspector: failed to compute task address location "
3063+ " from TLS: {0}" );
3064+ return std::nullopt ;
3065+ }
3066+
3067+ std::optional<addr_t > read_retry_result =
3068+ ReadPointer (*thread.GetProcess (), *task_addr_loc);
3069+ if (read_retry_result)
3070+ m_tid_to_task_addr_location[tid] = *task_addr_loc;
3071+ return read_retry_result;
3072+ }
3073+
3074+ llvm::SmallVector<std::optional<addr_t >>
3075+ TaskInspector::GetTaskAddrFromThreadLocalStorage (
3076+ llvm::ArrayRef<Thread *> threads) {
3077+ if (threads.empty ())
3078+ return {};
3079+
3080+ llvm::SmallVector<std::optional<addr_t >> addr_locations =
3081+ GetTaskAddrLocations (threads);
3082+
3083+ Process &process = *threads[0 ]->GetProcess ();
3084+ llvm::SmallVector<std::optional<addr_t >> mem_read_results =
3085+ MultiReadPointers (process, addr_locations);
3086+
3087+ for (auto [idx, thread] : llvm::enumerate (threads)) {
3088+ if (!addr_locations[idx])
3089+ continue ;
3090+ mem_read_results[idx] = UpdateTaskAddrLocationCacheAndRetryRead (
3091+ *thread, *addr_locations[idx], mem_read_results[idx]);
3092+ }
3093+
3094+ return mem_read_results;
30003095}
30013096
30023097namespace {
0 commit comments