From 430778293e4ce7c2ae418ff11601d61833b99a67 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Fri, 31 Mar 2023 18:31:11 +0100 Subject: [PATCH] plugins: Add an API entry for finding functions by name --- src/plugins/PluginAPI.cpp | 72 +++++++++++++++++++++++++++++++++++++++ src/plugins/PluginAPI.hpp | 15 ++++++++ 2 files changed, 87 insertions(+) diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index c878516b..8a7e2565 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -3,6 +3,10 @@ #include "../debug/HyprCtl.hpp" #include +#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) +#include +#endif + APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); @@ -240,4 +244,72 @@ APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map HyprlandAPI::findFunctionsByName(HANDLE handle, const std::string& name) { + auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); + + if (!PLUGIN) + return std::vector{}; + +#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 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; } \ No newline at end of file diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp index 813d7462..ff1f1ffe 100644 --- a/src/plugins/PluginAPI.hpp +++ b/src/plugins/PluginAPI.hpp @@ -33,6 +33,12 @@ typedef struct { std::string version; } PLUGIN_DESCRIPTION_INFO; +struct SFunctionMatch { + void* address = nullptr; + std::string signature; + std::string demangled; +}; + #define APICALL extern "C" #define EXPORT __attribute__((visibility("default"))) #define REQUIRED @@ -230,4 +236,13 @@ namespace HyprlandAPI { returns: true on success. False otherwise. */ APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map& 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 findFunctionsByName(HANDLE handle, const std::string& name); }; \ No newline at end of file