Skip to content

Elf

Description

Parsed ELF file. Holds the raw bytes plus decoded indices into them. Three construction paths, all of which leave the Elf in the same lifecycle state: parser owns the bytes, parser frees them on ElfDeinit. There is no “borrowed buffer” mode – the L / R split below mirrors VecInsertL / VecInsertR:

ElfOpen — reads a file from disk; parser owns the resulting buffer end-to-end. ElfOpenFromMemoryL: takes ownership of the caller’s (data, data_size). Caller must not free or touch data afterwards. alloc MUST be the allocator that produced data. ElfOpenFromMemoryCopyR: allocates internally through alloc, copies the caller’s bytes in, and never retains the caller’s pointer. Caller’s buffer is untouched and remains theirs.

Fields

Name Description
data Raw ELF bytes as a Buf (owned). Carries its own length and allocator – read via BufLength / BufData / BufAllocator.
header Decoded ELF header.
sections All section headers, in original order.
symbols Entries from .symtab (may be empty if stripped).
dynamic_symbols Entries from .dynsym (always present for dynamic objects).
build_id Bytes of the GNU build-ID (from .note.gnu.build-id); used to find a stripped binary’s sidecar .debug file under /usr/lib/debug/.build-id/.... NULL when the binary has no build-ID note.
build_id_size Length of build_id in bytes (typically 20).
debuglink_name Filename portion stored in .gnu_debuglink, identifying a sidecar debug file. NULL when the binary lacks the section.
debuglink_crc CRC32 of the expected sidecar contents (validated by the resolver before use).

Usage example (Cross-references)

