mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Dwarf: cleanup and port to new std.io.BufferedReader API
This commit is contained in:
parent
9dc0b4a98f
commit
d76c8d0bd2
@ -51,17 +51,6 @@ const Opcode = enum(u8) {
|
||||
pub const hi_user = 0x3f;
|
||||
};
|
||||
|
||||
fn readBlock(stream: *std.io.FixedBufferStream) ![]const u8 {
|
||||
const reader = stream.reader();
|
||||
const block_len = try leb.readUleb128(usize, reader);
|
||||
if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
|
||||
|
||||
const block = stream.buffer[stream.pos..][0..block_len];
|
||||
reader.context.pos += block_len;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
pub const Instruction = union(Opcode) {
|
||||
advance_loc: struct {
|
||||
delta: u8,
|
||||
@ -147,12 +136,11 @@ pub const Instruction = union(Opcode) {
|
||||
},
|
||||
|
||||
pub fn read(
|
||||
stream: *std.io.FixedBufferStream,
|
||||
reader: *std.io.BufferedReader,
|
||||
addr_size_bytes: u8,
|
||||
endian: std.builtin.Endian,
|
||||
) !Instruction {
|
||||
const reader = stream.reader();
|
||||
switch (try reader.readByte()) {
|
||||
switch (try reader.takeByte()) {
|
||||
Opcode.lo_inline...Opcode.hi_inline => |opcode| {
|
||||
const e: Opcode = @enumFromInt(opcode & 0b11000000);
|
||||
const value: u6 = @intCast(opcode & 0b111111);
|
||||
@ -163,7 +151,7 @@ pub const Instruction = union(Opcode) {
|
||||
.offset => .{
|
||||
.offset = .{
|
||||
.register = value,
|
||||
.offset = try leb.readUleb128(u64, reader),
|
||||
.offset = try reader.takeLeb128(u64),
|
||||
},
|
||||
},
|
||||
.restore => .{
|
||||
@ -175,121 +163,84 @@ pub const Instruction = union(Opcode) {
|
||||
Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {
|
||||
const e: Opcode = @enumFromInt(opcode);
|
||||
return switch (e) {
|
||||
.advance_loc,
|
||||
.offset,
|
||||
.restore,
|
||||
=> unreachable,
|
||||
.nop => .{ .nop = {} },
|
||||
.set_loc => .{
|
||||
.set_loc = .{
|
||||
.address = switch (addr_size_bytes) {
|
||||
2 => try reader.readInt(u16, endian),
|
||||
4 => try reader.readInt(u32, endian),
|
||||
8 => try reader.readInt(u64, endian),
|
||||
else => return error.InvalidAddrSize,
|
||||
},
|
||||
.advance_loc, .offset, .restore => unreachable,
|
||||
.nop => .nop,
|
||||
.set_loc => .{ .set_loc = .{
|
||||
.address = switch (addr_size_bytes) {
|
||||
2 => try reader.takeInt(u16, endian),
|
||||
4 => try reader.takeInt(u32, endian),
|
||||
8 => try reader.takeInt(u64, endian),
|
||||
else => return error.InvalidAddrSize,
|
||||
},
|
||||
},
|
||||
.advance_loc1 => .{
|
||||
.advance_loc1 = .{ .delta = try reader.readByte() },
|
||||
},
|
||||
.advance_loc2 => .{
|
||||
.advance_loc2 = .{ .delta = try reader.readInt(u16, endian) },
|
||||
},
|
||||
.advance_loc4 => .{
|
||||
.advance_loc4 = .{ .delta = try reader.readInt(u32, endian) },
|
||||
},
|
||||
.offset_extended => .{
|
||||
.offset_extended = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.offset = try leb.readUleb128(u64, reader),
|
||||
},
|
||||
},
|
||||
.restore_extended => .{
|
||||
.restore_extended = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
},
|
||||
},
|
||||
.undefined => .{
|
||||
.undefined = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
},
|
||||
},
|
||||
.same_value => .{
|
||||
.same_value = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
},
|
||||
},
|
||||
.register => .{
|
||||
.register = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.target_register = try leb.readUleb128(u8, reader),
|
||||
},
|
||||
},
|
||||
.remember_state => .{ .remember_state = {} },
|
||||
.restore_state => .{ .restore_state = {} },
|
||||
.def_cfa => .{
|
||||
.def_cfa = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.offset = try leb.readUleb128(u64, reader),
|
||||
},
|
||||
},
|
||||
.def_cfa_register => .{
|
||||
.def_cfa_register = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
},
|
||||
},
|
||||
.def_cfa_offset => .{
|
||||
.def_cfa_offset = .{
|
||||
.offset = try leb.readUleb128(u64, reader),
|
||||
},
|
||||
},
|
||||
.def_cfa_expression => .{
|
||||
.def_cfa_expression = .{
|
||||
.block = try readBlock(stream),
|
||||
},
|
||||
},
|
||||
.expression => .{
|
||||
.expression = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.block = try readBlock(stream),
|
||||
},
|
||||
},
|
||||
.offset_extended_sf => .{
|
||||
.offset_extended_sf = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.offset = try leb.readIleb128(i64, reader),
|
||||
},
|
||||
},
|
||||
.def_cfa_sf => .{
|
||||
.def_cfa_sf = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.offset = try leb.readIleb128(i64, reader),
|
||||
},
|
||||
},
|
||||
.def_cfa_offset_sf => .{
|
||||
.def_cfa_offset_sf = .{
|
||||
.offset = try leb.readIleb128(i64, reader),
|
||||
},
|
||||
},
|
||||
.val_offset => .{
|
||||
.val_offset = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.offset = try leb.readUleb128(u64, reader),
|
||||
},
|
||||
},
|
||||
.val_offset_sf => .{
|
||||
.val_offset_sf = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.offset = try leb.readIleb128(i64, reader),
|
||||
},
|
||||
},
|
||||
.val_expression => .{
|
||||
.val_expression = .{
|
||||
.register = try leb.readUleb128(u8, reader),
|
||||
.block = try readBlock(stream),
|
||||
},
|
||||
},
|
||||
} },
|
||||
.advance_loc1 => .{ .advance_loc1 = .{
|
||||
.delta = try reader.takeByte(),
|
||||
} },
|
||||
.advance_loc2 => .{ .advance_loc2 = .{
|
||||
.delta = try reader.takeInt(u16, endian),
|
||||
} },
|
||||
.advance_loc4 => .{ .advance_loc4 = .{
|
||||
.delta = try reader.takeInt(u32, endian),
|
||||
} },
|
||||
.offset_extended => .{ .offset_extended = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.offset = try reader.takeLeb128(u64),
|
||||
} },
|
||||
.restore_extended => .{ .restore_extended = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
} },
|
||||
.undefined => .{ .undefined = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
} },
|
||||
.same_value => .{ .same_value = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
} },
|
||||
.register => .{ .register = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.target_register = try reader.takeLeb128(u8),
|
||||
} },
|
||||
.remember_state => .remember_state,
|
||||
.restore_state => .restore_state,
|
||||
.def_cfa => .{ .def_cfa = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.offset = try reader.takeLeb128(u64),
|
||||
} },
|
||||
.def_cfa_register => .{ .def_cfa_register = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
} },
|
||||
.def_cfa_offset => .{ .def_cfa_offset = .{
|
||||
.offset = try reader.takeLeb128(u64),
|
||||
} },
|
||||
.def_cfa_expression => .{ .def_cfa_expression = .{
|
||||
.block = try reader.take(try reader.takeLeb128(usize)),
|
||||
} },
|
||||
.expression => .{ .expression = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.block = try reader.take(try reader.takeLeb128(usize)),
|
||||
} },
|
||||
.offset_extended_sf => .{ .offset_extended_sf = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.offset = try reader.takeLeb128(i64),
|
||||
} },
|
||||
.def_cfa_sf => .{ .def_cfa_sf = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.offset = try reader.takeLeb128(i64),
|
||||
} },
|
||||
.def_cfa_offset_sf => .{ .def_cfa_offset_sf = .{
|
||||
.offset = try reader.takeLeb128(i64),
|
||||
} },
|
||||
.val_offset => .{ .val_offset = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.offset = try reader.takeLeb128(u64),
|
||||
} },
|
||||
.val_offset_sf => .{ .val_offset_sf = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.offset = try reader.takeLeb128(i64),
|
||||
} },
|
||||
.val_expression => .{ .val_expression = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.block = try reader.take(try reader.takeLeb128(usize)),
|
||||
} },
|
||||
};
|
||||
},
|
||||
Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,
|
||||
|
||||
@ -68,14 +68,14 @@ pub const Error = error{
|
||||
/// Expressions can be decoded for non-native address size and endianness,
|
||||
/// but can only be executed if the current target matches the configuration.
|
||||
pub fn StackMachine(comptime options: Options) type {
|
||||
const addr_type = switch (options.addr_size) {
|
||||
const Address = switch (options.addr_size) {
|
||||
2 => u16,
|
||||
4 => u32,
|
||||
8 => u64,
|
||||
else => @compileError("Unsupported address size of " ++ options.addr_size),
|
||||
};
|
||||
|
||||
const addr_type_signed = switch (options.addr_size) {
|
||||
const SignedAddress = switch (options.addr_size) {
|
||||
2 => i16,
|
||||
4 => i32,
|
||||
8 => i64,
|
||||
@ -86,7 +86,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
const Self = @This();
|
||||
|
||||
const Operand = union(enum) {
|
||||
generic: addr_type,
|
||||
generic: Address,
|
||||
register: u8,
|
||||
type_size: u8,
|
||||
branch_offset: i16,
|
||||
@ -101,38 +101,38 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
block: []const u8,
|
||||
register_type: struct {
|
||||
register: u8,
|
||||
type_offset: addr_type,
|
||||
type_offset: Address,
|
||||
},
|
||||
const_type: struct {
|
||||
type_offset: addr_type,
|
||||
type_offset: Address,
|
||||
value_bytes: []const u8,
|
||||
},
|
||||
deref_type: struct {
|
||||
size: u8,
|
||||
type_offset: addr_type,
|
||||
type_offset: Address,
|
||||
},
|
||||
};
|
||||
|
||||
const Value = union(enum) {
|
||||
generic: addr_type,
|
||||
generic: Address,
|
||||
|
||||
// Typed value with a maximum size of a register
|
||||
regval_type: struct {
|
||||
// Offset of DW_TAG_base_type DIE
|
||||
type_offset: addr_type,
|
||||
type_offset: Address,
|
||||
type_size: u8,
|
||||
value: addr_type,
|
||||
value: Address,
|
||||
},
|
||||
|
||||
// Typed value specified directly in the instruction stream
|
||||
const_type: struct {
|
||||
// Offset of DW_TAG_base_type DIE
|
||||
type_offset: addr_type,
|
||||
type_offset: Address,
|
||||
// Backed by the instruction stream
|
||||
value_bytes: []const u8,
|
||||
},
|
||||
|
||||
pub fn asIntegral(self: Value) !addr_type {
|
||||
pub fn asIntegral(self: Value) !Address {
|
||||
return switch (self) {
|
||||
.generic => |v| v,
|
||||
|
||||
@ -147,7 +147,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
else => return error.InvalidIntegralTypeSize,
|
||||
};
|
||||
|
||||
return std.math.cast(addr_type, value) orelse error.TruncatedIntegralType;
|
||||
return std.math.cast(Address, value) orelse error.TruncatedIntegralType;
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -167,119 +167,87 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
const int_info = @typeInfo(@TypeOf(value)).int;
|
||||
if (@sizeOf(@TypeOf(value)) > options.addr_size) {
|
||||
return .{ .generic = switch (int_info.signedness) {
|
||||
.signed => @bitCast(@as(addr_type_signed, @truncate(value))),
|
||||
.signed => @bitCast(@as(SignedAddress, @truncate(value))),
|
||||
.unsigned => @truncate(value),
|
||||
} };
|
||||
} else {
|
||||
return .{ .generic = switch (int_info.signedness) {
|
||||
.signed => @bitCast(@as(addr_type_signed, @intCast(value))),
|
||||
.signed => @bitCast(@as(SignedAddress, @intCast(value))),
|
||||
.unsigned => @intCast(value),
|
||||
} };
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readOperand(stream: *std.io.FixedBufferStream, opcode: u8, context: Context) !?Operand {
|
||||
const reader = stream.reader();
|
||||
pub fn readOperand(reader: *std.io.BufferedReader, opcode: u8, context: Context) !?Operand {
|
||||
return switch (opcode) {
|
||||
OP.addr => generic(try reader.readInt(addr_type, options.endian)),
|
||||
OP.addr => generic(try reader.takeInt(Address, options.endian)),
|
||||
OP.call_ref => switch (context.format) {
|
||||
.@"32" => generic(try reader.readInt(u32, options.endian)),
|
||||
.@"64" => generic(try reader.readInt(u64, options.endian)),
|
||||
.@"32" => generic(try reader.takeInt(u32, options.endian)),
|
||||
.@"64" => generic(try reader.takeInt(u64, options.endian)),
|
||||
},
|
||||
OP.const1u,
|
||||
OP.pick,
|
||||
=> generic(try reader.readByte()),
|
||||
=> generic(try reader.takeByte()),
|
||||
OP.deref_size,
|
||||
OP.xderef_size,
|
||||
=> .{ .type_size = try reader.readByte() },
|
||||
OP.const1s => generic(try reader.readByteSigned()),
|
||||
=> .{ .type_size = try reader.takeByte() },
|
||||
OP.const1s => generic(try reader.takeByteSigned()),
|
||||
OP.const2u,
|
||||
OP.call2,
|
||||
=> generic(try reader.readInt(u16, options.endian)),
|
||||
OP.call4 => generic(try reader.readInt(u32, options.endian)),
|
||||
OP.const2s => generic(try reader.readInt(i16, options.endian)),
|
||||
=> generic(try reader.takeInt(u16, options.endian)),
|
||||
OP.call4 => generic(try reader.takeInt(u32, options.endian)),
|
||||
OP.const2s => generic(try reader.takeInt(i16, options.endian)),
|
||||
OP.bra,
|
||||
OP.skip,
|
||||
=> .{ .branch_offset = try reader.readInt(i16, options.endian) },
|
||||
OP.const4u => generic(try reader.readInt(u32, options.endian)),
|
||||
OP.const4s => generic(try reader.readInt(i32, options.endian)),
|
||||
OP.const8u => generic(try reader.readInt(u64, options.endian)),
|
||||
OP.const8s => generic(try reader.readInt(i64, options.endian)),
|
||||
=> .{ .branch_offset = try reader.takeInt(i16, options.endian) },
|
||||
OP.const4u => generic(try reader.takeInt(u32, options.endian)),
|
||||
OP.const4s => generic(try reader.takeInt(i32, options.endian)),
|
||||
OP.const8u => generic(try reader.takeInt(u64, options.endian)),
|
||||
OP.const8s => generic(try reader.takeInt(i64, options.endian)),
|
||||
OP.constu,
|
||||
OP.plus_uconst,
|
||||
OP.addrx,
|
||||
OP.constx,
|
||||
OP.convert,
|
||||
OP.reinterpret,
|
||||
=> generic(try leb.readUleb128(u64, reader)),
|
||||
=> generic(try reader.takeLeb128(u64)),
|
||||
OP.consts,
|
||||
OP.fbreg,
|
||||
=> generic(try leb.readIleb128(i64, reader)),
|
||||
=> generic(try reader.takeLeb128(i64)),
|
||||
OP.lit0...OP.lit31 => |n| generic(n - OP.lit0),
|
||||
OP.reg0...OP.reg31 => |n| .{ .register = n - OP.reg0 },
|
||||
OP.breg0...OP.breg31 => |n| .{ .base_register = .{
|
||||
.base_register = n - OP.breg0,
|
||||
.offset = try leb.readIleb128(i64, reader),
|
||||
.offset = try reader.takeLeb128(i64),
|
||||
} },
|
||||
OP.regx => .{ .register = try leb.readUleb128(u8, reader) },
|
||||
OP.bregx => blk: {
|
||||
const base_register = try leb.readUleb128(u8, reader);
|
||||
const offset = try leb.readIleb128(i64, reader);
|
||||
break :blk .{ .base_register = .{
|
||||
.base_register = base_register,
|
||||
.offset = offset,
|
||||
} };
|
||||
},
|
||||
OP.regval_type => blk: {
|
||||
const register = try leb.readUleb128(u8, reader);
|
||||
const type_offset = try leb.readUleb128(addr_type, reader);
|
||||
break :blk .{ .register_type = .{
|
||||
.register = register,
|
||||
.type_offset = type_offset,
|
||||
} };
|
||||
},
|
||||
OP.piece => .{
|
||||
.composite_location = .{
|
||||
.size = try leb.readUleb128(u8, reader),
|
||||
.offset = 0,
|
||||
},
|
||||
},
|
||||
OP.bit_piece => blk: {
|
||||
const size = try leb.readUleb128(u8, reader);
|
||||
const offset = try leb.readIleb128(i64, reader);
|
||||
break :blk .{ .composite_location = .{
|
||||
.size = size,
|
||||
.offset = offset,
|
||||
} };
|
||||
},
|
||||
OP.implicit_value, OP.entry_value => blk: {
|
||||
const size = try leb.readUleb128(u8, reader);
|
||||
if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
|
||||
const block = stream.buffer[stream.pos..][0..size];
|
||||
stream.pos += size;
|
||||
break :blk .{
|
||||
.block = block,
|
||||
};
|
||||
},
|
||||
OP.const_type => blk: {
|
||||
const type_offset = try leb.readUleb128(addr_type, reader);
|
||||
const size = try reader.readByte();
|
||||
if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
|
||||
const value_bytes = stream.buffer[stream.pos..][0..size];
|
||||
stream.pos += size;
|
||||
break :blk .{ .const_type = .{
|
||||
.type_offset = type_offset,
|
||||
.value_bytes = value_bytes,
|
||||
} };
|
||||
},
|
||||
OP.deref_type,
|
||||
OP.xderef_type,
|
||||
=> .{
|
||||
.deref_type = .{
|
||||
.size = try reader.readByte(),
|
||||
.type_offset = try leb.readUleb128(addr_type, reader),
|
||||
},
|
||||
OP.regx => .{ .register = try reader.takeLeb128(u8) },
|
||||
OP.bregx => .{ .base_register = .{
|
||||
.base_register = try reader.takeLeb128(u8),
|
||||
.offset = try reader.takeLeb128(i64),
|
||||
} },
|
||||
OP.regval_type => .{ .register_type = .{
|
||||
.register = try reader.takeLeb128(u8),
|
||||
.type_offset = try reader.takeLeb128(Address),
|
||||
} },
|
||||
OP.piece => .{ .composite_location = .{
|
||||
.size = try reader.takeLeb128(u64),
|
||||
.offset = 0,
|
||||
} },
|
||||
OP.bit_piece => .{ .composite_location = .{
|
||||
.size = try reader.takeLeb128(u64),
|
||||
.offset = try reader.takeLeb128(i64),
|
||||
} },
|
||||
OP.implicit_value, OP.entry_value => .{
|
||||
.block = try reader.take(try reader.takeLeb128(usize)),
|
||||
},
|
||||
OP.const_type => .{ .const_type = .{
|
||||
.type_offset = try reader.takeLeb128(Address),
|
||||
.value_bytes = try reader.take(try reader.takeByte()),
|
||||
} },
|
||||
OP.deref_type, OP.xderef_type => .{ .deref_type = .{
|
||||
.size = try reader.takeByte(),
|
||||
.type_offset = try reader.takeLeb128(Address),
|
||||
} },
|
||||
OP.lo_user...OP.hi_user => return error.UnimplementedUserOpcode,
|
||||
else => null,
|
||||
};
|
||||
@ -291,10 +259,11 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
allocator: std.mem.Allocator,
|
||||
context: Context,
|
||||
initial_value: ?usize,
|
||||
) Error!?Value {
|
||||
) anyerror!?Value {
|
||||
if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });
|
||||
var stream: std.io.FixedBufferStream = .{ .buffer = expression };
|
||||
while (try self.step(&stream, allocator, context)) {}
|
||||
var reader: std.io.BufferedReader = undefined;
|
||||
reader.initFixed(expression);
|
||||
while (try self.step(&reader, allocator, context)) {}
|
||||
if (self.stack.items.len == 0) return null;
|
||||
return self.stack.items[self.stack.items.len - 1];
|
||||
}
|
||||
@ -302,16 +271,19 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
/// Reads an opcode and its operands from `stream`, then executes it
|
||||
pub fn step(
|
||||
self: *Self,
|
||||
stream: *std.io.FixedBufferStream,
|
||||
reader: *std.io.BufferedReader,
|
||||
allocator: std.mem.Allocator,
|
||||
context: Context,
|
||||
) Error!bool {
|
||||
if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != native_endian)
|
||||
) anyerror!bool {
|
||||
if (@sizeOf(usize) != @sizeOf(Address) or options.endian != native_endian)
|
||||
@compileError("Execution of non-native address sizes / endianness is not supported");
|
||||
|
||||
const opcode = try stream.reader().readByte();
|
||||
const opcode = reader.takeByte() catch |err| switch (err) {
|
||||
error.EndOfStream => return false,
|
||||
else => |e| return @errorCast(e),
|
||||
};
|
||||
if (options.call_frame_context and !isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
|
||||
const operand = try readOperand(stream, opcode, context);
|
||||
const operand = try readOperand(reader, opcode, context);
|
||||
switch (opcode) {
|
||||
|
||||
// 2.5.1.1: Literal Encodings
|
||||
@ -397,7 +369,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
try self.stack.append(allocator, .{
|
||||
.regval_type = .{
|
||||
.type_offset = register_type.type_offset,
|
||||
.type_size = @sizeOf(addr_type),
|
||||
.type_size = @sizeOf(Address),
|
||||
.value = value,
|
||||
},
|
||||
});
|
||||
@ -455,7 +427,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
const size = switch (opcode) {
|
||||
OP.deref,
|
||||
OP.xderef,
|
||||
=> @sizeOf(addr_type),
|
||||
=> @sizeOf(Address),
|
||||
OP.deref_size,
|
||||
OP.xderef_size,
|
||||
=> operand.?.type_size,
|
||||
@ -475,7 +447,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
}) return error.InvalidExpression;
|
||||
}
|
||||
|
||||
const value: addr_type = std.math.cast(addr_type, @as(u64, switch (size) {
|
||||
const value: Address = std.math.cast(Address, @as(u64, switch (size) {
|
||||
1 => @as(*const u8, @ptrFromInt(addr)).*,
|
||||
2 => @as(*const u16, @ptrFromInt(addr)).*,
|
||||
4 => @as(*const u32, @ptrFromInt(addr)).*,
|
||||
@ -544,7 +516,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
if (self.stack.items.len < 2) return error.InvalidExpression;
|
||||
const b = try self.stack.pop().?.asIntegral();
|
||||
self.stack.items[self.stack.items.len - 1] = .{
|
||||
.generic = try std.math.sub(addr_type, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
|
||||
.generic = try std.math.sub(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
|
||||
};
|
||||
},
|
||||
OP.mod => {
|
||||
@ -590,14 +562,14 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
if (self.stack.items.len < 2) return error.InvalidExpression;
|
||||
const b = try self.stack.pop().?.asIntegral();
|
||||
self.stack.items[self.stack.items.len - 1] = .{
|
||||
.generic = try std.math.add(addr_type, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
|
||||
.generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
|
||||
};
|
||||
},
|
||||
OP.plus_uconst => {
|
||||
if (self.stack.items.len == 0) return error.InvalidExpression;
|
||||
const constant = operand.?.generic;
|
||||
self.stack.items[self.stack.items.len - 1] = .{
|
||||
.generic = try std.math.add(addr_type, try self.stack.items[self.stack.items.len - 1].asIntegral(), constant),
|
||||
.generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), constant),
|
||||
};
|
||||
},
|
||||
OP.shl => {
|
||||
@ -670,15 +642,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
break :blk try self.stack.pop().?.asIntegral() != 0;
|
||||
} else true;
|
||||
|
||||
if (condition) {
|
||||
const new_pos = std.math.cast(
|
||||
usize,
|
||||
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;
|
||||
stream.pos = new_pos;
|
||||
}
|
||||
if (condition) reader.seekBy(branch_offset) catch return error.InvalidExpression;
|
||||
},
|
||||
OP.call2,
|
||||
OP.call4,
|
||||
@ -722,7 +686,7 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
.generic => |v| .{
|
||||
.regval_type = .{
|
||||
.type_offset = type_offset,
|
||||
.type_size = @sizeOf(addr_type),
|
||||
.type_size = @sizeOf(Address),
|
||||
.value = v,
|
||||
},
|
||||
},
|
||||
@ -756,8 +720,9 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
if (isOpcodeRegisterLocation(block[0])) {
|
||||
if (context.thread_context == null) return error.IncompleteExpressionContext;
|
||||
|
||||
var block_stream: std.io.FixedBufferStream = .{ .buffer = block };
|
||||
const register = (try readOperand(&block_stream, block[0], context)).?.register;
|
||||
var block_reader: std.io.BufferedReader = undefined;
|
||||
block_reader.initFixed(block);
|
||||
const register = (try readOperand(&block_reader, block[0], context)).?.register;
|
||||
const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian);
|
||||
try self.stack.append(allocator, .{ .generic = value });
|
||||
} else {
|
||||
@ -778,14 +743,13 @@ pub fn StackMachine(comptime options: Options) type {
|
||||
return error.UnknownExpressionOpcode;
|
||||
},
|
||||
}
|
||||
|
||||
return stream.pos < stream.buffer.len;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn Builder(comptime options: Options) type {
|
||||
const addr_type = switch (options.addr_size) {
|
||||
const Address = switch (options.addr_size) {
|
||||
2 => u16,
|
||||
4 => u32,
|
||||
8 => u64,
|
||||
@ -888,9 +852,9 @@ pub fn Builder(comptime options: Options) type {
|
||||
try writer.writeAll(value_bytes);
|
||||
}
|
||||
|
||||
pub fn writeAddr(writer: anytype, value: addr_type) !void {
|
||||
pub fn writeAddr(writer: anytype, value: Address) !void {
|
||||
try writer.writeByte(OP.addr);
|
||||
try writer.writeInt(addr_type, value, options.endian);
|
||||
try writer.writeInt(Address, value, options.endian);
|
||||
}
|
||||
|
||||
pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {
|
||||
|
||||
@ -51,22 +51,21 @@ pub fn readIntChecked(
|
||||
return fbr.readInt(T);
|
||||
}
|
||||
|
||||
pub fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
|
||||
pub fn readLeb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
|
||||
var br: std.io.BufferedReader = undefined;
|
||||
br.initFixed(fbr.buf);
|
||||
br.seek = fbr.pos;
|
||||
const result = br.takeUleb128(T);
|
||||
const result = br.takeLeb128(T);
|
||||
fbr.pos = br.seek;
|
||||
return @errorCast(result);
|
||||
}
|
||||
|
||||
pub fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
|
||||
return fbr.readLeb128(T);
|
||||
}
|
||||
|
||||
pub fn readIleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
|
||||
var br: std.io.BufferedReader = undefined;
|
||||
br.initFixed(fbr.buf);
|
||||
br.seek = fbr.pos;
|
||||
const result = br.takeIleb128(T);
|
||||
fbr.pos = br.seek;
|
||||
return @errorCast(result);
|
||||
return fbr.readLeb128(T);
|
||||
}
|
||||
|
||||
pub fn readAddress(fbr: *FixedBufferReader, format: std.dwarf.Format) Error!u64 {
|
||||
|
||||
@ -2025,18 +2025,15 @@ pub const VirtualMachine = struct {
|
||||
assert(self.cie_row == null);
|
||||
if (pc < fde.pc_begin or pc >= fde.pc_begin + fde.pc_range) return error.AddressOutOfRange;
|
||||
|
||||
var readers: [2]std.io.BufferedReader = undefined;
|
||||
readers[0].initFixed(cie.initial_instructions);
|
||||
readers[1].initFixed(fde.instructions);
|
||||
|
||||
var prev_row: Row = self.current_row;
|
||||
|
||||
var cie_stream: std.io.BufferedReader = undefined;
|
||||
cie_stream.initFixed(cie.initial_instructions);
|
||||
var fde_stream: std.io.BufferedReader = undefined;
|
||||
fde_stream.initFixed(fde.instructions);
|
||||
const streams: [2]*std.io.BufferedReader = .{ &cie_stream, &fde_stream };
|
||||
|
||||
for (&streams, 0..) |stream, i| {
|
||||
while (stream.seek < stream.storageBuffer().len) {
|
||||
const instruction = try std.debug.Dwarf.call_frame.Instruction.read(stream, addr_size_bytes, endian);
|
||||
prev_row = try self.step(allocator, cie, i == 0, instruction);
|
||||
for (&readers, [2]bool{ true, false }) |*reader, is_initial| {
|
||||
while (reader.seek < reader.storageBuffer().len) {
|
||||
const instruction = try std.debug.Dwarf.call_frame.Instruction.read(reader, addr_size_bytes, endian);
|
||||
prev_row = try self.step(allocator, cie, is_initial, instruction);
|
||||
if (pc < fde.pc_begin + self.current_row.offset) return prev_row;
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +164,21 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
pub fn seekBy(br: *BufferedReader, seek_by: i64) anyerror!void {
|
||||
if (seek_by < 0) try br.seekBackwardBy(@abs(seek_by)) else try br.seekForwardBy(@abs(seek_by));
|
||||
}
|
||||
|
||||
pub fn seekBackwardBy(br: *BufferedReader, seek_by: u64) anyerror!void {
|
||||
if (seek_by > br.storage.buffer.items.len - br.seek) return error.Unseekable; // TODO
|
||||
br.seek += @abs(seek_by);
|
||||
}
|
||||
|
||||
pub fn seekForwardBy(br: *BufferedReader, seek_by: u64) anyerror!void {
|
||||
const seek, const need_unbuffered_seek = @subWithOverflow(br.seek, @abs(seek_by));
|
||||
if (need_unbuffered_seek > 0) return error.Unseekable; // TODO
|
||||
br.seek = seek;
|
||||
}
|
||||
|
||||
/// Returns the next `n` bytes from `unbuffered_reader`, filling the buffer as
|
||||
/// necessary.
|
||||
///
|
||||
@ -176,12 +191,31 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!
|
||||
/// is returned instead.
|
||||
///
|
||||
/// See also:
|
||||
/// * `peekAll`
|
||||
/// * `toss`
|
||||
pub fn peek(br: *BufferedReader, n: usize) anyerror![]u8 {
|
||||
return (try br.peekAll(n))[0..n];
|
||||
}
|
||||
|
||||
/// Returns the next buffered bytes from `unbuffered_reader`, after filling the buffer
|
||||
/// with at least `n` bytes.
|
||||
///
|
||||
/// Invalidates previously returned values from `peek`.
|
||||
///
|
||||
/// Asserts that the `BufferedReader` was initialized with a buffer capacity at
|
||||
/// least as big as `n`.
|
||||
///
|
||||
/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
|
||||
/// is returned instead.
|
||||
///
|
||||
/// See also:
|
||||
/// * `peek`
|
||||
/// * `toss`
|
||||
pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 {
|
||||
const list = &br.storage.buffer;
|
||||
assert(n <= list.capacity);
|
||||
try fill(br, n);
|
||||
return list.items[br.seek..][0..n];
|
||||
try br.fill(n);
|
||||
return list.items[br.seek..];
|
||||
}
|
||||
|
||||
/// Skips the next `n` bytes from the stream, advancing the seek position. This
|
||||
@ -563,93 +597,41 @@ pub fn takeEnum(br: *BufferedReader, comptime Enum: type, endian: std.builtin.En
|
||||
return std.meta.intToEnum(Enum, int);
|
||||
}
|
||||
|
||||
/// Read a single unsigned LEB128 value from the given reader as type T,
|
||||
/// or error.Overflow if the value cannot fit.
|
||||
pub fn takeUleb128(br: *std.io.BufferedReader, comptime T: type) anyerror!T {
|
||||
const U = if (@typeInfo(T).int.bits < 8) u8 else T;
|
||||
const ShiftT = std.math.Log2Int(U);
|
||||
|
||||
const max_group = (@typeInfo(U).int.bits + 6) / 7;
|
||||
|
||||
var value: U = 0;
|
||||
var group: ShiftT = 0;
|
||||
|
||||
while (group < max_group) : (group += 1) {
|
||||
const byte = try br.takeByte();
|
||||
|
||||
const ov = @shlWithOverflow(@as(U, byte & 0x7f), group * 7);
|
||||
if (ov[1] != 0) return error.Overflow;
|
||||
|
||||
value |= ov[0];
|
||||
if (byte & 0x80 == 0) break;
|
||||
} else {
|
||||
return error.Overflow;
|
||||
}
|
||||
|
||||
// only applies in the case that we extended to u8
|
||||
if (U != T) {
|
||||
if (value > std.math.maxInt(T)) return error.Overflow;
|
||||
}
|
||||
|
||||
return @truncate(value);
|
||||
/// Read a single LEB128 value as type T, or `error.Overflow` if the value cannot fit.
|
||||
pub fn takeLeb128(br: *BufferedReader, comptime Result: type) anyerror!Result {
|
||||
const result_info = @typeInfo(Result).int;
|
||||
return std.math.cast(Result, try br.takeMultipleOf7Leb128(@Type(.{ .int = .{
|
||||
.signedness = result_info.signedness,
|
||||
.bits = std.mem.alignForwardAnyAlign(u16, result_info.bits, 7),
|
||||
} }))) orelse error.Overflow;
|
||||
}
|
||||
|
||||
/// Read a single signed LEB128 value from the given reader as type T,
|
||||
/// or `error.Overflow` if the value cannot fit.
|
||||
pub fn takeIleb128(br: *std.io.BufferedReader, comptime T: type) anyerror!T {
|
||||
const S = if (@typeInfo(T).int.bits < 8) i8 else T;
|
||||
const U = std.meta.Int(.unsigned, @typeInfo(S).int.bits);
|
||||
const ShiftU = std.math.Log2Int(U);
|
||||
|
||||
const max_group = (@typeInfo(U).int.bits + 6) / 7;
|
||||
|
||||
var value = @as(U, 0);
|
||||
var group = @as(ShiftU, 0);
|
||||
|
||||
while (group < max_group) : (group += 1) {
|
||||
const byte = try br.takeByte();
|
||||
|
||||
const shift = group * 7;
|
||||
const ov = @shlWithOverflow(@as(U, byte & 0x7f), shift);
|
||||
if (ov[1] != 0) {
|
||||
// Overflow is ok so long as the sign bit is set and this is the last byte
|
||||
if (byte & 0x80 != 0) return error.Overflow;
|
||||
if (@as(S, @bitCast(ov[0])) >= 0) return error.Overflow;
|
||||
|
||||
// and all the overflowed bits are 1
|
||||
const remaining_shift = @as(u3, @intCast(@typeInfo(U).int.bits - @as(u16, shift)));
|
||||
const remaining_bits = @as(i8, @bitCast(byte | 0x80)) >> remaining_shift;
|
||||
if (remaining_bits != -1) return error.Overflow;
|
||||
} else {
|
||||
// If we don't overflow and this is the last byte and the number being decoded
|
||||
// is negative, check that the remaining bits are 1
|
||||
if ((byte & 0x80 == 0) and (@as(S, @bitCast(ov[0])) < 0)) {
|
||||
const remaining_shift = @as(u3, @intCast(@typeInfo(U).int.bits - @as(u16, shift)));
|
||||
const remaining_bits = @as(i8, @bitCast(byte | 0x80)) >> remaining_shift;
|
||||
if (remaining_bits != -1) return error.Overflow;
|
||||
}
|
||||
fn takeMultipleOf7Leb128(br: *BufferedReader, comptime Result: type) anyerror!Result {
|
||||
const result_info = @typeInfo(Result).int;
|
||||
comptime assert(result_info.bits % 7 == 0);
|
||||
var remaining_bits: std.math.Log2IntCeil(Result) = result_info.bits;
|
||||
const UnsignedResult = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = result_info.bits,
|
||||
} });
|
||||
var result: UnsignedResult = 0;
|
||||
var fits = true;
|
||||
while (true) {
|
||||
const buffer: []const packed struct(u8) { bits: u7, more: bool } = @ptrCast(try br.peekAll(1));
|
||||
for (buffer, 1..) |byte, len| {
|
||||
if (remaining_bits > 0) {
|
||||
result = @shlExact(@as(UnsignedResult, byte.bits), result_info.bits - 7) | @shrExact(result, 7);
|
||||
remaining_bits -= 7;
|
||||
} else if (fits) fits = switch (result_info.signedness) {
|
||||
.signed => @as(i7, @bitCast(byte.bits)) == @as(i7, @truncate(@as(Result, @bitCast(result)) >> (result_info.bits - 1))),
|
||||
.unsigned => byte.bits == 0,
|
||||
};
|
||||
if (byte.more) continue;
|
||||
br.toss(len);
|
||||
return if (fits) @as(Result, @bitCast(result)) >> remaining_bits else error.Overflow;
|
||||
}
|
||||
|
||||
value |= ov[0];
|
||||
if (byte & 0x80 == 0) {
|
||||
const needs_sign_ext = group + 1 < max_group;
|
||||
if (byte & 0x40 != 0 and needs_sign_ext) {
|
||||
const ones = @as(S, -1);
|
||||
value |= @as(U, @bitCast(ones)) << (shift + 7);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return error.Overflow;
|
||||
br.toss(buffer.len);
|
||||
}
|
||||
|
||||
const result = @as(S, @bitCast(value));
|
||||
// Only applies if we extended to i8
|
||||
if (S != T) {
|
||||
if (result > std.math.maxInt(T) or result < std.math.minInt(T)) return error.Overflow;
|
||||
}
|
||||
|
||||
return @truncate(result);
|
||||
}
|
||||
|
||||
test initFixed {
|
||||
@ -669,6 +651,10 @@ test peek {
|
||||
return error.Unimplemented;
|
||||
}
|
||||
|
||||
test peekAll {
|
||||
return error.Unimplemented;
|
||||
}
|
||||
|
||||
test toss {
|
||||
return error.Unimplemented;
|
||||
}
|
||||
@ -766,10 +752,6 @@ test takeEnum {
|
||||
return error.Unimplemented;
|
||||
}
|
||||
|
||||
test takeUleb128 {
|
||||
return error.Unimplemented;
|
||||
}
|
||||
|
||||
test takeIleb128 {
|
||||
test takeLeb128 {
|
||||
return error.Unimplemented;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user