Jonathan.Crowther created this revision.
Jonathan.Crowther added reviewers: hubert.reinterpretcast, xingxue.
Herald added subscribers: llvm-commits, cfe-commits, arphaman, hiraditya.
Herald added projects: clang, LLVM.

Implemented (for AIX) a function to take any function and return the path of 
the load module it is located in. Used this function to implement 
`getMainExecutable` for AIX (instead of incorrectly attempting to use `/proc`) 
Additionally, fixed multiple locations where `getMainExecutable` was used 
incorrectly.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72736

Files:
  clang/lib/Tooling/CompilationDatabase.cpp
  clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
  clang/tools/libclang/CIndexer.cpp
  llvm/include/llvm/Support/FileUtilities.h
  llvm/lib/Support/FileUtilities.cpp
  llvm/lib/Support/Unix/Path.inc
  llvm/unittests/Support/ProgramTest.cpp

Index: llvm/unittests/Support/ProgramTest.cpp
===================================================================
--- llvm/unittests/Support/ProgramTest.cpp
+++ llvm/unittests/Support/ProgramTest.cpp
@@ -58,6 +58,8 @@
 static cl::opt<std::string>
 ProgramTestStringArg2("program-test-string-arg2");
 
+void DummyFunction() {}
+
 class ProgramEnvTest : public testing::Test {
   std::vector<StringRef> EnvTable;
   std::vector<std::string> EnvStorage;
@@ -114,8 +116,8 @@
     exit(0);
 
   // getMainExecutable returns an absolute path; prepend the long-path prefix.
-  std::string MyAbsExe =
-      sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+  void *MainAddr = (void *)(intptr_t)DummyFunction;
+  std::string MyAbsExe = sys::fs::getMainExecutable(TestMainArgv0, MainAddr);
   std::string MyExe;
   if (!StringRef(MyAbsExe).startswith("\\\\?\\"))
     MyExe.append("\\\\?\\");
@@ -160,8 +162,8 @@
     exit(1);
   }
 
-  std::string my_exe =
-      sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+  void *MainAddr = (void *)(intptr_t)DummyFunction;
+  std::string my_exe = sys::fs::getMainExecutable(TestMainArgv0, MainAddr);
   StringRef argv[] = {
       my_exe,
       "--gtest_filter=ProgramEnvTest.CreateProcessTrailingSlash",
@@ -197,8 +199,8 @@
     exit(0);
   }
 
-  std::string Executable =
-      sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+  void *MainAddr = (void *)(intptr_t)DummyFunction;
+  std::string Executable = sys::fs::getMainExecutable(TestMainArgv0, MainAddr);
   StringRef argv[] = {Executable,
                       "--gtest_filter=ProgramEnvTest.TestExecuteNoWait"};
 
@@ -252,8 +254,8 @@
     exit(0);
   }
 
-  std::string Executable =
-      sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+  void *MainAddr = (void *)(intptr_t)DummyFunction;
+  std::string Executable = sys::fs::getMainExecutable(TestMainArgv0, MainAddr);
   StringRef argv[] = {
       Executable, "--gtest_filter=ProgramEnvTest.TestExecuteAndWaitTimeout"};
 
Index: llvm/lib/Support/Unix/Path.inc
===================================================================
--- llvm/lib/Support/Unix/Path.inc
+++ llvm/lib/Support/Unix/Path.inc
@@ -87,6 +87,7 @@
 #include <sys/vfs.h>
 #elif defined(_AIX)
 #include <sys/statfs.h>
+#include <llvm/Support/FileUtilities.h>
 
 // <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to
 // `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide
@@ -222,7 +223,7 @@
   if (getprogpath(exe_path, argv0) != NULL)
     return exe_path;
 #elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__minix) ||       \
