augusto2112 created this revision.
augusto2112 added reviewers: labath, clayborg, jasonmolenda.
Herald added a subscriber: dang.
augusto2112 requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

jAttachWait provides the same functionality as vAttachWait/vAttachOrWait. 
Additionaly, it allows for the usage of two new options, 'waitfor-duration' and 
'waitfor-interval'


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96176

Files:
  lldb/include/lldb/Target/Process.h
  lldb/include/lldb/Utility/StringExtractorGDBRemote.h
  lldb/include/lldb/lldb-enumerations.h
  lldb/source/Commands/CommandObjectProcess.cpp
  lldb/source/Commands/Options.td
  lldb/source/Interpreter/CommandObject.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  lldb/source/Utility/StringExtractorGDBRemote.cpp

Index: lldb/source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -200,7 +200,10 @@
       if (PACKET_MATCHES("qHostInfo"))
         return eServerPacketType_qHostInfo;
       break;
-
+    case 'J':
+      if (PACKET_MATCHES("qJAttachWaitSupported"))
+        return eServerPacketType_qJAttachWaitSupported;
+      break;
     case 'K':
       if (PACKET_STARTS_WITH("qKillSpawnedProcess"))
         return eServerPacketType_qKillSpawnedProcess;
@@ -294,6 +297,8 @@
     break;
 
   case 'j':
+    if (PACKET_STARTS_WITH("jAttachWait:"))
+      return eServerPacketType_jAttachWait;
     if (PACKET_STARTS_WITH("jModulesInfo:"))
       return eServerPacketType_jModulesInfo;
     if (PACKET_MATCHES("jSignalsInfo"))
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1160,41 +1160,73 @@
   return error;
 }
 
