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.

CommonInformationEntry

Unwind.CommonInformationEntry
pub const CommonInformationEntry = struct

File

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

Code

pub const CommonInformationEntry = struct {
    version: u8,
    format: Format,

    /// In version 4, CIEs can specify the address size used in the CIE and associated FDEs.
    /// This value must be used *only* to parse associated FDEs in `FrameDescriptionEntry.parse`.
    addr_size_bytes: u8,

    /// Always 0 for versions which do not specify this (currently all versions other than 4).
    segment_selector_size: u8,

    code_alignment_factor: u32,
    data_alignment_factor: i32,
    return_address_register: u8,

    fde_pointer_enc: EH.PE,
    is_signal_frame: bool,

    augmentation_kind: AugmentationKind,

    initial_instructions: []const u8,

    last_row: ?struct {
        offset: u64,
        cfa: VirtualMachine.CfaRule,
        cols: []VirtualMachine.Column,
    },

    pub const AugmentationKind = enum { none, gcc_eh, lsb_z };

    /// This function expects to read the CIE starting with the version field.
    /// The returned struct references memory backed by `cie_bytes`.
    ///
    /// `length_offset` specifies the offset of this CIE's length field in the
    /// .eh_frame / .debug_frame section.
    fn parse(
        format: Format,
        cie_bytes: []const u8,
        section: Section,
        default_addr_size_bytes: u8,
    ) !CommonInformationEntry {
        // We only read the data through this reader.
        var r: Reader = .fixed(cie_bytes);

        const version = try r.takeByte();
        switch (section) {
            .eh_frame => if (version != 1 and version != 3) return error.UnsupportedDwarfVersion,
            .debug_frame => if (version != 4) return error.UnsupportedDwarfVersion,
        }

        const aug_str = try r.takeSentinel(0);
        const aug_kind: AugmentationKind = aug: {
            if (aug_str.len == 0) break :aug .none;
            if (aug_str[0] == 'z') break :aug .lsb_z;
            if (std.mem.eql(u8, aug_str, "eh")) break :aug .gcc_eh;
            // We can't finish parsing the CIE if we don't know what its augmentation means.
            return bad();
        };

        switch (aug_kind) {
            .none => {}, // no extra data
            .lsb_z => {}, // no extra data yet, but there is a bit later
            .gcc_eh => try r.discardAll(default_addr_size_bytes), // unsupported data
        }

        const addr_size_bytes = if (version == 4) try r.takeByte() else default_addr_size_bytes;
        const segment_selector_size: u8 = if (version == 4) try r.takeByte() else 0;
        const code_alignment_factor = try r.takeLeb128(u32);
        const data_alignment_factor = try r.takeLeb128(i32);
        const return_address_register = if (version == 1) try r.takeByte() else try r.takeLeb128(u8);

        // This is where LSB's augmentation might add some data.
        const fde_pointer_enc: EH.PE, const is_signal_frame: bool = aug: {
            const default_fde_pointer_enc: EH.PE = .{ .type = .absptr, .rel = .abs };
            if (aug_kind != .lsb_z) break :aug .{ default_fde_pointer_enc, false };
            const aug_data_len = try r.takeLeb128(u32);
            var aug_data: Reader = .fixed(try r.take(aug_data_len));
            var fde_pointer_enc: EH.PE = default_fde_pointer_enc;
            var is_signal_frame = false;
            for (aug_str[1..]) |byte| switch (byte) {
                'L' => _ = try aug_data.takeByte(), // we ignore the LSDA pointer
                'P' => {
                    const enc: EH.PE = @bitCast(try aug_data.takeByte());
                    const endian: Endian = .little; // irrelevant because we're discarding the value anyway
                    _ = try readEhPointerAbs(&aug_data, enc.type, addr_size_bytes, endian); // we ignore the personality routine; endianness is irrelevant since we're discarding
                },
                'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()),
                'S' => is_signal_frame = true,
                'B', 'G' => {},
                else => return bad(),
            };
            break :aug .{ fde_pointer_enc, is_signal_frame };
        };

        return .{
            .format = format,
            .version = version,
            .addr_size_bytes = addr_size_bytes,
            .segment_selector_size = segment_selector_size,
            .code_alignment_factor = code_alignment_factor,
            .data_alignment_factor = data_alignment_factor,
            .return_address_register = return_address_register,
            .fde_pointer_enc = fde_pointer_enc,
            .is_signal_frame = is_signal_frame,
            .augmentation_kind = aug_kind,
            .initial_instructions = r.buffered(),
            .last_row = null,
        };
    }
}