This revision was automatically updated to reflect the committed changes.
JDevlieghere marked an inline comment as done.
Closed by commit rG2451cbf07bbc: [lldb/Reproducers] Intercept the FindProcesses 
API (authored by JDevlieghere).

Changed prior to commit:
  https://reviews.llvm.org/D75877?vs=249764&id=250236#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75877

Files:
  lldb/include/lldb/Host/Host.h
  lldb/include/lldb/Utility/ProcessInfo.h
  lldb/source/Commands/CommandObjectReproducer.cpp
  lldb/source/Host/common/Host.cpp
  lldb/source/Host/linux/Host.cpp
  lldb/source/Host/macosx/objcxx/Host.mm
  lldb/source/Host/netbsd/Host.cpp
  lldb/source/Host/openbsd/Host.cpp
  lldb/source/Utility/ProcessInfo.cpp
  lldb/test/API/functionalities/reproducers/attach/Makefile
  lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py
  lldb/test/API/functionalities/reproducers/attach/main.cpp

Index: lldb/test/API/functionalities/reproducers/attach/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/reproducers/attach/main.cpp
@@ -0,0 +1,24 @@
+#include <chrono>
+#include <stdio.h>
+#include <thread>
+
+using std::chrono::seconds;
+
+int main(int argc, char const *argv[]) {
+  lldb_enable_attach();
+
+  // Create the synchronization token.
+  FILE *f;
+  if (f = fopen(argv[1], "wx")) {
+    fputs("\n", f);
+    fflush(f);
+    fclose(f);
+  } else
+    return 1;
+
+  while (true) {
+    std::this_thread::sleep_for(seconds(1));
+  }
+
+  return 0;
+}
Index: lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py
@@ -0,0 +1,71 @@
+"""
+Test reproducer attach.
+"""
+
+import lldb
+import tempfile
+from lldbsuite.test import lldbtest_config
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class CreateAfterAttachTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipIfFreeBSD
+    @skipIfNetBSD
+    @skipIfWindows
+    @skipIfRemote
+    @skipIfiOSSimulator
+    def test_create_after_attach_with_fork(self):
+        """Test thread creation after process attach."""
+        exe = '%s_%d' % (self.testMethodName, os.getpid())
+
+        token = self.getBuildArtifact(exe + '.token')
+        if os.path.exists(token):
+            os.remove(token)
+
+        reproducer = self.getBuildArtifact(exe + '.reproducer')
+        if os.path.exists(reproducer):
+            try:
+                shutil.rmtree(reproducer)
+            except OSError:
+                pass
+
+        self.build(dictionary={'EXE': exe})
+        self.addTearDownHook(self.cleanupSubprocesses)
+
+        inferior = self.spawnSubprocess(self.getBuildArtifact(exe), [token])
+        pid = inferior.pid
+
+        lldbutil.wait_for_file_on_target(self, token)
+
+        # Use Popen because pexpect is overkill and spawnSubprocess is
+        # asynchronous.
+        capture = subprocess.Popen([
+            lldbtest_config.lldbExec, '-b', '--capture', '--capture-path',
+            reproducer, '-o', 'proc att -n {}'.format(exe), '-o',
+            'reproducer generate'
+        ],
+                                   stdin=subprocess.PIPE,
+                                   stdout=subprocess.PIPE,
+                                   stderr=subprocess.PIPE)
+        outs, errs = capture.communicate()
+        self.assertIn('Process {} stopped'.format(pid), outs)
+        self.assertIn('Reproducer written', outs)
+
+        # Check that replay works.
+        replay = subprocess.Popen(
+            [lldbtest_config.lldbExec, '-replay', reproducer],
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE)
+        outs, errs = replay.communicate()
+        self.assertIn('Process {} stopped'.format(pid), outs)
+
+        # We can dump the reproducer in the current context.
+        self.expect('reproducer dump -f {} -p process'.format(reproducer),
+                    substrs=['pid = {}'.format(pid), 'name = {}'.format(exe)])
Index: lldb/test/API/functionalities/reproducers/attach/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/reproducers/attach/Makefile
@@ -0,0 +1,2 @@
+CXX_SOURCES := main.cpp
+include Makefile.rules
Index: lldb/source/Utility/ProcessInfo.cpp
===================================================================
--- lldb/source/Utility/ProcessInfo.cpp
+++ lldb/source/Utility/ProcessInfo.cpp
@@ -18,6 +18,7 @@
 
 using namespace lldb;
 using namespace lldb_private;
