[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Fangrui Song via Phabricator via lldb-commits
MaskRay added a comment.

Hi! The added lines have some spaces at line ends. I think using 
`clang-format-diff.py` would remove them.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Med Ismail Bennani via Phabricator via lldb-commits
mib added a comment.

LGTM! Thanks Jim!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Jim Ingham via Phabricator via lldb-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG2b0c88654212: Refine the reporting mechanism for 
interruption. (authored by jingham).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/Target/TargetList.h
  lldb/source/API/SBFrame.cpp
  lldb/source/Commands/CommandCompletions.cpp
  lldb/source/Commands/CommandObjectFrame.cpp
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Commands/CommandObjectThread.cpp
  lldb/source/Core/Debugger.cpp
  lldb/source/Core/Module.cpp
  lldb/source/Interpreter/CommandInterpreter.cpp
  lldb/source/Target/StackFrameList.cpp
  lldb/source/Target/Target.cpp
  lldb/source/Target/TargetList.cpp

Index: lldb/source/Target/TargetList.cpp
===
--- lldb/source/Target/TargetList.cpp
+++ lldb/source/Target/TargetList.cpp
@@ -325,6 +325,7 @@
 return error;
   }
   target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+  debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
   if (user_exe_path_is_bundle)
 exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
@@ -336,6 +337,7 @@
 // No file was specified, just create an empty target with any arch if a
 // valid arch was specified
 target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   }
 
   if (!target_sp)
@@ -513,6 +515,7 @@
 void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
   lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
  "target already exists it the list");
+  UnregisterInProcessTarget(target_sp);
   m_target_list.push_back(std::move(target_sp));
   if (do_select)
 SetSelectedTargetInternal(m_target_list.size() - 1);
@@ -540,3 +543,35 @@
 m_selected_target_idx = 0;
   return GetTargetAtIndex(m_selected_target_idx);
 }
+
+bool TargetList::AnyTargetContainsModule(Module &module) {
+  std::lock_guard guard(m_target_list_mutex);
+  for (const auto &target_sp : m_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  for (const auto &target_sp: m_in_process_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  return false;
+}
+
+  void TargetList::RegisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+std::unordered_set::iterator iter;
+bool was_added;
+std::tie(iter, was_added) = m_in_process_target_list.insert(target_sp);
+assert(was_added && "Target pointer was left in the in-process map");
+  }
+  
+  void TargetList::UnregisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+bool was_present = m_in_process_target_list.erase(target_sp);
+assert(was_present && "Target pointer being removed was not registered");
+  }
+  
+  bool TargetList::IsTargetInProcess(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+return m_in_process_target_list.count(target_sp) == 1; 
+  }
Index: lldb/source/Target/Target.cpp
===
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -2236,7 +2236,6 @@
 // each library in parallel.
 if (GetPreloadSymbols())
   module_sp->PreloadSymbols();
-
 llvm::SmallVector replaced_modules;
 for (ModuleSP &old_module_sp : old_modules) {
   if (m_images.GetIndexForModule(old_module_sp.get()) !=
@@ -4205,6 +4204,10 @@
 }
 
 bool TargetProperties::GetPreloadSymbols() const {
+  if (INTERRUPT_REQUESTED(m_target->GetDebugger(), 
+  "Interrupted checking preload symbols")) {
+return false;
+  }
   const uint32_t idx = ePropertyPreloadSymbols;
   return GetPropertyAtIndexAs(
   idx, g_target_properties[idx].default_uint_value != 0);
Index: lldb/source/Target/StackFrameList.cpp
===
--- lldb/source/Target/StackFrameList.cpp
+++ lldb/source/Target/StackFrameList.cpp
@@ -509,11 +509,11 @@
 } else {
   // Check for interruption when building the frames.
   // Do the check in idx > 0 so that we'll always create a 0th frame.
-  if (allow_interrupt && dbg.InterruptRequested()) {
-Log *log = GetLog(LLDBLog::Host);
-LLDB_LOG(log, "Interrupted %s", __FUNCTION__);
-was_interrupted = true;
-break;
+  if (allow_interrupt 
+  && INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames",
+ m_frames.size())) {
+  was_interrupted = true;
+  break;
   }

[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Alex Langford via Phabricator via lldb-commits
bulbazord accepted this revision.
bulbazord added a comment.
This revision is now accepted and ready to land.

LGTM!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Jim Ingham via Phabricator via lldb-commits
jingham updated this revision to Diff 537908.
jingham added a comment.

Add some std;:move's, Jonas agrees all the cool kids are doing that these days.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/Target/TargetList.h
  lldb/source/API/SBFrame.cpp
  lldb/source/Commands/CommandCompletions.cpp
  lldb/source/Commands/CommandObjectFrame.cpp
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Commands/CommandObjectThread.cpp
  lldb/source/Core/Debugger.cpp
  lldb/source/Core/Module.cpp
  lldb/source/Interpreter/CommandInterpreter.cpp
  lldb/source/Target/StackFrameList.cpp
  lldb/source/Target/Target.cpp
  lldb/source/Target/TargetList.cpp

Index: lldb/source/Target/TargetList.cpp
===
--- lldb/source/Target/TargetList.cpp
+++ lldb/source/Target/TargetList.cpp
@@ -325,6 +325,7 @@
 return error;
   }
   target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+  debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
   if (user_exe_path_is_bundle)
 exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
@@ -336,6 +337,7 @@
 // No file was specified, just create an empty target with any arch if a
 // valid arch was specified
 target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   }
 
   if (!target_sp)
@@ -513,6 +515,7 @@
 void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
   lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
  "target already exists it the list");
