mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
289 lines
9.3 KiB
Zig
289 lines
9.3 KiB
Zig
const std = @import("../../std.zig");
|
|
const Reader = std.Io.Reader;
|
|
|
|
/// TODO merge with std.dwarf.CFA
|
|
const Opcode = enum(u8) {
|
|
advance_loc = 0x1 << 6,
|
|
offset = 0x2 << 6,
|
|
restore = 0x3 << 6,
|
|
|
|
nop = 0x00,
|
|
set_loc = 0x01,
|
|
advance_loc1 = 0x02,
|
|
advance_loc2 = 0x03,
|
|
advance_loc4 = 0x04,
|
|
offset_extended = 0x05,
|
|
restore_extended = 0x06,
|
|
undefined = 0x07,
|
|
same_value = 0x08,
|
|
register = 0x09,
|
|
remember_state = 0x0a,
|
|
restore_state = 0x0b,
|
|
def_cfa = 0x0c,
|
|
def_cfa_register = 0x0d,
|
|
def_cfa_offset = 0x0e,
|
|
def_cfa_expression = 0x0f,
|
|
expression = 0x10,
|
|
offset_extended_sf = 0x11,
|
|
def_cfa_sf = 0x12,
|
|
def_cfa_offset_sf = 0x13,
|
|
val_offset = 0x14,
|
|
val_offset_sf = 0x15,
|
|
val_expression = 0x16,
|
|
|
|
// These opcodes encode an operand in the lower 6 bits of the opcode itself
|
|
pub const lo_inline = @intFromEnum(Opcode.advance_loc);
|
|
pub const hi_inline = @intFromEnum(Opcode.restore) | 0b111111;
|
|
|
|
// These opcodes are trailed by zero or more operands
|
|
pub const lo_reserved = @intFromEnum(Opcode.nop);
|
|
pub const hi_reserved = @intFromEnum(Opcode.val_expression);
|
|
|
|
// Vendor-specific opcodes
|
|
pub const lo_user = 0x1c;
|
|
pub const hi_user = 0x3f;
|
|
};
|
|
|
|
/// The returned slice points into `reader.buffer`.
|
|
fn readBlock(reader: *Reader) ![]const u8 {
|
|
const block_len = try reader.takeLeb128(usize);
|
|
return reader.take(block_len) catch |err| switch (err) {
|
|
error.EndOfStream => return error.InvalidOperand,
|
|
error.ReadFailed => |e| return e,
|
|
};
|
|
}
|
|
|
|
pub const Instruction = union(Opcode) {
|
|
advance_loc: struct {
|
|
delta: u8,
|
|
},
|
|
offset: struct {
|
|
register: u8,
|
|
offset: u64,
|
|
},
|
|
restore: struct {
|
|
register: u8,
|
|
},
|
|
nop: void,
|
|
set_loc: struct {
|
|
address: u64,
|
|
},
|
|
advance_loc1: struct {
|
|
delta: u8,
|
|
},
|
|
advance_loc2: struct {
|
|
delta: u16,
|
|
},
|
|
advance_loc4: struct {
|
|
delta: u32,
|
|
},
|
|
offset_extended: struct {
|
|
register: u8,
|
|
offset: u64,
|
|
},
|
|
restore_extended: struct {
|
|
register: u8,
|
|
},
|
|
undefined: struct {
|
|
register: u8,
|
|
},
|
|
same_value: struct {
|
|
register: u8,
|
|
},
|
|
register: struct {
|
|
register: u8,
|
|
target_register: u8,
|
|
},
|
|
remember_state: void,
|
|
restore_state: void,
|
|
def_cfa: struct {
|
|
register: u8,
|
|
offset: u64,
|
|
},
|
|
def_cfa_register: struct {
|
|
register: u8,
|
|
},
|
|
def_cfa_offset: struct {
|
|
offset: u64,
|
|
},
|
|
def_cfa_expression: struct {
|
|
block: []const u8,
|
|
},
|
|
expression: struct {
|
|
register: u8,
|
|
block: []const u8,
|
|
},
|
|
offset_extended_sf: struct {
|
|
register: u8,
|
|
offset: i64,
|
|
},
|
|
def_cfa_sf: struct {
|
|
register: u8,
|
|
offset: i64,
|
|
},
|
|
def_cfa_offset_sf: struct {
|
|
offset: i64,
|
|
},
|
|
val_offset: struct {
|
|
register: u8,
|
|
offset: u64,
|
|
},
|
|
val_offset_sf: struct {
|
|
register: u8,
|
|
offset: i64,
|
|
},
|
|
val_expression: struct {
|
|
register: u8,
|
|
block: []const u8,
|
|
},
|
|
|
|
/// `reader` must be a `Reader.fixed` so that regions of its buffer are never invalidated.
|
|
pub fn read(
|
|
reader: *Reader,
|
|
addr_size_bytes: u8,
|
|
endian: std.builtin.Endian,
|
|
) !Instruction {
|
|
switch (try reader.takeByte()) {
|
|
Opcode.lo_inline...Opcode.hi_inline => |opcode| {
|
|
const e: Opcode = @enumFromInt(opcode & 0b11000000);
|
|
const value: u6 = @intCast(opcode & 0b111111);
|
|
return switch (e) {
|
|
.advance_loc => .{
|
|
.advance_loc = .{ .delta = value },
|
|
},
|
|
.offset => .{
|
|
.offset = .{
|
|
.register = value,
|
|
.offset = try reader.takeLeb128(u64),
|
|
},
|
|
},
|
|
.restore => .{
|
|
.restore = .{ .register = value },
|
|
},
|
|
else => unreachable,
|
|
};
|
|
},
|
|
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.takeInt(u16, endian),
|
|
4 => try reader.takeInt(u32, endian),
|
|
8 => try reader.takeInt(u64, endian),
|
|
else => return error.UnsupportedAddrSize,
|
|
},
|
|
} },
|
|
.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 readBlock(reader),
|
|
},
|
|
},
|
|
.expression => .{
|
|
.expression = .{
|
|
.register = try reader.takeLeb128(u8),
|
|
.block = try readBlock(reader),
|
|
},
|
|
},
|
|
.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 readBlock(reader),
|
|
},
|
|
},
|
|
};
|
|
},
|
|
Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,
|
|
else => return error.InvalidOpcode,
|
|
}
|
|
}
|
|
};
|