DoxigAlpha

parse

This function expects to read the CIE starting with the version field. The returned struct references memory backed by cie_bytes.

See the FrameDescriptionEntry.parse documentation for the description of pc_rel_offset and is_runtime.

length_offset specifies the offset of this CIE's length field in the .eh_frame / .debug_frame section.

Function parameters

Parameters

#
cie_bytes:[]const u8
pc_rel_offset:i64
is_runtime:bool
dwarf_section:Section.Id
length_offset:u64
addr_size_bytes:u8
endian:std.builtin.Endian

Type definitions in this namespace

Types

#
ExceptionFrameHeader
This represents the decoded .eh_frame_hdr header

Initialize DWARF info.

Functions

#
open
Initialize DWARF info.
findCompileUnit
TODO: change this to binary searching the sorted compile unit list
scanAllUnwindInfo
If `.eh_frame_hdr` is present, then only the header needs to be parsed.
scanCieFdeInfo
Scan `.eh_frame` and `.debug_frame` and build a sorted list of FDEs for binary searching during
compactUnwindToDwarfRegNumber
Returns the DWARF register number for an x86_64 register number found in compact unwind info
bad
This function is to make it handy to comment out the return and make it

Error sets in this namespace

Error Sets

#

= [_]?Section{null} ** num_sections

Values

#
null_section_array
= [_]?Section{null} ** num_sections

Source

Implementation

#
pub fn parse(
    cie_bytes: []const u8,
    pc_rel_offset: i64,
    is_runtime: bool,
    format: Format,
    dwarf_section: Section.Id,
    length_offset: u64,
    addr_size_bytes: u8,
    endian: std.builtin.Endian,
) !CommonInformationEntry {
    if (addr_size_bytes > 8) return error.UnsupportedAddrSize;

    var fbr: FixedBufferReader = .{ .buf = cie_bytes, .endian = endian };

    const version = try fbr.readByte();
    switch (dwarf_section) {
        .eh_frame => if (version != 1 and version != 3) return error.UnsupportedDwarfVersion,
        .debug_frame => if (version != 4) return error.UnsupportedDwarfVersion,
        else => return error.UnsupportedDwarfSection,
    }

    var has_eh_data = false;
    var has_aug_data = false;

    var aug_str_len: usize = 0;
    const aug_str_start = fbr.pos;
    var aug_byte = try fbr.readByte();
    while (aug_byte != 0) : (aug_byte = try fbr.readByte()) {
        switch (aug_byte) {
            'z' => {
                if (aug_str_len != 0) return bad();
                has_aug_data = true;
            },
            'e' => {
                if (has_aug_data or aug_str_len != 0) return bad();
                if (try fbr.readByte() != 'h') return bad();
                has_eh_data = true;
            },
            else => if (has_eh_data) return bad(),
        }

        aug_str_len += 1;
    }

    if (has_eh_data) {
        // legacy data created by older versions of gcc - unsupported here
        for (0..addr_size_bytes) |_| _ = try fbr.readByte();
    }

    const address_size = if (version == 4) try fbr.readByte() else addr_size_bytes;
    const segment_selector_size = if (version == 4) try fbr.readByte() else null;

    const code_alignment_factor = try fbr.readUleb128(u32);
    const data_alignment_factor = try fbr.readIleb128(i32);
    const return_address_register = if (version == 1) try fbr.readByte() else try fbr.readUleb128(u8);

    var lsda_pointer_enc: u8 = EH.PE.omit;
    var personality_enc: ?u8 = null;
    var personality_routine_pointer: ?u64 = null;
    var fde_pointer_enc: u8 = EH.PE.absptr;

    var aug_data: []const u8 = &[_]u8{};
    const aug_str = if (has_aug_data) blk: {
        const aug_data_len = try fbr.readUleb128(usize);
        const aug_data_start = fbr.pos;
        aug_data = cie_bytes[aug_data_start..][0..aug_data_len];

        const aug_str = cie_bytes[aug_str_start..][0..aug_str_len];
        for (aug_str[1..]) |byte| {
            switch (byte) {
                'L' => {
                    lsda_pointer_enc = try fbr.readByte();
                },
                'P' => {
                    personality_enc = try fbr.readByte();
                    personality_routine_pointer = try readEhPointer(&fbr, personality_enc.?, addr_size_bytes, .{
                        .pc_rel_base = try pcRelBase(@intFromPtr(&cie_bytes[fbr.pos]), pc_rel_offset),
                        .follow_indirect = is_runtime,
                    });
                },
                'R' => {
                    fde_pointer_enc = try fbr.readByte();
                },
                'S', 'B', 'G' => {},
                else => return bad(),
            }
        }

        // aug_data_len can include padding so the CIE ends on an address boundary
        fbr.pos = aug_data_start + aug_data_len;
        break :blk aug_str;
    } else &[_]u8{};

    const initial_instructions = cie_bytes[fbr.pos..];
    return .{
        .length_offset = length_offset,
        .version = version,
        .address_size = address_size,
        .format = format,
        .segment_selector_size = segment_selector_size,
        .code_alignment_factor = code_alignment_factor,
        .data_alignment_factor = data_alignment_factor,
        .return_address_register = return_address_register,
        .aug_str = aug_str,
        .aug_data = aug_data,
        .lsda_pointer_enc = lsda_pointer_enc,
        .personality_enc = personality_enc,
        .personality_routine_pointer = personality_routine_pointer,
        .fde_pointer_enc = fde_pointer_enc,
        .initial_instructions = initial_instructions,
    };
}