labath created this revision.
labath added reviewers: JDevlieghere, stella.stamenova.
labath requested review of this revision.
Herald added a project: LLDB.

Our code for locating the shared library directory works via dladdr (or
the windows equivalent) to locate the path of an address known to reside
in liblldb. This works great for C++ programs, but there's a catch.

When (lib)lldb is used from python (like in our test suite), this dladdr
call will return a path to the _lldb.so (or such) file in the python
directory. To compensate for this, we have code which attempts to
resolve this symlink, to ensure we get the canonical location. However,
here's the second catch.

On windows, this file is not a symlink (but a copy), so this logic
fails. Since most of our other paths are derived from the liblldb
location, all of these paths will be wrong, when running the test suite.
One effect of this was the failure to find lldb-server in D96202 
<https://reviews.llvm.org/D96202>.

To fix this issue, I add some windows-specific code to locate the
liblldb directory. Since it cannot rely on symlinks, it works by
manually walking the directory tree -- essentially doing the opposite of
what we do when computing the python directory.

To avoid python leaking back into the host code, I implement this with
the help of a callback which can be passed to HostInfo::Initialize in
order to assist with the directory location. The callback lives inside
the python plugin.

I also strenghten the existing path test to ensure the returned path is
the right one.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96779

Files:
  lldb/include/lldb/Host/HostInfoBase.h
  lldb/include/lldb/Host/linux/HostInfoLinux.h
  lldb/include/lldb/Host/windows/HostInfoWindows.h
  lldb/include/lldb/Initialization/SystemInitializerCommon.h
  lldb/source/API/SystemInitializerFull.cpp
  lldb/source/Host/common/HostInfoBase.cpp
  lldb/source/Host/linux/HostInfoLinux.cpp
  lldb/source/Host/windows/HostInfoWindows.cpp
  lldb/source/Initialization/SystemInitializerCommon.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
  lldb/test/API/functionalities/paths/TestPaths.py
  lldb/tools/lldb-server/SystemInitializerLLGS.h
  lldb/tools/lldb-test/SystemInitializerTest.cpp

Index: lldb/tools/lldb-test/SystemInitializerTest.cpp
===================================================================
--- lldb/tools/lldb-test/SystemInitializerTest.cpp
+++ lldb/tools/lldb-test/SystemInitializerTest.cpp
@@ -22,7 +22,8 @@
 
 using namespace lldb_private;
 
-SystemInitializerTest::SystemInitializerTest() = default;
+SystemInitializerTest::SystemInitializerTest()
+    : SystemInitializerCommon(nullptr) {}
 SystemInitializerTest::~SystemInitializerTest() = default;
 
 llvm::Error SystemInitializerTest::Initialize() {
Index: lldb/tools/lldb-server/SystemInitializerLLGS.h
===================================================================
--- lldb/tools/lldb-server/SystemInitializerLLGS.h
+++ lldb/tools/lldb-server/SystemInitializerLLGS.h
@@ -14,6 +14,8 @@
 
 class SystemInitializerLLGS : public lldb_private::SystemInitializerCommon {
 public:
+  SystemInitializerLLGS() : SystemInitializerCommon(nullptr) {}
+
   llvm::Error Initialize() override;
   void Terminate() override;
 };
Index: lldb/test/API/functionalities/paths/TestPaths.py
===================================================================
--- lldb/test/API/functionalities/paths/TestPaths.py
+++ lldb/test/API/functionalities/paths/TestPaths.py
@@ -8,6 +8,7 @@
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
 from lldbsuite.test import lldbutil
+from lldbsuite.test import lldbplatformutil
 
 
 class TestPaths(TestBase):
@@ -29,7 +30,18 @@
         for path_type in dir_path_types:
             f = lldb.SBHostOS.GetLLDBPath(path_type)
             # No directory path types should have the filename set
-            self.assertTrue(f.GetFilename() is None)
+            self.assertIsNone(f.GetFilename())
+
+        shlib_dir = lldb.SBHostOS.GetLLDBPath(lldb.ePathTypeLLDBShlibDir).GetDirectory()
+        if lldbplatformutil.getHostPlatform() == 'windows':
+            filenames = ['liblldb.dll']
+        elif lldbplatformutil.getHostPlatform() == 'darwin':
+            filenames = ['LLDB', 'liblldb.dylib']
+        else:
+            filenames = ['liblldb.so']
+        self.assertTrue(any([os.path.exists(os.path.join(shlib_dir, f)) for f in
+            filenames]), "shlib_dir = " + shlib_dir)
+
 
     @no_debug_info_test
     def test_directory_doesnt_end_with_slash(self):
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -51,6 +51,7 @@
   static lldb_private::ConstString GetPluginNameStatic();
   static const char *GetPluginDescriptionStatic();
   static FileSpec GetPythonDir();
+  static void SharedLibraryDirectoryHelper(FileSpec &this_file);
 
 protected:
   static void ComputePythonDirForApple(llvm::SmallVectorImpl<char> &path);
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -410,6 +410,31 @@
   return g_spec;
 }
 
