Function parse [src]
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.
Prototype
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
Parameters
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
Source
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,
};
}