[lldb] [Process/FreeBSDRemote] Initial multithreading support
authorMichał Górny <mgorny@moritz.systems>
Wed, 14 Oct 2020 17:17:42 +0000 (19:17 +0200)
committerMichał Górny <mgorny@moritz.systems>
Thu, 15 Oct 2020 15:37:37 +0000 (17:37 +0200)
Implement initial support for watching thread creation and termination.
Update ptrace() calls to correctly indicate requested thread.
Watchpoints are not supported yet.

This patch fixes at least multithreaded register tests.

Differential Revision: https://reviews.llvm.org/D89413

lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp

index e99d38f..c234c0e 100644 (file)
@@ -93,7 +93,7 @@ NativeProcessFreeBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
       pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
       Info.GetArchitecture(), mainloop));
 
-  status = process_up->ReinitializeThreads();
+  status = process_up->SetupTrace();
   if (status.Fail())
     return status.ToError();
 
@@ -125,6 +125,10 @@ NativeProcessFreeBSD::Factory::Attach(
   if (!status.Success())
     return status.ToError();
 
+  status = process_up->SetupTrace();
+  if (status.Fail())
+    return status.ToError();
+
   return std::move(process_up);
 }
 
@@ -191,14 +195,26 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
     return;
   }
   assert(info.pl_event == PL_EVENT_SIGNAL);
-  // TODO: do we need to handle !PL_FLAG_SI?
-  assert(info.pl_flags & PL_FLAG_SI);
-  assert(info.pl_siginfo.si_signo == SIGTRAP);
-
-  LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
-           info.pl_lwpid, info.pl_siginfo.si_code);
 
+  LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}", pid, info.pl_lwpid);
   NativeThreadFreeBSD *thread = nullptr;
+
+  if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) {
+    if (info.pl_flags & PL_FLAG_BORN) {
+      LLDB_LOG(log, "monitoring new thread, tid = {0}", info.pl_lwpid);
+      AddThread(info.pl_lwpid);
+    } else /*if (info.pl_flags & PL_FLAG_EXITED)*/ {
+      LLDB_LOG(log, "thread exited, tid = {0}", info.pl_lwpid);
+      RemoveThread(info.pl_lwpid);
+    }
+
+    Status error =
+        PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+    if (error.Fail())
+      SetState(StateType::eStateInvalid);
+    return;
+  }
+
   if (info.pl_lwpid > 0) {
     for (const auto &t : m_threads) {
       if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid)) {
@@ -212,19 +228,23 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
                info.pl_lwpid);
   }
 
-  switch (info.pl_siginfo.si_code) {
-  case TRAP_BRKPT:
-    if (thread) {
-      thread->SetStoppedByBreakpoint();
-      FixupBreakpointPCAsNeeded(*thread);
+  if (info.pl_flags & PL_FLAG_SI) {
+    assert(info.pl_siginfo.si_signo == SIGTRAP);
+
+    switch (info.pl_siginfo.si_code) {
+    case TRAP_BRKPT:
+      if (thread) {
+        thread->SetStoppedByBreakpoint();
+        FixupBreakpointPCAsNeeded(*thread);
+      }
+      SetState(StateType::eStateStopped, true);
+      break;
+    case TRAP_TRACE:
+      if (thread)
+        thread->SetStoppedByTrace();
+      SetState(StateType::eStateStopped, true);
+      break;
     }
-    SetState(StateType::eStateStopped, true);
-    break;
-  case TRAP_TRACE:
-    if (thread)
-      thread->SetStoppedByTrace();
-    SetState(StateType::eStateStopped, true);
-    break;
   }
 }
 
@@ -743,6 +763,21 @@ NativeProcessFreeBSD::GetAuxvData() const {
   return buf;
 }
 
+Status NativeProcessFreeBSD::SetupTrace() {
+  // Enable event reporting
+  int events;
+  Status status =
+      PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
+  if (status.Fail())
+    return status;
+  events |= PTRACE_LWP;
+  status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
+  if (status.Fail())
+    return status;
+
+  return ReinitializeThreads();
+}
+
 Status NativeProcessFreeBSD::ReinitializeThreads() {
   // Clear old threads
   m_threads.clear();
index 8b4ae98..5900048 100644 (file)
@@ -107,6 +107,7 @@ private:
   void SigchldHandler();
 
   Status Attach();
+  Status SetupTrace();
   Status ReinitializeThreads();
 };
 
index 2a7dc3d..2a2995e 100644 (file)
@@ -25,11 +25,6 @@ NativeRegisterContextFreeBSD::NativeRegisterContextFreeBSD(
     RegisterInfoInterface *reg_info_interface_p)
     : NativeRegisterContextRegisterInfo(native_thread, reg_info_interface_p) {}
 
-Status NativeRegisterContextFreeBSD::DoRegisterSet(int ptrace_req, void *buf) {
-  return NativeProcessFreeBSD::PtraceWrapper(ptrace_req, GetProcessPid(), buf,
-                                             m_thread.GetID());
-}
-
 NativeProcessFreeBSD &NativeRegisterContextFreeBSD::GetProcess() {
   return static_cast<NativeProcessFreeBSD &>(m_thread.GetProcess());
 }
index db32e21..0f7b1e9 100644 (file)
@@ -37,7 +37,6 @@ public:
   virtual Status ClearWatchpointHit(uint32_t wp_index) = 0;
 
 protected:
-  Status DoRegisterSet(int req, void *buf);
   virtual NativeProcessFreeBSD &GetProcess();
   virtual ::pid_t GetProcessPid();
 };
