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"); 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/tools/libclang/CIndexer.cpp =================================================================== --- clang/tools/libclang/CIndexer.cpp +++ clang/tools/libclang/CIndexer.cpp @@ -38,63 +38,10 @@ #else #include #endif +#include using namespace clang; -#ifdef _AIX -namespace clang { -namespace { - -template -void getClangResourcesPathImplAIX(LibClangPathType &LibClangPath) { - int PrevErrno = errno; - - size_t BufSize = 2048u; - std::unique_ptr Buf; - while (true) { - Buf = std::make_unique(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(clang_createTranslationUnit); - - // Loop to locate the function entry point in the loadquery() results. - ld_xinfo *CurInfo = reinterpret_cast(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(reinterpret_cast(CurInfo) + - CurInfo->ldinfo_next); - } - - LibClangPath += reinterpret_cast(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,9 @@ LibClangPath += path; #elif defined(_AIX) - getClangResourcesPathImplAIX(LibClangPath); + LibClangPath += + llvm::getLoadModuleFilenameForFunction(clang_createTranslationUnit) + ->c_str(); #else // This silly cast below avoids a C++ warning. Dl_info info; Index: llvm/include/llvm/Support/SystemUtils.h =================================================================== --- llvm/include/llvm/Support/SystemUtils.h +++ llvm/include/llvm/Support/SystemUtils.h @@ -14,6 +14,8 @@ #ifndef LLVM_SUPPORT_SYSTEMUTILS_H #define LLVM_SUPPORT_SYSTEMUTILS_H +#include + namespace llvm { class raw_ostream; @@ -26,6 +28,16 @@ bool print_warning = true ///< Control whether warnings are printed ); +llvm::Expected> +getLoadModuleFilenameForFunctionImpl(void (*Func)(void)); + +template +llvm::Expected> +getLoadModuleFilenameForFunction(FuncAddrType FuncAddr) { + void (*FP)(void) = reinterpret_cast(FuncAddr); + return getLoadModuleFilenameForFunctionImpl(FP); +} + } // End llvm namespace #endif Index: llvm/lib/Support/SystemUtils.cpp =================================================================== --- llvm/lib/Support/SystemUtils.cpp +++ llvm/lib/Support/SystemUtils.cpp @@ -13,6 +13,17 @@ #include "llvm/Support/SystemUtils.h" #include "llvm/Support/raw_ostream.h" + +// 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 +#include +#endif + using namespace llvm; bool llvm::CheckBitcodeOutputToConsole(raw_ostream &stream_to_check, @@ -28,3 +39,66 @@ } return false; } + +#if defined(_AIX) +// Returns the name of the load module that contains the entry point of the +// function referenced by fp. +static SmallString<128> getLoadModuleFilenameForFunctionAIX(void (*fp)(void)) { + int PrevErrno = errno; + + size_t BufSize = 2048u; + std::unique_ptr Buf; + while (true) { + Buf = std::make_unique(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(fp); + + // Loop to locate the function entry point in the loadquery() results. + ld_xinfo *CurInfo = reinterpret_cast(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(reinterpret_cast(CurInfo) + + CurInfo->ldinfo_next); + } + + errno = PrevErrno; + char *filename = reinterpret_cast(CurInfo) + CurInfo->ldinfo_filename; + return SmallString<128>(filename); +} +#endif + +llvm::Expected> +llvm::getLoadModuleFilenameForFunctionImpl(void (*fp)(void)) { + if (!fp) { + return createStringError(std::errc::invalid_argument, + "Function address can not be found"); + } +#if defined(_AIX) + return getLoadModuleFilenameForFunctionAIX(fp); +#endif + llvm::report_fatal_error( + "getLoadModuleFilenameForFunction not implemented on this platform"); +} + Index: llvm/lib/Support/Unix/Path.inc =================================================================== --- llvm/lib/Support/Unix/Path.inc +++ llvm/lib/Support/Unix/Path.inc @@ -87,6 +87,7 @@ #include #elif defined(_AIX) #include +#include // depends on `uint` to be a typedef from to // `uint_t`; however, 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)->c_str(); #elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__) char exe_path[MAXPATHLEN]; const char *aPath = "/proc/self/exe"; Index: llvm/unittests/Support/ProgramTest.cpp =================================================================== --- llvm/unittests/Support/ProgramTest.cpp +++ llvm/unittests/Support/ProgramTest.cpp @@ -58,6 +58,8 @@ static cl::opt ProgramTestStringArg2("program-test-string-arg2"); +void DummyFunction() {} + class ProgramEnvTest : public testing::Test { std::vector EnvTable; std::vector 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"};