+void ScriptInterpreterPython::SharedLibraryDirectoryHelper(
+    FileSpec &this_file) {
+  // When we're loaded from python, this_file will point to the file inside the
+  // python package directory. Replace it with the one in the lib directory.
+#ifdef _WIN32
+  // On windows, we need to manually back out of the python tree, and go into
+  // the bin directory. This is pretty much the inverse of what ComputePythonDir
+  // does.
+  if (this_file.GetFileNameExtension() == ConstString(".pyd")) {
+    this_file.RemoveLastPathComponent(); // _lldb.pyd or _lldb_d.pyd
+    this_file.RemoveLastPathComponent(); // lldb
+    for (auto it = llvm::sys::path::begin(LLDB_PYTHON_RELATIVE_LIBDIR),
+              end = llvm::sys::path::end(LLDB_PYTHON_RELATIVE_LIBDIR);
+         it != end; ++it)
+      this_file.RemoveLastPathComponent();
+    this_file.AppendPathComponent("bin");
+    this_file.AppendPathComponent("liblldb.dll");
+  }
+#else
+  // The python file is a symlink, so we can find the real library by resolving
+  // it. We can do this unconditionally.
+  FileSystem::Instance().ResolveSymbolicLink(this_file, this_file);
+#endif
+}
+
 lldb_private::ConstString ScriptInterpreterPython::GetPluginNameStatic() {
   static ConstString g_name("script-python");
   return g_name;
Index: lldb/source/Initialization/SystemInitializerCommon.cpp
===================================================================
--- lldb/source/Initialization/SystemInitializerCommon.cpp
+++ lldb/source/Initialization/SystemInitializerCommon.cpp
@@ -11,7 +11,6 @@
 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
-#include "lldb/Host/HostInfo.h"
 #include "lldb/Host/Socket.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/ReproducerProvider.h"
@@ -35,7 +34,9 @@
 using namespace lldb_private;
 using namespace lldb_private::repro;
 
-SystemInitializerCommon::SystemInitializerCommon() {}
+SystemInitializerCommon::SystemInitializerCommon(
+    HostInfo::SharedLibraryDirectoryHelper *helper)
+    : m_shlib_dir_helper(helper) {}
 
 SystemInitializerCommon::~SystemInitializerCommon() {}
 
@@ -125,7 +126,7 @@
     return e;
 
   Log::Initialize();
-  HostInfo::Initialize();
+  HostInfo::Initialize(m_shlib_dir_helper);
 
   llvm::Error error = Socket::Initialize();
   if (error)
Index: lldb/source/Host/windows/HostInfoWindows.cpp
===================================================================
--- lldb/source/Host/windows/HostInfoWindows.cpp
+++ lldb/source/Host/windows/HostInfoWindows.cpp
@@ -39,9 +39,9 @@
 
 FileSpec HostInfoWindows::m_program_filespec;
 
-void HostInfoWindows::Initialize() {
+void HostInfoWindows::Initialize(SharedLibraryDirectoryHelper *helper) {
   ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
-  HostInfoBase::Initialize();
+  HostInfoBase::Initialize(helper);
 }
 
 void HostInfoWindows::Terminate() {
Index: lldb/source/Host/linux/HostInfoLinux.cpp
===================================================================
--- lldb/source/Host/linux/HostInfoLinux.cpp
+++ lldb/source/Host/linux/HostInfoLinux.cpp
@@ -33,8 +33,8 @@
 HostInfoLinuxFields *g_fields = nullptr;
 }
 
-void HostInfoLinux::Initialize() {
-  HostInfoPosix::Initialize();
+void HostInfoLinux::Initialize(SharedLibraryDirectoryHelper *helper) {
+  HostInfoPosix::Initialize(helper);
 
   g_fields = new HostInfoLinuxFields();
 }
Index: lldb/source/Host/common/HostInfoBase.cpp
===================================================================
--- lldb/source/Host/common/HostInfoBase.cpp
+++ lldb/source/Host/common/HostInfoBase.cpp
@@ -71,13 +71,18 @@
   llvm::once_flag m_lldb_global_tmp_dir_once;
   FileSpec m_lldb_global_tmp_dir;
 };
+} // namespace
 
-HostInfoBaseFields *g_fields = nullptr;
-}
+static HostInfoBaseFields *g_fields = nullptr;
+static HostInfoBase::SharedLibraryDirectoryHelper *g_shlib_dir_helper = nullptr;
 
