authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-06 20:04:33-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:15-04:00
log8547c42ba542f77c55ce50253446fd2bf4f3592b
treee8d03a2cdbea5fbefe21bdda9dc6d16dd189d64e
parent424b1299a88b4ac3ae50128118ed510a79c3ab4b

dwarf: expression fixups for non-64bit arches, check call_frame_context when writing expressions


2 files changed, 42 insertions(+), 31 deletions(-)

lib/std/dwarf.zig+1-1
...@@ -1783,7 +1783,7 @@ pub const UnwindContext = struct {...@@ -1783,7 +1783,7 @@ pub const UnwindContext = struct {
1783 reg_ctx: abi.RegisterContext,1783 reg_ctx: abi.RegisterContext,
1784 isValidMemory: *const fn (address: usize) bool,1784 isValidMemory: *const fn (address: usize) bool,
1785 vm: call_frame.VirtualMachine = .{},1785 vm: call_frame.VirtualMachine = .{},
1786 stack_machine: expressions.StackMachine(.{ .call_frame_mode = true }) = .{},1786 stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{},
17871787
1788 pub fn init(allocator: mem.Allocator, ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext {1788 pub fn init(allocator: mem.Allocator, ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
1789 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));1789 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));
lib/std/dwarf/expressions.zig+41-30
...@@ -33,7 +33,7 @@ pub const ExpressionOptions = struct {...@@ -33,7 +33,7 @@ pub const ExpressionOptions = struct {
33 endian: std.builtin.Endian = .Little,33 endian: std.builtin.Endian = .Little,
3434
35 /// Restrict the stack machine to a subset of opcodes used in call frame instructions35 /// Restrict the stack machine to a subset of opcodes used in call frame instructions
36 call_frame_mode: bool = false,36 call_frame_context: bool = false,
37};37};
3838
39/// A stack machine that can decode and run DWARF expressions.39/// A stack machine that can decode and run DWARF expressions.
...@@ -111,13 +111,15 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -111,13 +111,15 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
111 // TODO: For these two prongs, look up the type and assert it's integral?111 // TODO: For these two prongs, look up the type and assert it's integral?
112 .regval_type => |regval_type| regval_type.value,112 .regval_type => |regval_type| regval_type.value,
113 .const_type => |const_type| {113 .const_type => |const_type| {
114 return switch (const_type.value_bytes.len) {114 const value: u64 = switch (const_type.value_bytes.len) {
115 1 => mem.readIntSliceNative(u8, const_type.value_bytes),115 1 => mem.readIntSliceNative(u8, const_type.value_bytes),
116 2 => mem.readIntSliceNative(u16, const_type.value_bytes),116 2 => mem.readIntSliceNative(u16, const_type.value_bytes),
117 4 => mem.readIntSliceNative(u32, const_type.value_bytes),117 4 => mem.readIntSliceNative(u32, const_type.value_bytes),
118 8 => mem.readIntSliceNative(u64, const_type.value_bytes),118 8 => mem.readIntSliceNative(u64, const_type.value_bytes),
119 else => error.InvalidIntegralTypeLength,119 else => return error.InvalidIntegralTypeSize,
120 };120 };
121
122 return std.math.cast(addr_type, value) orelse error.TruncatedIntegralType;
121 },123 },
122 };124 };
123 }125 }
...@@ -278,26 +280,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -278,26 +280,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
278 @compileError("Execution of non-native address sizees / endianness is not supported");280 @compileError("Execution of non-native address sizees / endianness is not supported");
279281
280 const opcode = try stream.reader().readByte();282 const opcode = try stream.reader().readByte();
281 if (options.call_frame_mode) {283 if (options.call_frame_context and !opcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
282 // Certain opcodes are not allowed in a CFA context, see 6.4.2
283 switch (opcode) {
284 OP.addrx,
285 OP.call2,
286 OP.call4,
287 OP.call_ref,
288 OP.const_type,
289 OP.constx,
290 OP.convert,
291 OP.deref_type,
292 OP.regval_type,
293 OP.reinterpret,
294 OP.push_object_address,
295 OP.call_frame_cfa,
296 => return error.InvalidCFAExpression,
297 else => {},
298 }
299 }
300
301 switch (opcode) {284 switch (opcode) {
302285
303 // 2.5.1.1: Literal Encodings286 // 2.5.1.1: Literal Encodings
...@@ -420,7 +403,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -420,7 +403,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
420 OP.xderef_type,403 OP.xderef_type,
421 => {404 => {
422 if (self.stack.items.len == 0) return error.InvalidExpression;405 if (self.stack.items.len == 0) return error.InvalidExpression;
423 var addr = try self.stack.pop().asIntegral();406 var addr = try self.stack.items[self.stack.items.len - 1].asIntegral();
424 const addr_space_identifier: ?usize = switch (opcode) {407 const addr_space_identifier: ?usize = switch (opcode) {
425 OP.xderef,408 OP.xderef,
426 OP.xderef_size,409 OP.xderef_size,
...@@ -447,24 +430,24 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -447,24 +430,24 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
447 else => unreachable,430 else => unreachable,
448 };431 };
449432
450 const value: u64 = switch (size) {433 const value: addr_type = std.math.cast(addr_type, @as(u64, switch (size) {
451 1 => @as(*const u8, @ptrFromInt(addr)).*,434 1 => @as(*const u8, @ptrFromInt(addr)).*,
452 2 => @as(*const u16, @ptrFromInt(addr)).*,435 2 => @as(*const u16, @ptrFromInt(addr)).*,
453 4 => @as(*const u32, @ptrFromInt(addr)).*,436 4 => @as(*const u32, @ptrFromInt(addr)).*,
454 8 => @as(*const u64, @ptrFromInt(addr)).*,437 8 => @as(*const u64, @ptrFromInt(addr)).*,
455 else => return error.InvalidExpression,438 else => return error.InvalidExpression,
456 };439 })) orelse return error.InvalidExpression;
457440
458 if (opcode == OP.deref_type) {441 if (opcode == OP.deref_type) {
459 try self.stack.append(allocator, .{442 self.stack.items[self.stack.items.len - 1] = .{
460 .regval_type = .{443 .regval_type = .{
461 .type_offset = operand.?.deref_type.type_offset,444 .type_offset = operand.?.deref_type.type_offset,
462 .type_size = operand.?.deref_type.size,445 .type_size = operand.?.deref_type.size,
463 .value = value,446 .value = value,
464 },447 },
465 });448 };
466 } else {449 } else {
467 try self.stack.append(allocator, .{ .generic = value });450 self.stack.items[self.stack.items.len - 1] = .{ .generic = value };
468 }451 }
469 },452 },
470 OP.push_object_address,453 OP.push_object_address,
...@@ -738,6 +721,7 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -738,6 +721,7 @@ pub fn Writer(options: ExpressionOptions) type {
738 return struct {721 return struct {
739 /// Zero-operand instructions722 /// Zero-operand instructions
740 pub fn writeOpcode(writer: anytype, comptime opcode: u8) !void {723 pub fn writeOpcode(writer: anytype, comptime opcode: u8) !void {
724 if (options.call_frame_context and !comptime opcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
741 switch (opcode) {725 switch (opcode) {
742 OP.dup,726 OP.dup,
743 OP.drop,727 OP.drop,
...@@ -820,6 +804,7 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -820,6 +804,7 @@ pub fn Writer(options: ExpressionOptions) type {
820 }804 }
821805
822 pub fn writeConstType(writer: anytype, die_offset: anytype, size: u8, value_bytes: []const u8) !void {806 pub fn writeConstType(writer: anytype, die_offset: anytype, size: u8, value_bytes: []const u8) !void {
807 if (options.call_frame_context) return error.InvalidCFAOpcode;
823 if (size != value_bytes.len) return error.InvalidValueSize;808 if (size != value_bytes.len) return error.InvalidValueSize;
824 try writer.writeByte(OP.const_type);809 try writer.writeByte(OP.const_type);
825 try leb.writeULEB128(writer, die_offset);810 try leb.writeULEB128(writer, die_offset);
...@@ -833,6 +818,7 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -833,6 +818,7 @@ pub fn Writer(options: ExpressionOptions) type {
833 }818 }
834819
835 pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {820 pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {
821 if (options.call_frame_context) return error.InvalidCFAOpcode;
836 try writer.writeByte(OP.addrx);822 try writer.writeByte(OP.addrx);
837 try leb.writeULEB128(writer, debug_addr_offset);823 try leb.writeULEB128(writer, debug_addr_offset);
838 }824 }
...@@ -856,6 +842,7 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -856,6 +842,7 @@ pub fn Writer(options: ExpressionOptions) type {
856 }842 }
857843
858 pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void {844 pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void {
845 if (options.call_frame_context) return error.InvalidCFAOpcode;
859 try writer.writeByte(OP.bregx);846 try writer.writeByte(OP.bregx);
860 try leb.writeULEB128(writer, register);847 try leb.writeULEB128(writer, register);
861 try leb.writeULEB128(writer, offset);848 try leb.writeULEB128(writer, offset);
...@@ -878,6 +865,7 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -878,6 +865,7 @@ pub fn Writer(options: ExpressionOptions) type {
878 }865 }
879866
880 pub fn writeDerefType(writer: anytype, size: u8, die_offset: anytype) !void {867 pub fn writeDerefType(writer: anytype, size: u8, die_offset: anytype) !void {
868 if (options.call_frame_context) return error.InvalidCFAOpcode;
881 try writer.writeByte(OP.deref_type);869 try writer.writeByte(OP.deref_type);
882 try writer.writeByte(size);870 try writer.writeByte(size);
883 try leb.writeULEB128(writer, die_offset);871 try leb.writeULEB128(writer, die_offset);
...@@ -909,6 +897,7 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -909,6 +897,7 @@ pub fn Writer(options: ExpressionOptions) type {
909 }897 }
910898
911 pub fn writeCall(writer: anytype, comptime T: type, offset: T) !void {899 pub fn writeCall(writer: anytype, comptime T: type, offset: T) !void {
900 if (options.call_frame_context) return error.InvalidCFAOpcode;
912 switch (T) {901 switch (T) {
913 u16 => try writer.writeByte(OP.call2),902 u16 => try writer.writeByte(OP.call2),
914 u32 => try writer.writeByte(OP.call4),903 u32 => try writer.writeByte(OP.call4),
...@@ -919,16 +908,19 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -919,16 +908,19 @@ pub fn Writer(options: ExpressionOptions) type {
919 }908 }
920909
921 pub fn writeCallRef(writer: anytype, debug_info_offset: addr_type) !void {910 pub fn writeCallRef(writer: anytype, debug_info_offset: addr_type) !void {
911 if (options.call_frame_context) return error.InvalidCFAOpcode;
922 try writer.writeByte(OP.call_ref);912 try writer.writeByte(OP.call_ref);
923 try writer.writeInt(addr_type, debug_info_offset, options.endian);913 try writer.writeInt(addr_type, debug_info_offset, options.endian);
924 }914 }
925915
926 pub fn writeConvert(writer: anytype, die_offset: anytype) !void {916 pub fn writeConvert(writer: anytype, die_offset: anytype) !void {
917 if (options.call_frame_context) return error.InvalidCFAOpcode;
927 try writer.writeByte(OP.convert);918 try writer.writeByte(OP.convert);
928 try leb.writeULEB128(writer, die_offset);919 try leb.writeULEB128(writer, die_offset);
929 }920 }
930921
931 pub fn writeReinterpret(writer: anytype, die_offset: anytype) !void {922 pub fn writeReinterpret(writer: anytype, die_offset: anytype) !void {
923 if (options.call_frame_context) return error.InvalidCFAOpcode;
932 try writer.writeByte(OP.reinterpret);924 try writer.writeByte(OP.reinterpret);
933 try leb.writeULEB128(writer, die_offset);925 try leb.writeULEB128(writer, die_offset);
934 }926 }
...@@ -942,12 +934,31 @@ pub fn Writer(options: ExpressionOptions) type {...@@ -942,12 +934,31 @@ pub fn Writer(options: ExpressionOptions) type {
942 }934 }
943935
944 // 2.6: Location Descriptions936 // 2.6: Location Descriptions
945
946 // TODO937 // TODO
947938
948 };939 };
949}940}
950941
942// Certain opcodes are not allowed in a CFA context, see 6.4.2
943fn opcodeValidInCFA(opcode: u8) bool {
944 return switch (opcode) {
945 OP.addrx,
946 OP.call2,
947 OP.call4,
948 OP.call_ref,
949 OP.const_type,
950 OP.constx,
951 OP.convert,
952 OP.deref_type,
953 OP.regval_type,
954 OP.reinterpret,
955 OP.push_object_address,
956 OP.call_frame_cfa,
957 => false,
958 else => true,
959 };
960}
961
951test "DWARF expressions" {962test "DWARF expressions" {
952 const allocator = std.testing.allocator;963 const allocator = std.testing.allocator;
953964