diff --git a/include/hiload/hiload.h b/include/hiload.h similarity index 77% rename from include/hiload/hiload.h rename to include/hiload.h index 6bb441b..501ce3c 100644 --- a/include/hiload/hiload.h +++ b/include/hiload.h @@ -1,3 +1,11 @@ +/** + * Hiload is an Elf hotreloader that patches C and C++ code live while + * developing, significantly tightening the traditional feedback loop. + * + * Currently not supported: + * - modifying modules loaded at runtime + */ + #ifndef HILOAD_H_ #define HILOAD_H_ @@ -24,7 +32,7 @@ extern "C" { int hi_init(size_t n, const char **enabled_modules); /** - * Frees allocated memory. Call when hiload is no longer used. + * Call when hiload is no longer needed. */ void hi_deinit(void); diff --git a/src/files.c b/src/files.c index 484262f..9a9549c 100644 --- a/src/files.c +++ b/src/files.c @@ -1,7 +1,7 @@ #include "files.h" -#include "logger.h" #include "histring.h" +#include "logger.h" #include "types.h" #include @@ -13,7 +13,7 @@ char *file_to_str_dyn(const char *filename) { - char *s = hi_str_from_file(filename, 0, 0); + char *s = string_from_file(filename, 0, 0); if (!s) { sc_log_error("Failed to read file: %s\n", filename); return 0; @@ -28,23 +28,6 @@ static FileType file_interpret_as_type(const char *path) { return as_dir ? HI_FILE_TYPE_DIR : HI_FILE_TYPE_FILE; } -const char *file_name_from_path(const char *path) { - const char *filename = path; - - // Find the last directory separator - const char *last_slash = strrchr(path, '/'); - const char *last_backslash = strrchr(path, '\\'); - - // Determine which separator was found last (if any) - if (last_slash && (!last_backslash || last_slash > last_backslash)) { - filename = last_slash + 1; - } else if (last_backslash) { - filename = last_backslash + 1; - } - - return filename; -} - HiResult file_copy(const char *srcname, const char *destination) { HiResult ret = HI_FAIL; @@ -61,8 +44,7 @@ HiResult file_copy(const char *srcname, const char *destination) { FileType dst_type = file_interpret_as_type(destination); if (dst_type == HI_FILE_TYPE_DIR) { - hi_str_concat_buf(sizeof(buf), buf, destination, - file_name_from_path(srcname)); + string_concat_buf(sizeof(buf), buf, destination, strpath_filename(srcname)); dstname = buf; } @@ -89,8 +71,10 @@ HiResult file_copy(const char *srcname, const char *destination) { ret = HI_OK; cleanup: - if (src) fclose(src); - if (dst) fclose(dst); + if (src) + fclose(src); + if (dst) + fclose(dst); return ret; } @@ -136,4 +120,3 @@ FileType file_type(const char *path) { return HI_FILE_TYPE_NONE; } - diff --git a/src/files.h b/src/files.h index 6c48099..d69a8e9 100644 --- a/src/files.h +++ b/src/files.h @@ -35,5 +35,3 @@ char *file_to_str_dyn(const char *filename); HiResult file_copy(const char *filename, const char *dest); FileType file_type(const char *path); - -const char *file_name_from_path(const char *path); diff --git a/src/filewatcher/filewatch_type.h b/src/filewatcher/filewatch_type.h index 937f9d0..1eebdb9 100644 --- a/src/filewatcher/filewatch_type.h +++ b/src/filewatcher/filewatch_type.h @@ -13,7 +13,7 @@ typedef enum { HI_FILE_PARENT = (1 << 30), } FileWatchType; -static inline const char *hi_file_watch_type_to_str(FileWatchType type) { +static inline const char *filewatch_type_to_str(FileWatchType type) { switch (type) { case HI_FILE_NONE: return "HI_FILE_NONE"; @@ -26,11 +26,11 @@ static inline const char *hi_file_watch_type_to_str(FileWatchType type) { case HI_FILE_MOVE: return "HI_FILE_MOVE"; default: - return "Unknown HI_FILE_TYPE"; - return "Unknown HI_FILE_TYPE"; // clang-format on } + + return "Unknown HI_FILE_TYPE"; } #endif // FILEWATCH_TYPE_H_ diff --git a/src/filewatcher/filewatcher.c b/src/filewatcher/filewatcher.c index 1dc8cbd..65c4aa9 100644 --- a/src/filewatcher/filewatcher.c +++ b/src/filewatcher/filewatcher.c @@ -141,7 +141,7 @@ static FileEvent file_event_create(const struct inotify_event *inevent, return NULL_EVENT; } -FileEvent file_event_pop(FileWatcher *fw) { +FileEvent filewatcher_event_pop(FileWatcher *fw) { mtx_lock(&fw->mutex); FileEvent e = NULL_EVENT; @@ -179,7 +179,7 @@ static void file_watcher_ctx_destroy(FileWatcherContext *ctx) { // Declare the thread func int file_watcher_watch(void *arg); -FileWatcher *file_watcher_create() { +FileWatcher *filewatcher_create() { // Allocate context FileWatcher *fw = malloc(sizeof(FileWatcher)); @@ -205,7 +205,7 @@ FileWatcher *file_watcher_create() { return NULL; } -HiResult file_watcher_add(FileWatcher *fw, const char *filename, u32 flags) { +HiResult filewatcher_add(FileWatcher *fw, const char *filename, u32 flags) { if (!fw) { sc_log_error("Attempted to add file watcher for '%s' with null context\n", filename); @@ -264,7 +264,7 @@ void file_watcher_notify(FileWatcher *fw) { } } -void file_watcher_destroy(FileWatcher *fw) { +void filewatcher_destroy(FileWatcher *fw) { if (!fw) return; @@ -275,6 +275,10 @@ void file_watcher_destroy(FileWatcher *fw) { } file_watcher_ctx_destroy(&fw->context); + + mtx_destroy(&fw->mutex); + cnd_destroy(&fw->cond); + free(fw); } @@ -309,7 +313,7 @@ int file_watcher_watch(void *arg) { if (event->len) { sc_log_debug("Event created: queue-size: %u, %s %s\n", vector_size(&ctx->events), e.pathname, - hi_file_watch_type_to_str(e.type)); + filewatch_type_to_str(e.type)); } } } diff --git a/src/filewatcher/filewatcher.h b/src/filewatcher/filewatcher.h index a52bb44..9d21beb 100644 --- a/src/filewatcher/filewatcher.h +++ b/src/filewatcher/filewatcher.h @@ -1,16 +1,9 @@ -#ifndef HI_FILEWATCHER_H_ -#define HI_FILEWATCHER_H_ - -#include "filewatch_context.h" -#include "filewatch_type.h" -#include "types.h" - /** * File event watcher using inotify. * - * Create a FileWatcher and give it files to monitor. FileWatcher creates a thread - * for listening system notifications. It then creates events for each filechange - * for those files under scrutiny. + * Create a FileWatcher and give it files to monitor. FileWatcher creates a + * thread for listening system notifications. It then creates events for each + * filechange for those files under scrutiny. * * Paths are stored as absolute, and this doesn't handle symlinks in watched * files. So if you have e.g. a symlink 'my-proj' to your project folder in @@ -18,6 +11,12 @@ * not interpreted as equal. */ +#pragma once + +#include "filewatch_context.h" +#include "filewatch_type.h" +#include "types.h" + /** * File Event produced by FileWatcher. * @@ -47,15 +46,15 @@ typedef struct FileEvents FileEvents; * * Starts a new watcher thread immediately. */ -FileWatcher *file_watcher_create(void); +FileWatcher *filewatcher_create(void); /** - * Destroy a previously created file watcher. + * Destroy a previously created file watcher, cleaning resources. * * Will join the thread and destroy event stack. Any FileEvent still in * existence will contain invalid data after this call. */ -void file_watcher_destroy(FileWatcher *fw); +void filewatcher_destroy(FileWatcher *fw); /** * Start watching for events on a file. @@ -64,11 +63,9 @@ void file_watcher_destroy(FileWatcher *fw); * @param pathname Absolute path to the file or directory * @param flags The event mask for the events to watch for */ -HiResult file_watcher_add(FileWatcher *fw, const char *pathname, u32 flags); +HiResult filewatcher_add(FileWatcher *fw, const char *pathname, u32 flags); /** * Pop an event from event stack. */ -FileEvent file_event_pop(FileWatcher *ctx); - -#endif // HI_FILEWATCHER_H_ +FileEvent filewatcher_event_pop(FileWatcher *ctx); diff --git a/src/hiload.c b/src/hiload.c index f4b2f73..adba3b0 100644 --- a/src/hiload.c +++ b/src/hiload.c @@ -1,4 +1,4 @@ -#include "hiload/hiload.h" +#include "hiload.h" #include "common.h" #include "filewatcher/filewatcher.h" @@ -23,13 +23,11 @@ * assumption is that libraries from system folders won't be actively developed * on, nor do they contain references to the modifiable code. */ -static const char *module_exclude_filter[] = { +static const char *system_folders[] = { "/usr/", "/lib/", "/lib64/", "/bin/", "/opt/", }; typedef struct { - VectorMemoryMap memory_regions; - VectorStr enabled_modules; FileWatcher *filewatcher; VectorModuleData modules; } HiloadContext; @@ -37,11 +35,11 @@ typedef struct { static HiloadContext context = {0}; // Callback function for dl_iterate_phdr -static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, - void *data) { - (void)size; +static int initial_gather_callback(struct dl_phdr_info *info, size_t size, + void *data) { + UNUSED(size); - // '' for executable, fname for rest + // '' for executable, filepath for rest const char *modname = info->dlpi_name; log_info("Found: '%s'\n", info->dlpi_name); @@ -56,7 +54,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, // Mark executable if (strcmp(modname, "") == 0) { - module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_EXEC); + module.info = modinfo_add(module.info, HI_MODULE_STATE_EXEC); } Dl_info dl_info = {0}; @@ -67,35 +65,12 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, const char *modpath = dl_info.dli_fname; module.name = strdup(modpath); - // Mark everything but system and virtual modules as patchable - if (module.name[0] == '/') { - if (!hi_str_starts_with(module.name, ARRLEN(module_exclude_filter), - module_exclude_filter)) { - module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_PATCHABLE); - } - } - log_debugv("dli_fname: %s\n", dl_info.dli_fname); log_debugv("dli_sname: %s\n", dl_info.dli_sname); - for (size_t i = 0; i < vector_size(&context.enabled_modules); i++) { - - // If module is in the provided modules list - if (hi_path_has_filename(modname, - vector_at(&context.enabled_modules, i))) { - - // Replace shortform with str pointer from module info - vector_at(&context.enabled_modules, i) = module.name; - - if (!HIOK(file_watcher_add(context.filewatcher, modpath, - HI_FILE_ALL_EVENTS))) { - log_error("Failed to set filewatcher for: '%s'\n", modpath); - } else { - log_info("Watching file: %s\n", modpath); - } - } - } } else { + // I don't know when this could happen since we're passing the info straight + // from the info struct module.name = strdup(modname); log_warn("Couldn't load dlinfo for %s: %s\n", module.name, dlerror()); } @@ -106,7 +81,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, return 0; // Continue iteration } -static void module_infos_free(VectorModuleData *modules) { +static void module_data_free(VectorModuleData *modules) { if (!modules) return; @@ -115,22 +90,72 @@ static void module_infos_free(VectorModuleData *modules) { } } -static HiResult gather_module_infos(VectorModuleData *modules) { +static HiResult +module_data_initial_gather(VectorModuleData *modules, size_t enabled_count, + const char *enabled_modules[enabled_count]) { vector_init(modules); // Iterate over all loaded shared objects - if (dl_iterate_phdr(gather_module_data_callback, modules) != 0) { + if (dl_iterate_phdr(initial_gather_callback, modules) != 0) { // Error occurred in callback - module_infos_free(modules); + module_data_free(modules); return HI_FAIL; } + for (size_t i = 0; i < vector_size(&context.modules); ++i) { + ModuleData *module = &vector_at(&context.modules, i); + + // Mark everything but system and virtual modules as patchable + if (module->name[0] == '/') { + // Virtual module(s) don't have the root at start + if (string_starts_with_any(module->name, ARRLEN(system_folders), + system_folders)) { + // Exclude anything from system folders with libraries + continue; + } else if (string_last_token_is(module->name, "libhiload.so", '/')) { + // Exclude ourselves, so we don't accidentally try to override + // ourselves while running ourselves. + continue; + } + module->info = modinfo_add(module->info, HI_MODULE_STATE_PATCHABLE); + } + + bool enable = false; + + for (size_t i = 0; i < enabled_count; ++i) { + const char *enabled_module = enabled_modules[i]; + if (string_is_empty(enabled_module)) { + if (modinfo_has(module->info, HI_MODULE_STATE_EXEC)) { + enable = true; + break; + } + } else { + if (string_last_token_is(module->name, enabled_module, '/')) { + enable = true; + break; + } + } + } + + if (enable) { + module->info = modinfo_add(module->info, HI_MODULE_STATE_ENABLED); + + // Add filewatcher + if (!HIOK(filewatcher_add(context.filewatcher, module->name, + HI_FILE_ALL_EVENTS))) { + log_error("Failed to set filewatcher for: '%s'\n", module->name); + } else { + log_info("Watching file: %s\n", module->name); + } + } + } + return HI_OK; } -static ModuleData *get_module_by_path(const char *path, - VectorModuleData *modules) { +static ModuleData *module_get(const char *path, + const VectorModuleData *modules) { for (size_t i = 0; i < vector_size(modules); i++) { ModuleData *module = &vector_at(modules, i); @@ -139,6 +164,7 @@ static ModuleData *get_module_by_path(const char *path, return module; } } + return NULL; } @@ -147,35 +173,23 @@ static ModuleData *get_module_by_path(const char *path, * * Marks a module dirty if there has been any event. */ -static void handle_events(FileWatcher *fw, VectorModuleData *modules) { +static void handle_file_events(FileWatcher *fw, VectorModuleData *modules) { - FileEvent event = file_event_pop(fw); + FileEvent event = filewatcher_event_pop(fw); while (event.type != HI_FILE_NONE) { log_debug("Event pop: %s – %s\n", event.pathname, - hi_file_watch_type_to_str(event.type)); + filewatch_type_to_str(event.type)); - ModuleData *module = get_module_by_path(event.pathname, modules); + ModuleData *module = module_get(event.pathname, modules); if (!module) { log_warn("Watched module: %s not found.\n", event.pathname); } else { - module->info = hi_modinfo_add(module->info, HI_MODULE_STATE_DIRTY); + module->info = modinfo_add(module->info, HI_MODULE_STATE_DIRTY); } - event = file_event_pop(context.filewatcher); + event = filewatcher_event_pop(context.filewatcher); } } -static const char *find_string_from_array(const char *needle, - const VectorStr *haystack) { - - for (size_t i = 0; i < vector_size(haystack); i++) { - if (strcmp(needle, vector_at(haystack, i)) == 0) { - return vector_at(haystack, i); - } - } - - return NULL; -} - static HiResult reload_dirty_modules(HiloadContext *context) { HiResult ret = HI_OK; @@ -183,16 +197,11 @@ static HiResult reload_dirty_modules(HiloadContext *context) { ModuleData *module = &vector_at(&context->modules, i); // Operate on dirty modules only - if (hi_modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) { + if (modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) { - // Operate only if the module is marked as operatable - const char *module_name = - find_string_from_array(module->name, &context->enabled_modules); - if (module_name) { - log_info("Reloading %s...\n", module_name); - - if (!HIOK(moduler_reload(&context->modules, module, - &context->memory_regions))) { + if (modinfo_has(module->info, HI_MODULE_STATE_ENABLED)) { + log_info("Reloading %s...\n", module->name); + if (!HIOK(moduler_reload(&context->modules, module))) { ret = HI_FAIL; log_error("Failed loading: %s\n", module->name); } @@ -205,6 +214,7 @@ static HiResult reload_dirty_modules(HiloadContext *context) { int hi_init(size_t n, const char **enabled_modules) { if (log_init() != 0) { + // When there's no logging, only fprintf fprintf(stderr, "Failed to init logger.\n"); return 1; } @@ -212,21 +222,10 @@ int hi_init(size_t n, const char **enabled_modules) { log_set_thread_name("Main"); // Start the filewatcher - context.filewatcher = file_watcher_create(); + context.filewatcher = filewatcher_create(); - for (unsigned i = 0; i < n; i++) { - const char *module_name = enabled_modules[i]; - log_info("Enabling module: '%s'\n", module_name); - vector_add(&context.enabled_modules, module_name); - } - - vector_init(&context.memory_regions); - if (memmaps_from_process(&context.memory_regions) != HI_OK) { - log_error("Could not populate program memory maps.\n"); - return HI_FAIL; - } - - HiResult re = gather_module_infos(&context.modules); + HiResult re = + module_data_initial_gather(&context.modules, n, enabled_modules); if (re != HI_OK) { log_error("Failed to gather module infos.\n"); return 1; @@ -236,15 +235,15 @@ int hi_init(size_t n, const char **enabled_modules) { } void hi_deinit() { - module_infos_free(&context.modules); - file_watcher_destroy(context.filewatcher); + module_data_free(&context.modules); + filewatcher_destroy(context.filewatcher); log_term(); memset(&context, 0, sizeof(context)); } HiResult hi_reload() { - handle_events(context.filewatcher, &context.modules); + handle_file_events(context.filewatcher, &context.modules); reload_dirty_modules(&context); return HI_OK; } diff --git a/src/histring.c b/src/histring.c index 43b27d6..4789f75 100644 --- a/src/histring.c +++ b/src/histring.c @@ -7,8 +7,8 @@ #include #include -size_t hi_str_concat_buf(size_t buflen, char buf[buflen], const char *first, - const char *second) { +size_t string_concat_buf(size_t buflen, char buf[buflen], const char *first, + const char *second) { if (!buf) return 0; @@ -16,6 +16,7 @@ size_t hi_str_concat_buf(size_t buflen, char buf[buflen], const char *first, size_t second_len = strlen(second); if (buf + first_len + second_len > buf + buflen - 1) { + // If combined length of the strings wouldn't fit in the buffer, exit early return 0; } @@ -30,22 +31,7 @@ size_t hi_str_concat_buf(size_t buflen, char buf[buflen], const char *first, return second_end - buf; } -int hi_path_has_filename(const char *path, const char *filename) { - - const char *compared_filename = path; - const char *basename = strrchr(path, '/'); - - if (basename) - compared_filename = basename + 1; - - if (strcmp(compared_filename, filename) == 0) { - return 1; - } - return 0; -} - -char *hi_str_from_file(const char *filename, size_t *nread, - size_t nmax) { +char *string_from_file(const char *filename, size_t *nread, size_t nmax) { FILE *f = fopen(filename, "r"); if (!f) { @@ -107,17 +93,61 @@ char *hi_str_from_file(const char *filename, size_t *nread, return buf; } -const char *hi_str_starts_with(const char path[static 1], size_t listn, - const char *pathlist[listn]) { +bool string_is_empty(const char s[static 1]) { return s[0] == '\0'; } - if (!pathlist) - return path; - size_t pathlen = strlen(path); +bool string_starts_with(const char s[static 1], + const char startswith[static 1]) { + size_t startswith_len = strlen(startswith); + size_t s_len = strlen(s); + + if (startswith_len > s_len) + return false; + size_t len = MIN(strlen(s), strlen(startswith)); + bool res = strncmp(s, startswith, len) == 0; + return res; +} + +const char *string_starts_with_any(const char s[static 1], size_t listn, + const char *slist[listn]) { + if (!slist) + return s; + size_t pathlen = strlen(s); for (size_t i = 0; i < listn; ++i) { - size_t len = MIN(strlen(pathlist[i]), pathlen); - if (strncmp(path, pathlist[i], len) == 0) { - return pathlist[i]; + size_t len = MIN(strlen(slist[i]), pathlen); + if (strncmp(s, slist[i], len) == 0) { + return slist[i]; } } return NULL; } + +const char *string_ends_with_any(const char s[static 1], size_t listn, + const char *slist[listn]) { + if (!slist) + return s; + size_t slen = strlen(s); + for (size_t i = 0; i < listn; ++i) { + + size_t len = MIN(strlen(slist[i]), slen); + if (strncmp(s, slist[i], len) == 0) { + return slist[i]; + } + } + return NULL; +} + +int string_last_token_is(const char *s, const char *ifthis, char delim) { + + const char *last_token = s; + const char *basename = strrchr(s, delim); + + if (basename) + last_token = basename + 1; + + if (strcmp(last_token, ifthis) == 0) { + return 1; + } + return 0; +} + +const char *strpath_filename(const char *s) { return strrchr(s, '/'); } diff --git a/src/histring.h b/src/histring.h index 5c32cbe..ac8878d 100644 --- a/src/histring.h +++ b/src/histring.h @@ -1,19 +1,21 @@ #pragma once +#include #include /** * Concatenate two strings into a buffer. * - * If resulting string would be longer than @a buflen - 1, @a buf remains unchanged. + * If resulting string would be longer than @a buflen - 1, @a buf remains + * unchanged. * * @param bufsize Size of the destination buffer @a buf * @param buf The destination buffer * @param first Null terminated character string * @param second Null terminated character string */ -size_t hi_str_concat_buf(size_t bufsize, char buf[bufsize], - const char *first, const char *second); +size_t string_concat_buf(size_t bufsize, char buf[bufsize], const char *first, + const char *second); /** * Copy file content to a null terminated string, allocating memory while @@ -31,20 +33,34 @@ size_t hi_str_concat_buf(size_t bufsize, char buf[bufsize], * @param nmax if not 0, this amount of memory in bytes is read and used as * initial allocation */ -char *hi_str_from_file(const char *filename, size_t *nread, - size_t nmax); +char *string_from_file(const char *filename, size_t *nread, size_t nmax); /** - * Return the first string from @a pathlist that is fully included in @a path. + * Test if null terminated string is empty */ -const char *hi_str_starts_with(const char path[static 1], size_t listn, - const char *pathlist[listn]); +bool string_is_empty(const char s[static 1]); +/** + * Return the first string from @a slist that @a s starts with. + */ +const char *string_starts_with_any(const char s[static 1], size_t listn, + const char *slist[listn]); +/** + * Return the first string from @a slist that @a s ends with. + */ +const char *string_ends_with_any(const char s[static 1], size_t listn, + const char *slist[listn]); /** * Find if @a filename exists at the end of @a path. * + * ```c + * + * if (string_last_token_is(fullpath, filename, '/')) { ... } + * ```` + * * @return 0 if not found, positive if found */ -int hi_path_has_filename(const char *path, const char *filename); +int string_last_token_is(const char *s, const char *ifthis, char delim); +const char *strpath_filename(const char *s); diff --git a/src/moduler.c b/src/moduler.c index 3e3c16c..0b90b99 100644 --- a/src/moduler.c +++ b/src/moduler.c @@ -264,7 +264,7 @@ static HiResult moduler_apply_module_patch(VectorSymbol *psymbols, return HI_OK; } -PatchData moduler_create_patch(ModuleData *module) { +static PatchData moduler_create_patch(ModuleData *module) { time_t now = time(NULL); struct tm *t = localtime(&now); @@ -281,7 +281,7 @@ PatchData moduler_create_patch(ModuleData *module) { char filename[512]; size_t written = - hi_str_concat_buf(sizeof(filename), filename, module->name, file_append); + string_concat_buf(sizeof(filename), filename, module->name, file_append); if (written == 0) { log_error("Failed to concat %s and %s\n", module->name, ".patch"); @@ -294,14 +294,13 @@ PatchData moduler_create_patch(ModuleData *module) { return data; } -HiResult moduler_reload(VectorModuleData *modules, ModuleData *module, - VectorMemoryMap *memmaps) { +HiResult moduler_reload(VectorModuleData *modules, ModuleData *module) { // Return OK because this isn't an error case. We just don't do it yet // because we only handle reloading a complete solib. Can't do that with // executables. - if (hi_modinfo_has(module->info, HI_MODULE_STATE_EXEC)) { - module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); + if (modinfo_has(module->info, HI_MODULE_STATE_EXEC)) { + module->info = modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); return HI_OK; } @@ -317,18 +316,19 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module, void *new_handle = dlopen(patch.filename, RTLD_LAZY); if (!new_handle) { log_error("Couldn't load: %s\n", dlerror()); - module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); + module->info = modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); return HI_FAIL; } patch.dlhandle = new_handle; - // refresh cache - if (!HIOK(memmaps_from_process(memmaps))) { + VectorMemoryMap memmaps; + vector_init(&memmaps); + if (!HIOK(memmaps_from_process(&memmaps))) { log_error("Failed to collect memory information for process\n"); return HI_FAIL; } - patch.memreg = memmaps_find_by_name(patch.filename, memmaps); + patch.memreg = memmaps_find_by_name(patch.filename, &memmaps); void *patch_base = (void *)patch.memreg.start; VectorSymbol patch_symbols; @@ -344,11 +344,11 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module, for (size_t i = 0; i < vector_size(modules); ++i) { ModuleData mod = vector_at(modules, i); - if (!hi_modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE)) + if (!modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE)) continue; log_debug("Patching: %s\n", mod.name); - MemorySpan module_memory = memmaps_find_by_name(mod.name, memmaps); + MemorySpan module_memory = memmaps_find_by_name(mod.name, &memmaps); moduler_apply_module_patch(&patch_symbols, module_memory); if (strncmp(mod.name, patch.filename, strlen(mod.name)) == 0) { @@ -383,7 +383,7 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module, symbol_term(&module_symbols); } - module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); + module->info = modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); } free((char *)patch.filename); diff --git a/src/moduler.h b/src/moduler.h index b8b9fb9..4440b3a 100644 --- a/src/moduler.h +++ b/src/moduler.h @@ -8,33 +8,37 @@ struct HiloadContext; typedef enum { - HI_MODULE_STATE_DIRTY = (1 << 0), + HI_MODULE_STATE_ENABLED = (1 << 0), + HI_MODULE_STATE_DIRTY = (1 << 1), HI_MODULE_STATE_PATCHABLE = (1 << 6), // non system module we will modify HI_MODULE_STATE_EXEC = (1 << 7), // denote the current executable } ModuleFlags; -typedef u8 ModuleInfo; +typedef u32 ModuleInfo; typedef struct { - const char *name; // Filename + /// Owning. Filename for the module. + const char *name; + /// Handle given by dlopen void *dlhandle; + /// Start address for the module uptr address; + /// Additional information, see @a ModuleFlags ModuleInfo info; } ModuleData; vector_def(ModuleData, ModuleData); -static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, ModuleFlags flag) { +static inline ModuleInfo modinfo_add(ModuleInfo flags, ModuleFlags flag) { return flags | flag; } -static inline ModuleInfo hi_modinfo_clear(ModuleInfo flags, ModuleFlags flag) { +static inline ModuleInfo modinfo_clear(ModuleInfo flags, ModuleFlags flag) { return flags & ~flag; } -static inline bool hi_modinfo_has(ModuleInfo flags, ModuleFlags flag) { +static inline bool modinfo_has(ModuleInfo flags, ModuleFlags flag) { return (flags & flag) != 0; } #define HI_MODINFO_SET(info, flag) ((info) |= flag) #define HI_MODINFO_CLEAR(info, flag) ((info) &= ~flag) -HiResult moduler_reload(VectorModuleData *modules, ModuleData *module, - VectorMemoryMap *memregs); +HiResult moduler_reload(VectorModuleData *modules, ModuleData *module); diff --git a/test/manual/minimal.cpp b/test/manual/minimal.cpp index 272a801..fb2ff8f 100644 --- a/test/manual/minimal.cpp +++ b/test/manual/minimal.cpp @@ -1,6 +1,6 @@ #include "minimal_lib.h" -#include "../../include/hiload/hiload.h" +#include "../../include/hiload.h" #include #include