From 4361c5e7876b3beaf6ad2cbd4741050c427748e8 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 8 Aug 2026 22:18:27 +0800 Subject: [PATCH] Library: adds function `ffLibraryIterateDynamicLibs` --- src/common/impl/library.c | 75 +++++++++++++++++++++++++++++++++++++++ src/common/library.h | 6 +++- src/common/windows/nt.h | 16 +++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/common/impl/library.c b/src/common/impl/library.c index 440ea1336..f4cfd1421 100644 --- a/src/common/impl/library.c +++ b/src/common/impl/library.c @@ -178,3 +178,78 @@ void* ffLibraryGetModule(const wchar_t* libraryFileName) { return module; } #endif + +struct LibraryIterateDynamicLibsBundle { + FFLibraryIterateCallback callback; + void* userData; +}; + +#if _WIN32 + +static void ffLibraryIterateDynamicLibsCallback(PLDR_DATA_TABLE_ENTRY DataTableEntry, PVOID Context, BOOLEAN* StopEnumeration) { + if (DataTableEntry->FullDllName.Buffer == nullptr || DataTableEntry->FullDllName.Buffer[0] == L'\0') { + return; + } + + char path[PATH_MAX * 3]; + ULONG outBytes; + if (NT_SUCCESS(RtlUnicodeToUTF8N(path, sizeof(path), &outBytes, DataTableEntry->FullDllName.Buffer, (uint32_t) (DataTableEntry->FullDllName.Length + sizeof(wchar_t))))) { + struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) Context; + *StopEnumeration = !bundle->callback(path, bundle->userData); + } +} + +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { + struct LibraryIterateDynamicLibsBundle bundle = { + .callback = callback, + .userData = userData, + }; + LdrEnumerateLoadedModules(FALSE, ffLibraryIterateDynamicLibsCallback, &bundle); +} + +#elif defined(__APPLE__) + +#include + +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { + uint32_t imageCount = _dyld_image_count(); + for (uint32_t i = 0; i < imageCount; ++i) { + const char* name = _dyld_get_image_name(i); + if (name == nullptr || name[0] == '\0') { + continue; + } + + if (!callback(name, userData)) { + break; + } + } +} + +#elif __has_include() + #include + +static int ffLibraryIterateDynamicLibsCallback(struct dl_phdr_info* info, size_t, void* data) { + if (info->dlpi_name == nullptr || info->dlpi_name[0] == '\0') { + return 0; + } + + struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) data; + return !bundle->callback(info->dlpi_name, bundle->userData); +} + +void ffLibraryIterateDynamicLibs(bool (*callback)(const char* name, void* userData), void* userData) { + dl_iterate_phdr( + ffLibraryIterateDynamicLibsCallback, + &(struct LibraryIterateDynamicLibsBundle) { + .callback = callback, + .userData = userData, + }); +} + +#else + +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback, void*) { + // Not implemented for this platform +} + +#endif diff --git a/src/common/library.h b/src/common/library.h index 06003cc93..f2b2cca33 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -1,6 +1,6 @@ #pragma once -#include "fastfetch.h" +#include "fastfetch.h" // IWYU pragma: keep #ifndef FF_DISABLE_DLOPEN @@ -111,3 +111,7 @@ void* ffLibraryLoadMulti(const char* path, int maxVersion, ...); #if _WIN32 void* ffLibraryGetModule(const wchar_t* libraryFileName); #endif + +// Return false to stop iterating, true to continue +typedef bool (*FFLibraryIterateCallback)(const char* name, void* userData); +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData); diff --git a/src/common/windows/nt.h b/src/common/windows/nt.h index 77e0a00c1..f00384984 100644 --- a/src/common/windows/nt.h +++ b/src/common/windows/nt.h @@ -1279,6 +1279,22 @@ NTSYSAPI NTSTATUS NTAPI LdrGetProcedureAddress( _In_opt_ ULONG ProcedureNumber, _Out_ PVOID* ProcedureAddress); +typedef _Function_class_(LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION) +VOID NTAPI LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION( + _In_ PLDR_DATA_TABLE_ENTRY DataTableEntry, + _In_opt_ PVOID Context, + _Inout_ BOOLEAN* StopEnumeration +); + +NTSYSAPI +NTSTATUS +NTAPI +LdrEnumerateLoadedModules( + _In_ BOOLEAN ReservedFlag, + _In_ LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION* EnumProc, + _In_opt_ PVOID Context +); + typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2