Type and naming cleanup

Do not use Hi prefic for things that shouldn't be visible to outside code
This commit is contained in:
2025-05-02 00:15:51 +03:00
parent 3baa45c32e
commit 5539596929
21 changed files with 263 additions and 242 deletions

View File

@@ -1,7 +1,10 @@
#ifndef HILOAD_H_
#define HILOAD_H_
#include "types.h"
#include "hitypes.h"
#include <stddef.h>
#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

9
include/hitypes.h Normal file
View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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_

View File

@@ -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_

View File

@@ -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";

View File

@@ -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);

View File

@@ -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_

View File

@@ -19,11 +19,21 @@
#include <stdlib.h>
#include <string.h>
/**
* 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;
}

View File

@@ -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",
&reg.region_start,
&reg.region_end,
perm_str,
@@ -63,11 +63,11 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) {
&reg.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

View File

@@ -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_

View File

@@ -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;

View File

@@ -10,11 +10,8 @@
#include "types.h"
#include <dlfcn.h>
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <gelf.h>
#include <libelf.h>
#include <link.h>
#include <stdalign.h>
#include <stdbool.h>
@@ -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;
}

View File

@@ -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_

View File

@@ -5,7 +5,6 @@
#include <string.h>
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) {

View File

@@ -1,6 +1,8 @@
#ifndef TYPES_H_
#define TYPES_H_
#include "hitypes.h"
#include <stddef.h>
#include <stdint.h>
@@ -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_

View File

@@ -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");
}
}