Init. Copied over heload, made a minimal tester.
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.DS_Store
|
||||||
|
.idea
|
||||||
|
*.log
|
||||||
|
tmp/
|
||||||
|
|
||||||
|
**/build
|
||||||
|
**/compile_commands.json
|
||||||
55
CMakeLists.txt
Normal file
55
CMakeLists.txt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.21)
|
||||||
|
project(Hiload)
|
||||||
|
|
||||||
|
# I just like to have this with my tooling
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
# hiload library
|
||||||
|
# ##############
|
||||||
|
|
||||||
|
add_library(hiload SHARED
|
||||||
|
src/hiload.c
|
||||||
|
src/symbols.c
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(TARGET hiload PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_link_libraries(hiload dl)
|
||||||
|
|
||||||
|
# Specify the public headers location
|
||||||
|
target_include_directories(hiload PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # During build
|
||||||
|
$<INSTALL_INTERFACE:include> # When installed
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS hiload
|
||||||
|
EXPORT hiloadTargets
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install header files
|
||||||
|
install(DIRECTORY include/ DESTINATION include)
|
||||||
|
|
||||||
|
# Export the library for find_package()
|
||||||
|
install(EXPORT hiloadTargets
|
||||||
|
FILE hiloadConfig.cmake
|
||||||
|
DESTINATION lib/cmake/hiload
|
||||||
|
)
|
||||||
|
|
||||||
|
export(TARGETS hiload FILE hiloadConfig.cmake)
|
||||||
|
|
||||||
|
# auditor libraries
|
||||||
|
# ###############
|
||||||
|
|
||||||
|
add_library(auditor-x86_64 SHARED
|
||||||
|
src/auditor/auditor-x86_64.c
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS auditor-x86_64
|
||||||
|
EXPORT auditor-x86_64Targets
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
25
include/hiload/hiload.h
Normal file
25
include/hiload/hiload.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef HILOAD_H_
|
||||||
|
#define HILOAD_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Return codes for reload_module
|
||||||
|
typedef enum {
|
||||||
|
RELOAD_SUCCESS = 0,
|
||||||
|
RELOAD_NOT_FOUND,
|
||||||
|
RELOAD_CLOSE_ERROR,
|
||||||
|
RELOAD_OPEN_ERROR
|
||||||
|
} ReloadResult;
|
||||||
|
|
||||||
|
int he_init();
|
||||||
|
void he_deinit();
|
||||||
|
void he_print_module_infos();
|
||||||
|
ReloadResult he_reload_module(const char *module_name);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HILOAD_H_
|
||||||
22
include/hiload/symbols.h
Normal file
22
include/hiload/symbols.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef SYMBOLS_H_
|
||||||
|
#define SYMBOLS_H_
|
||||||
|
|
||||||
|
#include <link.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char **names;
|
||||||
|
void **addresses;
|
||||||
|
size_t count;
|
||||||
|
size_t capacity;
|
||||||
|
} SymbolInfos;
|
||||||
|
|
||||||
|
typedef enum { CREATE_SUCCESS = 0, CREATE_FAILED } CreateResult;
|
||||||
|
|
||||||
|
struct dl_phdr_info;
|
||||||
|
|
||||||
|
CreateResult he_create_symbol_info(SymbolInfos *, struct dl_phdr_info *);
|
||||||
|
void he_free_symbol_info(SymbolInfos *);
|
||||||
|
|
||||||
|
#endif // SYMBOLS_H_
|
||||||
81
src/auditor/auditor-x86_64.c
Normal file
81
src/auditor/auditor-x86_64.c
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <link.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned int la_version(unsigned int version) {
|
||||||
|
printf("la_version(): version = %u; LAV_CURRENT = %u\n", version,
|
||||||
|
LAV_CURRENT);
|
||||||
|
|
||||||
|
return LAV_CURRENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag) {
|
||||||
|
printf("la_objsearch(): name = %s; cookie = %p", name, cookie);
|
||||||
|
printf("; flag = %s\n", (flag == LA_SER_ORIG) ? "LA_SER_ORIG"
|
||||||
|
: (flag == LA_SER_LIBPATH) ? "LA_SER_LIBPATH"
|
||||||
|
: (flag == LA_SER_RUNPATH) ? "LA_SER_RUNPATH"
|
||||||
|
: (flag == LA_SER_DEFAULT) ? "LA_SER_DEFAULT"
|
||||||
|
: (flag == LA_SER_CONFIG) ? "LA_SER_CONFIG"
|
||||||
|
: (flag == LA_SER_SECURE) ? "LA_SER_SECURE"
|
||||||
|
: "???");
|
||||||
|
|
||||||
|
return (char *)name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void la_activity(uintptr_t *cookie, unsigned int flag) {
|
||||||
|
printf("la_activity(): cookie = %p; flag = %s\n", cookie,
|
||||||
|
(flag == LA_ACT_CONSISTENT) ? "LA_ACT_CONSISTENT"
|
||||||
|
: (flag == LA_ACT_ADD) ? "LA_ACT_ADD"
|
||||||
|
: (flag == LA_ACT_DELETE) ? "LA_ACT_DELETE"
|
||||||
|
: "???");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie) {
|
||||||
|
printf("la_objopen(): loading \"%s\"; lmid = %s; cookie=%p\n", map->l_name,
|
||||||
|
(lmid == LM_ID_BASE) ? "LM_ID_BASE"
|
||||||
|
: (lmid == LM_ID_NEWLM) ? "LM_ID_NEWLM"
|
||||||
|
: "???",
|
||||||
|
cookie);
|
||||||
|
|
||||||
|
return LA_FLG_BINDTO | LA_FLG_BINDFROM;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int la_objclose(uintptr_t *cookie) {
|
||||||
|
printf("la_objclose(): %p\n", cookie);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void la_preinit(uintptr_t *cookie) { printf("la_preinit(): %p\n", cookie); }
|
||||||
|
|
||||||
|
uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||||
|
uintptr_t *defcook, unsigned int *flags,
|
||||||
|
const char *symname) {
|
||||||
|
printf("la_symbind64(): symname = %s; sym->st_value = %p\n", symname,
|
||||||
|
sym->st_value);
|
||||||
|
printf(" ndx = %u; flags = %#x", ndx, *flags);
|
||||||
|
printf("; refcook = %p; defcook = %p\n", refcook, defcook);
|
||||||
|
|
||||||
|
return sym->st_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||||
|
uintptr_t *defcook, unsigned int *flags,
|
||||||
|
const char *symname) {
|
||||||
|
printf("la_symbind64(): symname = %s; sym->st_value = %p\n", symname,
|
||||||
|
(void*)sym->st_value);
|
||||||
|
printf(" ndx = %u; flags = %#x", ndx, *flags);
|
||||||
|
printf("; refcook = %p; defcook = %p\n", refcook, defcook);
|
||||||
|
|
||||||
|
return sym->st_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf64_Addr la_i86_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx,
|
||||||
|
uintptr_t *refcook, uintptr_t *defcook,
|
||||||
|
La_x86_64_regs *regs, unsigned int *flags,
|
||||||
|
const char *symname, long *framesizep) {
|
||||||
|
printf("la_x86_64_gnu_pltenter(): %s (%p)\n", symname, (void*)sym->st_value);
|
||||||
|
|
||||||
|
return sym->st_value;
|
||||||
|
}
|
||||||
26
src/auditor/auditor.h
Normal file
26
src/auditor/auditor.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef AUDITOR_H_
|
||||||
|
#define AUDITOR_H_
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <link.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
unsigned int la_version(unsigned int version);
|
||||||
|
char *la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag);
|
||||||
|
void la_activity(uintptr_t *cookie, unsigned int flag);
|
||||||
|
unsigned int la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie);
|
||||||
|
unsigned int la_objclose(uintptr_t *cookie);
|
||||||
|
void la_preinit(uintptr_t *cookie);
|
||||||
|
uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||||
|
uintptr_t *defcook, unsigned int *flags,
|
||||||
|
const char *symname);
|
||||||
|
uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||||
|
uintptr_t *defcook, unsigned int *flags,
|
||||||
|
const char *symname);
|
||||||
|
/* Elf32_Addr la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx, */
|
||||||
|
/* uintptr_t *refcook, uintptr_t *defcook, */
|
||||||
|
/* La_i86_regs *regs, unsigned int *flags, */
|
||||||
|
/* const char *symname, long *framesizep); */
|
||||||
|
|
||||||
|
|
||||||
|
#endif // AUDITOR_H_
|
||||||
266
src/hiload.c
Normal file
266
src/hiload.c
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
// Required for dlinfo and other GNU specific linker code
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "hiload/hiload.h"
|
||||||
|
#include "hiload/symbols.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char **names; // Array of library names
|
||||||
|
void **handles; // Array of library handles
|
||||||
|
SymbolInfos *symbols; // Symbol info for modules
|
||||||
|
size_t count; // Number of libraries
|
||||||
|
size_t capacity; // Allocated capacity
|
||||||
|
} ModuleInfos;
|
||||||
|
|
||||||
|
static ModuleInfos *module_infos = 0;
|
||||||
|
|
||||||
|
// Callback function for dl_iterate_phdr
|
||||||
|
static int gather_module_infos_callback(struct dl_phdr_info *info, size_t size,
|
||||||
|
void *data) {
|
||||||
|
ModuleInfos *infos = (ModuleInfos *)data;
|
||||||
|
|
||||||
|
// Resize arrays if needed
|
||||||
|
if (infos->count >= infos->capacity) {
|
||||||
|
infos->capacity *= 2;
|
||||||
|
char **new_names = realloc(infos->names, infos->capacity * sizeof(char *));
|
||||||
|
void **new_handles =
|
||||||
|
realloc(infos->handles, infos->capacity * sizeof(void *));
|
||||||
|
SymbolInfos *new_symbols =
|
||||||
|
realloc(infos->symbols, infos->capacity * sizeof(SymbolInfos));
|
||||||
|
|
||||||
|
if (!new_names || !new_handles || !new_symbols) {
|
||||||
|
return 1; // Stop iteration on error
|
||||||
|
}
|
||||||
|
|
||||||
|
infos->names = new_names;
|
||||||
|
infos->handles = new_handles;
|
||||||
|
infos->symbols = new_symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the module name
|
||||||
|
infos->names[infos->count] = strdup(info->dlpi_name);
|
||||||
|
if (!infos->names[infos->count]) {
|
||||||
|
return 1; // Stop iteration on error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get the handle
|
||||||
|
infos->handles[infos->count] =
|
||||||
|
dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD);
|
||||||
|
|
||||||
|
if (he_create_symbol_info(&infos->symbols[infos->count], info) != CREATE_SUCCESS) {
|
||||||
|
fprintf(stderr, "Failed to create symbol info for %s\n", infos->names[infos->count]);
|
||||||
|
}
|
||||||
|
infos->count++;
|
||||||
|
return 0; // Continue iteration
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_module_infos(ModuleInfos *modules) {
|
||||||
|
if (!modules)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < modules->count; i++) {
|
||||||
|
if (modules->names[i])
|
||||||
|
free(modules->names[i]);
|
||||||
|
he_free_symbol_info(&modules->symbols[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(modules->names);
|
||||||
|
free(modules->handles);
|
||||||
|
free(modules->symbols);
|
||||||
|
free(modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ModuleInfos *gather_shared_libraries(void) {
|
||||||
|
ModuleInfos *result = NULL;
|
||||||
|
|
||||||
|
// Allocate the result structure
|
||||||
|
result = calloc(1, sizeof(ModuleInfos));
|
||||||
|
if (!result) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial capacity
|
||||||
|
result->capacity = 16;
|
||||||
|
result->names = calloc(result->capacity, sizeof(char *));
|
||||||
|
result->handles = calloc(result->capacity, sizeof(void *));
|
||||||
|
result->symbols = calloc(result->capacity, sizeof(SymbolInfos));
|
||||||
|
|
||||||
|
if (!result->names || !result->handles || !result->symbols) {
|
||||||
|
if (result->names)
|
||||||
|
free(result->names);
|
||||||
|
if (result->handles)
|
||||||
|
free(result->handles);
|
||||||
|
if (result->symbols)
|
||||||
|
free(result->symbols);
|
||||||
|
free(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over all shared objects
|
||||||
|
if (dl_iterate_phdr(gather_module_infos_callback, result) != 0) {
|
||||||
|
// Error occurred in callback
|
||||||
|
free_module_infos(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int he_init() {
|
||||||
|
assert(!module_infos);
|
||||||
|
|
||||||
|
ModuleInfos *infos = gather_shared_libraries();
|
||||||
|
if (!infos) {
|
||||||
|
fprintf(stderr, "Failed to gather module infos.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (module_infos) {
|
||||||
|
free_module_infos(module_infos);
|
||||||
|
}
|
||||||
|
module_infos = infos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void he_deinit() { free_module_infos(module_infos); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads a shared library module
|
||||||
|
*
|
||||||
|
* @param modules The ModuleInfos structure containing loaded modules
|
||||||
|
* @param filename The name of the module to reload
|
||||||
|
* @param updated_handle Pointer to store the new handle (can be NULL)
|
||||||
|
* @return ReloadResult indicating success or failure
|
||||||
|
*/
|
||||||
|
static ReloadResult reload_module(ModuleInfos *modules, const char *filename,
|
||||||
|
void **updated_handle) {
|
||||||
|
if (!modules || !filename) {
|
||||||
|
return RELOAD_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
if (modules->names[i] && strcmp(modules->names[i], filename) == 0) {
|
||||||
|
found = 1;
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check if the filename is at the end of the path
|
||||||
|
if (modules->names[i]) {
|
||||||
|
const char *basename = strrchr(modules->names[i], '/');
|
||||||
|
if (basename && strcmp(basename + 1, filename) == 0) {
|
||||||
|
found = 1;
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return RELOAD_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the full path
|
||||||
|
char *fullpath = strdup(modules->names[index]);
|
||||||
|
if (!fullpath) {
|
||||||
|
return RELOAD_OPEN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the old handle
|
||||||
|
if (modules->handles[index]) {
|
||||||
|
if (dlclose(modules->handles[index]) != 0) {
|
||||||
|
free(fullpath);
|
||||||
|
return RELOAD_CLOSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the module again with RTLD_NOW
|
||||||
|
void *new_handle = dlopen(fullpath, RTLD_NOW);
|
||||||
|
if (!new_handle) {
|
||||||
|
fprintf(stderr, "Error reloading module: %s\n", dlerror());
|
||||||
|
free(fullpath);
|
||||||
|
return RELOAD_OPEN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the handle in our structure
|
||||||
|
modules->handles[index] = new_handle;
|
||||||
|
|
||||||
|
// If the caller wants the new handle, provide it
|
||||||
|
if (updated_handle) {
|
||||||
|
*updated_handle = new_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fullpath);
|
||||||
|
return RELOAD_SUCCESS;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Helper function to print the result of a module reload
|
||||||
|
*/
|
||||||
|
static void print_reload_result(ReloadResult result, const char *filename) {
|
||||||
|
switch (result) {
|
||||||
|
case RELOAD_SUCCESS:
|
||||||
|
printf("Successfully reloaded module: %s\n", filename);
|
||||||
|
break;
|
||||||
|
case RELOAD_NOT_FOUND:
|
||||||
|
printf("Module not found: %s\n", filename);
|
||||||
|
break;
|
||||||
|
case RELOAD_CLOSE_ERROR:
|
||||||
|
printf("Error closing module: %s\n", filename);
|
||||||
|
break;
|
||||||
|
case RELOAD_OPEN_ERROR:
|
||||||
|
printf("Error reopening module: %s\n", filename);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown error reloading module: %s\n", filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReloadResult he_reload_module(const char *module_name) {
|
||||||
|
assert(module_infos);
|
||||||
|
|
||||||
|
void *new_handle = NULL;
|
||||||
|
ReloadResult result = reload_module(module_infos, module_name, &new_handle);
|
||||||
|
print_reload_result(result, module_name);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void he_print_module_infos() {
|
||||||
|
assert(module_infos);
|
||||||
|
|
||||||
|
const ModuleInfos *modules = module_infos;
|
||||||
|
if (!modules) {
|
||||||
|
printf("No module information available.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Found %zu loaded modules:\n\n", modules->count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < modules->count; i++) {
|
||||||
|
// Get handle information where possible
|
||||||
|
Dl_info info = {0};
|
||||||
|
int has_info = 0;
|
||||||
|
|
||||||
|
printf("%s: %p\n", modules->names[i], modules->handles[i]);
|
||||||
|
if (modules->symbols) {
|
||||||
|
for (int j = 0; j < modules->symbols->count; j++) {
|
||||||
|
const void *addr = modules->symbols->addresses[j];
|
||||||
|
const char *name = modules->symbols->names[j];
|
||||||
|
printf(" %p: %s\n", addr, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/symbols.c
Normal file
115
src/symbols.c
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include "hiload/symbols.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers and populates symbols, given a dynamic module info
|
||||||
|
*
|
||||||
|
* Will clear and free the given SymbolInfo struct. Allocates enough memory to
|
||||||
|
* hold found symbols.
|
||||||
|
*/
|
||||||
|
CreateResult he_create_symbol_info(SymbolInfos *symbols,
|
||||||
|
struct dl_phdr_info *info) {
|
||||||
|
|
||||||
|
if (!symbols)
|
||||||
|
return CREATE_FAILED;
|
||||||
|
|
||||||
|
he_free_symbol_info(symbols);
|
||||||
|
|
||||||
|
for (int i = 0; i < info->dlpi_phnum; i++) {
|
||||||
|
const ElfW(Phdr) *phdr = &info->dlpi_phdr[i];
|
||||||
|
|
||||||
|
// Look for the dynamic segment
|
||||||
|
if (phdr->p_type != PT_DYNAMIC)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("Dynamic Header:\n");
|
||||||
|
printf("p_type: %u\n", phdr->p_type);
|
||||||
|
printf("p_flags: %u\n", phdr->p_flags);
|
||||||
|
printf("p_offset: %#06x\n", phdr->p_offset);
|
||||||
|
printf("p_vaddr: %#06x\n", phdr->p_vaddr);
|
||||||
|
printf("p_paddr: %#06x\n", phdr->p_paddr);
|
||||||
|
printf("p_filesz: %zu\n", phdr->p_filesz);
|
||||||
|
printf("p_memsz: %zu\n", phdr->p_memsz);
|
||||||
|
printf("p_align: %zu\n", phdr->p_align);
|
||||||
|
|
||||||
|
const ElfW(Dyn) *dyn = (const ElfW(Dyn) *)(info->dlpi_addr + phdr->p_vaddr);
|
||||||
|
const char *strtab = NULL;
|
||||||
|
const ElfW(Sym) *symtab = NULL;
|
||||||
|
size_t symtab_size = 0;
|
||||||
|
size_t strtab_size = 0;
|
||||||
|
|
||||||
|
// Parse the dynamic table
|
||||||
|
for (; dyn->d_tag != DT_NULL; dyn++) {
|
||||||
|
if (dyn->d_tag == DT_STRTAB) {
|
||||||
|
strtab = (const char *)(dyn->d_un.d_ptr);
|
||||||
|
} else if (dyn->d_tag == DT_STRSZ) {
|
||||||
|
strtab_size = dyn->d_un.d_val;
|
||||||
|
} else if (dyn->d_tag == DT_SYMTAB) {
|
||||||
|
symtab = (const ElfW(Sym) *)(dyn->d_un.d_ptr);
|
||||||
|
} else if (dyn->d_tag == DT_SYMENT) {
|
||||||
|
symtab_size = dyn->d_un.d_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we found the symbol and string tables
|
||||||
|
if (!strtab || !symtab || strtab_size == 0 || symtab_size == 0) {
|
||||||
|
fprintf(stderr, "Failed to find symbol or string table in %s\n",
|
||||||
|
info->dlpi_name);
|
||||||
|
return CREATE_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols->capacity = symtab_size / sizeof(ElfW(Sym));
|
||||||
|
|
||||||
|
symbols->names = calloc(symbols->capacity, sizeof(char *));
|
||||||
|
if (!symbols->names) {
|
||||||
|
fprintf(stderr, "Failed to allocate memory for symbol names.\n");
|
||||||
|
return CREATE_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols->addresses = calloc(symbols->capacity, sizeof(void *));
|
||||||
|
if (!symbols->addresses) {
|
||||||
|
fprintf(stderr, "Failed to allocate memory for symbol addresses.\n");
|
||||||
|
return CREATE_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the symbol table
|
||||||
|
for (const ElfW(Sym) *sym = symtab;
|
||||||
|
(const char *)sym < (const char *)symtab + symtab_size; sym++) {
|
||||||
|
if (ELF64_ST_TYPE(sym->st_info) == STT_FUNC ||
|
||||||
|
ELF64_ST_TYPE(sym->st_info) == STT_OBJECT) {
|
||||||
|
const char *name = strdup(&strtab[sym->st_name]);
|
||||||
|
void *address = (void *)(info->dlpi_addr + sym->st_value);
|
||||||
|
|
||||||
|
// Store the symbol information in the struct of arrays
|
||||||
|
if (symbols->count < symbols->capacity) {
|
||||||
|
symbols->names[symbols->count] = (char *)name;
|
||||||
|
symbols->addresses[symbols->count] = address;
|
||||||
|
symbols->count++;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Symbol table capacity exceeded!\n");
|
||||||
|
return CREATE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CREATE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void he_free_symbol_info(SymbolInfos *symbols) {
|
||||||
|
for (size_t i = 0; i < symbols->count; i++) {
|
||||||
|
free(symbols->names[i]);
|
||||||
|
}
|
||||||
|
free(symbols->names);
|
||||||
|
free(symbols->addresses);
|
||||||
|
symbols->count = 0;
|
||||||
|
symbols->capacity = 0;
|
||||||
|
}
|
||||||
13
test/manual/CMakeLists.txt
Normal file
13
test/manual/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
project(Minimal)
|
||||||
|
|
||||||
|
set( CMAKE_EXPORT_COMPILE_COMMANDS ON )
|
||||||
|
add_executable(minimal
|
||||||
|
minimal.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(mini SHARED
|
||||||
|
minimal_lib.cpp
|
||||||
|
minimal_lib.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(minimal mini)
|
||||||
18
test/manual/minimal.cpp
Normal file
18
test/manual/minimal.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include "minimal_lib.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
int modified = -1;
|
||||||
|
while (modified != 0) {
|
||||||
|
modified = minimal_lib::getModified(5);
|
||||||
|
printf("getModified(5): %d\n", modified);
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7
test/manual/minimal_lib.cpp
Normal file
7
test/manual/minimal_lib.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "minimal_lib.h"
|
||||||
|
|
||||||
|
namespace minimal_lib {
|
||||||
|
|
||||||
|
int getModified(int x) { return x + 1; }
|
||||||
|
|
||||||
|
} // namespace minimal_lib
|
||||||
11
test/manual/minimal_lib.h
Normal file
11
test/manual/minimal_lib.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef MINIMAL_LIB_H_
|
||||||
|
#define MINIMAL_LIB_H_
|
||||||
|
|
||||||
|
namespace minimal_lib {
|
||||||
|
|
||||||
|
static int value = 5;
|
||||||
|
|
||||||
|
int getModified(int x);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // MINIMAL_LIB_H_
|
||||||
Reference in New Issue
Block a user