elfinspect

ELF and DWARF Binary Inspector
git clone anongit@rnpnr.xyz:elfinspect.git
Log | Files | Refs | Feed | README | LICENSE

Commit: 42e1d79f4da4706e6047d66795b1673fcfd8d892
Parent: a42d40b02ffe7269c267c5bb0e9e46986e65bc76
Author: Randy Palamar
Date:   Sun, 27 Apr 2025 11:12:00 -0600

section header parsing

Diffstat:
Melfinspect.c | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mmain_posix.c | 19+++++++++++++++++--
2 files changed, 151 insertions(+), 19 deletions(-)

diff --git a/elfinspect.c b/elfinspect.c @@ -4,9 +4,13 @@ /* TODO(rnp) platform specific */ #define ASSERT(c) do { if (!(c)) asm("int3"); } while (0) +#define TODO(c) ASSERT(c) #define countof(a) (sizeof(a) / sizeof(*a)) +#define KB(a) ((u64)a << 10ULL) +#define MB(a) ((u64)a << 20ULL) + typedef struct {u8 *beg, *end;} Arena; #define str8(s) (str8){.len = countof(s) - 1, .data = (u8 *)s} @@ -37,17 +41,17 @@ typedef struct { u8 identifier[16]; ELF_HEADER_MEMBERS(u64) } ELFHeader64; #undef X typedef enum { - EHK_NONE = 0x00, - EHK_32 = 0x01, - EHK_64 = 0x02, -} ELFHeaderKind; + EK_NONE = 0x00, + EK_32 = 0x01, + EK_64 = 0x02, +} ELFKind; typedef struct { union { ELFHeader64 eh64; ELFHeader32 eh32; - } u; - ELFHeaderKind kind; + }; + ELFKind kind; } ELFHeader; typedef enum { @@ -56,6 +60,91 @@ typedef enum { EEK_BIG = 0x02, } ELFEndianKind; +/* X(ctype, name) */ +#define ELF_SECTION_HEADER_MEMBERS(ptrsize) \ + X(u32, name_table_offset) \ + X(u32, kind) \ + X(ptrsize, flags) \ + X(ptrsize, addr) \ + X(ptrsize, offset) \ + X(ptrsize, size) \ + X(u32, link) \ + X(u32, info) \ + X(ptrsize, addralign) \ + X(ptrsize, entsize) + +#define X(ctype, name) ctype name; +typedef struct {ELF_SECTION_HEADER_MEMBERS(u32)} ELFSectionHeader32; +typedef struct {ELF_SECTION_HEADER_MEMBERS(u64)} ELFSectionHeader64; +#undef X + +typedef struct { + str8 name; + union { + ELFSectionHeader64 sh64; + ELFSectionHeader32 sh32; + }; +} ELFSectionHeader; + +typedef enum { + ESK_NULL = 0, + ESK_PROGBITS = 1, + ESK_SYMBOL_TABLE = 2, + ESK_STR_TABLE = 3, + ESK_RELA = 4, + ESK_HASH = 5, + ESK_DYNAMIC = 6, + ESK_NOTE = 7, + ESK_NOBITS = 8, + ESK_REL = 9, + ESK_SHLIB = 10, + ESK_DYNSYM = 11, + ESK_INIT_ARRAY = 14, + ESK_FINI_ARRAY = 15, + ESK_PREINIT_ARR = 16, + ESK_GROUP = 17, + ESK_SYMTAB_SHND = 18, + ESK_RELR = 19, + ESK_NUM = 20, + ESK_LOPROC = 0x70000000, + ESK_HIPROC = 0x7fffffff, + ESK_LOUSER = 0x80000000, + ESK_HIUSER = 0x8fffffff, +} ELFSectionKind; + +#define zero_struct(s) mem_clear(s, 0, sizeof(*s)); +function void * +mem_clear(void *restrict _s, u8 byte, iz size) +{ + u8 *s = _s; + for (iz i = 0; i < size; i++) + s[i] = byte; + return s; +} + +#define alloc(a, t, c) (t *)alloc_(a, _Alignof(t), sizeof(t), c) +function void * +alloc_(Arena *a, iz alignment, iz size, iz count) +{ + iz capacity = a->end - a->beg; + iz padding = -(uintptr_t)a->beg & alignment; + if ((capacity - padding) / size < count) { + ASSERT(0 && "OOM: buy more ram lol"); + } + u8 *result = a->beg + padding; + a->beg += padding + size * count; + return mem_clear(result, 0, size * count); +} + +function str8 +c_str_to_str8(u8 *c_str) +{ + str8 result = {.data = c_str}; + if (c_str) while (*c_str) c_str++; + result.len = c_str - result.data; + return result; +} + function void print_u64(u64 v) { @@ -68,18 +157,18 @@ function void print_u32(u32 v) { print_u64(v); } function void print_elf_header_32(ELFHeader *eh) { - ASSERT(eh->kind == EHK_32); + ASSERT(eh->kind == EK_32); printf("TODO: print 32 bit elf header\n"); } function void print_elf_header_64(ELFHeader *eh) { - ASSERT(eh->kind == EHK_64); + ASSERT(eh->kind == EK_64); printf("ELF Header:\nidentifier: 0x"); - for (u32 i = 0; i < countof(eh->u.eh64.identifier); i++) - printf(" %02x", eh->u.eh64.identifier[i]); - #define X(ctype, name) printf("\n"); printf(#name ": "); print_##ctype(eh->u.eh64.name); + for (u32 i = 0; i < countof(eh->eh64.identifier); i++) + printf(" %02x", eh->eh64.identifier[i]); + #define X(ctype, name) printf("\n"); printf(#name ": "); print_##ctype(eh->eh64.name); ELF_HEADER_MEMBERS(u64) #undef X printf("\n"); @@ -89,8 +178,8 @@ function void print_elf_header(ELFHeader *eh) { switch (eh->kind) { - case EHK_32: print_elf_header_32(eh); break; - case EHK_64: print_elf_header_64(eh); break; + case EK_32: print_elf_header_32(eh); break; + case EK_64: print_elf_header_64(eh); break; default: printf("invalid elf header\n"); break; } } @@ -111,23 +200,51 @@ elf_header_from_file(str8 file) { ELFHeader result = {0}; ASSERT(file.len > sizeof(ELFHeader64)); - ASSERT(file.data[4] == EHK_64); + ASSERT(file.data[4] == EK_64); ASSERT(file.data[5] == EEK_LITTLE); - result.u.eh64 = *(ELFHeader64 *)file.data; - result.kind = file.data[4]; + result.eh64 = *(ELFHeader64 *)file.data; + result.kind = file.data[4]; + + return result; +} + +function ELFSectionHeader * +elf_extract_section_headers(Arena *a, str8 file, ELFHeader *eh) +{ + TODO(eh->kind == EK_64); + TODO(eh->eh64.identifier[5] == EEK_LITTLE); + TODO(file.len >= eh->eh64.shoff + eh->eh64.shentsize * eh->eh64.shnum); + u32 sections = eh->eh64.shnum; + ELFSectionHeader *result = alloc(a, ELFSectionHeader, sections); + for (u32 i = 0; i < sections; i++) { + iz offset = eh->eh64.shoff + eh->eh64.shentsize * i; + result[i].sh64 = *(ELFSectionHeader64 *)(file.data + offset); + } + + u8 *str_tab = file.data + result[eh->eh64.shstrndx].sh64.offset; + for (u32 i = 0; i < sections; i++) + result[i].name = c_str_to_str8(str_tab + result[i].sh64.name_table_offset); return result; } function b32 -elfinspect(str8 file) +elfinspect(Arena arena, str8 file) { b32 result = 0; if (is_elf(file)) { ELFHeader header = elf_header_from_file(file); + ELFSectionHeader *sections = elf_extract_section_headers(&arena, file, &header); print_elf_header(&header); + printf("\nSections:\n"); + for (u32 i = 0; i < header.eh64.shnum; i++) { + printf("[%u]:", i); + str8 name = sections[i].name; + if (name.len) printf(" %.*s", (s32)name.len, name.data); + printf("\n"); + } result = 1; } diff --git a/main_posix.c b/main_posix.c @@ -21,6 +21,20 @@ typedef ptrdiff_t iz; #include <sys/stat.h> #include <unistd.h> +function Arena +os_arena_new(iz size) +{ + Arena result = {0}; + iz page_size = sysconf(_SC_PAGESIZE); + if (size % page_size) size += page_size - (size % page_size); + u8 *mem = mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (mem != MAP_FAILED) { + result.beg = mem; + result.end = mem + size; + } + return result; +} + function str8 os_map_file(u8 *name) { @@ -39,7 +53,8 @@ os_map_file(u8 *name) s32 main(s32 argc, char *argv[]) { - str8 file = os_map_file((u8 *)argv[0]); - elfinspect(file); + Arena arena = os_arena_new(MB(32)); + str8 file = os_map_file((u8 *)argv[0]); + elfinspect(arena, file); return 0; }