some logger changes

This commit is contained in:
2025-04-12 22:28:16 +03:00
parent 6f3c76b005
commit 1a10f79b02
9 changed files with 110 additions and 146 deletions

View File

@@ -46,6 +46,7 @@ add_library(hiload SHARED
src/files.c
src/memory.c
src/string/string.c
src/logger/logger.c
src/filewatcher/filewatcher.c
src/filewatcher/filewatch.c

View File

@@ -1,6 +1,7 @@
#ifndef HILOAD_H_
#define HILOAD_H_
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -8,14 +9,6 @@ extern "C" {
// Allows using -fvisibility=hidden by default, decreasing visible symbols
#pragma GCC visibility push(default)
// Return codes for reload_module
typedef enum {
HI_RELOAD_SUCCESS = 0,
HI_RELOAD_NOT_FOUND,
HI_RELOAD_CLOSE_ERROR,
HI_RELOAD_OPEN_ERROR
} ReloadResult;
/**
* Initialiez the module. Must be called before anything else
*/
@@ -34,8 +27,12 @@ void hi_print_loaded_modules(void);
/**
* Reload shared library if it has changed since last reload or init was called
*/
ReloadResult hi_reload_solib(const char *module_name);
HiloadResult hi_reload_solib(const char *module_name);
/**
* Reload all watched modules
*/
HiloadResult hi_reload();
#pragma GCC visibility pop

View File

@@ -11,6 +11,7 @@
#include <unistd.h>
#include "array/array.h"
#include "array/sc_array.h"
#include "common.h"
#include "filewatch.h"
#include "filewatch_context.h"
@@ -85,8 +86,8 @@ static hiFileEvent file_event_create(const struct inotify_event *inevent,
size_t fullpath_size = parent_name_size + event_path_size;
if (fullpath_size > BUFSIZE - 1) {
sc_log_error("Pathname length over %u, please compile with smaller "
"paths. Event discarded for %s\n.", BUFSIZE - 1,
inevent->name);
"paths. Event discarded for %s\n.",
BUFSIZE - 1, inevent->name);
return NULL_EVENT;
}
#undef BUFSIZE
@@ -124,7 +125,8 @@ static hiFileEvent file_event_create(const struct inotify_event *inevent,
return NULL_EVENT;
}
event.pathname = watched_file;
// Use params path pointer, because that's what user has control over.
event.pathname = params->path;
// Event matched and we're watching for it
return event;
@@ -137,14 +139,16 @@ static hiFileEvent file_event_create(const struct inotify_event *inevent,
return NULL_EVENT;
}
hiFileEvent hi_file_event_pop(hiFileWatcher *ctx) {
mtx_lock(&ctx->mutex);
hiFileEvent *last = &sc_array_last(&ctx->events);
hiFileEvent e = *last;
hiFileEvent hi_file_event_pop(hiFileWatcher *fw) {
mtx_lock(&fw->mutex);
sc_array_del_last(&ctx->events);
hiFileEvent e = NULL_EVENT;
if (sc_array_size(&fw->events) > 0) {
e = sc_array_last(&fw->events);
sc_array_del_last(&fw->events);
}
mtx_unlock(&ctx->mutex);
mtx_unlock(&fw->mutex);
return e;
}

View File

@@ -6,9 +6,13 @@
/**
* File event watcher using inotify.
*
* 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
* '/workspace/code/my-proj' paths might exist from either side and they are
* not interpreted as equal.
*/
/**
* File Event produced by FileWatcher.
*

View File

@@ -1,9 +1,8 @@
#include "hiload/hiload.h"
#include "array/sc_array.h"
#include "array/array.h"
#include "filewatcher/filewatcher.h"
#include "logger/logger.h"
#include "logger/sc_log.h"
#include "memory.h"
#include "string/string.h"
#include "symbols.h"
@@ -25,6 +24,7 @@ typedef struct {
struct sc_array_ptr handles; // Array of library handles
struct sc_array_uptr addresses; // Array of library base addresses
struct sc_array_syms symbols; // Symbol info for modules
bool dirty[256]; // Flag for when module needs to be changed
size_t count; // Number of modules
} ModuleInfos;
@@ -47,7 +47,7 @@ static int gather_module_infos_callback(struct dl_phdr_info *info, size_t size,
const char *modname = info->dlpi_name;
sc_array_add(&mod_infos->names, strdup(modname));
sc_log_info("Processing: '%s'\n", info->dlpi_name);
log_info("Processing: '%s'\n", info->dlpi_name);
// Try to get the handle
void *handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD);
@@ -56,11 +56,11 @@ static int gather_module_infos_callback(struct dl_phdr_info *info, size_t size,
sc_array_add(&mod_infos->handles, handle);
sc_array_add(&mod_infos->addresses, info->dlpi_addr);
sc_log_debug(" size: %u\n", size);
sc_log_debug(" handle: %p\n", sc_array_last(&mod_infos->handles));
sc_log_debug(" dlpi_addr: %p\n", info->dlpi_addr);
sc_log_debug(" dlpi_tls_modid: %zu\n", info->dlpi_tls_modid);
sc_log_debug(" dlpi_tls_data: %p\n", info->dlpi_tls_data);
log_debug_v(" size: %u\n", size);
log_debug_v(" handle: %p\n", sc_array_last(&mod_infos->handles));
log_debug_v(" dlpi_addr: %p\n", info->dlpi_addr);
log_debug_v(" dlpi_tls_modid: %zu\n", info->dlpi_tls_modid);
log_debug_v(" dlpi_tls_data: %p\n", info->dlpi_tls_data);
Dl_info dl_info = {0};
if (dladdr((void *)sc_array_last(&mod_infos->addresses), &dl_info)) {
@@ -78,14 +78,14 @@ static int gather_module_infos_callback(struct dl_phdr_info *info, size_t size,
}
if (!HILOADRES(hi_file_watcher_add(context.filewatcher, filename,
HI_FILE_ALL_EVENTS))) {
sc_log_error("Failed to set filewatcher for: '%s'\n", filename);
log_error("Failed to set filewatcher for: '%s'\n", filename);
} else {
sc_log_info("Watching file: %s\n", filename);
log_info("Watching file: %s\n", filename);
}
}
}
} else {
sc_log_error("Couldn't load dlinfo for %s: %s\n",
log_error("Couldn't load dlinfo for %s: %s\n",
(sc_array_last(&mod_infos->names)), dlerror());
}
@@ -131,137 +131,60 @@ static ModuleInfos *gather_module_infos(void) {
return result;
}
static ReloadResult reload_solib(ModuleInfos *modules, const char *filename,
void **updated_handle) {
if (!modules || !filename) {
return HI_RELOAD_NOT_FOUND;
}
i32 get_module_index(const char *path, HiloadContext *ctx) {
// Find the module by filename
int found = 0;
size_t index = 0;
for (size_t i = 0; i < modules->count; i++) {
// Check if this is the module we're looking for
const char *pathname = sc_array_at(&modules->names, i);
if (hi_path_has_filename(pathname, filename)) {
found = 1;
index = i;
break;
for (size_t i = 0; i < ctx->loaded_modules->count; i++) {
const char *name = sc_array_at(&ctx->loaded_modules->names, i);
if (strcmp(name, path) == 0) {
return i;
}
}
if (!found) {
return HI_RELOAD_NOT_FOUND;
return -1;
}
// Save the full path
const char *fullpath = sc_array_at(&modules->names, index);
if (!fullpath) {
return HI_RELOAD_OPEN_ERROR;
HiloadResult hi_reload() {
hiFileEvent event = hi_file_event_pop(context.filewatcher);
while (event.type != HI_FILE_NONE) {
log_debug("Event pop: %s %s\n", event.pathname,
hi_file_watch_type_to_str(event.type));
i32 index = get_module_index(event.pathname, &context);
if (index < 0) {
log_warn("Watched module: %s not found.\n", event.pathname);
}
event = hi_file_event_pop(context.filewatcher);
}
// Close the old handle
void *handle = sc_array_at(&modules->handles, index);
if (handle) {
if (dlclose(handle) != 0) {
return HI_RELOAD_CLOSE_ERROR;
}
}
// Open the module with RTLD_NOW
void *new_handle = dlopen(fullpath, RTLD_LAZY);
if (!new_handle) {
sc_log_error("Error reloading module: %s\n", dlerror());
return HI_RELOAD_OPEN_ERROR;
}
if (new_handle != handle) {
sc_log_info("%s: changed\n", fullpath);
}
// Update the handle in our structure
modules->handles.elems[index] = new_handle;
// If the caller wants the new handle, provide it
if (updated_handle) {
*updated_handle = new_handle;
}
return HI_RELOAD_SUCCESS;
}
ReloadResult hi_reload_solib(const char *module_name) {
void *new_handle = NULL;
ReloadResult result =
reload_solib(context.loaded_modules, module_name, &new_handle);
return result;
}
void hi_print_loaded_modules(void) {
sc_log_info("Loaded module info:\n");
sc_log_info("-------------------\n");
const ModuleInfos *mod_infos = context.loaded_modules;
if (!mod_infos) {
sc_log_error("No module information available.\n");
return;
}
sc_log_info("Found %zu loaded modules:\n", mod_infos->count);
for (size_t i = 0; i < mod_infos->count; i++) {
sc_log_info("'%s'\n", sc_array_at(&mod_infos->names, i));
sc_log_info(" handle: %p\n", sc_array_at(&mod_infos->handles, i));
sc_log_info(" address: %p\n", sc_array_at(&mod_infos->addresses, i));
// If we have loaded symbols, print those
if (sc_array_size(&mod_infos->symbols) > 0) {
const SymbolInfos *symbols = &sc_array_at(&mod_infos->symbols, i);
if (symbols) {
for (size_t j = 0; j < sc_array_size(&symbols->names); j++) {
const void *addr = sc_array_at(&symbols->addresses, j);
const char *name = sc_array_at(&symbols->names, j);
sc_log_info(" %p: %s\n", addr, name);
}
}
}
sc_log_info("\n");
}
return HILOAD_OK;
}
int hi_init(unsigned n, const char **enabled_modules) {
if (sc_log_init() != 0) {
if (log_init() != 0) {
fprintf(stderr, "Failed to init logger.\n");
return 1;
}
sc_log_set_level("DEBUG");
sc_log_set_thread_name("Main");
log_set_level("DEBUG");
log_set_thread_name("Main");
// Start the filewatcher
context.filewatcher = hi_file_watcher_create();
for (unsigned i = 0; i < n; i++) {
const char *module_name = enabled_modules[i];
sc_log_info("Enabling module: '%s'\n", module_name);
log_info("Enabling module: '%s'\n", module_name);
sc_array_add(&context.enabled_modules, module_name);
}
if (read_memory_maps_self(&context.memory_regions) != HILOAD_OK) {
sc_log_error("Could not populate program memory maps.\n");
log_error("Could not populate program memory maps.\n");
return HILOAD_FAIL;
}
ModuleInfos *infos = gather_module_infos();
if (!infos) {
sc_log_error("Failed to gather module infos.\n");
log_error("Failed to gather module infos.\n");
return 1;
}
@@ -271,14 +194,12 @@ int hi_init(unsigned n, const char **enabled_modules) {
}
context.loaded_modules = infos;
hi_print_loaded_modules();
return 0;
}
void hi_deinit() {
module_infos_free(context.loaded_modules);
hi_file_watcher_destroy(context.filewatcher);
sc_log_term();
log_term();
memset(&context, 0, sizeof(context));
}

13
src/logger/logger.c Normal file
View File

@@ -0,0 +1,13 @@
#include "logger.h"
#include <stdatomic.h>
_Atomic bool hiload_verbose_log = false;
void log_set_verbose(bool value) {
atomic_store_explicit(&hiload_verbose_log, value, memory_order_relaxed);
}
bool log_get_verbose() {
return atomic_load_explicit(&hiload_verbose_log, memory_order_relaxed);
}

View File

@@ -3,4 +3,26 @@
#include "logger/sc_log.h"
void log_set_verbose(bool value);
bool log_get_verbose();
#define log_init() (sc_log_init())
#define log_set_level(level) (sc_log_set_level((level)))
#define log_set_thread_name(name) (sc_log_set_thread_name((name)))
#define log_term() (sc_log_term())
#define log_debug(...) (sc_log_debug(__VA_ARGS__))
#define log_info(...) (sc_log_info(__VA_ARGS__))
#define log_warn(...) (sc_log_warn(__VA_ARGS__))
#define log_error(...) (sc_log_error(__VA_ARGS__))
#define log_debug_v(...) do { if (log_get_verbose()) { \
log_debug(__VA_ARGS__); } } while(0)
#define log_info_v(...) do { if (log_get_verbose()) { \
log_info(__VA_ARGS__); } } while(0)
#define log_warn_v(...) do { if (log_get_verbose()) { \
log_warn(__VA_ARGS__); } } while(0)
#define log_error_v(...) do { if (log_get_verbose()) { \
log_error(__VA_ARGS__); } } while(0)
#endif // LOGGER_H_

View File

@@ -39,7 +39,7 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) {
if (!maps_str)
return HILOAD_FAIL;
sc_log_debug("/proc/self/maps:\n%s", maps_str);
log_debug_v("/proc/self/maps:\n%s", maps_str);
char *strptr = maps_str;
@@ -47,10 +47,10 @@ HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) {
while (line) {
MemoryRegion reg = {0};
char pathname[256];
char perm_str[5];
u32 dev_major;
u32 dev_minor;
char pathname[256];
// clang-format off
// Format example from the file:

View File

@@ -2,24 +2,27 @@
#include "../../include/hiload/hiload.h"
#include <assert.h>
#include <chrono>
#include <cstdio>
#include <thread>
#define ARRLEN(A) (sizeof((A)) / (sizeof((A)[0])))
int main(int argc, char *argv[]) {
const char *reloadable_modules[] = {"", "libmini.so"};
hi_init(2, reloadable_modules);
hi_init(ARRLEN(reloadable_modules), reloadable_modules);
int modified = -1;
while (modified != 0) {
printf("==========================\n");
printf("main address: %p\n", main);
printf("minimal_lib::getNewValue address: %p\n", minimal_lib::getNewValue);
printf("minimal_lib::otherValue address: %p\n", &minimal_lib::otherValue);
printf("==========================\n");
printf("");
// printf("==========================\n");
// printf("main address: %p\n", main);
// printf("minimal_lib::getNewValue address: %p\n", minimal_lib::getNewValue);
// printf("minimal_lib::otherValue address: %p\n", &minimal_lib::otherValue);
// printf("==========================\n");
// printf("");
modified = minimal_lib::getNewValue(5);
printf("getModified(5): %d\n", modified);
@@ -27,10 +30,9 @@ int main(int argc, char *argv[]) {
printf("otherValue: %d\n", minimal_lib::otherValue++);
std::this_thread::sleep_for(std::chrono::seconds(1));
printf("\n");
if (hi_reload_solib("libmini.so") != HI_RELOAD_SUCCESS) {
fprintf(stderr, "Failed to load solib\n");
if (hi_reload() != HILOAD_OK) {
fprintf(stderr, "Failed to load modules\n");
}
}