plugins: Add an API entry for finding functions by name

This commit is contained in:
vaxerski 2023-03-31 18:31:11 +01:00
parent de3b00b5ee
commit 430778293e
2 changed files with 87 additions and 0 deletions

View file

@ -3,6 +3,10 @@
#include "../debug/HyprCtl.hpp" #include "../debug/HyprCtl.hpp"
#include <dlfcn.h> #include <dlfcn.h>
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/sysctl.h>
#endif
APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) { APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
@ -241,3 +245,71 @@ APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::stri
return true; return true;
} }
APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE handle, const std::string& name) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!PLUGIN)
return std::vector<SFunctionMatch>{};
#if defined(KERN_PROC_PATHNAME)
int mib[] = {
CTL_KERN,
#if defined(__NetBSD__)
KERN_PROC_ARGS,
-1,
KERN_PROC_PATHNAME,
#else
KERN_PROC,
KERN_PROC_PATHNAME,
-1,
#endif
};
u_int miblen = sizeof(mib) / sizeof(mib[0]);
char exe[PATH_MAX] = "";
size_t sz = sizeof(exe);
sysctl(mib, miblen, &exe, &sz, NULL, 0);
const auto FPATH = std::filesystem::canonical(exe);
#elif defined(__OpenBSD__)
// Neither KERN_PROC_PATHNAME nor /proc are supported
const auto FPATH = std::filesystem::canonical("/usr/local/bin/Hyprland");
#else
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
#endif
const auto SYMBOLS = execAndGet(("nm -D -j " + FPATH.string()).c_str());
const auto SYMBOLSDEMANGLED = execAndGet(("nm -D -j --demangle=auto " + FPATH.string()).c_str());
auto demangledFromID = [&](size_t id) -> std::string {
size_t pos = 0;
size_t count = 0;
while (count < id) {
pos++;
pos = SYMBOLSDEMANGLED.find('\n', pos);
if (pos == std::string::npos)
return "";
count++;
}
return SYMBOLSDEMANGLED.substr(pos, SYMBOLSDEMANGLED.find('\n', pos + 1) - pos);
};
std::vector<SFunctionMatch> matches;
std::istringstream inStream(SYMBOLS);
std::string line;
int lineNo = 0;
while (std::getline(inStream, line)) {
if (line.contains(name)) {
void* address = dlsym(nullptr, line.c_str());
if (!address)
continue;
matches.push_back({address, line, demangledFromID(lineNo)});
}
lineNo++;
}
return matches;
}

View file

@ -33,6 +33,12 @@ typedef struct {
std::string version; std::string version;
} PLUGIN_DESCRIPTION_INFO; } PLUGIN_DESCRIPTION_INFO;
struct SFunctionMatch {
void* address = nullptr;
std::string signature;
std::string demangled;
};
#define APICALL extern "C" #define APICALL extern "C"
#define EXPORT __attribute__((visibility("default"))) #define EXPORT __attribute__((visibility("default")))
#define REQUIRED #define REQUIRED
@ -230,4 +236,13 @@ namespace HyprlandAPI {
returns: true on success. False otherwise. returns: true on success. False otherwise.
*/ */
APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::string, std::any>& data); APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::string, std::any>& data);
/*
Returns a vector of found functions matching the provided name.
These addresses will not change, and should be made static. Lookups are slow.
Empty means either none found or handle was invalid
*/
APICALL std::vector<SFunctionMatch> findFunctionsByName(HANDLE handle, const std::string& name);
}; };