feature. See also
. The project being documented here (as the example) is the Zig library itself.
Dwarf.DebugRangeIterator
const DebugRangeIterator = struct
File
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(),
};
// 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,
};
}
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);
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;
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,
}
}
}