Usage examples (Cross-references)
    #define MISRA_SYS_SYMBOL_RESOLVER_H
    
    #include <Misra/Parsers/Elf.h>
    #if FEATURE_PARSER_DWARF
    #    include <Misra/Parsers/Dwarf.h>
    typedef struct ResolverCacheEntry {
        Zstr path; // borrowed from ProcMaps.raw
        Elf  elf;
        // Sidecar debug file found via .gnu_debuglink or .note.gnu.build-id.
        // Populated lazily for stripped binaries that have an installed
        // is true, the sidecar's symbol tables (and DWARF lines, below)
        // are searched after the main file's.
        Elf  sidecar;
        bool has_sidecar;
    #if FEATURE_PARSER_DWARF
    
    #include <Misra/Parsers/Dwarf/Private.h>
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator.h>
    #include <Misra/Std/Container/Str.h>
    #define MISRA_PARSERS_ELF_H
    
    #include <Misra/Parsers/Elf/Private.h>
    #include <Misra/Std/Allocator.h>
    #include <Misra/Std/Container/Buf.h>
        Zstr        debuglink_name;
        u32         debuglink_crc;
    } Elf;
    
    ///
    /// TAGS: Parser, ELF, Memory, Ownership
    ///
    bool ElfOpenFromMemory(Elf *out, Buf *in);
    
    ///
    /// TAGS: Parser, ELF, Deinit, Lifecycle
    ///
    void ElfDeinit(Elf *self);
    
    ///
    /// TAGS: Parser, ELF, Symbol
    ///
    const ElfSymbol *ElfResolveAddress(const Elf *self, u64 vaddr);
    
    ///
    // For debuglink lookups, the file's mere presence is good enough in v1
    // (CRC32 cross-check is in FUTURE-PLANS).
    static bool sidecar_matches(const Elf *main, const Elf *sidecar, bool by_build_id) {
        if (!by_build_id) {
            return true;
    //
    // Returns true on success; `out` is populated with an opened Elf.
    static bool try_open_sidecar(Zstr main_path, const Elf *main, Elf *out, Allocator *alloc) {
        Str path = StrInit(alloc);
    // is unambiguous. Bias is constant per module (`dl_iterate_phdr`'s
    // `dlpi_addr`).
    static u64 resolver_load_bias(const Elf *elf, u64 map_start, u64 map_file_offset, u64 runtime_addr) {
        u64 addr_file_offset = map_file_offset + (runtime_addr - map_start);
        VecForeachPtr(&elf->segments, seg) {
    // approach) so they don't shadow the real symbol. STT_NOTYPE is otherwise kept,
    // since hand-written assembly functions legitimately carry no type.
    static bool resolver_is_mapping_symbol(const Elf *elf, const ElfSymbol *s) {
        if (elf->header.machine != ELF_MACHINE_AARCH64 || !s->name)
            return false;
    // GLOBAL) and adds the mapping-symbol filter the parser deliberately stays out
    // of -- address->function resolution is a SymbolResolver concern, not ELF's.
    static const ElfSymbol *resolver_search_symbols(const Elf *elf, const ElfSymbols *syms, u64 vaddr) {
        const ElfSymbol *best = NULL;
        for (u64 i = 0; i < VecLen(syms); ++i) {
    }
    
    static const ElfSymbol *resolver_resolve_addr(const Elf *elf, u64 vaddr) {
        const ElfSymbol *hit = resolver_search_symbols(elf, &elf->symbols, vaddr);
        return hit ? hit : resolver_search_symbols(elf, &elf->dynamic_symbols, vaddr);
    }
    
    bool dwarf_functions_build_from_elf(DwarfFunctions *out, const Elf *elf, Allocator *alloc) {
        if (!out || !elf || !alloc) {
            LOG_FATAL("DwarfFunctionsBuildFromElf: NULL argument");
    }
    
    bool dwarf_cfi_build_from_elf(DwarfCfi *out, const Elf *elf, Allocator *alloc) {
        if (!out || !elf || !alloc) {
            LOG_FATAL("DwarfCfiBuildFromElf: NULL argument");
    /// or ELF32 later is mostly a matter of swapping the format strings.
    
    #include <Misra/Parsers/Elf.h>
    
    #include <Misra/Std.h>
    // ---------------------------------------------------------------------------
    
    static Zstr elf_str_at(const Elf *self, u64 strtab_offset, u64 strtab_size, u32 idx) {
        if ((u64)idx >= strtab_size) {
            return "";
    }
    
    static bool elf_range_ok(const Elf *self, u64 offset, u64 size) {
        if (offset > BufLength(&self->data))
            return false;
    // ---------------------------------------------------------------------------
    
    static bool elf_decode_header(Elf *self) {
        if (BufLength(&self->data) < EI_NIDENT + EHDR64_SIZE_AFTER_IDENT) {
            LOG_ERROR("Elf: file too small for ELF64 header ({} bytes)", (u64)BufLength(&self->data));
    static bool elf_decode_header(Elf *self) {
        if (BufLength(&self->data) < EI_NIDENT + EHDR64_SIZE_AFTER_IDENT) {
            LOG_ERROR("Elf: file too small for ELF64 header ({} bytes)", (u64)BufLength(&self->data));
            return false;
        }
        const u8 *id = BufData(&self->data);
        if (id[EI_MAG0] != ELF_MAG0 || id[EI_MAG1] != ELF_MAG1 || id[EI_MAG2] != ELF_MAG2 || id[EI_MAG3] != ELF_MAG3) {
            LOG_ERROR("Elf: bad magic");
            return false;
        }
    
        if (id[EI_CLASS] != (u8)ELF_CLASS_64) {
            LOG_ERROR("Elf: only ELF64 supported in v1 (got class {})", (u32)id[EI_CLASS]);
            return false;
        }
        }
        if (id[EI_DATA] != (u8)ELF_DATA_LSB) {
            LOG_ERROR("Elf: only little-endian supported in v1 (got data {})", (u32)id[EI_DATA]);
            return false;
        }
    
        if (shentsize != SHDR64_SIZE && shnum > 0) {
            LOG_ERROR("Elf: unexpected e_shentsize ({} vs {})", (u32)shentsize, (u32)SHDR64_SIZE);
            return false;
        }
    }
    
    static bool elf_decode_sections(Elf *self) {
        u16 n      = self->header.shnum;
        u64 shoff  = self->header.shoff;
        u64 needed = (u64)n * SHDR64_SIZE;
        if (!elf_range_ok(self, shoff, needed)) {
            LOG_ERROR("Elf: section header table out of range");
            return false;
        }
    
        if (self->header.shstrndx >= n) {
            LOG_ERROR("Elf: shstrndx {} out of range (shnum={})", (u32)self->header.shstrndx, (u32)n);
            return false;
        }
        }
        if (!elf_range_ok(self, shstr_off, shstr_size)) {
            LOG_ERROR("Elf: shstrtab out of range");
            return false;
        }
    // Decode the program-header (segment) table. Relocatable objects (.o)
    // have no program headers (phnum == 0); that is not an error.
    static bool elf_decode_segments(Elf *self) {
        u16 n     = self->header.phnum;
        u64 phoff = self->header.phoff;
        u64 needed = (u64)n * PHDR64_SIZE;
        if (!elf_range_ok(self, phoff, needed)) {
            LOG_ERROR("Elf: program header table out of range");
            return false;
        }
    // ---------------------------------------------------------------------------
    
    static bool elf_decode_symbol_table(Elf *self, const ElfSection *symtab, ElfSymbols *out) {
        if (!symtab || symtab->size == 0) {
            return true;
        }
        if (symtab->entry_size != SYM64_SIZE) {
            LOG_ERROR("Elf: unexpected symbol entry size {}", (u64)symtab->entry_size);
            return false;
        }
        }
        if (!elf_range_ok(self, symtab->offset, symtab->size)) {
            LOG_ERROR("Elf: symbol table out of range");
            return false;
        }
        u32 strtab_idx = symtab->link;
        if (strtab_idx >= VecLen(&self->sections)) {
            LOG_ERROR("Elf: symtab link {} out of range", (u32)strtab_idx);
            return false;
        }
        const ElfSection *strtab = VecPtrAt(&self->sections, strtab_idx);
        if (!elf_range_ok(self, strtab->offset, strtab->size)) {
            LOG_ERROR("Elf: strtab out of range");
            return false;
        }
        };
        if (count > ELF_MAX_SYMBOLS) {
            LOG_ERROR("Elf: symbol count {} exceeds sanity cap; refusing", count);
            return false;
        }
    }
    
    static bool elf_decode_symbols(Elf *self) {
        const ElfSection *symtab    = NULL;
        const ElfSection *dynsymtab = NULL;
    };
    
    static void elf_decode_build_id(Elf *self, const ElfSection *note) {
        if (!elf_range_ok(self, note->offset, note->size) || note->size < 16) {
            return;
    }
    
    static void elf_decode_debug_link(Elf *self, const ElfSection *dl) {
        if (!elf_range_ok(self, dl->offset, dl->size) || dl->size < 5) {
            return;
    }
    
    static void elf_decode_debug_metadata(Elf *self) {
        const ElfSection *note = ElfFindSection(self, ".note.gnu.build-id");
        if (note) {
    // Anything that fails past the snapshot cleans up via ElfDeinit,
    // so the buffer never leaks.
    bool ElfOpenFromMemory(Elf *out, Buf *in) {
        if (!out || !in || !BufData(in) || !BufAllocator(in)) {
            LOG_FATAL("ElfOpenFromMemory: NULL argument (contract violation)");
    
    // R-value form (copy). Caller's `data` is never retained.
    bool elf_open_from_memory_copy(Elf *out, const u8 *data, size data_size, Allocator *alloc) {
        if (!out || !data || !alloc) {
            LOG_FATAL("ElfOpenFromMemoryCopy: NULL argument (contract violation)");
    }
    
    bool elf_open(Elf *out, Zstr path, Allocator *alloc) {
        if (!out || !path || !alloc) {
            LOG_FATAL("ElfOpen: NULL argument (contract violation)");
    }
    
    void ElfDeinit(Elf *self) {
        if (!self)
            return;
    }
    
    const ElfSymbol *ElfResolveAddress(const Elf *self, u64 vaddr) {
        if (!self)
            return NULL;
    }
    
    const ElfSection *elf_find_section_zstr(const Elf *self, Zstr name) {
        if (!self || !name)
            return NULL;
    }
    
    const ElfSection *elf_find_section_str(const Elf *self, const Str *name) {
        if (!self || !name)
            return NULL;
    // ---------------------------------------------------------------------------
    
    bool dwarf_lines_build_from_elf(DwarfLines *out, const Elf *elf, Allocator *alloc) {
        if (!out || !elf || !alloc) {
            LOG_FATAL("DwarfLinesBuildFromElf: NULL argument");
    #include <Misra.h>
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/File.h>
    bool test_elf_self_exe_parse(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
    
        bool opened = ElfOpen(&elf, "/proc/self/exe", ALLOCATOR_OF(&alloc));
    bool test_elf_find_text_section(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
    
        if (!ElfOpen(&elf, "/proc/self/exe", ALLOCATOR_OF(&alloc))) {
    bool test_elf_build_id_present(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!ElfOpen(&elf, "/proc/self/exe", ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
    bool test_elf_some_function_symbol(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
    
        if (!ElfOpen(&elf, "/proc/self/exe", ALLOCATOR_OF(&alloc))) {
        build_elf_blob();
    
        Elf  elf;
        bool ok = ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc));
        if (!ok) {
        build_elf_blob();
    
        Elf  elf;
        bool ok = ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc));
        if (ok) {
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
    static bool elf_rejects(const u8 *bytes, u64 len) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        bool             opened = ElfOpenFromMemoryCopy(&elf, bytes, len, ALLOCATOR_OF(&alloc));
        if (opened)
        build_dbg_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, dbg_blob, sizeof(dbg_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf  elf;
        bool ok = ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc));
        if (ok) {
        wr_u64(&bad[SHT_OFF + SEC_SHSTRTAB * SHDR_SIZE + 32], 0);                // sh_size
    
        Elf  elf;
        bool ok = ElfOpenFromMemoryCopy(&elf, bad, sizeof(bad), ALLOCATOR_OF(&alloc));
        if (ok) {
        wr_u64(&bad[SHT_OFF + SEC_SHSTRTAB * SHDR_SIZE + 32], (u64)sizeof(bad)); // sh_size
    
        Elf  elf;
        bool ok = ElfOpenFromMemoryCopy(&elf, bad, sizeof(bad), ALLOCATOR_OF(&alloc));
        if (ok) {
        wr_shdr2(&sht[1 * SHDR_SIZE], U_NAME_AB, ELF_SECTION_TYPE_STRTAB, 0, 0, U_SHSTR_OFF, U_SHSTR_SIZE, 0, 0, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        wr_shdr2(&sht[1 * SHDR_SIZE], B_NAME_AB, ELF_SECTION_TYPE_STRTAB, 0, 0, B_SHSTR_OFF, B_SHSTR_SIZE, 0, 0, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        wr_shdr2(&sht[1 * SHDR_SIZE], F_NAME_XYZ, ELF_SECTION_TYPE_STRTAB, 0, 0, F_SHSTR_OFF, F_SHSTR_SIZE, 0, 0, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
    bool test_el2_self_exe_header_exact(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!ElfOpen(&elf, "/proc/self/exe", ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_blob();
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
    
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        bool             opened = ElfOpenFromMemoryCopy(&elf, b, sizeof(b), ALLOCATOR_OF(&alloc));
        bool             ok     = opened && elf.header.shnum == 1 && VecLen(&elf.sections) == 1;
        build_elf_blob();
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        bool             opened = ElfOpenFromMemoryCopy(&elf, elf_blob, sizeof(elf_blob), ALLOCATOR_OF(&alloc));
        if (opened)
    
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        bool             opened = ElfOpenFromMemoryCopy(&elf, bad, sizeof(bad), ALLOCATOR_OF(&alloc));
        if (opened) {
    bool test_el2_open_real_file_succeeds(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        bool             opened = ElfOpen(&elf, "/proc/self/exe", ALLOCATOR_OF(&alloc));
        bool             ok     = opened && elf.header.machine == ELF_MACHINE_HOST && VecLen(&elf.sections) > 0;
    }
    
    static bool open_sym(Elf *elf, DefaultAllocator *alloc) {
        build_sym_blob();
        return ElfOpenFromMemoryCopy(elf, sym_blob, sizeof(sym_blob), ALLOCATOR_OF(alloc));
    bool test_el3_symtab_count_exact(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
    bool test_el3_symtab_names_decode(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
    bool test_el3_symtab_fields_intact(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
    bool test_el3_dynsym_decoded(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
        wr_u64(&sym_blob[SF_SHT_OFF + SF_SEC_STRTAB * SHDR_SIZE + 24], (u64)sizeof(sym_blob) + 0x1000);
    
        Elf  elf;
        bool opened = ElfOpenFromMemoryCopy(&elf, sym_blob, sizeof(sym_blob), ALLOCATOR_OF(&alloc));
        if (opened)
    bool test_el3_resolve_sized_boundaries(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
    bool test_el3_resolve_zero_size_exact(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
    bool test_el3_resolve_prefers_global_zero_size(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
    bool test_el3_resolve_prefers_global_sized(void) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Elf              elf;
        if (!open_sym(&elf, &alloc)) {
            DefaultAllocatorDeinit(&alloc);
        build_bid_blob(note, (u32)sizeof(note), 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, bid_blob, sizeof(bid_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_bid_blob(note, 16, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, bid_blob, sizeof(bid_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_bid_blob(note, 16, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, bid_blob, sizeof(bid_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_bid_blob(note, 16, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, bid_blob, sizeof(bid_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_bid_blob(note, 16, (u64)sizeof(bid_blob) + 0x1000);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, bid_blob, sizeof(bid_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_dl_blob(payload, 16, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, dl_blob, sizeof(dl_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_dl_blob(payload, 16, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, dl_blob, sizeof(dl_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_dl_blob(payload, 16, 0);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, dl_blob, sizeof(dl_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_dl_blob(payload, 16, (u64)sizeof(dl_blob) + 0x1000);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, dl_blob, sizeof(dl_blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        wr_ehdr_exec(blob, SHOFF, SHNUM, /*shstrndx=*/0);
    
        Elf  elf;
        bool opened = ElfOpenFromMemoryCopy(&elf, blob, sizeof(blob), ALLOCATOR_OF(&alloc));
        if (opened)
        build_dbg(blob, DBG_NOTE_OFF, DBG_NOTE_SIZE, DBG_DL_OFF, DBG_DL_SIZE);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_dbg(blob, DBG_NOTE_OFF, bad_note_size, DBG_DL_OFF, DBG_DL_SIZE);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        build_dbg(blob, DBG_NOTE_OFF, DBG_NOTE_SIZE, DBG_DL_OFF, bad_dl_size);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        );
    
        Elf  elf;
        bool opened = ElfOpenFromMemoryCopy(&elf, buf, sizeof(buf), ALLOCATOR_OF(&alloc));
        if (opened)
    
    int main(void) {
        WriteFmt("[INFO] Starting Elf tests\n\n");
    
        TestFunction tests[] = {
        };
    
        return run_test_suite(tests, sizeof(tests) / sizeof(tests[0]), NULL, 0, "Elf");
    }
    #include <Misra/Parsers/Dwarf.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/File.h>
    
        // (2) Open the stripped sibling.
        Elf stripped;
        if (!ElfOpen(&stripped, stripped_path_arg, base)) {
            LOG_ERROR("stripped binary not openable: {}", stripped_path_arg);
    #include <Misra.h>
    #include <Misra/Parsers/Dwarf.h>
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/Memory.h>
        build_elf_with_eh_frame(elfbuf, &elf_len, eh, eh_len, /*eh_addr*/ 0x4000);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_eh_frame(elfbuf, &elf_len, eh, eh_len, EH_SECTION_VADDR);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_debug_frame(elfbuf, &elf_len, df, df_len, EH_SECTION_VADDR);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_eh_frame(elfbuf, &elf_len, eh, eh_len, EH_SECTION_VADDR);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
    
        bool ok = false;
        Elf  elf;
        if (ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DwarfCfi cfi;
    
        bool ok = false;
        Elf  elf;
        if (ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DwarfCfi cfi;
    
        bool ok = false;
        Elf  elf;
        if (ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DwarfCfi cfi;
    
        bool ok = false;
        Elf  elf;
        if (ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DwarfCfi cfi;
    
        bool ok = false;
        Elf  elf;
        if (ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DwarfCfi cfi;
    #include <Misra/Parsers/Dwarf.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator/Debug.h>
    #include <Misra/Std/Allocator/Default.h>
        DefaultAllocator alloc = DefaultAllocatorInit();
    
        Elf elf;
        if (!ElfOpen(&elf, "/proc/self/exe", ALLOCATOR_OF(&alloc))) {
            DefaultAllocatorDeinit(&alloc);
        u64 file_relative = (u64)&dwarf_marker_helper - r.module_base;
    
        Elf elf;
        if (!ElfOpen(&elf, r.module_path, base)) {
            SymbolResolverDeinit(&res);
        u64 file_relative = (u64)&dwarf_marker_helper - r.module_base;
    
        Elf elf;
        if (!ElfOpen(&elf, r.module_path, base)) {
            SymbolResolverDeinit(&res);
        u64 file_relative = (u64)&dwarf_marker_helper - r.module_base;
    
        Elf elf;
        if (!ElfOpen(&elf, r.module_path, base)) {
            SymbolResolverDeinit(&res);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
    typedef struct LinesFixture {
        DefaultAllocator alloc;
        Elf              elf;
        DwarfLines       lines;
        bool             built;
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base))
            return false;
    }
    
    static bool lines_from_debug_line(DwarfLines *out, Elf *elf, const u8 *dl, u64 dl_len, Allocator *base) {
        static u8 elfbuf[8192];
        u64       elf_len = 0;
        build_elf_with_debug_line_8192(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base))
            return false;
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        put_u32(dl, 0x7fffff00u);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = lines_from_debug_line(&lines, &elf, dl, dl_len, base);
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DefaultAllocatorDeinit(&alloc);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DebugAllocatorDeinit(&dbg);
        build_elf_with_debug_line(elfbuf, &elf_len, dl, dl_len);
    
        Elf elf;
        if (!ElfOpenFromMemoryCopy(&elf, elfbuf, (size)elf_len, base)) {
            DebugAllocatorDeinit(&dbg);
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = lines_from_debug_line(&lines, &elf, dl, dl_len, base);
        u64 dl_len = finalize_unit(dl, &fx, p);
    
        Elf        elf;
        DwarfLines lines;
        if (!lines_from_debug_line(&lines, &elf, dl, dl_len, base)) {
    // Build a DwarfLines from a raw `.debug_line` payload through `base`.
    // Returns the build result; on true the caller owns `*lines` + `*elf`.
    static bool build_from_dl(DwarfLines *lines, Elf *elf, Allocator *base, const u8 *dl, u64 dl_len) {
        static u8 elfbuf[8192];
        u64       elf_len = 0;
        u64 dl_len       = dwm_finalize_unit(&fx, dl, p);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        u64 dl_len = (u64)(q - dl);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        u64 dl_len       = dwm_finalize_unit(&fx, dl, p);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        u64 dl_len  = dwm_finalize_unit(&fx, dl, p);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        u64 dl_len       = dwm_finalize_unit(&fx, dl, p);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        u64 dl_len       = dwm_finalize_unit(&fx, dl, p);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        dl[dl_len++] = 0xbb;
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        u64 dl_len       = dwm_finalize_unit(&fx, dl, p);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
        u64 dl_len = (u64)(q - dl);
    
        Elf        elf;
        DwarfLines lines;
        bool       built = build_from_dl(&lines, &elf, base, dl, dl_len);
Last updated on