- rework CFI instruction parsing to not use std.meta

- move register formatting code to zig-dwardump
This commit is contained in:
kcbanner 2023-05-22 17:59:20 -04:00
parent e72e762d1e
commit c98e03fc7e
2 changed files with 29 additions and 102 deletions

View File

@ -25,21 +25,6 @@ pub fn fpRegNum(reg_ctx: RegisterContext) u8 {
.x86_64 => 6,
.arm => 11,
.aarch64 => 29,
// const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
// const ip = switch (native_os) {
// .macos => @intCast(usize, ctx.mcontext.ss.pc),
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
// else => @intCast(usize, ctx.mcontext.pc),
// };
// // x29 is the ABI-designated frame pointer
// const bp = switch (native_os) {
// .macos => @intCast(usize, ctx.mcontext.ss.fp),
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
// else => @intCast(usize, ctx.mcontext.regs[29]),
// };
else => unreachable,
};
}
@ -231,7 +216,10 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext
0...29 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.x[reg_number]),
30 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.lr),
31 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.sp),
32 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.elr), // TODO: This seems wrong, but it was in the old debug.zig code for PC, check this
// TODO: This seems wrong, but it was in the previous debug.zig code for mapping PC, check this
32 => mem.asBytes(&ucontext_ptr.mcontext.gpregs.elr),
else => error.InvalidRegister,
},
else => switch (reg_number) {
@ -252,76 +240,3 @@ pub fn getRegDefaultValue(reg_number: u8, out: []u8) void {
_ = reg_number;
@memset(out, undefined);
}
fn writeUnknownReg(writer: anytype, reg_number: u8) !void {
try writer.print("reg{}", .{reg_number});
}
pub fn writeRegisterName(writer: anytype, arch: ?std.Target.Cpu.Arch, reg_number: u8) !void {
if (arch) |a| {
switch (a) {
.x86_64 => {
switch (reg_number) {
0 => try writer.writeAll("RAX"),
1 => try writer.writeAll("RDX"),
2 => try writer.writeAll("RCX"),
3 => try writer.writeAll("RBX"),
4 => try writer.writeAll("RSI"),
5 => try writer.writeAll("RDI"),
6 => try writer.writeAll("RBP"),
7 => try writer.writeAll("RSP"),
8...15 => try writer.print("R{}", .{reg_number}),
16 => try writer.writeAll("RIP"),
17...32 => try writer.print("XMM{}", .{reg_number - 17}),
33...40 => try writer.print("ST{}", .{reg_number - 33}),
41...48 => try writer.print("MM{}", .{reg_number - 41}),
49 => try writer.writeAll("RFLAGS"),
50 => try writer.writeAll("ES"),
51 => try writer.writeAll("CS"),
52 => try writer.writeAll("SS"),
53 => try writer.writeAll("DS"),
54 => try writer.writeAll("FS"),
55 => try writer.writeAll("GS"),
// 56-57 Reserved
58 => try writer.writeAll("FS.BASE"),
59 => try writer.writeAll("GS.BASE"),
// 60-61 Reserved
62 => try writer.writeAll("TR"),
63 => try writer.writeAll("LDTR"),
64 => try writer.writeAll("MXCSR"),
65 => try writer.writeAll("FCW"),
66 => try writer.writeAll("FSW"),
67...82 => try writer.print("XMM{}", .{reg_number - 51}),
// 83-117 Reserved
118...125 => try writer.print("K{}", .{reg_number - 118}),
// 126-129 Reserved
else => try writeUnknownReg(writer, reg_number),
}
},
// TODO: Add x86, aarch64
else => try writeUnknownReg(writer, reg_number),
}
} else try writeUnknownReg(writer, reg_number);
}
const FormatRegisterData = struct {
reg_number: u8,
arch: ?std.Target.Cpu.Arch,
};
pub fn formatRegister(
data: FormatRegisterData,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = fmt;
_ = options;
try writeRegisterName(writer, data.arch, data.reg_number);
}
pub fn fmtRegister(reg_number: u8, arch: ?std.Target.Cpu.Arch) std.fmt.Formatter(formatRegister) {
return .{ .data = .{ .reg_number = reg_number, .arch = arch } };
}

View File

@ -38,12 +38,12 @@ const Opcode = enum(u8) {
val_expression = 0x16,
// These opcodes encode an operand in the lower 6 bits of the opcode itself
pub const lo_inline = Opcode.advance_loc;
pub const lo_inline = @enumToInt(Opcode.advance_loc);
pub const hi_inline = @enumToInt(Opcode.restore) | 0b111111;
// These opcodes are trailed by zero or more operands
pub const lo_reserved = Opcode.nop;
pub const hi_reserved = Opcode.val_expression;
pub const lo_reserved = @enumToInt(Opcode.nop);
pub const hi_reserved = @enumToInt(Opcode.val_expression);
// Vendor-specific opcodes
pub const lo_user = 0x1c;
@ -187,28 +187,40 @@ pub const Instruction = union(Opcode) {
val_offset_sf: InstructionType(.{ .a = .uleb128_offset, .b = .sleb128_offset }),
val_expression: InstructionType(.{ .a = .uleb128_offset, .block = .block }),
fn readOperands(
self: *Instruction,
stream: *std.io.FixedBufferStream([]const u8),
opcode_value: ?u6,
addr_size_bytes: u8,
endian: std.builtin.Endian,
) !void {
switch (self.*) {
inline else => |*inst| inst.* = try @TypeOf(inst.*).read(stream, opcode_value, addr_size_bytes, endian),
}
}
pub fn read(
stream: *std.io.FixedBufferStream([]const u8),
addr_size_bytes: u8,
endian: std.builtin.Endian,
) !Instruction {
@setEvalBranchQuota(1800);
return switch (try stream.reader().readByte()) {
inline @enumToInt(Opcode.lo_inline)...Opcode.hi_inline => |opcode| blk: {
inline Opcode.lo_inline...Opcode.hi_inline => |opcode| blk: {
const e = @intToEnum(Opcode, opcode & 0b11000000);
const payload_type = std.meta.TagPayload(Instruction, e);
const value = try payload_type.read(stream, @intCast(u6, opcode & 0b111111), addr_size_bytes, endian);
break :blk @unionInit(Instruction, @tagName(e), value);
var result = @unionInit(Instruction, @tagName(e), undefined);
try result.readOperands(stream, @intCast(u6, opcode & 0b111111), addr_size_bytes, endian);
break :blk result;
},
inline @enumToInt(Opcode.lo_reserved)...@enumToInt(Opcode.hi_reserved) => |opcode| blk: {
inline Opcode.lo_reserved...Opcode.hi_reserved => |opcode| blk: {
const e = @intToEnum(Opcode, opcode);
const payload_type = std.meta.TagPayload(Instruction, e);
const value = try payload_type.read(stream, null, addr_size_bytes, endian);
break :blk @unionInit(Instruction, @tagName(e), value);
var result = @unionInit(Instruction, @tagName(e), undefined);
try result.readOperands(stream, null, addr_size_bytes, endian);
break :blk result;
},
Opcode.lo_user...Opcode.hi_user => error.UnimplementedUserOpcode,
else => |opcode| blk: {
// TODO: Remove this
std.debug.print("Opcode {x}\n", .{opcode});
break :blk error.InvalidOpcode;