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;- In
Backtrace.c:461:
}
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);- In
Backtrace.c:484:
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); }
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&sr_notype_marker, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "sr_notype_marker") != NULL; }
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&sr_cache_data_marker, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "sr_cache_data_marker") != NULL; }
ResolvedSymbol r0;
bool ok = SymbolResolverResolve(&res, (void *)&sr1_marker_a, &r0);
ok = ok && r0.symbol_name && r0.symbol_size > 0; if (ok) {
u64 base = (u64)(void *)&sr1_marker_a;
ResolvedSymbol re;
if (SymbolResolverResolve(&res, (void *)(base + r0.symbol_size), &re)) {
// The one-past-end address must not land back inside marker_a:
}
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 ro;
ok = ok && SymbolResolverResolve(&res, (void *)other, &ro) && ro.module_path;
ok = ok && ZstrCompare(ra.module_path, ro.module_path) != 0; // two distinct cache entries
}
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&sr1_marker_a, &r) && r.module_base != 0;- In
SymBind.c:58:
}
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&sr_bind_global_sized, &r);
ok = ok && r.symbol_name != NULL;- In
SymBind.c:78:
}
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&sr_bind_global_zero, &r);
ok = ok && r.symbol_name != NULL; }
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&scd_marker, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "scd_marker") != NULL; }
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&scd_marker, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "scd_marker") != NULL;- In
SidecarSub.c:43:
u64 addr = (u64)(void *)&subdir_marker;
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)addr, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "subdir_marker") != NULL;- In
SidecarSub.c:67:
}
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&subdir_marker, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "subdir_marker") != NULL;- In
Sidecar.c:44:
}
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&sidecar_marker, &r);
ok = ok && r.module_path && r.module_path[0] != '\0';- In
Sidecar.c:80:
}
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&sidecar_marker, &r);
// The marker is named only via the opened sidecar, proving the cache
u64 addr = (u64)(void *)&df_marker_a;
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)addr, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "df_marker_a") != NULL; // -- pushes that probe outside the body and the marker name disappears.
if (ok) {
ResolvedSymbol rlast;
ok = SymbolResolverResolve(&res, (void *)(addr + r.symbol_size - 1), &rlast);
ok = ok && rlast.symbol_name && ZstrFindSubstring(rlast.symbol_name, "df_marker_a") != NULL;
u64 base = (u64)(void *)&df_marker_a;
ResolvedSymbol r0, rk;
bool ok = SymbolResolverResolve(&res, (void *)base, &r0);
ok = ok && r0.symbol_name && r0.symbol_size > 4; }
ResolvedSymbol ra, rb;
bool ok = SymbolResolverResolve(&res, (void *)&df_marker_a, &ra);
ok = ok && SymbolResolverResolve(&res, (void *)&df_marker_b, &rb); }
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, (void *)&df_marker_a, &r);
// The name came from DWARF, proving the function table was built (and the
- In
Bias.c:64:
void *addr = symres_bias_data_addr();
ResolvedSymbol r;
bool ok = SymbolResolverResolve(&res, addr, &r);
ok = ok && r.symbol_name && ZstrFindSubstring(r.symbol_name, "symres_bias_data") != NULL;- In
Bias.c:88:
u64 base = (u64)symres_bias_data_addr();
const u64 K = 8;
ResolvedSymbol r0, rk;
bool ok = SymbolResolverResolve(&res, (void *)base, &r0);
ok = ok && SymbolResolverResolve(&res, (void *)(base + K), &rk);- In
Bias.c:116:
void *data = symres_bias_data_addr();
ResolvedSymbol r0;
bool ok = SymbolResolverResolve(&res, data, &r0) && r0.module_path && r0.symbol_size > 0;- In
Bias.c:124:
if (ok) {
u64 uncovered = (u64)data + r0.symbol_size + 8;
ResolvedSymbol rf;
ok = SymbolResolverResolve(&res, (void *)uncovered, &rf);
ok = ok && rf.module_base == ms - mfo;- In
Bias.c:147:
void *data = symres_bias_data_addr();
ResolvedSymbol r0;
bool ok = SymbolResolverResolve(&res, data, &r0) && r0.module_path && r0.symbol_size > 0;- In
Bias.c:154:
if (ok) {
u64 past = (u64)data + r0.symbol_size;
ResolvedSymbol re;
ok = SymbolResolverResolve(&res, (void *)past, &re);
ok = ok && re.module_base == ms - mfo; // fallback base, segment excluded
- In
Stripped.c:51:
return false;
}
ResolvedSymbol r;
if (!SymbolResolverResolve(&res, (void *)func, &r)) {
SymbolResolverDeinit(&res);- In
Dwarf.c:54:
}
ResolvedSymbol r;
if (!SymbolResolverResolve(&res, (void *)&dwarf_marker_helper, &r)) {
SymbolResolverDeinit(&res);- In
Dwarf.c:100:
}
ResolvedSymbol r;
if (!SymbolResolverResolve(&res, (void *)&dwarf_marker_helper, &r)) {
SymbolResolverDeinit(&res);- In
Dwarf.c:163:
}
ResolvedSymbol r;
if (!SymbolResolverResolve(&res, (void *)&dwarf_marker_helper, &r)) {
SymbolResolverDeinit(&res);
Last updated on