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.

scanAllFunctions

Dwarf.scanAllFunctions
fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void

File

lib/std/debug/Dwarf.zig:378

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;
                        // Prevent endless loops
                        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;

                                // Follow the DIE it points to and repeat
                                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, // wrong abbrev table for different cu
                                    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;

                                // Follow the DIE it points to and repeat
                                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, // wrong abbrev table for different cu
                                    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;
    }
}