Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

DebugRangeIterator

Dwarf.DebugRangeIterator
const DebugRangeIterator = struct

File

lib/std/debug/Dwarf.zig:695

Code

const DebugRangeIterator = struct {
    base_address: u64,
    section_type: Section.Id,
    di: *const Dwarf,
    endian: Endian,
    compile_unit: *const CompileUnit,
    fr: Reader,

    pub fn init(ranges_value: *const FormValue, di: *const Dwarf, endian: Endian, compile_unit: *const CompileUnit) !@This() {
        const section_type = if (compile_unit.version >= 5) Section.Id.debug_rnglists else Section.Id.debug_ranges;
        const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo;

        const ranges_offset = switch (ranges_value.*) {
            .sec_offset, .udata => |off| off,
            .rnglistx => |idx| off: {
                switch (compile_unit.format) {
                    .@"32" => {
                        const offset_loc = compile_unit.rnglists_base + 4 * idx;
                        if (offset_loc + 4 > debug_ranges.len) return bad();
                        const offset = mem.readInt(u32, debug_ranges[@intCast(offset_loc)..][0..4], endian);
                        break :off compile_unit.rnglists_base + offset;
                    },
                    .@"64" => {
                        const offset_loc = compile_unit.rnglists_base + 8 * idx;
                        if (offset_loc + 8 > debug_ranges.len) return bad();
                        const offset = mem.readInt(u64, debug_ranges[@intCast(offset_loc)..][0..8], endian);
                        break :off compile_unit.rnglists_base + offset;
                    },
                }
            },
            else => return bad(),
        };

        // All the addresses in the list are relative to the value
        // specified by DW_AT.low_pc or to some other value encoded
        // in the list itself.
        // If no starting value is specified use zero.
        const base_address = compile_unit.die.getAttrAddr(di, endian, AT.low_pc, compile_unit) catch |err| switch (err) {
            error.MissingDebugInfo => 0,
            else => return err,
        };

        var fr: Reader = .fixed(debug_ranges);
        fr.seek = cast(usize, ranges_offset) orelse return bad();

        return .{
            .base_address = base_address,
            .section_type = section_type,
            .di = di,
            .endian = endian,
            .compile_unit = compile_unit,
            .fr = fr,
        };
    }

    // Returns the next range in the list, or null if the end was reached.
    pub fn next(self: *@This()) !?PcRange {
        const endian = self.endian;
        const addr_size_bytes = self.compile_unit.addr_size_bytes;
        switch (self.section_type) {
            .debug_rnglists => {
                const kind = try self.fr.takeByte();
                switch (kind) {
                    RLE.end_of_list => return null,
                    RLE.base_addressx => {
                        const index = try self.fr.takeLeb128(u64);
                        self.base_address = try self.di.readDebugAddr(endian, self.compile_unit, index);
                        return try self.next();
                    },
                    RLE.startx_endx => {
                        const start_index = try self.fr.takeLeb128(u64);
                        const start_addr = try self.di.readDebugAddr(endian, self.compile_unit, start_index);

                        const end_index = try self.fr.takeLeb128(u64);
                        const end_addr = try self.di.readDebugAddr(endian, self.compile_unit, end_index);

                        return .{
                            .start = start_addr,
                            .end = end_addr,
                        };
                    },
                    RLE.startx_length => {
                        const start_index = try self.fr.takeLeb128(u64);
                        const start_addr = try self.di.readDebugAddr(endian, self.compile_unit, start_index);

                        const len = try self.fr.takeLeb128(u64);
                        const end_addr = start_addr + len;

                        return .{
                            .start = start_addr,
                            .end = end_addr,
                        };
                    },
                    RLE.offset_pair => {
                        const start_addr = try self.fr.takeLeb128(u64);
                        const end_addr = try self.fr.takeLeb128(u64);

                        // This is the only kind that uses the base address
                        return .{
                            .start = self.base_address + start_addr,
                            .end = self.base_address + end_addr,
                        };
                    },
                    RLE.base_address => {
                        self.base_address = try readAddress(&self.fr, endian, addr_size_bytes);
                        return try self.next();
                    },
                    RLE.start_end => {
                        const start_addr = try readAddress(&self.fr, endian, addr_size_bytes);
                        const end_addr = try readAddress(&self.fr, endian, addr_size_bytes);

                        return .{
                            .start = start_addr,
                            .end = end_addr,
                        };
                    },
                    RLE.start_length => {
                        const start_addr = try readAddress(&self.fr, endian, addr_size_bytes);
                        const len = try self.fr.takeLeb128(u64);
                        const end_addr = start_addr + len;

                        return .{
                            .start = start_addr,
                            .end = end_addr,
                        };
                    },
                    else => return bad(),
                }
            },
            .debug_ranges => {
                const start_addr = try readAddress(&self.fr, endian, addr_size_bytes);
                const end_addr = try readAddress(&self.fr, endian, addr_size_bytes);
                if (start_addr == 0 and end_addr == 0) return null;

                // The entry with start_addr = max_representable_address selects a new value for the base address
                const max_representable_address = ~@as(u64, 0) >> @intCast(64 - addr_size_bytes);
                if (start_addr == max_representable_address) {
                    self.base_address = end_addr;
                    return try self.next();
                }

                return .{
                    .start = self.base_address + start_addr,
                    .end = self.base_address + end_addr,
                };
            },
            else => unreachable,
        }
    }
}