Collect dynamic symbols from patch

This commit is contained in:
2025-04-21 23:55:14 +03:00
parent 26752683a1
commit 57b47cec64
9 changed files with 269 additions and 52 deletions

View File

@@ -9,5 +9,6 @@ static inline u32 has_mask(u32 flags, u32 mask) { return flags & mask; }
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define ARRLEN(A) (sizeof((A)) / (sizeof((A)[0])))
#define HIOK(res) ((res) == HILOAD_OK)
#endif // COMMON_H_

View File

@@ -184,7 +184,7 @@ hiFileWatcher *hi_file_watcher_create() {
memset(fw, 0, sizeof(hiFileWatcher));
if (fw) {
if (!HILOADRES(file_watcher_ctx_init(&fw->context))) {
if (!HIOK(file_watcher_ctx_init(&fw->context))) {
sc_log_error("Failed to initialize watch paths\n");
if (fw->context.fd == -1) {
sc_log_error("Couldn't initialize inotify\n");
@@ -213,7 +213,7 @@ HiloadResult hi_file_watcher_add(struct hiFileWatcher *fw, const char *filename,
mtx_lock(&fw->mutex);
if (!HILOADRES(file_watch_add(&fw->context, flags, filename))) {
if (!HIOK(file_watch_add(&fw->context, flags, filename))) {
mtx_unlock(&fw->mutex);
return HILOAD_FAIL;
}
@@ -240,7 +240,7 @@ HiloadResult hi_file_watcher_remove(struct hiFileWatcher *fw,
}
mtx_lock(&fw->mutex);
if (!HILOADRES(file_watch_remove(&fw->context, filename))) {
if (!HIOK(file_watch_remove(&fw->context, filename))) {
mtx_unlock(&fw->mutex);
return HILOAD_FAIL;
}

View File

@@ -1,6 +1,7 @@
#include "hiload/hiload.h"
#include "array/array.h"
#include "common.h"
#include "filewatcher/filewatch_context.h"
#include "filewatcher/filewatcher.h"
#include "logger/logger.h"
@@ -8,7 +9,6 @@
#include "moduler/moduler.h"
#include "string/string.h"
#include "symbols.h"
#include "types.h"
#include <assert.h>
#include <dlfcn.h>
@@ -71,8 +71,8 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
sc_array_at(&context.enabled_modules, i) = module.name;
// Add filewatcher
if (!HILOADRES(hi_file_watcher_add(context.filewatcher, modpath,
HI_FILE_ALL_EVENTS))) {
if (!HIOK(hi_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);
@@ -81,7 +81,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
}
} else {
module.name = strdup(modname);
log_error("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;
@@ -95,7 +95,7 @@ static void module_infos_free(HiModuleArray *modules) {
return;
for (size_t i = 0; i < sc_array_size(modules); i++) {
free((char*)sc_array_at(modules, i).name);
free((char *)sc_array_at(modules, i).name);
}
free(modules);
@@ -115,7 +115,8 @@ HiloadResult gather_module_infos(HiModuleArray *modules) {
return HILOAD_OK;
}
static HiModuleData *get_module_by_path(const char *path, HiModuleArray *modules) {
static HiModuleData *get_module_by_path(const char *path,
HiModuleArray *modules) {
for (size_t i = 0; i < sc_array_size(modules); i++) {
HiModuleData *module = &sc_array_at(modules, i);
@@ -149,8 +150,8 @@ static void handle_events(struct hiFileWatcher *fw, HiModuleArray *modules) {
}
}
static const char* find_string_from_array(const char *needle,
const struct sc_array_str *haystack) {
static const char *find_string_from_array(const char *needle,
const struct sc_array_str *haystack) {
for (size_t i = 0; i < sc_array_size(haystack); i++) {
if (strcmp(needle, sc_array_at(haystack, i)) == 0) {
@@ -171,11 +172,12 @@ static HiloadResult reload_dirty_modules(HiloadContext *context) {
if (module->state == 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);
const char *module_name =
find_string_from_array(module->name, &context->enabled_modules);
if (module_name) {
log_info("Reloading %s...\n", module_name);
if (moduler_reload(module, &context->memory_regions) != HILOAD_OK) {
if (!HIOK(moduler_reload(module, &context->memory_regions))) {
ret = HILOAD_FAIL;
log_error("Failed loading: %s\n", module->name);
}
@@ -218,7 +220,7 @@ int hi_init(unsigned n, const char **enabled_modules) {
}
HiloadResult re = gather_module_infos(&context.modules);
if (re != HILOAD_OK) {
if (re != HILOAD_OK) {
log_error("Failed to gather module infos.\n");
return 1;
}

View File

@@ -4,17 +4,43 @@
#include "types.h"
#include <fcntl.h>
#include <gelf.h>
#include <libelf.h>
#include <unistd.h>
void *hi_elf_load_module(void *address, size_t n) {
void *hi_elf_find_dynamic_segment(void *module_base, size_t n, Elf **elf_ret) {
Elf *elf = elf_memory(address, n);
Elf_Kind modkind = elf_kind(elf);
log_debug("kind: %u\n", modkind);
Elf *elf = elf_memory(module_base, n);
elf_end(elf);
return address;
size_t phdrnum = 0;
int err = elf_getphdrnum(elf, &phdrnum);
if (err == -1) {
log_error("%s\n", elf_errmsg(elf_errno()));
return NULL;
}
void *dyn_addr = NULL;
for (size_t i=0; i < phdrnum; ++i) {
GElf_Phdr phdr;
if (gelf_getphdr(elf, i, &phdr) != &phdr) {
log_error("Failed to find program headers: %s\n", elf_errmsg(elf_errno()));
continue;
}
if (phdr.p_type == PT_DYNAMIC) {
dyn_addr = module_base + phdr.p_vaddr;
break;
}
}
if (elf_ret) {
*elf_ret = elf;
} else {
elf_end(elf);
}
return dyn_addr;
}
void hi_elf_print_module_from_memory(void *address, size_t size) {
@@ -32,7 +58,7 @@ void hi_elf_print_module_from_memory(void *address, size_t size) {
for (size_t i = 0; i < phdrnum; ++i) {
Elf64_Phdr *p = phdr + i;
log_debug("segment type: %s\n", segment_type_to_str(p->p_type));
log_debug("segment type: %s\n", hi_elf_segtostr(p->p_type));
size_t segment_size = p->p_memsz;
void *segment_start = address + p->p_vaddr;
@@ -53,7 +79,7 @@ void hi_elf_print_module_from_memory(void *address, size_t size) {
if (p->p_type == PT_DYNAMIC) {
Elf64_Dyn *dyn = (Elf64_Dyn *)segment_start;
while ((void *)dyn < segment_end) {
log_debug(" dyn type: %s\n", dyn_type_to_str(dyn->d_tag));
log_debug(" dyn type: %s\n", hi_elf_dyntostr(dyn->d_tag));
if (dyn->d_tag == DT_STRTAB) {
strtab = (void *)dyn->d_un.d_ptr;
@@ -101,7 +127,7 @@ void hi_elf_print_module_from_memory(void *address, size_t size) {
case (type): \
return #type
const char *dyn_type_to_str(unsigned type) {
const char *hi_elf_dyntostr(unsigned type) {
// clang-format off
switch (type) {
TYPE_TO_STR(DT_NULL);
@@ -184,7 +210,7 @@ const char *dyn_type_to_str(unsigned type) {
// clang-format on
}
const char *segment_type_to_str(unsigned type) {
const char *hi_elf_segtostr(unsigned type) {
// clang-format off
switch (type) {
TYPE_TO_STR(PT_NULL);

View File

@@ -6,10 +6,9 @@
#include <libelf.h>
#include <gelf.h>
void *hi_elf_load_module(void *address, size_t n);
void hi_elf_print_module_from_memory(void *address, size_t size);
void *hi_elf_find_dynamic_segment(void *module_base, size_t n, Elf **elf);
const char *dyn_type_to_str(unsigned type);
const char *segment_type_to_str(unsigned type);
const char *hi_elf_dyntostr(unsigned type);
const char *hi_elf_segtostr(unsigned type);
#endif

View File

@@ -5,24 +5,164 @@
#include "memory.h"
#include "moduler/elf.h"
#include "string/string.h"
#include "symbols.h"
#include "types.h"
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <gelf.h>
#include <libelf.h>
#include <link.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <unistd.h>
static HiloadResult moduler_apply_patch(void *address, size_t n) {
static HiloadResult gather_patchable_symbols(struct sc_array_sym *symbols,
const char *patch_name,
void *module_base) {
sc_array_clear(symbols);
HiloadResult ret = HILOAD_FAIL;
Elf *elf = elf_memory(address, n);
int patchfd = open(patch_name, O_RDONLY);
if (patchfd == -1) {
log_error("Failed to open %s: %s\n", patch_name, strerror(errno));
return HILOAD_FAIL;
}
if (elf_version(EV_CURRENT) == EV_NONE) {
log_error("Failed to initialize libelf\n");
close(patchfd);
return HILOAD_FAIL;
}
Elf *elf = elf_begin(patchfd, ELF_C_READ, NULL);
if (!elf) {
log_error("Failed to open elf file: %s\n", elf_errmsg(elf_errno()));
goto cleanup;
}
if (elf_kind(elf) != ELF_K_ELF) {
log_error("Not a valid ELF file\n");
goto cleanup;
}
// Get ELF header
GElf_Ehdr ehdr;
if (gelf_getehdr(elf, &ehdr) == NULL) {
log_error("Failed to get ELF header: %s\n", elf_errmsg(elf_errno()));
goto cleanup;
}
// Iterate through sections to find symbol tables
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
GElf_Shdr shdr;
if (gelf_getshdr(scn, &shdr) != &shdr) {
log_error("Failed to get section header: %s\n", elf_errmsg(elf_errno()));
continue;
}
// Look for dynamic symbol table (SHT_DYNSYM)
if (shdr.sh_type == SHT_DYNSYM) {
// Get the string table for symbol names
Elf_Scn *str_scn = elf_getscn(elf, shdr.sh_link);
if (!str_scn) {
log_error("Failed to get string table section: %s\n",
elf_errmsg(elf_errno()));
continue;
}
GElf_Shdr str_shdr;
if (gelf_getshdr(str_scn, &str_shdr) != &str_shdr) {
log_error("Failed to get string table header: %s\n",
elf_errmsg(elf_errno()));
continue;
}
// Get string table data
Elf_Data *str_data = elf_getdata(str_scn, NULL);
if (!str_data) {
log_error("Failed to get string table data: %s\n",
elf_errmsg(elf_errno()));
continue;
}
// Get symbol table data
Elf_Data *sym_data = elf_getdata(scn, NULL);
if (!sym_data) {
log_error("Failed to get symbol table data: %s\n",
elf_errmsg(elf_errno()));
continue;
}
// Calculate number of symbols
size_t sym_count = shdr.sh_size / shdr.sh_entsize;
for (size_t i = 0; i < sym_count; ++i) {
GElf_Sym sym;
if (gelf_getsym(sym_data, i, &sym) != &sym) {
log_error("Failed to get symbol: %s\n", elf_errmsg(elf_errno()));
continue;
}
const char *name = (const char *)(str_data->d_buf) + sym.st_name;
if (sym.st_name == 0 || strlen(name) == 0) {
continue; // Skip unnamed symbols
}
// Calculate actual address (base + offset)
void *sym_addr = (void *)((uintptr_t)module_base + sym.st_value);
HiSymbolBind binding = symbol_bind_from_efi(GELF_ST_BIND(sym.st_info));
HiSymbolType type = symbol_type_from_efi(GELF_ST_TYPE(sym.st_info));
if (binding == HI_SYMBOL_BIND_GLOBAL) {
HiSymbol hisym = {.name = strdup(name),
.binding = binding,
.type = type,
.address = sym_addr};
sc_array_add(symbols, hisym);
}
}
}
}
hi_elf_print_module_from_memory(address, n);
ret = HILOAD_OK;
cleanup:
elf_end(elf);
close(patchfd);
return ret;
}
static HiloadResult moduler_apply_module_patch(const char *module_name, const char *patch_name,
struct sc_array_memreg *memregs) {
MemoryRegionSpan patch_memory = memory_get_module_span(memregs, patch_name);
void *patch_base = (void *)patch_memory.region_start;
HiSymbols symbols;
symbol_init_symbols(&symbols);
HiloadResult ret = gather_patchable_symbols(&symbols, patch_name, patch_base);
if (!HIOK(ret)) {
log_error("Failed to gather symbols for %s\n", patch_name);
return HILOAD_FAIL;
}
MemoryRegionSpan module_memory = memory_get_module_span(memregs, module_name);
void *module_base = (void *)module_memory.region_start;
size_t module_size = module_memory.region_end - module_memory.region_start;
Elf *elf = NULL;
GElf_Phdr *dyn_sct = hi_elf_find_dynamic_segment(module_base, module_size, &elf);
(void)dyn_sct;
// TODO: cont
symbol_term_symbols(&symbols);
return ret;
}
@@ -34,11 +174,11 @@ HiloadResult moduler_reload(HiModuleData *module,
log_debugv("Module: %s - [%p, %p]\n", module->name, memspan.region_start,
memspan.region_end);
dlerror();
dlerror(); // clear old errors
char patch_name[512];
size_t written =
hi_strncat_buf(sizeof(patch_name), patch_name, module->name, ".patch");
if (!written) {
if (written == 0) {
log_error("Failed to concat %s and %s\n", module->name, ".patch");
return HILOAD_FAIL;
}
@@ -52,13 +192,14 @@ HiloadResult moduler_reload(HiModuleData *module,
return HILOAD_FAIL;
}
// refresh before using
read_memory_maps_self(memregs);
memspan = memory_get_module_span(memregs, patch_name);
void *patch_address = (void *)memspan.region_start;
log_debug("patch address: %p\n", patch_address);
moduler_apply_patch(patch_address, memspan.region_end - memspan.region_start);
moduler_apply_module_patch(module->name, patch_name, memregs);
module->state = HI_MODULE_STATE_CLEAN;
return HILOAD_OK;

View File

@@ -1,12 +1,29 @@
#include "symbols.h"
#include <stdlib.h>
#include <elf.h>
void hi_free_symbol_info(SymbolInfos *symbols) {
for (size_t i = 0; i < symbols->names.size; i++) {
free((void *)symbols->names.elems[i]);
HiSymbolBind symbol_bind_from_efi(u32 efi_bind) {
// clang-format off
switch (efi_bind) {
case STB_LOCAL: return HI_SYMBOL_BIND_LOCAL;
case STB_GLOBAL: return HI_SYMBOL_BIND_GLOBAL;
case STB_WEAK: return HI_SYMBOL_BIND_WEAK;
}
sc_array_term(&symbols->names);
sc_array_term(&symbols->addresses);
// clang-format on
return ~0u;
}
HiSymbolType symbol_type_from_efi(u32 efi_type) {
// clang-format off
switch (efi_type) {
case STT_NOTYPE: return HI_SYMBOL_TYPE_NOTYPE; /* Symbol type is unspecified */
case STT_OBJECT: return HI_SYMBOL_TYPE_OBJECT; /* Symbol is a data object */
case STT_FUNC: return HI_SYMBOL_TYPE_FUNC; /* Symbol is a code object */
case STT_SECTION: return HI_SYMBOL_TYPE_SECTION; /* Symbol associated with a section */
case STT_FILE: return HI_SYMBOL_TYPE_FILE; /* Symbol's name is file name */
case STT_COMMON: return HI_SYMBOL_TYPE_COMMON; /* Symbol is a common data object */
case STT_TLS: return HI_SYMBOL_TYPE_TLS; /* Symbol is thread-local data object*/
}
// clang-format on
return ~0u;
}

View File

@@ -1,20 +1,52 @@
#ifndef SYMBOLS_H_
#define SYMBOLS_H_
#include "memory.h"
#include "array/array.h"
#include "array/sc_array.h"
#include "types.h"
#include <link.h>
#include <stddef.h>
#include <stdint.h>
typedef enum {
HI_SYMBOL_BIND_LOCAL,
HI_SYMBOL_BIND_GLOBAL,
HI_SYMBOL_BIND_WEAK,
} HiSymbolBind;
typedef struct {
struct sc_array_str names;
struct sc_array_ptr addresses;
} SymbolInfos;
typedef enum {
HI_SYMBOL_TYPE_NOTYPE,
HI_SYMBOL_TYPE_OBJECT,
HI_SYMBOL_TYPE_FUNC,
HI_SYMBOL_TYPE_SECTION,
HI_SYMBOL_TYPE_FILE,
HI_SYMBOL_TYPE_COMMON,
HI_SYMBOL_TYPE_TLS,
} HiSymbolType;
sc_array_def(SymbolInfos, syms);
typedef struct HiSymbol {
const char *name;
HiSymbolBind binding;
HiSymbolType type;
void *address;
} HiSymbol;
sc_array_def(HiSymbol, sym);
typedef struct sc_array_sym HiSymbols;
void hi_free_symbol_info(SymbolInfos *);
static inline void symbol_free(HiSymbol *symbol) { free((char *)symbol->name); }
static inline void symbol_init_symbols(HiSymbols *symbols) {
sc_array_init(symbols);
}
static inline void symbol_clear_symbols(HiSymbols *symbols) {
for (size_t i = 0; i < sc_array_size(symbols); ++i) {
symbol_free(&sc_array_at(symbols, i));
}
sc_array_clear(symbols);
}
static inline void symbol_term_symbols(HiSymbols *symbols) {
symbol_clear_symbols(symbols);
sc_array_term(symbols);
}
HiSymbolBind symbol_bind_from_efi(u32 efi_bind);
HiSymbolType symbol_type_from_efi(u32 efi_type);
#endif // SYMBOLS_H_

View File

@@ -22,7 +22,6 @@ typedef uint8_t bool8;
typedef uint32_t bool32;
typedef enum { HILOAD_FAIL = 0, HILOAD_OK } HiloadResult;
#define HILOADRES(res) ((res) == HILOAD_OK)
#endif // TYPES_H_