authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-06-26 00:58:42-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:14-04:00
loga9b6f2d92984e1b4d4a9fe2b0ba0b14ec8b812c5
tree614a4c9b1b8dddeb8574a01d19f916aa0e882829
parent41832aa1e651a4a19f3ab275a54c28ed27180cd5

dwarf: add support for .debug_frame and CIE version 4


1 files changed, 78 insertions(+), 48 deletions(-)

lib/std/dwarf.zig+78-48
...@@ -7,6 +7,7 @@ const os = std.os;...@@ -7,6 +7,7 @@ const os = std.os;
7const mem = std.mem;7const mem = std.mem;
8const math = std.math;8const math = std.math;
9const leb = @import("leb128.zig");9const leb = @import("leb128.zig");
10const assert = std.debug.assert;
1011
11pub const TAG = @import("dwarf/TAG.zig");12pub const TAG = @import("dwarf/TAG.zig");
12pub const AT = @import("dwarf/AT.zig");13pub const AT = @import("dwarf/AT.zig");
...@@ -1530,45 +1531,49 @@ pub const DwarfInfo = struct {...@@ -1530,45 +1531,49 @@ pub const DwarfInfo = struct {
1530 return;1531 return;
1531 }1532 }
15321533
1533 if (di.section(.eh_frame)) |eh_frame| {1534 const frame_sections = [2]DwarfSection{ .eh_frame, .debug_frame };
1534 var stream = io.fixedBufferStream(eh_frame);1535 for (frame_sections) |frame_section| {
1535 while (stream.pos < stream.buffer.len) {1536 if (di.section(frame_section)) |eh_frame| {
1536 const entry_header = try EntryHeader.read(&stream, di.endian);1537 var stream = io.fixedBufferStream(eh_frame);
1537 switch (entry_header.type) {1538 while (stream.pos < stream.buffer.len) {
1538 .cie => {1539 const entry_header = try EntryHeader.read(&stream, frame_section, di.endian);
1539 const cie = try CommonInformationEntry.parse(1540 switch (entry_header.type) {
1540 entry_header.entry_bytes,1541 .cie => {
1541 -@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),1542 const cie = try CommonInformationEntry.parse(
1542 true,1543 entry_header.entry_bytes,
1543 entry_header.length_offset,1544 -@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),
1544 @sizeOf(usize),1545 true,
1545 di.endian,1546 frame_section,
1546 );1547 entry_header.length_offset,
1547 try di.cie_map.put(allocator, entry_header.length_offset, cie);1548 @sizeOf(usize),
1548 },1549 di.endian,
1549 .fde => |cie_offset| {1550 );
1550 const cie = di.cie_map.get(cie_offset) orelse return badDwarf();1551 try di.cie_map.put(allocator, entry_header.length_offset, cie);
1551 const fde = try FrameDescriptionEntry.parse(1552 },
1552 entry_header.entry_bytes,1553 .fde => |cie_offset| {
1553 -@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),1554 const cie = di.cie_map.get(cie_offset) orelse return badDwarf();
1554 true,1555 const fde = try FrameDescriptionEntry.parse(
1555 cie,1556 entry_header.entry_bytes,
1556 @sizeOf(usize),1557 -@as(i64, @intCast(@intFromPtr(binary_mem.ptr))),
1557 di.endian,1558 true,
1558 );1559 cie,
1559 try di.fde_list.append(allocator, fde);1560 @sizeOf(usize),
1560 },1561 di.endian,
1561 .terminator => break,1562 );
1563 try di.fde_list.append(allocator, fde);
1564 },
1565 .terminator => break,
1566 }
1562 }1567 }
1563 }
15641568
1565 // TODO: Avoiding sorting if has_eh_frame_hdr exists1569 // TODO: Avoiding sorting if has_eh_frame_hdr exists
1566 std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct {1570 std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct {
1567 fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool {1571 fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool {
1568 _ = ctx;1572 _ = ctx;
1569 return a.pc_begin < b.pc_begin;1573 return a.pc_begin < b.pc_begin;
1570 }1574 }
1571 }.lessThan);1575 }.lessThan);
1576 }
1572 }1577 }
1573 }1578 }
15741579
...@@ -1905,14 +1910,14 @@ pub const ExceptionFrameHeader = struct {...@@ -1905,14 +1910,14 @@ pub const ExceptionFrameHeader = struct {
1905 var eh_frame_stream = io.fixedBufferStream(eh_frame);1910 var eh_frame_stream = io.fixedBufferStream(eh_frame);
1906 try eh_frame_stream.seekTo(fde_offset);1911 try eh_frame_stream.seekTo(fde_offset);
19071912
1908 const fde_entry_header = try EntryHeader.read(&eh_frame_stream, builtin.cpu.arch.endian());1913 const fde_entry_header = try EntryHeader.read(&eh_frame_stream, .eh_frame, builtin.cpu.arch.endian());
1909 if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();1914 if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();
1910 if (fde_entry_header.type != .fde) return badDwarf();1915 if (fde_entry_header.type != .fde) return badDwarf();
19111916
1912 // CIEs always come before FDEs (the offset is a subtration), so we can assume this memory is readable1917 // CIEs always come before FDEs (the offset is a subtration), so we can assume this memory is readable
1913 const cie_offset = fde_entry_header.type.fde;1918 const cie_offset = fde_entry_header.type.fde;
1914 try eh_frame_stream.seekTo(cie_offset);1919 try eh_frame_stream.seekTo(cie_offset);
1915 const cie_entry_header = try EntryHeader.read(&eh_frame_stream, builtin.cpu.arch.endian());1920 const cie_entry_header = try EntryHeader.read(&eh_frame_stream, .eh_frame, builtin.cpu.arch.endian());
1916 if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();1921 if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();
1917 if (cie_entry_header.type != .cie) return badDwarf();1922 if (cie_entry_header.type != .cie) return badDwarf();
19181923
...@@ -1920,6 +1925,7 @@ pub const ExceptionFrameHeader = struct {...@@ -1920,6 +1925,7 @@ pub const ExceptionFrameHeader = struct {
1920 cie_entry_header.entry_bytes,1925 cie_entry_header.entry_bytes,
1921 0,1926 0,
1922 true,1927 true,
1928 .eh_frame,
1923 cie_entry_header.length_offset,1929 cie_entry_header.length_offset,
1924 @sizeOf(usize),1930 @sizeOf(usize),
1925 builtin.cpu.arch.endian(),1931 builtin.cpu.arch.endian(),
...@@ -1937,7 +1943,7 @@ pub const ExceptionFrameHeader = struct {...@@ -1937,7 +1943,7 @@ pub const ExceptionFrameHeader = struct {
1937};1943};
19381944
1939pub const EntryHeader = struct {1945pub const EntryHeader = struct {
1940 /// Offset of the length in the backing buffer1946 /// Offset of the length field in the backing buffer
1941 length_offset: usize,1947 length_offset: usize,
1942 is_64: bool,1948 is_64: bool,
1943 type: union(enum) {1949 type: union(enum) {
...@@ -1950,8 +1956,10 @@ pub const EntryHeader = struct {...@@ -1950,8 +1956,10 @@ pub const EntryHeader = struct {
1950 entry_bytes: []const u8,1956 entry_bytes: []const u8,
19511957
1952 /// Reads a header for either an FDE or a CIE, then advances the stream to the position after the trailing structure.1958 /// Reads a header for either an FDE or a CIE, then advances the stream to the position after the trailing structure.
1953 /// `stream` must be a stream backed by the .eh_frame section.1959 /// `stream` must be a stream backed by either the .eh_frame or .debug_frame sections.
1954 pub fn read(stream: *std.io.FixedBufferStream([]const u8), endian: std.builtin.Endian) !EntryHeader {1960 pub fn read(stream: *std.io.FixedBufferStream([]const u8), dwarf_section: DwarfSection, endian: std.builtin.Endian) !EntryHeader {
1961 assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame);
1962
1955 const reader = stream.reader();1963 const reader = stream.reader();
1956 const length_offset = stream.pos;1964 const length_offset = stream.pos;
19571965
...@@ -1967,14 +1975,21 @@ pub const EntryHeader = struct {...@@ -1967,14 +1975,21 @@ pub const EntryHeader = struct {
1967 const id_len = @as(u8, if (is_64) 8 else 4);1975 const id_len = @as(u8, if (is_64) 8 else 4);
1968 const id = if (is_64) try reader.readInt(u64, endian) else try reader.readInt(u32, endian);1976 const id = if (is_64) try reader.readInt(u64, endian) else try reader.readInt(u32, endian);
1969 const entry_bytes = stream.buffer[stream.pos..][0 .. length - id_len];1977 const entry_bytes = stream.buffer[stream.pos..][0 .. length - id_len];
1978 const cie_id: u64 = switch (dwarf_section) {
1979 .eh_frame => CommonInformationEntry.eh_id,
1980 .debug_frame => if (is_64) CommonInformationEntry.dwarf64_id else CommonInformationEntry.dwarf32_id,
1981 else => unreachable,
1982 };
19701983
1971 const result = EntryHeader{1984 const result = EntryHeader{
1972 .length_offset = length_offset,1985 .length_offset = length_offset,
1973 .is_64 = is_64,1986 .is_64 = is_64,
1974 .type = switch (id) {1987 .type = if (id == cie_id) .{ .cie = {} } else .{
1975 0 => .{ .cie = {} },1988 .fde = switch (dwarf_section) {
1976 // TODO: Support CommonInformationEntry.dwarf32_id, CommonInformationEntry.dwarf64_id1989 .eh_frame => stream.pos - id_len - id,
1977 else => .{ .fde = stream.pos - id_len - id },1990 .debug_frame => id,
1991 else => unreachable,
1992 },
1978 },1993 },
1979 .entry_bytes = entry_bytes,1994 .entry_bytes = entry_bytes,
1980 };1995 };
...@@ -2004,6 +2019,11 @@ pub const CommonInformationEntry = struct {...@@ -2004,6 +2019,11 @@ pub const CommonInformationEntry = struct {
2004 length_offset: u64,2019 length_offset: u64,
2005 version: u8,2020 version: u8,
20062021
2022 address_size: u8,
2023
2024 // Only present in version 4
2025 segment_selector_size: ?u8,
2026
2007 code_alignment_factor: u32,2027 code_alignment_factor: u32,
2008 data_alignment_factor: i32,2028 data_alignment_factor: i32,
2009 return_address_register: u8,2029 return_address_register: u8,
...@@ -2038,11 +2058,12 @@ pub const CommonInformationEntry = struct {...@@ -2038,11 +2058,12 @@ pub const CommonInformationEntry = struct {
2038 /// of `pc_rel_offset` and `is_runtime`.2058 /// of `pc_rel_offset` and `is_runtime`.
2039 ///2059 ///
2040 /// `length_offset` specifies the offset of this CIE's length field in the2060 /// `length_offset` specifies the offset of this CIE's length field in the
2041 /// .eh_frame section.2061 /// .eh_frame / .debug_framesection.
2042 pub fn parse(2062 pub fn parse(
2043 cie_bytes: []const u8,2063 cie_bytes: []const u8,
2044 pc_rel_offset: i64,2064 pc_rel_offset: i64,
2045 is_runtime: bool,2065 is_runtime: bool,
2066 dwarf_section: DwarfSection,
2046 length_offset: u64,2067 length_offset: u64,
2047 addr_size_bytes: u8,2068 addr_size_bytes: u8,
2048 endian: std.builtin.Endian,2069 endian: std.builtin.Endian,
...@@ -2053,7 +2074,11 @@ pub const CommonInformationEntry = struct {...@@ -2053,7 +2074,11 @@ pub const CommonInformationEntry = struct {
2053 const reader = stream.reader();2074 const reader = stream.reader();
20542075
2055 const version = try reader.readByte();2076 const version = try reader.readByte();
2056 if (version != 1 and version != 3) return error.UnsupportedDwarfVersion;2077 switch (dwarf_section) {
2078 .eh_frame => if (version != 1 and version != 3) return error.UnsupportedDwarfVersion,
2079 .debug_frame => if (version != 4) return error.UnsupportedDwarfVersion,
2080 else => return error.UnsupportedDwarfSection,
2081 }
20572082
2058 var has_eh_data = false;2083 var has_eh_data = false;
2059 var has_aug_data = false;2084 var has_aug_data = false;
...@@ -2083,6 +2108,9 @@ pub const CommonInformationEntry = struct {...@@ -2083,6 +2108,9 @@ pub const CommonInformationEntry = struct {
2083 for (0..addr_size_bytes) |_| _ = try reader.readByte();2108 for (0..addr_size_bytes) |_| _ = try reader.readByte();
2084 }2109 }
20852110
2111 const address_size = if (version == 4) try reader.readByte() else addr_size_bytes;
2112 const segment_selector_size = if (version == 4) try reader.readByte() else null;
2113
2086 const code_alignment_factor = try leb.readULEB128(u32, reader);2114 const code_alignment_factor = try leb.readULEB128(u32, reader);
2087 const data_alignment_factor = try leb.readILEB128(i32, reader);2115 const data_alignment_factor = try leb.readILEB128(i32, reader);
2088 const return_address_register = if (version == 1) try reader.readByte() else try leb.readULEB128(u8, reader);2116 const return_address_register = if (version == 1) try reader.readByte() else try leb.readULEB128(u8, reader);
...@@ -2134,6 +2162,8 @@ pub const CommonInformationEntry = struct {...@@ -2134,6 +2162,8 @@ pub const CommonInformationEntry = struct {
2134 return .{2162 return .{
2135 .length_offset = length_offset,2163 .length_offset = length_offset,
2136 .version = version,2164 .version = version,
2165 .address_size = address_size,
2166 .segment_selector_size = segment_selector_size,
2137 .code_alignment_factor = code_alignment_factor,2167 .code_alignment_factor = code_alignment_factor,
2138 .data_alignment_factor = data_alignment_factor,2168 .data_alignment_factor = data_alignment_factor,
2139 .return_address_register = return_address_register,2169 .return_address_register = return_address_register,