authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2024-07-10 02:25:19-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-10 10:46:35-04:00
log95d9292a7a09ed883e65510ec054619747315c48
treeb335ce3241314861c08d8be1f8ccaa50766158d7
parent1f6b3d16644c8727323a1512d555236afbca7d7f

dwarf: use StackIterator.MemoryAccessor to check memory accesses instead of isValidMemory


4 files changed, 107 insertions(+), 57 deletions(-)

lib/std/debug.zig+3-3
...@@ -610,7 +610,7 @@ pub const StackIterator = struct {...@@ -610,7 +610,7 @@ pub const StackIterator = struct {
610 var iterator = init(first_address, null);610 var iterator = init(first_address, null);
611 iterator.unwind_state = .{611 iterator.unwind_state = .{
612 .debug_info = debug_info,612 .debug_info = debug_info,
613 .dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context, &isValidMemory),613 .dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context),
614 };614 };
615615
616 return iterator;616 return iterator;
...@@ -793,7 +793,7 @@ pub const StackIterator = struct {...@@ -793,7 +793,7 @@ pub const StackIterator = struct {
793 // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding793 // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding
794 // via DWARF before attempting to use the compact unwind info will produce incorrect results.794 // via DWARF before attempting to use the compact unwind info will produce incorrect results.
795 if (module.unwind_info) |unwind_info| {795 if (module.unwind_info) |unwind_info| {
796 if (DW.unwindFrameMachO(&unwind_state.dwarf_context, unwind_info, module.eh_frame, module.base_address)) |return_address| {796 if (DW.unwindFrameMachO(&unwind_state.dwarf_context, &it.ma, unwind_info, module.eh_frame, module.base_address)) |return_address| {
797 return return_address;797 return return_address;
798 } else |err| {798 } else |err| {
799 if (err != error.RequiresDWARFUnwind) return err;799 if (err != error.RequiresDWARFUnwind) return err;
...@@ -804,7 +804,7 @@ pub const StackIterator = struct {...@@ -804,7 +804,7 @@ pub const StackIterator = struct {
804 }804 }
805805
806 if (try module.getDwarfInfoForAddress(unwind_state.debug_info.allocator, unwind_state.dwarf_context.pc)) |di| {806 if (try module.getDwarfInfoForAddress(unwind_state.debug_info.allocator, unwind_state.dwarf_context.pc)) |di| {
807 return di.unwindFrame(&unwind_state.dwarf_context, null);807 return di.unwindFrame(&unwind_state.dwarf_context, &it.ma, null);
808 } else return error.MissingDebugInfo;808 } else return error.MissingDebugInfo;
809 }809 }
810810
lib/std/dwarf.zig+89-49
...@@ -475,8 +475,8 @@ const UnitHeader = struct {...@@ -475,8 +475,8 @@ const UnitHeader = struct {
475 header_length: u4,475 header_length: u4,
476 unit_length: u64,476 unit_length: u64,
477};477};
478fn readUnitHeader(fbr: *FixedBufferReader) !UnitHeader {478fn readUnitHeader(fbr: *FixedBufferReader, opt_ma: ?*debug.StackIterator.MemoryAccessor) !UnitHeader {
479 return switch (try fbr.readInt(u32)) {479 return switch (try if (opt_ma) |ma| fbr.readIntChecked(u32, ma) else fbr.readInt(u32)) {
480 0...0xfffffff0 - 1 => |unit_length| .{480 0...0xfffffff0 - 1 => |unit_length| .{
481 .format = .@"32",481 .format = .@"32",
482 .header_length = 4,482 .header_length = 4,
...@@ -486,7 +486,7 @@ fn readUnitHeader(fbr: *FixedBufferReader) !UnitHeader {...@@ -486,7 +486,7 @@ fn readUnitHeader(fbr: *FixedBufferReader) !UnitHeader {
486 0xffffffff => .{486 0xffffffff => .{
487 .format = .@"64",487 .format = .@"64",
488 .header_length = 12,488 .header_length = 12,
489 .unit_length = try fbr.readInt(u64),489 .unit_length = try if (opt_ma) |ma| fbr.readIntChecked(u64, ma) else fbr.readInt(u64),
490 },490 },
491 };491 };
492}492}
...@@ -663,7 +663,7 @@ pub const DwarfInfo = struct {...@@ -663,7 +663,7 @@ pub const DwarfInfo = struct {
663 while (this_unit_offset < fbr.buf.len) {663 while (this_unit_offset < fbr.buf.len) {
664 try fbr.seekTo(this_unit_offset);664 try fbr.seekTo(this_unit_offset);
665665
666 const unit_header = try readUnitHeader(&fbr);666 const unit_header = try readUnitHeader(&fbr, null);
667 if (unit_header.unit_length == 0) return;667 if (unit_header.unit_length == 0) return;
668 const next_offset = unit_header.header_length + unit_header.unit_length;668 const next_offset = unit_header.header_length + unit_header.unit_length;
669669
...@@ -853,7 +853,7 @@ pub const DwarfInfo = struct {...@@ -853,7 +853,7 @@ pub const DwarfInfo = struct {
853 while (this_unit_offset < fbr.buf.len) {853 while (this_unit_offset < fbr.buf.len) {
854 try fbr.seekTo(this_unit_offset);854 try fbr.seekTo(this_unit_offset);
855855
856 const unit_header = try readUnitHeader(&fbr);856 const unit_header = try readUnitHeader(&fbr, null);
857 if (unit_header.unit_length == 0) return;857 if (unit_header.unit_length == 0) return;
858 const next_offset = unit_header.header_length + unit_header.unit_length;858 const next_offset = unit_header.header_length + unit_header.unit_length;
859859
...@@ -1200,7 +1200,7 @@ pub const DwarfInfo = struct {...@@ -1200,7 +1200,7 @@ pub const DwarfInfo = struct {
1200 var fbr: FixedBufferReader = .{ .buf = di.section(.debug_line).?, .endian = di.endian };1200 var fbr: FixedBufferReader = .{ .buf = di.section(.debug_line).?, .endian = di.endian };
1201 try fbr.seekTo(line_info_offset);1201 try fbr.seekTo(line_info_offset);
12021202
1203 const unit_header = try readUnitHeader(&fbr);1203 const unit_header = try readUnitHeader(&fbr, null);
1204 if (unit_header.unit_length == 0) return missingDwarf();1204 if (unit_header.unit_length == 0) return missingDwarf();
1205 const next_offset = unit_header.header_length + unit_header.unit_length;1205 const next_offset = unit_header.header_length + unit_header.unit_length;
12061206
...@@ -1532,7 +1532,7 @@ pub const DwarfInfo = struct {...@@ -1532,7 +1532,7 @@ pub const DwarfInfo = struct {
1532 if (di.section(frame_section)) |section_data| {1532 if (di.section(frame_section)) |section_data| {
1533 var fbr: FixedBufferReader = .{ .buf = section_data, .endian = di.endian };1533 var fbr: FixedBufferReader = .{ .buf = section_data, .endian = di.endian };
1534 while (fbr.pos < fbr.buf.len) {1534 while (fbr.pos < fbr.buf.len) {
1535 const entry_header = try EntryHeader.read(&fbr, frame_section);1535 const entry_header = try EntryHeader.read(&fbr, null, frame_section);
1536 switch (entry_header.type) {1536 switch (entry_header.type) {
1537 .cie => {1537 .cie => {
1538 const cie = try CommonInformationEntry.parse(1538 const cie = try CommonInformationEntry.parse(
...@@ -1580,7 +1580,7 @@ pub const DwarfInfo = struct {...@@ -1580,7 +1580,7 @@ pub const DwarfInfo = struct {
1580 ///1580 ///
1581 /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info1581 /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info
1582 /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.1582 /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.
1583 pub fn unwindFrame(di: *const DwarfInfo, context: *UnwindContext, explicit_fde_offset: ?usize) !usize {1583 pub fn unwindFrame(di: *const DwarfInfo, context: *UnwindContext, ma: *debug.StackIterator.MemoryAccessor, explicit_fde_offset: ?usize) !usize {
1584 if (!comptime abi.supportsUnwinding(builtin.target)) return error.UnsupportedCpuArchitecture;1584 if (!comptime abi.supportsUnwinding(builtin.target)) return error.UnsupportedCpuArchitecture;
1585 if (context.pc == 0) return 0;1585 if (context.pc == 0) return 0;
15861586
...@@ -1599,14 +1599,14 @@ pub const DwarfInfo = struct {...@@ -1599,14 +1599,14 @@ pub const DwarfInfo = struct {
1599 .endian = di.endian,1599 .endian = di.endian,
1600 };1600 };
16011601
1602 const fde_entry_header = try EntryHeader.read(&fbr, dwarf_section);1602 const fde_entry_header = try EntryHeader.read(&fbr, null, dwarf_section);
1603 if (fde_entry_header.type != .fde) return error.MissingFDE;1603 if (fde_entry_header.type != .fde) return error.MissingFDE;
16041604
1605 const cie_offset = fde_entry_header.type.fde;1605 const cie_offset = fde_entry_header.type.fde;
1606 try fbr.seekTo(cie_offset);1606 try fbr.seekTo(cie_offset);
16071607
1608 fbr.endian = native_endian;1608 fbr.endian = native_endian;
1609 const cie_entry_header = try EntryHeader.read(&fbr, dwarf_section);1609 const cie_entry_header = try EntryHeader.read(&fbr, null, dwarf_section);
1610 if (cie_entry_header.type != .cie) return badDwarf();1610 if (cie_entry_header.type != .cie) return badDwarf();
16111611
1612 cie = try CommonInformationEntry.parse(1612 cie = try CommonInformationEntry.parse(
...@@ -1631,7 +1631,7 @@ pub const DwarfInfo = struct {...@@ -1631,7 +1631,7 @@ pub const DwarfInfo = struct {
1631 } else if (di.eh_frame_hdr) |header| {1631 } else if (di.eh_frame_hdr) |header| {
1632 const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null;1632 const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null;
1633 try header.findEntry(1633 try header.findEntry(
1634 context.isValidMemory,1634 ma,
1635 eh_frame_len,1635 eh_frame_len,
1636 @intFromPtr(di.section(.eh_frame_hdr).?.ptr),1636 @intFromPtr(di.section(.eh_frame_hdr).?.ptr),
1637 context.pc,1637 context.pc,
...@@ -1656,7 +1656,7 @@ pub const DwarfInfo = struct {...@@ -1656,7 +1656,7 @@ pub const DwarfInfo = struct {
16561656
1657 var expression_context: expressions.ExpressionContext = .{1657 var expression_context: expressions.ExpressionContext = .{
1658 .format = cie.format,1658 .format = cie.format,
1659 .isValidMemory = context.isValidMemory,1659 .memory_accessor = ma,
1660 .compile_unit = di.findCompileUnit(fde.pc_begin) catch null,1660 .compile_unit = di.findCompileUnit(fde.pc_begin) catch null,
1661 .thread_context = context.thread_context,1661 .thread_context = context.thread_context,
1662 .reg_context = context.reg_context,1662 .reg_context = context.reg_context,
...@@ -1691,7 +1691,7 @@ pub const DwarfInfo = struct {...@@ -1691,7 +1691,7 @@ pub const DwarfInfo = struct {
1691 else => return error.InvalidCFARule,1691 else => return error.InvalidCFARule,
1692 };1692 };
16931693
1694 if (!context.isValidMemory(context.cfa.?)) return error.InvalidCFA;1694 if (ma.load(usize, context.cfa.?) == null) return error.InvalidCFA;
1695 expression_context.cfa = context.cfa;1695 expression_context.cfa = context.cfa;
16961696
1697 // Buffering the modifications is done because copying the thread context is not portable,1697 // Buffering the modifications is done because copying the thread context is not portable,
...@@ -1730,6 +1730,7 @@ pub const DwarfInfo = struct {...@@ -1730,6 +1730,7 @@ pub const DwarfInfo = struct {
1730 try column.resolveValue(1730 try column.resolveValue(
1731 context,1731 context,
1732 expression_context,1732 expression_context,
1733 ma,
1733 src,1734 src,
1734 );1735 );
1735 }1736 }
...@@ -1788,7 +1789,13 @@ const macho = std.macho;...@@ -1788,7 +1789,13 @@ const macho = std.macho;
1788/// Unwind a frame using MachO compact unwind info (from __unwind_info).1789/// Unwind a frame using MachO compact unwind info (from __unwind_info).
1789/// If the compact encoding can't encode a way to unwind a frame, it will1790/// If the compact encoding can't encode a way to unwind a frame, it will
1790/// defer unwinding to DWARF, in which case `.eh_frame` will be used if available.1791/// defer unwinding to DWARF, in which case `.eh_frame` will be used if available.
1791pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_frame: ?[]const u8, module_base_address: usize) !usize {1792pub fn unwindFrameMachO(
1793 context: *UnwindContext,
1794 ma: *debug.StackIterator.MemoryAccessor,
1795 unwind_info: []const u8,
1796 eh_frame: ?[]const u8,
1797 module_base_address: usize,
1798) !usize {
1792 const header = mem.bytesAsValue(1799 const header = mem.bytesAsValue(
1793 macho.unwind_info_section_header,1800 macho.unwind_info_section_header,
1794 unwind_info[0..@sizeOf(macho.unwind_info_section_header)],1801 unwind_info[0..@sizeOf(macho.unwind_info_section_header)],
...@@ -1950,7 +1957,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -1950,7 +1957,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
1950 const new_sp = fp + 2 * @sizeOf(usize);1957 const new_sp = fp + 2 * @sizeOf(usize);
19511958
1952 // Verify the stack range we're about to read register values from1959 // Verify the stack range we're about to read register values from
1953 if (!context.isValidMemory(new_sp) or !context.isValidMemory(fp - frame_offset + max_reg * @sizeOf(usize))) return error.InvalidUnwindInfo;1960 if (ma.load(usize, new_sp) == null or ma.load(usize, fp - frame_offset + max_reg * @sizeOf(usize)) == null) return error.InvalidUnwindInfo;
19541961
1955 const ip_ptr = fp + @sizeOf(usize);1962 const ip_ptr = fp + @sizeOf(usize);
1956 const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;1963 const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;
...@@ -1981,7 +1988,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -1981,7 +1988,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
1981 module_base_address +1988 module_base_address +
1982 entry.function_offset +1989 entry.function_offset +
1983 encoding.value.x86_64.frameless.stack.indirect.sub_offset;1990 encoding.value.x86_64.frameless.stack.indirect.sub_offset;
1984 if (!context.isValidMemory(sub_offset_addr)) return error.InvalidUnwindInfo;1991 if (ma.load(usize, sub_offset_addr) == null) return error.InvalidUnwindInfo;
19851992
1986 // `sub_offset_addr` points to the offset of the literal within the instruction1993 // `sub_offset_addr` points to the offset of the literal within the instruction
1987 const sub_operand = @as(*align(1) const u32, @ptrFromInt(sub_offset_addr)).*;1994 const sub_operand = @as(*align(1) const u32, @ptrFromInt(sub_offset_addr)).*;
...@@ -2023,7 +2030,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -2023,7 +2030,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
2023 }2030 }
20242031
2025 var reg_addr = sp + stack_size - @sizeOf(usize) * @as(usize, reg_count + 1);2032 var reg_addr = sp + stack_size - @sizeOf(usize) * @as(usize, reg_count + 1);
2026 if (!context.isValidMemory(reg_addr)) return error.InvalidUnwindInfo;2033 if (ma.load(usize, reg_addr) == null) return error.InvalidUnwindInfo;
2027 for (0..reg_count) |i| {2034 for (0..reg_count) |i| {
2028 const reg_number = try compactUnwindToDwarfRegNumber(registers[i]);2035 const reg_number = try compactUnwindToDwarfRegNumber(registers[i]);
2029 (try abi.regValueNative(usize, context.thread_context, reg_number, reg_context)).* = @as(*const usize, @ptrFromInt(reg_addr)).*;2036 (try abi.regValueNative(usize, context.thread_context, reg_number, reg_context)).* = @as(*const usize, @ptrFromInt(reg_addr)).*;
...@@ -2035,7 +2042,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -2035,7 +2042,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
20352042
2036 const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;2043 const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;
2037 const new_sp = ip_ptr + @sizeOf(usize);2044 const new_sp = ip_ptr + @sizeOf(usize);
2038 if (!context.isValidMemory(new_sp)) return error.InvalidUnwindInfo;2045 if (ma.load(usize, new_sp) == null) return error.InvalidUnwindInfo;
20392046
2040 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(reg_context), reg_context)).* = new_sp;2047 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(reg_context), reg_context)).* = new_sp;
2041 (try abi.regValueNative(usize, context.thread_context, abi.ipRegNum(), reg_context)).* = new_ip;2048 (try abi.regValueNative(usize, context.thread_context, abi.ipRegNum(), reg_context)).* = new_ip;
...@@ -2043,7 +2050,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -2043,7 +2050,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
2043 break :blk new_ip;2050 break :blk new_ip;
2044 },2051 },
2045 .DWARF => {2052 .DWARF => {
2046 return unwindFrameMachODwarf(context, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.x86_64.dwarf));2053 return unwindFrameMachODwarf(context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.x86_64.dwarf));
2047 },2054 },
2048 },2055 },
2049 .aarch64 => switch (encoding.mode.arm64) {2056 .aarch64 => switch (encoding.mode.arm64) {
...@@ -2052,12 +2059,12 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -2052,12 +2059,12 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
2052 const sp = (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(reg_context), reg_context)).*;2059 const sp = (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(reg_context), reg_context)).*;
2053 const new_sp = sp + encoding.value.arm64.frameless.stack_size * 16;2060 const new_sp = sp + encoding.value.arm64.frameless.stack_size * 16;
2054 const new_ip = (try abi.regValueNative(usize, context.thread_context, 30, reg_context)).*;2061 const new_ip = (try abi.regValueNative(usize, context.thread_context, 30, reg_context)).*;
2055 if (!context.isValidMemory(new_sp)) return error.InvalidUnwindInfo;2062 if (ma.load(usize, new_sp) == null) return error.InvalidUnwindInfo;
2056 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(reg_context), reg_context)).* = new_sp;2063 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(reg_context), reg_context)).* = new_sp;
2057 break :blk new_ip;2064 break :blk new_ip;
2058 },2065 },
2059 .DWARF => {2066 .DWARF => {
2060 return unwindFrameMachODwarf(context, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.arm64.dwarf));2067 return unwindFrameMachODwarf(context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.arm64.dwarf));
2061 },2068 },
2062 .FRAME => blk: {2069 .FRAME => blk: {
2063 const fp = (try abi.regValueNative(usize, context.thread_context, abi.fpRegNum(reg_context), reg_context)).*;2070 const fp = (try abi.regValueNative(usize, context.thread_context, abi.fpRegNum(reg_context), reg_context)).*;
...@@ -2069,7 +2076,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -2069,7 +2076,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
2069 @popCount(@as(u4, @bitCast(encoding.value.arm64.frame.d_reg_pairs)));2076 @popCount(@as(u4, @bitCast(encoding.value.arm64.frame.d_reg_pairs)));
2070 const min_reg_addr = fp - num_restored_pairs * 2 * @sizeOf(usize);2077 const min_reg_addr = fp - num_restored_pairs * 2 * @sizeOf(usize);
20712078
2072 if (!context.isValidMemory(new_sp) or !context.isValidMemory(min_reg_addr)) return error.InvalidUnwindInfo;2079 if (ma.load(usize, new_sp) == null or ma.load(usize, min_reg_addr) == null) return error.InvalidUnwindInfo;
20732080
2074 var reg_addr = fp - @sizeOf(usize);2081 var reg_addr = fp - @sizeOf(usize);
2075 inline for (@typeInfo(@TypeOf(encoding.value.arm64.frame.x_reg_pairs)).Struct.fields, 0..) |field, i| {2082 inline for (@typeInfo(@TypeOf(encoding.value.arm64.frame.x_reg_pairs)).Struct.fields, 0..) |field, i| {
...@@ -2114,7 +2121,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra...@@ -2114,7 +2121,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra
2114 return new_ip;2121 return new_ip;
2115}2122}
21162123
2117fn unwindFrameMachODwarf(context: *UnwindContext, eh_frame: []const u8, fde_offset: usize) !usize {2124fn unwindFrameMachODwarf(context: *UnwindContext, ma: *debug.StackIterator.MemoryAccessor, eh_frame: []const u8, fde_offset: usize) !usize {
2118 var di = DwarfInfo{2125 var di = DwarfInfo{
2119 .endian = native_endian,2126 .endian = native_endian,
2120 .is_macho = true,2127 .is_macho = true,
...@@ -2126,7 +2133,7 @@ fn unwindFrameMachODwarf(context: *UnwindContext, eh_frame: []const u8, fde_offs...@@ -2126,7 +2133,7 @@ fn unwindFrameMachODwarf(context: *UnwindContext, eh_frame: []const u8, fde_offs
2126 .owned = false,2133 .owned = false,
2127 };2134 };
21282135
2129 return di.unwindFrame(context, fde_offset);2136 return di.unwindFrame(context, ma, fde_offset);
2130}2137}
21312138
2132pub const UnwindContext = struct {2139pub const UnwindContext = struct {
...@@ -2135,12 +2142,21 @@ pub const UnwindContext = struct {...@@ -2135,12 +2142,21 @@ pub const UnwindContext = struct {
2135 pc: usize,2142 pc: usize,
2136 thread_context: *debug.ThreadContext,2143 thread_context: *debug.ThreadContext,
2137 reg_context: abi.RegisterContext,2144 reg_context: abi.RegisterContext,
2138 isValidMemory: *const fn (address: usize) bool,
2139 vm: call_frame.VirtualMachine,2145 vm: call_frame.VirtualMachine,
2140 stack_machine: expressions.StackMachine(.{ .call_frame_context = true }),2146 stack_machine: expressions.StackMachine(.{ .call_frame_context = true }),
21412147
2142 pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {2148 pub fn init(
2143 const pc = abi.stripInstructionPtrAuthCode((try abi.regValueNative(usize, thread_context, abi.ipRegNum(), null)).*);2149 allocator: mem.Allocator,
2150 thread_context: *const debug.ThreadContext,
2151 ) !UnwindContext {
2152 const pc = abi.stripInstructionPtrAuthCode(
2153 (try abi.regValueNative(
2154 usize,
2155 thread_context,
2156 abi.ipRegNum(),
2157 null,
2158 )).*,
2159 );
21442160
2145 const context_copy = try allocator.create(debug.ThreadContext);2161 const context_copy = try allocator.create(debug.ThreadContext);
2146 debug.copyContext(thread_context, context_copy);2162 debug.copyContext(thread_context, context_copy);
...@@ -2151,7 +2167,6 @@ pub const UnwindContext = struct {...@@ -2151,7 +2167,6 @@ pub const UnwindContext = struct {
2151 .pc = pc,2167 .pc = pc,
2152 .thread_context = context_copy,2168 .thread_context = context_copy,
2153 .reg_context = undefined,2169 .reg_context = undefined,
2154 .isValidMemory = isValidMemory,
2155 .vm = .{},2170 .vm = .{},
2156 .stack_machine = .{},2171 .stack_machine = .{},
2157 };2172 };
...@@ -2297,25 +2312,26 @@ pub const ExceptionFrameHeader = struct {...@@ -2297,25 +2312,26 @@ pub const ExceptionFrameHeader = struct {
22972312
2298 fn isValidPtr(2313 fn isValidPtr(
2299 self: ExceptionFrameHeader,2314 self: ExceptionFrameHeader,
2315 comptime T: type,
2300 ptr: usize,2316 ptr: usize,
2301 isValidMemory: *const fn (address: usize) bool,2317 ma: *debug.StackIterator.MemoryAccessor,
2302 eh_frame_len: ?usize,2318 eh_frame_len: ?usize,
2303 ) bool {2319 ) bool {
2304 if (eh_frame_len) |len| {2320 if (eh_frame_len) |len| {
2305 return ptr >= self.eh_frame_ptr and ptr < self.eh_frame_ptr + len;2321 return ptr >= self.eh_frame_ptr and ptr <= self.eh_frame_ptr + len - @sizeOf(T);
2306 } else {2322 } else {
2307 return isValidMemory(ptr);2323 return ma.load(T, ptr) != null;
2308 }2324 }
2309 }2325 }
23102326
2311 /// Find an entry by binary searching the eh_frame_hdr section.2327 /// Find an entry by binary searching the eh_frame_hdr section.
2312 ///2328 ///
2313 /// Since the length of the eh_frame section (`eh_frame_len`) may not be known by the caller,2329 /// Since the length of the eh_frame section (`eh_frame_len`) may not be known by the caller,
2314 /// `isValidMemory` will be called before accessing any memory referenced by2330 /// MemoryAccessor will be used to verify readability of the header entries.
2315 /// the header entries. If `eh_frame_len` is provided, then these checks can be skipped.2331 /// If `eh_frame_len` is provided, then these checks can be skipped.
2316 pub fn findEntry(2332 pub fn findEntry(
2317 self: ExceptionFrameHeader,2333 self: ExceptionFrameHeader,
2318 isValidMemory: *const fn (address: usize) bool,2334 ma: *debug.StackIterator.MemoryAccessor,
2319 eh_frame_len: ?usize,2335 eh_frame_len: ?usize,
2320 eh_frame_hdr_ptr: usize,2336 eh_frame_hdr_ptr: usize,
2321 pc: usize,2337 pc: usize,
...@@ -2364,14 +2380,9 @@ pub const ExceptionFrameHeader = struct {...@@ -2364,14 +2380,9 @@ pub const ExceptionFrameHeader = struct {
2364 .data_rel_base = eh_frame_hdr_ptr,2380 .data_rel_base = eh_frame_hdr_ptr,
2365 }) orelse return badDwarf()) orelse return badDwarf();2381 }) orelse return badDwarf()) orelse return badDwarf();
23662382
2367 // Verify the length fields of the FDE header are readable2383 if (fde_ptr < self.eh_frame_ptr) return badDwarf();
2368 if (!self.isValidPtr(fde_ptr, isValidMemory, eh_frame_len) or fde_ptr < self.eh_frame_ptr) return badDwarf();
2369
2370 var fde_entry_header_len: usize = 4;
2371 if (!self.isValidPtr(fde_ptr + 3, isValidMemory, eh_frame_len)) return badDwarf();
2372 if (self.isValidPtr(fde_ptr + 11, isValidMemory, eh_frame_len)) fde_entry_header_len = 12;
23732384
2374 // Even if eh_frame_len is not specified, all ranges accssed are checked by isValidPtr2385 // Even if eh_frame_len is not specified, all ranges accssed are checked via MemoryAccessor
2375 const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0 .. eh_frame_len orelse math.maxInt(u32)];2386 const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0 .. eh_frame_len orelse math.maxInt(u32)];
23762387
2377 const fde_offset = fde_ptr - self.eh_frame_ptr;2388 const fde_offset = fde_ptr - self.eh_frame_ptr;
...@@ -2381,15 +2392,15 @@ pub const ExceptionFrameHeader = struct {...@@ -2381,15 +2392,15 @@ pub const ExceptionFrameHeader = struct {
2381 .endian = native_endian,2392 .endian = native_endian,
2382 };2393 };
23832394
2384 const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame);2395 const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame);
2385 if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();2396 if (!self.isValidPtr(u8, @intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return badDwarf();
2386 if (fde_entry_header.type != .fde) return badDwarf();2397 if (fde_entry_header.type != .fde) return badDwarf();
23872398
2388 // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable2399 // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable
2389 const cie_offset = fde_entry_header.type.fde;2400 const cie_offset = fde_entry_header.type.fde;
2390 try eh_frame_fbr.seekTo(cie_offset);2401 try eh_frame_fbr.seekTo(cie_offset);
2391 const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame);2402 const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame);
2392 if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf();2403 if (!self.isValidPtr(u8, @intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return badDwarf();
2393 if (cie_entry_header.type != .cie) return badDwarf();2404 if (cie_entry_header.type != .cie) return badDwarf();
23942405
2395 cie.* = try CommonInformationEntry.parse(2406 cie.* = try CommonInformationEntry.parse(
...@@ -2434,11 +2445,15 @@ pub const EntryHeader = struct {...@@ -2434,11 +2445,15 @@ pub const EntryHeader = struct {
24342445
2435 /// Reads a header for either an FDE or a CIE, then advances the fbr to the position after the trailing structure.2446 /// Reads a header for either an FDE or a CIE, then advances the fbr to the position after the trailing structure.
2436 /// `fbr` must be a FixedBufferReader backed by either the .eh_frame or .debug_frame sections.2447 /// `fbr` must be a FixedBufferReader backed by either the .eh_frame or .debug_frame sections.
2437 pub fn read(fbr: *FixedBufferReader, dwarf_section: DwarfSection) !EntryHeader {2448 pub fn read(
2449 fbr: *FixedBufferReader,
2450 opt_ma: ?*debug.StackIterator.MemoryAccessor,
2451 dwarf_section: DwarfSection,
2452 ) !EntryHeader {
2438 assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame);2453 assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame);
24392454
2440 const length_offset = fbr.pos;2455 const length_offset = fbr.pos;
2441 const unit_header = try readUnitHeader(fbr);2456 const unit_header = try readUnitHeader(fbr, opt_ma);
2442 const unit_length = math.cast(usize, unit_header.unit_length) orelse return badDwarf();2457 const unit_length = math.cast(usize, unit_header.unit_length) orelse return badDwarf();
2443 if (unit_length == 0) return .{2458 if (unit_length == 0) return .{
2444 .length_offset = length_offset,2459 .length_offset = length_offset,
...@@ -2450,7 +2465,10 @@ pub const EntryHeader = struct {...@@ -2450,7 +2465,10 @@ pub const EntryHeader = struct {
2450 const end_offset = start_offset + unit_length;2465 const end_offset = start_offset + unit_length;
2451 defer fbr.pos = end_offset;2466 defer fbr.pos = end_offset;
24522467
2453 const id = try fbr.readAddress(unit_header.format);2468 const id = try if (opt_ma) |ma|
2469 fbr.readAddressChecked(unit_header.format, ma)
2470 else
2471 fbr.readAddress(unit_header.format);
2454 const entry_bytes = fbr.buf[fbr.pos..end_offset];2472 const entry_bytes = fbr.buf[fbr.pos..end_offset];
2455 const cie_id: u64 = switch (dwarf_section) {2473 const cie_id: u64 = switch (dwarf_section) {
2456 .eh_frame => CommonInformationEntry.eh_id,2474 .eh_frame => CommonInformationEntry.eh_id,
...@@ -2732,7 +2750,7 @@ pub const FixedBufferReader = struct {...@@ -2732,7 +2750,7 @@ pub const FixedBufferReader = struct {
2732 pos: usize = 0,2750 pos: usize = 0,
2733 endian: std.builtin.Endian,2751 endian: std.builtin.Endian,
27342752
2735 pub const Error = error{ EndOfBuffer, Overflow };2753 pub const Error = error{ EndOfBuffer, Overflow, InvalidBuffer };
27362754
2737 fn seekTo(fbr: *FixedBufferReader, pos: u64) Error!void {2755 fn seekTo(fbr: *FixedBufferReader, pos: u64) Error!void {
2738 if (pos > fbr.buf.len) return error.EndOfBuffer;2756 if (pos > fbr.buf.len) return error.EndOfBuffer;
...@@ -2761,6 +2779,17 @@ pub const FixedBufferReader = struct {...@@ -2761,6 +2779,17 @@ pub const FixedBufferReader = struct {
2761 return mem.readInt(T, fbr.buf[fbr.pos..][0..size], fbr.endian);2779 return mem.readInt(T, fbr.buf[fbr.pos..][0..size], fbr.endian);
2762 }2780 }
27632781
2782 fn readIntChecked(
2783 fbr: *FixedBufferReader,
2784 comptime T: type,
2785 ma: *debug.StackIterator.MemoryAccessor,
2786 ) Error!T {
2787 if (ma.load(T, @intFromPtr(fbr.buf[fbr.pos..].ptr)) == null)
2788 return error.InvalidBuffer;
2789
2790 return readInt(fbr, T);
2791 }
2792
2764 fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {2793 fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
2765 return std.leb.readUleb128(T, fbr);2794 return std.leb.readUleb128(T, fbr);
2766 }2795 }
...@@ -2776,6 +2805,17 @@ pub const FixedBufferReader = struct {...@@ -2776,6 +2805,17 @@ pub const FixedBufferReader = struct {
2776 };2805 };
2777 }2806 }
27782807
2808 fn readAddressChecked(
2809 fbr: *FixedBufferReader,
2810 format: Format,
2811 ma: *debug.StackIterator.MemoryAccessor,
2812 ) Error!u64 {
2813 return switch (format) {
2814 .@"32" => try fbr.readIntChecked(u32, ma),
2815 .@"64" => try fbr.readIntChecked(u64, ma),
2816 };
2817 }
2818
2779 fn readBytes(fbr: *FixedBufferReader, len: usize) Error![]const u8 {2819 fn readBytes(fbr: *FixedBufferReader, len: usize) Error![]const u8 {
2780 if (fbr.buf.len - fbr.pos < len) return error.EndOfBuffer;2820 if (fbr.buf.len - fbr.pos < len) return error.EndOfBuffer;
2781 defer fbr.pos += len;2821 defer fbr.pos += len;
lib/std/dwarf/call_frame.zig+3-2
...@@ -365,6 +365,7 @@ pub const VirtualMachine = struct {...@@ -365,6 +365,7 @@ pub const VirtualMachine = struct {
365 self: Column,365 self: Column,
366 context: *dwarf.UnwindContext,366 context: *dwarf.UnwindContext,
367 expression_context: dwarf.expressions.ExpressionContext,367 expression_context: dwarf.expressions.ExpressionContext,
368 ma: *debug.StackIterator.MemoryAccessor,
368 out: []u8,369 out: []u8,
369 ) !void {370 ) !void {
370 switch (self.rule) {371 switch (self.rule) {
...@@ -385,7 +386,7 @@ pub const VirtualMachine = struct {...@@ -385,7 +386,7 @@ pub const VirtualMachine = struct {
385 .offset => |offset| {386 .offset => |offset| {
386 if (context.cfa) |cfa| {387 if (context.cfa) |cfa| {
387 const addr = try applyOffset(cfa, offset);388 const addr = try applyOffset(cfa, offset);
388 if (expression_context.isValidMemory) |isValidMemory| if (!isValidMemory(addr)) return error.InvalidAddress;389 if (ma.load(usize, addr) == null) return error.InvalidAddress;
389 const ptr: *const usize = @ptrFromInt(addr);390 const ptr: *const usize = @ptrFromInt(addr);
390 mem.writeInt(usize, out[0..@sizeOf(usize)], ptr.*, native_endian);391 mem.writeInt(usize, out[0..@sizeOf(usize)], ptr.*, native_endian);
391 } else return error.InvalidCFA;392 } else return error.InvalidCFA;
...@@ -408,7 +409,7 @@ pub const VirtualMachine = struct {...@@ -408,7 +409,7 @@ pub const VirtualMachine = struct {
408 break :blk v.generic;409 break :blk v.generic;
409 } else return error.NoExpressionValue;410 } else return error.NoExpressionValue;
410411
411 if (!context.isValidMemory(addr)) return error.InvalidExpressionAddress;412 if (ma.load(usize, addr) == null) return error.InvalidExpressionAddress;
412 const ptr: *usize = @ptrFromInt(addr);413 const ptr: *usize = @ptrFromInt(addr);
413 mem.writeInt(usize, out[0..@sizeOf(usize)], ptr.*, native_endian);414 mem.writeInt(usize, out[0..@sizeOf(usize)], ptr.*, native_endian);
414 },415 },
lib/std/dwarf/expressions.zig+12-3
...@@ -15,8 +15,8 @@ pub const ExpressionContext = struct {...@@ -15,8 +15,8 @@ pub const ExpressionContext = struct {
15 /// The dwarf format of the section this expression is in15 /// The dwarf format of the section this expression is in
16 format: dwarf.Format = .@"32",16 format: dwarf.Format = .@"32",
1717
18 /// If specified, any addresses will pass through this function before being accessed18 /// If specified, any addresses will pass through before being accessed
19 isValidMemory: ?*const fn (address: usize) bool = null,19 memory_accessor: ?*std.debug.StackIterator.MemoryAccessor = null,
2020
21 /// The compilation unit this expression relates to, if any21 /// The compilation unit this expression relates to, if any
22 compile_unit: ?*const dwarf.CompileUnit = null,22 compile_unit: ?*const dwarf.CompileUnit = null,
...@@ -460,7 +460,6 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -460,7 +460,6 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
460 // This code will need to be updated to handle any architectures that utilize this.460 // This code will need to be updated to handle any architectures that utilize this.
461 _ = addr_space_identifier;461 _ = addr_space_identifier;
462462
463 if (context.isValidMemory) |isValidMemory| if (!isValidMemory(addr)) return error.InvalidExpression;
464 const size = switch (opcode) {463 const size = switch (opcode) {
465 OP.deref,464 OP.deref,
466 OP.xderef,465 OP.xderef,
...@@ -474,6 +473,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -474,6 +473,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
474 else => unreachable,473 else => unreachable,
475 };474 };
476475
476 if (context.memory_accessor) |memory_accessor| {
477 if (!switch (size) {
478 1 => memory_accessor.load(u8, addr) != null,
479 2 => memory_accessor.load(u16, addr) != null,
480 4 => memory_accessor.load(u32, addr) != null,
481 8 => memory_accessor.load(u64, addr) != null,
482 else => return error.InvalidExpression,
483 }) return error.InvalidExpression;
484 }
485
477 const value: addr_type = std.math.cast(addr_type, @as(u64, switch (size) {486 const value: addr_type = std.math.cast(addr_type, @as(u64, switch (size) {
478 1 => @as(*const u8, @ptrFromInt(addr)).*,487 1 => @as(*const u8, @ptrFromInt(addr)).*,
479 2 => @as(*const u16, @ptrFromInt(addr)).*,488 2 => @as(*const u16, @ptrFromInt(addr)).*,