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.

EntryHeader

The shared header of an FDE/CIE, containing a length in bytes (DWARF's "initial length field") and a value which differentiates CIEs from FDEs and maps FDEs to their corresponding CIEs. The .eh_frame format also includes a third variation, here called .terminator, which acts as a sentinel for the whole section.

CommonInformationEntry.parse and FrameDescriptionEntry.parse expect the EntryHeader to have been parsed first: they accept data stored in the EntryHeader, and only read the bytes following this header.

Unwind.EntryHeader
const EntryHeader = union(enum)

File

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

Code

const EntryHeader = union(enum) {
    cie: struct {
        format: Format,
        /// Remaining bytes in the CIE. These are parseable by `CommonInformationEntry.parse`.
        bytes_len: u64,
    },
    fde: struct {
        /// Offset into the section of the corresponding CIE, *including* its entry header.
        cie_offset: u64,
        /// Remaining bytes in the FDE. These are parseable by `FrameDescriptionEntry.parse`.
        bytes_len: u64,
    },
    /// The `.eh_frame` format includes terminators which indicate that the last CIE/FDE has been
    /// reached. However, `.debug_frame` does not include such a terminator, so the caller must
    /// keep track of how many section bytes remain when parsing all entries in `.debug_frame`.
    terminator,

    fn read(r: *Reader, header_section_offset: u64, section: Section, endian: Endian) !EntryHeader {
        const unit_header = try Dwarf.readUnitHeader(r, endian);
        if (unit_header.unit_length == 0) return .terminator;

        // Next is a value which will disambiguate CIEs and FDEs. Annoyingly, LSB Core makes this
        // value always 4-byte, whereas DWARF makes it depend on the `dwarf.Format`.
        const cie_ptr_or_id_size: u8 = switch (section) {
            .eh_frame => 4,
            .debug_frame => switch (unit_header.format) {
                .@"32" => 4,
                .@"64" => 8,
            },
        };
        const cie_ptr_or_id = switch (cie_ptr_or_id_size) {
            4 => try r.takeInt(u32, endian),
            8 => try r.takeInt(u64, endian),
            else => unreachable,
        };
        const remaining_bytes = unit_header.unit_length - cie_ptr_or_id_size;

        // If this entry is a CIE, then `cie_ptr_or_id` will have this value, which is different
        // between the DWARF `.debug_frame` section and the LSB Core `.eh_frame` section.
        const cie_id: u64 = switch (section) {
            .eh_frame => 0,
            .debug_frame => switch (unit_header.format) {
                .@"32" => maxInt(u32),
                .@"64" => maxInt(u64),
            },
        };
        if (cie_ptr_or_id == cie_id) {
            return .{ .cie = .{
                .format = unit_header.format,
                .bytes_len = remaining_bytes,
            } };
        }

        // This is an FDE -- `cie_ptr_or_id` points to the associated CIE. Unfortunately, the format
        // of that pointer again differs between `.debug_frame` and `.eh_frame`.
        const cie_offset = switch (section) {
            .eh_frame => try std.math.sub(u64, header_section_offset + unit_header.header_length, cie_ptr_or_id),
            .debug_frame => cie_ptr_or_id,
        };
        return .{ .fde = .{
            .cie_offset = cie_offset,
            .bytes_len = remaining_bytes,
        } };
    }
}