dwarf: fixup default endianness in ExpressionOptions, add control flow tests

This commit is contained in:
kcbanner
2023-07-08 00:20:37 -04:00
parent 54ca62fef4
commit 021f537863

View File

@@ -33,7 +33,7 @@ pub const ExpressionOptions = struct {
addr_size: u8 = @sizeOf(usize),
/// Endianess of the target architecture
endian: std.builtin.Endian = .Little,
endian: std.builtin.Endian = builtin.target.cpu.arch.endian(),
/// Restrict the stack machine to a subset of opcodes used in call frame instructions
call_frame_context: bool = false,
@@ -272,7 +272,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
return self.stack.items[self.stack.items.len - 1];
}
/// Reads an opcode and its operands from the stream and executes it
/// Reads an opcode and its operands from `stream`, then executes it
pub fn step(
self: *Self,
stream: *std.io.FixedBufferStream([]const u8),
@@ -607,7 +607,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
const a_int: isize = @bitCast(a.asIntegral() catch unreachable);
const b_int: isize = @bitCast(b.asIntegral() catch unreachable);
const result = @intFromBool(switch (opcode) {
OP.le => b_int < a_int,
OP.le => b_int <= a_int,
OP.ge => b_int >= a_int,
OP.eq => b_int == a_int,
OP.lt => b_int < a_int,
@@ -635,7 +635,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset),
) orelse return error.InvalidExpression;
if (new_pos < 0 or new_pos >= stream.buffer.len) return error.InvalidExpression;
if (new_pos < 0 or new_pos > stream.buffer.len) return error.InvalidExpression;
stream.pos = new_pos;
}
},
@@ -657,12 +657,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
OP.convert => {
if (self.stack.items.len == 0) return error.InvalidExpression;
const type_offset = (try readOperand(stream, opcode)).?.generic;
_ = type_offset;
// TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator
// from the old type to the new type, run it.
return error.UnimplementedTypeConversion;
// TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size
const value = self.stack.items[self.stack.items.len - 1];
if (type_offset == 0) {
self.stack.items[self.stack.items.len - 1] = .{ .generic = try value.asIntegral() };
} else {
// TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator
// from the old type to the new type, run it.
return error.UnimplementedTypeConversion;
}
},
OP.reinterpret => {
if (self.stack.items.len == 0) return error.InvalidExpression;
@@ -1373,4 +1377,66 @@ test "DWARF expressions" {
_ = try stack_machine.run(program.items, allocator, context, null);
try testing.expectEqual(@as(usize, 0x0ff0), stack_machine.stack.popOrNull().?.generic);
}
// Control Flow Operations
{
var context = ExpressionContext{};
const expected = .{
.{ OP.le, 1, 1, 0 },
.{ OP.ge, 1, 0, 1 },
.{ OP.eq, 1, 0, 0 },
.{ OP.lt, 0, 1, 0 },
.{ OP.gt, 0, 0, 1 },
.{ OP.ne, 0, 1, 1 },
};
inline for (expected) |e| {
stack_machine.reset();
program.clearRetainingCapacity();
try b.writeConst(writer, u16, 0);
try b.writeConst(writer, u16, 0);
try b.writeOpcode(writer, e[0]);
try b.writeConst(writer, u16, 0);
try b.writeConst(writer, u16, 1);
try b.writeOpcode(writer, e[0]);
try b.writeConst(writer, u16, 1);
try b.writeConst(writer, u16, 0);
try b.writeOpcode(writer, e[0]);
_ = try stack_machine.run(program.items, allocator, context, null);
try testing.expectEqual(@as(usize, e[3]), stack_machine.stack.popOrNull().?.generic);
try testing.expectEqual(@as(usize, e[2]), stack_machine.stack.popOrNull().?.generic);
try testing.expectEqual(@as(usize, e[1]), stack_machine.stack.popOrNull().?.generic);
}
stack_machine.reset();
program.clearRetainingCapacity();
try b.writeLiteral(writer, 2);
try b.writeSkip(writer, 1);
try b.writeLiteral(writer, 3);
_ = try stack_machine.run(program.items, allocator, context, null);
try testing.expectEqual(@as(usize, 2), stack_machine.stack.popOrNull().?.generic);
stack_machine.reset();
program.clearRetainingCapacity();
try b.writeLiteral(writer, 2);
try b.writeBra(writer, 1);
try b.writeLiteral(writer, 3);
try b.writeLiteral(writer, 0);
try b.writeBra(writer, 1);
try b.writeLiteral(writer, 4);
try b.writeLiteral(writer, 5);
_ = try stack_machine.run(program.items, allocator, context, null);
try testing.expectEqual(@as(usize, 5), stack_machine.stack.popOrNull().?.generic);
try testing.expectEqual(@as(usize, 4), stack_machine.stack.popOrNull().?.generic);
try testing.expect(stack_machine.stack.popOrNull() == null);
// TODO: Test call2, call4, call_ref once implemented
}
}