Skip to content

PdbFunction

Description

One public function name + range from the PDB.

Fields

Name Description
rva Image-relative virtual address of the function start (= file-relative VA in PE / runtime_addr - ImageBase).
size Best-effort byte size. PDB S_PUB32 records don’t carry a size directly; we infer it as next_rva - this_rva after sorting, so the last function’s size is 0.
name Function name string. Borrowed from the PDB’s name pool; valid until PdbDeinit.

Usage example (Cross-references)

Usage examples (Cross-references)
        u32  size;
        Zstr name;
    } PdbFunction;
    
    typedef Vec(PdbFunction) PdbFunctions;
    } PdbFunction;
    
    typedef Vec(PdbFunction) PdbFunctions;
    
    ///
    /// TAGS: Parser, PDB, Function, Resolve
    ///
    const PdbFunction *PdbResolveRva(const Pdb *self, u32 rva);
    
    #endif // MISRA_PARSERS_PDB_H
        u32 rva = (u32)rva64;
    
        const PdbFunction *f = PdbResolveRva(&entry->pdb, rva);
        if (!f)
            return false;
        for (size i = 0; i < VecLen(&pending); ++i) {
            const PendingPub *pp = VecPtrAt(&pending, i);
            PdbFunction       f  = {
                       .rva  = pp->rva,
                       .size = 0,
    }
    
    const PdbFunction *PdbResolveRva(const Pdb *self, u32 rva) {
        if (!self || VecLen(&self->functions) == 0)
            return NULL;
        while (lo < hi) {
            size mid = lo + (hi - lo) / 2;
            if (((const PdbFunction *)VecPtrAt(&self->functions, mid))->rva <= rva)
                lo = mid + 1;
            else
        if (lo == 0)
            return NULL;
        const PdbFunction *f = VecPtrAt(&self->functions, lo - 1);
        // size == 0 means "until next entry"; we already accept that case.
        // Widen to u64 to avoid u32 wrap: rva and size are both u32, so a
        bool ok = VecLen(&pdb.functions) == 1;
        if (ok) {
            const PdbFunction *f = VecPtrAt(&pdb.functions, 0);
            ok                   = f->rva == 0x1100 && ZstrCompare(f->name, "deepblk") == 0;
        }
        bool ok     = opened && VecLen(&pdb.functions) == 1 && pdb.num_streams == N;
        if (ok) {
            const PdbFunction *f = VecPtrAt(&pdb.functions, 0);
            ok                   = f->rva == 0x1100 && ZstrCompare(f->name, "deepfn") == 0;
        }
        bool ok     = opened && VecLen(&pdb.functions) == 1;
        if (ok) {
            const PdbFunction *f = VecPtrAt(&pdb.functions, 0);
            ok                   = f->rva == 0x1100 && ZstrCompare(f->name, "fn") == 0;
        }
        ok = VecLen(&pdb.functions) == 1;
        if (ok) {
            const PdbFunction *f = VecPtrAt(&pdb.functions, 0);
            ok                   = ok && f->rva == 0x1100 && f->name && ZstrCompare(f->name, "my_function") == 0;
        }
        // Direct lookup by RVA.
        if (ok) {
            const PdbFunction *f = PdbResolveRva(&pdb, 0x1100);
            ok                   = f && ZstrCompare(f->name, "my_function") == 0;
        }
        // Functions are stored sorted by RVA regardless of input order.
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *f2 = VecPtrAt(&pdb.functions, 2);
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *f2 = VecPtrAt(&pdb.functions, 2);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "fn_alpha") == 0;
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *f2 = VecPtrAt(&pdb.functions, 2);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "fn_alpha") == 0;
            ok                    = ok && f1->rva == 0x1200 && ZstrCompare(f1->name, "fn_beta") == 0;
        // Exact starts.
        if (ok) {
            const PdbFunction *a = PdbResolveRva(&pdb, 0x1100);
            const PdbFunction *b = PdbResolveRva(&pdb, 0x1200);
            const PdbFunction *c = PdbResolveRva(&pdb, 0x1300);
        if (ok) {
            const PdbFunction *a = PdbResolveRva(&pdb, 0x1100);
            const PdbFunction *b = PdbResolveRva(&pdb, 0x1200);
            const PdbFunction *c = PdbResolveRva(&pdb, 0x1300);
            ok                   = ok && a && ZstrCompare(a->name, "fn_alpha") == 0;
            const PdbFunction *a = PdbResolveRva(&pdb, 0x1100);
            const PdbFunction *b = PdbResolveRva(&pdb, 0x1200);
            const PdbFunction *c = PdbResolveRva(&pdb, 0x1300);
            ok                   = ok && a && ZstrCompare(a->name, "fn_alpha") == 0;
            ok                   = ok && b && ZstrCompare(b->name, "fn_beta") == 0;
        // first/only entry.
        if (ok) {
            const PdbFunction *mid_a = PdbResolveRva(&pdb, 0x11FF); // inside alpha
            const PdbFunction *mid_b = PdbResolveRva(&pdb, 0x12AB); // inside beta
            ok                       = ok && mid_a && ZstrCompare(mid_a->name, "fn_alpha") == 0;
        if (ok) {
            const PdbFunction *mid_a = PdbResolveRva(&pdb, 0x11FF); // inside alpha
            const PdbFunction *mid_b = PdbResolveRva(&pdb, 0x12AB); // inside beta
            ok                       = ok && mid_a && ZstrCompare(mid_a->name, "fn_alpha") == 0;
            ok                       = ok && mid_b && ZstrCompare(mid_b->name, "fn_beta") == 0;
        int n = (int)VecLen(&pdb.functions);
        if (n >= 1 && out_rva0)
            *out_rva0 = ((const PdbFunction *)VecPtrAt(&pdb.functions, 0))->rva;
        PdbDeinit(&pdb);
        return n;
        ok = VecLen(&pdb.functions) == 4;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *f2 = VecPtrAt(&pdb.functions, 2);
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *f2 = VecPtrAt(&pdb.functions, 2);
            const PdbFunction *f3 = VecPtrAt(&pdb.functions, 3);
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *f2 = VecPtrAt(&pdb.functions, 2);
            const PdbFunction *f3 = VecPtrAt(&pdb.functions, 3);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "fn_one") == 0;
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *f2 = VecPtrAt(&pdb.functions, 2);
            const PdbFunction *f3 = VecPtrAt(&pdb.functions, 3);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "fn_one") == 0;
            ok                    = ok && f1->rva == 0x1200 && ZstrCompare(f1->name, "fn_two") == 0;
        if (ok) {
            for (size i = 0; i < VecLen(&pdb.functions); ++i) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, i);
                if (ZstrCompare(f->name, "data_sym") == 0) {
                    ok = false;
        if (ok) {
            // sorted: 0x1040 (text) then 0x8010 (rdata)
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x1040 && ZstrCompare(f0->name, "in_text") == 0;
            // sorted: 0x1040 (text) then 0x8010 (rdata)
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x1040 && ZstrCompare(f0->name, "in_text") == 0;
            ok                    = ok && f1->rva == 0x8010 && ZstrCompare(f1->name, "in_rdata") == 0;
        // second section's VA (0x8000) was used -- not section[0]'s 0x1000.
        if (ok) {
            const PdbFunction *r = PdbResolveRva(&pdb, 0x8010);
            ok                   = r && ZstrCompare(r->name, "in_rdata") == 0;
        }
        }
        if (ok) {
            const PdbFunction *t = PdbResolveRva(&pdb, 0x1040);
            ok                   = t && ZstrCompare(t->name, "in_text") == 0;
        }
        ok = VecLen(&pdb.functions) == 2;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "valid_fn") == 0;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "valid_fn") == 0;
            ok                    = ok && f1->rva == 0x1200 && ZstrCompare(f1->name, "valid_fn2") == 0;
        if (ok) {
            for (size i = 0; i < VecLen(&pdb.functions); ++i) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, i);
                if (ZstrCompare(f->name, "bad_seg_fn") == 0) {
                    ok = false;
        ok = VecLen(&pdb.functions) == 3;
        if (ok) {
            const PdbFunction *a = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *b = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *c = VecPtrAt(&pdb.functions, 2);
        if (ok) {
            const PdbFunction *a = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *b = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *c = VecPtrAt(&pdb.functions, 2);
            ok                   = ok && a->rva == 0x1100 && a->size == 0x200; // 0x1300 - 0x1100
            const PdbFunction *a = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *b = VecPtrAt(&pdb.functions, 1);
            const PdbFunction *c = VecPtrAt(&pdb.functions, 2);
            ok                   = ok && a->rva == 0x1100 && a->size == 0x200; // 0x1300 - 0x1100
            ok                   = ok && b->rva == 0x1300 && b->size == 0x80;  // 0x1380 - 0x1300
        // computed sizes being correct.
        if (ok) {
            const PdbFunction *mid = PdbResolveRva(&pdb, 0x12FF);
            ok                     = mid && ZstrCompare(mid->name, "fn_a") == 0;
        }
        }
        if (ok) {
            const PdbFunction *atb = PdbResolveRva(&pdb, 0x1300);
            ok                     = atb && ZstrCompare(atb->name, "fn_b") == 0;
        }
        // Trailing function: any rva >= its start resolves to it.
        if (ok) {
            const PdbFunction *tail = PdbResolveRva(&pdb, 0x9999);
            ok                      = tail && ZstrCompare(tail->name, "fn_c") == 0;
        }
            u32 prev = 0;
            for (size i = 0; i < VecLen(&pdb.functions); ++i) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, i);
                if (i > 0 && !(f->rva > prev)) {
                    ok = false;
        // would flip these.
        if (ok) {
            const PdbFunction *first = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *last  = VecPtrAt(&pdb.functions, 4);
            ok                       = ok && first->rva == 0x1100 && ZstrCompare(first->name, "a") == 0;
        if (ok) {
            const PdbFunction *first = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *last  = VecPtrAt(&pdb.functions, 4);
            ok                       = ok && first->rva == 0x1100 && ZstrCompare(first->name, "a") == 0;
            ok                       = ok && last->rva == 0x1500 && ZstrCompare(last->name, "e") == 0;
        ok = VecLen(&pdb.functions) == 2;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "fn_keep") == 0;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x1100 && ZstrCompare(f0->name, "fn_keep") == 0;
            ok                    = ok && f1->rva == 0x1300 && ZstrCompare(f1->name, "fn_keep2") == 0;
        if (ok) {
            for (size i = 0; i < VecLen(&pdb.functions); ++i) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, i);
                if (ZstrCompare(f->name, "AAAAAAAA") == 0) {
                    ok = false;
        ok = VecLen(&pdb.functions) == 2;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x2050u && ZstrCompare(f0->name, "fn_low") == 0;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0);
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1);
            ok                    = ok && f0->rva == 0x2050u && ZstrCompare(f0->name, "fn_low") == 0;
            ok                    = ok && f1->rva == 0xFFFFFFFFu && ZstrCompare(f1->name, "fn_max") == 0;
        if (ok) {
            for (size i = 0; i < VecLen(&pdb.functions); ++i) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, i);
                if (ZstrCompare(f->name, "fn_ovf") == 0) {
                    ok = false;
        // `cur = next` advanced correctly through the overflow branch.
        if (ok) {
            const PdbFunction *r = PdbResolveRva(&pdb, 0x2050);
            ok                   = r && ZstrCompare(r->name, "fn_low") == 0;
        }
        ok = VecLen(&pdb.functions) == 2;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0); // rva 0x2000
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1); // rva 0x3000
            ok                    = ok && f0->rva == 0x2000 && ZstrCompare(f0->name, "second_block_function") == 0;
        if (ok) {
            const PdbFunction *f0 = VecPtrAt(&pdb.functions, 0); // rva 0x2000
            const PdbFunction *f1 = VecPtrAt(&pdb.functions, 1); // rva 0x3000
            ok                    = ok && f0->rva == 0x2000 && ZstrCompare(f0->name, "second_block_function") == 0;
            ok                    = ok && f1->rva == 0x3000 && ZstrCompare(f1->name, "straddling_boundary_function") == 0;
        // sides of the block boundary; resolve it to be sure.
        if (ok) {
            const PdbFunction *f = PdbResolveRva(&pdb, 0x3000);
            ok                   = f && ZstrCompare(f->name, "straddling_boundary_function") == 0;
        }
        }
    
        const PdbFunction *first = PdbResolveRva(&pdb, 0x2000);
        ok                       = first && ZstrCompare(first->name, "second_block_function") == 0;
        ok                       = ok && PdbResolveRva(&pdb, 0x1FFF) == NULL; // below first
        // rva <= query, not the first/only entry).
        if (ok) {
            const PdbFunction *mid = PdbResolveRva(&pdb, 0x2500);
            ok                     = mid && ZstrCompare(mid->name, "second_block_function") == 0;
        }
            ok = VecLen(&pdb.functions) == 1;
            if (ok) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, 0);
                ok                   = f->rva == 0x6010 && ZstrCompare(f->name, "sixth") == 0;
            }
            ok = VecLen(&pdb.functions) == 1;
            if (ok) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, 0);
                ok                   = f->rva == 0x1040 && ZstrCompare(f->name, "good") == 0;
            }
            ok = VecLen(&pdb.functions) == 3;
            if (ok) {
                const PdbFunction *a = VecPtrAt(&pdb.functions, 0);            // alpha 0x1100
                const PdbFunction *b = VecPtrAt(&pdb.functions, 1);            // beta  0x1200
                const PdbFunction *c = VecPtrAt(&pdb.functions, 2);            // gamma 0x1300
            if (ok) {
                const PdbFunction *a = VecPtrAt(&pdb.functions, 0);            // alpha 0x1100
                const PdbFunction *b = VecPtrAt(&pdb.functions, 1);            // beta  0x1200
                const PdbFunction *c = VecPtrAt(&pdb.functions, 2);            // gamma 0x1300
                ok                   = ok && a->rva == 0x1100 && a->size == 0x100;
                const PdbFunction *a = VecPtrAt(&pdb.functions, 0);            // alpha 0x1100
                const PdbFunction *b = VecPtrAt(&pdb.functions, 1);            // beta  0x1200
                const PdbFunction *c = VecPtrAt(&pdb.functions, 2);            // gamma 0x1300
                ok                   = ok && a->rva == 0x1100 && a->size == 0x100;
                ok                   = ok && b->rva == 0x1200 && b->size == 0x100;
            ok = VecLen(&pdb.functions) == 1;
            if (ok) {
                const PdbFunction *f = VecPtrAt(&pdb.functions, 0);
                ok                   = f->rva == 0x1010 && ZstrCompare(f->name, "named_fn") == 0;
            }
Last updated on