-void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
+void HostInfoBase::Initialize(SharedLibraryDirectoryHelper *helper) {
+  g_shlib_dir_helper = helper;
+  g_fields = new HostInfoBaseFields();
+}
 
 void HostInfoBase::Terminate() {
+  g_shlib_dir_helper = nullptr;
   delete g_fields;
   g_fields = nullptr;
 }
@@ -249,9 +254,8 @@
       reinterpret_cast<void *>(
           HostInfoBase::ComputeSharedLibraryDirectory)));
 
-  // This is necessary because when running the testsuite the shlib might be a
-  // symbolic link inside the Python resource dir.
-  FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
+  if (g_shlib_dir_helper)
+    g_shlib_dir_helper(lldb_file_spec);
 
   // Remove the filename so that this FileSpec only represents the directory.
   file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
Index: lldb/source/API/SystemInitializerFull.cpp
===================================================================
--- lldb/source/API/SystemInitializerFull.cpp
+++ lldb/source/API/SystemInitializerFull.cpp
@@ -29,9 +29,22 @@
 #define LLDB_PLUGIN(p) LLDB_PLUGIN_DECLARE(p)
 #include "Plugins/Plugins.def"
 
+#if LLDB_ENABLE_PYTHON
+#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
+
+constexpr lldb_private::HostInfo::SharedLibraryDirectoryHelper
+    *g_shlib_dir_helper =
+        lldb_private::ScriptInterpreterPython::SharedLibraryDirectoryHelper;
+
+#else
+constexpr lldb_private::HostInfo::SharedLibraryDirectoryHelper
+    *g_shlib_dir_helper = 0;
+#endif
+
 using namespace lldb_private;
 
-SystemInitializerFull::SystemInitializerFull() = default;
+SystemInitializerFull::SystemInitializerFull()
+    : SystemInitializerCommon(g_shlib_dir_helper) {}
 SystemInitializerFull::~SystemInitializerFull() = default;
 
 llvm::Error SystemInitializerFull::Initialize() {
Index: lldb/include/lldb/Initialization/SystemInitializerCommon.h
===================================================================
--- lldb/include/lldb/Initialization/SystemInitializerCommon.h
+++ lldb/include/lldb/Initialization/SystemInitializerCommon.h
@@ -10,6 +10,7 @@
 #define LLDB_INITIALIZATION_SYSTEMINITIALIZERCOMMON_H
 
 #include "SystemInitializer.h"
+#include "lldb/Host/HostInfo.h"
 
 namespace lldb_private {
 /// Initializes common lldb functionality.
@@ -22,11 +23,14 @@
 /// the constructor.
 class SystemInitializerCommon : public SystemInitializer {
 public:
-  SystemInitializerCommon();
+  SystemInitializerCommon(HostInfo::SharedLibraryDirectoryHelper *helper);
   ~SystemInitializerCommon() override;
 
   llvm::Error Initialize() override;
   void Terminate() override;
+
+private:
+  HostInfo::SharedLibraryDirectoryHelper *m_shlib_dir_helper;
 };
 
 } // namespace lldb_private
Index: lldb/include/lldb/Host/windows/HostInfoWindows.h
===================================================================
--- lldb/include/lldb/Host/windows/HostInfoWindows.h
+++ lldb/include/lldb/Host/windows/HostInfoWindows.h
@@ -25,7 +25,7 @@
   ~HostInfoWindows();
 
 public:
-  static void Initialize();
+  static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr);
   static void Terminate();
 
   static size_t GetPageSize();
Index: lldb/include/lldb/Host/linux/HostInfoLinux.h
===================================================================
--- lldb/include/lldb/Host/linux/HostInfoLinux.h
+++ lldb/include/lldb/Host/linux/HostInfoLinux.h
@@ -27,7 +27,7 @@
   ~HostInfoLinux();
 
 public:
-  static void Initialize();
+  static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr);
 
   static llvm::VersionTuple GetOSVersion();
   static bool GetOSBuildString(std::string &s);
Index: lldb/include/lldb/Host/HostInfoBase.h
===================================================================
--- lldb/include/lldb/Host/HostInfoBase.h
+++ lldb/include/lldb/Host/HostInfoBase.h
@@ -37,7 +37,13 @@
   ~HostInfoBase() {}
 
 public:
-  static void Initialize();
+  /// A helper function for determining the liblldb location. It receives a
+  /// FileSpec with the location of file containing _this_ code. It can
+  /// (optionally) replace it with a file spec pointing to a more canonical
+  /// copy.
+  using SharedLibraryDirectoryHelper = void(FileSpec &this_file);
+
+  static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr);
   static void Terminate();
 
   /// Gets the host target triple.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to