| ... | ... | @@ -33,7 +33,7 @@ pub const ExpressionOptions = struct { |
| 33 | 33 | endian: std.builtin.Endian = .Little, |
| 34 | 34 | |
| 35 | 35 | /// 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 | }; |
| 38 | 38 | |
| 39 | 39 | /// A stack machine that can decode and run DWARF expressions. |
| ... | ... | @@ -111,13 +111,15 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 111 | 111 | // TODO: For these two prongs, look up the type and assert it's integral? |
| 112 | 112 | .regval_type => |regval_type| regval_type.value, |
| 113 | 113 | .const_type => |const_type| { |
| 114 | | return switch (const_type.value_bytes.len) { |
| 114 | const value: u64 = switch (const_type.value_bytes.len) { |
| 115 | 115 | 1 => mem.readIntSliceNative(u8, const_type.value_bytes), |
| 116 | 116 | 2 => mem.readIntSliceNative(u16, const_type.value_bytes), |
| 117 | 117 | 4 => mem.readIntSliceNative(u32, const_type.value_bytes), |
| 118 | 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 | 280 | @compileError("Execution of non-native address sizees / endianness is not supported"); |
| 279 | 281 | |
| 280 | 282 | const opcode = try stream.reader().readByte(); |
| 281 | | if (options.call_frame_mode) { |
| 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 | | |
| 283 | if (options.call_frame_context and !opcodeValidInCFA(opcode)) return error.InvalidCFAOpcode; |
| 301 | 284 | switch (opcode) { |
| 302 | 285 | |
| 303 | 286 | // 2.5.1.1: Literal Encodings |
| ... | ... | @@ -420,7 +403,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 420 | 403 | OP.xderef_type, |
| 421 | 404 | => { |
| 422 | 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 | 407 | const addr_space_identifier: ?usize = switch (opcode) { |
| 425 | 408 | OP.xderef, |
| 426 | 409 | OP.xderef_size, |
| ... | ... | @@ -447,24 +430,24 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 447 | 430 | else => unreachable, |
| 448 | 431 | }; |
| 449 | 432 | |
| 450 | | const value: u64 = switch (size) { |
| 433 | const value: addr_type = std.math.cast(addr_type, @as(u64, switch (size) { |
| 451 | 434 | 1 => @as(*const u8, @ptrFromInt(addr)).*, |
| 452 | 435 | 2 => @as(*const u16, @ptrFromInt(addr)).*, |
| 453 | 436 | 4 => @as(*const u32, @ptrFromInt(addr)).*, |
| 454 | 437 | 8 => @as(*const u64, @ptrFromInt(addr)).*, |
| 455 | 438 | else => return error.InvalidExpression, |
| 456 | | }; |
| 439 | })) orelse return error.InvalidExpression; |
| 457 | 440 | |
| 458 | 441 | if (opcode == OP.deref_type) { |
| 459 | | try self.stack.append(allocator, .{ |
| 442 | self.stack.items[self.stack.items.len - 1] = .{ |
| 460 | 443 | .regval_type = .{ |
| 461 | 444 | .type_offset = operand.?.deref_type.type_offset, |
| 462 | 445 | .type_size = operand.?.deref_type.size, |
| 463 | 446 | .value = value, |
| 464 | 447 | }, |
| 465 | | }); |
| 448 | }; |
| 466 | 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 | 453 | OP.push_object_address, |
| ... | ... | @@ -738,6 +721,7 @@ pub fn Writer(options: ExpressionOptions) type { |
| 738 | 721 | return struct { |
| 739 | 722 | /// Zero-operand instructions |
| 740 | 723 | pub fn writeOpcode(writer: anytype, comptime opcode: u8) !void { |
| 724 | if (options.call_frame_context and !comptime opcodeValidInCFA(opcode)) return error.InvalidCFAOpcode; |
| 741 | 725 | switch (opcode) { |
| 742 | 726 | OP.dup, |
| 743 | 727 | OP.drop, |
| ... | ... | @@ -820,6 +804,7 @@ pub fn Writer(options: ExpressionOptions) type { |
| 820 | 804 | } |
| 821 | 805 | |
| 822 | 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 | 808 | if (size != value_bytes.len) return error.InvalidValueSize; |
| 824 | 809 | try writer.writeByte(OP.const_type); |
| 825 | 810 | try leb.writeULEB128(writer, die_offset); |
| ... | ... | @@ -833,6 +818,7 @@ pub fn Writer(options: ExpressionOptions) type { |
| 833 | 818 | } |
| 834 | 819 | |
| 835 | 820 | pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void { |
| 821 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 836 | 822 | try writer.writeByte(OP.addrx); |
| 837 | 823 | try leb.writeULEB128(writer, debug_addr_offset); |
| 838 | 824 | } |
| ... | ... | @@ -856,6 +842,7 @@ pub fn Writer(options: ExpressionOptions) type { |
| 856 | 842 | } |
| 857 | 843 | |
| 858 | 844 | pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void { |
| 845 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 859 | 846 | try writer.writeByte(OP.bregx); |
| 860 | 847 | try leb.writeULEB128(writer, register); |
| 861 | 848 | try leb.writeULEB128(writer, offset); |
| ... | ... | @@ -878,6 +865,7 @@ pub fn Writer(options: ExpressionOptions) type { |
| 878 | 865 | } |
| 879 | 866 | |
| 880 | 867 | pub fn writeDerefType(writer: anytype, size: u8, die_offset: anytype) !void { |
| 868 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 881 | 869 | try writer.writeByte(OP.deref_type); |
| 882 | 870 | try writer.writeByte(size); |
| 883 | 871 | try leb.writeULEB128(writer, die_offset); |
| ... | ... | @@ -909,6 +897,7 @@ pub fn Writer(options: ExpressionOptions) type { |
| 909 | 897 | } |
| 910 | 898 | |
| 911 | 899 | pub fn writeCall(writer: anytype, comptime T: type, offset: T) !void { |
| 900 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 912 | 901 | switch (T) { |
| 913 | 902 | u16 => try writer.writeByte(OP.call2), |
| 914 | 903 | u32 => try writer.writeByte(OP.call4), |
| ... | ... | @@ -919,16 +908,19 @@ pub fn Writer(options: ExpressionOptions) type { |
| 919 | 908 | } |
| 920 | 909 | |
| 921 | 910 | pub fn writeCallRef(writer: anytype, debug_info_offset: addr_type) !void { |
| 911 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 922 | 912 | try writer.writeByte(OP.call_ref); |
| 923 | 913 | try writer.writeInt(addr_type, debug_info_offset, options.endian); |
| 924 | 914 | } |
| 925 | 915 | |
| 926 | 916 | pub fn writeConvert(writer: anytype, die_offset: anytype) !void { |
| 917 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 927 | 918 | try writer.writeByte(OP.convert); |
| 928 | 919 | try leb.writeULEB128(writer, die_offset); |
| 929 | 920 | } |
| 930 | 921 | |
| 931 | 922 | pub fn writeReinterpret(writer: anytype, die_offset: anytype) !void { |
| 923 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 932 | 924 | try writer.writeByte(OP.reinterpret); |
| 933 | 925 | try leb.writeULEB128(writer, die_offset); |
| 934 | 926 | } |
| ... | ... | @@ -942,12 +934,31 @@ pub fn Writer(options: ExpressionOptions) type { |
| 942 | 934 | } |
| 943 | 935 | |
| 944 | 936 | // 2.6: Location Descriptions |
| 945 | | |
| 946 | 937 | // TODO |
| 947 | 938 | |
| 948 | 939 | }; |
| 949 | 940 | } |
| 950 | 941 | |
| 942 | // Certain opcodes are not allowed in a CFA context, see 6.4.2 |
| 943 | fn 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 | |
| 951 | 962 | test "DWARF expressions" { |
| 952 | 963 | const allocator = std.testing.allocator; |
| 953 | 964 | |