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.

EhFrameHeader

Decoded version of the .eh_frame_hdr section.

Unwind.EhFrameHeader
pub const EhFrameHeader = struct

File

lib/std/debug/Dwarf/Unwind.zig:126

Code

pub const EhFrameHeader = struct {
    /// The virtual address (i.e. as given in the binary, before relocations) of the `.eh_frame`
    /// section. This value is important when using `.eh_frame_hdr` to find debug information for
    /// the current binary, because it allows locating where the `.eh_frame` section is loaded in
    /// memory (by adding it to the ELF module's base address).
    eh_frame_vaddr: u64,
    search_table: ?SearchTable,

    pub const SearchTable = struct {
        /// The byte offset of the search table into the `.eh_frame_hdr` section.
        offset: u8,
        encoding: EH.PE,
        fde_count: usize,
        /// The actual table entries are viewed as a plain byte slice because `encoding` causes the
        /// size of entries in the table to vary.
        entries: []const u8,

        /// Returns the vaddr of the FDE for `pc`, or `null` if no matching FDE was found.
        fn findEntry(
            table: *const SearchTable,
            eh_frame_hdr_vaddr: u64,
            pc: u64,
            addr_size_bytes: u8,
            endian: Endian,
        ) !?u64 {
            const table_vaddr = eh_frame_hdr_vaddr + table.offset;
            const entry_size = try entrySize(table.encoding, addr_size_bytes);
            var left: usize = 0;
            var len: usize = table.fde_count;
            while (len > 1) {
                const mid = left + len / 2;
                var entry_reader: Reader = .fixed(table.entries[mid * entry_size ..][0..entry_size]);
                const pc_begin = try readEhPointer(&entry_reader, table.encoding, addr_size_bytes, .{
                    .pc_rel_base = table_vaddr + left * entry_size,
                    .data_rel_base = eh_frame_hdr_vaddr,
                }, endian);
                if (pc < pc_begin) {
                    len /= 2;
                } else {
                    left = mid;
                    len -= len / 2;
                }
            }
            if (len == 0) return null;
            var entry_reader: Reader = .fixed(table.entries[left * entry_size ..][0..entry_size]);
            // Skip past `pc_begin`; we're now interested in the fde offset
            _ = try readEhPointerAbs(&entry_reader, table.encoding.type, addr_size_bytes, endian);
            const fde_ptr = try readEhPointer(&entry_reader, table.encoding, addr_size_bytes, .{
                .pc_rel_base = table_vaddr + left * entry_size,
                .data_rel_base = eh_frame_hdr_vaddr,
            }, endian);
            return fde_ptr;
        }

        fn entrySize(table_enc: EH.PE, addr_size_bytes: u8) !u8 {
            return switch (table_enc.type) {
                .absptr => 2 * addr_size_bytes,
                .udata2, .sdata2 => 4,
                .udata4, .sdata4 => 8,
                .udata8, .sdata8 => 16,
                .uleb128, .sleb128 => return bad(), // this is a binary search table; all entries must be the same size
                _ => return bad(),
            };
        }
    };

    pub fn parse(
        eh_frame_hdr_vaddr: u64,
        eh_frame_hdr_bytes: []const u8,
        addr_size_bytes: u8,
        endian: Endian,
    ) !EhFrameHeader {
        var r: Reader = .fixed(eh_frame_hdr_bytes);

        const version = try r.takeByte();
        if (version != 1) return bad();

        const eh_frame_ptr_enc: EH.PE = @bitCast(try r.takeByte());
        const fde_count_enc: EH.PE = @bitCast(try r.takeByte());
        const table_enc: EH.PE = @bitCast(try r.takeByte());

        const eh_frame_ptr = try readEhPointer(&r, eh_frame_ptr_enc, addr_size_bytes, .{
            .pc_rel_base = eh_frame_hdr_vaddr + r.seek,
        }, endian);

        const table: ?SearchTable = table: {
            if (fde_count_enc == EH.PE.omit) break :table null;
            if (table_enc == EH.PE.omit) break :table null;
            const fde_count = try readEhPointer(&r, fde_count_enc, addr_size_bytes, .{
                .pc_rel_base = eh_frame_hdr_vaddr + r.seek,
            }, endian);
            const entry_size = try SearchTable.entrySize(table_enc, addr_size_bytes);
            const bytes_offset = r.seek;
            const bytes_len = cast(usize, fde_count * entry_size) orelse return error.EndOfStream;
            const bytes = try r.take(bytes_len);
            break :table .{
                .encoding = table_enc,
                .fde_count = @intCast(fde_count),
                .entries = bytes,
                .offset = @intCast(bytes_offset),
            };
        };

        return .{
            .eh_frame_vaddr = eh_frame_ptr,
            .search_table = table,
        };
    }
}