+  UnregisterInProcessTarget(target_sp);
   m_target_list.push_back(std::move(target_sp));
   if (do_select)
 SetSelectedTargetInternal(m_target_list.size() - 1);
@@ -540,3 +543,35 @@
 m_selected_target_idx = 0;
   return GetTargetAtIndex(m_selected_target_idx);
 }
+
+bool TargetList::AnyTargetContainsModule(Module &module) {
+  std::lock_guard guard(m_target_list_mutex);
+  for (const auto &target_sp : m_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  for (const auto &target_sp: m_in_process_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  return false;
+}
+
+  void TargetList::RegisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+std::unordered_set::iterator iter;
+bool was_added;
+std::tie(iter, was_added) = m_in_process_target_list.insert(target_sp);
+assert(was_added && "Target pointer was left in the in-process map");
+  }
+  
+  void TargetList::UnregisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+bool was_present = m_in_process_target_list.erase(target_sp);
+assert(was_present && "Target pointer being removed was not registered");
+  }
+  
+  bool TargetList::IsTargetInProcess(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+return m_in_process_target_list.count(target_sp) == 1; 
+  }
Index: lldb/source/Target/Target.cpp
===
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -2236,7 +2236,6 @@
 // each library in parallel.
 if (GetPreloadSymbols())
   module_sp->PreloadSymbols();
