mallailua
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
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])))
|
||||
|
||||
#endif // COMMON_H_
|
||||
|
||||
123
src/files.c
123
src/files.c
@@ -2,7 +2,14 @@
|
||||
|
||||
#include "logger/logger.h"
|
||||
#include "string/string.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef HI_FILE_BUFFER_SIZE
|
||||
#define HI_FILE_BUFFER_SIZE 4096
|
||||
#endif
|
||||
|
||||
char *hi_file_to_str_dyn(const char *filename) {
|
||||
|
||||
@@ -14,3 +21,119 @@ char *hi_file_to_str_dyn(const char *filename) {
|
||||
return s;
|
||||
}
|
||||
|
||||
HiFileType hi_file_interpret_as_type(const char *path) {
|
||||
const char *pathname_end = path + strlen(path);
|
||||
char last_char = *(pathname_end - 1);
|
||||
bool as_dir = (last_char == '/') || (last_char == '\\');
|
||||
return as_dir ? HI_FILE_TYPE_DIR : HI_FILE_TYPE_FILE;
|
||||
}
|
||||
|
||||
const char *hi_file_name_from_path(const char *path) {
|
||||
const char *filename = path;
|
||||
|
||||
// Find the last directory separator
|
||||
const char *last_slash = strrchr(path, '/');
|
||||
const char *last_backslash = strrchr(path, '\\');
|
||||
|
||||
// Determine which separator was found last (if any)
|
||||
if (last_slash && (!last_backslash || last_slash > last_backslash)) {
|
||||
filename = last_slash + 1;
|
||||
} else if (last_backslash) {
|
||||
filename = last_backslash + 1;
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
HiloadResult hi_file_copy(const char *srcname, const char *destination) {
|
||||
|
||||
HiloadResult ret = HILOAD_FAIL;
|
||||
|
||||
FILE *src = fopen(srcname, "rb");
|
||||
if (src == NULL) {
|
||||
log_error("Couldn't open file: %s for copy\n", srcname);
|
||||
return HILOAD_FAIL;
|
||||
}
|
||||
|
||||
char buf[512];
|
||||
|
||||
const char *dstname = destination;
|
||||
|
||||
HiFileType dst_type = hi_file_interpret_as_type(destination);
|
||||
if (dst_type == HI_FILE_TYPE_DIR) {
|
||||
hi_strncat_buf(sizeof(buf), buf, destination,
|
||||
hi_file_name_from_path(srcname));
|
||||
dstname = buf;
|
||||
}
|
||||
|
||||
FILE *dst = fopen(dstname, "wb");
|
||||
if (dst == NULL) {
|
||||
log_error("Failed to open destination: %s\n", dstname);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
char buffer[HI_FILE_BUFFER_SIZE];
|
||||
size_t bytes_read = 0;
|
||||
while ((bytes_read = fread(buffer, 1, sizeof buffer, src)) > 0) {
|
||||
if (fwrite(buffer, 1, bytes_read, dst) != bytes_read) {
|
||||
log_error("Error writing to destination: %s\n", dstname);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(src)) {
|
||||
log_error("Error reading from source: %s\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = HILOAD_OK;
|
||||
|
||||
cleanup:
|
||||
if (src) fclose(src);
|
||||
if (dst) fclose(dst);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check file type from path.
|
||||
*
|
||||
* TAG: posix
|
||||
*/
|
||||
HiFileType hi_file_type(const char *path) {
|
||||
struct stat path_stat;
|
||||
int err = stat(path, &path_stat);
|
||||
if (err == -1) {
|
||||
if (errno == ENOENT) {
|
||||
// Doesn't exist, don't count as error
|
||||
return HI_FILE_TYPE_NONE;
|
||||
}
|
||||
log_error("Opening file failed: %s\n", strerror(errno));
|
||||
return HI_FILE_TYPE_NONE;
|
||||
}
|
||||
|
||||
if (S_ISREG(path_stat.st_mode)) {
|
||||
return HI_FILE_TYPE_FILE;
|
||||
}
|
||||
if (S_ISDIR(path_stat.st_mode)) {
|
||||
return HI_FILE_TYPE_DIR;
|
||||
}
|
||||
if (S_ISCHR(path_stat.st_mode)) {
|
||||
return HI_FILE_TYPE_CHR;
|
||||
}
|
||||
if (S_ISBLK(path_stat.st_mode)) {
|
||||
return HI_FILE_TYPE_BLK;
|
||||
}
|
||||
if (S_ISFIFO(path_stat.st_mode)) {
|
||||
return HI_FILE_TYPE_FIFO;
|
||||
}
|
||||
if (S_ISLNK(path_stat.st_mode)) {
|
||||
return HI_FILE_TYPE_LNK;
|
||||
}
|
||||
if (S_ISSOCK(path_stat.st_mode)) {
|
||||
return HI_FILE_TYPE_SOCK;
|
||||
}
|
||||
|
||||
return HI_FILE_TYPE_NONE;
|
||||
}
|
||||
|
||||
|
||||
27
src/files.h
27
src/files.h
@@ -1,6 +1,21 @@
|
||||
#ifndef FILES_H_
|
||||
#define FILES_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef enum {
|
||||
HI_FILE_TYPE_FILE = 0,
|
||||
HI_FILE_TYPE_DIR,
|
||||
HI_FILE_TYPE_CHR,
|
||||
HI_FILE_TYPE_BLK,
|
||||
HI_FILE_TYPE_FIFO,
|
||||
HI_FILE_TYPE_LNK,
|
||||
HI_FILE_TYPE_SOCK,
|
||||
|
||||
HI_FILE_TYPE_COUNT,
|
||||
HI_FILE_TYPE_NONE,
|
||||
} HiFileType;
|
||||
|
||||
/**
|
||||
* Read file dynamically to a string
|
||||
*
|
||||
@@ -8,7 +23,19 @@
|
||||
* with no size. The realistic optimum case contains two allocations, one for
|
||||
* the initial memory and a reallocation to match the string size.
|
||||
*/
|
||||
|
||||
char *hi_file_to_str_dyn(const char *filename);
|
||||
|
||||
/**
|
||||
* Copy file \p filename to \p dest
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
HiloadResult hi_file_copy(const char *filename, const char *dest);
|
||||
|
||||
HiFileType hi_file_type(const char *path);
|
||||
|
||||
const char *hi_file_name_from_path(const char *path);
|
||||
|
||||
#endif // FILES_H_
|
||||
|
||||
@@ -211,6 +211,7 @@ int hi_init(unsigned n, const char **enabled_modules) {
|
||||
sc_array_add(&context.enabled_modules, module_name);
|
||||
}
|
||||
|
||||
sc_array_init(&context.memory_regions);
|
||||
if (read_memory_maps_self(&context.memory_regions) != HILOAD_OK) {
|
||||
log_error("Could not populate program memory maps.\n");
|
||||
return HILOAD_FAIL;
|
||||
|
||||
26
src/memory.c
26
src/memory.c
@@ -31,8 +31,7 @@ HiloadResult memory_find_region(uptr ptr, struct sc_array_memreg *const regions,
|
||||
}
|
||||
|
||||
HiloadResult read_memory_maps_self(struct sc_array_memreg *regions) {
|
||||
sc_array_clear(regions);
|
||||
sc_array_init(regions);
|
||||
memory_clear_memregs(regions);
|
||||
|
||||
char *maps_str = hi_file_to_str_dyn("/proc/self/maps");
|
||||
if (!maps_str)
|
||||
@@ -103,10 +102,31 @@ memory_get_module_span(const struct sc_array_memreg *const regions,
|
||||
}
|
||||
} else {
|
||||
// we passed the module regions
|
||||
if (end > 0) break;
|
||||
if (end > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(start < ~0ull && end > 0);
|
||||
return (MemoryRegionSpan){.region_start = start, .region_end = end};
|
||||
}
|
||||
|
||||
void memory_clear_memregs(struct sc_array_memreg *regions) {
|
||||
for (size_t i = 0; i < sc_array_size(regions); i++) {
|
||||
memory_free_memreg(&sc_array_at(regions, i));
|
||||
}
|
||||
sc_array_clear(regions);
|
||||
}
|
||||
|
||||
void memory_term_memregs(struct sc_array_memreg *regions) {
|
||||
for (size_t i = 0; i < sc_array_size(regions); i++) {
|
||||
memory_free_memreg(&sc_array_at(regions, i));
|
||||
}
|
||||
sc_array_term(regions);
|
||||
}
|
||||
|
||||
void memory_free_memreg(MemoryRegion *reg) {
|
||||
if (reg) {
|
||||
free((char *)reg->pathname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,15 @@ typedef struct {
|
||||
const char *pathname;
|
||||
u32 permission; // enum MemoryPermissions
|
||||
} MemoryRegion;
|
||||
|
||||
sc_array_def(MemoryRegion, memreg);
|
||||
|
||||
// Free memory and init to zero
|
||||
void memory_term_memregs(struct sc_array_memreg *regions);
|
||||
// Doesn't free underlying array memory, only for each region
|
||||
void memory_clear_memregs(struct sc_array_memreg *regions);
|
||||
// Free child memory
|
||||
void memory_free_memreg(MemoryRegion *reg);
|
||||
|
||||
/* A pointer that can be used to place the memory regions into. Clears regions
|
||||
* before use, but uses the same buffer. */
|
||||
HiloadResult read_memory_maps_self(struct sc_array_memreg *regions);
|
||||
|
||||
@@ -7,18 +7,14 @@
|
||||
#include <libelf.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void *hi_elf_load_module(const char *filename) {
|
||||
int fd = open(filename, O_RDONLY);
|
||||
|
||||
Elf *elf = elf_begin(fd, ELF_C_READ, NULL);
|
||||
void *hi_elf_load_module(void *address, size_t n) {
|
||||
|
||||
Elf *elf = elf_memory(address, n);
|
||||
Elf_Kind modkind = elf_kind(elf);
|
||||
log_debug("kind: %u\n", modkind);
|
||||
|
||||
uptr modbase = elf_getbase(elf);
|
||||
|
||||
close(fd);
|
||||
return (void*)modbase;
|
||||
elf_end(elf);
|
||||
return address;
|
||||
}
|
||||
|
||||
void hi_elf_print_module_from_memory(void *address, size_t size) {
|
||||
@@ -36,7 +32,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_debugv("segment type: %s\n", segment_type_to_str(p->p_type));
|
||||
log_debug("segment type: %s\n", segment_type_to_str(p->p_type));
|
||||
|
||||
size_t segment_size = p->p_memsz;
|
||||
void *segment_start = address + p->p_vaddr;
|
||||
@@ -57,7 +53,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_debugv(" dyn type: %s\n", dyn_type_to_str(dyn->d_tag));
|
||||
log_debug(" dyn type: %s\n", dyn_type_to_str(dyn->d_tag));
|
||||
|
||||
if (dyn->d_tag == DT_STRTAB) {
|
||||
strtab = (void *)dyn->d_un.d_ptr;
|
||||
@@ -84,7 +80,7 @@ void hi_elf_print_module_from_memory(void *address, size_t size) {
|
||||
}
|
||||
++dyn;
|
||||
}
|
||||
log_debugv("\nstrtab: %p\n"
|
||||
log_debug("\nstrtab: %p\n"
|
||||
"symtab: %p\n"
|
||||
"strsz: %zu\n"
|
||||
"syment: %zu\n"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#ifndef ELF_H_
|
||||
#define ELF_H_
|
||||
|
||||
// TODO: Move these into .c file after API has found its form
|
||||
#include <elf.h>
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
|
||||
void *hi_elf_load_module(const char* filename);
|
||||
void *hi_elf_load_module(void *address, size_t n);
|
||||
void hi_elf_print_module_from_memory(void *address, size_t size);
|
||||
|
||||
const char *dyn_type_to_str(unsigned type);
|
||||
|
||||
@@ -1,21 +1,64 @@
|
||||
#include "moduler.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "logger/logger.h"
|
||||
#include "memory.h"
|
||||
#include "moduler/elf.h"
|
||||
#include "string/string.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <libelf.h>
|
||||
#include <link.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static HiloadResult moduler_apply_patch(void *address, size_t n) {
|
||||
|
||||
HiloadResult ret = HILOAD_FAIL;
|
||||
|
||||
Elf *elf = elf_memory(address, n);
|
||||
|
||||
hi_elf_print_module_from_memory(address, n);
|
||||
ret = HILOAD_OK;
|
||||
|
||||
elf_end(elf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HiloadResult moduler_reload(HiModuleData *module,
|
||||
const struct sc_array_memreg *const memregs) {
|
||||
struct sc_array_memreg *memregs) {
|
||||
|
||||
MemoryRegionSpan memspan = memory_get_module_span(memregs, module->name);
|
||||
log_debugv("Module: %s - [%p, %p]\n", module->name, memspan.region_start,
|
||||
memspan.region_end);
|
||||
|
||||
void *address = hi_elf_load_module(module->name);
|
||||
log_debug("modaddress: %p\n", address);
|
||||
dlerror();
|
||||
char patch_name[512];
|
||||
size_t written =
|
||||
hi_strncat_buf(sizeof(patch_name), patch_name, module->name, ".patch");
|
||||
if (!written) {
|
||||
log_error("Failed to concat %s and %s\n", module->name, ".patch");
|
||||
return HILOAD_FAIL;
|
||||
}
|
||||
|
||||
log_debug("Opening: %s\n", patch_name);
|
||||
|
||||
void *new_handle = dlopen(patch_name, RTLD_NOW);
|
||||
if (!new_handle) {
|
||||
log_error("Couldn't load: %s\n", dlerror());
|
||||
module->state = HI_MODULE_STATE_CLEAN;
|
||||
return HILOAD_FAIL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
module->state = HI_MODULE_STATE_CLEAN;
|
||||
return HILOAD_OK;
|
||||
|
||||
@@ -24,7 +24,6 @@ sc_array_def(HiModuleData, module);
|
||||
typedef struct sc_array_module HiModuleArray;
|
||||
|
||||
HiloadResult moduler_reload(HiModuleData *module,
|
||||
const struct sc_array_memreg *const memregs);
|
||||
|
||||
struct sc_array_memreg *memregs);
|
||||
|
||||
#endif // MODULER_H_
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
#include "string.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
size_t hi_strncat_buf(size_t buflen, char buf[buflen], const char *first, const char *second) {
|
||||
if (!buf) return 0;
|
||||
|
||||
size_t first_len = strlen(first);
|
||||
size_t second_len = strlen(second);
|
||||
|
||||
if (buf + first_len + second_len > buf + buflen - 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * first_end = buf + first_len;
|
||||
char * second_end = first_end + second_len;
|
||||
|
||||
strncpy(buf, first, first_end - buf);
|
||||
strncpy(first_end, second, second_end - first_end);
|
||||
|
||||
*second_end = '\0';
|
||||
|
||||
return second_end - buf;
|
||||
}
|
||||
|
||||
int hi_path_has_filename(const char *path, const char *filename) {
|
||||
|
||||
const char *compared_filename = path;
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* Concatenate two strings into a buffer.
|
||||
*
|
||||
* If resulting string would be longer than buflen - 1, the resulting string in \p
|
||||
* buf is unchanged.
|
||||
*
|
||||
* @param first Null terminated character string
|
||||
* @param second Null terminated character string
|
||||
*/
|
||||
size_t hi_strncat_buf(size_t bufsize, char buf[bufsize], const char *first,
|
||||
const char *second);
|
||||
|
||||
/**
|
||||
* @brief Copy file content to a null terminated string, allocating memory while
|
||||
* reading.
|
||||
@@ -18,8 +30,7 @@
|
||||
* @param nmax if not 0, this amount of memory in bytes is read and used as
|
||||
* initial allocation
|
||||
*/
|
||||
char *hi_string_from_file_dyn(const char *filename, size_t *nread,
|
||||
size_t nmax);
|
||||
char *hi_string_from_file_dyn(const char *filename, size_t *nread, size_t nmax);
|
||||
|
||||
/**
|
||||
* Find if filename exists at the end of path.
|
||||
|
||||
Reference in New Issue
Block a user