File indexing completed on 2024-05-12 03:54:59

0001 /*
0002     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0003     SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>
0004 */
0005 
0006 #include "klibexec.h"
0007 #include <config-util.h>
0008 
0009 #if HAVE_DLADDR
0010 #include <dlfcn.h>
0011 #elif defined(Q_OS_WIN)
0012 #include <windows.h>
0013 
0014 #include <QVarLengthArray>
0015 #endif
0016 
0017 #include <QCoreApplication>
0018 #include <QDir>
0019 #include <QLibraryInfo>
0020 
0021 #include <kcoreaddons_debug.h>
0022 
0023 static QString libraryPathFromAddress(void *address)
0024 {
0025 #if HAVE_DLADDR
0026     Dl_info info{};
0027     if (dladdr(address, &info) == 0) {
0028         qCWarning(KCOREADDONS_DEBUG) << "Failed to match address to shared object.";
0029         // Do not call dlerror. It's only expected to return something useful on freebsd!
0030         return {};
0031     }
0032     return QFile::decodeName(info.dli_fname);
0033 #elif defined(Q_OS_WIN)
0034     HMODULE hModule = nullptr;
0035     if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast<LPWSTR>(address), &hModule)) {
0036         qCWarning(KCOREADDONS_DEBUG) << "Failed to GetModuleHandleExW" << GetLastError();
0037         return {};
0038     }
0039     if (!hModule) {
0040         qCWarning(KCOREADDONS_DEBUG) << "hModule null unexpectedly";
0041         return {};
0042     }
0043 
0044     QVarLengthArray<wchar_t, MAX_PATH> pathArray;
0045     DWORD pathSize = pathArray.size();
0046     while (pathSize == pathArray.size()) { // pathSize doesn't include the null byte on success, so this only ever true if we need to grow
0047         pathArray.resize(pathArray.size() + MAX_PATH);
0048         pathSize = GetModuleFileNameW(hModule, pathArray.data(), pathArray.size());
0049         if (pathSize == 0) {
0050             qCWarning(KCOREADDONS_DEBUG) << "Failed to GetModuleFileNameW" << GetLastError();
0051             return {};
0052         }
0053     }
0054     return QDir::fromNativeSeparators(QString::fromWCharArray(pathArray.data()));
0055 #else // unsupported
0056     return {};
0057 #endif
0058 }
0059 
0060 QString KLibexec::pathFromAddress(const QString &relativePath, void *address)
0061 {
0062     const QString libraryPath = libraryPathFromAddress(address);
0063     const QString absoluteDirPath = QFileInfo(libraryPath).absolutePath();
0064     const QString libexecPath = QFileInfo(absoluteDirPath + QLatin1Char('/') + relativePath).absoluteFilePath();
0065     return libexecPath;
0066 }
0067 
0068 QStringList KLibexec::pathCandidates(const QString &relativePath)
0069 {
0070     const QString qLibexec = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath);
0071     const QString qLibexecKF6 = qLibexec + QLatin1String("/kf6");
0072 
0073     return {
0074         QCoreApplication::applicationDirPath(), // look where our application binary is located
0075         qLibexec, // look where libexec path is (can be set in qt.conf)
0076         qLibexecKF6, // on !win32 we use a kf6 suffix
0077         relativePath,
0078     };
0079 }