Skip to content

Pdb

Description

Parsed PDB file. Holds the raw bytes (always parser-owned) plus decoded indices into them. All three PdbOpen* constructors leave the parser as sole owner of data – see the L / R semantics on the FromMemory / FromMemoryCopy constructors (mirrors VecInsertL / VecInsertR).

Fields

Name Description
allocator Allocator backing data + the functions vec.
data Raw PDB bytes (owned).
data_size Length of data in bytes.
block_size MSF page size (read from the superblock; usually 4096 but can be 512/1024/2048).
num_streams Stream count from the directory.
info Decoded PDB Info stream (#1).
functions Sorted-by-rva list of public function names from the Publics stream. Populated by PdbOpen[FromMemory].

Usage example (Cross-references)

Usage examples (Cross-references)
    
    #include <Misra.h>
    #include <Misra/Parsers/Pdb.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Std/Allocator/Default.h>
        build_msf_blob();
    
        Pdb pdb;
        bool    ok = PdbOpenFromMemoryCopy(&pdb, blob, sizeof(blob), base);
        if (!ok) {
        MemSet(garbage, 0xCC, sizeof(garbage));
    
        Pdb pdb;
        bool    ok = !PdbOpenFromMemoryCopy(&pdb, garbage, sizeof(garbage), base);
        build_full_pdb_blob();
    
        Pdb pdb;
        bool    ok = PdbOpenFromMemoryCopy(&pdb, fblob, sizeof(fblob), base);
        if (!ok) {
    
    int main(void) {
        WriteFmt("[INFO] Starting Pdb tests\n\n");
    
        TestFunction tests[] = {
        };
    
        return run_test_suite(tests, sizeof(tests) / sizeof(tests[0]), NULL, 0, "Pdb");
    }
    
    #include <Misra/Std/Container/Buf.h>
    #include <Misra/Parsers/Pdb.h>
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    // Return a pointer to the first byte of block `block_id` inside the
    // PDB file. NULL on out-of-range.
    static const u8 *block_ptr(const Pdb *self, u32 block_id) {
        u64 off = (u64)block_id * self->block_size;
        if (off + self->block_size > BufLength(&self->data))
    // Read `n` bytes from stream `idx` starting at byte offset `offset`
    // into `dest`. Walks the stream's block chain.
    static bool stream_read(const Pdb *self, u32 idx, u64 offset, u8 *dest, u64 n) {
        if (idx >= self->num_streams)
            return false;
    // ---------------------------------------------------------------------------
    
    static bool parse_superblock(Pdb *self, u32 *out_num_dir_bytes, u32 *out_block_map_addr) {
        if (BufLength(&self->data) < SUPERBLOCK_SIZE) {
            LOG_ERROR("PDB: file too small for MSF superblock");
    
    // Reconstruct the stream directory into a contiguous buffer.
    static bool reconstruct_directory(Pdb *self, u32 num_dir_bytes, u32 block_map_addr) {
        // The block_map_addr page holds an array of u32 block indices,
        // one per `block_size` chunk of the directory. The number of
    
    // Parse the reconstructed directory bytes into per-stream metadata.
    static bool parse_directory(Pdb *self) {
        if (self->stream_dir_size < 4) {
            LOG_ERROR("PDB: directory truncated (no stream count)");
    // ---------------------------------------------------------------------------
    
    static bool parse_pdb_info(Pdb *self) {
        if (self->num_streams <= 1)
            return true; // no info stream
    } DbiSubstreamInfo;
    
    static DbiSubstreamInfo parse_dbi_header(const Pdb *self) {
        DbiSubstreamInfo r = {0};
        if (DBI_STREAM_INDEX >= self->num_streams)
    // return a small allocator-backed array of (RVA, VSize) pairs. Caller
    // frees via AllocatorFree.
    static SectionRva *load_section_table(const Pdb *self, u16 section_hdr_stream, u32 *out_count) {
        *out_count = 0;
        if (section_hdr_stream >= self->num_streams)
    
    static bool walk_publics(
        const Pdb        *self,
        u16               symrec_stream,
        const SectionRva *sections,
    
    // Top-level: pull DBI -> SectionHdr table + SymRecord stream -> publics.
    static bool parse_pdb_functions(Pdb *self) {
        DbiSubstreamInfo dbi = parse_dbi_header(self);
        if (!dbi.ok)
    // L-value form. `data` is `u8 **` -- ownership of the pointer moves
    // from caller to parser. On exit `*data == NULL` (success or failure).
    bool pdb_open_from_memory(Pdb *out, Buf *in) {
        if (!out || !in || !in->data || !in->allocator) {
            LOG_FATAL("PdbOpenFromMemory: NULL argument (contract violation)");
    
    // R-value form: allocate Buf, copy, hand `&copy` to the L-form.
    bool pdb_open_from_memory_copy(Pdb *out, const u8 *data, size data_size, Allocator *alloc) {
        if (!out || !data || !alloc) {
            LOG_FATAL("PdbOpenFromMemoryCopy: NULL argument (contract violation)");
    }
    
    bool pdb_open(Pdb *out, const char *path, Allocator *alloc) {
        if (!out || !path || !alloc) {
            LOG_FATAL("PdbOpen: NULL argument (contract violation)");
    }
    
    void PdbDeinit(Pdb *self) {
        if (!self)
            return;
    }
    
    const PdbFunction *PdbResolveRva(const Pdb *self, u32 rva) {
        if (!self || self->functions.length == 0)
            return NULL;
    #define MISRA_SYS_PDB_CACHE_H
    
    #include <Misra/Parsers/Pdb.h>
    #include <Misra/Parsers/Pe.h>
    #include <Misra/Std/Allocator.h>
        u64     module_base; // last-seen runtime load base
        Pe  pe;
        Pdb pdb;
        bool    pe_open;
        bool    pdb_open;
        size  name_pool_size;
        size  name_pool_used;
    } Pdb;
    
    ///
    /// TAGS: Parser, PDB, File
    ///
    bool pdb_open(Pdb *out, const char *path, Allocator *alloc);
    #define PdbOpen(...) MISRA_OVERLOAD(PdbOpen, __VA_ARGS__)
    #define PdbOpen_2(out, path)                                                                                           \
    /// TAGS: Parser, PDB, Memory, Ownership
    ///
    bool pdb_open_from_memory(Pdb *out, Buf *in);
    #define PdbOpenFromMemory(out, in) pdb_open_from_memory((out), (in))
    /// TAGS: Parser, PDB, Memory, Copy
    ///
    bool pdb_open_from_memory_copy(Pdb *out, const u8 *data, size data_size, Allocator *alloc);
    #define PdbOpenFromMemoryCopy(...)                    MISRA_OVERLOAD(PdbOpenFromMemoryCopy, __VA_ARGS__)
    #define PdbOpenFromMemoryCopy_3(out, data, data_size) pdb_open_from_memory_copy((out), (data), (data_size), MisraScope)
    /// Release storage owned by a `Pdb`. Safe on a zeroed struct.
    ///
    void PdbDeinit(Pdb *self);
    
    ///
    /// FAILURE : Returns NULL.
    ///
    const PdbFunction *PdbResolveRva(const Pdb *self, u32 rva);
    
    #endif // MISRA_PARSERS_PDB_H
Last updated on