DoxigAlpha

findEntry

Find an entry by binary searching the eh_frame_hdr section.

Since the length of the eh_frame section (eh_frame_len) may not be known by the caller, MemoryAccessor will be used to verify readability of the header entries. If eh_frame_len is provided, then these checks can be skipped.

Function parameters

Parameters

#
ma:*MemoryAccessor
eh_frame_len:?usize
eh_frame_hdr_ptr:usize
pc:usize
cie:*CommonInformationEntry
fde:*FrameDescriptionEntry

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 findEntry(
    self: ExceptionFrameHeader,
    ma: *MemoryAccessor,
    eh_frame_len: ?usize,
    eh_frame_hdr_ptr: usize,
    pc: usize,
    cie: *CommonInformationEntry,
    fde: *FrameDescriptionEntry,
) !void {
    const entry_size = try entrySize(self.table_enc);

    var left: usize = 0;
    var len: usize = self.fde_count;

    var fbr: FixedBufferReader = .{ .buf = self.entries, .endian = native_endian };

    while (len > 1) {
        const mid = left + len / 2;

        fbr.pos = mid * entry_size;
        const pc_begin = try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{
            .pc_rel_base = @intFromPtr(&self.entries[fbr.pos]),
            .follow_indirect = true,
            .data_rel_base = eh_frame_hdr_ptr,
        }) orelse return bad();

        if (pc < pc_begin) {
            len /= 2;
        } else {
            left = mid;
            if (pc == pc_begin) break;
            len -= len / 2;
        }
    }

    if (len == 0) return missing();
    fbr.pos = left * entry_size;

    // Read past the pc_begin field of the entry
    _ = try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{
        .pc_rel_base = @intFromPtr(&self.entries[fbr.pos]),
        .follow_indirect = true,
        .data_rel_base = eh_frame_hdr_ptr,
    }) orelse return bad();

    const fde_ptr = cast(usize, try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{
        .pc_rel_base = @intFromPtr(&self.entries[fbr.pos]),
        .follow_indirect = true,
        .data_rel_base = eh_frame_hdr_ptr,
    }) orelse return bad()) orelse return bad();

    if (fde_ptr < self.eh_frame_ptr) return bad();

    // Even if eh_frame_len is not specified, all ranges accssed are checked via MemoryAccessor
    const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0 .. eh_frame_len orelse maxInt(u32)];

    const fde_offset = fde_ptr - self.eh_frame_ptr;
    var eh_frame_fbr: FixedBufferReader = .{
        .buf = eh_frame,
        .pos = fde_offset,
        .endian = native_endian,
    };

    const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame);
    if (fde_entry_header.entry_bytes.len > 0 and !self.isValidPtr(u8, @intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad();
    if (fde_entry_header.type != .fde) return bad();

    // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable
    const cie_offset = fde_entry_header.type.fde;
    try eh_frame_fbr.seekTo(cie_offset);
    const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame);
    if (cie_entry_header.entry_bytes.len > 0 and !self.isValidPtr(u8, @intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad();
    if (cie_entry_header.type != .cie) return bad();

    cie.* = try CommonInformationEntry.parse(
        cie_entry_header.entry_bytes,
        0,
        true,
        cie_entry_header.format,
        .eh_frame,
        cie_entry_header.length_offset,
        @sizeOf(usize),
        native_endian,
    );

    fde.* = try FrameDescriptionEntry.parse(
        fde_entry_header.entry_bytes,
        0,
        true,
        cie.*,
        @sizeOf(usize),
        native_endian,
    );

    if (pc < fde.pc_begin or pc >= fde.pc_begin + fde.pc_range) return missing();
}