Skip to content
ResolvedSymbol

ResolvedSymbol

Description

Per-resolve output. All string fields are borrowed from internal state and remain valid until the next call (which may rebuild the cache) or SymbolResolverDeinit.

Fields

Name Description
module_path Backing file of the loaded ELF that contains addr, or NULL if no mapping was found.
module_base Lowest mapped virtual address for that file.
symbol_name Name of the enclosing symbol, or NULL if the address landed inside the module but outside any named symbol’s range.
symbol_value st_value of the matching symbol (file-relative).
symbol_size st_size of the matching symbol.
offset addr minus the start of the matching symbol. If no symbol matched, the offset from module_base.
source_file When FEATURE_PARSER_DWARF is on and the module ships .debug_line data we understand, this is the source file containing addr. NULL otherwise.
source_dir Compilation directory hint paired with source_file. May be NULL.
source_line 1-based source line, or 0 if unknown.
source_column 1-based source column, or 0 if unknown.

Usage example (Cross-references)

Usage examples (Cross-references)
        u32  source_line;
        u32  source_column;
    } ResolvedSymbol;
    
    typedef struct ResolverCacheEntry {
    /// TAGS: Sys, Symbol, Resolver
    ///
    bool SymbolResolverResolve(SymbolResolver *self, void *runtime_addr, ResolvedSymbol *out);
    
    #if FEATURE_PARSER_DWARF
    // ---------------------------------------------------------------------------
    
    bool SymbolResolverResolve(SymbolResolver *self, void *runtime_addr, ResolvedSymbol *out) {
        if (!self || !out)
            return false;
    }
    
    static void emit_resolved_line(Str *out, u32 idx, const ResolvedSymbol *r, void *ip) {
        if (r->symbol_name) {
            Zstr mod = sys_basename_of(r->module_path);
    static void format_walk_with(Str *out, const StackFrame *frames, size count, SymbolResolver *resolver) {
        for (size i = 0; i < count; ++i) {
            ResolvedSymbol r;
            if (SymbolResolverResolve(resolver, frames[i].ip, &r)) {
                emit_resolved_line(out, (u32)i, &r, frames[i].ip);
    // ---------------------------------------------------------------------------
    
    static bool resolve_addr(SymbolResolver *res, void *addr, ResolvedSymbol *out) {
        return SymbolResolverResolve(res, addr, out);
    }
        }
    
        ResolvedSymbol r;
        bool           ok = resolve_addr(&res, (void *)&sr1_marker_a, &r);
        ok                = ok && r.module_path && r.module_path[0] != '\0';
        }
    
        ResolvedSymbol ra, rb;
        bool           ok = resolve_addr(&res, (void *)&sr1_marker_a, &ra);
        ok                = ok && resolve_addr(&res, (void *)&sr1_marker_b, &rb);
    
        u64            addr = (u64)(void *)&sr1_marker_a;
        ResolvedSymbol r;
        bool           ok = resolve_addr(&res, (void *)addr, &r);
        ok                = ok && r.symbol_name != NULL;
        const u64      K    = 16;
        u64            base = (u64)(void *)&sr1_marker_a;
        ResolvedSymbol r0, rk;
        bool           ok = resolve_addr(&res, (void *)base, &r0);
        ok                = ok && resolve_addr(&res, (void *)(base + K), &rk);
        }
    
        ResolvedSymbol ra, rb;
        bool           ok = resolve_addr(&res, (void *)&sr1_marker_a, &ra);
        ok                = ok && resolve_addr(&res, (void *)&sr1_marker_b, &rb);
        }
    
        ResolvedSymbol r;
        bool           ok = resolve_addr(&res, (void *)&sr1_marker_a, &r);
        ok                = ok && r.symbol_name != NULL;
        }
    
        ResolvedSymbol r0;
        bool           ok = resolve_addr(&res, (void *)&sr1_marker_a, &r0);
        ok                = ok && r0.symbol_name && r0.symbol_size > 0;
    
        // Last byte of the symbol: still the same function, offset == size-1.
        ResolvedSymbol rlast;
        ok = resolve_addr(&res, (void *)(base + size - 1), &rlast);
        ok = ok && rlast.symbol_name;
    
        // Get this module's base via a normal resolve.
        ResolvedSymbol probe;
        bool           got_base = resolve_addr(&res, (void *)&sr1_marker_a, &probe);
        bool           ok       = got_base && probe.module_base != 0;
            bool found_unnamed = false;
            for (u64 off = 1; off <= 8 && !found_unnamed; ++off) {
                ResolvedSymbol r;
                if (resolve_addr(&res, (void *)(base + off), &r)) {
                    if (r.symbol_name == NULL) {
        }
    
        ResolvedSymbol r;
        // Page-zero-ish address that no module maps.
        bool ok = !SymbolResolverResolve(&res, (void *)(u64)0x1000, &r);
        }
    
        ResolvedSymbol r;
        bool           ok = SymbolResolverResolve(&res, (void *)&test_symres_resolve_self, &r);
        ok                = ok && r.module_path && r.module_path[0] != '\0';
        // Static functions don't appear in .dynsym but do appear in
        // .symtab. libc dladdr would fail to name this; we should not.
        ResolvedSymbol r;
        bool           ok = SymbolResolverResolve(&res, (void *)&symres_marker_helper, &r);
        ok                = ok && r.symbol_name != NULL && ZstrFindSubstring(r.symbol_name, "symres_marker_helper") != NULL;
        }
    
        ResolvedSymbol ra;
        bool           ok    = SymbolResolverResolve(&res, (void *)&sr1_marker_a, &ra) && ra.module_path;
        size           live1 = DebugAllocatorLiveCount(&alloc);
        size           live1 = DebugAllocatorLiveCount(&alloc);
    
        ResolvedSymbol rb;
        ok         = ok && SymbolResolverResolve(&res, (void *)&sr1_marker_b, &rb) && rb.module_path;
        size live2 = DebugAllocatorLiveCount(&alloc);
        }
    
        ResolvedSymbol rc;
        bool           ok    = SymbolResolverResolve(&res, (void *)&sr1_marker_a, &rc) && rc.module_path;
        size           live1 = DebugAllocatorLiveCount(&alloc);
        size           live1 = DebugAllocatorLiveCount(&alloc);
    
        ResolvedSymbol rd;
        ok         = ok && SymbolResolverResolve(&res, (void *)&sr_cache_data_marker, &rd) && rd.module_path;
        size live2 = DebugAllocatorLiveCount(&alloc);
        }
    
        ResolvedSymbol ra;
        bool           ok = SymbolResolverResolve(&res, (void *)&sr1_marker_a, &ra) && ra.module_path;
        size live1 = DebugAllocatorLiveCount(&alloc);
    
        ResolvedSymbol ro;
        ok         = ok && SymbolResolverResolve(&res, (void *)other, &ro) && ro.module_path;
        size live2 = DebugAllocatorLiveCount(&alloc);
        }
    
        ResolvedSymbol ra;
        bool           ok = SymbolResolverResolve(&res, (void *)&sr1_marker_a, &ra) && ra.module_path;
        ok        = ok && find_other_module_addr(ra.module_path, &other);
    
        ResolvedSymbol r1;
        ok         = ok && SymbolResolverResolve(&res, (void *)other, &r1) && r1.module_path;
        size live1 = DebugAllocatorLiveCount(&alloc);
        size live1 = DebugAllocatorLiveCount(&alloc);
    
        ResolvedSymbol r2;
        ok         = ok && SymbolResolverResolve(&res, (void *)other, &r2) && r2.module_path;
        size live2 = DebugAllocatorLiveCount(&alloc);
            return false;
        }
        ResolvedSymbol r;
        bool           ok = SymbolResolverResolve(&res, (void *)&sr1_marker_a, &r);
            return false;
        }
        ResolvedSymbol r;
        if (!SymbolResolverResolve(&res, (void *)func, &r)) {
            SymbolResolverDeinit(&res);
        }
    
        ResolvedSymbol r;
        if (!SymbolResolverResolve(&res, (void *)&dwarf_marker_helper, &r)) {
            SymbolResolverDeinit(&res);
        }
    
        ResolvedSymbol r;
        if (!SymbolResolverResolve(&res, (void *)&dwarf_marker_helper, &r)) {
            SymbolResolverDeinit(&res);
        }
    
        ResolvedSymbol r;
        if (!SymbolResolverResolve(&res, (void *)&dwarf_marker_helper, &r)) {
            SymbolResolverDeinit(&res);
Last updated on