+using namespace lldb_private::repro;
 
 ProcessInfo::ProcessInfo()
     : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX),
@@ -344,3 +345,86 @@
   io.mapRequired("effective-gid", Info.m_egid);
   io.mapRequired("parent-pid", Info.m_parent_pid);
 }
+
+llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
+ProcessInfoRecorder::Create(const FileSpec &filename) {
+  std::error_code ec;
+  auto recorder =
+      std::make_unique<ProcessInfoRecorder>(std::move(filename), ec);
+  if (ec)
+    return llvm::errorCodeToError(ec);
+  return std::move(recorder);
+}
+
+void ProcessInfoProvider::Keep() {
+  std::vector<std::string> files;
+  for (auto &recorder : m_process_info_recorders) {
+    recorder->Stop();
+    files.push_back(recorder->GetFilename().GetPath());
+  }
+
+  FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
+  std::error_code ec;
+  llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
+  if (ec)
+    return;
+  llvm::yaml::Output yout(os);
+  yout << files;
+}
+
+void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); }
+
+ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() {
+  std::size_t i = m_process_info_recorders.size() + 1;
+  std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
+                          llvm::Twine(i) + llvm::Twine(".yaml"))
+                             .str();
+  auto recorder_or_error = ProcessInfoRecorder::Create(
+      GetRoot().CopyByAppendingPathComponent(filename));
+  if (!recorder_or_error) {
+    llvm::consumeError(recorder_or_error.takeError());
+    return nullptr;
+  }
+
+  m_process_info_recorders.push_back(std::move(*recorder_or_error));
+  return m_process_info_recorders.back().get();
+}
+
+void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) {
+  if (!m_record)
+    return;
+  llvm::yaml::Output yout(m_os);
+  yout << const_cast<ProcessInstanceInfoList &>(process_infos);
+  m_os.flush();
+}
+
+llvm::Optional<ProcessInstanceInfoList>
+repro::GetReplayProcessInstanceInfoList() {
+  static std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
+      loader = repro::MultiLoader<repro::ProcessInfoProvider>::Create(
+          repro::Reproducer::Instance().GetLoader());
+
+  if (!loader)
+    return {};
+
+  llvm::Optional<std::string> nextfile = loader->GetNextFile();
+  if (!nextfile)
+    return {};
+
+  auto error_or_file = llvm::MemoryBuffer::getFile(*nextfile);
+  if (std::error_code err = error_or_file.getError())
+    return {};
+
+  ProcessInstanceInfoList infos;
+  llvm::yaml::Input yin((*error_or_file)->getBuffer());
+  yin >> infos;
+
+  if (auto err = yin.error())
+    return {};
+
+  return infos;
+}
+
+char ProcessInfoProvider::ID = 0;
+const char *ProcessInfoProvider::Info::file = "process-info.yaml";
+const char *ProcessInfoProvider::Info::name = "process-info";
Index: lldb/source/Host/openbsd/Host.cpp
===================================================================
--- lldb/source/Host/openbsd/Host.cpp
+++ lldb/source/Host/openbsd/Host.cpp
@@ -140,8 +140,8 @@
   return false;
 }
 
-uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
-                             ProcessInstanceInfoList &process_infos) {
+uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
+                                 ProcessInstanceInfoList &process_infos) {
   std::vector<struct kinfo_proc> kinfos;
 
   int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
Index: lldb/source/Host/netbsd/Host.cpp
===================================================================
--- lldb/source/Host/netbsd/Host.cpp
+++ lldb/source/Host/netbsd/Host.cpp
@@ -176,8 +176,8 @@
   return false;
 }
 
-uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
-                             ProcessInstanceInfoList &process_infos) {
+uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
+                                 ProcessInstanceInfoList &process_infos) {
   const ::pid_t our_pid = ::getpid();
   const ::uid_t our_uid = ::getuid();
 
Index: lldb/source/Host/macosx/objcxx/Host.mm
===================================================================
--- lldb/source/Host/macosx/objcxx/Host.mm
+++ lldb/source/Host/macosx/objcxx/Host.mm
@@ -591,8 +591,8 @@
   return false;
 }
 
-uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
-                             ProcessInstanceInfoList &process_infos) {
+uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
+                                 ProcessInstanceInfoList &process_infos) {
   std::vector<struct kinfo_proc> kinfos;
 
   int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
Index: lldb/source/Host/linux/Host.cpp
===================================================================
--- lldb/source/Host/linux/Host.cpp
+++ lldb/source/Host/linux/Host.cpp
@@ -221,8 +221,8 @@
   return true;
 }
 
-uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
-                             ProcessInstanceInfoList &process_infos) {
+uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
+                                 ProcessInstanceInfoList &process_infos) {
   static const char procdir[] = "/proc/";
 
   DIR *dirproc = opendir(procdir);
Index: lldb/source/Host/common/Host.cpp
===================================================================
--- lldb/source/Host/common/Host.cpp
+++ lldb/source/Host/common/Host.cpp
@@ -678,3 +678,23 @@
   }
   OS << desc << " " << int(WS.status);
 }
+
+uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
+                             ProcessInstanceInfoList &process_infos) {
+
+  if (llvm::Optional<ProcessInstanceInfoList> infos =
+          repro::GetReplayProcessInstanceInfoList()) {
+    process_infos = *infos;
+    return process_infos.size();
+  }
+
+  uint32_t result = FindProcessesImpl(match_info, process_infos);
+
+  if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
+    g->GetOrCreate<repro::ProcessInfoProvider>()
+        .GetNewProcessInfoRecorder()
+        ->Record(process_infos);
+  }
+
+  return result;
+}
Index: lldb/source/Commands/CommandObjectReproducer.cpp
===================================================================
--- lldb/source/Commands/CommandObjectReproducer.cpp
+++ lldb/source/Commands/CommandObjectReproducer.cpp
@@ -8,13 +8,14 @@
 
 #include "CommandObjectReproducer.h"
 
+#include "lldb/Host/HostInfo.h"
 #include "lldb/Host/OptionParser.h"
-#include "lldb/Utility/GDBRemote.h"
-#include "lldb/Utility/Reproducer.h"
-
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Utility/GDBRemote.h"
+#include "lldb/Utility/ProcessInfo.h"
+#include "lldb/Utility/Reproducer.h"
 
 #include <csignal>
 
@@ -27,6 +28,7 @@
   eReproducerProviderCommands,
   eReproducerProviderFiles,
   eReproducerProviderGDB,
+  eReproducerProviderProcessInfo,
   eReproducerProviderVersion,
   eReproducerProviderWorkingDirectory,
   eReproducerProviderNone
