[llvm] 13ad00b - [ORC] Add a TargetProcessControl-based dynamic library search generator.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 22 16:31:33 PDT 2020


Author: Lang Hames
Date: 2020-07-22T16:19:24-07:00
New Revision: 13ad00be98e10bb08aeb6eacf8f3aebff653578c

URL: https://github.com/llvm/llvm-project/commit/13ad00be98e10bb08aeb6eacf8f3aebff653578c
DIFF: https://github.com/llvm/llvm-project/commit/13ad00be98e10bb08aeb6eacf8f3aebff653578c.diff

LOG: [ORC] Add a TargetProcessControl-based dynamic library search generator.

TPCDynamicLibrarySearchGenerator uses a TargetProcessControl instance to
load libraries and search for symbol addresses in a target process. It
can be used in place of a DynamicLibrarySearchGenerator to enable
target-process agnostic lookup.

Added: 
    llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
    llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp

Modified: 
    llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
    llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
    llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
    llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
index a88360e3a8cd..a6cd5dbb1630 100644
--- a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
+++ b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
@@ -25,6 +25,7 @@
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
+#include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"
 #include "llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
 #include "llvm/Support/InitLLVM.h"
@@ -51,17 +52,23 @@ ExitOnError ExitOnErr;
 
 const llvm::StringRef FooMod =
     R"(
+  declare i32 @return1()
+
   define i32 @foo_body() {
   entry:
-    ret i32 1
+    %0 = call i32 @return1()
+    ret i32 %0
   }
 )";
 
 const llvm::StringRef BarMod =
     R"(
+  declare i32 @return2()
+
   define i32 @bar_body() {
   entry:
-    ret i32 2
+    %0 = call i32 @return2()
+    ret i32 %0
   }
 )";
 
@@ -91,6 +98,9 @@ const llvm::StringRef MainMod =
   declare i32 @bar()
 )";
 
