2022-01-05 16:14:27 +01:00
|
|
|
#include "fastfetch.h"
|
2026-01-06 09:48:38 +08:00
|
|
|
#include "common/library.h"
|
2022-01-05 16:14:27 +01:00
|
|
|
|
2026-03-19 15:24:55 +08:00
|
|
|
#if _WIN32
|
|
|
|
|
#include "common/debug.h"
|
|
|
|
|
#include "common/windows/nt.h"
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <ntstatus.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-05-24 14:40:14 +08:00
|
|
|
#ifndef FF_DISABLE_DLOPEN
|
2024-05-23 16:35:16 +08:00
|
|
|
|
2022-01-05 16:14:27 +01:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
2022-09-22 22:02:58 +02:00
|
|
|
//Clang doesn't define __SANITIZE_ADDRESS__ but defines __has_feature(address_sanitizer)
|
2024-04-26 08:48:58 +08:00
|
|
|
#if !defined(__SANITIZE_ADDRESS__) && defined(__has_feature)
|
2022-09-22 22:02:58 +02:00
|
|
|
#if __has_feature(address_sanitizer)
|
|
|
|
|
#define __SANITIZE_ADDRESS__
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-10-13 17:00:36 +08:00
|
|
|
#ifndef FF_DLOPEN_FLAGS
|
|
|
|
|
#ifdef __SANITIZE_ADDRESS__
|
|
|
|
|
#define FF_DLOPEN_FLAGS RTLD_LAZY | RTLD_NODELETE
|
|
|
|
|
#else
|
|
|
|
|
#define FF_DLOPEN_FLAGS RTLD_LAZY
|
|
|
|
|
#endif
|
2022-09-22 22:02:58 +02:00
|
|
|
#endif
|
|
|
|
|
|
2022-04-11 17:41:21 +02:00
|
|
|
static void* libraryLoad(const char* path, int maxVersion)
|
|
|
|
|
{
|
2022-09-22 22:02:58 +02:00
|
|
|
void* result = dlopen(path, FF_DLOPEN_FLAGS);
|
2022-10-09 02:04:41 +08:00
|
|
|
|
2022-10-14 16:39:48 +08:00
|
|
|
#ifdef _WIN32
|
2022-10-09 02:04:41 +08:00
|
|
|
|
|
|
|
|
// libX.dll.1 never exists on Windows, while libX-1.dll may exist
|
|
|
|
|
FF_UNUSED(maxVersion)
|
|
|
|
|
|
2024-11-04 09:56:44 +08:00
|
|
|
if(result != NULL)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
uint32_t pathLen = ffStrbufLastIndexC(&instance.state.platform.exePath, '/');
|
|
|
|
|
if (pathLen == instance.state.platform.exePath.length)
|
|
|
|
|
return result;
|
|
|
|
|
|
2026-03-19 15:24:55 +08:00
|
|
|
char absPath[MAX_PATH * 2];
|
2024-11-04 09:56:44 +08:00
|
|
|
strcpy(mempcpy(absPath, instance.state.platform.exePath.chars, pathLen + 1), path);
|
|
|
|
|
return dlopen(absPath, FF_DLOPEN_FLAGS);
|
|
|
|
|
|
2022-10-09 02:04:41 +08:00
|
|
|
#else
|
|
|
|
|
|
2022-09-14 12:41:43 +02:00
|
|
|
if(result != NULL || maxVersion < 0)
|
2022-04-11 17:41:21 +02:00
|
|
|
return result;
|
|
|
|
|
|
2023-04-15 15:29:54 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY pathbuf = ffStrbufCreateA(64);
|
2022-04-11 17:41:21 +02:00
|
|
|
ffStrbufAppendS(&pathbuf, path);
|
|
|
|
|
ffStrbufAppendC(&pathbuf, '.');
|
|
|
|
|
|
|
|
|
|
for(int i = maxVersion; i >= 0; --i)
|
|
|
|
|
{
|
|
|
|
|
uint32_t originalLength = pathbuf.length;
|
2025-08-19 17:22:11 +08:00
|
|
|
ffStrbufAppendSInt(&pathbuf, i);
|
2022-04-11 17:41:21 +02:00
|
|
|
|
2022-09-22 22:02:58 +02:00
|
|
|
result = dlopen(pathbuf.chars, FF_DLOPEN_FLAGS);
|
2022-04-11 17:41:21 +02:00
|
|
|
if(result != NULL)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
ffStrbufSubstrBefore(&pathbuf, originalLength);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-09 02:04:41 +08:00
|
|
|
#endif
|
|
|
|
|
|
2022-04-11 17:41:21 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:28:35 +08:00
|
|
|
void* ffLibraryLoad(const char* path, int maxVersion, ...)
|
2022-01-05 16:14:27 +01:00
|
|
|
{
|
2024-09-04 15:28:35 +08:00
|
|
|
void* result = libraryLoad(path, maxVersion);
|
2022-01-05 16:14:27 +01:00
|
|
|
|
2024-09-04 15:28:35 +08:00
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
va_list defaultNames;
|
|
|
|
|
va_start(defaultNames, maxVersion);
|
2022-01-05 16:14:27 +01:00
|
|
|
|
2024-09-04 15:28:35 +08:00
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
const char* pathRest = va_arg(defaultNames, const char*);
|
|
|
|
|
if(pathRest == NULL)
|
|
|
|
|
break;
|
2022-01-05 16:14:27 +01:00
|
|
|
|
2024-09-04 15:28:35 +08:00
|
|
|
int maxVersionRest = va_arg(defaultNames, int);
|
|
|
|
|
result = libraryLoad(pathRest, maxVersionRest);
|
|
|
|
|
} while (!result);
|
2022-04-11 17:41:21 +02:00
|
|
|
|
2024-09-04 15:28:35 +08:00
|
|
|
va_end(defaultNames);
|
2022-01-05 16:14:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2024-05-23 16:35:16 +08:00
|
|
|
|
|
|
|
|
#endif
|
2026-03-19 15:24:55 +08:00
|
|
|
|
|
|
|
|
#if _WIN32
|
|
|
|
|
|
|
|
|
|
void* dlopen(const char* path, FF_MAYBE_UNUSED int mode)
|
|
|
|
|
{
|
|
|
|
|
wchar_t pathW[MAX_PATH + 1];
|
|
|
|
|
ULONG pathWBytes = 0;
|
|
|
|
|
|
|
|
|
|
NTSTATUS status = RtlUTF8ToUnicodeN(pathW, sizeof(pathW), &pathWBytes, path, (uint32_t)strlen(path) + 1);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
FF_DEBUG("RtlUTF8ToUnicodeN failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PVOID module = NULL;
|
|
|
|
|
status = LdrLoadDll(NULL, NULL, &(UNICODE_STRING) {
|
|
|
|
|
.Length = (USHORT) pathWBytes - sizeof(wchar_t), // Exclude null terminator
|
|
|
|
|
.MaximumLength = (USHORT) pathWBytes,
|
|
|
|
|
.Buffer = pathW,
|
|
|
|
|
}, &module);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
FF_DEBUG("LdrLoadDll failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return module;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int dlclose(void* handle)
|
|
|
|
|
{
|
|
|
|
|
NTSTATUS status = LdrUnloadDll(handle);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
FF_DEBUG("LdrUnloadDll failed for handle %p with status 0x%08lX: %s", handle, status, ffDebugNtStatus(status));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* dlsym(void* handle, const char* symbol)
|
|
|
|
|
{
|
|
|
|
|
void* address;
|
|
|
|
|
USHORT symbolBytes = (USHORT) strlen(symbol) + 1;
|
|
|
|
|
NTSTATUS status = LdrGetProcedureAddress(handle, &(ANSI_STRING) {
|
|
|
|
|
.Length = symbolBytes - sizeof(char),
|
|
|
|
|
.MaximumLength = symbolBytes,
|
|
|
|
|
.Buffer = (char*) symbol,
|
|
|
|
|
}, 0, &address);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
FF_DEBUG("LdrGetProcedureAddress failed for symbol %s with status 0x%08lX: %s", symbol, status, ffDebugNtStatus(status));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return address;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* ffLibraryGetModule(const wchar_t* libraryFileName)
|
|
|
|
|
{
|
|
|
|
|
assert(libraryFileName != NULL && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
|
|
|
|
|
|
|
|
|
|
void* module = NULL;
|
|
|
|
|
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t)) + sizeof(wchar_t);
|
|
|
|
|
NTSTATUS status = LdrGetDllHandle(NULL, NULL, &(UNICODE_STRING) {
|
|
|
|
|
.Length = libraryFileNameBytes - sizeof(wchar_t),
|
|
|
|
|
.MaximumLength = libraryFileNameBytes,
|
|
|
|
|
.Buffer = (wchar_t*) libraryFileName,
|
|
|
|
|
}, &module);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
FF_DEBUG("LdrGetDllHandle failed for library %ls with status 0x%08lX: %s", libraryFileName, status, ffDebugNtStatus(status));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return module;
|
|
|
|
|
}
|
|
|
|
|
#endif
|