Type and naming cleanup
Do not use Hi prefic for things that shouldn't be visible to outside code
This commit is contained in:
@@ -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
9
include/hitypes.h
Normal 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_
|
||||||
@@ -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_
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
77
src/hiload.c
77
src/hiload.c
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
26
src/memory.c
26
src/memory.c
@@ -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",
|
||||||
®.region_start,
|
®.region_start,
|
||||||
®.region_end,
|
®.region_end,
|
||||||
perm_str,
|
perm_str,
|
||||||
@@ -63,11 +63,11 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) {
|
|||||||
®.inode,
|
®.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
|
||||||
|
|||||||
17
src/memory.h
17
src/memory.h
@@ -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_
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user