From 5539596929818e795a922a6928f581c4f7f05ec6 Mon Sep 17 00:00:00 2001 From: Kasper Date: Fri, 2 May 2025 00:15:51 +0300 Subject: [PATCH] Type and naming cleanup Do not use Hi prefic for things that shouldn't be visible to outside code --- include/hiload/hiload.h | 33 ++++++----- include/hitypes.h | 9 +++ src/array/array.h | 6 ++ src/common.h | 2 - src/files.c | 8 +-- src/files.h | 2 +- src/filewatcher/filewatch.c | 46 +++++++-------- src/filewatcher/filewatch.h | 15 +++-- src/filewatcher/filewatch_context.h | 47 +++++++++------ src/filewatcher/filewatch_type.h | 14 ++--- src/filewatcher/filewatcher.c | 88 ++++++++++++++--------------- src/filewatcher/filewatcher.h | 23 ++++---- src/hiload.c | 77 ++++++++++++++----------- src/memory.c | 26 ++++----- src/memory.h | 17 +++--- src/moduler/elf.c | 6 +- src/moduler/moduler.c | 50 +++++++--------- src/moduler/moduler.h | 28 ++++----- src/symbols.c | 1 - src/types.h | 5 +- test/manual/minimal.cpp | 2 +- 21 files changed, 263 insertions(+), 242 deletions(-) create mode 100644 include/hitypes.h diff --git a/include/hiload/hiload.h b/include/hiload/hiload.h index df919dd..6bb441b 100644 --- a/include/hiload/hiload.h +++ b/include/hiload/hiload.h @@ -1,7 +1,10 @@ #ifndef HILOAD_H_ #define HILOAD_H_ -#include "types.h" +#include "hitypes.h" + +#include + #ifdef __cplusplus extern "C" { #endif @@ -10,30 +13,26 @@ extern "C" { #pragma GCC visibility push(default) /** - * Initialiez the module. Must be called before anything else + * Must be called before other functions. Sets up filewatchers for the relevant + * files + * @n n Number of modules in @a enabled_modules + * @param enabled_modules The name of a module that should have its changes + * applied to the running process. A short form is expected, e.g. + * `libhiload.so`. An empty string denotes the executable of the running + * process. */ -int hi_init(unsigned n, const char **enabled_modules); +int hi_init(size_t n, const char **enabled_modules); /** - * Frees memory and cleans up + * Frees allocated memory. Call when hiload is no longer used. */ void hi_deinit(void); /** - * Print a random assortment of information from current state + * Reload all enabled modules that have been changed since init or last + * invocation and apply changes to the running process. */ -void hi_print_loaded_modules(void); - -/** - * Reload shared library if it has changed since last reload or init was called - */ -HiloadResult hi_reload_solib(const char *module_name); - -/** - * Reload all watched modules - */ -HiloadResult hi_reload(); - +HiResult hi_reload(void); #pragma GCC visibility pop diff --git a/include/hitypes.h b/include/hitypes.h new file mode 100644 index 0000000..ac61edd --- /dev/null +++ b/include/hitypes.h @@ -0,0 +1,9 @@ +#ifndef HITYPES_H_ +#define HITYPES_H_ + +typedef enum { HI_FAIL = 0, HI_OK } HiResult; + +#define HIOK(res) ((res) == HI_OK) + + +#endif // HITYPES_H_ diff --git a/src/array/array.h b/src/array/array.h index 3982f93..e40d0ab 100644 --- a/src/array/array.h +++ b/src/array/array.h @@ -3,4 +3,10 @@ #include "array/sc_array.h" +typedef struct sc_array_32 VectorU32; +typedef struct sc_array_64 VectorU64; +typedef struct sc_array_double VectorDouble; +typedef struct sc_array_str VectorStr; +typedef struct sc_array_ptr VectorPtr; + #endif // ARRAY_H_ diff --git a/src/common.h b/src/common.h index f838c0c..e70b536 100644 --- a/src/common.h +++ b/src/common.h @@ -9,8 +9,6 @@ static inline u32 has_mask(u32 flags, u32 mask) { return flags & mask; } #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define ARRLEN(A) (sizeof((A)) / (sizeof((A)[0]))) -#define HIOK(res) ((res) == HILOAD_OK) - #define UNUSED(v) (void)(v) #endif // COMMON_H_ diff --git a/src/files.c b/src/files.c index ef870e8..bfc442b 100644 --- a/src/files.c +++ b/src/files.c @@ -45,14 +45,14 @@ const char *hi_file_name_from_path(const char *path) { return filename; } -HiloadResult hi_file_copy(const char *srcname, const char *destination) { +HiResult hi_file_copy(const char *srcname, const char *destination) { - HiloadResult ret = HILOAD_FAIL; + HiResult ret = HI_FAIL; FILE *src = fopen(srcname, "rb"); if (src == NULL) { log_error("Couldn't open file: %s for copy\n", srcname); - return HILOAD_FAIL; + return HI_FAIL; } char buf[512]; @@ -86,7 +86,7 @@ HiloadResult hi_file_copy(const char *srcname, const char *destination) { goto cleanup; } - ret = HILOAD_OK; + ret = HI_OK; cleanup: if (src) fclose(src); diff --git a/src/files.h b/src/files.h index 6064d91..f1e216c 100644 --- a/src/files.h +++ b/src/files.h @@ -32,7 +32,7 @@ char *hi_file_to_str_dyn(const char *filename); * If \p dest has either '/' or '\' as the last character, it is interpreted as * a directory and the file is copied to the directory with the same filename. */ -HiloadResult hi_file_copy(const char *filename, const char *dest); +HiResult hi_file_copy(const char *filename, const char *dest); HiFileType hi_file_type(const char *path); diff --git a/src/filewatcher/filewatch.c b/src/filewatcher/filewatch.c index da8f60c..a4045f8 100644 --- a/src/filewatcher/filewatch.c +++ b/src/filewatcher/filewatch.c @@ -46,7 +46,7 @@ static inline struct WatchMaskParams inode_watch_masks_create(u32 flags) { .parent_mask = parent_mask}; } -static void file_watch_destroy(int fd, hiFileWatch *fw) { +static void file_watch_destroy(int fd, FileWatch *fw) { inotify_rm_watch(fd, fw->wd); free((void *)fw->path); @@ -54,20 +54,20 @@ static void file_watch_destroy(int fd, hiFileWatch *fw) { fw->path = NULL; } -void file_watch_destroy_watches(struct hiFileWatcherContext *ctx) { +void file_watch_destroy_watches(FileWatcherContext *ctx) { for (size_t i = 0; i < sc_array_size(&ctx->watches); i++) { - hiFileWatch *fw = &sc_array_at(&ctx->watches, i); + FileWatch *fw = &sc_array_at(&ctx->watches, i); file_watch_destroy(ctx->fd, fw); } sc_array_term(&ctx->watches); } -hiFileWatch *file_watch_find_by_wd(struct hiFileWatcherContext *ctx, int wd, +FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, int wd, size_t *index) { struct sc_array_fwatch *watches = &ctx->watches; for (size_t i = 0; i < sc_array_size(watches); ++i) { - hiFileWatch *fw = &sc_array_at(watches, i); + FileWatch *fw = &sc_array_at(watches, i); if (fw->wd == wd) { if (index) { *index = i; @@ -78,10 +78,10 @@ hiFileWatch *file_watch_find_by_wd(struct hiFileWatcherContext *ctx, int wd, return NULL; } -hiFileWatch *file_watch_find_by_path(struct hiFileWatcherContext *ctx, +FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, const char *path, size_t *index) { for (size_t i = 0; i < sc_array_size(&ctx->watches); i++) { - hiFileWatch *watch = &sc_array_at(&ctx->watches, i); + FileWatch *watch = &sc_array_at(&ctx->watches, i); if (strcmp(watch->path, path) == 0) { if (index) { *index = i; @@ -110,22 +110,22 @@ static char *get_parent_folder(const char path[static 1]) { return parent; } -HiloadResult file_watch_add(hiFileWatcherContext *ctx, u32 mask, +HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, const char *path) { if (!ctx || ctx->fd == -1) { - sc_log_error("Invalid inotify context\n"); - return HILOAD_FAIL; + log_error("Invalid inotify context\n"); + return HI_FAIL; } struct WatchMaskParams params = inode_watch_masks_create(mask); - hiFileWatch *watch = file_watch_find_by_path(ctx, path, NULL); + FileWatch *watch = file_watch_find_by_path(ctx, path, NULL); if (!watch) { int wd = inotify_add_watch(ctx->fd, path, params.file_mask); if (wd == -1) { - sc_log_error("Couldn't watch: %s: %s\n", path, strerror(errno)); - return HILOAD_FAIL; + log_error("Couldn't watch: %s: %s\n", path, strerror(errno)); + return HI_FAIL; } - hiFileWatch wp = {.wd = wd, .mask = mask, .path = strdup(path)}; + FileWatch wp = {.wd = wd, .mask = mask, .path = strdup(path)}; sc_array_add(&ctx->watches, wp); watch = &sc_array_last(&ctx->watches); } else { @@ -134,11 +134,11 @@ HiloadResult file_watch_add(hiFileWatcherContext *ctx, u32 mask, if (!has_mask(HI_FILE_PARENT, mask)) { char *parent_name = get_parent_folder(path); - hiFileWatch *parent_watch = file_watch_find_by_path(ctx, parent_name, NULL); + FileWatch *parent_watch = file_watch_find_by_path(ctx, parent_name, NULL); if (!parent_watch) { // parent not yet watched int wd = inotify_add_watch(ctx->fd, parent_name, params.parent_mask); - hiFileWatch wp = {.wd = wd, .mask = HI_FILE_PARENT, .path = parent_name}; + FileWatch wp = {.wd = wd, .mask = HI_FILE_PARENT, .path = parent_name}; sc_array_init(&wp.files); sc_array_add(&wp.files, strdup(watch->path)); sc_array_add(&ctx->watches, wp); @@ -163,19 +163,19 @@ HiloadResult file_watch_add(hiFileWatcherContext *ctx, u32 mask, } } - return HILOAD_OK; + return HI_OK; } -HiloadResult file_watch_remove(hiFileWatcherContext *ctx, const char *path) { +HiResult file_watch_remove(FileWatcherContext *ctx, const char *path) { size_t i = 0; - hiFileWatch *watch = file_watch_find_by_path(ctx, path, &i); + FileWatch *watch = file_watch_find_by_path(ctx, path, &i); if (watch) { - // destroy parent reference. We assume it will only have one. + // Destroy parent reference. We assume it will only have one. char *parent = get_parent_folder(path); if (parent) { - hiFileWatch *pw = file_watch_find_by_path(ctx, parent, NULL); + FileWatch *pw = file_watch_find_by_path(ctx, parent, NULL); if (pw) { for (size_t i = 0; i < sc_array_size(&pw->files); i++) { const char *fn = sc_array_at(&pw->files, i); @@ -189,7 +189,7 @@ HiloadResult file_watch_remove(hiFileWatcherContext *ctx, const char *path) { } file_watch_destroy(ctx->fd, watch); sc_array_del(&ctx->watches, i); - return HILOAD_OK; + return HI_OK; } - return HILOAD_FAIL; + return HI_FAIL; } diff --git a/src/filewatcher/filewatch.h b/src/filewatcher/filewatch.h index 64bb0dd..f67dbcf 100644 --- a/src/filewatcher/filewatch.h +++ b/src/filewatcher/filewatch.h @@ -2,21 +2,20 @@ #define FILEWATCH_H_ #include "array/array.h" -#include "filewatch_context.h" #include "types.h" -struct hiFileWatcherContext; -struct hiFileWatch; +typedef struct FileWatcherContext FileWatcherContext; +typedef struct FileWatch FileWatch; -hiFileWatch *file_watch_find_by_wd(struct hiFileWatcherContext *ctx, +FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, int wd, size_t *index); -hiFileWatch *file_watch_find_by_path(struct hiFileWatcherContext *ctx, +FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, const char *path, size_t *index); -HiloadResult file_watch_add(struct hiFileWatcherContext *ctx, u32 mask, +HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, const char *path); -HiloadResult file_watch_remove(struct hiFileWatcherContext *ctx, +HiResult file_watch_remove(FileWatcherContext *ctx, const char *path); -void file_watch_destroy_watches(struct hiFileWatcherContext *ctx); +void file_watch_destroy_watches(FileWatcherContext *ctx); #endif // FILEWATCH_H_ diff --git a/src/filewatcher/filewatch_context.h b/src/filewatcher/filewatch_context.h index 6b9c391..e397f11 100644 --- a/src/filewatcher/filewatch_context.h +++ b/src/filewatcher/filewatch_context.h @@ -2,34 +2,47 @@ #define FILEWATCH_CONTEXT_H_ #include "array/array.h" +#include "filewatcher/filewatch.h" #include "types.h" /** - * Added for each file watch call. + * Represents one watch by the user. * * Events and watches refer to the same string as params for efficient string * comparison, but this means care has to be taken when deleting the params. - * Events should be cleared first. + * Events should be cleared or not referenced before watches are removed. */ -typedef struct { - const char *path; // Params own their path +typedef struct WatchParams { + const char *path; // Owning u32 mask; -} hiWatchParams; -sc_array_def(hiWatchParams, fwparam); +} WatchParams; -typedef struct { - int wd; // Watch descriptor +sc_array_def(WatchParams, fwparam); +typedef struct sc_array_fwparam VectorWatchParams; + +/** + * Represents a single watch entity given to inotify. + * + * Typically one exists for the file itself and one for the parent. Parents are + * reused, and @a files is a list of files that have this watch as their parent. + */ +typedef struct FileWatch { + i32 wd; // Watch descriptor u32 mask; // watch mask used - const char *path; // inotify watch path, owning if it's a parent watcher - struct sc_array_str - files; // param paths associated with that path. Pointers to paths params. -} hiFileWatch; -sc_array_def(hiFileWatch, fwatch); + const char *path; // Owning + VectorStr files; +} FileWatch; -typedef struct hiFileWatcherContext { +sc_array_def(FileWatch, fwatch); +typedef struct sc_array_fwatch VectorFileWatch; + +/** + * Holds the required data to understand a running FileWatcher. + */ +typedef struct FileWatcherContext { int fd; - struct sc_array_fwparam params; - struct sc_array_fwatch watches; -} hiFileWatcherContext; + VectorWatchParams params; + VectorFileWatch watches; +} FileWatcherContext; #endif // FILEWATCH_CONTEXT_H_ diff --git a/src/filewatcher/filewatch_type.h b/src/filewatcher/filewatch_type.h index fd79f6b..937f9d0 100644 --- a/src/filewatcher/filewatch_type.h +++ b/src/filewatcher/filewatch_type.h @@ -3,17 +3,17 @@ typedef enum { HI_FILE_NONE = 0, // Used to signal invalid event - HI_FILE_MODIFY = 1 << 1, - HI_FILE_CREATE = 1 << 2, - HI_FILE_DELETE = 1 << 3, - HI_FILE_MOVE = 1 << 4, + HI_FILE_MODIFY = (1 << 1), + HI_FILE_CREATE = (1 << 2), + HI_FILE_DELETE = (1 << 3), + HI_FILE_MOVE = (1 << 4), HI_FILE_CHANGE = (HI_FILE_MODIFY | HI_FILE_CREATE | HI_FILE_DELETE | HI_FILE_MOVE), HI_FILE_ALL_EVENTS = (HI_FILE_CHANGE), - HI_FILE_PARENT = 1 << 31, -} HiFileWatchType; + HI_FILE_PARENT = (1 << 30), +} FileWatchType; -static inline const char *hi_file_watch_type_to_str(HiFileWatchType type) { +static inline const char *hi_file_watch_type_to_str(FileWatchType type) { switch (type) { case HI_FILE_NONE: return "HI_FILE_NONE"; diff --git a/src/filewatcher/filewatcher.c b/src/filewatcher/filewatcher.c index c6b8250..01875fb 100644 --- a/src/filewatcher/filewatcher.c +++ b/src/filewatcher/filewatcher.c @@ -19,35 +19,36 @@ #include "logger/logger.h" #include "types.h" -sc_array_def(hiFileEvent, fwevent); +sc_array_def(FileEvent, fwevent); +typedef struct sc_array_fwevent VectorFileEvent; -typedef struct hiFileWatcher { +typedef struct FileWatcher { thrd_t thread; mtx_t mutex; cnd_t cond; int running; - struct hiFileWatcherContext context; - struct sc_array_fwevent events; -} hiFileWatcher; + FileWatcherContext context; + VectorFileEvent events; +} FileWatcher; /* * Watch Params */ -static inline hiWatchParams watch_params_create(const char *path, u32 mask) { - return (hiWatchParams){.path = strdup(path), .mask = mask}; +static inline WatchParams watch_params_create(const char *path, u32 mask) { + return (WatchParams){.path = strdup(path), .mask = mask}; } -static inline void watch_params_destroy(hiWatchParams *params) { +static inline void watch_params_destroy(WatchParams *params) { free((char *)params->path); } -static hiWatchParams *watch_params_find_by_path(const char *path, - hiFileWatcherContext *ctx, - size_t *index) { +static WatchParams *watch_params_find_by_path(const char *path, + FileWatcherContext *ctx, + size_t *index) { const struct sc_array_fwparam *params = &ctx->params; for (size_t i = 0; i < sc_array_size(params); ++i) { - hiWatchParams *param = &sc_array_at(params, i); + WatchParams *param = &sc_array_at(params, i); if (strcmp(path, param->path) == 0) { if (index) *index = i; @@ -61,17 +62,17 @@ static hiWatchParams *watch_params_find_by_path(const char *path, * File Events */ -#define NULL_EVENT (hiFileEvent){0}; +#define NULL_EVENT (FileEvent){0}; -static hiFileEvent file_event_create(const struct inotify_event *inevent, - hiFileWatcherContext *ctx) { - hiFileEvent event = {0}; +static FileEvent file_event_create(const struct inotify_event *inevent, + FileWatcherContext *ctx) { + FileEvent event = {0}; if (!inevent) { return event; } - const hiFileWatch *fw = file_watch_find_by_wd(ctx, inevent->wd, NULL); + const FileWatch *fw = file_watch_find_by_wd(ctx, inevent->wd, NULL); if (has_mask(inevent->mask, IN_IGNORED)) { sc_log_debug("IN_IGNORED received on %s\n", fw->path); @@ -102,7 +103,7 @@ static hiFileEvent file_event_create(const struct inotify_event *inevent, if (strcmp(watched_file, filename) == 0) { // check if event mask matches the watcher mask - hiWatchParams *params = + WatchParams *params = watch_params_find_by_path(watched_file, ctx, NULL); if (!params) { return NULL_EVENT; @@ -139,10 +140,10 @@ static hiFileEvent file_event_create(const struct inotify_event *inevent, return NULL_EVENT; } -hiFileEvent hi_file_event_pop(hiFileWatcher *fw) { +FileEvent hi_file_event_pop(FileWatcher *fw) { mtx_lock(&fw->mutex); - hiFileEvent e = NULL_EVENT; + FileEvent e = NULL_EVENT; if (sc_array_size(&fw->events) > 0) { e = sc_array_last(&fw->events); sc_array_del_last(&fw->events); @@ -156,19 +157,19 @@ hiFileEvent hi_file_event_pop(hiFileWatcher *fw) { * File Watcher */ -static HiloadResult file_watcher_ctx_init(hiFileWatcherContext *ctx) { +static HiResult file_watcher_ctx_init(FileWatcherContext *ctx) { ctx->fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); if (ctx->fd == -1) { - return HILOAD_FAIL; + return HI_FAIL; } sc_array_init(&ctx->watches); sc_array_init(&ctx->params); - return HILOAD_OK; + return HI_OK; } -static void file_watcher_ctx_destroy(hiFileWatcherContext *ctx) { +static void file_watcher_ctx_destroy(FileWatcherContext *ctx) { if (ctx) { file_watch_destroy_watches(ctx); } @@ -177,11 +178,11 @@ static void file_watcher_ctx_destroy(hiFileWatcherContext *ctx) { // Declare the thread func int file_watcher_watch(void *arg); -hiFileWatcher *hi_file_watcher_create() { +FileWatcher *hi_file_watcher_create() { // Allocate context - hiFileWatcher *fw = malloc(sizeof(hiFileWatcher)); - memset(fw, 0, sizeof(hiFileWatcher)); + FileWatcher *fw = malloc(sizeof(FileWatcher)); + memset(fw, 0, sizeof(FileWatcher)); if (fw) { if (!HIOK(file_watcher_ctx_init(&fw->context))) { @@ -203,26 +204,25 @@ hiFileWatcher *hi_file_watcher_create() { return NULL; } -HiloadResult hi_file_watcher_add(struct hiFileWatcher *fw, const char *filename, - u32 flags) { +HiResult hi_file_watcher_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); - return HILOAD_FAIL; + return HI_FAIL; } mtx_lock(&fw->mutex); if (!HIOK(file_watch_add(&fw->context, flags, filename))) { mtx_unlock(&fw->mutex); - return HILOAD_FAIL; + return HI_FAIL; } { // Add watch param as well - hiWatchParams *params = + WatchParams *params = watch_params_find_by_path(filename, &fw->context, NULL); if (!params) { - hiWatchParams params = watch_params_create(filename, flags); + WatchParams params = watch_params_create(filename, flags); sc_array_add(&fw->context.params, params); } else { params->mask |= flags; @@ -230,42 +230,40 @@ HiloadResult hi_file_watcher_add(struct hiFileWatcher *fw, const char *filename, } mtx_unlock(&fw->mutex); - return HILOAD_OK; + return HI_OK; } -HiloadResult hi_file_watcher_remove(struct hiFileWatcher *fw, - const char *filename) { +HiResult hi_file_watcher_remove(FileWatcher *fw, const char *filename) { if (!fw) { - return HILOAD_FAIL; + return HI_FAIL; } mtx_lock(&fw->mutex); if (!HIOK(file_watch_remove(&fw->context, filename))) { mtx_unlock(&fw->mutex); - return HILOAD_FAIL; + return HI_FAIL; } { // remove watchparam as well size_t i = 0; - hiWatchParams *params = - watch_params_find_by_path(filename, &fw->context, &i); + WatchParams *params = watch_params_find_by_path(filename, &fw->context, &i); watch_params_destroy(params); sc_array_del(&fw->context.params, i); } mtx_unlock(&fw->mutex); sc_log_info("Removed file: '%s' from watch, filename"); - return HILOAD_OK; + return HI_OK; } -void hi_file_watcher_notify(hiFileWatcher *fw) { +void hi_file_watcher_notify(FileWatcher *fw) { if (fw && fw->running) { cnd_signal(&fw->cond); } } -void hi_file_watcher_destroy(hiFileWatcher *fw) { +void hi_file_watcher_destroy(FileWatcher *fw) { if (!fw) return; @@ -280,7 +278,7 @@ void hi_file_watcher_destroy(hiFileWatcher *fw) { } int file_watcher_watch(void *arg) { - hiFileWatcher *ctx = (hiFileWatcher *)arg; + FileWatcher *ctx = (FileWatcher *)arg; sc_log_set_thread_name("File Watcher"); char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); @@ -303,7 +301,7 @@ int file_watcher_watch(void *arg) { ptr += sizeof(struct inotify_event) + event->len) { event = (const struct inotify_event *)ptr; - hiFileEvent e = file_event_create(event, &ctx->context); + FileEvent e = file_event_create(event, &ctx->context); if (e.type != HI_FILE_NONE) { sc_array_add(&ctx->events, e); diff --git a/src/filewatcher/filewatcher.h b/src/filewatcher/filewatcher.h index d76cdce..fc431f0 100644 --- a/src/filewatcher/filewatcher.h +++ b/src/filewatcher/filewatcher.h @@ -21,32 +21,35 @@ * memory inside the file watcher struct. */ typedef struct { - const char *pathname; // Pathname given with the `hi_file_watcher_add` call. + const char *pathname; // Pathname given to a `hi_file_watcher_add` call. // Do not free. - HiFileWatchType type; -} hiFileEvent; + FileWatchType type; +} FileEvent; + +typedef struct FileWatcher FileWatcher; -struct hiFileWatcher; /** * FileEvents is a thread safe list of events. * * It is implemented as a stack, so the events will be popped * in reverse chronological order. * */ -struct hiFileEvents; +typedef struct FileEvents FileEvents; /** * Create watcher and necessary data to run it. * * Will start the watcher thread immediately. */ -struct hiFileWatcher *hi_file_watcher_create(void); +FileWatcher *hi_file_watcher_create(void); + /** * Destroy a previously created file watcher context. * * Will join the thread and destroy event stack. */ -void hi_file_watcher_destroy(struct hiFileWatcher *context); +void hi_file_watcher_destroy(FileWatcher *context); + /** * Add a file to the watch list of a file watcher. * @@ -54,18 +57,18 @@ void hi_file_watcher_destroy(struct hiFileWatcher *context); * @param pathname Absolute path to the file or directory * @param flags The events that will be watched for */ -HiloadResult hi_file_watcher_add(struct hiFileWatcher *context, +HiResult hi_file_watcher_add(FileWatcher *context, const char *pathname, u32 flags); /** * Can be used to poke file watcher thread to make sure it empties * events before doing something, e.g. for shutting it down. */ -void hi_file_watcher_notify(struct hiFileWatcher *context); +void hi_file_watcher_notify(FileWatcher *context); /** * Pop an event from event stack. Call `hi_file_event_destroy` when done with * it. */ -hiFileEvent hi_file_event_pop(struct hiFileWatcher *ctx); +FileEvent hi_file_event_pop(FileWatcher *ctx); #endif // HI_FILEWATCHER_H_ diff --git a/src/hiload.c b/src/hiload.c index 0f15d87..29c399e 100644 --- a/src/hiload.c +++ b/src/hiload.c @@ -19,11 +19,21 @@ #include #include +/** + * These paths will be excluded when searching for symbols to replace. The + * 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[] = { + "/usr/", "/lib/", "/lib64/", "/bin/", "/opt/", +}; + + typedef struct { - struct sc_array_memreg memory_regions; - struct sc_array_str enabled_modules; - struct hiFileWatcher *filewatcher; - HiModuleArray modules; + VectorMemoryRegion memory_regions; + VectorStr enabled_modules; + FileWatcher *filewatcher; + VectorModuleData modules; } HiloadContext; static HiloadContext context = {0}; @@ -42,7 +52,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, void *handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); assert(handle); - HiModuleData module = {0}; + ModuleData module = {0}; module.dlhandle = handle; module.address = info->dlpi_addr; @@ -61,8 +71,8 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, // Mark everything but system and virtual modules as patchable if (module.name[0] == '/') { - if (!hi_string_starts_with(module.name, ARRLEN(mod_exclude_filter), - mod_exclude_filter)) { + if (!hi_string_starts_with(module.name, ARRLEN(module_exclude_filter), + module_exclude_filter)) { module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_PATCHABLE); } } @@ -79,7 +89,6 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, // Replace shortform with str pointer from module info sc_array_at(&context.enabled_modules, i) = module.name; - // Add filewatcher if (!HIOK(hi_file_watcher_add(context.filewatcher, modpath, HI_FILE_ALL_EVENTS))) { log_error("Failed to set filewatcher for: '%s'\n", modpath); @@ -93,13 +102,13 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size, log_warn("Couldn't load dlinfo for %s: %s\n", module.name, dlerror()); } - HiModuleArray *modules = (HiModuleArray *)data; + VectorModuleData *modules = (VectorModuleData *)data; sc_array_add(modules, module); return 0; // Continue iteration } -static void module_infos_free(HiModuleArray *modules) { +static void module_infos_free(VectorModuleData *modules) { if (!modules) return; @@ -108,7 +117,7 @@ static void module_infos_free(HiModuleArray *modules) { } } -HiloadResult gather_module_infos(HiModuleArray *modules) { +HiResult gather_module_infos(VectorModuleData *modules) { sc_array_init(modules); @@ -116,17 +125,17 @@ HiloadResult gather_module_infos(HiModuleArray *modules) { if (dl_iterate_phdr(gather_module_data_callback, modules) != 0) { // Error occurred in callback module_infos_free(modules); - return HILOAD_FAIL; + return HI_FAIL; } - return HILOAD_OK; + return HI_OK; } -static HiModuleData *get_module_by_path(const char *path, - HiModuleArray *modules) { +static ModuleData *get_module_by_path(const char *path, + VectorModuleData *modules) { for (size_t i = 0; i < sc_array_size(modules); i++) { - HiModuleData *module = &sc_array_at(modules, i); + ModuleData *module = &sc_array_at(modules, i); const char *name = module->name; if (strcmp(name, path) == 0) { return module; @@ -140,14 +149,14 @@ static HiModuleData *get_module_by_path(const char *path, * * Marks a module dirty if there has been any event. */ -static void handle_events(struct hiFileWatcher *fw, HiModuleArray *modules) { +static void handle_events(FileWatcher *fw, VectorModuleData *modules) { - hiFileEvent event = hi_file_event_pop(fw); + FileEvent event = hi_file_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)); - HiModuleData *module = get_module_by_path(event.pathname, modules); + ModuleData *module = get_module_by_path(event.pathname, modules); if (!module) { log_warn("Watched module: %s not found.\n", event.pathname); } else { @@ -169,11 +178,11 @@ static const char *find_string_from_array(const char *needle, return NULL; } -static HiloadResult reload_dirty_modules(HiloadContext *context) { +static HiResult reload_dirty_modules(HiloadContext *context) { - HiloadResult ret = HILOAD_OK; + HiResult ret = HI_OK; for (u8 i = 0; i < sc_array_size(&context->modules); i++) { - HiModuleData *module = &sc_array_at(&context->modules, i); + ModuleData *module = &sc_array_at(&context->modules, i); // Operate on dirty modules only if (hi_modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) { @@ -186,7 +195,7 @@ static HiloadResult reload_dirty_modules(HiloadContext *context) { if (!HIOK(moduler_reload(&context->modules, module, &context->memory_regions))) { - ret = HILOAD_FAIL; + ret = HI_FAIL; log_error("Failed loading: %s\n", module->name); } } @@ -195,14 +204,9 @@ static HiloadResult reload_dirty_modules(HiloadContext *context) { return ret; } -HiloadResult hi_reload() { - handle_events(context.filewatcher, &context.modules); - reload_dirty_modules(&context); - return HILOAD_OK; -} -int hi_init(unsigned n, const char **enabled_modules) { +int hi_init(size_t n, const char **enabled_modules) { if (log_init() != 0) { fprintf(stderr, "Failed to init logger.\n"); @@ -221,13 +225,13 @@ int hi_init(unsigned n, const char **enabled_modules) { } sc_array_init(&context.memory_regions); - if (read_memory_maps_self(&context.memory_regions) != HILOAD_OK) { + if (read_memory_maps_self(&context.memory_regions) != HI_OK) { log_error("Could not populate program memory maps.\n"); - return HILOAD_FAIL; + return HI_FAIL; } - HiloadResult re = gather_module_infos(&context.modules); - if (re != HILOAD_OK) { + HiResult re = gather_module_infos(&context.modules); + if (re != HI_OK) { log_error("Failed to gather module infos.\n"); return 1; } @@ -241,3 +245,10 @@ void hi_deinit() { log_term(); memset(&context, 0, sizeof(context)); } + +HiResult hi_reload() { + + handle_events(context.filewatcher, &context.modules); + reload_dirty_modules(&context); + return HI_OK; +} diff --git a/src/memory.c b/src/memory.c index 5995a51..c4321af 100644 --- a/src/memory.c +++ b/src/memory.c @@ -9,33 +9,33 @@ static inline int ptr_in_range(uptr ptr, uptr start, uptr end) { return ptr >= start && ptr <= end; } -HiloadResult memory_find_region(uptr ptr, struct sc_array_memreg *const regions, +HiResult memory_find_region(uptr ptr, struct sc_array_memreg *const regions, size_t *index) { for (size_t i = 0; i < sc_array_size(regions); i++) { uptr start = regions->elems[i].region_start; // we assume a sorted region by start address, so we can do a quick discard // here. very useful for relative vs absolute address checks if (ptr < start) - return HILOAD_FAIL; + return HI_FAIL; uptr end = regions->elems[i].region_end; if (ptr_in_range(ptr, start, end)) { if (index) *index = i; sc_log_debug("Pointer match (%p) found in index: %u, range: %p - %p\n", ptr, i, start, end); - return HILOAD_OK; + return HI_OK; } } - return HILOAD_FAIL; + return HI_FAIL; } -HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) { +HiResult read_memory_maps_self(struct sc_array_memreg *regions) { memory_clear_memregs(regions); char *maps_str = hi_file_to_str_dyn("/proc/self/maps"); if (!maps_str) - return HILOAD_FAIL; + return HI_FAIL; log_debugv("/proc/self/maps:\n%s", maps_str); @@ -53,7 +53,7 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) { // clang-format off // Format example from the file: // 7fa0b66ca000-7fa0b66cc000 rw-p 00033000 fe:02 28063911 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 - int result = sscanf(line, "%lx-%lx %4s %lx %x:%x %lu %255s", + int result = sscanf(line, "%lx-%lx %4s %ld %x:%x %lu %255s", ®.region_start, ®.region_end, perm_str, @@ -63,11 +63,11 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) { ®.inode, pathname); - if (perm_str[0] == 'r') reg.permission |= HI_MEMORY_READ; - if (perm_str[1] == 'w') reg.permission |= HI_MEMORY_WRITE; - if (perm_str[2] == 'x') reg.permission |= HI_MEMORY_EXECUTE; - if (perm_str[3] == 'p') reg.permission |= HI_MEMORY_PRIVATE; - if (perm_str[3] == 's') reg.permission |= HI_MEMORY_SHARED; + if (perm_str[0] == 'r') reg.permissions |= HI_MEMORY_READ; + if (perm_str[1] == 'w') reg.permissions |= HI_MEMORY_WRITE; + if (perm_str[2] == 'x') reg.permissions |= HI_MEMORY_EXECUTE; + if (perm_str[3] == 'p') reg.permissions |= HI_MEMORY_PRIVATE; + if (perm_str[3] == 's') reg.permissions |= HI_MEMORY_SHARED; // clang-format on // pathname could be empty, so we check for it @@ -81,7 +81,7 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) { free(maps_str); - return HILOAD_OK; + return HI_OK; } MemoryRegionSpan diff --git a/src/memory.h b/src/memory.h index 349fe52..18af806 100644 --- a/src/memory.h +++ b/src/memory.h @@ -20,32 +20,33 @@ typedef struct { } MemoryRegionSpan; typedef struct { + const char *pathname; uptr region_start; uptr region_end; ptrdiff offset; u64 inode; - const char *pathname; - u32 permission; // enum MemoryPermissions + u32 permissions; // enum MemoryPermissions } MemoryRegion; sc_array_def(MemoryRegion, memreg); +typedef struct sc_array_memreg VectorMemoryRegion; // Free memory and init to zero -void memory_term_memregs(struct sc_array_memreg *regions); +void memory_term_memregs(VectorMemoryRegion *regions); // Doesn't free underlying array memory, only for each region -void memory_clear_memregs(struct sc_array_memreg *regions); +void memory_clear_memregs(VectorMemoryRegion *regions); // Free child memory void memory_free_memreg(MemoryRegion *reg); /* A pointer that can be used to place the memory regions into. Clears regions * before use, but uses the same buffer. */ -HiloadResult read_memory_maps_self(struct sc_array_memreg *regions); +HiResult read_memory_maps_self(VectorMemoryRegion *regions); /* Return index the pointer is found in */ -HiloadResult memory_find_pointer(uptr ptr, - struct sc_array_memreg *const regions, +HiResult memory_find_pointer(uptr ptr, + VectorMemoryRegion *const regions, size_t *index); -MemoryRegionSpan memory_get_module_span(const struct sc_array_memreg *const regions, +MemoryRegionSpan memory_get_module_span(const VectorMemoryRegion *const regions, const char module_name[static 1]); #endif // MEMORY_H_ diff --git a/src/moduler/elf.c b/src/moduler/elf.c index 16b9709..8c9cc26 100644 --- a/src/moduler/elf.c +++ b/src/moduler/elf.c @@ -29,7 +29,7 @@ void *hi_elf_find_dynamic_segment(void *module_base, size_t n, Elf **elf_ret) { } if (phdr.p_type == PT_DYNAMIC) { - dyn_addr = module_base + phdr.p_vaddr; + dyn_addr = (void*)((uptr)module_base + phdr.p_vaddr); break; } } @@ -61,8 +61,8 @@ void hi_elf_print_module_from_memory(void *address, size_t size) { log_debug("segment type: %s\n", hi_elf_segtostr(p->p_type)); size_t segment_size = p->p_memsz; - void *segment_start = address + p->p_vaddr; - void *segment_end = address + p->p_vaddr + segment_size; + void *segment_start = (void*)((uptr)address + p->p_vaddr); + void *segment_end = (void*)((uptr)address + p->p_vaddr + segment_size); void *strtab = 0; void *symtab = 0; diff --git a/src/moduler/moduler.c b/src/moduler/moduler.c index 582fc6d..7053cdb 100644 --- a/src/moduler/moduler.c +++ b/src/moduler/moduler.c @@ -10,11 +10,8 @@ #include "types.h" #include -#include #include #include -#include -#include #include #include #include @@ -36,23 +33,23 @@ static void *adjust_if_relative(void *ptr, void *module_base) { return (void *)p; } -static HiloadResult gather_patchable_symbols(struct sc_array_sym *symbols, +static HiResult gather_patchable_symbols(struct sc_array_sym *symbols, const char *module_name, void *module_base) { sc_array_clear(symbols); - HiloadResult ret = HILOAD_FAIL; + HiResult ret = HI_FAIL; int patchfd = open(module_name, O_RDONLY); if (patchfd == -1) { log_error("Failed to open %s: %s\n", module_name, strerror(errno)); - return HILOAD_FAIL; + return HI_FAIL; } if (elf_version(EV_CURRENT) == EV_NONE) { log_error("Failed to initialize libelf\n"); close(patchfd); - return HILOAD_FAIL; + return HI_FAIL; } Elf *elf = elf_begin(patchfd, ELF_C_READ, NULL); @@ -160,7 +157,7 @@ static HiloadResult gather_patchable_symbols(struct sc_array_sym *symbols, } } - ret = HILOAD_OK; + ret = HI_OK; cleanup: elf_end(elf); @@ -169,7 +166,7 @@ cleanup: return ret; } -static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols, +static HiResult moduler_apply_module_patch(HiSymbols *psymbols, MemoryRegionSpan module_memory) { void *module_base = (void *)module_memory.region_start; @@ -180,9 +177,7 @@ static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols, ElfW(Rela) *rela = NULL; ElfW(Sym) *symtab = NULL; char *strtab = NULL; - size_t pltsz = 0; size_t relasz = 0; - size_t plt_type = 0; Elf *elf = NULL; ElfW(Dyn) *dyn_sct = @@ -201,12 +196,6 @@ static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols, case DT_PLTGOT: plt = (ElfW(Rela) *)d->d_un.d_ptr; break; - case DT_PLTRELSZ: - pltsz = d->d_un.d_val; - break; - case DT_PLTREL: - plt_type = d->d_un.d_val; - break; case DT_JMPREL: jmprel = (ElfW(Rela) *)d->d_un.d_ptr; break; @@ -228,7 +217,7 @@ static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols, if ((!rela && !jmprel) || !symtab || !strtab || relasz == 0) { log_error("Missing required dynamic information\n"); elf_end(elf); - return HILOAD_FAIL; + return HI_FAIL; } int found_count = 0; @@ -272,10 +261,10 @@ static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols, } elf_end(elf); - return HILOAD_OK; + return HI_OK; } -PatchData moduler_create_patch(HiModuleData *module) { +PatchData moduler_create_patch(ModuleData *module) { time_t now = time(NULL); struct tm *t = localtime(&now); @@ -305,7 +294,7 @@ PatchData moduler_create_patch(HiModuleData *module) { return data; } -HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, +HiResult moduler_reload(VectorModuleData *modules, ModuleData *module, struct sc_array_memreg *memregs) { // Return OK because this isn't an error case. We just don't do it yet @@ -313,13 +302,13 @@ HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, // executables. if (hi_modinfo_has(module->info, HI_MODULE_STATE_EXEC)) { module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); - return HILOAD_OK; + return HI_OK; } PatchData patch = moduler_create_patch(module); if (!patch.filename) { log_error("Couldn't create patch for %s\n", module->name); - return HILOAD_FAIL; + return HI_FAIL; } // Load patch @@ -329,7 +318,7 @@ HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, if (!new_handle) { log_error("Couldn't load: %s\n", dlerror()); module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); - return HILOAD_FAIL; + return HI_FAIL; } patch.dlhandle = new_handle; @@ -342,25 +331,26 @@ HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, HiSymbols patch_symbols; symbol_init_symbols(&patch_symbols); - HiloadResult ret = + HiResult ret = gather_patchable_symbols(&patch_symbols, patch.filename, patch_base); if (!HIOK(ret)) { log_error("Failed to gather symbols for %s\n", patch.filename); - return HILOAD_FAIL; + return HI_FAIL; } for (size_t i = 0; i < sc_array_size(modules); ++i) { - HiModuleData mod = sc_array_at(modules, i); + ModuleData mod = sc_array_at(modules, i); if (!hi_modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE)) continue; + log_debug("Patching: %s\n", mod.name); MemoryRegionSpan module_memory = memory_get_module_span(memregs, mod.name); moduler_apply_module_patch(&patch_symbols, module_memory); - // If patch is for the same module, also collect local object symbols for - // coping those over if (strncmp(mod.name, patch.filename, strlen(mod.name)) == 0) { + // If patch is for the same module, also collect local object symbols for + // coping those over. HiSymbols module_symbols; symbol_init_symbols(&module_symbols); @@ -399,5 +389,5 @@ HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, dlclose(module->dlhandle); module->dlhandle = patch.dlhandle; - return HILOAD_OK; + return HI_OK; } diff --git a/src/moduler/moduler.h b/src/moduler/moduler.h index a74f247..dbe2f16 100644 --- a/src/moduler/moduler.h +++ b/src/moduler/moduler.h @@ -8,15 +8,12 @@ struct HiloadContext; -static const char *mod_exclude_filter[] = { - "/usr/", "/lib/", "/lib64/", "/bin/", "/opt/", -}; typedef enum { - HI_MODULE_STATE_DIRTY = (1 << 0), + HI_MODULE_STATE_DIRTY = (1 << 0), HI_MODULE_STATE_PATCHABLE = (1 << 6), // non system module we will modify - HI_MODULE_STATE_EXEC = (1 << 7), // denote the current executable -} HiModuleFlags; + HI_MODULE_STATE_EXEC = (1 << 7), // denote the current executable +} ModuleFlags; typedef u8 ModuleInfo; typedef struct { @@ -24,27 +21,26 @@ typedef struct { void *dlhandle; uptr address; ModuleInfo info; -} HiModuleData; +} ModuleData; +sc_array_def(ModuleData, module); +typedef struct sc_array_module VectorModuleData; -sc_array_def(HiModuleData, module); -typedef struct sc_array_module HiModuleArray; - - -static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, HiModuleFlags flag) { +static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, ModuleFlags flag) { return flags | flag; } -static inline ModuleInfo hi_modinfo_clear(ModuleInfo flags, HiModuleFlags flag) { +static inline ModuleInfo hi_modinfo_clear(ModuleInfo flags, + ModuleFlags flag) { return flags & ~flag; } -static inline bool hi_modinfo_has(ModuleInfo flags, HiModuleFlags flag) { +static inline bool hi_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) -HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, - struct sc_array_memreg *memregs); +HiResult moduler_reload(VectorModuleData *modules, ModuleData *module, + VectorMemoryRegion *memregs); #endif // MODULER_H_ diff --git a/src/symbols.c b/src/symbols.c index b759d65..5fdbe8f 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -5,7 +5,6 @@ #include HiSymbol *symbol_find(HiSymbols *symbols, HiSymbol *symbol) { - size_t namelen = strlen(symbol->name); for (size_t i=0; i < sc_array_size(symbols); ++i) { HiSymbol *s = &sc_array_at(symbols, i); if (strcmp(s->name, symbol->name) == 0) { diff --git a/src/types.h b/src/types.h index 552ab07..8055cee 100644 --- a/src/types.h +++ b/src/types.h @@ -1,6 +1,8 @@ #ifndef TYPES_H_ #define TYPES_H_ +#include "hitypes.h" + #include #include @@ -21,7 +23,4 @@ typedef ptrdiff_t ptrdiff; typedef uint8_t bool8; typedef uint32_t bool32; -typedef enum { HILOAD_FAIL = 0, HILOAD_OK } HiloadResult; - - #endif // TYPES_H_ diff --git a/test/manual/minimal.cpp b/test/manual/minimal.cpp index 14b69e6..272a801 100644 --- a/test/manual/minimal.cpp +++ b/test/manual/minimal.cpp @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) { printf("otherValue: %d\n", minimal_lib::otherValue++); std::this_thread::sleep_for(std::chrono::seconds(1)); - if (hi_reload() != HILOAD_OK) { + if (hi_reload() != HI_OK) { fprintf(stderr, "Failed to load modules\n"); } }