-
 llvm::SmallVector replaced_modules;
 for (ModuleSP &old_module_sp : old_modules) {
   if (m_images.GetIndexForModule(old_module_sp.get()) !=
@@ -4205,6 +4204,10 @@
 }
 
 bool TargetProperties::GetPreloadSymbols() const {
+  if (INTERRUPT_REQUESTED(m_target->GetDebugger(), 
+  "Interrupted checking preload symbols")) {
+return false;
+  }
   const uint32_t idx = ePropertyPreloadSymbols;
   return GetPropertyAtIndexAs(
   idx, g_target_properties[idx].default_uint_value != 0);
Index: lldb/source/Target/StackFrameList.cpp
===
--- lldb/source/Target/StackFrameList.cpp
+++ lldb/source/Target/StackFrameList.cpp
@@ -509,11 +509,11 @@
 } else {
   // Check for interruption when building the frames.
   // Do the check in idx > 0 so that we'll always create a 0th frame.
-  if (allow_interrupt && dbg.InterruptRequested()) {
-Log *log = GetLog(LLDBLog::Host);
-LLDB_LOG(log, "Interrupted %s", __FUNCTION__);
-was_interrupted = true;
-break;
+  if (allow_interrupt 
+  && INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames",
+ m_frames.size())) {
+  was_interrupted = true;
+  break;
   }
 
   const bool success

[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Alex Langford via Phabricator via lldb-commits
bulbazord added inline comments.



Comment at: lldb/include/lldb/Core/Debugger.h:455-456
+InterruptionReport(std::string function_name, std::string description) :
+m_function_name(function_name), 
+m_description(description),
+m_interrupt_time(std::chrono::system_clock::now()),

jingham wrote:
> bulbazord wrote:
> > jingham wrote:
> > > bulbazord wrote:
> > > > To avoid some unnecessary copies
> > > > 
> > > > Could also do what Ismail is suggesting.
> > > This is a local that is copied to an ivar and never used again.  Do I 
> > > really have to put move in there explicitly for the optimizer to know it 
> > > can reuse the value?
> > Yes. I created a simple example on Godbolt: https://godbolt.org/z/G4ej76Enn
> > 
> > Observe that the constructor in the example invokes the `std::string` copy 
> > constructor. Add a `std::move` and it then invokes the move constructor.
> Thanks for the example, that was interesting.  
> 
> Note however that in your example, you the flags you specified were 
> `-std=c++17` so that was an unoptimized build.  That's expected, unoptimized 
> builds are supposed to be as literal as they can be.  If you instead use the 
> same example with `-std=c++17 -O3` you won't see any copy constructors.  I 
> don't 100% mind putting this std::move in, but it seems noisy to decorate up 
> your code with hints that the optimizer can figure out on its own.
You're right that I did not consider higher optimization levels there. That 
being said, I believe this is a matter of language semantics and not 
optimization level. I've created a slightly more complex example to illustrate: 
https://godbolt.org/z/naMTcd7Ev

In this other example, I have passed `-O3`. You'll notice that in the emitted 
constructor code there are 2 calls to `operator new`. If you add `std::move` 
for both of the parameters of the constructor, both of these allocations go 
away and the generated code becomes ~60% smaller. Even with optimization 
involved, the compiler can only optimize so much without breaking semantics.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Jim Ingham via Phabricator via lldb-commits
jingham added inline comments.



Comment at: lldb/include/lldb/Core/Debugger.h:455-456
+InterruptionReport(std::string function_name, std::string description) :
+m_function_name(function_name), 
+m_description(description),
+m_interrupt_time(std::chrono::system_clock::now()),

bulbazord wrote:
> jingham wrote:
> > bulbazord wrote:
> > > To avoid some unnecessary copies
> > > 
> > > Could also do what Ismail is suggesting.
> > This is a local that is copied to an ivar and never used again.  Do I 
> > really have to put move in there explicitly for the optimizer to know it 
> > can reuse the value?
> Yes. I created a simple example on Godbolt: https://godbolt.org/z/G4ej76Enn
> 
> Observe that the constructor in the example invokes the `std::string` copy 
> constructor. Add a `std::move` and it then invokes the move constructor.
Thanks for the example, that was interesting.  

Note however that in your example, you the flags you specified were 
`-std=c++17` so that was an unoptimized build.  That's expected, unoptimized 
builds are supposed to be as literal as they can be.  If you instead use the 
same example with `-std=c++17 -O3` you won't see any copy constructors.  I 
don't 100% mind putting this std::move in, but it seems noisy to decorate up 
your code with hints that the optimizer can figure out on its own.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-06 Thread Alex Langford via Phabricator via lldb-commits
bulbazord added inline comments.



Comment at: lldb/include/lldb/Core/Debugger.h:430-431
+  template 
+  bool InterruptRequested(const char *cur_func, 
+  const char *formatv, Args &&... args) {
+bool ret_val = InterruptRequested();

jingham wrote:
> bulbazord wrote:
> > I think it would make more sense to have `cur_func` and `formatv` be of 
> > type `llvm::StringRef`. Concretely, if you construct a `std::string` from 
> > `nullptr` (like you're doing below when you make an InterruptionReport 
> > object), you will crash.
> > 
> > I know the recommendation is to use `INTERRUPT_REQUESTED` instead of 
> > filling this manually, but inevitably somebody will go against the advice 
> > and make a mistake.
> > I think it would make more sense to have `cur_func` and `formatv` be of 
> > type `llvm::StringRef`. Concretely, if you construct a `std::string` from 
> > `nullptr` (like you're doing below when you make an InterruptionReport 
> > object), you will crash.
> > 
> > I know the recommendation is to use `INTERRUPT_REQUESTED` instead of 
> > filling this manually, but inevitably somebody will go against the advice 
> > and make a mistake.
> 
> I don't see how I can make the formatv option a StringRef.  The llvm::formatv 
> API only offers a version that takes a `const char *`.  Anyway, these are 
> formatv strings, they are almost universally going to be const strings.  
> Turning them into llvm::StringRef's and back out again to use in 
> llvm::formatv seems odd.
> 
> But you are right, we should protect against someone passing in a null 
> pointer for the function or format to InterruptRequested.   Since this is 
> just logging, an assert seems overkill, I'll just add null pointer checks 
> here and turn them into "UNKNOWN FUNCTION" and "Unknown message".
Oh... so `llvm::formatv` does take a `const char *`... My bad there, that makes 
sense, no need to change the type of `format` then.

Otherwise, I'm satisfied with the safety checks.



Comment at: lldb/include/lldb/Core/Debugger.h:455-456
+InterruptionReport(std::string function_name, std::string description) :
+m_function_name(function_name), 
+m_description(description),
+m_interrupt_time(std::chrono::system_clock::now()),

jingham wrote:
> bulbazord wrote:
> > To avoid some unnecessary copies
> > 
> > Could also do what Ismail is suggesting.
> This is a local that is copied to an ivar and never used again.  Do I really 
> have to put move in there explicitly for the optimizer to know it can reuse 
> the value?
Yes. I created a simple example on Godbolt: https://godbolt.org/z/G4ej76Enn

Observe that the constructor in the example invokes the `std::string` copy 
constructor. Add a `std::move` and it then invokes the move constructor.



Comment at: lldb/include/lldb/Core/Debugger.h:465
+  InterruptionReport(std::string function_name,
+  const char *format, Args &&... args) :
+InterruptionReport(function_name, llvm::formatv(format, 
std::forward(args)...)) {}

bulbazord wrote:
> since we're passing `format` to `formatv`, I think it would make sense for 
> its type to be `llvm::StringRef` up-front here.
As you've pointed out above, `formatv` takes a `const char *` so ignore this.



Comment at: lldb/source/Core/Debugger.cpp:1280
+const llvm::formatv_object_base &payload) :  
+m_function_name(function_name), 
+m_interrupt_time(std::chrono::system_clock::now()),

You'll also want to `std::move(function_name)` here too, I think.



Comment at: lldb/source/Target/TargetList.cpp:518
  "target already exists it the list");
+  UnregisterInProcessTarget(target_sp.get());
   m_target_list.push_back(std::move(target_sp));

jingham wrote:
> bulbazord wrote:
> > I'm somewhat puzzled by this. Why are we unregistering the target in 
> > `AddTargetInternal` when we're registering it in `CreateTargetInternal`? 
> > Maybe I don't understand the intent behind 
> > `{Register,Unregister}InProcessTarget`.
> The point behind this is someone says "make me a target" and then in the 
> process of making the target, the Target code does something slow (e.g. look 
> for external debug files) that we want to interrupt.  So we need a way for 
> the debugger to find the "in the process of being made" Targets.  
> 
>  "AddTargetInternal" is the API where the target gets added to the Debugger's 
> TargetList, so after that method has run we will find the target in the 
> regular TargetList.  But between CreateTargetInternal and AddTargetInternal, 
> that target isn't stored anywhere that the Debugger knows how to query.  I 
> added this list to hold the targets that are in the process of getting made, 
> before they get added to the Debugger's TargetList.
Gotcha, that makes sense. Thanks for explaining!


Repository:
  rG LLVM

[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Jim Ingham via Phabricator via lldb-commits
jingham added inline comments.



Comment at: lldb/include/lldb/Core/Debugger.h:455-456
+InterruptionReport(std::string function_name, std::string description) :
+m_function_name(function_name), 
+m_description(description),
+m_interrupt_time(std::chrono::system_clock::now()),

bulbazord wrote:
> To avoid some unnecessary copies
> 
> Could also do what Ismail is suggesting.
This is a local that is copied to an ivar and never used again.  Do I really 
have to put move in there explicitly for the optimizer to know it can reuse the 
value?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Jim Ingham via Phabricator via lldb-commits
jingham updated this revision to Diff 537551.
jingham added a comment.

Protect InterruptRequested from null function & format strings.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/Target/TargetList.h
  lldb/source/API/SBFrame.cpp
  lldb/source/Commands/CommandCompletions.cpp
  lldb/source/Commands/CommandObjectFrame.cpp
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Commands/CommandObjectThread.cpp
  lldb/source/Core/Debugger.cpp
  lldb/source/Core/Module.cpp
  lldb/source/Interpreter/CommandInterpreter.cpp
  lldb/source/Target/StackFrameList.cpp
  lldb/source/Target/Target.cpp
  lldb/source/Target/TargetList.cpp

Index: lldb/source/Target/TargetList.cpp
===
--- lldb/source/Target/TargetList.cpp
+++ lldb/source/Target/TargetList.cpp
@@ -325,6 +325,7 @@
 return error;
   }
   target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+  debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
   if (user_exe_path_is_bundle)
 exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
@@ -336,6 +337,7 @@
 // No file was specified, just create an empty target with any arch if a
 // valid arch was specified
 target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   }
 
   if (!target_sp)
@@ -513,6 +515,7 @@
 void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
   lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
  "target already exists it the list");