+static StreamGDBRemote MakeJAttachWaitPacket(
+    const char *process_name, const ProcessAttachInfo &attach_info) {
+  StreamString json_string;
+  json_string.PutCString("jAttachWait:");
+
+  StructuredData::Dictionary json_packet;
+  json_packet.AddStringItem("process_name", process_name);
+
+  if (auto interval = attach_info.GetWaitForLaunchInterval())
+    json_packet.AddIntegerItem("waitfor-interval-usec",
+                               *interval);
+
+  if (auto duration = attach_info.GetWaitForLaunchDuration())
+    json_packet.AddIntegerItem("waitfor-duration-sec",
+                               *duration);
+
+  json_packet.AddBooleanItem("include-existing",
+                             !attach_info.GetIgnoreExisting());
+
+  json_packet.Dump(json_string, false);
+  StreamGDBRemote escaped_packet;
+  escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+  return escaped_packet;
+}
+
 Status ProcessGDBRemote::DoAttachToProcessWithName(
     const char *process_name, const ProcessAttachInfo &attach_info) {
   Status error;
   // Clear out and clean up from any current state
   Clear();
 
-  if (process_name && process_name[0]) {
-    error = EstablishConnectionIfNeeded(attach_info);
-    if (error.Success()) {
-      StreamString packet;
+  if (!process_name || !process_name[0])
+    return error;
 
-      m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+  error = EstablishConnectionIfNeeded(attach_info);
+  if (!error.Success()) {
+    SetExitStatus(-1, error.AsCString());
+    return error;
+  }
 
-      if (attach_info.GetWaitForLaunch()) {
-        if (!m_gdb_comm.GetVAttachOrWaitSupported()) {
+  m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+  if (attach_info.GetWaitForLaunch() && m_gdb_comm.GetJAttachWaitSupported()) {
+    auto gdb_stream = MakeJAttachWaitPacket(process_name, attach_info);
+    m_async_broadcaster.BroadcastEvent(
+        eBroadcastBitAsyncContinue,
+        new EventDataBytes(gdb_stream.GetString().data(),
+                           gdb_stream.GetSize()));
+  } else {
+    StreamString packet;
+    if (attach_info.GetWaitForLaunch()) {
+      if (!m_gdb_comm.GetVAttachOrWaitSupported()) {
+        packet.PutCString("vAttachWait");
+      } else {
+        if (attach_info.GetIgnoreExisting())
           packet.PutCString("vAttachWait");
-        } else {
-          if (attach_info.GetIgnoreExisting())
-            packet.PutCString("vAttachWait");
-          else
-            packet.PutCString("vAttachOrWait");
-        }
-      } else
-        packet.PutCString("vAttachName");
-      packet.PutChar(';');
-      packet.PutBytesAsRawHex8(process_name, strlen(process_name),
-                               endian::InlHostByteOrder(),
-                               endian::InlHostByteOrder());
-
-      m_async_broadcaster.BroadcastEvent(
-          eBroadcastBitAsyncContinue,
-          new EventDataBytes(packet.GetString().data(), packet.GetSize()));
-
+        else
+          packet.PutCString("vAttachOrWait");
+      }
     } else
-      SetExitStatus(-1, error.AsCString());
+      packet.PutCString("vAttachName");
+    packet.PutChar(';');
+    packet.PutBytesAsRawHex8(process_name, strlen(process_name),
+                             endian::InlHostByteOrder(),
+                             endian::InlHostByteOrder());
+    m_async_broadcaster.BroadcastEvent(
+        eBroadcastBitAsyncContinue,
+        new EventDataBytes(packet.GetString().data(), packet.GetSize()));
   }
   return error;
 }
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -65,10 +65,26 @@
   /// with a given name and attaching llgs to that via the configured
   /// Platform.
   ///
+  /// \param process_name
+  ///     The process we'd like to attach to.
+  /// \param include_existing
+  ///     Look for the process we'd like to attach to among the processes
+  ///     already running.
+  /// \param custom_polling_interval_usec
+  ///     The polling interval the function should use in microseconds. Defaults
+  ///     to 1000.
+  /// \param timeout
+  ///     How long we should look for the process in seconds. Defaults to
+  ///     infinity.
+  ///
   /// \return
   ///     An Status object indicating the success or failure of the
   ///     attach operation.
-  Status AttachWaitProcess(llvm::StringRef process_name, bool include_existing);
+  Status AttachWaitProcess(
+      llvm::StringRef process_name, bool include_existing,
+      llvm::Optional<uint64_t> custom_polling_interval_usec =
+          llvm::Optional<uint64_t>(),
+      llvm::Optional<uint64_t> timeout_seconds = llvm::Optional<uint64_t>());
 
   // NativeProcessProtocol::NativeDelegate overrides
   void InitializeDelegate(NativeProcessProtocol *process) override;
@@ -187,6 +203,10 @@
 
   PacketResult Handle_vAttachOrWait(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_qJAttachWaitSupported(StringExtractorGDBRemote &packet);
+
+  PacketResult Handle_jAttachWait(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_D(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet);
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -168,6 +168,12 @@
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_vAttachOrWait,
       &GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_qJAttachWaitSupported,
+      &GDBRemoteCommunicationServerLLGS::Handle_qJAttachWaitSupported);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jAttachWait,
+      &GDBRemoteCommunicationServerLLGS::Handle_jAttachWait);
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_vCont,
       &GDBRemoteCommunicationServerLLGS::Handle_vCont);
@@ -344,10 +350,13 @@
 }
 
 Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
-    llvm::StringRef process_name, bool include_existing) {
+    llvm::StringRef process_name, bool include_existing,
+    llvm::Optional<uint64_t> custom_polling_interval_usec,
+    llvm::Optional<uint64_t> timeout) {
   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
 
-  std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1);
+  auto polling_interval =
+      std::chrono::microseconds(custom_polling_interval_usec.getValueOr(1000));
 
   // Create the matcher used to search the process list.
   ProcessInstanceInfoList exclusion_list;
@@ -376,8 +385,13 @@
         return false;
       };
 
+  auto now = std::chrono::system_clock::now();
+  auto target = now;
+  if (timeout.hasValue())
+    target += std::chrono::seconds(timeout.getValue());
+
   ProcessInstanceInfoList loop_process_list;
