feature. See also
. The project being documented here (as the example) is the Zig library itself.
Dwarf.scanAllFunctions
fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void
File
Code
fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void {
var fr: Reader = .fixed(di.section(.debug_info).?);
var this_unit_offset: u64 = 0;
while (this_unit_offset < fr.buffer.len) {
fr.seek = @intCast(this_unit_offset);
const unit_header = try readUnitHeader(&fr, endian);
if (unit_header.unit_length == 0) return;
const next_offset = unit_header.header_length + unit_header.unit_length;
const version = try fr.takeInt(u16, endian);
if (version < 2 or version > 5) return bad();
var address_size: u8 = undefined;
var debug_abbrev_offset: u64 = undefined;
if (version >= 5) {
const unit_type = try fr.takeByte();
if (unit_type != DW.UT.compile) return bad();
address_size = try fr.takeByte();
debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
} else {
debug_abbrev_offset = try readFormatSizedInt(&fr, unit_header.format, endian);
address_size = try fr.takeByte();
}
const abbrev_table = try di.getAbbrevTable(gpa, debug_abbrev_offset);
var max_attrs: usize = 0;
var zig_padding_abbrev_code: u7 = 0;
for (abbrev_table.abbrevs) |abbrev| {
max_attrs = @max(max_attrs, abbrev.attrs.len);
if (cast(u7, abbrev.code)) |code| {
if (abbrev.tag_id == DW.TAG.ZIG_padding and
!abbrev.has_children and
abbrev.attrs.len == 0)
{
zig_padding_abbrev_code = code;
}
}
}
const attrs_buf = try gpa.alloc(Die.Attr, max_attrs * 3);
defer gpa.free(attrs_buf);
var attrs_bufs: [3][]Die.Attr = undefined;
for (&attrs_bufs, 0..) |*buf, index| buf.* = attrs_buf[index * max_attrs ..][0..max_attrs];
const next_unit_pos = this_unit_offset + next_offset;
var compile_unit: CompileUnit = .{
.version = version,
.format = unit_header.format,
.addr_size_bytes = address_size,
.die = undefined,
.pc_range = null,
.str_offsets_base = 0,
.addr_base = 0,
.rnglists_base = 0,
.loclists_base = 0,
.frame_base = null,
.src_loc_cache = null,
};
while (true) {
fr.seek = std.mem.findNonePos(u8, fr.buffer, fr.seek, &.{
zig_padding_abbrev_code, 0,
}) orelse fr.buffer.len;
if (fr.seek >= next_unit_pos) break;
var die_obj = (try parseDie(
&fr,
attrs_bufs[0],
abbrev_table,
unit_header.format,
endian,
address_size,
)) orelse continue;
switch (die_obj.tag_id) {
DW.TAG.compile_unit => {
compile_unit.die = die_obj;
compile_unit.die.attrs = attrs_bufs[1][0..die_obj.attrs.len];
@memcpy(compile_unit.die.attrs, die_obj.attrs);
compile_unit.str_offsets_base = if (die_obj.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0;
compile_unit.addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0;
compile_unit.rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0;
compile_unit.loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0;
compile_unit.frame_base = die_obj.getAttr(AT.frame_base);
},
DW.TAG.subprogram, DW.TAG.inlined_subroutine, DW.TAG.subroutine, DW.TAG.entry_point => {
const fn_name = x: {
var this_die_obj = die_obj;
for (0..3) |_| {
if (this_die_obj.getAttr(AT.name)) |_| {
break :x try this_die_obj.getAttrString(di, endian, AT.name, di.section(.debug_str), &compile_unit);
} else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
const after_die_offset = fr.seek;
defer fr.seek = after_die_offset;
const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin, this_unit_offset, next_offset);
fr.seek = @intCast(ref_offset);
this_die_obj = (try parseDie(
&fr,
attrs_bufs[2],
abbrev_table,
unit_header.format,
endian,
address_size,
)) orelse return bad();
} else if (this_die_obj.getAttr(AT.specification)) |_| {
const after_die_offset = fr.seek;
defer fr.seek = after_die_offset;
const ref_offset = try this_die_obj.getAttrRef(AT.specification, this_unit_offset, next_offset);
fr.seek = @intCast(ref_offset);
this_die_obj = (try parseDie(
&fr,
attrs_bufs[2],
abbrev_table,
unit_header.format,
endian,
address_size,
)) orelse return bad();
} else {
break :x null;
}
}
break :x null;
};
var range_added = if (die_obj.getAttrAddr(di, endian, AT.low_pc, &compile_unit)) |low_pc| blk: {
if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {
const pc_end = switch (high_pc_value.*) {
.addr => |value| value,
.udata => |offset| low_pc + offset,
else => return bad(),
};
try di.func_list.append(gpa, .{
.name = fn_name,
.pc_range = .{
.start = low_pc,
.end = pc_end,
},
});
break :blk true;
}
break :blk false;
} else |err| blk: {
if (err != error.MissingDebugInfo) return err;
break :blk false;
};
if (die_obj.getAttr(AT.ranges)) |ranges_value| blk: {
var iter = DebugRangeIterator.init(ranges_value, di, endian, &compile_unit) catch |err| {
if (err != error.MissingDebugInfo) return err;
break :blk;
};
while (try iter.next()) |range| {
range_added = true;
try di.func_list.append(gpa, .{
.name = fn_name,
.pc_range = .{
.start = range.start,
.end = range.end,
},
});
}
}
if (fn_name != null and !range_added) {
try di.func_list.append(gpa, .{
.name = fn_name,
.pc_range = null,
});
}
},
else => {},
}
}
this_unit_offset += next_offset;
}
}