Commit b85f84061a
Changed files (4)
lib
lib/std/dwarf/call_frame.zig
@@ -183,9 +183,9 @@ pub const Instruction = union(Opcode) {
offset_extended_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
def_cfa_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
def_cfa_offset_sf: InstructionType(.{ .offset = .sleb128_offset }),
- val_offset: InstructionType(.{ .a = .uleb128_offset, .b = .uleb128_offset }),
- val_offset_sf: InstructionType(.{ .a = .uleb128_offset, .b = .sleb128_offset }),
- val_expression: InstructionType(.{ .a = .uleb128_offset, .block = .block }),
+ val_offset: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
+ val_offset_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
+ val_expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),
fn readOperands(
self: *Instruction,
@@ -292,7 +292,14 @@ pub const VirtualMachine = struct {
rule: RegisterRule = .{ .default = {} },
/// Resolves the register rule and places the result into `out` (see dwarf.abi.regBytes)
- pub fn resolveValue(self: Column, context: dwarf.UnwindContext, out: []u8) !void {
+ pub fn resolveValue(
+ self: Column,
+ context: *dwarf.UnwindContext,
+ compile_unit: ?*const dwarf.CompileUnit,
+ ucontext: *const std.os.ucontext_t,
+ reg_ctx: abi.RegisterContext,
+ out: []u8,
+ ) !void {
switch (self.rule) {
.default => {
const register = self.register orelse return error.InvalidRegister;
@@ -321,14 +328,21 @@ pub const VirtualMachine = struct {
@memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
},
.expression => |expression| {
- // TODO
- _ = expression;
- unreachable;
+ context.stack_machine.reset();
+ const value = try context.stack_machine.run(expression, context.allocator, compile_unit, ucontext, reg_ctx, context.cfa.?);
+
+ if (value != .generic) return error.InvalidExpressionValue;
+ if (!context.isValidMemory(value.generic)) return error.InvalidExpressionAddress;
+
+ const ptr: *usize = @ptrFromInt(value.generic);
+ mem.writeIntSliceNative(usize, out, ptr.*);
},
.val_expression => |expression| {
- // TODO
- _ = expression;
- unreachable;
+ context.stack_machine.reset();
+ const value = try context.stack_machine.run(expression, context.allocator, compile_unit, ucontext, reg_ctx, context.cfa.?);
+
+ if (value != .generic) return error.InvalidExpressionValue;
+ mem.writeIntSliceNative(usize, out, value.generic);
},
.architectural => return error.UnimplementedRule,
}
@@ -546,12 +560,16 @@ pub const VirtualMachine = struct {
.def_cfa_offset => |i| {
try self.resolveCopyOnWrite(allocator);
if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
- self.current_row.cfa.rule = .{ .val_offset = @intCast(i.operands.offset) };
+ self.current_row.cfa.rule = .{
+ .val_offset = @intCast(i.operands.offset),
+ };
},
.def_cfa_offset_sf => |i| {
try self.resolveCopyOnWrite(allocator);
if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
- self.current_row.cfa.rule = .{ .val_offset = i.operands.offset * cie.data_alignment_factor };
+ self.current_row.cfa.rule = .{
+ .val_offset = i.operands.offset * cie.data_alignment_factor,
+ };
},
.def_cfa_expression => |i| {
try self.resolveCopyOnWrite(allocator);
@@ -567,17 +585,26 @@ pub const VirtualMachine = struct {
.expression = i.operands.block,
};
},
- .val_offset => {
- // TODO: Implement
- unreachable;
+ .val_offset => |i| {
+ try self.resolveCopyOnWrite(allocator);
+ const column = try self.getOrAddColumn(allocator, i.operands.register);
+ column.rule = .{
+ .val_offset = @as(i64, @intCast(i.operands.offset)) * cie.data_alignment_factor,
+ };
},
- .val_offset_sf => {
- // TODO: Implement
- unreachable;
+ .val_offset_sf => |i| {
+ try self.resolveCopyOnWrite(allocator);
+ const column = try self.getOrAddColumn(allocator, i.operands.register);
+ column.rule = .{
+ .val_offset = i.operands.offset * cie.data_alignment_factor,
+ };
},
- .val_expression => {
- // TODO: Implement
- unreachable;
+ .val_expression => |i| {
+ try self.resolveCopyOnWrite(allocator);
+ const column = try self.getOrAddColumn(allocator, i.operands.register);
+ column.rule = .{
+ .val_expression = i.operands.block,
+ };
},
}
lib/std/dwarf/expressions.zig
@@ -2,6 +2,9 @@ const std = @import("std");
const builtin = @import("builtin");
const OP = @import("OP.zig");
const leb = @import("../leb128.zig");
+const dwarf = @import("../dwarf.zig");
+const abi = dwarf.abi;
+const mem = std.mem;
pub const StackMachineOptions = struct {
/// The address size of the target architecture
@@ -33,9 +36,10 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
};
return struct {
- const Value = union(enum) {
+ const Self = @This();
+
+ const Operand = union(enum) {
generic: addr_type,
- const_type: []const u8,
register: u8,
base_register: struct {
base_register: u8,
@@ -46,7 +50,11 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
offset: i64,
},
block: []const u8,
- base_type: struct {
+ register_type: struct {
+ register: u8,
+ type_offset: u64,
+ },
+ const_type: struct {
type_offset: u64,
value_bytes: []const u8,
},
@@ -56,9 +64,31 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
},
};
+ const Value = union(enum) {
+ generic: addr_type,
+ regval_type: struct {
+ // Offset of DW_TAG_base_type DIE
+ type_offset: u64,
+ value: addr_type,
+ },
+ const_type: struct {
+ // Offset of DW_TAG_base_type DIE
+ type_offset: u64,
+ value_bytes: []const u8,
+ },
+ };
+
stack: std.ArrayListUnmanaged(Value) = .{},
- fn generic(value: anytype) Value {
+ pub fn reset(self: *Self) void {
+ self.stack.clearRetainingCapacity();
+ }
+
+ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
+ self.stack.deinit(allocator);
+ }
+
+ fn generic(value: anytype) Operand {
const int_info = @typeInfo(@TypeOf(value)).Int;
if (@sizeOf(@TypeOf(value)) > options.addr_size) {
return .{ .generic = switch (int_info.signedness) {
@@ -73,7 +103,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
}
}
- pub fn readOperand(stream: *std.io.FixedBufferStream([]const u8), opcode: u8) !?Value {
+ pub fn readOperand(stream: *std.io.FixedBufferStream([]const u8), opcode: u8) !?Operand {
const reader = stream.reader();
return switch (opcode) {
OP.addr,
@@ -87,8 +117,8 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
OP.const1s => generic(try reader.readByteSigned()),
OP.const2u,
OP.call2,
- OP.call4,
=> generic(try reader.readInt(u16, options.endian)),
+ OP.call4 => generic(try reader.readInt(u32, options.endian)),
OP.const2s,
OP.bra,
OP.skip,
@@ -114,21 +144,35 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
.offset = try leb.readILEB128(i64, reader),
} },
OP.regx => .{ .register = try leb.readULEB128(u8, reader) },
- OP.bregx, OP.regval_type => .{ .base_register = .{
- .base_register = try leb.readULEB128(u8, reader),
- .offset = try leb.readILEB128(i64, 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(u64, 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 => .{
- .composite_location = .{
- .size = try leb.readULEB128(u8, reader),
- .offset = try leb.readILEB128(i64, reader),
- },
+ 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);
@@ -145,7 +189,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
const value_bytes = stream.buffer[stream.pos..][0..size];
stream.pos += size;
- break :blk .{ .base_type = .{
+ break :blk .{ .const_type = .{
.type_offset = type_offset,
.value_bytes = value_bytes,
} };
@@ -163,22 +207,144 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
};
}
+ pub fn run(
+ self: *Self,
+ expression: []const u8,
+ allocator: std.mem.Allocator,
+ compile_unit: ?*const dwarf.CompileUnit,
+ ucontext: *const std.os.ucontext_t,
+ reg_ctx: abi.RegisterContext,
+ initial_value: usize,
+ ) !Value {
+ try self.stack.append(allocator, .{ .generic = initial_value });
+ var stream = std.io.fixedBufferStream(expression);
+ while (try self.step(&stream, allocator, compile_unit, ucontext, reg_ctx)) {}
+ if (self.stack.items.len == 0) return error.InvalidExpression;
+ return self.stack.items[self.stack.items.len - 1];
+ }
+
+ /// Reads an opcode and its operands from the stream and executes it
pub fn step(
- self: *StackMachine,
- stream: std.io.FixedBufferStream([]const u8),
+ self: *Self,
+ stream: *std.io.FixedBufferStream([]const u8),
allocator: std.mem.Allocator,
- ) !void {
- if (@sizeOf(usize) != addr_type or options.endian != builtin.target.cpu.arch.endian())
+ compile_unit: ?*const dwarf.CompileUnit,
+ ucontext: *const std.os.ucontext_t,
+ reg_ctx: dwarf.abi.RegisterContext,
+ ) !bool {
+ if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != comptime builtin.target.cpu.arch.endian())
@compileError("Execution of non-native address sizees / endianness is not supported");
- const opcode = try stream.reader.readByte();
- _ = opcode;
- _ = self;
- _ = allocator;
+ const opcode = try stream.reader().readByte();
+ if (options.call_frame_mode) {
+ // Certain opcodes are not allowed in a CFA context, see 6.4.2
+ switch (opcode) {
+ OP.addrx,
+ OP.call2,
+ OP.call4,
+ OP.call_ref,
+ OP.const_type,
+ OP.constx,
+ OP.convert,
+ OP.deref_type,
+ OP.regval_type,
+ OP.reinterpret,
+ OP.push_object_address,
+ OP.call_frame_cfa,
+ => return error.InvalidCFAExpression,
+ else => {},
+ }
+ }
+
+ switch (opcode) {
+
+ // 2.5.1.1: Literal Encodings
+ OP.lit0...OP.lit31,
+ OP.addr,
+ OP.const1u,
+ OP.const2u,
+ OP.const4u,
+ OP.const8u,
+ OP.const1s,
+ OP.const2s,
+ OP.const4s,
+ OP.const8s,
+ OP.constu,
+ OP.consts,
+ => try self.stack.append(allocator, .{ .generic = (try readOperand(stream, opcode)).?.generic }),
+
+ OP.const_type => {
+ const const_type = (try readOperand(stream, opcode)).?.const_type;
+ try self.stack.append(allocator, .{ .const_type = .{
+ .type_offset = const_type.type_offset,
+ .value_bytes = const_type.value_bytes,
+ } });
+ },
+
+ OP.addrx, OP.constx => {
+ const debug_addr_index = (try readOperand(stream, opcode)).?.generic;
+
+ // TODO: Read item from .debug_addr, this requires need DW_AT_addr_base of the compile unit, push onto stack as generic
+
+ _ = debug_addr_index;
+ unreachable;
+ },
+
+ // 2.5.1.2: Register Values
+ OP.fbreg => {
+ if (compile_unit == null) return error.ExpressionRequiresCompileUnit;
+ if (compile_unit.?.frame_base == null) return error.ExpressionRequiresFrameBase;
+
+ const offset: i64 = @intCast((try readOperand(stream, opcode)).?.generic);
+ _ = offset;
+
+ switch (compile_unit.?.frame_base.?.*) {
+ .ExprLoc => {
+ // TODO: Run this expression in a nested stack machine
+ return error.UnimplementedOpcode;
+ },
+ .LocListOffset => {
+ // TODO: Read value from .debug_loclists
+ return error.UnimplementedOpcode;
+ },
+ .SecOffset => {
+ // TODO: Read value from .debug_loclists
+ return error.UnimplementedOpcode;
+ },
+ else => return error.InvalidFrameBase,
+ }
+ },
+ OP.breg0...OP.breg31, OP.bregx => {
+ const base_register = (try readOperand(stream, opcode)).?.base_register;
+ var value: i64 = @intCast(mem.readIntSliceNative(usize, try abi.regBytes(ucontext, base_register.base_register, reg_ctx)));
+ value += base_register.offset;
+ try self.stack.append(allocator, .{ .generic = @intCast(value) });
+ },
+ OP.regval_type => {
+ const register_type = (try readOperand(stream, opcode)).?.register_type;
+ const value = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, register_type.register, reg_ctx));
+ try self.stack.append(allocator, .{
+ .regval_type = .{
+ .value = value,
+ .type_offset = register_type.type_offset,
+ },
+ });
+ },
+
+ // 2.5.1.3: Stack Operations
+
+ OP.dup => {},
+
+ else => {
+ std.debug.print("Unimplemented DWARF expression opcode: {x}\n", .{opcode});
+ unreachable;
+ },
+
+ // These have already been handled by readOperand
+ OP.lo_user...OP.hi_user => unreachable,
+ }
- // switch (opcode) {
- // OP.addr => try self.stack.append(allocator, try readOperand(stream, opcode)),
- // }
+ return stream.pos < stream.buffer.len;
}
};
}
lib/std/debug.zig
@@ -483,16 +483,14 @@ pub const StackIterator = struct {
pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator {
var iterator = init(first_address, null);
iterator.debug_info = debug_info;
- iterator.dwarf_context = try DW.UnwindContext.init(context, &isValidMemory);
+ iterator.dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context, &isValidMemory);
iterator.last_error = null;
return iterator;
}
pub fn deinit(self: *StackIterator) void {
- if (have_ucontext) {
- if (self.debug_info) |debug_info| {
- self.dwarf_context.deinit(debug_info.allocator);
- }
+ if (have_ucontext and self.debug_info != null) {
+ self.dwarf_context.deinit();
}
}
@@ -599,7 +597,7 @@ pub const StackIterator = struct {
if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| {
self.dwarf_context.reg_ctx.eh_frame = true;
self.dwarf_context.reg_ctx.is_macho = di.is_macho;
- return di.unwindFrame(self.debug_info.?.allocator, &self.dwarf_context, module.base_address);
+ return di.unwindFrame(&self.dwarf_context, module.base_address);
} else return error.MissingDebugInfo;
}
lib/std/dwarf.zig
@@ -163,15 +163,9 @@ const PcRange = struct {
const Func = struct {
pc_range: ?PcRange,
name: ?[]const u8,
-
- fn deinit(func: *Func, allocator: mem.Allocator) void {
- if (func.name) |name| {
- allocator.free(name);
- }
- }
};
-const CompileUnit = struct {
+pub const CompileUnit = struct {
version: u16,
is_64: bool,
die: *Die,
@@ -181,6 +175,7 @@ const CompileUnit = struct {
addr_base: usize,
rnglists_base: usize,
loclists_base: usize,
+ frame_base: ?*const FormValue,
};
const AbbrevTable = std.ArrayList(AbbrevTableEntry);
@@ -216,7 +211,7 @@ const AbbrevAttr = struct {
payload: i64,
};
-const FormValue = union(enum) {
+pub const FormValue = union(enum) {
Address: u64,
AddrOffset: usize,
Block: []u8,
@@ -298,7 +293,7 @@ const Die = struct {
fn getAttrAddr(
self: *const Die,
- di: *DwarfInfo,
+ di: *const DwarfInfo,
id: u64,
compile_unit: CompileUnit,
) error{ InvalidDebugInfo, MissingDebugInfo }!u64 {
@@ -708,9 +703,6 @@ pub const DwarfInfo = struct {
allocator.destroy(cu.die);
}
di.compile_unit_list.deinit(allocator);
- for (di.func_list.items) |*func| {
- func.deinit(allocator);
- }
di.func_list.deinit(allocator);
di.cie_map.deinit(allocator);
di.fde_list.deinit(allocator);
@@ -793,6 +785,7 @@ pub const DwarfInfo = struct {
.addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
.rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
.loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
+ .frame_base = die_obj.getAttr(AT.frame_base),
};
},
TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {
@@ -802,8 +795,7 @@ pub const DwarfInfo = struct {
// Prevent endless loops
while (depth > 0) : (depth -= 1) {
if (this_die_obj.getAttr(AT.name)) |_| {
- const name = try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit);
- break :x try allocator.dupe(u8, name);
+ break :x try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit);
} else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
// Follow the DIE it points to and repeat
const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);
@@ -834,7 +826,7 @@ pub const DwarfInfo = struct {
break :x null;
};
- var found_range = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: {
+ var range_added = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: {
if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {
const pc_end = switch (high_pc_value.*) {
FormValue.Address => |value| value,
@@ -852,9 +844,11 @@ pub const DwarfInfo = struct {
.end = pc_end,
},
});
+
+ break :blk true;
}
- break :blk true;
+ break :blk false;
} else |err| blk: {
if (err != error.MissingDebugInfo) return err;
break :blk false;
@@ -867,7 +861,7 @@ pub const DwarfInfo = struct {
};
while (try iter.next()) |range| {
- found_range = true;
+ range_added = true;
try di.func_list.append(allocator, Func{
.name = fn_name,
.pc_range = .{
@@ -878,7 +872,7 @@ pub const DwarfInfo = struct {
}
}
- if (!found_range) {
+ if (fn_name != null and !range_added) {
try di.func_list.append(allocator, Func{
.name = fn_name,
.pc_range = null,
@@ -952,6 +946,7 @@ pub const DwarfInfo = struct {
.addr_base = if (compile_unit_die.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
.rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
.loclists_base = if (compile_unit_die.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
+ .frame_base = compile_unit_die.getAttr(AT.frame_base),
};
compile_unit.pc_range = x: {
@@ -987,11 +982,11 @@ pub const DwarfInfo = struct {
const DebugRangeIterator = struct {
base_address: u64,
section_type: DwarfSection,
- di: *DwarfInfo,
+ di: *const DwarfInfo,
compile_unit: *const CompileUnit,
stream: io.FixedBufferStream([]const u8),
- pub fn init(ranges_value: *const FormValue, di: *DwarfInfo, compile_unit: *const CompileUnit) !@This() {
+ pub fn init(ranges_value: *const FormValue, di: *const DwarfInfo, compile_unit: *const CompileUnit) !@This() {
const section_type = if (compile_unit.version >= 5) DwarfSection.debug_rnglists else DwarfSection.debug_ranges;
const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo;
@@ -1129,7 +1124,7 @@ pub const DwarfInfo = struct {
}
};
- pub fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
+ pub fn findCompileUnit(di: *const DwarfInfo, target_address: u64) !*const CompileUnit {
for (di.compile_unit_list.items) |*compile_unit| {
if (compile_unit.pc_range) |range| {
if (target_address >= range.start and target_address < range.end) return compile_unit;
@@ -1630,7 +1625,7 @@ pub const DwarfInfo = struct {
}
}
- pub fn unwindFrame(di: *const DwarfInfo, allocator: mem.Allocator, context: *UnwindContext, module_base_address: usize) !usize {
+ pub fn unwindFrame(di: *const DwarfInfo, context: *UnwindContext, module_base_address: usize) !usize {
if (!comptime abi.isSupportedArch(builtin.target.cpu.arch)) return error.UnsupportedCpuArchitecture;
if (context.pc == 0) return 0;
@@ -1678,10 +1673,11 @@ pub const DwarfInfo = struct {
cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE;
}
+ const compile_unit: ?*const CompileUnit = di.findCompileUnit(fde.pc_begin) catch null;
context.vm.reset();
context.reg_ctx.eh_frame = cie.version != 4;
- _ = try context.vm.runToNative(allocator, mapped_pc, cie, fde);
+ _ = try context.vm.runToNative(context.allocator, mapped_pc, cie, fde);
const row = &context.vm.current_row;
context.cfa = switch (row.cfa.rule) {
@@ -1690,12 +1686,19 @@ pub const DwarfInfo = struct {
const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
break :blk try call_frame.applyOffset(value, offset);
},
- .expression => |expression| {
-
- // TODO: Evaluate expression
- _ = expression;
-
- return error.UnimplementedTODO;
+ .expression => |expression| blk: {
+ context.stack_machine.reset();
+ const value = try context.stack_machine.run(
+ expression,
+ context.allocator,
+ compile_unit,
+ &context.ucontext,
+ context.reg_ctx,
+ context.cfa orelse 0,
+ );
+
+ if (value != .generic) return error.InvalidExpressionValue;
+ break :blk value.generic;
},
else => return error.InvalidCFARule,
};
@@ -1713,7 +1716,13 @@ pub const DwarfInfo = struct {
has_next_ip = column.rule != .undefined;
}
- try column.resolveValue(context.*, dest);
+ try column.resolveValue(
+ context,
+ compile_unit,
+ &context.ucontext,
+ context.reg_ctx,
+ dest,
+ );
}
}
@@ -1738,16 +1747,19 @@ pub const DwarfInfo = struct {
};
pub const UnwindContext = struct {
+ allocator: mem.Allocator,
cfa: ?usize,
pc: usize,
ucontext: os.ucontext_t,
reg_ctx: abi.RegisterContext,
isValidMemory: *const fn (address: usize) bool,
vm: call_frame.VirtualMachine = .{},
+ stack_machine: expressions.StackMachine(.{ .call_frame_mode = true }) = .{},
- pub fn init(ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
+ pub fn init(allocator: mem.Allocator, ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));
return .{
+ .allocator = allocator,
.cfa = null,
.pc = pc,
.ucontext = ucontext.*,
@@ -1756,8 +1768,9 @@ pub const UnwindContext = struct {
};
}
- pub fn deinit(self: *UnwindContext, allocator: mem.Allocator) void {
- self.vm.deinit(allocator);
+ pub fn deinit(self: *UnwindContext) void {
+ self.vm.deinit(self.allocator);
+ self.stack_machine.deinit(self.allocator);
}
pub fn getFp(self: *const UnwindContext) !usize {