Skip to content
DwarfLineEntry

DwarfLineEntry

Description

One row of the line-number matrix. address is the file-relative virtual address (the same address-space as ElfSymbol.value), so a caller who already did runtime_addr - module_base (e.g. via SymbolResolver) can feed the result directly to DwarfLinesResolve.

Fields

Name Description
address Code address this row applies to.
file Source filename (borrowed from internal string pool).
dir Compilation directory hint, may be NULL.
line Source line number (1-based, 0 means “no line”).
column Source column (1-based, 0 means “no column”).
is_stmt True at statement boundaries — preferred breakpoints.
end_sequence True for the synthetic row that closes a contiguous range. Lookups never return such a row.

Usage example (Cross-references)

Usage examples (Cross-references)
        bool is_stmt;
        bool end_sequence;
    } DwarfLineEntry;
    
    typedef Vec(DwarfLineEntry) DwarfLineEntries;
    } DwarfLineEntry;
    
    typedef Vec(DwarfLineEntry) DwarfLineEntries;
    
    ///
    /// TAGS: Parser, DWARF, Lookup
    ///
    const DwarfLineEntry *DwarfLinesResolve(const DwarfLines *self, u64 vaddr);
    
    ///
            cache_entry->dwarf_ok    = DwarfLinesBuildFromElf(&cache_entry->dwarf, &cache_entry->elf, self->allocator);
        }
        const DwarfLineEntry *de = NULL;
        if (cache_entry->dwarf_ok) {
            de = DwarfLinesResolve(&cache_entry->dwarf, file_relative);
        U64Vec          *pending_dir_offsets
    ) {
        DwarfLineEntry e;
        MemSet(&e, 0, sizeof(e));
        e.address      = st->address;
    // ---------------------------------------------------------------------------
    
    const DwarfLineEntry *DwarfLinesResolve(const DwarfLines *self, u64 vaddr) {
        if (!self || VecLen(&self->entries) == 0)
            return NULL;
        // by end_sequence rows; vaddr must not exceed the sequence's
        // closing row.
        const DwarfLineEntry *best     = NULL;
        const DwarfLineEntry *seq_open = NULL;
        for (u64 i = 0; i < VecLen(&self->entries); ++i) {
        // closing row.
        const DwarfLineEntry *best     = NULL;
        const DwarfLineEntry *seq_open = NULL;
        for (u64 i = 0; i < VecLen(&self->entries); ++i) {
            const DwarfLineEntry *e = VecPtrAt(&self->entries, i);
        const DwarfLineEntry *seq_open = NULL;
        for (u64 i = 0; i < VecLen(&self->entries); ++i) {
            const DwarfLineEntry *e = VecPtrAt(&self->entries, i);
            if (e->end_sequence) {
                // Sequence ends at this row's address (exclusive upper).
        bool       ok    = built;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x3000);
            // Out-of-range file -> no file string (NULL), not a bogus pointer.
            ok = ok && e && e->file == NULL;
        bool       ok    = built;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x3300);
            // file present, but dir index 0 -> dir must be NULL, not pool+42.
            ok = ok && e && e->file && ZstrFindSubstring(e->file, "only.c") != NULL;
    static bool first_real_row_address(const DwarfLines *lines, u64 *out) {
        for (u64 i = 0; i < VecLen(&lines->entries); ++i) {
            const DwarfLineEntry *e = &VecAt(&lines->entries, i);
            if (!e->end_sequence) {
                *out = e->address;
        bool       ok    = false;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, file_relative);
            if (e && e->file && ZstrFindSubstring(e->file, "Dwarf.c") != NULL && e->line > 0) {
                ok = true;
    
            // Address 0x2000 -> source.c:10
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x2000);
            ok                      = ok && e && e->file && ZstrFindSubstring(e->file, "source.c") != NULL && e->line == 10;
        bool ok = true;
        // The special opcode emitted a row at 0x3002, line 95.
        const DwarfLineEntry *e = DwarfLinesResolve(&fx.lines, 0x3002);
        ok                      = ok && e && e->line == 95 && e->address == 0x3002;
        // Just below 0x3002 there is no covering row (only the special-opcode
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&fx.lines, 0x5001);
        ok                       = ok && e && e->line == 51 && e->address == 0x5001;
        ok                       = ok && DwarfLinesResolve(&fx.lines, 0x5000) == NULL;
        bool ok = true;
        // Row landed at 0x7000 + 17 = 0x7011.
        const DwarfLineEntry *e = DwarfLinesResolve(&fx.lines, 0x7011);
        ok                      = ok && e && e->address == 0x7011 && e->line == 42;
        // 255-13=242 (sub_to_add mutation -> 268, /14 = 19 -> addr 0x7013) and
        bool ok = true;
        // A row must exist at 0x9000 with line 75 (special opcode 13 emitted it).
        const DwarfLineEntry *e = DwarfLinesResolve(&fx.lines, 0x9000);
        ok                      = ok && e && e->address == 0x9000 && e->line == 75;
        lines_fixture_close(&fx);
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&fx.lines, 0xB000);
        ok                       = ok && e && e->file;
        // Must be "other.c" (file 2), and NOT "source.c". `st.file = f` mutated
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&fx.lines, 0xB800);
        ok                       = ok && e && e->file && ZstrFindSubstring(e->file, "source.c") != NULL;
        lines_fixture_close(&fx);
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&fx.lines, 0xD000);
        ok                       = ok && e && e->column == 37;
        lines_fixture_close(&fx);
    
        bool                  ok = true;
        const DwarfLineEntry *e0 = DwarfLinesResolve(&fx.lines, 0xF000);
        ok                       = ok && e0 && e0->is_stmt == true;
        const DwarfLineEntry *e1 = DwarfLinesResolve(&fx.lines, 0xF010);
        const DwarfLineEntry *e0 = DwarfLinesResolve(&fx.lines, 0xF000);
        ok                       = ok && e0 && e0->is_stmt == true;
        const DwarfLineEntry *e1 = DwarfLinesResolve(&fx.lines, 0xF010);
        ok                       = ok && e1 && e1->is_stmt == false;
        lines_fixture_close(&fx);
    
        bool                  ok = true;
        const DwarfLineEntry *e1 = DwarfLinesResolve(&fx.lines, 0x11000);
        ok                       = ok && e1 && e1->line == 500;
        // Second sequence's row: line must be 7 (clean reset), not 506.
        ok                       = ok && e1 && e1->line == 500;
        // Second sequence's row: line must be 7 (clean reset), not 506.
        const DwarfLineEntry *e2 = DwarfLinesResolve(&fx.lines, 0x12000);
        ok                       = ok && e2 && e2->line == 7;
        lines_fixture_close(&fx);
        bool ok = true;
        // The real row resolves.
        const DwarfLineEntry *e = DwarfLinesResolve(&fx.lines, 0x13000);
        ok                      = ok && e && e->line == 10;
        // An address inside [0x13000, 0x13020) still maps to the real row.
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&fx.lines, 0x00150000u);
        // 4-byte decode must reconstruct the full address 0x150000 and emit the
        // row there. A broken == 4 branch / wrong decode / address = const moves
            // malformed record must not have produced a second resolvable row at
            // an out-of-range address derived from over-read bytes.
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x17000);
            // The only acceptable success is: either no rows, or the single safe
            // row, with end correctly bounded.
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&fx.lines, 0x18000);
        ok                       = ok && e && e->address == 0x18000 && e->line == 22;
        lines_fixture_close(&fx);
        if (built) {
            // First row at 0x5000, line 42.
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x5000);
            ok                      = ok && e && e->line == 42;
            // The byte right before the fixed advance still maps to row 1.
        bool       ok    = built;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x8000 + 0x7abc);
            ok                      = ok && e && e->address == 0x8000 + 0x7abc;
            // Just below the second row -> still the first row.
        if (built) {
            // The special opcode emitted exactly one real row at 0x6002:14.
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x6002);
            ok                      = ok && e && e->address == 0x6002 && e->line == 14;
            // Below the emitted address -> nothing (no row at/below 0x6002
        if (built) {
            // First special opcode: same address (addr_adv 0), line 42.
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x7000);
            ok                      = ok && e && e->address == 0x7000 && e->line == 42;
            // Second special opcode: address advanced by 3, line 48.
            u64 real_rows = 0;
            for (u64 i = 0; i < VecLen(&lines.entries); ++i) {
                const DwarfLineEntry *e = &VecAt(&lines.entries, i);
                if (!e->end_sequence)
                    ++real_rows;
            }
            ok                      = ok && real_rows >= 1;
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x9002);
            ok                      = ok && e && e->address == 0x9002;
            DwarfLinesDeinit(&lines);
        bool       ok    = built;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0xA000);
            ok                      = ok && e && e->address == 0xA000 && e->line == 7;
            DwarfLinesDeinit(&lines);
        bool       ok    = built;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0xB000);
            ok                      = ok && e && e->address == 0xB000 && e->line == 5;
            DwarfLinesDeinit(&lines);
        bool       ok    = built;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0xC000);
            ok                      = ok && e && e->address == 0xC000 && e->line == 3;
            DwarfLinesDeinit(&lines);
        bool       ok    = built;
        if (built) {
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0xD000);
            ok                      = ok && e && e->address == 0xD000 && e->line == 10;
            e                       = DwarfLinesResolve(&lines, 0xE000);
        ok = ok && VecLen(&lines.entries) == 3;
    
        const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x2000);
        ok                      = ok && e && e->file && ZstrFindSubstring(e->file, "second.c") != NULL;
        ok                      = ok && e && e->dir && ZstrFindSubstring(e->dir, "real_dir") != NULL;
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&lines, 0x3000);
        ok                       = ok && e && e->file && ZstrFindSubstring(e->file, "first.c") != NULL;
        ok                       = ok && e && e->line == 7;
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&lines, 0x5001);
        ok                       = ok && e && e->address == 0x5001;
        ok                       = ok && e && e->line == 3;
    
        // Sequence 1: 0x6000 -> second.c:100
        const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x6000);
        ok                      = ok && e && e->file && ZstrFindSubstring(e->file, "second.c") != NULL;
        ok                      = ok && e && e->line == 100;
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&lines, 0x8000);
        ok                       = ok && e && e->line == 4;
        ok                       = ok && e && e->is_stmt == false;
            ok = ok && VecLen(&lines.entries) >= 2;
    
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x2000);
            ok                      = ok && e && e->file && ZstrCompare(e->file, "source.c") == 0 && e->line == 10;
        if (built) {
            // Exact hit on the first row's address.
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x2000);
            ok                      = ok && e && e->line == 10;
            // Strictly inside the first row's [0x2000, 0x2008) span -> line 10.
            // Sanity: the file/dir tables really populated (otherwise the
            // CuStrings vectors never allocate and the leak is unobservable).
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x2000);
            ok                      = ok && e && e->file && ZstrCompare(e->file, "source.c") == 0;
            DwarfLinesDeinit(&lines);
            // The pool must really hold the "source.c" string so its buffer
            // is a distinct live allocation the deinit has to release.
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0x2000);
            ok                      = ok && e && e->file && ZstrCompare(e->file, "source.c") == 0;
            // After the build there must be live allocations to release.
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&lines, 0x2000);
        ok                       = ok && e && e->line == 10;
        ok                       = ok && e && e->file && ZstrFindSubstring(e->file, "second.c") != NULL;
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&lines, 0x4000);
        // Only an exact table-skip places the program at the SET_ADDRESS opcode,
        // so the row exists at 0x4000 with line 42 and file "first.c".
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&lines, 0x4400);
        ok                       = ok && e && e->address == 0x4400 && e->line == 22;
        ok                       = ok && e && e->file && ZstrFindSubstring(e->file, "second.c") != NULL;
    
        bool                  ok = true;
        const DwarfLineEntry *e  = DwarfLinesResolve(&lines, 0x6000);
        ok                       = ok && e && e->address == 0x6000 && e->line == 10;
Last updated on