Remove hi_ prefixes from internal code. Add documentation.

This commit is contained in:
2025-05-02 01:42:58 +03:00
parent fc9cdb5885
commit c6c1435f8a
15 changed files with 2943 additions and 174 deletions

2733
doc/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,9 @@
#define HI_FILE_BUFFER_SIZE 4096 #define HI_FILE_BUFFER_SIZE 4096
#endif #endif
char *hi_file_to_str_dyn(const char *filename) { char *file_to_str_dyn(const char *filename) {
char *s = hi_string_from_file_dyn(filename, 0, 0); char *s = hi_str_from_file(filename, 0, 0);
if (!s) { if (!s) {
sc_log_error("Failed to read file: %s\n", filename); sc_log_error("Failed to read file: %s\n", filename);
return 0; return 0;
@@ -21,14 +21,14 @@ char *hi_file_to_str_dyn(const char *filename) {
return s; return s;
} }
HiFileType hi_file_interpret_as_type(const char *path) { static FileType file_interpret_as_type(const char *path) {
const char *pathname_end = path + strlen(path); const char *pathname_end = path + strlen(path);
char last_char = *(pathname_end - 1); char last_char = *(pathname_end - 1);
bool as_dir = (last_char == '/') || (last_char == '\\'); bool as_dir = (last_char == '/') || (last_char == '\\');
return as_dir ? HI_FILE_TYPE_DIR : HI_FILE_TYPE_FILE; return as_dir ? HI_FILE_TYPE_DIR : HI_FILE_TYPE_FILE;
} }
const char *hi_file_name_from_path(const char *path) { const char *file_name_from_path(const char *path) {
const char *filename = path; const char *filename = path;
// Find the last directory separator // Find the last directory separator
@@ -45,7 +45,7 @@ const char *hi_file_name_from_path(const char *path) {
return filename; return filename;
} }
HiResult hi_file_copy(const char *srcname, const char *destination) { HiResult file_copy(const char *srcname, const char *destination) {
HiResult ret = HI_FAIL; HiResult ret = HI_FAIL;
@@ -59,10 +59,10 @@ HiResult hi_file_copy(const char *srcname, const char *destination) {
const char *dstname = destination; const char *dstname = destination;
HiFileType dst_type = hi_file_interpret_as_type(destination); FileType dst_type = file_interpret_as_type(destination);
if (dst_type == HI_FILE_TYPE_DIR) { if (dst_type == HI_FILE_TYPE_DIR) {
hi_strncat_buf(sizeof(buf), buf, destination, hi_str_concat_buf(sizeof(buf), buf, destination,
hi_file_name_from_path(srcname)); file_name_from_path(srcname));
dstname = buf; dstname = buf;
} }
@@ -100,7 +100,7 @@ cleanup:
* *
* TAG: posix * TAG: posix
*/ */
HiFileType hi_file_type(const char *path) { FileType file_type(const char *path) {
struct stat path_stat; struct stat path_stat;
int err = stat(path, &path_stat); int err = stat(path, &path_stat);
if (err == -1) { if (err == -1) {

View File

@@ -14,7 +14,7 @@ typedef enum {
HI_FILE_TYPE_COUNT, HI_FILE_TYPE_COUNT,
HI_FILE_TYPE_NONE, HI_FILE_TYPE_NONE,
} HiFileType; } FileType;
/** /**
* Read file dynamically to a string * Read file dynamically to a string
@@ -24,18 +24,19 @@ typedef enum {
* the initial memory and a reallocation to match the string size. * the initial memory and a reallocation to match the string size.
*/ */
char *hi_file_to_str_dyn(const char *filename); char *file_to_str_dyn(const char *filename);
/** /**
* Copy file \p filename to \p dest * Copy file \p filename to \p dest
* *
* 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 as
* the source.
*/ */
HiResult hi_file_copy(const char *filename, const char *dest); HiResult file_copy(const char *filename, const char *dest);
HiFileType hi_file_type(const char *path); FileType file_type(const char *path);
const char *hi_file_name_from_path(const char *path); const char *file_name_from_path(const char *path);
#endif // FILES_H_ #endif // FILES_H_

View File

@@ -9,10 +9,9 @@
#include <sys/inotify.h> #include <sys/inotify.h>
#include <unistd.h> #include <unistd.h>
/* /**
* File Watch * Used to pass information between some functions
*/ */
struct WatchMaskParams { struct WatchMaskParams {
u32 file_mask; u32 file_mask;
u32 parent_mask; u32 parent_mask;
@@ -46,6 +45,24 @@ static inline struct WatchMaskParams inode_watch_masks_create(u32 flags) {
.parent_mask = parent_mask}; .parent_mask = parent_mask};
} }
/**
* Return null terminated char array with the parent, or NULL if no path
* separator was found.
* */
static char *get_parent_folder(const char path[static 1]) {
const char *last_separator = strrchr(path, '/');
if (!last_separator)
return NULL;
// add one for the trailing slash
size_t length = last_separator - path + 1;
char *parent = calloc(length, sizeof(char));
strncpy(parent, path, length);
parent[length - 1] = '/';
parent[length] = '\0';
return parent;
}
static void file_watch_destroy(int fd, FileWatch *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);
@@ -78,8 +95,8 @@ FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, int wd,
return NULL; return NULL;
} }
FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, const char *path,
const char *path, size_t *index) { 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++) {
FileWatch *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) {
@@ -92,26 +109,7 @@ FileWatch *file_watch_find_by_path(FileWatcherContext *ctx,
return NULL; return NULL;
} }
/** HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, const char *path) {
* Return null terminated char array with the parent, or NULL if no path
* separator was found.
* */
static char *get_parent_folder(const char path[static 1]) {
const char *last_separator = strrchr(path, '/');
if (!last_separator)
return NULL;
// add one for the trailing slash
size_t length = last_separator - path + 1;
char *parent = calloc(length, sizeof(char));
strncpy(parent, path, length);
parent[length - 1] = '/';
parent[length] = '\0';
return parent;
}
HiResult file_watch_add(FileWatcherContext *ctx, u32 mask,
const char *path) {
if (!ctx || ctx->fd == -1) { if (!ctx || ctx->fd == -1) {
log_error("Invalid inotify context\n"); log_error("Invalid inotify context\n");
return HI_FAIL; return HI_FAIL;
@@ -167,25 +165,26 @@ HiResult file_watch_add(FileWatcherContext *ctx, u32 mask,
} }
HiResult file_watch_remove(FileWatcherContext *ctx, const char *path) { HiResult file_watch_remove(FileWatcherContext *ctx, const char *path) {
// BUG: Parent watchers are never properly cleared if all children are removed
// without removing the parent separately
size_t i = 0; size_t i = 0;
FileWatch *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. Parent should only have one, but lets make
// Destroy parent reference. We assume it will only have one. // sure.
char *parent = get_parent_folder(path); char *parent_name = get_parent_folder(path);
if (parent) { if (parent_name) {
FileWatch *pw = file_watch_find_by_path(ctx, parent, NULL); FileWatch *pw = file_watch_find_by_path(ctx, parent_name, 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);
if (fn == watch->path) { if (fn == watch->path) {
sc_array_del(&pw->files, i); sc_array_del(&pw->files, i);
break;
} }
} }
} }
free(parent); free(parent_name);
} }
file_watch_destroy(ctx->fd, watch); file_watch_destroy(ctx->fd, watch);
sc_array_del(&ctx->watches, i); sc_array_del(&ctx->watches, i);

View File

@@ -7,15 +7,40 @@
typedef struct FileWatcherContext FileWatcherContext; typedef struct FileWatcherContext FileWatcherContext;
typedef struct FileWatch FileWatch; typedef struct FileWatch FileWatch;
FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, /**
int wd, size_t *index); * Search for a FileWatch matching by watch descriptor.
FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, *
const char *path, size_t *index); * @param ctx
* @param wd Watch descriptor given by inotipy
* @param index Will contain the first occurrance of a matching FileWatch. Can
* be null.
*/
FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, int wd,
size_t *index);
/**
* Search for a FileWatch in a particular context matching by filepath.
* @param ctx
* @param path An absolute path for the file searched for
* @param index Will contain the first occurrance of a matching FileWatch. Can
* be null. */
FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, const char *path,
size_t *index);
HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, /**
const char *path); * Create FileWatch, start monitoring for changes and generating events.
HiResult file_watch_remove(FileWatcherContext *ctx, *
const char *path); * Creats a parent FileWatch if it doesn't already exist.
*/
HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, const char *path);
/**
* Stop a watch, clear all references and free memory
*/
HiResult file_watch_remove(FileWatcherContext *ctx, const char *path);
/**
* Free memory and clear all watches in this context
*/
void file_watch_destroy_watches(FileWatcherContext *ctx); void file_watch_destroy_watches(FileWatcherContext *ctx);
#endif // FILEWATCH_H_ #endif // FILEWATCH_H_

View File

@@ -27,8 +27,8 @@ typedef struct sc_array_fwparam VectorWatchParams;
* reused, and @a files is a list of files that have this watch as their parent. * reused, and @a files is a list of files that have this watch as their parent.
*/ */
typedef struct FileWatch { typedef struct FileWatch {
i32 wd; // Watch descriptor i32 wd;
u32 mask; // watch mask used u32 mask;
const char *path; // Owning const char *path; // Owning
VectorStr files; VectorStr files;
} FileWatch; } FileWatch;

View File

@@ -22,6 +22,9 @@
sc_array_def(FileEvent, fwevent); sc_array_def(FileEvent, fwevent);
typedef struct sc_array_fwevent VectorFileEvent; typedef struct sc_array_fwevent VectorFileEvent;
/**
* All context and state required to run a file watcher.
*/
typedef struct FileWatcher { typedef struct FileWatcher {
thrd_t thread; thrd_t thread;
mtx_t mutex; mtx_t mutex;
@@ -31,10 +34,10 @@ typedef struct FileWatcher {
VectorFileEvent events; VectorFileEvent events;
} FileWatcher; } FileWatcher;
/* /*
* Watch Params * Watch Params
*/ */
static inline WatchParams watch_params_create(const char *path, u32 mask) { static inline WatchParams watch_params_create(const char *path, u32 mask) {
return (WatchParams){.path = strdup(path), .mask = mask}; return (WatchParams){.path = strdup(path), .mask = mask};
} }
@@ -46,7 +49,7 @@ static inline void watch_params_destroy(WatchParams *params) {
static WatchParams *watch_params_find_by_path(const char *path, static WatchParams *watch_params_find_by_path(const char *path,
FileWatcherContext *ctx, FileWatcherContext *ctx,
size_t *index) { size_t *index) {
const struct sc_array_fwparam *params = &ctx->params; const VectorWatchParams *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) {
WatchParams *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) {
@@ -140,7 +143,7 @@ static FileEvent file_event_create(const struct inotify_event *inevent,
return NULL_EVENT; return NULL_EVENT;
} }
FileEvent hi_file_event_pop(FileWatcher *fw) { FileEvent file_event_pop(FileWatcher *fw) {
mtx_lock(&fw->mutex); mtx_lock(&fw->mutex);
FileEvent e = NULL_EVENT; FileEvent e = NULL_EVENT;
@@ -178,7 +181,7 @@ static void file_watcher_ctx_destroy(FileWatcherContext *ctx) {
// Declare the thread func // Declare the thread func
int file_watcher_watch(void *arg); int file_watcher_watch(void *arg);
FileWatcher *hi_file_watcher_create() { FileWatcher *file_watcher_create() {
// Allocate context // Allocate context
FileWatcher *fw = malloc(sizeof(FileWatcher)); FileWatcher *fw = malloc(sizeof(FileWatcher));
@@ -204,7 +207,7 @@ FileWatcher *hi_file_watcher_create() {
return NULL; return NULL;
} }
HiResult hi_file_watcher_add(FileWatcher *fw, const char *filename, u32 flags) { HiResult file_watcher_add(FileWatcher *fw, const char *filename, 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);
@@ -257,19 +260,19 @@ HiResult hi_file_watcher_remove(FileWatcher *fw, const char *filename) {
return HI_OK; return HI_OK;
} }
void hi_file_watcher_notify(FileWatcher *fw) { void 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(FileWatcher *fw) { void file_watcher_destroy(FileWatcher *fw) {
if (!fw) if (!fw)
return; return;
if (fw->running) { if (fw->running) {
fw->running = false; fw->running = false;
hi_file_watcher_notify(fw); file_watcher_notify(fw);
thrd_join(fw->thread, NULL); thrd_join(fw->thread, NULL);
} }

View File

@@ -21,8 +21,9 @@
* memory inside the file watcher struct. * memory inside the file watcher struct.
*/ */
typedef struct { typedef struct {
const char *pathname; // Pathname given to a `hi_file_watcher_add` call. /** Path of the file this event is about. Do not free. */
// Do not free. const char *pathname;
/** Might not be only those given to @a file_watcher_add. */
FileWatchType type; FileWatchType type;
} FileEvent; } FileEvent;
@@ -31,44 +32,38 @@ typedef struct FileWatcher FileWatcher;
/** /**
* 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 * Events will be popped mostly in reverse chronological order, but strict
* in reverse chronological order. * chronology is not guaranteed.
* */ */
typedef struct FileEvents FileEvents; 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. * Starts a new watcher thread immediately.
*/ */
FileWatcher *hi_file_watcher_create(void); FileWatcher *file_watcher_create(void);
/** /**
* Destroy a previously created file watcher context. * Destroy a previously created file watcher.
* *
* Will join the thread and destroy event stack. * Will join the thread and destroy event stack. Any FileEvent still in
* existence will contain invalid data after this call.
*/ */
void hi_file_watcher_destroy(FileWatcher *context); void file_watcher_destroy(FileWatcher *fw);
/** /**
* Add a file to the watch list of a file watcher. * Start watching for events on a file.
* *
* @param context Previously created watcher context * @param fw The watcher instance
* @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 event mask for the events to watch for
*/ */
HiResult hi_file_watcher_add(FileWatcher *context, HiResult file_watcher_add(FileWatcher *fw, const char *pathname, u32 flags);
const char *pathname, u32 flags);
/**
* Can be used to poke file watcher thread to make sure it empties
* events before doing something, e.g. for shutting it down.
*/
void hi_file_watcher_notify(FileWatcher *context);
/** /**
* Pop an event from event stack. Call `hi_file_event_destroy` when done with * Pop an event from event stack.
* it.
*/ */
FileEvent hi_file_event_pop(FileWatcher *ctx); FileEvent file_event_pop(FileWatcher *ctx);
#endif // HI_FILEWATCHER_H_ #endif // HI_FILEWATCHER_H_

View File

@@ -71,7 +71,7 @@ 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(module_exclude_filter), if (!hi_str_starts_with(module.name, ARRLEN(module_exclude_filter),
module_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);
} }
@@ -89,7 +89,7 @@ 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;
if (!HIOK(hi_file_watcher_add(context.filewatcher, modpath, if (!HIOK(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);
} else { } else {
@@ -151,7 +151,7 @@ static ModuleData *get_module_by_path(const char *path,
*/ */
static void handle_events(FileWatcher *fw, VectorModuleData *modules) { static void handle_events(FileWatcher *fw, VectorModuleData *modules) {
FileEvent event = hi_file_event_pop(fw); FileEvent event = 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));
@@ -162,7 +162,7 @@ static void handle_events(FileWatcher *fw, VectorModuleData *modules) {
} else { } else {
module->info = hi_modinfo_add(module->info, HI_MODULE_STATE_DIRTY); module->info = hi_modinfo_add(module->info, HI_MODULE_STATE_DIRTY);
} }
event = hi_file_event_pop(context.filewatcher); event = file_event_pop(context.filewatcher);
} }
} }
@@ -216,7 +216,7 @@ int hi_init(size_t n, const char **enabled_modules) {
log_set_thread_name("Main"); log_set_thread_name("Main");
// Start the filewatcher // Start the filewatcher
context.filewatcher = hi_file_watcher_create(); context.filewatcher = file_watcher_create();
for (unsigned i = 0; i < n; i++) { for (unsigned i = 0; i < n; i++) {
const char *module_name = enabled_modules[i]; const char *module_name = enabled_modules[i];
@@ -241,7 +241,7 @@ int hi_init(size_t n, const char **enabled_modules) {
void hi_deinit() { void hi_deinit() {
module_infos_free(&context.modules); module_infos_free(&context.modules);
hi_file_watcher_destroy(context.filewatcher); file_watcher_destroy(context.filewatcher);
log_term(); log_term();
memset(&context, 0, sizeof(context)); memset(&context, 0, sizeof(context));
} }

View File

@@ -33,7 +33,7 @@ HiResult memory_find_region(uptr ptr, struct sc_array_memreg *const regions,
HiResult 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 = file_to_str_dyn("/proc/self/maps");
if (!maps_str) if (!maps_str)
return HI_FAIL; return HI_FAIL;

View File

@@ -135,8 +135,8 @@ static HiResult gather_patchable_symbols(struct sc_array_sym *symbols,
} }
void *sym_addr = (void *)((uintptr_t)module_base + sym.st_value); void *sym_addr = (void *)((uintptr_t)module_base + sym.st_value);
HiSymbolBind binding = symbol_bind_from_efibind(GELF_ST_BIND(sym.st_info)); SymbolBind binding = symbol_bind_from_efibind(GELF_ST_BIND(sym.st_info));
HiSymbolType type = symbol_type_from_efitype(GELF_ST_TYPE(sym.st_info)); SymbolType type = symbol_type_from_efitype(GELF_ST_TYPE(sym.st_info));
size_t size = sym.st_size; size_t size = sym.st_size;
// Gather global symbols and local object symbols. Local functions are // Gather global symbols and local object symbols. Local functions are
@@ -145,7 +145,7 @@ static HiResult gather_patchable_symbols(struct sc_array_sym *symbols,
if (binding == HI_SYMBOL_BIND_GLOBAL || if (binding == HI_SYMBOL_BIND_GLOBAL ||
(binding == HI_SYMBOL_BIND_LOCAL && (binding == HI_SYMBOL_BIND_LOCAL &&
type == HI_SYMBOL_TYPE_OBJECT)) { type == HI_SYMBOL_TYPE_OBJECT)) {
HiSymbol hisym = {.name = strdup(name), Symbol hisym = {.name = strdup(name),
.size = size, .size = size,
.binding = binding, .binding = binding,
.type = type, .type = type,
@@ -166,7 +166,7 @@ cleanup:
return ret; return ret;
} }
static HiResult moduler_apply_module_patch(HiSymbols *psymbols, static HiResult moduler_apply_module_patch(VectorSymbol *psymbols,
MemoryRegionSpan module_memory) { MemoryRegionSpan module_memory) {
void *module_base = (void *)module_memory.region_start; void *module_base = (void *)module_memory.region_start;
@@ -246,7 +246,7 @@ static HiResult moduler_apply_module_patch(HiSymbols *psymbols,
// Check if this is a symbol we want to patch // Check if this is a symbol we want to patch
for (size_t j = 0; j < num_symbols; j++) { for (size_t j = 0; j < num_symbols; j++) {
HiSymbol *sym = &sc_array_at(psymbols, j); Symbol *sym = &sc_array_at(psymbols, j);
if (strcmp(sym->name, name) == 0) { if (strcmp(sym->name, name) == 0) {
sym->got_entry = got_entry; sym->got_entry = got_entry;
sym->orig_address = *got_entry; // Save the original function sym->orig_address = *got_entry; // Save the original function
@@ -280,7 +280,7 @@ PatchData moduler_create_patch(ModuleData *module) {
char filename[512]; char filename[512];
size_t written = size_t written =
hi_strncat_buf(sizeof(filename), filename, module->name, file_append); hi_str_concat_buf(sizeof(filename), filename, module->name, file_append);
if (written == 0) { if (written == 0) {
@@ -288,7 +288,7 @@ PatchData moduler_create_patch(ModuleData *module) {
return (PatchData){0}; return (PatchData){0};
} }
hi_file_copy(module->name, filename); file_copy(module->name, filename);
PatchData data = {.filename = strdup(filename)}; PatchData data = {.filename = strdup(filename)};
return data; return data;
@@ -328,7 +328,7 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
patch.memreg = memory_get_module_span(memregs, patch.filename); patch.memreg = memory_get_module_span(memregs, patch.filename);
void *patch_base = (void *)patch.memreg.region_start; void *patch_base = (void *)patch.memreg.region_start;
HiSymbols patch_symbols; VectorSymbol patch_symbols;
symbol_init_symbols(&patch_symbols); symbol_init_symbols(&patch_symbols);
HiResult ret = HiResult ret =
@@ -352,7 +352,7 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
// If patch is for the same module, also collect local object symbols for // If patch is for the same module, also collect local object symbols for
// coping those over. // coping those over.
HiSymbols module_symbols; VectorSymbol module_symbols;
symbol_init_symbols(&module_symbols); symbol_init_symbols(&module_symbols);
ret = gather_patchable_symbols(&module_symbols, mod.name, ret = gather_patchable_symbols(&module_symbols, mod.name,
(void *)mod.address); (void *)mod.address);
@@ -364,9 +364,9 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
// Copy old data to new data. Breaks with layout changes. // Copy old data to new data. Breaks with layout changes.
for (size_t i = 0; i < sc_array_size(&module_symbols); ++i) { for (size_t i = 0; i < sc_array_size(&module_symbols); ++i) {
HiSymbol *sym = &sc_array_at(&module_symbols, i); Symbol *sym = &sc_array_at(&module_symbols, i);
if (sym->type == HI_SYMBOL_TYPE_OBJECT) { if (sym->type == HI_SYMBOL_TYPE_OBJECT) {
HiSymbol *ps = symbol_find(&patch_symbols, sym); Symbol *ps = symbol_find(&patch_symbols, sym);
if (ps) { if (ps) {
if (ps->size >= sym->size) { if (ps->size >= sym->size) {
memcpy(ps->address, sym->address, sym->size); memcpy(ps->address, sym->address, sym->size);

View File

@@ -7,8 +7,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
size_t hi_strncat_buf(size_t buflen, char buf[buflen], const char *first, const char *second) { size_t hi_str_concat_buf(size_t buflen, char buf[buflen], const char *first,
if (!buf) return 0; const char *second) {
if (!buf)
return 0;
size_t first_len = strlen(first); size_t first_len = strlen(first);
size_t second_len = strlen(second); size_t second_len = strlen(second);
@@ -17,8 +19,8 @@ size_t hi_strncat_buf(size_t buflen, char buf[buflen], const char *first, const
return 0; return 0;
} }
char * first_end = buf + first_len; char *first_end = buf + first_len;
char * second_end = first_end + second_len; char *second_end = first_end + second_len;
strncpy(buf, first, first_end - buf); strncpy(buf, first, first_end - buf);
strncpy(first_end, second, second_end - first_end); strncpy(first_end, second, second_end - first_end);
@@ -42,7 +44,7 @@ int hi_path_has_filename(const char *path, const char *filename) {
return 0; return 0;
} }
char *hi_string_from_file_dyn(const char *filename, size_t *nread, char *hi_str_from_file(const char *filename, size_t *nread,
size_t nmax) { size_t nmax) {
FILE *f = fopen(filename, "r"); FILE *f = fopen(filename, "r");
@@ -105,11 +107,13 @@ char *hi_string_from_file_dyn(const char *filename, size_t *nread,
return buf; return buf;
} }
const char *hi_string_starts_with(const char path[static 1], size_t listn, const char *pathlist[listn]) { const char *hi_str_starts_with(const char path[static 1], size_t listn,
const char *pathlist[listn]) {
if (!pathlist) return path; if (!pathlist)
return path;
size_t pathlen = strlen(path); size_t pathlen = strlen(path);
for (size_t i=0; i < listn; ++i) { for (size_t i = 0; i < listn; ++i) {
size_t len = MIN(strlen(pathlist[i]), pathlen); size_t len = MIN(strlen(pathlist[i]), pathlen);
if (strncmp(path, pathlist[i], len) == 0) { if (strncmp(path, pathlist[i], len) == 0) {
return pathlist[i]; return pathlist[i];

View File

@@ -6,40 +6,47 @@
/** /**
* Concatenate two strings into a buffer. * Concatenate two strings into a buffer.
* *
* If resulting string would be longer than buflen - 1, the resulting string in * If resulting string would be longer than @a buflen - 1, the resulting string
* \p buf is unchanged. * in
* @a buf is unchanged.
* *
* @param first Null terminated character string * @param first Null terminated character string
* @param second Null terminated character string * @param second Null terminated character string
*/ */
size_t hi_strncat_buf(size_t bufsize, char buf[bufsize], const char *first, size_t hi_str_concat_buf(size_t bufsize, char buf[bufsize],
const char *second); const char *first, const char *second);
/** /**
* @brief Copy file content to a null terminated string, allocating memory while * Copy file content to a null terminated string, allocating memory while
* reading. * reading.
* *
* This doesn't assume it can read file size, so it allocates memory in chunks * Can be used for reading the virtual file system, where the file size isn't
* (default 4096 bytes) and keeps reading until 0 bytes is read. If nmax is * known. If @a nmax is non-zero, that amount of bytes is allocated and read at
* non-zero, instead that amount of bytes is allocated and that is read. * once. No more than @a nmax bytes is read in that case.
* *
* In either case, the string is reallocated to match the length before * In all cases, the string is reallocated to match the length before
* returning. * returning.
*
* @param filename a complete pathname to the file * @param filename a complete pathname to the file
* @param nread if not null, this will have the total amount bytes read * @param nread if not null, this will have the total amount bytes read
* @param nmax if not 0, this amount of memory in bytes is read and used as * @param nmax if not 0, this amount of memory in bytes is read and used as
* initial allocation * initial allocation
*/ */
char *hi_string_from_file_dyn(const char *filename, size_t *nread, size_t nmax); char *hi_str_from_file(const char *filename, size_t *nread,
size_t nmax);
/** /**
* Find if filename exists at the end of path. * Return the first string from @a pathlist that is fully included in @a path.
*/
const char *hi_str_starts_with(const char path[static 1], size_t listn,
const char *pathlist[listn]);
/**
* Find if @a filename exists at the end of @a path.
* *
* @return 0 if not found, positive if found * @return 0 if not found, positive if found
*/ */
int hi_path_has_filename(const char *path, const char *filename); int hi_path_has_filename(const char *path, const char *filename);
const char *hi_string_starts_with(const char path[static 1], size_t listn,
const char *pathlist[listn]);
#endif // HI_STRING_H_ #endif // HI_STRING_H_

View File

@@ -4,9 +4,9 @@
#include <elf.h> #include <elf.h>
#include <string.h> #include <string.h>
HiSymbol *symbol_find(HiSymbols *symbols, HiSymbol *symbol) { Symbol *symbol_find(VectorSymbol *symbols, Symbol *symbol) {
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); Symbol *s = &sc_array_at(symbols, i);
if (strcmp(s->name, symbol->name) == 0) { if (strcmp(s->name, symbol->name) == 0) {
return s; return s;
} }
@@ -14,7 +14,7 @@ HiSymbol *symbol_find(HiSymbols *symbols, HiSymbol *symbol) {
return NULL; return NULL;
} }
HiSymbolBind symbol_bind_from_efibind(u32 efi_bind) { SymbolBind symbol_bind_from_efibind(u32 efi_bind) {
// clang-format off // clang-format off
switch (efi_bind) { switch (efi_bind) {
case STB_LOCAL: return HI_SYMBOL_BIND_LOCAL; case STB_LOCAL: return HI_SYMBOL_BIND_LOCAL;
@@ -25,7 +25,7 @@ HiSymbolBind symbol_bind_from_efibind(u32 efi_bind) {
return ~0u; return ~0u;
} }
HiSymbolType symbol_type_from_efitype(u32 efi_type) { SymbolType symbol_type_from_efitype(u32 efi_type) {
// clang-format off // clang-format off
switch (efi_type) { switch (efi_type) {
case STT_NOTYPE: return HI_SYMBOL_TYPE_NOTYPE; /* Symbol type is unspecified */ case STT_NOTYPE: return HI_SYMBOL_TYPE_NOTYPE; /* Symbol type is unspecified */

View File

@@ -9,7 +9,7 @@ typedef enum {
HI_SYMBOL_BIND_LOCAL, HI_SYMBOL_BIND_LOCAL,
HI_SYMBOL_BIND_GLOBAL, HI_SYMBOL_BIND_GLOBAL,
HI_SYMBOL_BIND_WEAK, HI_SYMBOL_BIND_WEAK,
} HiSymbolBind; } SymbolBind;
typedef enum { typedef enum {
HI_SYMBOL_TYPE_NOTYPE, HI_SYMBOL_TYPE_NOTYPE,
@@ -19,39 +19,41 @@ typedef enum {
HI_SYMBOL_TYPE_FILE, HI_SYMBOL_TYPE_FILE,
HI_SYMBOL_TYPE_COMMON, HI_SYMBOL_TYPE_COMMON,
HI_SYMBOL_TYPE_TLS, HI_SYMBOL_TYPE_TLS,
} HiSymbolType; } SymbolType;
typedef struct HiSymbol { typedef struct Symbol {
const char *name; const char *name;
HiSymbolBind binding; SymbolBind binding;
HiSymbolType type; SymbolType type;
size_t size; size_t size;
void *address; void *address;
void **got_entry; void **got_entry;
void *orig_address; void *orig_address;
} HiSymbol; } Symbol;
sc_array_def(HiSymbol, sym);
typedef struct sc_array_sym HiSymbols;
static inline void symbol_free(HiSymbol *symbol) { free((char *)symbol->name); } sc_array_def(Symbol, sym);
typedef struct sc_array_sym VectorSymbol;
static inline void symbol_init_symbols(HiSymbols *symbols) { static inline void symbol_free(Symbol *symbol) { free((char *)symbol->name); }
static inline void symbol_init_symbols(VectorSymbol *symbols) {
sc_array_init(symbols); sc_array_init(symbols);
} }
static inline void symbol_clear_symbols(HiSymbols *symbols) { static inline void symbol_clear_symbols(VectorSymbol *symbols) {
for (size_t i = 0; i < sc_array_size(symbols); ++i) { for (size_t i = 0; i < sc_array_size(symbols); ++i) {
symbol_free(&sc_array_at(symbols, i)); symbol_free(&sc_array_at(symbols, i));
} }
sc_array_clear(symbols); sc_array_clear(symbols);
} }
static inline void symbol_term_symbols(HiSymbols *symbols) { static inline void symbol_term_symbols(VectorSymbol *symbols) {
symbol_clear_symbols(symbols); symbol_clear_symbols(symbols);
sc_array_term(symbols); sc_array_term(symbols);
} }
HiSymbol *symbol_find(HiSymbols *symbols, HiSymbol *symbol); Symbol *symbol_find(VectorSymbol *symbols, Symbol *symbol);
SymbolBind symbol_bind_from_efibind(u32 efi_bind);
SymbolType symbol_type_from_efitype(u32 efi_type);
HiSymbolBind symbol_bind_from_efibind(u32 efi_bind);
HiSymbolType symbol_type_from_efitype(u32 efi_type);
#endif // SYMBOLS_H_ #endif // SYMBOLS_H_