authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-07 01:03:43-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:15-04:00
log463bbe7807b236e6e3493fb8551c585620ae266b
treedc7e5fb016674a83ae21fe7d5800858f769b9233
parent5f72c6508d78291d8f0358d06d407a8d6b4a28c9

dwarf: implement constx,addrx, begin adding DWARF expression tests


1 files changed, 114 insertions(+), 28 deletions(-)

lib/std/dwarf/expressions.zig+114-28
...@@ -17,6 +17,9 @@ pub const ExpressionContext = struct {...@@ -17,6 +17,9 @@ pub const ExpressionContext = struct {
17 /// The compilation unit this expression relates to, if any17 /// The compilation unit this expression relates to, if any
18 compile_unit: ?*const dwarf.CompileUnit = null,18 compile_unit: ?*const dwarf.CompileUnit = null,
1919
20 // .debug_addr section
21 debug_addr: ?[]const u8 = null,
22
20 /// Thread context23 /// Thread context
21 thread_context: ?*std.debug.ThreadContext = null,24 thread_context: ?*std.debug.ThreadContext = null,
22 reg_context: ?abi.RegisterContext = null,25 reg_context: ?abi.RegisterContext = null,
...@@ -73,15 +76,15 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -73,15 +76,15 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
73 block: []const u8,76 block: []const u8,
74 register_type: struct {77 register_type: struct {
75 register: u8,78 register: u8,
76 type_offset: u64,79 type_offset: addr_type,
77 },80 },
78 const_type: struct {81 const_type: struct {
79 type_offset: u64,82 type_offset: addr_type,
80 value_bytes: []const u8,83 value_bytes: []const u8,
81 },84 },
82 deref_type: struct {85 deref_type: struct {
83 size: u8,86 size: u8,
84 type_offset: u64,87 type_offset: addr_type,
85 },88 },
86 };89 };
8790
...@@ -91,7 +94,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -91,7 +94,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
91 // Typed value with a maximum size of a register94 // Typed value with a maximum size of a register
92 regval_type: struct {95 regval_type: struct {
93 // Offset of DW_TAG_base_type DIE96 // Offset of DW_TAG_base_type DIE
94 type_offset: u64,97 type_offset: addr_type,
95 type_size: u8,98 type_size: u8,
96 value: addr_type,99 value: addr_type,
97 },100 },
...@@ -99,7 +102,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -99,7 +102,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
99 // Typed value specified directly in the instruction stream102 // Typed value specified directly in the instruction stream
100 const_type: struct {103 const_type: struct {
101 // Offset of DW_TAG_base_type DIE104 // Offset of DW_TAG_base_type DIE
102 type_offset: u64,105 type_offset: addr_type,
103 // Backed by the instruction stream106 // Backed by the instruction stream
104 value_bytes: []const u8,107 value_bytes: []const u8,
105 },108 },
...@@ -202,7 +205,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -202,7 +205,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
202 },205 },
203 OP.regval_type => blk: {206 OP.regval_type => blk: {
204 const register = try leb.readULEB128(u8, reader);207 const register = try leb.readULEB128(u8, reader);
205 const type_offset = try leb.readULEB128(u64, reader);208 const type_offset = try leb.readULEB128(addr_type, reader);
206 break :blk .{ .register_type = .{209 break :blk .{ .register_type = .{
207 .register = register,210 .register = register,
208 .type_offset = type_offset,211 .type_offset = type_offset,
...@@ -232,7 +235,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -232,7 +235,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
232 };235 };
233 },236 },
234 OP.const_type => blk: {237 OP.const_type => blk: {
235 const type_offset = try leb.readULEB128(u8, reader);238 const type_offset = try leb.readULEB128(addr_type, reader);
236 const size = try reader.readByte();239 const size = try reader.readByte();
237 if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;240 if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
238 const value_bytes = stream.buffer[stream.pos..][0..size];241 const value_bytes = stream.buffer[stream.pos..][0..size];
...@@ -247,7 +250,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -247,7 +250,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
247 => .{250 => .{
248 .deref_type = .{251 .deref_type = .{
249 .size = try reader.readByte(),252 .size = try reader.readByte(),
250 .type_offset = try leb.readULEB128(u64, reader),253 .type_offset = try leb.readULEB128(addr_type, reader),
251 },254 },
252 },255 },
253 OP.lo_user...OP.hi_user => return error.UnimplementedUserOpcode,256 OP.lo_user...OP.hi_user => return error.UnimplementedUserOpcode,
...@@ -277,7 +280,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -277,7 +280,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
277 context: ExpressionContext,280 context: ExpressionContext,
278 ) !bool {281 ) !bool {
279 if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != comptime builtin.target.cpu.arch.endian())282 if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != comptime builtin.target.cpu.arch.endian())
280 @compileError("Execution of non-native address sizees / endianness is not supported");283 @compileError("Execution of non-native address sizes / endianness is not supported");
281284
282 const opcode = try stream.reader().readByte();285 const opcode = try stream.reader().readByte();
283 if (options.call_frame_context and !opcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;286 if (options.call_frame_context and !opcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
...@@ -309,12 +312,13 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -309,12 +312,13 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
309 OP.addrx,312 OP.addrx,
310 OP.constx,313 OP.constx,
311 => {314 => {
315 if (context.compile_unit == null) return error.ExpressionRequiresCompileUnit;
316 if (context.debug_addr == null) return error.ExpressionRequiresDebugAddr;
312 const debug_addr_index = (try readOperand(stream, opcode)).?.generic;317 const debug_addr_index = (try readOperand(stream, opcode)).?.generic;
313318 const offset = context.compile_unit.?.addr_base + debug_addr_index;
314 // TODO: Read item from .debug_addr, this requires need DW_AT_addr_base of the compile unit, push onto stack as generic319 if (offset >= context.debug_addr.?.len) return error.InvalidExpression;
315320 const value = mem.readIntSliceNative(usize, context.debug_addr.?[offset..][0..@sizeOf(usize)]);
316 _ = debug_addr_index;321 try self.stack.append(allocator, .{ .generic = value });
317 unreachable;
318 },322 },
319323
320 // 2.5.1.2: Register Values324 // 2.5.1.2: Register Values
...@@ -464,7 +468,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -464,7 +468,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
464 // 2.5.1.4: Arithmetic and Logical Operations468 // 2.5.1.4: Arithmetic and Logical Operations
465 OP.abs => {469 OP.abs => {
466 if (self.stack.items.len == 0) return error.InvalidExpression;470 if (self.stack.items.len == 0) return error.InvalidExpression;
467 const value: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());471 const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
468 self.stack.items[self.stack.items.len - 1] = .{472 self.stack.items[self.stack.items.len - 1] = .{
469 .generic = std.math.absCast(value),473 .generic = std.math.absCast(value),
470 };474 };
...@@ -478,10 +482,10 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -478,10 +482,10 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
478 },482 },
479 OP.div => {483 OP.div => {
480 if (self.stack.items.len < 2) return error.InvalidExpression;484 if (self.stack.items.len < 2) return error.InvalidExpression;
481 const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral());485 const a: isize = @bitCast(try self.stack.pop().asIntegral());
482 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());486 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
483 self.stack.items[self.stack.items.len - 1] = .{487 self.stack.items[self.stack.items.len - 1] = .{
484 .generic = @bitCast(try std.math.divTrunc(addr_type_signed, b, a)),488 .generic = @bitCast(try std.math.divTrunc(isize, b, a)),
485 };489 };
486 },490 },
487 OP.minus => {491 OP.minus => {
...@@ -493,16 +497,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -493,16 +497,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
493 },497 },
494 OP.mod => {498 OP.mod => {
495 if (self.stack.items.len < 2) return error.InvalidExpression;499 if (self.stack.items.len < 2) return error.InvalidExpression;
496 const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral());500 const a: isize = @bitCast(try self.stack.pop().asIntegral());
497 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());501 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
498 self.stack.items[self.stack.items.len - 1] = .{502 self.stack.items[self.stack.items.len - 1] = .{
499 .generic = @bitCast(@mod(b, a)),503 .generic = @bitCast(@mod(b, a)),
500 };504 };
501 },505 },
502 OP.mul => {506 OP.mul => {
503 if (self.stack.items.len < 2) return error.InvalidExpression;507 if (self.stack.items.len < 2) return error.InvalidExpression;
504 const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral());508 const a: isize = @bitCast(try self.stack.pop().asIntegral());
505 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());509 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
506 self.stack.items[self.stack.items.len - 1] = .{510 self.stack.items[self.stack.items.len - 1] = .{
507 .generic = @bitCast(@mulWithOverflow(a, b)[0]),511 .generic = @bitCast(@mulWithOverflow(a, b)[0]),
508 };512 };
...@@ -512,7 +516,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -512,7 +516,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
512 self.stack.items[self.stack.items.len - 1] = .{516 self.stack.items[self.stack.items.len - 1] = .{
513 .generic = @bitCast(517 .generic = @bitCast(
514 try std.math.negate(518 try std.math.negate(
515 @as(addr_type_signed, @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral())),519 @as(isize, @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral())),
516 ),520 ),
517 ),521 ),
518 };522 };
...@@ -563,9 +567,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -563,9 +567,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
563 OP.shra => {567 OP.shra => {
564 if (self.stack.items.len < 2) return error.InvalidExpression;568 if (self.stack.items.len < 2) return error.InvalidExpression;
565 const a = try self.stack.pop().asIntegral();569 const a = try self.stack.pop().asIntegral();
566 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());570 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
567 self.stack.items[self.stack.items.len - 1] = .{571 self.stack.items[self.stack.items.len - 1] = .{
568 .generic = @bitCast(std.math.shr(addr_type_signed, b, a)),572 .generic = @bitCast(std.math.shr(isize, b, a)),
569 };573 };
570 },574 },
571 OP.xor => {575 OP.xor => {
...@@ -589,8 +593,8 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -589,8 +593,8 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
589 const b = self.stack.items[self.stack.items.len - 1];593 const b = self.stack.items[self.stack.items.len - 1];
590594
591 if (a == .generic and b == .generic) {595 if (a == .generic and b == .generic) {
592 const a_int: addr_type_signed = @bitCast(a.asIntegral() catch unreachable);596 const a_int: isize = @bitCast(a.asIntegral() catch unreachable);
593 const b_int: addr_type_signed = @bitCast(b.asIntegral() catch unreachable);597 const b_int: isize = @bitCast(b.asIntegral() catch unreachable);
594 const result = @intFromBool(switch (opcode) {598 const result = @intFromBool(switch (opcode) {
595 OP.le => b_int < a_int,599 OP.le => b_int < a_int,
596 OP.ge => b_int >= a_int,600 OP.ge => b_int >= a_int,
...@@ -617,7 +621,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -617,7 +621,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
617 if (condition) {621 if (condition) {
618 const new_pos = std.math.cast(622 const new_pos = std.math.cast(
619 usize,623 usize,
620 try std.math.add(addr_type_signed, @as(addr_type_signed, @intCast(stream.pos)), branch_offset),624 try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset),
621 ) orelse return error.InvalidExpression;625 ) orelse return error.InvalidExpression;
622626
623 if (new_pos < 0 or new_pos >= stream.buffer.len) return error.InvalidExpression;627 if (new_pos < 0 or new_pos >= stream.buffer.len) return error.InvalidExpression;
...@@ -781,6 +785,7 @@ pub fn Builder(comptime options: ExpressionOptions) type {...@@ -781,6 +785,7 @@ pub fn Builder(comptime options: ExpressionOptions) type {
781 i32 => OP.const4s,785 i32 => OP.const4s,
782 u64 => OP.const8u,786 u64 => OP.const8u,
783 i64 => OP.const8s,787 i64 => OP.const8s,
788 else => unreachable,
784 });789 });
785790
786 try writer.writeInt(T, value, options.endian);791 try writer.writeInt(T, value, options.endian);
...@@ -988,4 +993,85 @@ test "DWARF expressions" {...@@ -988,4 +993,85 @@ test "DWARF expressions" {
988 try testing.expectEqual(expected, stack_machine.stack.popOrNull().?.generic);993 try testing.expectEqual(expected, stack_machine.stack.popOrNull().?.generic);
989 }994 }
990 }995 }
996
997 // Constants
998 {
999 program.clearRetainingCapacity();
1000
1001 const expected = [_]comptime_int{
1002 1,
1003 -1,
1004 0x0fff,
1005 -0x0fff,
1006 0x0fffffff,
1007 -0x0fffffff,
1008 0x0fffffffffffffff,
1009 -0x0fffffffffffffff,
1010 0x8000000,
1011 -0x8000000,
1012 @as(usize, @truncate(0x12345678_12345678)),
1013 @as(usize, @truncate(0xffffffff_ffffffff)),
1014 @as(usize, @truncate(0xeeeeeeee_eeeeeeee)),
1015 };
1016
1017 try b.writeConst(writer, u8, expected[0]);
1018 try b.writeConst(writer, i8, expected[1]);
1019 try b.writeConst(writer, u16, expected[2]);
1020 try b.writeConst(writer, i16, expected[3]);
1021 try b.writeConst(writer, u32, expected[4]);
1022 try b.writeConst(writer, i32, expected[5]);
1023 try b.writeConst(writer, u64, expected[6]);
1024 try b.writeConst(writer, i64, expected[7]);
1025 try b.writeConst(writer, u28, expected[8]);
1026 try b.writeConst(writer, i28, expected[9]);
1027 try b.writeAddr(writer, expected[10]);
1028
1029 var mock_compile_unit: dwarf.CompileUnit = undefined;
1030 mock_compile_unit.addr_base = 1;
1031
1032 var mock_debug_addr = std.ArrayList(u8).init(allocator);
1033 defer mock_debug_addr.deinit();
1034
1035 try mock_debug_addr.writer().writeIntNative(u16, 0);
1036 try mock_debug_addr.writer().writeIntNative(usize, expected[11]);
1037 try mock_debug_addr.writer().writeIntNative(usize, expected[12]);
1038
1039 const context = ExpressionContext{
1040 .compile_unit = &mock_compile_unit,
1041 .debug_addr = mock_debug_addr.items,
1042 };
1043
1044 try b.writeConstx(writer, @as(usize, 1));
1045 try b.writeAddrx(writer, @as(usize, 1 + @sizeOf(usize)));
1046
1047 const die_offset: usize = @truncate(0xaabbccdd);
1048 const type_bytes: []const u8 = &.{ 1, 2, 3, 4 };
1049 try b.writeConstType(writer, die_offset, type_bytes.len, type_bytes);
1050
1051 _ = try stack_machine.run(program.items, allocator, context, 0);
1052
1053 const const_type = stack_machine.stack.popOrNull().?.const_type;
1054 try testing.expectEqual(die_offset, const_type.type_offset);
1055 try testing.expectEqualSlices(u8, type_bytes, const_type.value_bytes);
1056
1057 try testing.expectEqual(@as(usize, expected[12]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1058 try testing.expectEqual(@as(usize, expected[11]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1059 try testing.expectEqual(@as(usize, expected[10]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1060 try testing.expectEqual(@as(isize, @truncate(expected[9])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1061 try testing.expectEqual(@as(usize, @truncate(expected[8])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1062 try testing.expectEqual(@as(isize, @truncate(expected[7])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1063 try testing.expectEqual(@as(usize, @truncate(expected[6])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1064 try testing.expectEqual(@as(isize, @truncate(expected[5])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1065 try testing.expectEqual(@as(usize, @truncate(expected[4])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1066 try testing.expectEqual(@as(isize, @truncate(expected[3])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1067 try testing.expectEqual(@as(usize, @truncate(expected[2])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1068 try testing.expectEqual(@as(isize, @truncate(expected[1])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1069 try testing.expectEqual(@as(usize, @truncate(expected[0])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic)));
1070 }
1071
1072 // Register values
1073 var thread_context: std.debug.ThreadContext = undefined;
1074 if (std.debug.getContext(&thread_context)) {
1075 // TODO: Test fbreg, breg0..31, bregx, regval_type
1076 }
991}1077}