struct ExceptionFrameHeader [src]

This represents the decoded .eh_frame_hdr header

Fields

eh_frame_ptr: usize
table_enc: u8
fde_count: usize
entries: []const u8

Members

Source

pub const ExceptionFrameHeader = struct { eh_frame_ptr: usize, table_enc: u8, fde_count: usize, entries: []const u8, pub fn entrySize(table_enc: u8) !u8 { return switch (table_enc & EH.PE.type_mask) { EH.PE.udata2, EH.PE.sdata2, => 4, EH.PE.udata4, EH.PE.sdata4, => 8, EH.PE.udata8, EH.PE.sdata8, => 16, // This is a binary search table, so all entries must be the same length else => return bad(), }; } pub fn findEntry( self: ExceptionFrameHeader, eh_frame_len: usize, eh_frame_hdr_ptr: usize, pc: usize, cie: *CommonInformationEntry, fde: *FrameDescriptionEntry, endian: Endian, ) !void { const entry_size = try entrySize(self.table_enc); var left: usize = 0; var len: usize = self.fde_count; var fbr: Reader = .fixed(self.entries); while (len > 1) { const mid = left + len / 2; fbr.seek = mid * entry_size; const pc_begin = try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{ .pc_rel_base = @intFromPtr(&self.entries[fbr.seek]), .follow_indirect = true, .data_rel_base = eh_frame_hdr_ptr, }, endian) 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.seek = 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.seek]), .follow_indirect = true, .data_rel_base = eh_frame_hdr_ptr, }, endian) orelse return bad(); const fde_ptr = cast(usize, try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{ .pc_rel_base = @intFromPtr(&self.entries[fbr.seek]), .follow_indirect = true, .data_rel_base = eh_frame_hdr_ptr, }, endian) orelse return bad()) orelse return bad(); if (fde_ptr < self.eh_frame_ptr) return bad(); const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0..eh_frame_len]; const fde_offset = fde_ptr - self.eh_frame_ptr; var eh_frame_fbr: Reader = .fixed(eh_frame); eh_frame_fbr.seek = fde_offset; const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame, endian); 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; eh_frame_fbr.seek = @intCast(cie_offset); const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame, endian); 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), endian, ); fde.* = try FrameDescriptionEntry.parse( fde_entry_header.entry_bytes, 0, true, cie.*, @sizeOf(usize), endian, ); if (pc < fde.pc_begin or pc >= fde.pc_begin + fde.pc_range) return missing(); } }