Skip to content
DwarfLinesResolve

DwarfLinesResolve

Description

Find the entry covering vaddr (file-relative virtual address). The match is the row with the greatest address <= vaddr whose sequence has not ended; if vaddr falls past the last row of every sequence, returns NULL.

Success

Returns a pointer to the matching entry inside self->entries. Valid until DwarfLinesDeinit.

Failure

Returns NULL when no row covers vaddr.

Usage example (Cross-references)

Usage examples (Cross-references)
        const DwarfLineEntry *de = NULL;
        if (cache_entry->dwarf_ok) {
            de = DwarfLinesResolve(&cache_entry->dwarf, file_relative);
        }
        if (!de && cache_entry->has_sidecar) {
            }
            if (cache_entry->sidecar_dwarf_ok) {
                de = DwarfLinesResolve(&cache_entry->sidecar_dwarf, file_relative);
            }
        }
    // ---------------------------------------------------------------------------
    
    const DwarfLineEntry *DwarfLinesResolve(const DwarfLines *self, u64 vaddr) {
        if (!self || VecLen(&self->entries) == 0)
            return NULL;
        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;
        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;
    
            // An address inside the first row's range still maps to line 10.
            e  = DwarfLinesResolve(&lines, 0x2004);
            ok = ok && e && e->line == 10;
    
            // Address 0x2008 -> source.c:20
            e  = DwarfLinesResolve(&lines, 0x2008);
            ok = ok && e && e->line == 20;
    
            // Below the first row's address -> unresolved.
            ok = ok && DwarfLinesResolve(&lines, 0x1000) == NULL;
    
            // At/after the end_sequence boundary -> unresolved.
    
            // At/after the end_sequence boundary -> unresolved.
            ok = ok && DwarfLinesResolve(&lines, 0x2010) == NULL;
    
            DwarfLinesDeinit(&lines);
        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
        // Just below 0x3002 there is no covering row (only the special-opcode
        // row exists before end_sequence), so a lower address misses.
        ok = ok && DwarfLinesResolve(&fx.lines, 0x3001) == NULL;
        // The file is source.c (default file 1).
        ok = ok && e && e->file && ZstrFindSubstring(e->file, "source.c") != NULL;
    
        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;
        const DwarfLineEntry *e  = DwarfLinesResolve(&fx.lines, 0x5001);
        ok                       = ok && e && e->line == 51 && e->address == 0x5001;
        ok                       = ok && DwarfLinesResolve(&fx.lines, 0x5000) == NULL;
        lines_fixture_close(&fx);
        return ok;
        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
        // div_to_mul (242*14 huge -> saturates to u64 max) both move the row off
        // 0x7011. Pin that nothing covers an address just below 0x7011.
        ok = ok && DwarfLinesResolve(&fx.lines, 0x7010) == NULL;
        lines_fixture_close(&fx);
        return ok;
        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.
        ok                      = ok && e && e->line == 10;
        // An address inside [0x13000, 0x13020) still maps to the real row.
        e  = DwarfLinesResolve(&fx.lines, 0x13010);
        ok = ok && e && e->line == 10;
        // At/after the end_sequence boundary -> unresolved (closing row is not a
        // lookup target). If end_sequence were set to false, the closing row at
        // 0x13020 would resolve instead of returning NULL.
        ok = ok && DwarfLinesResolve(&fx.lines, 0x13020) == NULL;
        lines_fixture_close(&fx);
        return ok;
    
        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
        // the row off 0x150000.
        ok = ok && e && e->address == 0x00150000u && e->line == 34;
        ok = ok && DwarfLinesResolve(&fx.lines, 0x0014ffffu) == NULL;
        lines_fixture_close(&fx);
        return ok;
            // 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.
            ok                      = ok && e && e->line == 42;
            // The byte right before the fixed advance still maps to row 1.
            e  = DwarfLinesResolve(&lines, 0x5122);
            ok = ok && e && e->address == 0x5000 && e->line == 42;
            // Exactly at the fixed-advanced address: distinct second row.
            ok = ok && e && e->address == 0x5000 && e->line == 42;
            // Exactly at the fixed-advanced address: distinct second row.
            e  = DwarfLinesResolve(&lines, 0x5123);
            ok = ok && e && e->address == 0x5123 && e->line == 42;
            DwarfLinesDeinit(&lines);
        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.
            ok                      = ok && e && e->address == 0x8000 + 0x7abc;
            // Just below the second row -> still the first row.
            e  = DwarfLinesResolve(&lines, 0x8000 + 0x7abc - 1);
            ok = ok && e && e->address == 0x8000;
            DwarfLinesDeinit(&lines);
        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
            // Below the emitted address -> nothing (no row at/below 0x6002
            // other than the one we emitted; 0x6001 < 0x6002).
            ok = ok && DwarfLinesResolve(&lines, 0x6001) == NULL;
            // The file string came through.
            ok = ok && e->file && ZstrFindSubstring(e->file, "source.c") != NULL;
        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.
            ok                      = ok && e && e->address == 0x7000 && e->line == 42;
            // Second special opcode: address advanced by 3, line 48.
            e  = DwarfLinesResolve(&lines, 0x7003);
            ok = ok && e && e->address == 0x7003 && e->line == 48;
            DwarfLinesDeinit(&lines);
            }
            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);
            const DwarfLineEntry *e = DwarfLinesResolve(&lines, 0xD000);
            ok                      = ok && e && e->address == 0xD000 && e->line == 10;
            e                       = DwarfLinesResolve(&lines, 0xE000);
            ok                      = ok && e && e->address == 0xE000 && e->line == 50;
            // The gap between sequences (after seq 1's end_sequence at 0xD000,
            // The gap between sequences (after seq 1's end_sequence at 0xD000,
            // before seq 2) does not resolve to seq 1.
            ok = ok && DwarfLinesResolve(&lines, 0xCFFF) == NULL;
            DwarfLinesDeinit(&lines);
        }
        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;
    
        // Inside the first row's [0x2000, 0x2008) span -> still line 10.
        e  = DwarfLinesResolve(&lines, 0x2004);
        ok = ok && e && e->line == 10;
    
        // 0x2008 -> line 20, same file/dir.
        e  = DwarfLinesResolve(&lines, 0x2008);
        ok = ok && e && e->line == 20;
        ok = ok && e && e->file && ZstrFindSubstring(e->file, "second.c") != NULL;
    
        // Below the first address and at/after end_sequence -> unresolved.
        ok = ok && DwarfLinesResolve(&lines, 0x1fff) == NULL;
        ok = ok && DwarfLinesResolve(&lines, 0x2010) == NULL;
        // Below the first address and at/after end_sequence -> unresolved.
        ok = ok && DwarfLinesResolve(&lines, 0x1fff) == NULL;
        ok = ok && DwarfLinesResolve(&lines, 0x2010) == NULL;
    
        DwarfLinesDeinit(&lines);
    
        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;
        ok                       = ok && e && e->line == 3;
        // Below the emitted row's address -> unresolved.
        ok = ok && DwarfLinesResolve(&lines, 0x5000) == NULL;
    
        DwarfLinesDeinit(&lines);
    
        // 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;
        // Sequence 2: 0x7000 -> first.c:5  (only correct if reset restored
        // file=1 and line=1 between sequences).
        e  = DwarfLinesResolve(&lines, 0x7000);
        ok = ok && e && e->file && ZstrFindSubstring(e->file, "first.c") != NULL;
        ok = ok && e && e->line == 5;
    
        // The gap between sequences (0x6008 .. 0x7000) is unresolved.
        ok = ok && DwarfLinesResolve(&lines, 0x6800) == NULL;
    
        DwarfLinesDeinit(&lines);
    
        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;
            ok                      = ok && e && e->file && ZstrCompare(e->file, "source.c") == 0 && e->line == 10;
    
            e  = DwarfLinesResolve(&lines, 0x2008);
            ok = ok && e && e->file && ZstrCompare(e->file, "source.c") == 0 && e->line == 20;
        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.
            ok                      = ok && e && e->line == 10;
            // Strictly inside the first row's [0x2000, 0x2008) span -> line 10.
            e  = DwarfLinesResolve(&lines, 0x2004);
            ok = ok && e && e->line == 10;
            // Exact hit on the second row's address.
            ok = ok && e && e->line == 10;
            // Exact hit on the second row's address.
            e  = DwarfLinesResolve(&lines, 0x2008);
            ok = ok && e && e->line == 20;
            // Strictly inside the second row's [0x2008, 0x2010) span -> line 20.
            ok = ok && e && e->line == 20;
            // Strictly inside the second row's [0x2008, 0x2010) span -> line 20.
            e  = DwarfLinesResolve(&lines, 0x200f);
            ok = ok && e && e->line == 20;
            // Strictly below the first address -> no row.
            ok = ok && e && e->line == 20;
            // Strictly below the first address -> no row.
            ok = ok && DwarfLinesResolve(&lines, 0x1fff) == NULL;
            // At the end_sequence boundary (exclusive upper) -> no row.
            ok = ok && DwarfLinesResolve(&lines, 0x2010) == NULL;
            ok = ok && DwarfLinesResolve(&lines, 0x1fff) == NULL;
            // At the end_sequence boundary (exclusive upper) -> no row.
            ok = ok && DwarfLinesResolve(&lines, 0x2010) == NULL;
            // Above the last sequence -> no row.
            ok = ok && DwarfLinesResolve(&lines, 0x3000) == NULL;
            ok = ok && DwarfLinesResolve(&lines, 0x2010) == NULL;
            // Above the last sequence -> no row.
            ok = ok && DwarfLinesResolve(&lines, 0x3000) == NULL;
    
            DwarfLinesDeinit(&lines);
            // 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