@@ -49,6 +51,11 @@
         "GDB Remote Packets",
     },
     {
+        eReproducerProviderProcessInfo,
+        "processes",
+        "Process Info",
+    },
+    {
         eReproducerProviderVersion,
         "version",
         "Version",
@@ -97,6 +104,24 @@
 #define LLDB_OPTIONS_reproducer_xcrash
 #include "CommandOptions.inc"
 
+template <typename T>
+llvm::Expected<T> static ReadFromYAML(StringRef filename) {
+  auto error_or_file = MemoryBuffer::getFile(filename);
+  if (auto err = error_or_file.getError()) {
+    return errorCodeToError(err);
+  }
+
+  T t;
+  yaml::Input yin((*error_or_file)->getBuffer());
+  yin >> t;
+
+  if (auto err = yin.error()) {
+    return errorCodeToError(err);
+  }
+
+  return t;
+}
+
 class CommandObjectReproducerGenerate : public CommandObjectParsed {
 public:
   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
@@ -458,23 +483,41 @@
 
       llvm::Optional<std::string> gdb_file;
       while ((gdb_file = multi_loader->GetNextFile())) {
-        auto error_or_file = MemoryBuffer::getFile(*gdb_file);
-        if (auto err = error_or_file.getError()) {
-          SetError(result, errorCodeToError(err));
+        if (llvm::Expected<std::vector<GDBRemotePacket>> packets =
+                ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) {
+          for (GDBRemotePacket &packet : *packets) {
+            packet.Dump(result.GetOutputStream());
+          }
+        } else {
+          SetError(result, packets.takeError());
           return false;
         }
+      }
 
-        std::vector<GDBRemotePacket> packets;
-        yaml::Input yin((*error_or_file)->getBuffer());
-        yin >> packets;
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+      return true;
+    }
+    case eReproducerProviderProcessInfo: {
+      std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
+          multi_loader =
+              repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader);
 
-        if (auto err = yin.error()) {
-          SetError(result, errorCodeToError(err));
-          return false;
-        }
+      if (!multi_loader) {
+        SetError(result, make_error<StringError>(
+                             llvm::inconvertibleErrorCode(),
+                             "Unable to create process info loader."));
+        return false;
+      }
 
-        for (GDBRemotePacket &packet : packets) {
-          packet.Dump(result.GetOutputStream());
+      llvm::Optional<std::string> process_file;
+      while ((process_file = multi_loader->GetNextFile())) {
+        if (llvm::Expected<ProcessInstanceInfoList> infos =
+                ReadFromYAML<ProcessInstanceInfoList>(*process_file)) {
+          for (ProcessInstanceInfo info : *infos)
+            info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver());
+        } else {
+          SetError(result, infos.takeError());
+          return false;
         }
       }
 
Index: lldb/include/lldb/Utility/ProcessInfo.h
===================================================================
--- lldb/include/lldb/Utility/ProcessInfo.h
+++ lldb/include/lldb/Utility/ProcessInfo.h
@@ -14,6 +14,7 @@
 #include "lldb/Utility/Environment.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/Reproducer.h"
 #include "llvm/Support/YAMLTraits.h"
 #include <vector>
 
@@ -215,6 +216,42 @@
   bool m_match_all_users;
 };
 
+namespace repro {
+class ProcessInfoRecorder : public AbstractRecorder {
+public:
+  ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
+      : AbstractRecorder(filename, ec) {}
+
+  static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
+  Create(const FileSpec &filename);
+
+  void Record(const ProcessInstanceInfoList &process_infos);
+};
+
+class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
+public:
+  struct Info {
+    static const char *name;
+    static const char *file;
+  };
+
+  ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
+
+  ProcessInfoRecorder *GetNewProcessInfoRecorder();
+
+  void Keep() override;
+  void Discard() override;
+
+  static char ID;
+
+private:
+  std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
+  std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
+};
+
+llvm::Optional<ProcessInstanceInfoList> GetReplayProcessInstanceInfoList();
+
+} // namespace repro
 } // namespace lldb_private
 
 LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ProcessInstanceInfo)
Index: lldb/include/lldb/Host/Host.h
===================================================================
--- lldb/include/lldb/Host/Host.h
+++ lldb/include/lldb/Host/Host.h
@@ -232,6 +232,10 @@
 
   static std::unique_ptr<Connection>
   CreateDefaultConnection(llvm::StringRef url);
+
+protected:
+  static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
+                                    ProcessInstanceInfoList &proc_infos);
 };
 
 } // namespace lldb_private
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to