+extern "C" int32_t return1() { return 1; }
+extern "C" int32_t return2() { return 2; }
+
 static void *reenter(void *Ctx, void *TrampolineAddr) {
   std::promise<void *> LandingAddressP;
   auto LandingAddressF = LandingAddressP.get_future();
@@ -105,6 +115,11 @@ static void *reenter(void *Ctx, void *TrampolineAddr) {
   return LandingAddressF.get();
 }
 
+static void reportErrorAndExit() {
+  errs() << "Unable to lazily compile function. Exiting.\n";
+  exit(1);
+}
+
 cl::list<std::string> InputArgv(cl::Positional,
                                 cl::desc("<program arguments>..."));
 
@@ -135,8 +150,11 @@ int main(int argc, char *argv[]) {
   auto TPCIU = ExitOnErr(TPCIndirectionUtils::Create(*TPC));
   ExitOnErr(TPCIU->writeResolverBlock(pointerToJITTargetAddress(&reenter),
                                       pointerToJITTargetAddress(TPCIU.get())));
-  TPCIU->createLazyCallThroughManager(J->getExecutionSession(), 0);
+  TPCIU->createLazyCallThroughManager(
+      J->getExecutionSession(), pointerToJITTargetAddress(&reportErrorAndExit));
   auto ISM = TPCIU->createIndirectStubsManager();
+  J->getMainJITDylib().addGenerator(
+      ExitOnErr(TPCDynamicLibrarySearchGenerator::GetForTargetProcess(*TPC)));
 
   // (4) Add modules.
   ExitOnErr(J->addIRModule(ExitOnErr(parseExampleModule(FooMod, "foo-mod"))));

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
new file mode 100644
index 000000000000..6c95e22a4257
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
@@ -0,0 +1,60 @@
+//===------------ TPCDynamicLibrarySearchGenerator.h ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Support loading and searching of dynamic libraries in a target process via
+// the TargetProcessControl class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TPCDYNAMICLIBRARYSEARCHGENERATOR_H
+#define LLVM_EXECUTIONENGINE_ORC_TPCDYNAMICLIBRARYSEARCHGENERATOR_H
+
+#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
+
+namespace llvm {
+namespace orc {
+
+class TPCDynamicLibrarySearchGenerator : public JITDylib::DefinitionGenerator {
+public:
+  /// Create a DynamicLibrarySearchGenerator that searches for symbols in the
+  /// library with the given handle.
+  ///
+  /// If the Allow predicate is given then only symbols matching the predicate
+  /// will be searched for. If the predicate is not given then all symbols will
+  /// be searched for.
+  TPCDynamicLibrarySearchGenerator(
+      TargetProcessControl &TPC,
+      TargetProcessControl::DynamicLibraryHandle DylibHandle)
+      : TPC(TPC), DylibHandle(DylibHandle) {}
+
+  /// Permanently loads the library at the given path and, on success, returns
+  /// a DynamicLibrarySearchGenerator that will search it for symbol definitions
+  /// in the library. On failure returns the reason the library failed to load.
+  static Expected<std::unique_ptr<TPCDynamicLibrarySearchGenerator>>
+  Load(TargetProcessControl &TPC, const char *LibraryPath);
+
+  /// Creates a TPCDynamicLibrarySearchGenerator that searches for symbols in
+  /// the target process.
+  static Expected<std::unique_ptr<TPCDynamicLibrarySearchGenerator>>
+  GetForTargetProcess(TargetProcessControl &TPC) {
+    return Load(TPC, nullptr);
+  }
+
+  Error tryToGenerate(LookupKind K, JITDylib &JD,
+                      JITDylibLookupFlags JDLookupFlags,
+                      const SymbolLookupSet &Symbols) override;
+
+private:
+  TargetProcessControl &TPC;
+  TargetProcessControl::DynamicLibraryHandle DylibHandle;
+};
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TPCDYNAMICLIBRARYSEARCHGENERATOR_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
index cc0016e105d8..37bfa5a45b6c 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
@@ -13,11 +13,16 @@
 #ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESSCONTROL_H
 #define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESSCONTROL_H
 
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/MSVCErrorWorkarounds.h"
 
 #include <future>
+#include <vector>
 
 namespace llvm {
 namespace orc {
@@ -105,6 +110,22 @@ class TargetProcessControl {
     }
   };
 
+  using DynamicLibraryHandle = JITTargetAddress;
+
+  /// Request lookup within a single library.
+  /// If Library is None then the whole target process should be searched.
+  struct LookupRequestElement {
+    LookupRequestElement(DynamicLibraryHandle Handle,
+                         const SymbolLookupSet &Symbols)
+        : Handle(Handle), Symbols(Symbols) {}
+    DynamicLibraryHandle Handle;
+    const SymbolLookupSet &Symbols;
+  };
+
+  using LookupRequest = ArrayRef<LookupRequestElement>;
+
+  using LookupResult = std::vector<std::vector<JITTargetAddress>>;
+
   virtual ~TargetProcessControl();
 
   /// Return the Triple for the target process.
@@ -119,7 +140,16 @@ class TargetProcessControl {
   /// Return a MemoryAccess object for the target process.
   MemoryAccess &getMemoryAccess() const { return *MemAccess; }
 
-  /// Load the library at the given path.
+  /// Load the library at the given path. Returns a handle to the loaded
+  /// library. If LibraryPath is null this function will return the global
+  /// handle for the target process.
+  virtual Expected<DynamicLibraryHandle>
+  loadLibrary(const char *LibraryPath) = 0;
+
+  /// Search for symbols in the target process.
+  /// The result of the lookup is a 2-dimentional array of target addresses
+  /// that correspond to the lookup order.
+  virtual Expected<LookupResult> lookupSymbols(LookupRequest Request) = 0;
 
 protected:
   TargetProcessControl(Triple TT, unsigned PageSize);
@@ -138,6 +168,10 @@ class SelfTargetProcessControl : public TargetProcessControl,
 
   static Expected<std::unique_ptr<SelfTargetProcessControl>> Create();
 
+  Expected<DynamicLibraryHandle> loadLibrary(const char *LibraryPath) override;
+
+  Expected<LookupResult> lookupSymbols(LookupRequest Request) override;
+
 private:
   void writeUInt8s(ArrayRef<UInt8Write> Ws,
                    WriteResultFn OnWriteComplete) override;
@@ -156,6 +190,9 @@ class SelfTargetProcessControl : public TargetProcessControl,
 
   std::unique_ptr<jitlink::InProcessMemoryManager> IPMM =
       std::make_unique<jitlink::InProcessMemoryManager>();
+
+  char GlobalManglingPrefix = 0;
+  std::vector<std::unique_ptr<sys::DynamicLibrary>> DynamicLibraries;
 };
 
 } // end namespace orc

diff  --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
index f9d7924cd5e8..1876c3512d11 100644
--- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -26,6 +26,7 @@ add_llvm_component_library(LLVMOrcJIT
   SpeculateAnalyses.cpp
   TargetProcessControl.cpp
   ThreadSafeModule.cpp
+  TPCDynamicLibrarySearchGenerator.cpp
   TPCIndirectionUtils.cpp
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc

diff  --git a/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
new file mode 100644
index 000000000000..ea8bde971d1d
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
@@ -0,0 +1,51 @@
+//===---------------- TPCDynamicLibrarySearchGenerator.cpp ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"
+
+namespace llvm {
+namespace orc {
+
+Expected<std::unique_ptr<TPCDynamicLibrarySearchGenerator>>
+TPCDynamicLibrarySearchGenerator::Load(TargetProcessControl &TPC,
+                                       const char *LibraryPath) {
+  auto Handle = TPC.loadLibrary(LibraryPath);
+  if (!Handle)
+    return Handle.takeError();
+
+  return std::make_unique<TPCDynamicLibrarySearchGenerator>(TPC, *Handle);
+}
+
+Error TPCDynamicLibrarySearchGenerator::tryToGenerate(
+    LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags,
+    const SymbolLookupSet &Symbols) {
+
+  if (Symbols.empty())
+    return Error::success();
+
+  SymbolMap NewSymbols;
+
+  TargetProcessControl::LookupRequestElement Request(DylibHandle, Symbols);
+  auto Result = TPC.lookupSymbols(Request);
+  if (!Result)
+    return Result.takeError();
+
+  assert(Result->size() == 1 && "Results for more than one library returned");
+  assert(Result->front().size() == Symbols.size() &&
+         "Result has incorrect number of elements");
+
+  auto ResultI = Result->front().begin();
+  for (auto &KV : Symbols)
+    NewSymbols[KV.first] =
+        JITEvaluatedSymbol(*ResultI++, JITSymbolFlags::Exported);
+
+  return JD.define(absoluteSymbols(std::move(NewSymbols)));
+}
+
+} // end namespace orc
+} // end namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
index 833b597fe712..ab07d3ad90b1 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
+
+#include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/Process.h"
 
@@ -26,6 +28,8 @@ SelfTargetProcessControl::SelfTargetProcessControl(Triple TT, unsigned PageSize)
     : TargetProcessControl(std::move(TT), PageSize) {
   this->MemMgr = IPMM.get();
   this->MemAccess = this;
+  if (this->TT.isOSBinFormatMachO())
+    GlobalManglingPrefix = '_';
 }
 
 Expected<std::unique_ptr<SelfTargetProcessControl>>
@@ -39,6 +43,48 @@ SelfTargetProcessControl::Create() {
   return std::make_unique<SelfTargetProcessControl>(std::move(TT), *PageSize);
 }
 
+Expected<TargetProcessControl::DynamicLibraryHandle>
+SelfTargetProcessControl::loadLibrary(const char *LibraryPath) {
+  std::string ErrMsg;
+  auto Dylib = std::make_unique<sys::DynamicLibrary>(
+      sys::DynamicLibrary::getPermanentLibrary(LibraryPath, &ErrMsg));
+  if (!Dylib->isValid())
+    return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
+  DynamicLibraries.push_back(std::move(Dylib));
+  return pointerToJITTargetAddress(DynamicLibraries.back().get());
+}
+
+Expected<TargetProcessControl::LookupResult>
+SelfTargetProcessControl::lookupSymbols(LookupRequest Request) {
+  LookupResult R;
+
+  for (auto &Elem : Request) {
+    auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary *>(Elem.Handle);
+    assert(llvm::find_if(DynamicLibraries,
+                         [=](const std::unique_ptr<sys::DynamicLibrary> &DL) {
+                           return DL.get() == Dylib;
+                         }) != DynamicLibraries.end() &&
+           "Invalid handle");
+
+    R.push_back(std::vector<JITTargetAddress>());
+    for (auto &KV : Elem.Symbols) {
+      auto &Sym = KV.first;
+      std::string Tmp((*Sym).data() + !!GlobalManglingPrefix,
+                      (*Sym).size() - !!GlobalManglingPrefix);
+      if (void *Addr = Dylib->getAddressOfSymbol(Tmp.c_str()))
+        R.back().push_back(pointerToJITTargetAddress(Addr));
+      else if (KV.second == SymbolLookupFlags::RequiredSymbol) {
+        // FIXME: Collect all failing symbols before erroring out.
+        SymbolNameVector MissingSymbols;
+        MissingSymbols.push_back(Sym);
+        return make_error<SymbolsNotFound>(std::move(MissingSymbols));
+      }
+    }
+  }
+
+  return R;
+}
+
 void SelfTargetProcessControl::writeUInt8s(ArrayRef<UInt8Write> Ws,
                                            WriteResultFn OnWriteComplete) {
   for (auto &W : Ws)


        


More information about the llvm-commits mailing list