+  UnregisterInProcessTarget(target_sp);
   m_target_list.push_back(std::move(target_sp));
   if (do_select)
 SetSelectedTargetInternal(m_target_list.size() - 1);
@@ -540,3 +543,35 @@
 m_selected_target_idx = 0;
   return GetTargetAtIndex(m_selected_target_idx);
 }
+
+bool TargetList::AnyTargetContainsModule(Module &module) {
+  std::lock_guard guard(m_target_list_mutex);
+  for (const auto &target_sp : m_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  for (const auto &target_sp: m_in_process_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  return false;
+}
+
+  void TargetList::RegisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+std::unordered_set::iterator iter;
+bool was_added;
+std::tie(iter, was_added) = m_in_process_target_list.insert(target_sp);
+assert(was_added && "Target pointer was left in the in-process map");
+  }
+  
+  void TargetList::UnregisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+bool was_present = m_in_process_target_list.erase(target_sp);
+assert(was_present && "Target pointer being removed was not registered");
+  }
+  
+  bool TargetList::IsTargetInProcess(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+return m_in_process_target_list.count(target_sp) == 1; 
+  }
Index: lldb/source/Target/Target.cpp
===
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -2236,7 +2236,6 @@
 // each library in parallel.
 if (GetPreloadSymbols())
   module_sp->PreloadSymbols();
