Skip to content

ElfSymbol

Description

Decoded symbol-table entry. name is borrowed from the file’s .strtab (for symbols) or .dynstr (for dynamic_symbols).

Usage example (Cross-references)

Usage examples (Cross-references)
    
    typedef struct DwarfFunction {
        u64  low_pc;  // file-relative virtual address (same space as ElfSymbol.value)
        u64  high_pc; // exclusive end
        Zstr name;    // borrowed from `string_pool`
        u64           value; // virtual address for ET_EXEC / ET_DYN
        u64           size;
    } ElfSymbol;
    
    ///
    
    typedef Vec(ElfSection) ElfSections;
    typedef Vec(ElfSymbol) ElfSymbols;
    typedef Vec(ElfSegment) ElfSegments;
    /// TAGS: Parser, ELF, Symbol
    ///
    const ElfSymbol *ElfResolveAddress(const Elf *self, u64 vaddr);
    
    ///
    // 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) {
    // 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) {
            const ElfSymbol *s = VecPtrAt(syms, i);
        const ElfSymbol *best = NULL;
        for (u64 i = 0; i < VecLen(syms); ++i) {
            const ElfSymbol *s = VecPtrAt(syms, i);
            // Consider only real address symbols. Like llvm-symbolizer, keep
            // NOTYPE/FUNC/OBJECT (NOTYPE covers hand-written asm) and drop
    }
    
    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);
    
    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);
    }
        // sidecar (full `.symtab` for stripped binaries) if nothing
        // matches.
        const ElfSymbol *sym = resolver_resolve_addr(&cache_entry->elf, file_relative);
        if (!(sym && sym->name && sym->name[0]) && cache_entry->has_sidecar) {
            sym = resolver_resolve_addr(&cache_entry->sidecar, file_relative);
            BufReadFmt(&iter, FMT_SYM64_LE, name, info, other, shndx, value, size_);
    
            ElfSymbol s;
            s.name          = elf_str_at(self, strtab->offset, strtab->size, name);
            s.bind          = (ElfSymbolBind)(info >> 4);
    // ---------------------------------------------------------------------------
    
    static const ElfSymbol *elf_search_symbols(const ElfSymbols *syms, u64 vaddr) {
        const ElfSymbol *best = NULL;
        for (u64 i = 0; i < VecLen(syms); ++i) {
    
    static const ElfSymbol *elf_search_symbols(const ElfSymbols *syms, u64 vaddr) {
        const ElfSymbol *best = NULL;
        for (u64 i = 0; i < VecLen(syms); ++i) {
            const ElfSymbol *s = VecPtrAt(syms, i);
        const ElfSymbol *best = NULL;
        for (u64 i = 0; i < VecLen(syms); ++i) {
            const ElfSymbol *s = VecPtrAt(syms, i);
            if (s->size == 0) {
                // Some symbols (e.g. labels) have zero size — only match
    }
    
    const ElfSymbol *ElfResolveAddress(const Elf *self, u64 vaddr) {
        if (!self)
            return NULL;
        if (!self)
            return NULL;
        const ElfSymbol *hit = elf_search_symbols(&self->symbols, vaddr);
        if (hit)
            return hit;
        // (3) Symbol lookup against .symtab/.dynsym should miss for our
        //     static helpers (they're not exported, and .symtab is gone).
        const ElfSymbol *sym                    = ElfResolveAddress(&stripped, file_relative);
        bool             sym_missing_or_unnamed = (!sym) || (sym && (!sym->name || !sym->name[0]));
        if (!sym_missing_or_unnamed) {
        bool ok = false;
        for (u64 i = 0; i < VecLen(&elf.symbols); ++i) {
            const ElfSymbol *s = VecPtrAt(&elf.symbols, i);
            if (s->type == ELF_SYMBOL_TYPE_FUNC && s->size > 0 && s->name && s->name[0] != '\0') {
                ok = true;
        bool found_func = false;
        for (u64 i = 0; i < VecLen(&elf.symbols); ++i) {
            const ElfSymbol *s = VecPtrAt(&elf.symbols, i);
            if (s->name && ZstrCompare(s->name, "my_func") == 0) {
                found_func = s->value == FUNC_VADDR && s->size == FUNC_SIZE && s->type == ELF_SYMBOL_TYPE_FUNC &&
    
        // Exactly at the symbol start.
        const ElfSymbol *s  = ElfResolveAddress(&elf, FUNC_VADDR);
        bool             ok = s && s->name && ZstrCompare(s->name, "my_func") == 0;
            return false;
        }
        const ElfSymbol *a = VecPtrAt(&elf.symbols, 1);
        const ElfSymbol *b = VecPtrAt(&elf.symbols, 3);
        const ElfSymbol *l = VecPtrAt(&elf.symbols, 4);
        }
        const ElfSymbol *a = VecPtrAt(&elf.symbols, 1);
        const ElfSymbol *b = VecPtrAt(&elf.symbols, 3);
        const ElfSymbol *l = VecPtrAt(&elf.symbols, 4);
        bool ok = a->name && ZstrCompare(a->name, "alpha") == 0 && b->name && ZstrCompare(b->name, "beta") == 0 &&
        const ElfSymbol *a = VecPtrAt(&elf.symbols, 1);
        const ElfSymbol *b = VecPtrAt(&elf.symbols, 3);
        const ElfSymbol *l = VecPtrAt(&elf.symbols, 4);
        bool ok = a->name && ZstrCompare(a->name, "alpha") == 0 && b->name && ZstrCompare(b->name, "beta") == 0 &&
                  l->name && ZstrCompare(l->name, "local") == 0;
            return false;
        }
        const ElfSymbol *a  = VecPtrAt(&elf.symbols, 1);
        bool             ok = a->value == SF_ALPHA_VADDR && a->size == SF_ALPHA_SIZE && a->type == ELF_SYMBOL_TYPE_FUNC &&
                  a->bind == ELF_SYMBOL_BIND_GLOBAL && a->section_index == SF_SEC_TEXT;
        bool ok = VecLen(&elf.dynamic_symbols) == 2;
        if (ok) {
            const ElfSymbol *d = VecPtrAt(&elf.dynamic_symbols, 1);
            ok                 = d->name && ZstrCompare(d->name, "dyn_sym") == 0 && d->value == SF_DYN_VADDR;
        }
            return false;
        }
        const ElfSymbol *s;
        bool             ok = true;
            return false;
        }
        const ElfSymbol *hit  = ElfResolveAddress(&elf, SF_BETA_VADDR);
        const ElfSymbol *miss = ElfResolveAddress(&elf, SF_BETA_VADDR + 1);
        bool             ok   = hit && hit->name && ZstrCompare(hit->name, "beta") == 0 && miss == NULL;
        }
        const ElfSymbol *hit  = ElfResolveAddress(&elf, SF_BETA_VADDR);
        const ElfSymbol *miss = ElfResolveAddress(&elf, SF_BETA_VADDR + 1);
        bool             ok   = hit && hit->name && ZstrCompare(hit->name, "beta") == 0 && miss == NULL;
        ElfDeinit(&elf);
            return false;
        }
        const ElfSymbol *s  = ElfResolveAddress(&elf, SF_BETA_VADDR);
        bool             ok = s && s->name && ZstrCompare(s->name, "beta") == 0 && s->bind == ELF_SYMBOL_BIND_GLOBAL;
        ElfDeinit(&elf);
        // [0x1000, 0x1040). best starts at alpha; local is seen later and must
        // NOT displace it because local is not GLOBAL.
        const ElfSymbol *s  = ElfResolveAddress(&elf, SF_ALPHA_VADDR + 4);
        bool             ok = s && s->name && ZstrCompare(s->name, "alpha") == 0 && s->bind == ELF_SYMBOL_BIND_GLOBAL;
        ElfDeinit(&elf);
Last updated on