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();
}
}