struct CommonInformationEntry [src]
Fields
length_offset: u64
version: u8
address_size: u8
format: Format
segment_selector_size: ?u8
code_alignment_factor: u32
data_alignment_factor: i32
return_address_register: u8
aug_str: []const u8
aug_data: []const u8
lsda_pointer_enc: u8
personality_enc: ?u8
personality_routine_pointer: ?u64
fde_pointer_enc: u8
initial_instructions: []const u8
Members
- addressesSignedWithBKey (Function)
- dwarf32_id (Constant)
- dwarf64_id (Constant)
- eh_id (Constant)
- isSignalFrame (Function)
- mteTaggedFrame (Function)
- parse (Function)
Source
pub const CommonInformationEntry = struct {
// Used in .eh_frame
pub const eh_id = 0;
// Used in .debug_frame (DWARF32)
pub const dwarf32_id = maxInt(u32);
// Used in .debug_frame (DWARF64)
pub const dwarf64_id = maxInt(u64);
// Offset of the length field of this entry in the eh_frame section.
// This is the key that FDEs use to reference CIEs.
length_offset: u64,
version: u8,
address_size: u8,
format: Format,
// Only present in version 4
segment_selector_size: ?u8,
code_alignment_factor: u32,
data_alignment_factor: i32,
return_address_register: u8,
aug_str: []const u8,
aug_data: []const u8,
lsda_pointer_enc: u8,
personality_enc: ?u8,
personality_routine_pointer: ?u64,
fde_pointer_enc: u8,
initial_instructions: []const u8,
pub fn isSignalFrame(self: CommonInformationEntry) bool {
for (self.aug_str) |c| if (c == 'S') return true;
return false;
}
pub fn addressesSignedWithBKey(self: CommonInformationEntry) bool {
for (self.aug_str) |c| if (c == 'B') return true;
return false;
}
pub fn mteTaggedFrame(self: CommonInformationEntry) bool {
for (self.aug_str) |c| if (c == 'G') return true;
return false;
}
/// 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.
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,
};
}
}