-  while (true) {
+  while (!timeout.hasValue() || now < target) {
     loop_process_list.clear();
     if (Host::FindProcesses(match_info, loop_process_list)) {
       // Remove all the elements that are in the exclusion list.
@@ -409,7 +423,14 @@
     // No matches, we have not found the process. Sleep until next poll.
     LLDB_LOG(log, "sleep {0} seconds", polling_interval);
     std::this_thread::sleep_for(polling_interval);
+    if (timeout.hasValue())
+      now = std::chrono::system_clock::now();
   }
+
+  // Timed out
+  Status error;
+  error.SetErrorString("attach timed out.");
+  return error;
 }
 
 void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
@@ -3332,6 +3353,57 @@
   return SendStopReasonForState(m_debugged_process_up->GetState());
 }
 
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qJAttachWaitSupported(
+    StringExtractorGDBRemote &packet) {
+  return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jAttachWait(
+    StringExtractorGDBRemote &packet) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+  if (!packet.ConsumeFront("jAttachWait:"))
+    return SendIllFormedResponse(packet, "jAttachWait: Ill formed packet ");
+
+  auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+  if (!json_object ||
+      json_object->GetType() != lldb::eStructuredDataTypeDictionary)
+    return SendIllFormedResponse(packet, "jAttachWait: Ill formed packet ");
+
+  auto *json_dict = json_object->GetAsDictionary();
+
+  StringRef process_name;
+  auto polling_interval = llvm::Optional<uint64_t>();
+  auto polling_duration = llvm::Optional<uint64_t>();
+  bool include_existing = false;
+  uint64_t temp;
+
+  json_dict->GetValueForKeyAsString("process_name", process_name);
+  json_dict->GetValueForKeyAsBoolean("include-existing", include_existing);
+  if (json_dict->GetValueForKeyAsInteger("waitfor-interval-usec", temp))
+    polling_interval = temp;
+  if (json_dict->GetValueForKeyAsInteger("waitfor-duration-sec", temp))
+    polling_duration = temp;
+
+
+  LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+  Status error =
+      AttachWaitProcess(process_name, include_existing, polling_interval,
+                        polling_duration);
+  if (error.Fail()) {
+    LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+             error);
+    return SendErrorResponse(error);
+  }
+
+  // Notify we attached by sending a stop packet.
+  return SendStopReasonForState(m_debugged_process_up->GetState());
+}
+
 GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -257,6 +257,8 @@
 
   bool GetVAttachOrWaitSupported();
 
+  bool GetJAttachWaitSupported();
+
   bool GetSyncThreadStateSupported();
 
   void ResetDiscoverableSettings(bool did_exec);
@@ -542,6 +544,7 @@
   LazyBool m_supports_detach_stay_stopped;
   LazyBool m_watchpoints_trigger_after_instruction;
   LazyBool m_attach_or_wait_reply;
+  LazyBool m_j_attach_wait_reply;
   LazyBool m_prepare_for_reg_writing_reply;
   LazyBool m_supports_p;
   LazyBool m_supports_x;
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -74,6 +74,7 @@
       m_supports_detach_stay_stopped(eLazyBoolCalculate),
       m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
       m_attach_or_wait_reply(eLazyBoolCalculate),
+      m_j_attach_wait_reply(eLazyBoolCalculate),
       m_prepare_for_reg_writing_reply(eLazyBoolCalculate),
       m_supports_p(eLazyBoolCalculate), m_supports_x(eLazyBoolCalculate),
       m_avoid_g_packets(eLazyBoolCalculate),
@@ -257,6 +258,20 @@
   return m_attach_or_wait_reply == eLazyBoolYes;
 }
 
