DoxigAlpha

step

Executes a single instruction. If this instruction is from the CIE, is_initial should be set. Returns the value of current_row before executing this instruction.

Function parameters

Parameters

#
self:*VirtualMachine
allocator:std.mem.Allocator
cie:std.debug.Dwarf.CommonInformationEntry
is_initial:bool
instruction:Dwarf.call_frame.Instruction

How is this different than `Module` when the host is Windows?

Types

#
WindowsModule
How is this different than `Module` when the host is Windows?
VirtualMachine
This is a virtual machine that runs DWARF call frame instructions.

Functions in this namespace

Functions

#
readElfDebugInfo
Reads debug info from an ELF file, or the current binary if none in specified.
unwindFrameMachO
Unwind a frame using MachO compact unwind info (from __unwind_info).
stripInstructionPtrAuthCode
Some platforms use pointer authentication - the upper bits of instruction pointers contain a signature.
unwindFrameDwarf
Unwind a stack frame using DWARF unwinding info, updating the register context.
supportsUnwinding
Tells whether unwinding for this target is *implemented* here in the Zig

Error sets in this namespace

Error Sets

#

Tells whether unwinding for the host is implemented.

Values

#
supports_unwinding
Tells whether unwinding for the host is implemented.

Source

Implementation

#
pub fn step(
    self: *VirtualMachine,
    allocator: std.mem.Allocator,
    cie: std.debug.Dwarf.CommonInformationEntry,
    is_initial: bool,
    instruction: Dwarf.call_frame.Instruction,
) !Row {
    // CIE instructions must be run before FDE instructions
    assert(!is_initial or self.cie_row == null);
    if (!is_initial and self.cie_row == null) {
        self.cie_row = self.current_row;
        self.current_row.copy_on_write = true;
    }

    const prev_row = self.current_row;
    switch (instruction) {
        .set_loc => |i| {
            if (i.address <= self.current_row.offset) return error.InvalidOperation;
            // TODO: Check cie.segment_selector_size != 0 for DWARFV4
            self.current_row.offset = i.address;
        },
        inline .advance_loc,
        .advance_loc1,
        .advance_loc2,
        .advance_loc4,
        => |i| {
            self.current_row.offset += i.delta * cie.code_alignment_factor;
            self.current_row.copy_on_write = true;
        },
        inline .offset,
        .offset_extended,
        .offset_extended_sf,
        => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{ .offset = @as(i64, @intCast(i.offset)) * cie.data_alignment_factor };
        },
        inline .restore,
        .restore_extended,
        => |i| {
            try self.resolveCopyOnWrite(allocator);
            if (self.cie_row) |cie_row| {
                const column = try self.getOrAddColumn(allocator, i.register);
                column.rule = for (self.rowColumns(cie_row)) |cie_column| {
                    if (cie_column.register == i.register) break cie_column.rule;
                } else .{ .default = {} };
            } else return error.InvalidOperation;
        },
        .nop => {},
        .undefined => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{ .undefined = {} };
        },
        .same_value => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{ .same_value = {} };
        },
        .register => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{ .register = i.target_register };
        },
        .remember_state => {
            try self.stack.append(allocator, self.current_row.columns);
            self.current_row.copy_on_write = true;
        },
        .restore_state => {
            const restored_columns = self.stack.pop() orelse return error.InvalidOperation;
            self.columns.shrinkRetainingCapacity(self.columns.items.len - self.current_row.columns.len);
            try self.columns.ensureUnusedCapacity(allocator, restored_columns.len);

            self.current_row.columns.start = self.columns.items.len;
            self.current_row.columns.len = restored_columns.len;
            self.columns.appendSliceAssumeCapacity(self.columns.items[restored_columns.start..][0..restored_columns.len]);
        },
        .def_cfa => |i| {
            try self.resolveCopyOnWrite(allocator);
            self.current_row.cfa = .{
                .register = i.register,
                .rule = .{ .val_offset = @intCast(i.offset) },
            };
        },
        .def_cfa_sf => |i| {
            try self.resolveCopyOnWrite(allocator);
            self.current_row.cfa = .{
                .register = i.register,
                .rule = .{ .val_offset = i.offset * cie.data_alignment_factor },
            };
        },
        .def_cfa_register => |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.register = i.register;
        },
        .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.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.offset * cie.data_alignment_factor,
            };
        },
        .def_cfa_expression => |i| {
            try self.resolveCopyOnWrite(allocator);
            self.current_row.cfa.register = undefined;
            self.current_row.cfa.rule = .{
                .expression = i.block,
            };
        },
        .expression => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{
                .expression = i.block,
            };
        },
        .val_offset => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{
                .val_offset = @as(i64, @intCast(i.offset)) * cie.data_alignment_factor,
            };
        },
        .val_offset_sf => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{
                .val_offset = i.offset * cie.data_alignment_factor,
            };
        },
        .val_expression => |i| {
            try self.resolveCopyOnWrite(allocator);
            const column = try self.getOrAddColumn(allocator, i.register);
            column.rule = .{
                .val_expression = i.block,
            };
        },
    }

    return prev_row;
}