-
 llvm::SmallVector replaced_modules;
 for (ModuleSP &old_module_sp : old_modules) {
   if (m_images.GetIndexForModule(old_module_sp.get()) !=
@@ -4205,6 +4204,10 @@
 }
 
 bool TargetProperties::GetPreloadSymbols() const {
+  if (INTERRUPT_REQUESTED(m_target->GetDebugger(), 
+  "Interrupted checking preload symbols")) {
+return false;
+  }
   const uint32_t idx = ePropertyPreloadSymbols;
   return GetPropertyAtIndexAs(
   idx, g_target_properties[idx].default_uint_value != 0);
Index: lldb/source/Target/StackFrameList.cpp
===
--- lldb/source/Target/StackFrameList.cpp
+++ lldb/source/Target/StackFrameList.cpp
@@ -509,11 +509,11 @@
 } else {
   // Check for interruption when building the frames.
   // Do the check in idx > 0 so that we'll always create a 0th frame.
-  if (allow_interrupt && dbg.InterruptRequested()) {
-Log *log = GetLog(LLDBLog::Host);
-LLDB_LOG(log, "Interrupted %s", __FUNCTION__);
-was_interrupted = true;
-break;
+  if (allow_interrupt 
+  && INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames",
+ m_frames.size())) {
+  was_interrupted = true;
+  break;
   }
 
   const bool success =
@@ -965,11 +9

[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Jim Ingham via Phabricator via lldb-commits
jingham added inline comments.



Comment at: lldb/include/lldb/Core/Debugger.h:430-431
+  template 
+  bool InterruptRequested(const char *cur_func, 
+  const char *formatv, Args &&... args) {
+bool ret_val = InterruptRequested();

bulbazord wrote:
> I think it would make more sense to have `cur_func` and `formatv` be of type 
> `llvm::StringRef`. Concretely, if you construct a `std::string` from 
> `nullptr` (like you're doing below when you make an InterruptionReport 
> object), you will crash.
> 
> I know the recommendation is to use `INTERRUPT_REQUESTED` instead of filling 
> this manually, but inevitably somebody will go against the advice and make a 
> mistake.
> I think it would make more sense to have `cur_func` and `formatv` be of type 
> `llvm::StringRef`. Concretely, if you construct a `std::string` from 
> `nullptr` (like you're doing below when you make an InterruptionReport 
> object), you will crash.
> 
> I know the recommendation is to use `INTERRUPT_REQUESTED` instead of filling 
> this manually, but inevitably somebody will go against the advice and make a 
> mistake.

I don't see how I can make the formatv option a StringRef.  The llvm::formatv 
API only offers a version that takes a `const char *`.  Anyway, these are 
formatv strings, they are almost universally going to be const strings.  
Turning them into llvm::StringRef's and back out again to use in llvm::formatv 
seems odd.

But you are right, we should protect against someone passing in a null pointer 
for the function or format to InterruptRequested.   Since this is just logging, 
an assert seems overkill, I'll just add null pointer checks here and turn them 
into "UNKNOWN FUNCTION" and "Unknown message".



Comment at: lldb/source/API/SBFrame.cpp:57-58
 
+#include 
+
 using namespace lldb;

mib wrote:
> bulbazord wrote:
> > What is this used for?
> Is this still necessary ?
Not sure what you are asking here.  We use StackFrameSP w/o saying 
lldb::StackFrameSP and we use VariableList for instance rather than 
lldb_private::VariableList.  We could remove the using statements here but 
that's not how we do it in general.  In some cases we don't do `using namespace 
lldb` but that's mostly in files that use clang API's heavily since those 
conflict with some clang type names and it was good to be explicit there.  But 
I don't think we want to be verbose like that in the SB files.



Comment at: lldb/source/Target/StackFrameList.cpp:31
 #include 
+#include 
 

bulbazord wrote:
> Where is this used?
Dunno, but this seems more like an orthogonal cleanup unrelated to the current 
patch.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Jim Ingham via Phabricator via lldb-commits
jingham updated this revision to Diff 537544.
jingham added a comment.

Address review comments:

Made the in_process target list shared pointers.

Removed sstream includes.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/Target/TargetList.h
  lldb/source/API/SBFrame.cpp
  lldb/source/Commands/CommandCompletions.cpp
  lldb/source/Commands/CommandObjectFrame.cpp
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Commands/CommandObjectThread.cpp
  lldb/source/Core/Debugger.cpp
  lldb/source/Core/Module.cpp
  lldb/source/Interpreter/CommandInterpreter.cpp
  lldb/source/Target/StackFrameList.cpp
  lldb/source/Target/Target.cpp
  lldb/source/Target/TargetList.cpp

Index: lldb/source/Target/TargetList.cpp
===
--- lldb/source/Target/TargetList.cpp
+++ lldb/source/Target/TargetList.cpp
@@ -325,6 +325,7 @@
 return error;
   }
   target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+  debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
   if (user_exe_path_is_bundle)
 exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
@@ -336,6 +337,7 @@
 // No file was specified, just create an empty target with any arch if a
 // valid arch was specified
 target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+debugger.GetTargetList().RegisterInProcessTarget(target_sp);
   }
 
   if (!target_sp)
@@ -513,6 +515,7 @@
 void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
   lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
  "target already exists it the list");
+  UnregisterInProcessTarget(target_sp);
   m_target_list.push_back(std::move(target_sp));
   if (do_select)
 SetSelectedTargetInternal(m_target_list.size() - 1);
@@ -540,3 +543,35 @@
 m_selected_target_idx = 0;
   return GetTargetAtIndex(m_selected_target_idx);
 }
+
+bool TargetList::AnyTargetContainsModule(Module &module) {
+  std::lock_guard guard(m_target_list_mutex);
+  for (const auto &target_sp : m_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  for (const auto &target_sp: m_in_process_target_list) {
+if (target_sp->GetImages().FindModule(&module))
+  return true;
+  }
+  return false;
+}
+
+  void TargetList::RegisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+std::unordered_set::iterator iter;
+bool was_added;
+std::tie(iter, was_added) = m_in_process_target_list.insert(target_sp);
+assert(was_added && "Target pointer was left in the in-process map");
+  }
+  
+  void TargetList::UnregisterInProcessTarget(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+bool was_present = m_in_process_target_list.erase(target_sp);
+assert(was_present && "Target pointer being removed was not registered");
+  }
+  
+  bool TargetList::IsTargetInProcess(TargetSP target_sp) {
+std::lock_guard guard(m_target_list_mutex);
+return m_in_process_target_list.count(target_sp) == 1; 
+  }
Index: lldb/source/Target/Target.cpp
===
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -2236,7 +2236,6 @@
 // each library in parallel.
 if (GetPreloadSymbols())
   module_sp->PreloadSymbols();
