1/*
2 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
3 SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>
4*/
5
6#include "klibexec.h"
7#include <config-util.h>
8
9#if HAVE_DLADDR
10#include <dlfcn.h>
11#elif defined(Q_OS_WIN)
12#include <windows.h>
13
14#include <QVarLengthArray>
15#endif
16
17#include <QCoreApplication>
18#include <QDir>
19#include <QLibraryInfo>
20
21#include <kcoreaddons_debug.h>
22
23static QString libraryPathFromAddress(void *address)
24{
25#if HAVE_DLADDR
26 Dl_info info{};
27 if (dladdr(address: address, info: &info) == 0) {
28 qCWarning(KCOREADDONS_DEBUG) << "Failed to match address to shared object.";
29 // Do not call dlerror. It's only expected to return something useful on freebsd!
30 return {};
31 }
32 return QFile::decodeName(localFileName: info.dli_fname);
33#elif defined(Q_OS_WIN)
34 HMODULE hModule = nullptr;
35 if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast<LPWSTR>(address), &hModule)) {
36 qCWarning(KCOREADDONS_DEBUG) << "Failed to GetModuleHandleExW" << GetLastError();
37 return {};
38 }
39 if (!hModule) {
40 qCWarning(KCOREADDONS_DEBUG) << "hModule null unexpectedly";
41 return {};
42 }
43
44 QVarLengthArray<wchar_t, MAX_PATH> pathArray;
45 DWORD pathSize = pathArray.size();
46 while (pathSize == pathArray.size()) { // pathSize doesn't include the null byte on success, so this only ever true if we need to grow
47 pathArray.resize(pathArray.size() + MAX_PATH);
48 pathSize = GetModuleFileNameW(hModule, pathArray.data(), pathArray.size());
49 if (pathSize == 0) {
50 qCWarning(KCOREADDONS_DEBUG) << "Failed to GetModuleFileNameW" << GetLastError();
51 return {};
52 }
53 }
54 return QDir::fromNativeSeparators(QString::fromWCharArray(pathArray.data()));
55#else // unsupported
56 return {};
57#endif
58}
59
60QString KLibexec::pathFromAddress(const QString &relativePath, void *address)
61{
62 const QString libraryPath = libraryPathFromAddress(address);
63 const QString absoluteDirPath = QFileInfo(libraryPath).absolutePath();
64 const QString libexecPath = QFileInfo(absoluteDirPath + QLatin1Char('/') + relativePath).absoluteFilePath();
65 return libexecPath;
66}
67
68QStringList KLibexec::pathCandidates(const QString &relativePath)
69{
70 const QString qLibexec = QLibraryInfo::path(p: QLibraryInfo::LibraryExecutablesPath);
71 const QString qLibexecKF6 = qLibexec + QLatin1String("/kf6");
72
73 return {
74 QCoreApplication::applicationDirPath(), // look where our application binary is located
75 qLibexec, // look where libexec path is (can be set in qt.conf)
76 qLibexecKF6, // on !win32 we use a kf6 suffix
77 relativePath,
78 };
79}
80

source code of kcoreaddons/src/lib/util/klibexec.cpp