From c5532f988fbb6c70d8479c7d8b450316f537b755 Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Mon, 3 Mar 2025 15:02:37 +0300 Subject: [PATCH 1/8] add minimal plugin system --- .gitignore | 4 +++ CMakeLists.txt | 1 + include/machine.hh | 8 ++++++ include/plugin.hh | 60 +++++++++++++++++++++++++++++++++++++++ include/plugin_api.hh | 30 ++++++++++++++++++++ include/plugin_manager.hh | 30 ++++++++++++++++++++ plugins/CMakeLists.txt | 14 +++++++++ plugins/simple_plugin.cc | 25 ++++++++++++++++ src/main.cc | 2 ++ 9 files changed, 174 insertions(+) create mode 100644 include/plugin.hh create mode 100644 include/plugin_api.hh create mode 100644 include/plugin_manager.hh create mode 100644 plugins/CMakeLists.txt create mode 100644 plugins/simple_plugin.cc diff --git a/.gitignore b/.gitignore index 669b289..402ab6f 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,9 @@ # Directories build/ + +# IDEs and LSP specific .vscode/ __pycache__/ +.cache/ +compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 3434e5f..e4312a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ include(cmake/defaults.cmake) add_subdirectory(third_party) add_subdirectory(scripts) +add_subdirectory(plugins) set(hSIM_LIB src/memory.cc src/machine.cc diff --git a/include/machine.hh b/include/machine.hh index 3cc2ebe..978942d 100644 --- a/include/machine.hh +++ b/include/machine.hh @@ -2,12 +2,14 @@ #define HSIM_MACHINE_INCLUDED #include +#include #include "config.hh" #include "cpu_state.hh" #include "elf_loader.hh" #include "executors.hh" #include "memory.hh" +#include "plugin_manager.hh" namespace hsim { @@ -32,9 +34,15 @@ class Machine final { } } + void loadPlugin(const std::string &pluginPath, + const std::string &options = "") { + m_plugins.loadPlugin(pluginPath, options); + } + private: std::unique_ptr m_state; Memory m_mem{}; + PluginManager m_plugins; }; } // namespace hsim diff --git a/include/plugin.hh b/include/plugin.hh new file mode 100644 index 0000000..b920169 --- /dev/null +++ b/include/plugin.hh @@ -0,0 +1,60 @@ +#ifndef HSIM_PLUGIN_INCLUDED +#define HSIM_PLUGIN_INCLUDED + +#include +#include + +#include + +#include "plugin_api.hh" + +namespace hsim { + +class Plugin final { + public: + Plugin(const std::string &pluginPath, const std::string &options = "") + : m_pluginName{pluginPath}, m_options{options} { + m_dlhandle = dlopen(pluginPath.c_str(), RTLD_NOW); + if (m_dlhandle == nullptr) { + std::string dlErrorMsg = dlerror(); + std::string fullErrorMsg = "Unable to load plugin: " + pluginPath + + ". Error: " + dlErrorMsg; + throw std::runtime_error(fullErrorMsg); + } + + auto loadFunc = reinterpret_cast( + dlsym(m_dlhandle, kLoadFuncName.c_str())); + if (loadFunc == nullptr) { + std::string dlErrorMsg = dlerror(); + std::string fullErrorMsg = + "Unable to load : " + pluginPath + ". Error: " + dlErrorMsg; + throw std::runtime_error(fullErrorMsg); + } + + LoadablePlugin plugin = loadFunc(options.c_str()); + m_pluginMem = plugin.pluginMem; + m_notify = plugin.notify; + m_unload = plugin.unload; + } + + ~Plugin() { + m_unload(m_pluginMem); + + dlclose(m_dlhandle); + } + + void notify() { m_notify(m_pluginMem); } + + private: + std::string m_pluginName; + std::string m_options; + + void *m_dlhandle; + void *m_pluginMem; + NotifyFunc m_notify; + UnloadFunc m_unload; +}; + +} // namespace hsim + +#endif // HSIM_PLUGIN_INCLUDED diff --git a/include/plugin_api.hh b/include/plugin_api.hh new file mode 100644 index 0000000..9bbed76 --- /dev/null +++ b/include/plugin_api.hh @@ -0,0 +1,30 @@ +#ifndef HSIM_PLUGIN_API_INCLUDED +#define HSIM_PLUGIN_API_INCLUDED + +#include + +#define HSIM_PLUGIN_API_ATTR extern "C" + +namespace hsim { + +static const std::string kLoadFuncName = "loadPlugin"; + +struct LoadablePlugin; + +extern "C" { + +using LoadFunc = LoadablePlugin (*)(const char *options); +using NotifyFunc = void (*)(void *pluginMem); +using UnloadFunc = void (*)(void *pluginMem); + +} // extern "C" + +struct LoadablePlugin { + void *pluginMem; + NotifyFunc notify; + UnloadFunc unload; +}; + +}; // namespace hsim + +#endif // HSIM_PLUGIN_API_INCLUDED diff --git a/include/plugin_manager.hh b/include/plugin_manager.hh new file mode 100644 index 0000000..49e411b --- /dev/null +++ b/include/plugin_manager.hh @@ -0,0 +1,30 @@ +#ifndef HSIM_PLUGIN_MANAGER_INCLUDED +#define HSIM_PLUGIN_MANAGER_INCLUDED + +#include +#include + +#include "plugin.hh" + +namespace hsim { + +class PluginManager final { + public: + void loadPlugin(const std::string &pluginPath, + const std::string &options = "") { + m_plugins.emplace_back(pluginPath, options); + } + + void notify() { + for (auto &plugin : m_plugins) { + plugin.notify(); + } + } + + private: + std::vector m_plugins; +}; + +} // namespace hsim + +#endif // HSIM_PLUGIN_MANAGER_INCLUDED diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt new file mode 100644 index 0000000..5abdbee --- /dev/null +++ b/plugins/CMakeLists.txt @@ -0,0 +1,14 @@ +include_directories( + ${CMAKE_SOURCE_DIR}/include +) + +set(PLUGIN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/plugins") +file(MAKE_DIRECTORY ${PLUGIN_OUTPUT_DIR}) + +add_library(simple_plugin SHARED + simple_plugin.cc +) + +set_target_properties(simple_plugin PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${PLUGIN_OUTPUT_DIR} +) diff --git a/plugins/simple_plugin.cc b/plugins/simple_plugin.cc new file mode 100644 index 0000000..164147b --- /dev/null +++ b/plugins/simple_plugin.cc @@ -0,0 +1,25 @@ +#include "plugin_api.hh" + +#include + +void notify(void* pluginMem); +void unload(void* pluginMem); + +HSIM_PLUGIN_API_ATTR hsim::LoadablePlugin loadPlugin([[maybe_unused]] const char* options) { + hsim::LoadablePlugin plugin = {}; + plugin.pluginMem = nullptr; + plugin.notify = notify; + plugin.unload = unload; + + std::cout << "load plugin" << std::endl; + + return plugin; +} + +void notify([[maybe_unused]] void* pluginMem) { + std::cout << "notify plugin" << std::endl; +} + +void unload([[maybe_unused]] void* pluginMem) { + std::cout << "unload plugin" << std::endl; +} diff --git a/src/main.cc b/src/main.cc index a246ab1..d0e191e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -30,6 +30,8 @@ int main(int argc, char **argv) try { // hsim::Machine machine{config}; + // machine.loadPlugin("./build/plugins/libsimple_plugin.so"); + machine.run(); return 0; From 3bb586c30d5cb0d9fab114299debb07abde2e261 Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Thu, 6 Mar 2025 14:41:22 +0300 Subject: [PATCH 2/8] reimplement plugin subsystem --- include/machine.hh | 12 +++-- include/machine_event.hh | 35 ++++++++++++ include/plugin.hh | 108 +++++++++++++++++++++++--------------- include/plugin_api.hh | 30 ----------- include/plugin_manager.hh | 30 ----------- include/so_loader.hh | 48 +++++++++++++++++ plugins/simple_plugin.cc | 41 ++++++++------- src/main.cc | 14 +++-- 8 files changed, 190 insertions(+), 128 deletions(-) create mode 100644 include/machine_event.hh delete mode 100644 include/plugin_api.hh delete mode 100644 include/plugin_manager.hh create mode 100644 include/so_loader.hh diff --git a/include/machine.hh b/include/machine.hh index 978942d..c5c2914 100644 --- a/include/machine.hh +++ b/include/machine.hh @@ -3,13 +3,14 @@ #include #include +#include #include "config.hh" #include "cpu_state.hh" #include "elf_loader.hh" #include "executors.hh" +#include "machine_event.hh" #include "memory.hh" -#include "plugin_manager.hh" namespace hsim { @@ -34,15 +35,16 @@ class Machine final { } } - void loadPlugin(const std::string &pluginPath, - const std::string &options = "") { - m_plugins.loadPlugin(pluginPath, options); + void addEventConsumer(IEventConsumerHandle consumer) { + m_eventManager.attach(std::move(consumer)); } + void notify() { m_eventManager.notify(); } + private: std::unique_ptr m_state; Memory m_mem{}; - PluginManager m_plugins; + EventManager m_eventManager; }; } // namespace hsim diff --git a/include/machine_event.hh b/include/machine_event.hh new file mode 100644 index 0000000..0a707de --- /dev/null +++ b/include/machine_event.hh @@ -0,0 +1,35 @@ +#ifndef HSIM_MACHINE_EVENT_INCLUDED +#define HSIM_MACHINE_EVENT_INCLUDED + +#include +#include +#include + +namespace hsim { + +class IEventConsumer { + public: + virtual ~IEventConsumer() = default; + virtual void update() = 0; +}; + +using IEventConsumerHandle = std::unique_ptr; +class EventManager final { + public: + void notify() { + for (auto &consumer : m_consumers) { + consumer->update(); + } + } + void attach(IEventConsumerHandle consumer) { + m_consumers.push_back(std::move(consumer)); + } + void detach(IEventConsumerHandle consumer) { m_consumers.remove(consumer); } + + private: + std::list m_consumers; // unique? +}; + +} // namespace hsim + +#endif // HSIM_MACHINE_EVENT_INCLUDED diff --git a/include/plugin.hh b/include/plugin.hh index b920169..0487437 100644 --- a/include/plugin.hh +++ b/include/plugin.hh @@ -1,60 +1,84 @@ #ifndef HSIM_PLUGIN_INCLUDED #define HSIM_PLUGIN_INCLUDED -#include +#include +#include #include +#include #include -#include "plugin_api.hh" +#include "machine_event.hh" +#include "so_loader.hh" namespace hsim { -class Plugin final { +class IPlugin : public IEventConsumer { public: - Plugin(const std::string &pluginPath, const std::string &options = "") - : m_pluginName{pluginPath}, m_options{options} { - m_dlhandle = dlopen(pluginPath.c_str(), RTLD_NOW); - if (m_dlhandle == nullptr) { - std::string dlErrorMsg = dlerror(); - std::string fullErrorMsg = "Unable to load plugin: " + pluginPath + - ". Error: " + dlErrorMsg; - throw std::runtime_error(fullErrorMsg); - } - - auto loadFunc = reinterpret_cast( - dlsym(m_dlhandle, kLoadFuncName.c_str())); - if (loadFunc == nullptr) { - std::string dlErrorMsg = dlerror(); - std::string fullErrorMsg = - "Unable to load : " + pluginPath + ". Error: " + dlErrorMsg; - throw std::runtime_error(fullErrorMsg); - } - - LoadablePlugin plugin = loadFunc(options.c_str()); - m_pluginMem = plugin.pluginMem; - m_notify = plugin.notify; - m_unload = plugin.unload; - } - - ~Plugin() { - m_unload(m_pluginMem); - - dlclose(m_dlhandle); - } - - void notify() { m_notify(m_pluginMem); } + IPlugin(SharedLib so_lib) : m_sharedLib(std::move(so_lib)) {} + ~IPlugin() override = default; + SharedLib getSOLib() { return m_sharedLib; } private: - std::string m_pluginName; - std::string m_options; - - void *m_dlhandle; - void *m_pluginMem; - NotifyFunc m_notify; - UnloadFunc m_unload; + SharedLib m_sharedLib; }; +using LoadPLuginFunc = hsim::IPlugin *(*)(const char *options, + SharedLib so_lib); + +// using IPluginHandler = std::unique_ptr; +// auto loadPluginFromSO(const std::filesystem::path& path, const std::string& +// options) { +// SharedLib sharedLib{path, kLazy}; +// auto loadPluginFunc = sharedLib.get("loadPlugin"); +// +// // NOTE reason for custom deleter: +// // when ~IPlugin is called it first calls ~SharedLib and then +// ~SimplePlugin(wich is already unloaded) auto pluginDeleter = [lib = +// SharedLib{sharedLib}](IPlugin* plugin) mutable { delete plugin; }; + +// IPlugin* plugin = loadPluginFunc(options.c_str(), sharedLib); +// return std::unique_ptr{plugin, +// pluginDeleter}; +// } + +// // NOTE reason for custom deleter: +// // when ~IPlugin is called it first calls ~SharedLib and then +// ~SimplePlugin(wich is already unloaded) void ipluginDeleter(IPlugin* plugin) +// { +// SharedLib soLib = plugin->getSOLib(); +// soLib.~SharedLib(); +// } + +// using IPluginHandler = std::unique_ptr; +// IPluginHandler loadPluginFromSO(const std::filesystem::path& path, const +// std::string& options) { +// SharedLib sharedLib{path, kLazy}; +// auto loadPluginFunc = sharedLib.get("loadPlugin"); +// +// IPlugin* plugin = loadPluginFunc(options.c_str(), sharedLib); +// return IPluginHandler{plugin, ipluginDeleter}; +// } + +// using IPluginHandler = std::unique_ptr; +// IPluginHandler loadPluginFromSO(const std::filesystem::path& path, const +// std::string& options) { +// SharedLib sharedLib{path, kLazy}; +// auto loadPluginFunc = sharedLib.get("loadPlugin"); +// +// IPlugin* plugin = loadPluginFunc(options.c_str(), sharedLib); +// return IPluginHandler{plugin}; +// } + +using IPluginHandler = std::unique_ptr; +IPluginHandler loadPluginFromSO(SharedLib sharedLib, + const std::string &options) { + auto loadPluginFunc = sharedLib.get("loadPlugin"); + + IPlugin *plugin = loadPluginFunc(options.c_str(), sharedLib); + return IPluginHandler{plugin}; +} + } // namespace hsim #endif // HSIM_PLUGIN_INCLUDED diff --git a/include/plugin_api.hh b/include/plugin_api.hh deleted file mode 100644 index 9bbed76..0000000 --- a/include/plugin_api.hh +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef HSIM_PLUGIN_API_INCLUDED -#define HSIM_PLUGIN_API_INCLUDED - -#include - -#define HSIM_PLUGIN_API_ATTR extern "C" - -namespace hsim { - -static const std::string kLoadFuncName = "loadPlugin"; - -struct LoadablePlugin; - -extern "C" { - -using LoadFunc = LoadablePlugin (*)(const char *options); -using NotifyFunc = void (*)(void *pluginMem); -using UnloadFunc = void (*)(void *pluginMem); - -} // extern "C" - -struct LoadablePlugin { - void *pluginMem; - NotifyFunc notify; - UnloadFunc unload; -}; - -}; // namespace hsim - -#endif // HSIM_PLUGIN_API_INCLUDED diff --git a/include/plugin_manager.hh b/include/plugin_manager.hh deleted file mode 100644 index 49e411b..0000000 --- a/include/plugin_manager.hh +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef HSIM_PLUGIN_MANAGER_INCLUDED -#define HSIM_PLUGIN_MANAGER_INCLUDED - -#include -#include - -#include "plugin.hh" - -namespace hsim { - -class PluginManager final { - public: - void loadPlugin(const std::string &pluginPath, - const std::string &options = "") { - m_plugins.emplace_back(pluginPath, options); - } - - void notify() { - for (auto &plugin : m_plugins) { - plugin.notify(); - } - } - - private: - std::vector m_plugins; -}; - -} // namespace hsim - -#endif // HSIM_PLUGIN_MANAGER_INCLUDED diff --git a/include/so_loader.hh b/include/so_loader.hh new file mode 100644 index 0000000..c342acf --- /dev/null +++ b/include/so_loader.hh @@ -0,0 +1,48 @@ +#ifndef HSIM_SO_LOADER_INCLUDED +#define HSIM_SO_LOADER_INCLUDED + +#include +#include +#include +#include +#include + +#include + +namespace hsim { + +enum SharedLibMode : std::uint16_t { + kLazy = RTLD_LAZY, + kNow = RTLD_NOW, + kGlobal = RTLD_GLOBAL, + kLocal = RTLD_LOCAL, +}; + +class SharedLib { + public: + SharedLib(const std::filesystem::path &libPath, SharedLibMode mode) + : m_handle{dlopen(libPath.c_str(), mode), [](void *handle) { + if (handle != nullptr) { + dlclose(handle); + } + }} { + if (m_handle == nullptr) { + throw std::runtime_error{dlerror()}; + } + } + template T get(const std::string &symbol) { + void *loadedSymbol = dlsym(m_handle.get(), symbol.c_str()); + if (loadedSymbol == nullptr) { + throw std::runtime_error{dlerror()}; + } + + return reinterpret_cast(loadedSymbol); + } + + private: + std::shared_ptr m_handle; +}; + +} // namespace hsim + +#endif // HSIM_SO_LOADER_INCLUDED diff --git a/plugins/simple_plugin.cc b/plugins/simple_plugin.cc index 164147b..80efc16 100644 --- a/plugins/simple_plugin.cc +++ b/plugins/simple_plugin.cc @@ -1,25 +1,30 @@ -#include "plugin_api.hh" - #include +#include +#include -void notify(void* pluginMem); -void unload(void* pluginMem); +#include "plugin.hh" +#include "so_loader.hh" -HSIM_PLUGIN_API_ATTR hsim::LoadablePlugin loadPlugin([[maybe_unused]] const char* options) { - hsim::LoadablePlugin plugin = {}; - plugin.pluginMem = nullptr; - plugin.notify = notify; - plugin.unload = unload; +class SimplePlugin : public hsim::IPlugin { + public: + SimplePlugin(std::string name, hsim::SharedLib so_lib) + : IPlugin{std::move(so_lib)}, m_name{std::move(name)} { + std::cout << "SimplePlugin: " << m_name << std::endl; + } - std::cout << "load plugin" << std::endl; + ~SimplePlugin() override { + std::cout << "~SimplePlugin: " << m_name << std::endl; + } - return plugin; -} + void update() override { + std::cout << "SimplePlugin name is : " << m_name << std::endl; + } -void notify([[maybe_unused]] void* pluginMem) { - std::cout << "notify plugin" << std::endl; -} + private: + std::string m_name; +}; -void unload([[maybe_unused]] void* pluginMem) { - std::cout << "unload plugin" << std::endl; -} +extern "C" hsim::IPlugin *loadPlugin(const char *options, + hsim::SharedLib so_lib) { + return new SimplePlugin{options, std::move(so_lib)}; +} diff --git a/src/main.cc b/src/main.cc index d0e191e..b05b6ec 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,10 +1,13 @@ +#include #include -#include +#include // #include #include "config.hh" #include "machine.hh" +#include "plugin.hh" +#include "so_loader.hh" int main(int argc, char **argv) try { CLI::App app("hSim: high Performance CPU Simulator"); @@ -30,10 +33,15 @@ int main(int argc, char **argv) try { // hsim::Machine machine{config}; - // machine.loadPlugin("./build/plugins/libsimple_plugin.so"); - machine.run(); + // hsim::SharedLib sharedLib{"./build/plugins/libsimple_plugin.so", + // hsim::kLazy}; + + // auto plugin = hsim::loadPluginFromSO(sharedLib, "vova"); + // machine.addEventConsumer(std::move(plugin)); + // machine.notify(); + return 0; } catch (const std::exception &e) { std::cout << e.what() << '\n'; From 69a4a9b92a476fec7784e65b367d1e7bd05bdf05 Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Thu, 6 Mar 2025 15:11:16 +0300 Subject: [PATCH 3/8] remove SharedLib as filed in plugin --- include/plugin.hh | 23 ++++++++++++----------- plugins/simple_plugin.cc | 8 +++----- src/main.cc | 2 +- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/plugin.hh b/include/plugin.hh index 0487437..38ccba2 100644 --- a/include/plugin.hh +++ b/include/plugin.hh @@ -13,18 +13,19 @@ namespace hsim { -class IPlugin : public IEventConsumer { - public: - IPlugin(SharedLib so_lib) : m_sharedLib(std::move(so_lib)) {} - ~IPlugin() override = default; - SharedLib getSOLib() { return m_sharedLib; } +using IPlugin = IEventConsumer; - private: - SharedLib m_sharedLib; -}; +// class IPlugin : public IEventConsumer { +// public: +// IPlugin(SharedLib so_lib) : m_sharedLib(std::move(so_lib)) {} +// ~IPlugin() override = default; +// // SharedLib getSOLib() { return m_sharedLib; } -using LoadPLuginFunc = hsim::IPlugin *(*)(const char *options, - SharedLib so_lib); +// private: +// // SharedLib m_sharedLib; +// }; + +using LoadPLuginFunc = hsim::IPlugin *(*)(const char *options); // using IPluginHandler = std::unique_ptr; // auto loadPluginFromSO(const std::filesystem::path& path, const std::string& @@ -75,7 +76,7 @@ IPluginHandler loadPluginFromSO(SharedLib sharedLib, const std::string &options) { auto loadPluginFunc = sharedLib.get("loadPlugin"); - IPlugin *plugin = loadPluginFunc(options.c_str(), sharedLib); + IPlugin *plugin = loadPluginFunc(options.c_str()); return IPluginHandler{plugin}; } diff --git a/plugins/simple_plugin.cc b/plugins/simple_plugin.cc index 80efc16..698608a 100644 --- a/plugins/simple_plugin.cc +++ b/plugins/simple_plugin.cc @@ -7,8 +7,7 @@ class SimplePlugin : public hsim::IPlugin { public: - SimplePlugin(std::string name, hsim::SharedLib so_lib) - : IPlugin{std::move(so_lib)}, m_name{std::move(name)} { + SimplePlugin(std::string name) : m_name{std::move(name)} { std::cout << "SimplePlugin: " << m_name << std::endl; } @@ -24,7 +23,6 @@ class SimplePlugin : public hsim::IPlugin { std::string m_name; }; -extern "C" hsim::IPlugin *loadPlugin(const char *options, - hsim::SharedLib so_lib) { - return new SimplePlugin{options, std::move(so_lib)}; +extern "C" hsim::IPlugin *loadPlugin(const char *options) { + return new SimplePlugin{options}; } diff --git a/src/main.cc b/src/main.cc index b05b6ec..96de05a 100644 --- a/src/main.cc +++ b/src/main.cc @@ -33,7 +33,7 @@ int main(int argc, char **argv) try { // hsim::Machine machine{config}; - machine.run(); + // machine.run(); // hsim::SharedLib sharedLib{"./build/plugins/libsimple_plugin.so", // hsim::kLazy}; From 2d805f01ebcd52d87152b3e4187c1663c1ccff16 Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Fri, 7 Mar 2025 01:03:42 +0300 Subject: [PATCH 4/8] fix use after free bug --- include/plugin.hh | 91 +++++++++++----------------------------- plugins/simple_plugin.cc | 3 +- src/main.cc | 13 +++--- 3 files changed, 33 insertions(+), 74 deletions(-) diff --git a/include/plugin.hh b/include/plugin.hh index 38ccba2..d5b491d 100644 --- a/include/plugin.hh +++ b/include/plugin.hh @@ -2,9 +2,7 @@ #define HSIM_PLUGIN_INCLUDED #include -#include #include -#include #include @@ -13,72 +11,33 @@ namespace hsim { -using IPlugin = IEventConsumer; - -// class IPlugin : public IEventConsumer { -// public: -// IPlugin(SharedLib so_lib) : m_sharedLib(std::move(so_lib)) {} -// ~IPlugin() override = default; -// // SharedLib getSOLib() { return m_sharedLib; } - -// private: -// // SharedLib m_sharedLib; -// }; +class IPlugin { + public: + virtual ~IPlugin() = default; + virtual void update() = 0; +}; using LoadPLuginFunc = hsim::IPlugin *(*)(const char *options); - -// using IPluginHandler = std::unique_ptr; -// auto loadPluginFromSO(const std::filesystem::path& path, const std::string& -// options) { -// SharedLib sharedLib{path, kLazy}; -// auto loadPluginFunc = sharedLib.get("loadPlugin"); -// -// // NOTE reason for custom deleter: -// // when ~IPlugin is called it first calls ~SharedLib and then -// ~SimplePlugin(wich is already unloaded) auto pluginDeleter = [lib = -// SharedLib{sharedLib}](IPlugin* plugin) mutable { delete plugin; }; - -// IPlugin* plugin = loadPluginFunc(options.c_str(), sharedLib); -// return std::unique_ptr{plugin, -// pluginDeleter}; -// } - -// // NOTE reason for custom deleter: -// // when ~IPlugin is called it first calls ~SharedLib and then -// ~SimplePlugin(wich is already unloaded) void ipluginDeleter(IPlugin* plugin) -// { -// SharedLib soLib = plugin->getSOLib(); -// soLib.~SharedLib(); -// } - -// using IPluginHandler = std::unique_ptr; -// IPluginHandler loadPluginFromSO(const std::filesystem::path& path, const -// std::string& options) { -// SharedLib sharedLib{path, kLazy}; -// auto loadPluginFunc = sharedLib.get("loadPlugin"); -// -// IPlugin* plugin = loadPluginFunc(options.c_str(), sharedLib); -// return IPluginHandler{plugin, ipluginDeleter}; -// } - -// using IPluginHandler = std::unique_ptr; -// IPluginHandler loadPluginFromSO(const std::filesystem::path& path, const -// std::string& options) { -// SharedLib sharedLib{path, kLazy}; -// auto loadPluginFunc = sharedLib.get("loadPlugin"); -// -// IPlugin* plugin = loadPluginFunc(options.c_str(), sharedLib); -// return IPluginHandler{plugin}; -// } - -using IPluginHandler = std::unique_ptr; -IPluginHandler loadPluginFromSO(SharedLib sharedLib, - const std::string &options) { - auto loadPluginFunc = sharedLib.get("loadPlugin"); - - IPlugin *plugin = loadPluginFunc(options.c_str()); - return IPluginHandler{plugin}; -} +using UnloadPluginFunc = void (*)(IPlugin *plugin); + +class PluginConsumer : public IEventConsumer { + public: + PluginConsumer(const std::filesystem::path &path, + const std::string &options) + : m_sharedLib{path, kLazy} { + auto loadFunc = m_sharedLib.get("loadPlugin"); + m_plugin = loadFunc(options.c_str()); + } + ~PluginConsumer() override { + auto unloadFunc = m_sharedLib.get("unloadPlugin"); + unloadFunc(m_plugin); + } + void update() override { m_plugin->update(); } + + private: + IPlugin *m_plugin; + SharedLib m_sharedLib; +}; } // namespace hsim diff --git a/plugins/simple_plugin.cc b/plugins/simple_plugin.cc index 698608a..933c45e 100644 --- a/plugins/simple_plugin.cc +++ b/plugins/simple_plugin.cc @@ -3,7 +3,6 @@ #include #include "plugin.hh" -#include "so_loader.hh" class SimplePlugin : public hsim::IPlugin { public: @@ -26,3 +25,5 @@ class SimplePlugin : public hsim::IPlugin { extern "C" hsim::IPlugin *loadPlugin(const char *options) { return new SimplePlugin{options}; } + +extern "C" void unloadPlugin(SimplePlugin *plugin) { delete plugin; } diff --git a/src/main.cc b/src/main.cc index 96de05a..66ca343 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,13 +1,14 @@ #include #include +#include #include // #include #include "config.hh" #include "machine.hh" +#include "machine_event.hh" #include "plugin.hh" -#include "so_loader.hh" int main(int argc, char **argv) try { CLI::App app("hSim: high Performance CPU Simulator"); @@ -33,13 +34,11 @@ int main(int argc, char **argv) try { // hsim::Machine machine{config}; - // machine.run(); + machine.run(); - // hsim::SharedLib sharedLib{"./build/plugins/libsimple_plugin.so", - // hsim::kLazy}; - - // auto plugin = hsim::loadPluginFromSO(sharedLib, "vova"); - // machine.addEventConsumer(std::move(plugin)); + // auto *plugin = new + // hsim::PluginConsumer{"./build/plugins/libsimple_plugin.so", "vova"}; + // machine.addEventConsumer(std::unique_ptr{plugin}); // machine.notify(); return 0; From 6a86e30ea2e4b7fb21b85d4f3719b553674c471b Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Sat, 15 Mar 2025 01:02:18 +0300 Subject: [PATCH 5/8] add unique_ptr in IPluginConsumer and use concepts in SharedLib --- .gitignore | 2 -- include/plugin.hh | 27 ++++++++++++++++++--------- include/so_loader.hh | 21 ++++++++++++++------- plugins/CMakeLists.txt | 13 +++++++------ plugins/simple_plugin.cc | 4 ++-- src/main.cc | 6 ++---- 6 files changed, 43 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 402ab6f..37d6368 100644 --- a/.gitignore +++ b/.gitignore @@ -37,5 +37,3 @@ build/ # IDEs and LSP specific .vscode/ __pycache__/ -.cache/ -compile_commands.json diff --git a/include/plugin.hh b/include/plugin.hh index d5b491d..b5b5c4b 100644 --- a/include/plugin.hh +++ b/include/plugin.hh @@ -2,6 +2,7 @@ #define HSIM_PLUGIN_INCLUDED #include +#include #include #include @@ -17,26 +18,34 @@ class IPlugin { virtual void update() = 0; }; -using LoadPLuginFunc = hsim::IPlugin *(*)(const char *options); +using LoadPluginFunc = IPlugin *(*)(const std::string &options); using UnloadPluginFunc = void (*)(IPlugin *plugin); +constexpr std::string kLoadPluginFuncName = "loadPlugin"; +constexpr std::string kUnloadPluginFuncName = "unloadPlugin"; + +// NOTE plugins should use this defines when declaring a function +#define HSIM_LOAD_PLUGIN_FUNC extern "C" hsim::IPlugin *loadPlugin +#define HSIM_UNLOAD_PLUGIN_FUNC extern "C" void unloadPlugin + class PluginConsumer : public IEventConsumer { public: PluginConsumer(const std::filesystem::path &path, const std::string &options) - : m_sharedLib{path, kLazy} { - auto loadFunc = m_sharedLib.get("loadPlugin"); - m_plugin = loadFunc(options.c_str()); - } - ~PluginConsumer() override { - auto unloadFunc = m_sharedLib.get("unloadPlugin"); - unloadFunc(m_plugin); + : m_sharedLib{path, kLazy}, m_plugin{nullptr, nullptr} { + auto loadFunc = m_sharedLib.get(kLoadPluginFuncName); + auto unloadFunc = + m_sharedLib.get(kUnloadPluginFuncName); + + m_plugin = std::unique_ptr(loadFunc(options), + unloadFunc); } + void update() override { m_plugin->update(); } private: - IPlugin *m_plugin; SharedLib m_sharedLib; + std::unique_ptr m_plugin; }; } // namespace hsim diff --git a/include/so_loader.hh b/include/so_loader.hh index c342acf..a434a5b 100644 --- a/include/so_loader.hh +++ b/include/so_loader.hh @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -18,19 +19,25 @@ enum SharedLibMode : std::uint16_t { kLocal = RTLD_LOCAL, }; +template +concept PointerT = std::is_pointer_v; + class SharedLib { + private: + static void dlCloser(void *handle) { + if (handle != nullptr) { + dlclose(handle); + } + } + public: SharedLib(const std::filesystem::path &libPath, SharedLibMode mode) - : m_handle{dlopen(libPath.c_str(), mode), [](void *handle) { - if (handle != nullptr) { - dlclose(handle); - } - }} { + : m_handle{dlopen(libPath.c_str(), mode), dlCloser} { if (m_handle == nullptr) { throw std::runtime_error{dlerror()}; } } - template T get(const std::string &symbol) { + template T get(const std::string &symbol) { void *loadedSymbol = dlsym(m_handle.get(), symbol.c_str()); if (loadedSymbol == nullptr) { throw std::runtime_error{dlerror()}; @@ -40,7 +47,7 @@ class SharedLib { } private: - std::shared_ptr m_handle; + std::unique_ptr m_handle; }; } // namespace hsim diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 5abdbee..1230f7f 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,14 +1,15 @@ -include_directories( - ${CMAKE_SOURCE_DIR}/include +add_library(simple_plugin SHARED + simple_plugin.cc +) + +target_include_directories(simple_plugin + PRIVATE + ${CMAKE_SOURCE_DIR}/include ) set(PLUGIN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/plugins") file(MAKE_DIRECTORY ${PLUGIN_OUTPUT_DIR}) -add_library(simple_plugin SHARED - simple_plugin.cc -) - set_target_properties(simple_plugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN_OUTPUT_DIR} ) diff --git a/plugins/simple_plugin.cc b/plugins/simple_plugin.cc index 933c45e..fd151a6 100644 --- a/plugins/simple_plugin.cc +++ b/plugins/simple_plugin.cc @@ -22,8 +22,8 @@ class SimplePlugin : public hsim::IPlugin { std::string m_name; }; -extern "C" hsim::IPlugin *loadPlugin(const char *options) { +HSIM_LOAD_PLUGIN_FUNC(const std::string &options) { return new SimplePlugin{options}; } -extern "C" void unloadPlugin(SimplePlugin *plugin) { delete plugin; } +HSIM_UNLOAD_PLUGIN_FUNC(SimplePlugin *plugin) { delete plugin; } diff --git a/src/main.cc b/src/main.cc index 66ca343..ebd786b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,7 +1,6 @@ #include #include #include -#include // #include @@ -36,9 +35,8 @@ int main(int argc, char **argv) try { machine.run(); - // auto *plugin = new - // hsim::PluginConsumer{"./build/plugins/libsimple_plugin.so", "vova"}; - // machine.addEventConsumer(std::unique_ptr{plugin}); + // machine.addEventConsumer(std::make_unique( + // "./build/plugins/libsimple_plugin.so", "vova")); // machine.notify(); return 0; From feac4cf196c24085a107e1f0055b3227e2fb49aa Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Sat, 15 Mar 2025 13:29:52 +0300 Subject: [PATCH 6/8] add handlers for different types of events --- include/machine.hh | 4 +++- include/machine_event.hh | 18 ++++++++++++++---- include/plugin.hh | 19 +++++++++++++++++-- include/so_loader.hh | 6 +----- plugins/simple_plugin.cc | 24 ++++++++++++++++++++++-- src/main.cc | 8 +++++--- 6 files changed, 62 insertions(+), 17 deletions(-) diff --git a/include/machine.hh b/include/machine.hh index c5c2914..3255d2b 100644 --- a/include/machine.hh +++ b/include/machine.hh @@ -39,7 +39,9 @@ class Machine final { m_eventManager.attach(std::move(consumer)); } - void notify() { m_eventManager.notify(); } + template void notify(Args &&...args) { + m_eventManager.notify(std::forward(args)...); + } private: std::unique_ptr m_state; diff --git a/include/machine_event.hh b/include/machine_event.hh index 0a707de..b8b00e6 100644 --- a/include/machine_event.hh +++ b/include/machine_event.hh @@ -5,20 +5,30 @@ #include #include +#include "support.hh" + namespace hsim { +struct MemRead {}; +struct MemWrite {}; +struct PreInsn {}; +struct PostInsn {}; + class IEventConsumer { public: virtual ~IEventConsumer() = default; - virtual void update() = 0; + virtual void handle(MemRead event, Addr addr) = 0; + virtual void handle(MemWrite event, Addr addr, Word value) = 0; + virtual void handle(PreInsn event, Word insn) = 0; + virtual void handle(PostInsn event, Word insn) = 0; }; using IEventConsumerHandle = std::unique_ptr; class EventManager final { public: - void notify() { + template void notify(Args &&...args) { for (auto &consumer : m_consumers) { - consumer->update(); + consumer->handle(Event{}, std::forward(args)...); } } void attach(IEventConsumerHandle consumer) { @@ -27,7 +37,7 @@ class EventManager final { void detach(IEventConsumerHandle consumer) { m_consumers.remove(consumer); } private: - std::list m_consumers; // unique? + std::list m_consumers; }; } // namespace hsim diff --git a/include/plugin.hh b/include/plugin.hh index b5b5c4b..f6a71e3 100644 --- a/include/plugin.hh +++ b/include/plugin.hh @@ -9,13 +9,17 @@ #include "machine_event.hh" #include "so_loader.hh" +#include "support.hh" namespace hsim { class IPlugin { public: virtual ~IPlugin() = default; - virtual void update() = 0; + virtual void handle(MemRead event, Addr addr) = 0; + virtual void handle(MemWrite event, Addr addr, Word value) = 0; + virtual void handle(PreInsn event, Word insn) = 0; + virtual void handle(PostInsn event, Word insn) = 0; }; using LoadPluginFunc = IPlugin *(*)(const std::string &options); @@ -41,7 +45,18 @@ class PluginConsumer : public IEventConsumer { unloadFunc); } - void update() override { m_plugin->update(); } + void handle(MemRead event, Addr addr) override { + m_plugin->handle(event, addr); + } + void handle(MemWrite event, Addr addr, Word value) override { + m_plugin->handle(event, addr, value); + } + void handle(PreInsn event, Word insn) override { + m_plugin->handle(event, insn); + } + void handle(PostInsn event, Word insn) override { + m_plugin->handle(event, insn); + } private: SharedLib m_sharedLib; diff --git a/include/so_loader.hh b/include/so_loader.hh index a434a5b..c7823bb 100644 --- a/include/so_loader.hh +++ b/include/so_loader.hh @@ -24,11 +24,7 @@ concept PointerT = std::is_pointer_v; class SharedLib { private: - static void dlCloser(void *handle) { - if (handle != nullptr) { - dlclose(handle); - } - } + static void dlCloser(void *handle) { dlclose(handle); } public: SharedLib(const std::filesystem::path &libPath, SharedLibMode mode) diff --git a/plugins/simple_plugin.cc b/plugins/simple_plugin.cc index fd151a6..74200b5 100644 --- a/plugins/simple_plugin.cc +++ b/plugins/simple_plugin.cc @@ -2,7 +2,11 @@ #include #include +#include "machine_event.hh" #include "plugin.hh" +#include "support.hh" + +namespace hsim { class SimplePlugin : public hsim::IPlugin { public: @@ -14,8 +18,22 @@ class SimplePlugin : public hsim::IPlugin { std::cout << "~SimplePlugin: " << m_name << std::endl; } - void update() override { - std::cout << "SimplePlugin name is : " << m_name << std::endl; + void handle([[maybe_unused]] MemRead event, Addr addr) override { + std::cout << m_name << " MemRead: " << std::hex << addr << std::endl; + } + + void handle([[maybe_unused]] MemWrite event, Addr addr, + Word value) override { + std::cout << m_name << " MemWrite: " << std::hex << addr << " " << value + << std::endl; + } + + void handle([[maybe_unused]] PreInsn event, Word insn) override { + std::cout << m_name << " PreInsn: " << std::hex << insn << std::endl; + } + + void handle([[maybe_unused]] PostInsn event, Word insn) override { + std::cout << m_name << " PostInsn: " << std::hex << insn << std::endl; } private: @@ -27,3 +45,5 @@ HSIM_LOAD_PLUGIN_FUNC(const std::string &options) { } HSIM_UNLOAD_PLUGIN_FUNC(SimplePlugin *plugin) { delete plugin; } + +} // namespace hsim diff --git a/src/main.cc b/src/main.cc index ebd786b..dffce88 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,4 +1,5 @@ #include +#include #include #include // @@ -35,9 +36,10 @@ int main(int argc, char **argv) try { machine.run(); - // machine.addEventConsumer(std::make_unique( - // "./build/plugins/libsimple_plugin.so", "vova")); - // machine.notify(); + // std::filesystem::path pluginPath = "./build/plugins/libsimple_plugin.so"; + // machine.addEventConsumer( + // std::make_unique(pluginPath, "vova")); + // machine.notify(0, 0); return 0; } catch (const std::exception &e) { From cca53f86acc83d1aeacc716a18a448e87e796742 Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Sat, 15 Mar 2025 14:14:41 +0300 Subject: [PATCH 7/8] replace deleter function with deleter struct in so_loader.hh --- include/so_loader.hh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/so_loader.hh b/include/so_loader.hh index c7823bb..d00be5c 100644 --- a/include/so_loader.hh +++ b/include/so_loader.hh @@ -24,11 +24,13 @@ concept PointerT = std::is_pointer_v; class SharedLib { private: - static void dlCloser(void *handle) { dlclose(handle); } + struct DlCloser { + void operator()(void *handle) { dlclose(handle); } + }; public: SharedLib(const std::filesystem::path &libPath, SharedLibMode mode) - : m_handle{dlopen(libPath.c_str(), mode), dlCloser} { + : m_handle{dlopen(libPath.c_str(), mode)} { if (m_handle == nullptr) { throw std::runtime_error{dlerror()}; } @@ -43,7 +45,7 @@ class SharedLib { } private: - std::unique_ptr m_handle; + std::unique_ptr m_handle; }; } // namespace hsim From bcdbb30f000256b66b31902d3f1913915f400a60 Mon Sep 17 00:00:00 2001 From: fogInSingularity Date: Sun, 16 Mar 2025 15:44:08 +0300 Subject: [PATCH 8/8] remove check for existance of log file --- include/so_loader.hh | 1 + src/main.cc | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/so_loader.hh b/include/so_loader.hh index d00be5c..1bdd360 100644 --- a/include/so_loader.hh +++ b/include/so_loader.hh @@ -46,6 +46,7 @@ class SharedLib { private: std::unique_ptr m_handle; + static_assert(sizeof(m_handle) == sizeof(void *)); }; } // namespace hsim diff --git a/src/main.cc b/src/main.cc index dffce88..7769eb5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -18,9 +18,7 @@ int main(int argc, char **argv) try { ->required() ->check(CLI::ExistingFile); - app.add_option("--log", config.log_path, "Path to log file") - ->required() - ->check(CLI::ExistingFile); + app.add_option("--log", config.log_path, "Path to log file")->required(); app.add_flag("--dump-exec", config.dump_exec, "Option to enable dump of state on execution")