Remove unnecessarily stored data

This commit is contained in:
2025-05-04 02:02:45 +03:00
parent 487da24e65
commit e86dd4781c
12 changed files with 232 additions and 193 deletions

View File

@@ -1,3 +1,11 @@
/**
* Hiload is an Elf hotreloader that patches C and C++ code live while
* developing, significantly tightening the traditional feedback loop.
*
* Currently not supported:
* - modifying modules loaded at runtime
*/
#ifndef HILOAD_H_
#define HILOAD_H_
@@ -24,7 +32,7 @@ extern "C" {
int hi_init(size_t n, const char **enabled_modules);
/**
* Frees allocated memory. Call when hiload is no longer used.
* Call when hiload is no longer needed.
*/
void hi_deinit(void);

View File

@@ -1,7 +1,7 @@
#include "files.h"
#include "logger.h"
#include "histring.h"
#include "logger.h"
#include "types.h"
#include <errno.h>
@@ -13,7 +13,7 @@
char *file_to_str_dyn(const char *filename) {
char *s = hi_str_from_file(filename, 0, 0);
char *s = string_from_file(filename, 0, 0);
if (!s) {
sc_log_error("Failed to read file: %s\n", filename);
return 0;
@@ -28,23 +28,6 @@ static FileType file_interpret_as_type(const char *path) {
return as_dir ? HI_FILE_TYPE_DIR : HI_FILE_TYPE_FILE;
}
const char *file_name_from_path(const char *path) {
const char *filename = path;
// Find the last directory separator
const char *last_slash = strrchr(path, '/');
const char *last_backslash = strrchr(path, '\\');
// Determine which separator was found last (if any)
if (last_slash && (!last_backslash || last_slash > last_backslash)) {
filename = last_slash + 1;
} else if (last_backslash) {
filename = last_backslash + 1;
}
return filename;
}
HiResult file_copy(const char *srcname, const char *destination) {
HiResult ret = HI_FAIL;
@@ -61,8 +44,7 @@ HiResult file_copy(const char *srcname, const char *destination) {
FileType dst_type = file_interpret_as_type(destination);
if (dst_type == HI_FILE_TYPE_DIR) {
hi_str_concat_buf(sizeof(buf), buf, destination,
file_name_from_path(srcname));
string_concat_buf(sizeof(buf), buf, destination, strpath_filename(srcname));
dstname = buf;
}
@@ -89,8 +71,10 @@ HiResult file_copy(const char *srcname, const char *destination) {
ret = HI_OK;
cleanup:
if (src) fclose(src);
if (dst) fclose(dst);
if (src)
fclose(src);
if (dst)
fclose(dst);
return ret;
}
@@ -136,4 +120,3 @@ FileType file_type(const char *path) {
return HI_FILE_TYPE_NONE;
}

View File

@@ -35,5 +35,3 @@ char *file_to_str_dyn(const char *filename);
HiResult file_copy(const char *filename, const char *dest);
FileType file_type(const char *path);
const char *file_name_from_path(const char *path);

View File

@@ -13,7 +13,7 @@ typedef enum {
HI_FILE_PARENT = (1 << 30),
} FileWatchType;
static inline const char *hi_file_watch_type_to_str(FileWatchType type) {
static inline const char *filewatch_type_to_str(FileWatchType type) {
switch (type) {
case HI_FILE_NONE:
return "HI_FILE_NONE";
@@ -26,11 +26,11 @@ static inline const char *hi_file_watch_type_to_str(FileWatchType type) {
case HI_FILE_MOVE:
return "HI_FILE_MOVE";
default:
return "Unknown HI_FILE_TYPE";
return "Unknown HI_FILE_TYPE";
// clang-format on
}
return "Unknown HI_FILE_TYPE";
}
#endif // FILEWATCH_TYPE_H_

View File

@@ -141,7 +141,7 @@ static FileEvent file_event_create(const struct inotify_event *inevent,
return NULL_EVENT;
}
FileEvent file_event_pop(FileWatcher *fw) {
FileEvent filewatcher_event_pop(FileWatcher *fw) {
mtx_lock(&fw->mutex);
FileEvent e = NULL_EVENT;
@@ -179,7 +179,7 @@ static void file_watcher_ctx_destroy(FileWatcherContext *ctx) {
// Declare the thread func
int file_watcher_watch(void *arg);
FileWatcher *file_watcher_create() {
FileWatcher *filewatcher_create() {
// Allocate context
FileWatcher *fw = malloc(sizeof(FileWatcher));
@@ -205,7 +205,7 @@ FileWatcher *file_watcher_create() {
return NULL;
}
HiResult file_watcher_add(FileWatcher *fw, const char *filename, u32 flags) {
HiResult filewatcher_add(FileWatcher *fw, const char *filename, u32 flags) {
if (!fw) {
sc_log_error("Attempted to add file watcher for '%s' with null context\n",
filename);
@@ -264,7 +264,7 @@ void file_watcher_notify(FileWatcher *fw) {
}
}
void file_watcher_destroy(FileWatcher *fw) {
void filewatcher_destroy(FileWatcher *fw) {
if (!fw)
return;
@@ -275,6 +275,10 @@ void file_watcher_destroy(FileWatcher *fw) {
}
file_watcher_ctx_destroy(&fw->context);
mtx_destroy(&fw->mutex);
cnd_destroy(&fw->cond);
free(fw);
}
@@ -309,7 +313,7 @@ int file_watcher_watch(void *arg) {
if (event->len) {
sc_log_debug("Event created: queue-size: %u, %s %s\n",
vector_size(&ctx->events), e.pathname,
hi_file_watch_type_to_str(e.type));
filewatch_type_to_str(e.type));
}
}
}

View File

@@ -1,16 +1,9 @@
#ifndef HI_FILEWATCHER_H_
#define HI_FILEWATCHER_H_
#include "filewatch_context.h"
#include "filewatch_type.h"
#include "types.h"
/**
* File event watcher using inotify.
*
* Create a FileWatcher and give it files to monitor. FileWatcher creates a thread
* for listening system notifications. It then creates events for each filechange
* for those files under scrutiny.
* Create a FileWatcher and give it files to monitor. FileWatcher creates a
* thread for listening system notifications. It then creates events for each
* filechange for those files under scrutiny.
*
* Paths are stored as absolute, and this doesn't handle symlinks in watched
* files. So if you have e.g. a symlink 'my-proj' to your project folder in
@@ -18,6 +11,12 @@
* not interpreted as equal.
*/
#pragma once
#include "filewatch_context.h"
#include "filewatch_type.h"
#include "types.h"
/**
* File Event produced by FileWatcher.
*
@@ -47,15 +46,15 @@ typedef struct FileEvents FileEvents;
*
* Starts a new watcher thread immediately.
*/
FileWatcher *file_watcher_create(void);
FileWatcher *filewatcher_create(void);
/**
* Destroy a previously created file watcher.
* Destroy a previously created file watcher, cleaning resources.
*
* Will join the thread and destroy event stack. Any FileEvent still in
* existence will contain invalid data after this call.
*/
void file_watcher_destroy(FileWatcher *fw);
void filewatcher_destroy(FileWatcher *fw);
/**
* Start watching for events on a file.
@@ -64,11 +63,9 @@ void file_watcher_destroy(FileWatcher *fw);
* @param pathname Absolute path to the file or directory
* @param flags The event mask for the events to watch for
*/
HiResult file_watcher_add(FileWatcher *fw, const char *pathname, u32 flags);
HiResult filewatcher_add(FileWatcher *fw, const char *pathname, u32 flags);
/**
* Pop an event from event stack.
*/
FileEvent file_event_pop(FileWatcher *ctx);
#endif // HI_FILEWATCHER_H_
FileEvent filewatcher_event_pop(FileWatcher *ctx);

View File

@@ -1,4 +1,4 @@
#include "hiload/hiload.h"
#include "hiload.h"
#include "common.h"
#include "filewatcher/filewatcher.h"
@@ -23,13 +23,11 @@
* assumption is that libraries from system folders won't be actively developed
* on, nor do they contain references to the modifiable code.
*/
static const char *module_exclude_filter[] = {
static const char *system_folders[] = {
"/usr/", "/lib/", "/lib64/", "/bin/", "/opt/",
};
typedef struct {
VectorMemoryMap memory_regions;
VectorStr enabled_modules;
FileWatcher *filewatcher;
VectorModuleData modules;
} HiloadContext;
@@ -37,11 +35,11 @@ typedef struct {
static HiloadContext context = {0};
// Callback function for dl_iterate_phdr
static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
static int initial_gather_callback(struct dl_phdr_info *info, size_t size,
void *data) {
(void)size;
UNUSED(size);
// '' for executable, fname for rest
// '' for executable, filepath for rest
const char *modname = info->dlpi_name;
log_info("Found: '%s'\n", info->dlpi_name);
@@ -56,7 +54,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
// Mark executable
if (strcmp(modname, "") == 0) {
module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_EXEC);
module.info = modinfo_add(module.info, HI_MODULE_STATE_EXEC);
}
Dl_info dl_info = {0};
@@ -67,35 +65,12 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
const char *modpath = dl_info.dli_fname;
module.name = strdup(modpath);
// Mark everything but system and virtual modules as patchable
if (module.name[0] == '/') {
if (!hi_str_starts_with(module.name, ARRLEN(module_exclude_filter),
module_exclude_filter)) {
module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_PATCHABLE);
}
}
log_debugv("dli_fname: %s\n", dl_info.dli_fname);
log_debugv("dli_sname: %s\n", dl_info.dli_sname);
for (size_t i = 0; i < vector_size(&context.enabled_modules); i++) {
// If module is in the provided modules list
if (hi_path_has_filename(modname,
vector_at(&context.enabled_modules, i))) {
// Replace shortform with str pointer from module info
vector_at(&context.enabled_modules, i) = module.name;
if (!HIOK(file_watcher_add(context.filewatcher, modpath,
HI_FILE_ALL_EVENTS))) {
log_error("Failed to set filewatcher for: '%s'\n", modpath);
} else {
log_info("Watching file: %s\n", modpath);
}
}
}
} else {
// I don't know when this could happen since we're passing the info straight
// from the info struct
module.name = strdup(modname);
log_warn("Couldn't load dlinfo for %s: %s\n", module.name, dlerror());
}
@@ -106,7 +81,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
return 0; // Continue iteration
}
static void module_infos_free(VectorModuleData *modules) {
static void module_data_free(VectorModuleData *modules) {
if (!modules)
return;
@@ -115,22 +90,72 @@ static void module_infos_free(VectorModuleData *modules) {
}
}
static HiResult gather_module_infos(VectorModuleData *modules) {
static HiResult
module_data_initial_gather(VectorModuleData *modules, size_t enabled_count,
const char *enabled_modules[enabled_count]) {
vector_init(modules);
// Iterate over all loaded shared objects
if (dl_iterate_phdr(gather_module_data_callback, modules) != 0) {
if (dl_iterate_phdr(initial_gather_callback, modules) != 0) {
// Error occurred in callback
module_infos_free(modules);
module_data_free(modules);
return HI_FAIL;
}
for (size_t i = 0; i < vector_size(&context.modules); ++i) {
ModuleData *module = &vector_at(&context.modules, i);
// Mark everything but system and virtual modules as patchable
if (module->name[0] == '/') {
// Virtual module(s) don't have the root at start
if (string_starts_with_any(module->name, ARRLEN(system_folders),
system_folders)) {
// Exclude anything from system folders with libraries
continue;
} else if (string_last_token_is(module->name, "libhiload.so", '/')) {
// Exclude ourselves, so we don't accidentally try to override
// ourselves while running ourselves.
continue;
}
module->info = modinfo_add(module->info, HI_MODULE_STATE_PATCHABLE);
}
bool enable = false;
for (size_t i = 0; i < enabled_count; ++i) {
const char *enabled_module = enabled_modules[i];
if (string_is_empty(enabled_module)) {
if (modinfo_has(module->info, HI_MODULE_STATE_EXEC)) {
enable = true;
break;
}
} else {
if (string_last_token_is(module->name, enabled_module, '/')) {
enable = true;
break;
}
}
}
if (enable) {
module->info = modinfo_add(module->info, HI_MODULE_STATE_ENABLED);
// Add filewatcher
if (!HIOK(filewatcher_add(context.filewatcher, module->name,
HI_FILE_ALL_EVENTS))) {
log_error("Failed to set filewatcher for: '%s'\n", module->name);
} else {
log_info("Watching file: %s\n", module->name);
}
}
}
return HI_OK;
}
static ModuleData *get_module_by_path(const char *path,
VectorModuleData *modules) {
static ModuleData *module_get(const char *path,
const VectorModuleData *modules) {
for (size_t i = 0; i < vector_size(modules); i++) {
ModuleData *module = &vector_at(modules, i);
@@ -139,6 +164,7 @@ static ModuleData *get_module_by_path(const char *path,
return module;
}
}
return NULL;
}
@@ -147,35 +173,23 @@ static ModuleData *get_module_by_path(const char *path,
*
* Marks a module dirty if there has been any event.
*/
static void handle_events(FileWatcher *fw, VectorModuleData *modules) {
static void handle_file_events(FileWatcher *fw, VectorModuleData *modules) {
FileEvent event = file_event_pop(fw);
FileEvent event = filewatcher_event_pop(fw);
while (event.type != HI_FILE_NONE) {
log_debug("Event pop: %s %s\n", event.pathname,
hi_file_watch_type_to_str(event.type));
filewatch_type_to_str(event.type));
ModuleData *module = get_module_by_path(event.pathname, modules);
ModuleData *module = module_get(event.pathname, modules);
if (!module) {
log_warn("Watched module: %s not found.\n", event.pathname);
} else {
module->info = hi_modinfo_add(module->info, HI_MODULE_STATE_DIRTY);
module->info = modinfo_add(module->info, HI_MODULE_STATE_DIRTY);
}
event = file_event_pop(context.filewatcher);
event = filewatcher_event_pop(context.filewatcher);
}
}
static const char *find_string_from_array(const char *needle,
const VectorStr *haystack) {
for (size_t i = 0; i < vector_size(haystack); i++) {
if (strcmp(needle, vector_at(haystack, i)) == 0) {
return vector_at(haystack, i);
}
}
return NULL;
}
static HiResult reload_dirty_modules(HiloadContext *context) {
HiResult ret = HI_OK;
@@ -183,16 +197,11 @@ static HiResult reload_dirty_modules(HiloadContext *context) {
ModuleData *module = &vector_at(&context->modules, i);
// Operate on dirty modules only
if (hi_modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) {
if (modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) {
// Operate only if the module is marked as operatable
const char *module_name =
find_string_from_array(module->name, &context->enabled_modules);
if (module_name) {
log_info("Reloading %s...\n", module_name);
if (!HIOK(moduler_reload(&context->modules, module,
&context->memory_regions))) {
if (modinfo_has(module->info, HI_MODULE_STATE_ENABLED)) {
log_info("Reloading %s...\n", module->name);
if (!HIOK(moduler_reload(&context->modules, module))) {
ret = HI_FAIL;
log_error("Failed loading: %s\n", module->name);
}
@@ -205,6 +214,7 @@ static HiResult reload_dirty_modules(HiloadContext *context) {
int hi_init(size_t n, const char **enabled_modules) {
if (log_init() != 0) {
// When there's no logging, only fprintf
fprintf(stderr, "Failed to init logger.\n");
return 1;
}
@@ -212,21 +222,10 @@ int hi_init(size_t n, const char **enabled_modules) {
log_set_thread_name("Main");
// Start the filewatcher
context.filewatcher = file_watcher_create();
context.filewatcher = filewatcher_create();
for (unsigned i = 0; i < n; i++) {
const char *module_name = enabled_modules[i];
log_info("Enabling module: '%s'\n", module_name);
vector_add(&context.enabled_modules, module_name);
}
vector_init(&context.memory_regions);
if (memmaps_from_process(&context.memory_regions) != HI_OK) {
log_error("Could not populate program memory maps.\n");
return HI_FAIL;
}
HiResult re = gather_module_infos(&context.modules);
HiResult re =
module_data_initial_gather(&context.modules, n, enabled_modules);
if (re != HI_OK) {
log_error("Failed to gather module infos.\n");
return 1;
@@ -236,15 +235,15 @@ int hi_init(size_t n, const char **enabled_modules) {
}
void hi_deinit() {
module_infos_free(&context.modules);
file_watcher_destroy(context.filewatcher);
module_data_free(&context.modules);
filewatcher_destroy(context.filewatcher);
log_term();
memset(&context, 0, sizeof(context));
}
HiResult hi_reload() {
handle_events(context.filewatcher, &context.modules);
handle_file_events(context.filewatcher, &context.modules);
reload_dirty_modules(&context);
return HI_OK;
}

View File

@@ -7,7 +7,7 @@
#include <stdlib.h>
#include <string.h>
size_t hi_str_concat_buf(size_t buflen, char buf[buflen], const char *first,
size_t string_concat_buf(size_t buflen, char buf[buflen], const char *first,
const char *second) {
if (!buf)
return 0;
@@ -16,6 +16,7 @@ size_t hi_str_concat_buf(size_t buflen, char buf[buflen], const char *first,
size_t second_len = strlen(second);
if (buf + first_len + second_len > buf + buflen - 1) {
// If combined length of the strings wouldn't fit in the buffer, exit early
return 0;
}
@@ -30,22 +31,7 @@ size_t hi_str_concat_buf(size_t buflen, char buf[buflen], const char *first,
return second_end - buf;
}
int hi_path_has_filename(const char *path, const char *filename) {
const char *compared_filename = path;
const char *basename = strrchr(path, '/');
if (basename)
compared_filename = basename + 1;
if (strcmp(compared_filename, filename) == 0) {
return 1;
}
return 0;
}
char *hi_str_from_file(const char *filename, size_t *nread,
size_t nmax) {
char *string_from_file(const char *filename, size_t *nread, size_t nmax) {
FILE *f = fopen(filename, "r");
if (!f) {
@@ -107,17 +93,61 @@ char *hi_str_from_file(const char *filename, size_t *nread,
return buf;
}
const char *hi_str_starts_with(const char path[static 1], size_t listn,
const char *pathlist[listn]) {
bool string_is_empty(const char s[static 1]) { return s[0] == '\0'; }
if (!pathlist)
return path;
size_t pathlen = strlen(path);
bool string_starts_with(const char s[static 1],
const char startswith[static 1]) {
size_t startswith_len = strlen(startswith);
size_t s_len = strlen(s);
if (startswith_len > s_len)
return false;
size_t len = MIN(strlen(s), strlen(startswith));
bool res = strncmp(s, startswith, len) == 0;
return res;
}
const char *string_starts_with_any(const char s[static 1], size_t listn,
const char *slist[listn]) {
if (!slist)
return s;
size_t pathlen = strlen(s);
for (size_t i = 0; i < listn; ++i) {
size_t len = MIN(strlen(pathlist[i]), pathlen);
if (strncmp(path, pathlist[i], len) == 0) {
return pathlist[i];
size_t len = MIN(strlen(slist[i]), pathlen);
if (strncmp(s, slist[i], len) == 0) {
return slist[i];
}
}
return NULL;
}
const char *string_ends_with_any(const char s[static 1], size_t listn,
const char *slist[listn]) {
if (!slist)
return s;
size_t slen = strlen(s);
for (size_t i = 0; i < listn; ++i) {
size_t len = MIN(strlen(slist[i]), slen);
if (strncmp(s, slist[i], len) == 0) {
return slist[i];
}
}
return NULL;
}
int string_last_token_is(const char *s, const char *ifthis, char delim) {
const char *last_token = s;
const char *basename = strrchr(s, delim);
if (basename)
last_token = basename + 1;
if (strcmp(last_token, ifthis) == 0) {
return 1;
}
return 0;
}
const char *strpath_filename(const char *s) { return strrchr(s, '/'); }

View File

@@ -1,19 +1,21 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
/**
* Concatenate two strings into a buffer.
*
* If resulting string would be longer than @a buflen - 1, @a buf remains unchanged.
* If resulting string would be longer than @a buflen - 1, @a buf remains
* unchanged.
*
* @param bufsize Size of the destination buffer @a buf
* @param buf The destination buffer
* @param first Null terminated character string
* @param second Null terminated character string
*/
size_t hi_str_concat_buf(size_t bufsize, char buf[bufsize],
const char *first, const char *second);
size_t string_concat_buf(size_t bufsize, char buf[bufsize], const char *first,
const char *second);
/**
* Copy file content to a null terminated string, allocating memory while
@@ -31,20 +33,34 @@ size_t hi_str_concat_buf(size_t bufsize, char buf[bufsize],
* @param nmax if not 0, this amount of memory in bytes is read and used as
* initial allocation
*/
char *hi_str_from_file(const char *filename, size_t *nread,
size_t nmax);
char *string_from_file(const char *filename, size_t *nread, size_t nmax);
/**
* Return the first string from @a pathlist that is fully included in @a path.
* Test if null terminated string is empty
*/
const char *hi_str_starts_with(const char path[static 1], size_t listn,
const char *pathlist[listn]);
bool string_is_empty(const char s[static 1]);
/**
* Return the first string from @a slist that @a s starts with.
*/
const char *string_starts_with_any(const char s[static 1], size_t listn,
const char *slist[listn]);
/**
* Return the first string from @a slist that @a s ends with.
*/
const char *string_ends_with_any(const char s[static 1], size_t listn,
const char *slist[listn]);
/**
* Find if @a filename exists at the end of @a path.
*
* ```c
*
* if (string_last_token_is(fullpath, filename, '/')) { ... }
* ````
*
* @return 0 if not found, positive if found
*/
int hi_path_has_filename(const char *path, const char *filename);
int string_last_token_is(const char *s, const char *ifthis, char delim);
const char *strpath_filename(const char *s);

View File

@@ -264,7 +264,7 @@ static HiResult moduler_apply_module_patch(VectorSymbol *psymbols,
return HI_OK;
}
PatchData moduler_create_patch(ModuleData *module) {
static PatchData moduler_create_patch(ModuleData *module) {
time_t now = time(NULL);
struct tm *t = localtime(&now);
@@ -281,7 +281,7 @@ PatchData moduler_create_patch(ModuleData *module) {
char filename[512];
size_t written =
hi_str_concat_buf(sizeof(filename), filename, module->name, file_append);
string_concat_buf(sizeof(filename), filename, module->name, file_append);
if (written == 0) {
log_error("Failed to concat %s and %s\n", module->name, ".patch");
@@ -294,14 +294,13 @@ PatchData moduler_create_patch(ModuleData *module) {
return data;
}
HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
VectorMemoryMap *memmaps) {
HiResult moduler_reload(VectorModuleData *modules, ModuleData *module) {
// Return OK because this isn't an error case. We just don't do it yet
// because we only handle reloading a complete solib. Can't do that with
// executables.
if (hi_modinfo_has(module->info, HI_MODULE_STATE_EXEC)) {
module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
if (modinfo_has(module->info, HI_MODULE_STATE_EXEC)) {
module->info = modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
return HI_OK;
}
@@ -317,18 +316,19 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
void *new_handle = dlopen(patch.filename, RTLD_LAZY);
if (!new_handle) {
log_error("Couldn't load: %s\n", dlerror());
module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
module->info = modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
return HI_FAIL;
}
patch.dlhandle = new_handle;
// refresh cache
if (!HIOK(memmaps_from_process(memmaps))) {
VectorMemoryMap memmaps;
vector_init(&memmaps);
if (!HIOK(memmaps_from_process(&memmaps))) {
log_error("Failed to collect memory information for process\n");
return HI_FAIL;
}
patch.memreg = memmaps_find_by_name(patch.filename, memmaps);
patch.memreg = memmaps_find_by_name(patch.filename, &memmaps);
void *patch_base = (void *)patch.memreg.start;
VectorSymbol patch_symbols;
@@ -344,11 +344,11 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
for (size_t i = 0; i < vector_size(modules); ++i) {
ModuleData mod = vector_at(modules, i);
if (!hi_modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE))
if (!modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE))
continue;
log_debug("Patching: %s\n", mod.name);
MemorySpan module_memory = memmaps_find_by_name(mod.name, memmaps);
MemorySpan module_memory = memmaps_find_by_name(mod.name, &memmaps);
moduler_apply_module_patch(&patch_symbols, module_memory);
if (strncmp(mod.name, patch.filename, strlen(mod.name)) == 0) {
@@ -383,7 +383,7 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
symbol_term(&module_symbols);
}
module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
module->info = modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
}
free((char *)patch.filename);

View File

@@ -8,33 +8,37 @@
struct HiloadContext;
typedef enum {
HI_MODULE_STATE_DIRTY = (1 << 0),
HI_MODULE_STATE_ENABLED = (1 << 0),
HI_MODULE_STATE_DIRTY = (1 << 1),
HI_MODULE_STATE_PATCHABLE = (1 << 6), // non system module we will modify
HI_MODULE_STATE_EXEC = (1 << 7), // denote the current executable
} ModuleFlags;
typedef u8 ModuleInfo;
typedef u32 ModuleInfo;
typedef struct {
const char *name; // Filename
/// Owning. Filename for the module.
const char *name;
/// Handle given by dlopen
void *dlhandle;
/// Start address for the module
uptr address;
/// Additional information, see @a ModuleFlags
ModuleInfo info;
} ModuleData;
vector_def(ModuleData, ModuleData);
static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, ModuleFlags flag) {
static inline ModuleInfo modinfo_add(ModuleInfo flags, ModuleFlags flag) {
return flags | flag;
}
static inline ModuleInfo hi_modinfo_clear(ModuleInfo flags, ModuleFlags flag) {
static inline ModuleInfo modinfo_clear(ModuleInfo flags, ModuleFlags flag) {
return flags & ~flag;
}
static inline bool hi_modinfo_has(ModuleInfo flags, ModuleFlags flag) {
static inline bool modinfo_has(ModuleInfo flags, ModuleFlags flag) {
return (flags & flag) != 0;
}
#define HI_MODINFO_SET(info, flag) ((info) |= flag)
#define HI_MODINFO_CLEAR(info, flag) ((info) &= ~flag)
HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
VectorMemoryMap *memregs);
HiResult moduler_reload(VectorModuleData *modules, ModuleData *module);

View File

@@ -1,6 +1,6 @@
#include "minimal_lib.h"
#include "../../include/hiload/hiload.h"
#include "../../include/hiload.h"
#include <assert.h>
#include <chrono>