some logger changes
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
151
src/hiload.c
151
src/hiload.c
@@ -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,15 +78,15 @@ 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",
|
||||
(sc_array_last(&mod_infos->names)), dlerror());
|
||||
log_error("Couldn't load dlinfo for %s: %s\n",
|
||||
(sc_array_last(&mod_infos->names)), dlerror());
|
||||
}
|
||||
|
||||
return 0; // Continue iteration
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
// Save the full path
|
||||
const char *fullpath = sc_array_at(&modules->names, index);
|
||||
if (!fullpath) {
|
||||
return HI_RELOAD_OPEN_ERROR;
|
||||
}
|
||||
|
||||
// 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;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ReloadResult hi_reload_solib(const char *module_name) {
|
||||
HiloadResult hi_reload() {
|
||||
|
||||
void *new_handle = NULL;
|
||||
ReloadResult result =
|
||||
reload_solib(context.loaded_modules, module_name, &new_handle);
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
i32 index = get_module_index(event.pathname, &context);
|
||||
if (index < 0) {
|
||||
log_warn("Watched module: %s not found.\n", event.pathname);
|
||||
}
|
||||
|
||||
sc_log_info("\n");
|
||||
event = hi_file_event_pop(context.filewatcher);
|
||||
}
|
||||
|
||||
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
13
src/logger/logger.c
Normal 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);
|
||||
}
|
||||
@@ -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_
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user