index fd8e600..3460f53 100644 (file)
@@ -429,15 +429,19 @@ int NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum(
 Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(uint32_t set) {
   switch (set) {
   case GPRegSet:
-    return DoRegisterSet(PT_GETREGS, &m_gpr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+                                               &m_gpr);
   case FPRegSet:
 #if defined(__x86_64__)
-    return DoRegisterSet(PT_GETFPREGS, &m_fpr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(),
+                                               &m_fpr);
 #else
-    return DoRegisterSet(PT_GETXMMREGS, &m_fpr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_GETXMMREGS, m_thread.GetID(),
+                                               &m_fpr);
 #endif
   case DBRegSet:
-    return DoRegisterSet(PT_GETDBREGS, &m_dbr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(),
+                                               &m_dbr);
   case XSaveRegSet: {
     struct ptrace_xstate_info info;
     Status ret = NativeProcessFreeBSD::PtraceWrapper(
@@ -466,15 +470,19 @@ Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(uint32_t set) {
 Status NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet(uint32_t set) {
   switch (set) {
   case GPRegSet:
-    return DoRegisterSet(PT_SETREGS, &m_gpr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+                                               &m_gpr);
   case FPRegSet:
 #if defined(__x86_64__)
-    return DoRegisterSet(PT_SETFPREGS, &m_fpr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(),
+                                               &m_fpr);
 #else
-    return DoRegisterSet(PT_SETXMMREGS, &m_fpr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_SETXMMREGS, m_thread.GetID(),
+                                               &m_fpr);
 #endif
   case DBRegSet:
-    return DoRegisterSet(PT_SETDBREGS, &m_dbr);
+    return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(),
+                                               &m_dbr);
   case XSaveRegSet:
     // ReadRegisterSet() must always be called before WriteRegisterSet().
     assert(m_xsave.size() > 0);
index 1517e7f..d1f2838 100644 (file)
@@ -40,32 +40,27 @@ NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process,
       m_stop_description() {}
 
 Status NativeThreadFreeBSD::Resume() {
-  Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
-                                                   nullptr, GetID());
+  Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
   if (!ret.Success())
     return ret;
-  ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
-                                            nullptr, GetID());
+  ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());
   if (ret.Success())
     SetRunning();
   return ret;
 }
 
 Status NativeThreadFreeBSD::SingleStep() {
-  Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
-                                                   nullptr, GetID());
+  Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
   if (!ret.Success())
     return ret;
-  ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
-                                            nullptr, GetID());
+  ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID());
   if (ret.Success())
     SetStepping();
   return ret;
 }
 
 Status NativeThreadFreeBSD::Suspend() {
-  Status ret = NativeProcessFreeBSD::PtraceWrapper(
-      PT_SUSPEND, m_process.GetID(), nullptr, GetID());
+  Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID());
   if (ret.Success())
     SetStopped();
   return ret;