-
 llvm::SmallVector replaced_modules;
 for (ModuleSP &old_module_sp : old_modules) {
   if (m_images.GetIndexForModule(old_module_sp.get()) !=
@@ -4205,6 +4204,10 @@
 }
 
 bool TargetProperties::GetPreloadSymbols() const {
+  if (INTERRUPT_REQUESTED(m_target->GetDebugger(), 
+  "Interrupted checking preload symbols")) {
+return false;
+  }
   const uint32_t idx = ePropertyPreloadSymbols;
   return GetPropertyAtIndexAs(
   idx, g_target_properties[idx].default_uint_value != 0);
Index: lldb/source/Target/StackFrameList.cpp
===
--- lldb/source/Target/StackFrameList.cpp
+++ lldb/source/Target/StackFrameList.cpp
@@ -509,11 +509,11 @@
 } else {
   // Check for interruption when building the frames.
   // Do the check in idx > 0 so that we'll always create a 0th frame.
-  if (allow_interrupt && dbg.InterruptRequested()) {
-Log *log = GetLog(LLDBLog::Host);
-LLDB_LOG(log, "Interrupted %s", __FUNCTION__);
-was_interrupted = true;
-break;
+  if (allow_interrupt 
+  && INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames",
+ m_frames.size())) {
+  was_interrupted = true;
+  break;
   }
 
   

[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Jim Ingham via Phabricator via lldb-commits
jingham added inline comments.



Comment at: lldb/include/lldb/Core/Debugger.h:435-436
+  ReportInterruption(InterruptionReport(cur_func, 
+llvm::formatv(formatv, 
+std::forward(args)...)));
+}

mib wrote:
> If you use `LLVM_PRETTY_FUNCTION` you won't need this.
I'm not sure I understand how you want to use LLVM_PRETTY_FUNCTION.  From what 
I can tell, LLVM_PRETTY_FUNCTION prints something that looks like the function 
invocation as written.  But ReportInterruption and the associated macros 
provide a formatv API.



Comment at: lldb/source/Target/TargetList.cpp:518
  "target already exists it the list");
+  UnregisterInProcessTarget(target_sp.get());
   m_target_list.push_back(std::move(target_sp));

bulbazord wrote:
> I'm somewhat puzzled by this. Why are we unregistering the target in 
> `AddTargetInternal` when we're registering it in `CreateTargetInternal`? 
> Maybe I don't understand the intent behind 
> `{Register,Unregister}InProcessTarget`.
The point behind this is someone says "make me a target" and then in the 
process of making the target, the Target code does something slow (e.g. look 
for external debug files) that we want to interrupt.  So we need a way for the 
debugger to find the "in the process of being made" Targets.  

 "AddTargetInternal" is the API where the target gets added to the Debugger's 
TargetList, so after that method has run we will find the target in the regular 
TargetList.  But between CreateTargetInternal and AddTargetInternal, that 
target isn't stored anywhere that the Debugger knows how to query.  I added 
this list to hold the targets that are in the process of getting made, before 
they get added to the Debugger's TargetList.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Med Ismail Bennani via Phabricator via lldb-commits
mib added a comment.

I had an offline chat with Jim and I misunderstood originally, what he was 
trying to achieve with the `InterruptionReport:: m_function_name` so my 
suggestion of using `LLVM_PRETTY_FUNCTION` doesn't actually work here.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Alex Langford via Phabricator via lldb-commits
bulbazord added a comment.

I really like the change to the interface, I especially like that it can report 
what was interrupted and how much work actually done. I had a lot of the same 
feedback as Ismail but also had some questions to help me understand all the 
details.




Comment at: lldb/include/lldb/Core/Debugger.h:430-431
+  template 
+  bool InterruptRequested(const char *cur_func, 
+  const char *formatv, Args &&... args) {
+bool ret_val = InterruptRequested();

I think it would make more sense to have `cur_func` and `formatv` be of type 
`llvm::StringRef`. Concretely, if you construct a `std::string` from `nullptr` 
(like you're doing below when you make an InterruptionReport object), you will 
crash.

I know the recommendation is to use `INTERRUPT_REQUESTED` instead of filling 
this manually, but inevitably somebody will go against the advice and make a 
mistake.



Comment at: lldb/include/lldb/Core/Debugger.h:446
+#define INTERRUPT_REQUESTED(debugger, ...) \
+(debugger).InterruptRequested(__func__, __VA_ARGS__)
+

mib wrote:
> You could use `LLVM_PRETTY_FUNCTION` which will give you both the function 
> signature and the argument well formatted.
+1



Comment at: lldb/include/lldb/Core/Debugger.h:455-456
+InterruptionReport(std::string function_name, std::string description) :
+m_function_name(function_name), 
+m_description(description),
+m_interrupt_time(std::chrono::system_clock::now()),

To avoid some unnecessary copies

Could also do what Ismail is suggesting.



Comment at: lldb/include/lldb/Core/Debugger.h:465
+  InterruptionReport(std::string function_name,
+  const char *format, Args &&... args) :
+InterruptionReport(function_name, llvm::formatv(format, 
std::forward(args)...)) {}

since we're passing `format` to `formatv`, I think it would make sense for its 
type to be `llvm::StringRef` up-front here.



Comment at: lldb/include/lldb/Target/TargetList.h:191
+  ///  these not yet added target, but for interruption purposes, we might
+  ///  need to ask whetehr this target contains this module. 
+  bool AnyTargetContainsModule(Module *module);





Comment at: lldb/include/lldb/Target/TargetList.h:192
+  ///  need to ask whetehr this target contains this module. 
+  bool AnyTargetContainsModule(Module *module);
 

mib wrote:
> Can the module be null ? If not, can we pass a reference instead of a raw 
> pointer here ?
+1

Alternatively, if these are being pulled out of shared pointers, pass the 
shared pointer directly so we can avoid the issue of dangling raw pointers if 
the module ever is freed by the shared pointer.



Comment at: lldb/include/lldb/Target/TargetList.h:200
   collection m_target_list;
+  std::unordered_set m_in_process_target_list;
   mutable std::recursive_mutex m_target_list_mutex;

mib wrote:
> Same question as above, can any of the `in_process_target` be null ? If not, 
> lets make it a `Target&`
+1

Same as above, let's not circumvent shared pointer semantics since we're 
storing references/pointers to these objects.



Comment at: lldb/include/lldb/Target/TargetList.h:216-221
+  void RegisterInProcessTarget(Target *target);
+  
+  void UnregisterInProcessTarget(Target *target);
+  
+  bool IsTargetInProcess(Target *target);
+  

mib wrote:
> ditto
Same as my comment above.



Comment at: lldb/source/API/SBFrame.cpp:57
 
+#include 
+

What is this used for?



Comment at: lldb/source/Commands/CommandObjectTarget.cpp:67-68
 
+#include 
+
 

mib wrote:
> Is this still necessary ?
Where is this used?



Comment at: lldb/source/Core/Debugger.cpp:1266-1267
 
-bool Debugger::InterruptRequested() {
+bool Debugger::InterruptRequested() 
+{
   // This is the one we should call internally.  This will return true either

Did clang-format give this to you?



Comment at: lldb/source/Core/Debugger.cpp:1291-1292
+// For now, just log the description:
+  Log *log = GetLog(LLDBLog::Host);
+  LLDB_LOG(log, "Interruption: {0}", report.m_description);
+}





Comment at: lldb/source/Core/Module.cpp:1075
+for (auto debugger_sp : interruptors) {
+  REPORT_INTERRUPTION(*(debugger_sp.get()), 
+  "Interrupted fetching symbols for module {0}", 





Comment at: lldb/source/Core/Module.cpp:1077
+  "Interrupted fetching symbols for module {0}", 
+  this->GetFileSpec());
+}

I don't think you need to specify `this->`?



Comment at: lldb/source/Ta

[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Med Ismail Bennani via Phabricator via lldb-commits
mib added a comment.

This looks very cool! I left "a few" comments on how I think we can simplify 
this patch, and also had some remarks regarding the `in_process_target` sanity 
checks.




Comment at: lldb/include/lldb/Core/Debugger.h:435-436
+  ReportInterruption(InterruptionReport(cur_func, 
+llvm::formatv(formatv, 
+std::forward(args)...)));
+}

If you use `LLVM_PRETTY_FUNCTION` you won't need this.



Comment at: lldb/include/lldb/Core/Debugger.h:446
+#define INTERRUPT_REQUESTED(debugger, ...) \
+(debugger).InterruptRequested(__func__, __VA_ARGS__)
+

You could use `LLVM_PRETTY_FUNCTION` which will give you both the function 
signature and the argument well formatted.



Comment at: lldb/include/lldb/Core/Debugger.h:454
+  public:
+InterruptionReport(std::string function_name, std::string description) :
+m_function_name(function_name), 





Comment at: lldb/include/lldb/Core/Debugger.h:460-468
+InterruptionReport(std::string function_name, 
+const llvm::formatv_object_base &payload);
+
+  template 
+  InterruptionReport(std::string function_name,
+  const char *format, Args &&... args) :
+InterruptionReport(function_name, llvm::formatv(format, 
std::forward(args)...)) {}

Using `LLVM_PRETTY_FUNCTION` we can simplify the class by removing the variadic 
constructors and replace to `std::string` with a `llvm::StringLiteral`



Comment at: lldb/include/lldb/Target/TargetList.h:192
+  ///  need to ask whetehr this target contains this module. 
+  bool AnyTargetContainsModule(Module *module);
 

Can the module be null ? If not, can we pass a reference instead of a raw 
pointer here ?



Comment at: lldb/include/lldb/Target/TargetList.h:200
   collection m_target_list;
+  std::unordered_set m_in_process_target_list;
   mutable std::recursive_mutex m_target_list_mutex;

Same question as above, can any of the `in_process_target` be null ? If not, 
lets make it a `Target&`



Comment at: lldb/include/lldb/Target/TargetList.h:216
 
+  void RegisterInProcessTarget(Target *target);
+  

ditto



Comment at: lldb/include/lldb/Target/TargetList.h:218
+  
+  void UnregisterInProcessTarget(Target *target);
+  

ditto



Comment at: lldb/include/lldb/Target/TargetList.h:220
+  
+  bool IsTargetInProcess(Target *target);
+  

ditto



Comment at: lldb/source/API/SBFrame.cpp:57-58
 
+#include 
+
 using namespace lldb;

Is this still necessary ?



Comment at: lldb/source/Commands/CommandObjectTarget.cpp:67-68
 
+#include 
+
 

Is this still necessary ?



Comment at: lldb/source/Core/Debugger.cpp:1279-1287
+Debugger::InterruptionReport::InterruptionReport(std::string function_name, 
+const llvm::formatv_object_base &payload) :  
+m_function_name(function_name), 
+m_interrupt_time(std::chrono::system_clock::now()),
+m_thread_id(llvm::get_threadid())
+{
+  llvm::raw_string_ostream desc(m_description);

You can get rid of this is you use `LLVM_PRETTY_FUNCTION`.



Comment at: lldb/source/Core/Debugger.cpp:1289-1293
+void Debugger::ReportInterruption(const InterruptionReport &report) {
+// For now, just log the description:
+  Log *log = GetLog(LLDBLog::Host);
+  LLDB_LOG(log, "Interruption: {0}", report.m_description);
+}

It would be nice if `InterruptionReport` had a `Dump` method.



Comment at: lldb/source/Core/Module.cpp:1071-1072
 if (!m_did_load_symfile.load() && can_create) {
+  Debugger::DebuggerList interruptors 
+  = DebuggersOwningModuleRequestingInterruption(this);
+  if (!interruptors.empty()) {

You can get the Module reference by dereferencing `this`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154542/new/

https://reviews.llvm.org/D154542

___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [PATCH] D154542: Further refinements on reporting interruption in lldb

2023-07-05 Thread Jim Ingham via Phabricator via lldb-commits
jingham created this revision.
jingham added reviewers: JDevlieghere, mib, bulbazord, labath.
Herald added a project: All.
jingham requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

This  patch enhances the interruption features I added a little while back.  
There are two main changes.  The main one here is that I made a nicer interface 
to reporting interruption events.  I also added a way to ask a debugger if it 
was using a Module, so that we can query for interruption in Module code where 
we don't have access to a debugger.  I used that to support interrupting debug 
info reading on a per-module basis - since that's a long-running but - at least 
on a module boundary - resumable operation.

The current method of checking "Does this module one belong to a debugger 
requesting interruption" is quick and dirty here.  IMO, a better solution would 
be to have Modules keep a list of the Debuggers (or maybe Targets) using them.  
But we should figure out all the ways we want to use that and design something 
nice for the purpose.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154542

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/Target/TargetList.h
  lldb/source/API/SBFrame.cpp
  lldb/source/Commands/CommandCompletions.cpp
  lldb/source/Commands/CommandObjectFrame.cpp
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Commands/CommandObjectThread.cpp
  lldb/source/Core/Debugger.cpp
  lldb/source/Core/Module.cpp
  lldb/source/Interpreter/CommandInterpreter.cpp
  lldb/source/Target/StackFrameList.cpp
  lldb/source/Target/Target.cpp
  lldb/source/Target/TargetList.cpp

Index: lldb/source/Target/TargetList.cpp
===
--- lldb/source/Target/TargetList.cpp
+++ lldb/source/Target/TargetList.cpp
@@ -325,6 +325,7 @@
 return error;
   }
   target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+  debugger.GetTargetList().RegisterInProcessTarget(target_sp.get());
   target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
   if (user_exe_path_is_bundle)
 exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
@@ -336,6 +337,7 @@
 // No file was specified, just create an empty target with any arch if a
 // valid arch was specified
 target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
+debugger.GetTargetList().RegisterInProcessTarget(target_sp.get());
   }
 
   if (!target_sp)
@@ -513,6 +515,7 @@
 void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
   lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
  "target already exists it the list");
+  UnregisterInProcessTarget(target_sp.get());
   m_target_list.push_back(std::move(target_sp));
   if (do_select)
 SetSelectedTargetInternal(m_target_list.size() - 1);
@@ -540,3 +543,35 @@
 m_selected_target_idx = 0;
   return GetTargetAtIndex(m_selected_target_idx);
 }
+
+bool TargetList::AnyTargetContainsModule(Module *module) {
+  std::lock_guard guard(m_target_list_mutex);
+  for (const auto &target_sp : m_target_list) {
+if (target_sp->GetImages().FindModule(module))
+  return true;
+  }
+  for (const auto target: m_in_process_target_list) {
+if (target->GetImages().FindModule(module))
+  return true;
+  }
+  return false;
+}
+
+  void TargetList::RegisterInProcessTarget(Target *target) {
+std::lock_guard guard(m_target_list_mutex);
+std::unordered_set::iterator iter;
+bool was_added;
+std::tie(iter, was_added) = m_in_process_target_list.insert(target);
+assert(was_added && "Target pointer was left in the in-process map");
+  }
+  
+  void TargetList::UnregisterInProcessTarget(Target *target) {
+std::lock_guard guard(m_target_list_mutex);
+bool was_present = m_in_process_target_list.erase(target);
+assert(was_present && "Target pointer being removed was not registered");
+  }
+  
+  bool TargetList::IsTargetInProcess(Target *target) {
+std::lock_guard guard(m_target_list_mutex);
+return m_in_process_target_list.count(target) == 1; 
+  }
Index: lldb/source/Target/Target.cpp
===
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -2236,7 +2236,6 @@
 // each library in parallel.
 if (GetPreloadSymbols())
   module_sp->PreloadSymbols();
-
 llvm::SmallVector replaced_modules;
 for (ModuleSP &old_module_sp : old_modules) {
   if (m_images.GetIndexForModule(old_module_sp.get()) !=
@@ -4205,6 +4204,10 @@
 }
 
 bool TargetProperties::GetPreloadSymbols() const {
+  if (INTERRUPT_REQUESTED(m_target->GetDebugger(), 
+  "Interrupted checking preload symbols")) {
+return false;
+  }
   const uint32_t idx = ePropertyPreloadSymbols;
   return GetPropertyAtIndexAs(
   idx, g_tar