mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
dwarf: add support for .debug_frame and CIE version 4
This commit is contained in:
parent
41832aa1e6
commit
a9b6f2d929
@ -7,6 +7,7 @@ const os = std.os;
|
|||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const leb = @import("leb128.zig");
|
const leb = @import("leb128.zig");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
pub const TAG = @import("dwarf/TAG.zig");
|
pub const TAG = @import("dwarf/TAG.zig");
|
||||||
pub const AT = @import("dwarf/AT.zig");
|
pub const AT = @import("dwarf/AT.zig");
|
||||||
@ -1530,45 +1531,49 @@ pub const DwarfInfo = struct {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (di.section(.eh_frame)) |eh_frame| {
|
const frame_sections = [2]DwarfSection{ .eh_frame, .debug_frame };
|
||||||
var stream = io.fixedBufferStream(eh_frame);
|
for (frame_sections) |frame_section| {
|
||||||
while (stream.pos < stream.buffer.len) {
|
if (di.section(frame_section)) |eh_frame| {
|
||||||
const entry_header = try EntryHeader.read(&stream, di.endian);
|
var stream = io.fixedBufferStream(eh_frame);
|
||||||
switch (entry_header.type) {
|
while (stream.pos < stream.buffer.len) {
|
||||||
.cie => {
|
const entry_header = try EntryHeader.read(&stream, frame_section, di.endian);
|
||||||
const cie = try CommonInformationEntry.parse(
|
switch (entry_header.type) {
|
||||||
entry_header.entry_bytes,
|
.cie => {
|
||||||
-@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),
|
const cie = try CommonInformationEntry.parse(
|
||||||
true,
|
entry_header.entry_bytes,
|
||||||
entry_header.length_offset,
|
-@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),
|
||||||
@sizeOf(usize),
|
true,
|
||||||
di.endian,
|
frame_section,
|
||||||
);
|
entry_header.length_offset,
|
||||||
try di.cie_map.put(allocator, entry_header.length_offset, cie);
|
@sizeOf(usize),
|
||||||
},
|
di.endian,
|
||||||
.fde => |cie_offset| {
|
);
|
||||||
const cie = di.cie_map.get(cie_offset) orelse return badDwarf();
|
try di.cie_map.put(allocator, entry_header.length_offset, cie);
|
||||||
const fde = try FrameDescriptionEntry.parse(
|
},
|
||||||
entry_header.entry_bytes,
|
.fde => |cie_offset| {
|
||||||
-@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),
|
const cie = di.cie_map.get(cie_offset) orelse return badDwarf();
|
||||||
true,
|
const fde = try FrameDescriptionEntry.parse(
|
||||||
cie,
|
entry_header.entry_bytes,
|
||||||
@sizeOf(usize),
|
-@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),
|
||||||
di.endian,
|
true,
|
||||||
);
|
cie,
|
||||||
try di.fde_list.append(allocator, fde);
|
@sizeOf(usize),
|
||||||
},
|
di.endian,
|
||||||
.terminator => break,
|
);
|
||||||
|
try di.fde_list.append(allocator, fde);
|
||||||
|
},
|
||||||
|
.terminator => break,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Avoiding sorting if has_eh_frame_hdr exists
|
// TODO: Avoiding sorting if has_eh_frame_hdr exists
|
||||||
std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct {
|
std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct {
|
||||||
fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool {
|
fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool {
|
||||||
_ = ctx;
|
_ = ctx;
|
||||||
return a.pc_begin < b.pc_begin;
|
return a.pc_begin < b.pc_begin;
|
||||||
}
|
}
|
||||||
}.lessThan);
|
}.lessThan);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1905,14 +1910,14 @@ pub const ExceptionFrameHeader = struct {
|
|||||||
var eh_frame_stream = io.fixedBufferStream(eh_frame);
|
var eh_frame_stream = io.fixedBufferStream(eh_frame);
|
||||||
try eh_frame_stream.seekTo(fde_offset);
|
try eh_frame_stream.seekTo(fde_offset);
|
||||||
|
|
||||||
const fde_entry_header = try EntryHeader.read(&eh_frame_stream, builtin.cpu.arch.endian());
|
const fde_entry_header = try EntryHeader.read(&eh_frame_stream, .eh_frame, builtin.cpu.arch.endian());
|
||||||
if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();
|
if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();
|
||||||
if (fde_entry_header.type != .fde) return badDwarf();
|
if (fde_entry_header.type != .fde) return badDwarf();
|
||||||
|
|
||||||
// CIEs always come before FDEs (the offset is a subtration), so we can assume this memory is readable
|
// CIEs always come before FDEs (the offset is a subtration), so we can assume this memory is readable
|
||||||
const cie_offset = fde_entry_header.type.fde;
|
const cie_offset = fde_entry_header.type.fde;
|
||||||
try eh_frame_stream.seekTo(cie_offset);
|
try eh_frame_stream.seekTo(cie_offset);
|
||||||
const cie_entry_header = try EntryHeader.read(&eh_frame_stream, builtin.cpu.arch.endian());
|
const cie_entry_header = try EntryHeader.read(&eh_frame_stream, .eh_frame, builtin.cpu.arch.endian());
|
||||||
if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();
|
if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();
|
||||||
if (cie_entry_header.type != .cie) return badDwarf();
|
if (cie_entry_header.type != .cie) return badDwarf();
|
||||||
|
|
||||||
@ -1920,6 +1925,7 @@ pub const ExceptionFrameHeader = struct {
|
|||||||
cie_entry_header.entry_bytes,
|
cie_entry_header.entry_bytes,
|
||||||
0,
|
0,
|
||||||
true,
|
true,
|
||||||
|
.eh_frame,
|
||||||
cie_entry_header.length_offset,
|
cie_entry_header.length_offset,
|
||||||
@sizeOf(usize),
|
@sizeOf(usize),
|
||||||
builtin.cpu.arch.endian(),
|
builtin.cpu.arch.endian(),
|
||||||
@ -1937,7 +1943,7 @@ pub const ExceptionFrameHeader = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const EntryHeader = struct {
|
pub const EntryHeader = struct {
|
||||||
/// Offset of the length in the backing buffer
|
/// Offset of the length field in the backing buffer
|
||||||
length_offset: usize,
|
length_offset: usize,
|
||||||
is_64: bool,
|
is_64: bool,
|
||||||
type: union(enum) {
|
type: union(enum) {
|
||||||
@ -1950,8 +1956,10 @@ pub const EntryHeader = struct {
|
|||||||
entry_bytes: []const u8,
|
entry_bytes: []const u8,
|
||||||
|
|
||||||
/// Reads a header for either an FDE or a CIE, then advances the stream to the position after the trailing structure.
|
/// Reads a header for either an FDE or a CIE, then advances the stream to the position after the trailing structure.
|
||||||
/// `stream` must be a stream backed by the .eh_frame section.
|
/// `stream` must be a stream backed by either the .eh_frame or .debug_frame sections.
|
||||||
pub fn read(stream: *std.io.FixedBufferStream([]const u8), endian: std.builtin.Endian) !EntryHeader {
|
pub fn read(stream: *std.io.FixedBufferStream([]const u8), dwarf_section: DwarfSection, endian: std.builtin.Endian) !EntryHeader {
|
||||||
|
assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame);
|
||||||
|
|
||||||
const reader = stream.reader();
|
const reader = stream.reader();
|
||||||
const length_offset = stream.pos;
|
const length_offset = stream.pos;
|
||||||
|
|
||||||
@ -1967,14 +1975,21 @@ pub const EntryHeader = struct {
|
|||||||
const id_len = @as(u8, if (is_64) 8 else 4);
|
const id_len = @as(u8, if (is_64) 8 else 4);
|
||||||
const id = if (is_64) try reader.readInt(u64, endian) else try reader.readInt(u32, endian);
|
const id = if (is_64) try reader.readInt(u64, endian) else try reader.readInt(u32, endian);
|
||||||
const entry_bytes = stream.buffer[stream.pos..][0 .. length - id_len];
|
const entry_bytes = stream.buffer[stream.pos..][0 .. length - id_len];
|
||||||
|
const cie_id: u64 = switch (dwarf_section) {
|
||||||
|
.eh_frame => CommonInformationEntry.eh_id,
|
||||||
|
.debug_frame => if (is_64) CommonInformationEntry.dwarf64_id else CommonInformationEntry.dwarf32_id,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
const result = EntryHeader{
|
const result = EntryHeader{
|
||||||
.length_offset = length_offset,
|
.length_offset = length_offset,
|
||||||
.is_64 = is_64,
|
.is_64 = is_64,
|
||||||
.type = switch (id) {
|
.type = if (id == cie_id) .{ .cie = {} } else .{
|
||||||
0 => .{ .cie = {} },
|
.fde = switch (dwarf_section) {
|
||||||
// TODO: Support CommonInformationEntry.dwarf32_id, CommonInformationEntry.dwarf64_id
|
.eh_frame => stream.pos - id_len - id,
|
||||||
else => .{ .fde = stream.pos - id_len - id },
|
.debug_frame => id,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.entry_bytes = entry_bytes,
|
.entry_bytes = entry_bytes,
|
||||||
};
|
};
|
||||||
@ -2004,6 +2019,11 @@ pub const CommonInformationEntry = struct {
|
|||||||
length_offset: u64,
|
length_offset: u64,
|
||||||
version: u8,
|
version: u8,
|
||||||
|
|
||||||
|
address_size: u8,
|
||||||
|
|
||||||
|
// Only present in version 4
|
||||||
|
segment_selector_size: ?u8,
|
||||||
|
|
||||||
code_alignment_factor: u32,
|
code_alignment_factor: u32,
|
||||||
data_alignment_factor: i32,
|
data_alignment_factor: i32,
|
||||||
return_address_register: u8,
|
return_address_register: u8,
|
||||||
@ -2038,11 +2058,12 @@ pub const CommonInformationEntry = struct {
|
|||||||
/// of `pc_rel_offset` and `is_runtime`.
|
/// of `pc_rel_offset` and `is_runtime`.
|
||||||
///
|
///
|
||||||
/// `length_offset` specifies the offset of this CIE's length field in the
|
/// `length_offset` specifies the offset of this CIE's length field in the
|
||||||
/// .eh_frame section.
|
/// .eh_frame / .debug_framesection.
|
||||||
pub fn parse(
|
pub fn parse(
|
||||||
cie_bytes: []const u8,
|
cie_bytes: []const u8,
|
||||||
pc_rel_offset: i64,
|
pc_rel_offset: i64,
|
||||||
is_runtime: bool,
|
is_runtime: bool,
|
||||||
|
dwarf_section: DwarfSection,
|
||||||
length_offset: u64,
|
length_offset: u64,
|
||||||
addr_size_bytes: u8,
|
addr_size_bytes: u8,
|
||||||
endian: std.builtin.Endian,
|
endian: std.builtin.Endian,
|
||||||
@ -2053,7 +2074,11 @@ pub const CommonInformationEntry = struct {
|
|||||||
const reader = stream.reader();
|
const reader = stream.reader();
|
||||||
|
|
||||||
const version = try reader.readByte();
|
const version = try reader.readByte();
|
||||||
if (version != 1 and version != 3) return error.UnsupportedDwarfVersion;
|
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_eh_data = false;
|
||||||
var has_aug_data = false;
|
var has_aug_data = false;
|
||||||
@ -2083,6 +2108,9 @@ pub const CommonInformationEntry = struct {
|
|||||||
for (0..addr_size_bytes) |_| _ = try reader.readByte();
|
for (0..addr_size_bytes) |_| _ = try reader.readByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const address_size = if (version == 4) try reader.readByte() else addr_size_bytes;
|
||||||
|
const segment_selector_size = if (version == 4) try reader.readByte() else null;
|
||||||
|
|
||||||
const code_alignment_factor = try leb.readULEB128(u32, reader);
|
const code_alignment_factor = try leb.readULEB128(u32, reader);
|
||||||
const data_alignment_factor = try leb.readILEB128(i32, reader);
|
const data_alignment_factor = try leb.readILEB128(i32, reader);
|
||||||
const return_address_register = if (version == 1) try reader.readByte() else try leb.readULEB128(u8, reader);
|
const return_address_register = if (version == 1) try reader.readByte() else try leb.readULEB128(u8, reader);
|
||||||
@ -2134,6 +2162,8 @@ pub const CommonInformationEntry = struct {
|
|||||||
return .{
|
return .{
|
||||||
.length_offset = length_offset,
|
.length_offset = length_offset,
|
||||||
.version = version,
|
.version = version,
|
||||||
|
.address_size = address_size,
|
||||||
|
.segment_selector_size = segment_selector_size,
|
||||||
.code_alignment_factor = code_alignment_factor,
|
.code_alignment_factor = code_alignment_factor,
|
||||||
.data_alignment_factor = data_alignment_factor,
|
.data_alignment_factor = data_alignment_factor,
|
||||||
.return_address_register = return_address_register,
|
.return_address_register = return_address_register,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user