+bool GDBRemoteCommunicationClient::GetJAttachWaitSupported() {
+  if (m_j_attach_wait_reply == eLazyBoolCalculate) {
+    m_j_attach_wait_reply = eLazyBoolNo;
+
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse("qJAttachWaitSupported", response,
+                                     false) == PacketResult::Success) {
+      if (response.IsOKResponse())
+        m_j_attach_wait_reply = eLazyBoolYes;
+    }
+  }
+  return m_j_attach_wait_reply == eLazyBoolYes;
+}
+
 bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() {
   if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) {
     m_prepare_for_reg_writing_reply = eLazyBoolNo;
@@ -291,6 +306,7 @@
     m_supports_memory_region_info = eLazyBoolCalculate;
     m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
     m_attach_or_wait_reply = eLazyBoolCalculate;
+    m_j_attach_wait_reply = eLazyBoolCalculate;
     m_avoid_g_packets = eLazyBoolCalculate;
     m_supports_qXfer_auxv_read = eLazyBoolCalculate;
     m_supports_qXfer_libraries_read = eLazyBoolCalculate;
Index: lldb/source/Interpreter/CommandObject.cpp
===================================================================
--- lldb/source/Interpreter/CommandObject.cpp
+++ lldb/source/Interpreter/CommandObject.cpp
@@ -1088,6 +1088,8 @@
     { eArgTypePermissionsNumber, "perms-numeric", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as an octal number (e.g. 755)." },
     { eArgTypePermissionsString, "perms=string", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as a string value (e.g. rw-r-xr--)." },
     { eArgTypePid, "pid", CommandCompletions::eProcessIDCompletion, { nullptr, false }, "The process ID number." },
+    { eArgTypeWaitforInterval, "waitfor-interval", CommandCompletions::eProcessIDCompletion, { nullptr, false }, "The interval in microseconds that waitfor uses to poll the list of processes. Defaults to 1000." },
+    { eArgTypeWaitforDuration, "waitfor-duration", CommandCompletions::eProcessIDCompletion, { nullptr, false }, "The timout that in seconds when waiting for a process with waitfor. Defaults to infinite." },
     { eArgTypePlugin, "plugin", CommandCompletions::eProcessPluginCompletion, { nullptr, false }, "Help text goes here." },
     { eArgTypeProcessName, "process-name", CommandCompletions::eProcessNameCompletion, { nullptr, false }, "The name of the process." },
     { eArgTypePythonClass, "python-class", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a Python class." },
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -688,6 +688,12 @@
     Group<2>, Desc<"Include existing processes when doing attach -w.">;
   def process_attach_waitfor : Option<"waitfor", "w">, Group<2>,
     Desc<"Wait for the process with <process-name> to launch.">;
+  def process_attach_waitfor_interval : Option<"waitfor-interval", "I">,
+    Group<2>, Arg<"WaitforInterval">,
+    Desc<"The interval that waitfor uses to poll the list of processes.">;
+  def process_attach_waitfor_duration : Option<"waitfor-duration", "d">,
+    Group<2>, Arg<"WaitforDuration">,
+    Desc<"The interval that waitfor uses to poll the list of processes.">;
 }
 
 let Command = "process continue" in {
Index: lldb/source/Commands/CommandObjectProcess.cpp
===================================================================
--- lldb/source/Commands/CommandObjectProcess.cpp
+++ lldb/source/Commands/CommandObjectProcess.cpp
@@ -306,6 +306,26 @@
       case 'i':
         attach_info.SetIgnoreExisting(false);
         break;
+        
+      case 'I':
+        uint64_t interval;
+        if (option_arg.getAsInteger(0, interval)) {
+          error.SetErrorStringWithFormat("invalid polling interval '%s'",
+                                         option_arg.str().c_str());
+        } else {
+          attach_info.SetWaitForLaunchInterval(interval);
+        }
+        break;
+
+      case 'd':
+        uint64_t duration;
+        if (option_arg.getAsInteger(0, duration)) {
+          error.SetErrorStringWithFormat("invalid duration '%s'",
+                                         option_arg.str().c_str());
+        } else {
+          attach_info.SetWaitForLaunchDuration(duration);
+        }
+        break;
 
       default:
         llvm_unreachable("Unimplemented option");
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -597,6 +597,8 @@
   eArgTypeCommand,
   eArgTypeColumnNum,
   eArgTypeModuleUUID,
+  eArgTypeWaitforInterval,
+  eArgTypeWaitforDuration,
   eArgTypeLastArg // Always keep this entry as the last entry in this
                   // enumeration!!
 };
Index: lldb/include/lldb/Utility/StringExtractorGDBRemote.h
===================================================================
--- lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -122,6 +122,7 @@
     eServerPacketType_qThreadExtraInfo,
     eServerPacketType_qThreadStopInfo,
     eServerPacketType_qVAttachOrWaitSupported,
+    eServerPacketType_qJAttachWaitSupported,
     eServerPacketType_qWatchpointSupportInfo,
     eServerPacketType_qWatchpointSupportInfoSupported,
     eServerPacketType_qXfer,
@@ -132,6 +133,7 @@
     eServerPacketType_vAttach,
     eServerPacketType_vAttachWait,
     eServerPacketType_vAttachOrWait,
+    eServerPacketType_jAttachWait,
     eServerPacketType_vAttachName,
     eServerPacketType_vCont,
     eServerPacketType_vCont_actions, // vCont?
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -110,12 +110,16 @@
   ProcessAttachInfo()
       : ProcessInstanceInfo(), m_listener_sp(), m_hijack_listener_sp(),
         m_plugin_name(), m_resume_count(0), m_wait_for_launch(false),
+        m_wait_for_launch_interval(llvm::Optional<uint64_t>()),
+        m_wait_for_launch_duration(llvm::Optional<uint64_t>()),
         m_ignore_existing(true), m_continue_once_attached(false),
         m_detach_on_error(true), m_async(false) {}
 
   ProcessAttachInfo(const ProcessLaunchInfo &launch_info)
       : ProcessInstanceInfo(), m_listener_sp(), m_hijack_listener_sp(),
         m_plugin_name(), m_resume_count(0), m_wait_for_launch(false),
+        m_wait_for_launch_interval(llvm::Optional<uint64_t>()),
+        m_wait_for_launch_duration(llvm::Optional<uint64_t>()),
         m_ignore_existing(true), m_continue_once_attached(false),
         m_detach_on_error(true), m_async(false) {
     ProcessInfo::operator=(launch_info);
@@ -130,6 +134,22 @@
 
   void SetWaitForLaunch(bool b) { m_wait_for_launch = b; }
 
+  llvm::Optional<uint64_t> GetWaitForLaunchInterval() const {
+    return m_wait_for_launch_interval;
+  }
+
+  void SetWaitForLaunchInterval(llvm::Optional<uint64_t> new_interval) {
+    m_wait_for_launch_interval = new_interval;
+  }
+
+  llvm::Optional<uint64_t> GetWaitForLaunchDuration() const {
+    return m_wait_for_launch_duration;
+  }
+
+  void SetWaitForLaunchDuration(llvm::Optional<uint64_t> new_duration) {
+    m_wait_for_launch_duration = new_duration;
+  }
+
   bool GetAsync() const { return m_async; }
 
   void SetAsync(bool b) { m_async = b; }
@@ -159,6 +179,8 @@
     m_plugin_name.clear();
     m_resume_count = 0;
     m_wait_for_launch = false;
+    m_wait_for_launch_interval = llvm::Optional<uint64_t>();
+    m_wait_for_launch_duration = llvm::Optional<uint64_t>();
     m_ignore_existing = true;
     m_continue_once_attached = false;
   }
@@ -198,6 +220,8 @@
   std::string m_plugin_name;
   uint32_t m_resume_count; // How many times do we resume after launching
   bool m_wait_for_launch;
+  llvm::Optional<uint64_t> m_wait_for_launch_interval;
+  llvm::Optional<uint64_t> m_wait_for_launch_duration;
   bool m_ignore_existing;
   bool m_continue_once_attached; // Supports the use-case scenario of
                                  // immediately continuing the process once
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to