-    defined(__DragonFly__) || defined(__FreeBSD_kernel__) || defined(_AIX)
+    defined(__DragonFly__) || defined(__FreeBSD_kernel__)
   const char *curproc = "/proc/curproc/file";
   char exe_path[PATH_MAX];
   if (sys::fs::exists(curproc)) {
@@ -238,6 +239,8 @@
   // If we don't have procfs mounted, fall back to argv[0]
   if (getprogpath(exe_path, argv0) != NULL)
     return exe_path;
+#elif defined(_AIX)
+  return getLoadModuleFilenameForFunction(MainAddr).str();
 #elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__)
   char exe_path[MAXPATHLEN];
   const char *aPath = "/proc/self/exe";
Index: llvm/lib/Support/FileUtilities.cpp
===================================================================
--- llvm/lib/Support/FileUtilities.cpp
+++ llvm/lib/Support/FileUtilities.cpp
@@ -27,6 +27,16 @@
 #include <memory>
 #include <system_error>
 
+// These typedefs are needed for sys/ldr.h to work on AIX
+#if defined(_AIX)
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef void *__ptr64;
+static_assert(sizeof(__ptr64) == 8u, "__ptr64 size error.");
+#include <sys/ldr.h>
+#include <errno.h>
+#endif
+
 using namespace llvm;
 
 static bool isSignedChar(char C) {
@@ -268,6 +278,55 @@
   return CompareFailed;
 }
 
+#if defined(_AIX)
+// Returns the name of the load module that contains the entry point of the
+// function referenced by fp.
+SmallString<128> llvm::getLoadModuleFilenameForFunctionAIX(void (*fp)(void)) {
+  int PrevErrno = errno;
+
+  size_t BufSize = 2048u;
+  std::unique_ptr<char[]> Buf;
+  while (true) {
+    Buf = std::make_unique<char []>(BufSize);
+    errno = 0;
+    int Ret = loadquery(L_GETXINFO, Buf.get(), (unsigned int)BufSize);
+    if (Ret != -1)
+      break; // loadquery() was successful.
+    if (errno != ENOMEM)
+      llvm_unreachable("Encountered an unexpected loadquery() failure");
+
+    // errno == ENOMEM; try to allocate more memory.
+    if ((BufSize & ~((-1u) >> 1u)) != 0u)
+      llvm::report_fatal_error("BufSize needed for loadquery() too large");
+
+    Buf.release();
+    BufSize <<= 1u;
+  }
+
+  // Extract the function entry point from the function descriptor.
+  uint64_t EntryAddr = *reinterpret_cast<uintptr_t *>(fp);
+
+  // Loop to locate the function entry point in the loadquery() results.
+  ld_xinfo *CurInfo = reinterpret_cast<ld_xinfo *>(Buf.get());
+  while (true) {
+    uint64_t CurTextStart = (uint64_t)CurInfo->ldinfo_textorg;
+    uint64_t CurTextEnd = CurTextStart + CurInfo->ldinfo_textsize;
+    if (CurTextStart <= EntryAddr && EntryAddr < CurTextEnd)
+      break; // Successfully located.
+
+    if (CurInfo->ldinfo_next == 0u)
+      llvm::report_fatal_error("Cannot locate entry point in "
+                               "the loadquery() results");
+    CurInfo = reinterpret_cast<ld_xinfo *>(reinterpret_cast<char *>(CurInfo) +
+                                           CurInfo->ldinfo_next);
+  }
+
+  errno = PrevErrno;
+  char *filename = reinterpret_cast<char *>(CurInfo) + CurInfo->ldinfo_filename;
+  return filename;
+}
+#endif
+
 void llvm::AtomicFileWriteError::log(raw_ostream &OS) const {
   OS << "atomic_write_error: ";
   switch (Error) {
Index: llvm/include/llvm/Support/FileUtilities.h
===================================================================
--- llvm/include/llvm/Support/FileUtilities.h
+++ llvm/include/llvm/Support/FileUtilities.h
@@ -34,6 +34,22 @@
                              double AbsTol, double RelTol,
                              std::string *Error = nullptr);
 
+#if defined(_AIX)
+  SmallString<128> getLoadModuleFilenameForFunctionAIX(void (*Func)(void));
+#endif
+  
+  template <typename FuncAddrType>
+  SmallString<128> getLoadModuleFilenameForFunction(FuncAddrType FuncAddr) {
+    if (!FuncAddr) {
+      return "";
+    }
+    void (*FP)(void) = reinterpret_cast<void (*)(void)>(FuncAddr);
+#if defined(_AIX)
+    return getLoadModuleFilenameForFunctionAIX(FP);
+#endif
+    llvm::report_fatal_error(
+        "getLoadModuleFilenameForFunction not implemented for this platform");
+  }
 
   /// FileRemover - This class is a simple object meant to be stack allocated.
   /// If an exception is thrown from a region, the object removes the filename
Index: clang/tools/libclang/CIndexer.cpp
===================================================================
--- clang/tools/libclang/CIndexer.cpp
+++ clang/tools/libclang/CIndexer.cpp
@@ -38,63 +38,10 @@
 #else
 #include <dlfcn.h>
 #endif
+#include <llvm/Support/FileUtilities.h>
 
 using namespace clang;
 
-#ifdef _AIX
-namespace clang {
-namespace {
-
-template <typename LibClangPathType>
-void getClangResourcesPathImplAIX(LibClangPathType &LibClangPath) {
-  int PrevErrno = errno;
-
-  size_t BufSize = 2048u;
-  std::unique_ptr<char[]> Buf;
-  while (true) {
-    Buf = std::make_unique<char []>(BufSize);
-    errno = 0;
-    int Ret = loadquery(L_GETXINFO, Buf.get(), (unsigned int)BufSize);
-    if (Ret != -1)
-      break; // loadquery() was successful.
-    if (errno != ENOMEM)
-      llvm_unreachable("Encountered an unexpected loadquery() failure");
-
-    // errno == ENOMEM; try to allocate more memory.
-    if ((BufSize & ~((-1u) >> 1u)) != 0u)
-      llvm::report_fatal_error("BufSize needed for loadquery() too large");
-
-    Buf.release();
-    BufSize <<= 1u;
-  }
-
-  // Extract the function entry point from the function descriptor.
-  uint64_t EntryAddr =
-      reinterpret_cast<uintptr_t &>(clang_createTranslationUnit);
-
-  // Loop to locate the function entry point in the loadquery() results.
-  ld_xinfo *CurInfo = reinterpret_cast<ld_xinfo *>(Buf.get());
-  while (true) {
-    uint64_t CurTextStart = (uint64_t)CurInfo->ldinfo_textorg;
-    uint64_t CurTextEnd = CurTextStart + CurInfo->ldinfo_textsize;
-    if (CurTextStart <= EntryAddr && EntryAddr < CurTextEnd)
-      break; // Successfully located.
-
-    if (CurInfo->ldinfo_next == 0u)
-      llvm::report_fatal_error("Cannot locate entry point in "
-                               "the loadquery() results");
-    CurInfo = reinterpret_cast<ld_xinfo *>(reinterpret_cast<char *>(CurInfo) +
-                                           CurInfo->ldinfo_next);
-  }
-
-  LibClangPath += reinterpret_cast<char *>(CurInfo) + CurInfo->ldinfo_filename;
-  errno = PrevErrno;
-}
-
-} // end anonymous namespace
-} // end namespace clang
-#endif
-
 const std::string &CIndexer::getClangResourcesPath() {
   // Did we already compute the path?
   if (!ResourcesPath.empty())
@@ -122,7 +69,8 @@
 
   LibClangPath += path;
 #elif defined(_AIX)
-  getClangResourcesPathImplAIX(LibClangPath);
+  LibClangPath +=
+      llvm::getLoadModuleFilenameForFunction(clang_createTranslationUnit);
 #else
   // This silly cast below avoids a C++ warning.
   Dl_info info;
Index: clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
===================================================================
--- clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
+++ clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
@@ -921,7 +921,8 @@
 
   // Save the current executable directory as it will be useful to find other
   // tools.
-  BundlerExecutable = sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
+  void *MainAddr = (void *)(intptr_t)PrintVersion;
+  BundlerExecutable = sys::fs::getMainExecutable(argv[0], MainAddr);
 
   if (llvm::Error Err = Unbundle ? UnbundleFiles() : BundleFiles()) {
     reportError(std::move(Err));
Index: clang/lib/Tooling/CompilationDatabase.cpp
===================================================================
--- clang/lib/Tooling/CompilationDatabase.cpp
+++ clang/lib/Tooling/CompilationDatabase.cpp
@@ -227,9 +227,9 @@
 };
 
 std::string GetClangToolCommand() {
-  static int Dummy;
+  void *MainAddr = (void *)(intptr_t)GetClangToolCommand;
   std::string ClangExecutable =
-      llvm::sys::fs::getMainExecutable("clang", (void *)&Dummy);
+      llvm::sys::fs::getMainExecutable("clang", MainAddr);
   SmallString<128> ClangToolPath;
   ClangToolPath = llvm::sys::path::parent_path(ClangExecutable);
   llvm::sys::path::append(ClangToolPath, "clang-tool");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to