Skip to content
PdbCacheResolve

PdbCacheResolve

Description

Resolve runtime_ip to a function name.

Parameters

Name Direction Description
self in,out Cache. Grows on first sight of module_path.
module_path in Path to the loaded PE for the address being resolved. Caller-owned; we copy it.
module_base in Runtime virtual address of the module’s load point. ip - module_base is the RVA.
runtime_ip in Address to resolve.
out_name out On success, pointer to the function name (borrowed from the cached PDB; valid until the next PdbCacheDeinit).
out_offset out On success, byte offset from the function start (rva - function.rva).

Success

Returns true.

Failure

Returns false if the module can’t be opened, no PDB pairs with it, or the RVA falls outside every public function.

Usage example (Cross-references)

Usage examples (Cross-references)
                    u64   module_base = 0;
                    if (win_module_for_ip(frames[i].ip, data, MAX_PATH, &module_base)) {
                        if (PdbCacheResolve(&pdb_cache, data, module_base, (u64)ip, &sym_name, &sym_off)) {
                            named = true;
                        }
        Zstr      name        = NULL;
        u32       offset      = 0;
        bool      ok          = PdbCacheResolve(&cache, (Zstr)pe_path, module_base, ip, &name, &offset);
        ok                    = ok && name && ZstrCompare(name, "winproc") == 0 && offset == 0;
        name          = NULL;
        offset        = 0;
        ok            = ok && PdbCacheResolve(&cache, (Zstr)pe_path, module_base, ip2, &name, &offset);
        ok            = ok && name && ZstrCompare(name, "winproc") == 0 && offset == 0x10;
        PdbCache cache = PdbCacheInit(base);
        Zstr     name  = NULL;
        bool     ok    = !PdbCacheResolve(&cache, (Zstr)missing, 0, 0x1000, &name, NULL);
        PdbCacheDeinit(&cache);
        DefaultAllocatorDeinit(&alloc);
            Zstr      name  = NULL;
            u32       off   = 0;
            ok              = PdbCacheResolve(&cache, pe_name, mbase, mbase + 0x1100, &name, &off);
            ok              = ok && name && ZstrCompare(name, "winproc") == 0 && off == 0;
            PdbCacheDeinit(&cache);
            Zstr     name  = NULL;
            // PE opens, PDB lookup fails -> resolve returns false.
            ok = !PdbCacheResolve(&cache, (Zstr)pe_path, 0x140000000ull, 0x140001100ull, &name, NULL);
            PdbCacheDeinit(&cache);
            // Teardown returns every allocation (the failed-lookup candidate too).
            Zstr     name  = NULL;
            // PDB opens but GUID/age disagree -> resolve rejects it.
            ok = !PdbCacheResolve(&cache, (Zstr)pe_path, 0x140000000ull, 0x140001100ull, &name, NULL);
            PdbCacheDeinit(&cache);
            // The briefly-opened, then-rejected PDB must be freed.
            u32       off   = 0;
    
            bool ra = PdbCacheResolve(&cache, (Zstr)a_pe, mbase, mbase + 0x1100, &name, &off);
            bool rb = PdbCacheResolve(&cache, (Zstr)b_pe, mbase, mbase + 0x1100, &name, &off);
    
            bool ra = PdbCacheResolve(&cache, (Zstr)a_pe, mbase, mbase + 0x1100, &name, &off);
            bool rb = PdbCacheResolve(&cache, (Zstr)b_pe, mbase, mbase + 0x1100, &name, &off);
    
            // Both modules now open and cached; snapshot the live allocations.
            // Re-resolve B at a different IP: must hit B's existing slot.
            Zstr name2 = NULL;
            bool rb2   = PdbCacheResolve(&cache, (Zstr)b_pe, mbase, mbase + 0x1108, &name2, &off);
            size after = DebugAllocatorLiveCount(&alloc);
            Zstr      name  = NULL;
            u32       off   = 0;
            bool      r     = PdbCacheResolve(&cache, (Zstr)pe_path, mbase, mbase + 0x1100, &name, &off);
    
            // A populated cache with an opened PE+PDB sits strictly above baseline.
            u32       off   = 0;
            // ip exactly at module_base -> RVA 0 -> resolves under real `<`.
            ok = PdbCacheResolve(&cache, (Zstr)pe_path, mbase, mbase, &name, &off);
            ok = ok && name && ZstrCompare(name, "winzero") == 0 && off == 0;
            PdbCacheDeinit(&cache);
            Zstr      name  = NULL;
            u32       off   = 0;
            ok              = PdbCacheResolve(&cache, (Zstr)pe_path, mbase, mbase + 0xFFFFFFFFull, &name, &off);
            ok              = ok && name && ZstrCompare(name, "winmax") == 0 && off == 0;
            PdbCacheDeinit(&cache);
                u32  off  = 0;
                // ip strictly below module_base -> delegated resolve returns false.
                ok = !PdbCacheResolve(&cache, &mod, mbase, mbase - 1, &name, &off);
            }
            PdbCacheDeinit(&cache);
            Zstr      name  = NULL;
            u32       off   = 0;
            ok              = PdbCacheResolve(&cache, (Zstr)pe_path, mbase, mbase + 0x1100, &name, &off);
            ok              = ok && name && ZstrCompare(name, "winproc") == 0 && off == 0;
            PdbCacheDeinit(&cache);
            PdbCache cache = PdbCacheInit(a);
            Zstr     name  = NULL;
            ok             = !PdbCacheResolve(&cache, (Zstr)pe_path, 0x140000000ull, 0x140001100ull, &name, NULL);
            PdbCacheDeinit(&cache);
            ok = ok && DebugAllocatorLiveCount(&alloc) == baseline;
            Zstr      nb    = NULL;
            u32       off   = 0;
            bool      ra    = PdbCacheResolve(&cache, (Zstr)a_pe, mbase, mbase + 0x1100, &na, &off);
            bool      rb    = PdbCacheResolve(&cache, (Zstr)b_pe, mbase, mbase + 0x1100, &nb, &off);
            ok              = ra && rb && na && nb && ZstrCompare(na, "aproc") == 0 && ZstrCompare(nb, "bproc") == 0;
            u32       off   = 0;
            bool      ra    = PdbCacheResolve(&cache, (Zstr)a_pe, mbase, mbase + 0x1100, &na, &off);
            bool      rb    = PdbCacheResolve(&cache, (Zstr)b_pe, mbase, mbase + 0x1100, &nb, &off);
            ok              = ra && rb && na && nb && ZstrCompare(na, "aproc") == 0 && ZstrCompare(nb, "bproc") == 0;
            PdbCacheDeinit(&cache);
    
            // Two distinct modules -> two cache entries, each opening a PE+PDB.
            bool ra = PdbCacheResolve(&cache, (Zstr)a_pe, mbase, mbase + 0x1100, &name, &off);
            bool rb = PdbCacheResolve(&cache, (Zstr)b_pe, mbase, mbase + 0x1100, &name, &off);
            // Two distinct modules -> two cache entries, each opening a PE+PDB.
            bool ra = PdbCacheResolve(&cache, (Zstr)a_pe, mbase, mbase + 0x1100, &name, &off);
            bool rb = PdbCacheResolve(&cache, (Zstr)b_pe, mbase, mbase + 0x1100, &name, &off);
    
            // A populated two-entry cache sits strictly above baseline.
        PdbCache cache = PdbCacheInit(&bp);
        Zstr     name  = NULL;
        if (PdbCacheResolve(&cache, (char *)"/x", 0, 0x1000, &name, NULL))
            return false; // the entry must have failed to allocate
Last updated on