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_ #ifndef HILOAD_H_
#define HILOAD_H_ #define HILOAD_H_
#include "types.h" #include "hitypes.h"
#include <stddef.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -10,30 +13,26 @@ extern "C" {
#pragma GCC visibility push(default) #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); 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); HiResult hi_reload(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();
#pragma GCC visibility pop #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" #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_ #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 MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B))
#define ARRLEN(A) (sizeof((A)) / (sizeof((A)[0]))) #define ARRLEN(A) (sizeof((A)) / (sizeof((A)[0])))
#define HIOK(res) ((res) == HILOAD_OK)
#define UNUSED(v) (void)(v) #define UNUSED(v) (void)(v)
#endif // COMMON_H_ #endif // COMMON_H_

View File

@@ -45,14 +45,14 @@ const char *hi_file_name_from_path(const char *path) {
return filename; 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"); FILE *src = fopen(srcname, "rb");
if (src == NULL) { if (src == NULL) {
log_error("Couldn't open file: %s for copy\n", srcname); log_error("Couldn't open file: %s for copy\n", srcname);
return HILOAD_FAIL; return HI_FAIL;
} }
char buf[512]; char buf[512];
@@ -86,7 +86,7 @@ HiloadResult hi_file_copy(const char *srcname, const char *destination) {
goto cleanup; goto cleanup;
} }
ret = HILOAD_OK; ret = HI_OK;
cleanup: cleanup:
if (src) fclose(src); 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 * 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. * 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); 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}; .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); inotify_rm_watch(fd, fw->wd);
free((void *)fw->path); free((void *)fw->path);
@@ -54,20 +54,20 @@ static void file_watch_destroy(int fd, hiFileWatch *fw) {
fw->path = NULL; 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++) { 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); file_watch_destroy(ctx->fd, fw);
} }
sc_array_term(&ctx->watches); 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) { size_t *index) {
struct sc_array_fwatch *watches = &ctx->watches; struct sc_array_fwatch *watches = &ctx->watches;
for (size_t i = 0; i < sc_array_size(watches); ++i) { 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 (fw->wd == wd) {
if (index) { if (index) {
*index = i; *index = i;
@@ -78,10 +78,10 @@ hiFileWatch *file_watch_find_by_wd(struct hiFileWatcherContext *ctx, int wd,
return NULL; 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) { const char *path, size_t *index) {
for (size_t i = 0; i < sc_array_size(&ctx->watches); i++) { 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 (strcmp(watch->path, path) == 0) {
if (index) { if (index) {
*index = i; *index = i;
@@ -110,22 +110,22 @@ static char *get_parent_folder(const char path[static 1]) {
return parent; return parent;
} }
HiloadResult file_watch_add(hiFileWatcherContext *ctx, u32 mask, HiResult file_watch_add(FileWatcherContext *ctx, u32 mask,
const char *path) { const char *path) {
if (!ctx || ctx->fd == -1) { if (!ctx || ctx->fd == -1) {
sc_log_error("Invalid inotify context\n"); log_error("Invalid inotify context\n");
return HILOAD_FAIL; return HI_FAIL;
} }
struct WatchMaskParams params = inode_watch_masks_create(mask); 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) { if (!watch) {
int wd = inotify_add_watch(ctx->fd, path, params.file_mask); int wd = inotify_add_watch(ctx->fd, path, params.file_mask);
if (wd == -1) { if (wd == -1) {
sc_log_error("Couldn't watch: %s: %s\n", path, strerror(errno)); log_error("Couldn't watch: %s: %s\n", path, strerror(errno));
return HILOAD_FAIL; 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); sc_array_add(&ctx->watches, wp);
watch = &sc_array_last(&ctx->watches); watch = &sc_array_last(&ctx->watches);
} else { } else {
@@ -134,11 +134,11 @@ HiloadResult file_watch_add(hiFileWatcherContext *ctx, u32 mask,
if (!has_mask(HI_FILE_PARENT, mask)) { if (!has_mask(HI_FILE_PARENT, mask)) {
char *parent_name = get_parent_folder(path); 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) { if (!parent_watch) {
// parent not yet watched // parent not yet watched
int wd = inotify_add_watch(ctx->fd, parent_name, params.parent_mask); 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_init(&wp.files);
sc_array_add(&wp.files, strdup(watch->path)); sc_array_add(&wp.files, strdup(watch->path));
sc_array_add(&ctx->watches, wp); 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; 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) { 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); char *parent = get_parent_folder(path);
if (parent) { if (parent) {
hiFileWatch *pw = file_watch_find_by_path(ctx, parent, NULL); FileWatch *pw = file_watch_find_by_path(ctx, parent, NULL);
if (pw) { if (pw) {
for (size_t i = 0; i < sc_array_size(&pw->files); i++) { for (size_t i = 0; i < sc_array_size(&pw->files); i++) {
const char *fn = sc_array_at(&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); file_watch_destroy(ctx->fd, watch);
sc_array_del(&ctx->watches, i); 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_ #define FILEWATCH_H_
#include "array/array.h" #include "array/array.h"
#include "filewatch_context.h"
#include "types.h" #include "types.h"
struct hiFileWatcherContext; typedef struct FileWatcherContext FileWatcherContext;
struct hiFileWatch; 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); 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); 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); const char *path);
HiloadResult file_watch_remove(struct hiFileWatcherContext *ctx, HiResult file_watch_remove(FileWatcherContext *ctx,
const char *path); const char *path);
void file_watch_destroy_watches(struct hiFileWatcherContext *ctx); void file_watch_destroy_watches(FileWatcherContext *ctx);
#endif // FILEWATCH_H_ #endif // FILEWATCH_H_

View File

@@ -2,34 +2,47 @@
#define FILEWATCH_CONTEXT_H_ #define FILEWATCH_CONTEXT_H_
#include "array/array.h" #include "array/array.h"
#include "filewatcher/filewatch.h"
#include "types.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 * 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. * 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 { typedef struct WatchParams {
const char *path; // Params own their path const char *path; // Owning
u32 mask; u32 mask;
} hiWatchParams; } WatchParams;
sc_array_def(hiWatchParams, fwparam);
typedef struct { sc_array_def(WatchParams, fwparam);
int wd; // Watch descriptor 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 u32 mask; // watch mask used
const char *path; // inotify watch path, owning if it's a parent watcher const char *path; // Owning
struct sc_array_str VectorStr files;
files; // param paths associated with that path. Pointers to paths params. } FileWatch;
} hiFileWatch;
sc_array_def(hiFileWatch, fwatch);
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; int fd;
struct sc_array_fwparam params; VectorWatchParams params;
struct sc_array_fwatch watches; VectorFileWatch watches;
} hiFileWatcherContext; } FileWatcherContext;
#endif // FILEWATCH_CONTEXT_H_ #endif // FILEWATCH_CONTEXT_H_

View File

@@ -3,17 +3,17 @@
typedef enum { typedef enum {
HI_FILE_NONE = 0, // Used to signal invalid event HI_FILE_NONE = 0, // Used to signal invalid event
HI_FILE_MODIFY = 1 << 1, HI_FILE_MODIFY = (1 << 1),
HI_FILE_CREATE = 1 << 2, HI_FILE_CREATE = (1 << 2),
HI_FILE_DELETE = 1 << 3, HI_FILE_DELETE = (1 << 3),
HI_FILE_MOVE = 1 << 4, HI_FILE_MOVE = (1 << 4),
HI_FILE_CHANGE = HI_FILE_CHANGE =
(HI_FILE_MODIFY | HI_FILE_CREATE | HI_FILE_DELETE | HI_FILE_MOVE), (HI_FILE_MODIFY | HI_FILE_CREATE | HI_FILE_DELETE | HI_FILE_MOVE),
HI_FILE_ALL_EVENTS = (HI_FILE_CHANGE), HI_FILE_ALL_EVENTS = (HI_FILE_CHANGE),
HI_FILE_PARENT = 1 << 31, HI_FILE_PARENT = (1 << 30),
} HiFileWatchType; } 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) { switch (type) {
case HI_FILE_NONE: case HI_FILE_NONE:
return "HI_FILE_NONE"; return "HI_FILE_NONE";

View File

@@ -19,35 +19,36 @@
#include "logger/logger.h" #include "logger/logger.h"
#include "types.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; thrd_t thread;
mtx_t mutex; mtx_t mutex;
cnd_t cond; cnd_t cond;
int running; int running;
struct hiFileWatcherContext context; FileWatcherContext context;
struct sc_array_fwevent events; VectorFileEvent events;
} hiFileWatcher; } FileWatcher;
/* /*
* Watch Params * Watch Params
*/ */
static inline hiWatchParams watch_params_create(const char *path, u32 mask) { static inline WatchParams watch_params_create(const char *path, u32 mask) {
return (hiWatchParams){.path = strdup(path), .mask = 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); free((char *)params->path);
} }
static hiWatchParams *watch_params_find_by_path(const char *path, static WatchParams *watch_params_find_by_path(const char *path,
hiFileWatcherContext *ctx, FileWatcherContext *ctx,
size_t *index) { size_t *index) {
const struct sc_array_fwparam *params = &ctx->params; const struct sc_array_fwparam *params = &ctx->params;
for (size_t i = 0; i < sc_array_size(params); ++i) { 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 (strcmp(path, param->path) == 0) {
if (index) if (index)
*index = i; *index = i;
@@ -61,17 +62,17 @@ static hiWatchParams *watch_params_find_by_path(const char *path,
* File Events * File Events
*/ */
#define NULL_EVENT (hiFileEvent){0}; #define NULL_EVENT (FileEvent){0};
static hiFileEvent file_event_create(const struct inotify_event *inevent, static FileEvent file_event_create(const struct inotify_event *inevent,
hiFileWatcherContext *ctx) { FileWatcherContext *ctx) {
hiFileEvent event = {0}; FileEvent event = {0};
if (!inevent) { if (!inevent) {
return event; 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)) { if (has_mask(inevent->mask, IN_IGNORED)) {
sc_log_debug("IN_IGNORED received on %s\n", fw->path); 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) { if (strcmp(watched_file, filename) == 0) {
// check if event mask matches the watcher mask // check if event mask matches the watcher mask
hiWatchParams *params = WatchParams *params =
watch_params_find_by_path(watched_file, ctx, NULL); watch_params_find_by_path(watched_file, ctx, NULL);
if (!params) { if (!params) {
return NULL_EVENT; return NULL_EVENT;
@@ -139,10 +140,10 @@ static hiFileEvent file_event_create(const struct inotify_event *inevent,
return NULL_EVENT; return NULL_EVENT;
} }
hiFileEvent hi_file_event_pop(hiFileWatcher *fw) { FileEvent hi_file_event_pop(FileWatcher *fw) {
mtx_lock(&fw->mutex); mtx_lock(&fw->mutex);
hiFileEvent e = NULL_EVENT; FileEvent e = NULL_EVENT;
if (sc_array_size(&fw->events) > 0) { if (sc_array_size(&fw->events) > 0) {
e = sc_array_last(&fw->events); e = sc_array_last(&fw->events);
sc_array_del_last(&fw->events); sc_array_del_last(&fw->events);
@@ -156,19 +157,19 @@ hiFileEvent hi_file_event_pop(hiFileWatcher *fw) {
* File Watcher * 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); ctx->fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
if (ctx->fd == -1) { if (ctx->fd == -1) {
return HILOAD_FAIL; return HI_FAIL;
} }
sc_array_init(&ctx->watches); sc_array_init(&ctx->watches);
sc_array_init(&ctx->params); 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) { if (ctx) {
file_watch_destroy_watches(ctx); file_watch_destroy_watches(ctx);
} }
@@ -177,11 +178,11 @@ static void file_watcher_ctx_destroy(hiFileWatcherContext *ctx) {
// Declare the thread func // Declare the thread func
int file_watcher_watch(void *arg); int file_watcher_watch(void *arg);
hiFileWatcher *hi_file_watcher_create() { FileWatcher *hi_file_watcher_create() {
// Allocate context // Allocate context
hiFileWatcher *fw = malloc(sizeof(hiFileWatcher)); FileWatcher *fw = malloc(sizeof(FileWatcher));
memset(fw, 0, sizeof(hiFileWatcher)); memset(fw, 0, sizeof(FileWatcher));
if (fw) { if (fw) {
if (!HIOK(file_watcher_ctx_init(&fw->context))) { if (!HIOK(file_watcher_ctx_init(&fw->context))) {
@@ -203,26 +204,25 @@ hiFileWatcher *hi_file_watcher_create() {
return NULL; return NULL;
} }
HiloadResult hi_file_watcher_add(struct hiFileWatcher *fw, const char *filename, HiResult hi_file_watcher_add(FileWatcher *fw, const char *filename, u32 flags) {
u32 flags) {
if (!fw) { if (!fw) {
sc_log_error("Attempted to add file watcher for '%s' with null context\n", sc_log_error("Attempted to add file watcher for '%s' with null context\n",
filename); filename);
return HILOAD_FAIL; return HI_FAIL;
} }
mtx_lock(&fw->mutex); mtx_lock(&fw->mutex);
if (!HIOK(file_watch_add(&fw->context, flags, filename))) { if (!HIOK(file_watch_add(&fw->context, flags, filename))) {
mtx_unlock(&fw->mutex); mtx_unlock(&fw->mutex);
return HILOAD_FAIL; return HI_FAIL;
} }
{ {
// Add watch param as well // Add watch param as well
hiWatchParams *params = WatchParams *params =
watch_params_find_by_path(filename, &fw->context, NULL); watch_params_find_by_path(filename, &fw->context, NULL);
if (!params) { if (!params) {
hiWatchParams params = watch_params_create(filename, flags); WatchParams params = watch_params_create(filename, flags);
sc_array_add(&fw->context.params, params); sc_array_add(&fw->context.params, params);
} else { } else {
params->mask |= flags; params->mask |= flags;
@@ -230,42 +230,40 @@ HiloadResult hi_file_watcher_add(struct hiFileWatcher *fw, const char *filename,
} }
mtx_unlock(&fw->mutex); mtx_unlock(&fw->mutex);
return HILOAD_OK; return HI_OK;
} }
HiloadResult hi_file_watcher_remove(struct hiFileWatcher *fw, HiResult hi_file_watcher_remove(FileWatcher *fw, const char *filename) {
const char *filename) {
if (!fw) { if (!fw) {
return HILOAD_FAIL; return HI_FAIL;
} }
mtx_lock(&fw->mutex); mtx_lock(&fw->mutex);
if (!HIOK(file_watch_remove(&fw->context, filename))) { if (!HIOK(file_watch_remove(&fw->context, filename))) {
mtx_unlock(&fw->mutex); mtx_unlock(&fw->mutex);
return HILOAD_FAIL; return HI_FAIL;
} }
{ {
// remove watchparam as well // remove watchparam as well
size_t i = 0; size_t i = 0;
hiWatchParams *params = WatchParams *params = watch_params_find_by_path(filename, &fw->context, &i);
watch_params_find_by_path(filename, &fw->context, &i);
watch_params_destroy(params); watch_params_destroy(params);
sc_array_del(&fw->context.params, i); sc_array_del(&fw->context.params, i);
} }
mtx_unlock(&fw->mutex); mtx_unlock(&fw->mutex);
sc_log_info("Removed file: '%s' from watch, filename"); 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) { if (fw && fw->running) {
cnd_signal(&fw->cond); cnd_signal(&fw->cond);
} }
} }
void hi_file_watcher_destroy(hiFileWatcher *fw) { void hi_file_watcher_destroy(FileWatcher *fw) {
if (!fw) if (!fw)
return; return;
@@ -280,7 +278,7 @@ void hi_file_watcher_destroy(hiFileWatcher *fw) {
} }
int file_watcher_watch(void *arg) { int file_watcher_watch(void *arg) {
hiFileWatcher *ctx = (hiFileWatcher *)arg; FileWatcher *ctx = (FileWatcher *)arg;
sc_log_set_thread_name("File Watcher"); sc_log_set_thread_name("File Watcher");
char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); 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) { ptr += sizeof(struct inotify_event) + event->len) {
event = (const struct inotify_event *)ptr; 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) { if (e.type != HI_FILE_NONE) {
sc_array_add(&ctx->events, e); sc_array_add(&ctx->events, e);

View File

@@ -21,32 +21,35 @@
* memory inside the file watcher struct. * memory inside the file watcher struct.
*/ */
typedef 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. // Do not free.
HiFileWatchType type; FileWatchType type;
} hiFileEvent; } FileEvent;
typedef struct FileWatcher FileWatcher;
struct hiFileWatcher;
/** /**
* FileEvents is a thread safe list of events. * FileEvents is a thread safe list of events.
* *
* It is implemented as a stack, so the events will be popped * It is implemented as a stack, so the events will be popped
* in reverse chronological order. * in reverse chronological order.
* */ * */
struct hiFileEvents; typedef struct FileEvents FileEvents;
/** /**
* Create watcher and necessary data to run it. * Create watcher and necessary data to run it.
* *
* Will start the watcher thread immediately. * 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. * Destroy a previously created file watcher context.
* *
* Will join the thread and destroy event stack. * 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. * 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 pathname Absolute path to the file or directory
* @param flags The events that will be watched for * @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); const char *pathname, u32 flags);
/** /**
* Can be used to poke file watcher thread to make sure it empties * Can be used to poke file watcher thread to make sure it empties
* events before doing something, e.g. for shutting it down. * 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 * Pop an event from event stack. Call `hi_file_event_destroy` when done with
* it. * it.
*/ */
hiFileEvent hi_file_event_pop(struct hiFileWatcher *ctx); FileEvent hi_file_event_pop(FileWatcher *ctx);
#endif // HI_FILEWATCHER_H_ #endif // HI_FILEWATCHER_H_

View File

@@ -19,11 +19,21 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.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 { typedef struct {
struct sc_array_memreg memory_regions; VectorMemoryRegion memory_regions;
struct sc_array_str enabled_modules; VectorStr enabled_modules;
struct hiFileWatcher *filewatcher; FileWatcher *filewatcher;
HiModuleArray modules; VectorModuleData modules;
} HiloadContext; } HiloadContext;
static HiloadContext context = {0}; 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); void *handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD);
assert(handle); assert(handle);
HiModuleData module = {0}; ModuleData module = {0};
module.dlhandle = handle; module.dlhandle = handle;
module.address = info->dlpi_addr; 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 // Mark everything but system and virtual modules as patchable
if (module.name[0] == '/') { if (module.name[0] == '/') {
if (!hi_string_starts_with(module.name, ARRLEN(mod_exclude_filter), if (!hi_string_starts_with(module.name, ARRLEN(module_exclude_filter),
mod_exclude_filter)) { module_exclude_filter)) {
module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_PATCHABLE); 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 // Replace shortform with str pointer from module info
sc_array_at(&context.enabled_modules, i) = module.name; sc_array_at(&context.enabled_modules, i) = module.name;
// Add filewatcher
if (!HIOK(hi_file_watcher_add(context.filewatcher, modpath, if (!HIOK(hi_file_watcher_add(context.filewatcher, modpath,
HI_FILE_ALL_EVENTS))) { HI_FILE_ALL_EVENTS))) {
log_error("Failed to set filewatcher for: '%s'\n", modpath); 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()); 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); sc_array_add(modules, module);
return 0; // Continue iteration return 0; // Continue iteration
} }
static void module_infos_free(HiModuleArray *modules) { static void module_infos_free(VectorModuleData *modules) {
if (!modules) if (!modules)
return; 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); sc_array_init(modules);
@@ -116,17 +125,17 @@ HiloadResult gather_module_infos(HiModuleArray *modules) {
if (dl_iterate_phdr(gather_module_data_callback, modules) != 0) { if (dl_iterate_phdr(gather_module_data_callback, modules) != 0) {
// Error occurred in callback // Error occurred in callback
module_infos_free(modules); 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, static ModuleData *get_module_by_path(const char *path,
HiModuleArray *modules) { VectorModuleData *modules) {
for (size_t i = 0; i < sc_array_size(modules); i++) { 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; const char *name = module->name;
if (strcmp(name, path) == 0) { if (strcmp(name, path) == 0) {
return module; 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. * 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) { while (event.type != HI_FILE_NONE) {
log_debug("Event pop: %s %s\n", event.pathname, log_debug("Event pop: %s %s\n", event.pathname,
hi_file_watch_type_to_str(event.type)); 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) { if (!module) {
log_warn("Watched module: %s not found.\n", event.pathname); log_warn("Watched module: %s not found.\n", event.pathname);
} else { } else {
@@ -169,11 +178,11 @@ static const char *find_string_from_array(const char *needle,
return NULL; 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++) { 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 // Operate on dirty modules only
if (hi_modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) { 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, if (!HIOK(moduler_reload(&context->modules, module,
&context->memory_regions))) { &context->memory_regions))) {
ret = HILOAD_FAIL; ret = HI_FAIL;
log_error("Failed loading: %s\n", module->name); log_error("Failed loading: %s\n", module->name);
} }
} }
@@ -195,14 +204,9 @@ static HiloadResult reload_dirty_modules(HiloadContext *context) {
return ret; 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) { if (log_init() != 0) {
fprintf(stderr, "Failed to init logger.\n"); 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); 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"); log_error("Could not populate program memory maps.\n");
return HILOAD_FAIL; return HI_FAIL;
} }
HiloadResult re = gather_module_infos(&context.modules); HiResult re = gather_module_infos(&context.modules);
if (re != HILOAD_OK) { if (re != HI_OK) {
log_error("Failed to gather module infos.\n"); log_error("Failed to gather module infos.\n");
return 1; return 1;
} }
@@ -241,3 +245,10 @@ void hi_deinit() {
log_term(); log_term();
memset(&context, 0, sizeof(context)); 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; 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) { size_t *index) {
for (size_t i = 0; i < sc_array_size(regions); i++) { for (size_t i = 0; i < sc_array_size(regions); i++) {
uptr start = regions->elems[i].region_start; uptr start = regions->elems[i].region_start;
// we assume a sorted region by start address, so we can do a quick discard // we assume a sorted region by start address, so we can do a quick discard
// here. very useful for relative vs absolute address checks // here. very useful for relative vs absolute address checks
if (ptr < start) if (ptr < start)
return HILOAD_FAIL; return HI_FAIL;
uptr end = regions->elems[i].region_end; uptr end = regions->elems[i].region_end;
if (ptr_in_range(ptr, start, end)) { if (ptr_in_range(ptr, start, end)) {
if (index) if (index)
*index = i; *index = i;
sc_log_debug("Pointer match (%p) found in index: %u, range: %p - %p\n", sc_log_debug("Pointer match (%p) found in index: %u, range: %p - %p\n",
ptr, i, start, end); 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); memory_clear_memregs(regions);
char *maps_str = hi_file_to_str_dyn("/proc/self/maps"); char *maps_str = hi_file_to_str_dyn("/proc/self/maps");
if (!maps_str) if (!maps_str)
return HILOAD_FAIL; return HI_FAIL;
log_debugv("/proc/self/maps:\n%s", maps_str); 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 // clang-format off
// Format example from the file: // 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 // 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_start,
&reg.region_end, &reg.region_end,
perm_str, perm_str,
@@ -63,11 +63,11 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) {
&reg.inode, &reg.inode,
pathname); pathname);
if (perm_str[0] == 'r') reg.permission |= HI_MEMORY_READ; if (perm_str[0] == 'r') reg.permissions |= HI_MEMORY_READ;
if (perm_str[1] == 'w') reg.permission |= HI_MEMORY_WRITE; if (perm_str[1] == 'w') reg.permissions |= HI_MEMORY_WRITE;
if (perm_str[2] == 'x') reg.permission |= HI_MEMORY_EXECUTE; if (perm_str[2] == 'x') reg.permissions |= HI_MEMORY_EXECUTE;
if (perm_str[3] == 'p') reg.permission |= HI_MEMORY_PRIVATE; if (perm_str[3] == 'p') reg.permissions |= HI_MEMORY_PRIVATE;
if (perm_str[3] == 's') reg.permission |= HI_MEMORY_SHARED; if (perm_str[3] == 's') reg.permissions |= HI_MEMORY_SHARED;
// clang-format on // clang-format on
// pathname could be empty, so we check for it // 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); free(maps_str);
return HILOAD_OK; return HI_OK;
} }
MemoryRegionSpan MemoryRegionSpan

View File

@@ -20,32 +20,33 @@ typedef struct {
} MemoryRegionSpan; } MemoryRegionSpan;
typedef struct { typedef struct {
const char *pathname;
uptr region_start; uptr region_start;
uptr region_end; uptr region_end;
ptrdiff offset; ptrdiff offset;
u64 inode; u64 inode;
const char *pathname; u32 permissions; // enum MemoryPermissions
u32 permission; // enum MemoryPermissions
} MemoryRegion; } MemoryRegion;
sc_array_def(MemoryRegion, memreg); sc_array_def(MemoryRegion, memreg);
typedef struct sc_array_memreg VectorMemoryRegion;
// Free memory and init to zero // 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 // 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 // Free child memory
void memory_free_memreg(MemoryRegion *reg); void memory_free_memreg(MemoryRegion *reg);
/* A pointer that can be used to place the memory regions into. Clears regions /* A pointer that can be used to place the memory regions into. Clears regions
* before use, but uses the same buffer. */ * 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 */ /* Return index the pointer is found in */
HiloadResult memory_find_pointer(uptr ptr, HiResult memory_find_pointer(uptr ptr,
struct sc_array_memreg *const regions, VectorMemoryRegion *const regions,
size_t *index); 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]); const char module_name[static 1]);
#endif // MEMORY_H_ #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) { if (phdr.p_type == PT_DYNAMIC) {
dyn_addr = module_base + phdr.p_vaddr; dyn_addr = (void*)((uptr)module_base + phdr.p_vaddr);
break; 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)); log_debug("segment type: %s\n", hi_elf_segtostr(p->p_type));
size_t segment_size = p->p_memsz; size_t segment_size = p->p_memsz;
void *segment_start = address + p->p_vaddr; void *segment_start = (void*)((uptr)address + p->p_vaddr);
void *segment_end = address + p->p_vaddr + segment_size; void *segment_end = (void*)((uptr)address + p->p_vaddr + segment_size);
void *strtab = 0; void *strtab = 0;
void *symtab = 0; void *symtab = 0;

View File

@@ -10,11 +10,8 @@
#include "types.h" #include "types.h"
#include <dlfcn.h> #include <dlfcn.h>
#include <elf.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <gelf.h>
#include <libelf.h>
#include <link.h> #include <link.h>
#include <stdalign.h> #include <stdalign.h>
#include <stdbool.h> #include <stdbool.h>
@@ -36,23 +33,23 @@ static void *adjust_if_relative(void *ptr, void *module_base) {
return (void *)p; 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, const char *module_name,
void *module_base) { void *module_base) {
sc_array_clear(symbols); sc_array_clear(symbols);
HiloadResult ret = HILOAD_FAIL; HiResult ret = HI_FAIL;
int patchfd = open(module_name, O_RDONLY); int patchfd = open(module_name, O_RDONLY);
if (patchfd == -1) { if (patchfd == -1) {
log_error("Failed to open %s: %s\n", module_name, strerror(errno)); 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) { if (elf_version(EV_CURRENT) == EV_NONE) {
log_error("Failed to initialize libelf\n"); log_error("Failed to initialize libelf\n");
close(patchfd); close(patchfd);
return HILOAD_FAIL; return HI_FAIL;
} }
Elf *elf = elf_begin(patchfd, ELF_C_READ, NULL); 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: cleanup:
elf_end(elf); elf_end(elf);
@@ -169,7 +166,7 @@ cleanup:
return ret; return ret;
} }
static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols, static HiResult moduler_apply_module_patch(HiSymbols *psymbols,
MemoryRegionSpan module_memory) { MemoryRegionSpan module_memory) {
void *module_base = (void *)module_memory.region_start; 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(Rela) *rela = NULL;
ElfW(Sym) *symtab = NULL; ElfW(Sym) *symtab = NULL;
char *strtab = NULL; char *strtab = NULL;
size_t pltsz = 0;
size_t relasz = 0; size_t relasz = 0;
size_t plt_type = 0;
Elf *elf = NULL; Elf *elf = NULL;
ElfW(Dyn) *dyn_sct = ElfW(Dyn) *dyn_sct =
@@ -201,12 +196,6 @@ static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols,
case DT_PLTGOT: case DT_PLTGOT:
plt = (ElfW(Rela) *)d->d_un.d_ptr; plt = (ElfW(Rela) *)d->d_un.d_ptr;
break; 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: case DT_JMPREL:
jmprel = (ElfW(Rela) *)d->d_un.d_ptr; jmprel = (ElfW(Rela) *)d->d_un.d_ptr;
break; break;
@@ -228,7 +217,7 @@ static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols,
if ((!rela && !jmprel) || !symtab || !strtab || relasz == 0) { if ((!rela && !jmprel) || !symtab || !strtab || relasz == 0) {
log_error("Missing required dynamic information\n"); log_error("Missing required dynamic information\n");
elf_end(elf); elf_end(elf);
return HILOAD_FAIL; return HI_FAIL;
} }
int found_count = 0; int found_count = 0;
@@ -272,10 +261,10 @@ static HiloadResult moduler_apply_module_patch(HiSymbols *psymbols,
} }
elf_end(elf); 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); time_t now = time(NULL);
struct tm *t = localtime(&now); struct tm *t = localtime(&now);
@@ -305,7 +294,7 @@ PatchData moduler_create_patch(HiModuleData *module) {
return data; return data;
} }
HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
struct sc_array_memreg *memregs) { struct sc_array_memreg *memregs) {
// Return OK because this isn't an error case. We just don't do it yet // 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. // executables.
if (hi_modinfo_has(module->info, HI_MODULE_STATE_EXEC)) { if (hi_modinfo_has(module->info, HI_MODULE_STATE_EXEC)) {
module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
return HILOAD_OK; return HI_OK;
} }
PatchData patch = moduler_create_patch(module); PatchData patch = moduler_create_patch(module);
if (!patch.filename) { if (!patch.filename) {
log_error("Couldn't create patch for %s\n", module->name); log_error("Couldn't create patch for %s\n", module->name);
return HILOAD_FAIL; return HI_FAIL;
} }
// Load patch // Load patch
@@ -329,7 +318,7 @@ HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module,
if (!new_handle) { if (!new_handle) {
log_error("Couldn't load: %s\n", dlerror()); log_error("Couldn't load: %s\n", dlerror());
module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY); module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
return HILOAD_FAIL; return HI_FAIL;
} }
patch.dlhandle = new_handle; patch.dlhandle = new_handle;
@@ -342,25 +331,26 @@ HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module,
HiSymbols patch_symbols; HiSymbols patch_symbols;
symbol_init_symbols(&patch_symbols); symbol_init_symbols(&patch_symbols);
HiloadResult ret = HiResult ret =
gather_patchable_symbols(&patch_symbols, patch.filename, patch_base); gather_patchable_symbols(&patch_symbols, patch.filename, patch_base);
if (!HIOK(ret)) { if (!HIOK(ret)) {
log_error("Failed to gather symbols for %s\n", patch.filename); 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) { 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)) if (!hi_modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE))
continue; continue;
log_debug("Patching: %s\n", mod.name);
MemoryRegionSpan module_memory = memory_get_module_span(memregs, mod.name); MemoryRegionSpan module_memory = memory_get_module_span(memregs, mod.name);
moduler_apply_module_patch(&patch_symbols, module_memory); 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 (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; HiSymbols module_symbols;
symbol_init_symbols(&module_symbols); symbol_init_symbols(&module_symbols);
@@ -399,5 +389,5 @@ HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module,
dlclose(module->dlhandle); dlclose(module->dlhandle);
module->dlhandle = patch.dlhandle; module->dlhandle = patch.dlhandle;
return HILOAD_OK; return HI_OK;
} }

View File

@@ -8,15 +8,12 @@
struct HiloadContext; struct HiloadContext;
static const char *mod_exclude_filter[] = {
"/usr/", "/lib/", "/lib64/", "/bin/", "/opt/",
};
typedef enum { 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_PATCHABLE = (1 << 6), // non system module we will modify
HI_MODULE_STATE_EXEC = (1 << 7), // denote the current executable HI_MODULE_STATE_EXEC = (1 << 7), // denote the current executable
} HiModuleFlags; } ModuleFlags;
typedef u8 ModuleInfo; typedef u8 ModuleInfo;
typedef struct { typedef struct {
@@ -24,27 +21,26 @@ typedef struct {
void *dlhandle; void *dlhandle;
uptr address; uptr address;
ModuleInfo info; ModuleInfo info;
} HiModuleData; } ModuleData;
sc_array_def(ModuleData, module);
typedef struct sc_array_module VectorModuleData;
sc_array_def(HiModuleData, module); static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, ModuleFlags flag) {
typedef struct sc_array_module HiModuleArray;
static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, HiModuleFlags flag) {
return flags | 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; 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; return (flags & flag) != 0;
} }
#define HI_MODINFO_SET(info, flag) ((info) |= flag) #define HI_MODINFO_SET(info, flag) ((info) |= flag)
#define HI_MODINFO_CLEAR(info, flag) ((info) &= ~flag) #define HI_MODINFO_CLEAR(info, flag) ((info) &= ~flag)
HiloadResult moduler_reload(HiModuleArray *modules, HiModuleData *module, HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
struct sc_array_memreg *memregs); VectorMemoryRegion *memregs);
#endif // MODULER_H_ #endif // MODULER_H_

View File

@@ -5,7 +5,6 @@
#include <string.h> #include <string.h>
HiSymbol *symbol_find(HiSymbols *symbols, HiSymbol *symbol) { HiSymbol *symbol_find(HiSymbols *symbols, HiSymbol *symbol) {
size_t namelen = strlen(symbol->name);
for (size_t i=0; i < sc_array_size(symbols); ++i) { for (size_t i=0; i < sc_array_size(symbols); ++i) {
HiSymbol *s = &sc_array_at(symbols, i); HiSymbol *s = &sc_array_at(symbols, i);
if (strcmp(s->name, symbol->name) == 0) { if (strcmp(s->name, symbol->name) == 0) {

View File

@@ -1,6 +1,8 @@
#ifndef TYPES_H_ #ifndef TYPES_H_
#define TYPES_H_ #define TYPES_H_
#include "hitypes.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -21,7 +23,4 @@ typedef ptrdiff_t ptrdiff;
typedef uint8_t bool8; typedef uint8_t bool8;
typedef uint32_t bool32; typedef uint32_t bool32;
typedef enum { HILOAD_FAIL = 0, HILOAD_OK } HiloadResult;
#endif // TYPES_H_ #endif // TYPES_H_

View File

@@ -24,7 +24,7 @@ int main(int argc, char *argv[]) {
printf("otherValue: %d\n", minimal_lib::otherValue++); printf("otherValue: %d\n", minimal_lib::otherValue++);
std::this_thread::sleep_for(std::chrono::seconds(1)); 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"); fprintf(stderr, "Failed to load modules\n");
} }
} }