mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
- add default register rule
- fixup eh pointer decoding
This commit is contained in:
parent
a0a40c2e7e
commit
69399fbb82
@ -1494,18 +1494,34 @@ pub const DwarfInfo = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const id_len = @as(u8, if (is_64) 8 else 4);
|
const id_len = @as(u8, if (is_64) 8 else 4);
|
||||||
const entry_bytes = eh_frame[stream.pos..][0..length - id_len];
|
const entry_bytes = eh_frame[stream.pos..][0 .. length - id_len];
|
||||||
const id = try reader.readInt(u32, di.endian);
|
const id = try reader.readInt(u32, di.endian);
|
||||||
|
|
||||||
// TODO: Get section_offset here (pass in from headers)
|
// TODO: Get section_offset here (pass in from headers)
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
const cie = try CommonInformationEntry.parse(entry_bytes, @ptrToInt(eh_frame.ptr), 0, length_offset, @sizeOf(usize), di.endian);
|
const cie = try CommonInformationEntry.parse(
|
||||||
|
entry_bytes,
|
||||||
|
@ptrToInt(eh_frame.ptr),
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
length_offset,
|
||||||
|
@sizeOf(usize),
|
||||||
|
di.endian,
|
||||||
|
);
|
||||||
try di.cie_map.put(allocator, length_offset, cie);
|
try di.cie_map.put(allocator, length_offset, cie);
|
||||||
} else {
|
} else {
|
||||||
const cie_offset = stream.pos - 4 - id;
|
const cie_offset = stream.pos - 4 - id;
|
||||||
const cie = di.cie_map.get(cie_offset) orelse return badDwarf();
|
const cie = di.cie_map.get(cie_offset) orelse return badDwarf();
|
||||||
const fde = try FrameDescriptionEntry.parse(entry_bytes, @ptrToInt(eh_frame.ptr), 0, cie, @sizeOf(usize), di.endian);
|
const fde = try FrameDescriptionEntry.parse(
|
||||||
|
entry_bytes,
|
||||||
|
@ptrToInt(eh_frame.ptr),
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
cie,
|
||||||
|
@sizeOf(usize),
|
||||||
|
di.endian,
|
||||||
|
);
|
||||||
try di.fde_list.append(allocator, fde);
|
try di.fde_list.append(allocator, fde);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1557,6 +1573,11 @@ const EhPointerContext = struct {
|
|||||||
// The address of the pointer field itself
|
// The address of the pointer field itself
|
||||||
pc_rel_base: u64,
|
pc_rel_base: u64,
|
||||||
|
|
||||||
|
// Whether or not to follow indirect pointers. This should only be
|
||||||
|
// used when decoding pointers at runtime using the current process's
|
||||||
|
// debug info.
|
||||||
|
follow_indirect: bool,
|
||||||
|
|
||||||
// These relative addressing modes are only used in specific cases, and
|
// These relative addressing modes are only used in specific cases, and
|
||||||
// might not be available / required in all parsing contexts
|
// might not be available / required in all parsing contexts
|
||||||
data_rel_base: ?u64 = null,
|
data_rel_base: ?u64 = null,
|
||||||
@ -1570,7 +1591,7 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo
|
|||||||
const value: union(enum) {
|
const value: union(enum) {
|
||||||
signed: i64,
|
signed: i64,
|
||||||
unsigned: u64,
|
unsigned: u64,
|
||||||
} = switch (enc & 0x0f) {
|
} = switch (enc & EH.PE.type_mask) {
|
||||||
EH.PE.absptr => .{
|
EH.PE.absptr => .{
|
||||||
.unsigned = switch (addr_size_bytes) {
|
.unsigned = switch (addr_size_bytes) {
|
||||||
2 => try reader.readInt(u16, endian),
|
2 => try reader.readInt(u16, endian),
|
||||||
@ -1590,33 +1611,31 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo
|
|||||||
else => return badDwarf(),
|
else => return badDwarf(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const relative_to = enc & 0xf0;
|
var base = switch (enc & EH.PE.rel_mask) {
|
||||||
var base = switch (relative_to) {
|
|
||||||
EH.PE.pcrel => ctx.pc_rel_base,
|
EH.PE.pcrel => ctx.pc_rel_base,
|
||||||
EH.PE.textrel => ctx.text_rel_base orelse return error.PointerBaseNotSpecified,
|
EH.PE.textrel => ctx.text_rel_base orelse return error.PointerBaseNotSpecified,
|
||||||
EH.PE.datarel => ctx.data_rel_base orelse return error.PointerBaseNotSpecified,
|
EH.PE.datarel => ctx.data_rel_base orelse return error.PointerBaseNotSpecified,
|
||||||
EH.PE.funcrel => ctx.function_rel_base orelse return error.PointerBaseNotSpecified,
|
EH.PE.funcrel => ctx.function_rel_base orelse return error.PointerBaseNotSpecified,
|
||||||
EH.PE.indirect => {
|
|
||||||
switch (addr_size_bytes) {
|
|
||||||
2 => return @intToPtr(*const u16, value.unsigned).*,
|
|
||||||
4 => return @intToPtr(*const u32, value.unsigned).*,
|
|
||||||
8 => return @intToPtr(*const u64, value.unsigned).*,
|
|
||||||
else => return error.UnsupportedAddrSize,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => null,
|
else => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (base) |b| {
|
const ptr = if (base) |b| switch (value) {
|
||||||
return switch (value) {
|
.signed => |s| @intCast(u64, s + @intCast(i64, b)),
|
||||||
.signed => |s| @intCast(u64, s + @intCast(i64, b)),
|
.unsigned => |u| u + b,
|
||||||
.unsigned => |u| u + b,
|
} else switch (value) {
|
||||||
|
.signed => |s| @intCast(u64, s),
|
||||||
|
.unsigned => |u| u,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((enc & EH.PE.indirect) > 0 and ctx.follow_indirect) {
|
||||||
|
return switch (addr_size_bytes) {
|
||||||
|
2 => return @intToPtr(*const u16, ptr).*,
|
||||||
|
4 => return @intToPtr(*const u32, ptr).*,
|
||||||
|
8 => return @intToPtr(*const u64, ptr).*,
|
||||||
|
else => return error.UnsupportedAddrSize,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return switch (value) {
|
return ptr;
|
||||||
.signed => |s| @intCast(u64, s),
|
|
||||||
.unsigned => |u| u,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1668,6 +1687,7 @@ pub const CommonInformationEntry = struct {
|
|||||||
cie_bytes: []const u8,
|
cie_bytes: []const u8,
|
||||||
section_base: u64,
|
section_base: u64,
|
||||||
section_offset: u64,
|
section_offset: u64,
|
||||||
|
is_runtime: bool,
|
||||||
length_offset: u64,
|
length_offset: u64,
|
||||||
addr_size_bytes: u8,
|
addr_size_bytes: u8,
|
||||||
endian: std.builtin.Endian,
|
endian: std.builtin.Endian,
|
||||||
@ -1735,7 +1755,10 @@ pub const CommonInformationEntry = struct {
|
|||||||
reader,
|
reader,
|
||||||
personality_enc.?,
|
personality_enc.?,
|
||||||
addr_size_bytes,
|
addr_size_bytes,
|
||||||
.{ .pc_rel_base = @ptrToInt(&cie_bytes[stream.pos]) - section_base + section_offset },
|
.{
|
||||||
|
.pc_rel_base = @ptrToInt(&cie_bytes[stream.pos]) - section_base + section_offset,
|
||||||
|
.follow_indirect = is_runtime,
|
||||||
|
},
|
||||||
endian,
|
endian,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -1785,6 +1808,7 @@ pub const FrameDescriptionEntry = struct {
|
|||||||
fde_bytes: []const u8,
|
fde_bytes: []const u8,
|
||||||
section_base: u64,
|
section_base: u64,
|
||||||
section_offset: u64,
|
section_offset: u64,
|
||||||
|
is_runtime: bool,
|
||||||
cie: CommonInformationEntry,
|
cie: CommonInformationEntry,
|
||||||
addr_size_bytes: u8,
|
addr_size_bytes: u8,
|
||||||
endian: std.builtin.Endian,
|
endian: std.builtin.Endian,
|
||||||
@ -1798,15 +1822,21 @@ pub const FrameDescriptionEntry = struct {
|
|||||||
reader,
|
reader,
|
||||||
cie.fde_pointer_enc,
|
cie.fde_pointer_enc,
|
||||||
addr_size_bytes,
|
addr_size_bytes,
|
||||||
.{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset },
|
.{
|
||||||
|
.pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset,
|
||||||
|
.follow_indirect = is_runtime,
|
||||||
|
},
|
||||||
endian,
|
endian,
|
||||||
) orelse return badDwarf();
|
) orelse return badDwarf();
|
||||||
|
|
||||||
const pc_range = try readEhPointer(
|
const pc_range = try readEhPointer(
|
||||||
reader,
|
reader,
|
||||||
cie.fde_pointer_enc & 0x0f,
|
cie.fde_pointer_enc,
|
||||||
addr_size_bytes,
|
addr_size_bytes,
|
||||||
.{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset },
|
.{
|
||||||
|
.pc_rel_base = 0,
|
||||||
|
.follow_indirect = false,
|
||||||
|
},
|
||||||
endian,
|
endian,
|
||||||
) orelse return badDwarf();
|
) orelse return badDwarf();
|
||||||
|
|
||||||
@ -1819,9 +1849,12 @@ pub const FrameDescriptionEntry = struct {
|
|||||||
const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit)
|
const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit)
|
||||||
try readEhPointer(
|
try readEhPointer(
|
||||||
reader,
|
reader,
|
||||||
cie.lsda_pointer_enc & 0x0f,
|
cie.lsda_pointer_enc,
|
||||||
addr_size_bytes,
|
addr_size_bytes,
|
||||||
.{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) },
|
.{
|
||||||
|
.pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset,
|
||||||
|
.follow_indirect = is_runtime,
|
||||||
|
},
|
||||||
endian,
|
endian,
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
pub const PE = struct {
|
pub const PE = struct {
|
||||||
pub const absptr = 0x00;
|
pub const absptr = 0x00;
|
||||||
|
|
||||||
|
pub const size_mask = 0x7;
|
||||||
|
pub const sign_mask = 0x8;
|
||||||
|
pub const type_mask = size_mask | sign_mask;
|
||||||
|
|
||||||
pub const uleb128 = 0x01;
|
pub const uleb128 = 0x01;
|
||||||
pub const udata2 = 0x02;
|
pub const udata2 = 0x02;
|
||||||
pub const udata4 = 0x03;
|
pub const udata4 = 0x03;
|
||||||
@ -10,11 +14,13 @@ pub const PE = struct {
|
|||||||
pub const sdata4 = 0x0B;
|
pub const sdata4 = 0x0B;
|
||||||
pub const sdata8 = 0x0C;
|
pub const sdata8 = 0x0C;
|
||||||
|
|
||||||
|
pub const rel_mask = 0x70;
|
||||||
pub const pcrel = 0x10;
|
pub const pcrel = 0x10;
|
||||||
pub const textrel = 0x20;
|
pub const textrel = 0x20;
|
||||||
pub const datarel = 0x30;
|
pub const datarel = 0x30;
|
||||||
pub const funcrel = 0x40;
|
pub const funcrel = 0x40;
|
||||||
pub const aligned = 0x50;
|
pub const aligned = 0x50;
|
||||||
|
|
||||||
pub const indirect = 0x80;
|
pub const indirect = 0x80;
|
||||||
|
|
||||||
pub const omit = 0xff;
|
pub const omit = 0xff;
|
||||||
|
|||||||
@ -216,16 +216,35 @@ pub const Instruction = union(Opcode) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// See section 6.4.1 of the DWARF5 specification
|
/// This is a virtual machine that runs DWARF call frame instructions.
|
||||||
|
/// See section 6.4.1 of the DWARF5 specification.
|
||||||
pub const VirtualMachine = struct {
|
pub const VirtualMachine = struct {
|
||||||
|
|
||||||
const RegisterRule = union(enum) {
|
const RegisterRule = union(enum) {
|
||||||
|
// The spec says that the default rule for each column is the undefined rule.
|
||||||
|
// However, it also allows ABI / compiler authors to specify alternate defaults, so
|
||||||
|
// there is a distinction made here.
|
||||||
|
default: void,
|
||||||
|
|
||||||
undefined: void,
|
undefined: void,
|
||||||
same_value: void,
|
same_value: void,
|
||||||
|
|
||||||
|
// offset(N)
|
||||||
offset: i64,
|
offset: i64,
|
||||||
|
|
||||||
|
// val_offset(N)
|
||||||
val_offset: i64,
|
val_offset: i64,
|
||||||
|
|
||||||
|
// register(R)
|
||||||
register: u8,
|
register: u8,
|
||||||
|
|
||||||
|
// expression(E)
|
||||||
expression: []const u8,
|
expression: []const u8,
|
||||||
|
|
||||||
|
// val_expression(E)
|
||||||
val_expression: []const u8,
|
val_expression: []const u8,
|
||||||
|
|
||||||
|
// Augmenter-defined rule
|
||||||
architectural: void,
|
architectural: void,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -248,7 +267,7 @@ pub const VirtualMachine = struct {
|
|||||||
pub const Column = struct {
|
pub const Column = struct {
|
||||||
/// Register can only null in the case of the CFA column
|
/// Register can only null in the case of the CFA column
|
||||||
register: ?u8 = null,
|
register: ?u8 = null,
|
||||||
rule: RegisterRule = .{ .undefined = {} },
|
rule: RegisterRule = .{ .default = {} },
|
||||||
};
|
};
|
||||||
|
|
||||||
const ColumnRange = struct {
|
const ColumnRange = struct {
|
||||||
@ -264,13 +283,6 @@ pub const VirtualMachine = struct {
|
|||||||
/// The result of executing the CIE's initial_instructions
|
/// The result of executing the CIE's initial_instructions
|
||||||
cie_row: ?Row = null,
|
cie_row: ?Row = null,
|
||||||
|
|
||||||
pub fn reset(self: *VirtualMachine) void {
|
|
||||||
self.stack.clearRetainingCapacity();
|
|
||||||
self.columns.clearRetainingCapacity();
|
|
||||||
self.current_row = .{};
|
|
||||||
self.cie_row = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void {
|
pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void {
|
||||||
self.stack.deinit(allocator);
|
self.stack.deinit(allocator);
|
||||||
self.columns.deinit(allocator);
|
self.columns.deinit(allocator);
|
||||||
@ -357,7 +369,7 @@ pub const VirtualMachine = struct {
|
|||||||
|
|
||||||
/// Executes a single instruction.
|
/// Executes a single instruction.
|
||||||
/// If this instruction is from the CIE, `is_initial` should be set.
|
/// If this instruction is from the CIE, `is_initial` should be set.
|
||||||
/// Returns the value of `current_row` before executing this instruction
|
/// Returns the value of `current_row` before executing this instruction.
|
||||||
pub fn step(
|
pub fn step(
|
||||||
self: *VirtualMachine,
|
self: *VirtualMachine,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
@ -367,13 +379,16 @@ pub const VirtualMachine = struct {
|
|||||||
) !Row {
|
) !Row {
|
||||||
// CIE instructions must be run before FDE instructions
|
// CIE instructions must be run before FDE instructions
|
||||||
assert(!is_initial or self.cie_row == null);
|
assert(!is_initial or self.cie_row == null);
|
||||||
if (!is_initial and self.cie_row == null) self.cie_row = self.current_row;
|
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;
|
const prev_row = self.current_row;
|
||||||
switch (instruction) {
|
switch (instruction) {
|
||||||
.set_loc => |i| {
|
.set_loc => |i| {
|
||||||
if (i.operands.address <= self.current_row.offset) return error.InvalidOperation;
|
if (i.operands.address <= self.current_row.offset) return error.InvalidOperation;
|
||||||
// TODO: Check cie.segment_selector_size != for DWARFV4
|
// TODO: Check cie.segment_selector_size != 0 for DWARFV4
|
||||||
self.current_row.offset = i.operands.address;
|
self.current_row.offset = i.operands.address;
|
||||||
},
|
},
|
||||||
inline .advance_loc,
|
inline .advance_loc,
|
||||||
@ -392,11 +407,6 @@ pub const VirtualMachine = struct {
|
|||||||
const column = try self.getOrAddColumn(allocator, i.operands.register);
|
const column = try self.getOrAddColumn(allocator, i.operands.register);
|
||||||
column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor };
|
column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor };
|
||||||
},
|
},
|
||||||
// .offset_extended_sf => |i| {
|
|
||||||
// try self.resolveCopyOnWrite(allocator);
|
|
||||||
// const column = try self.getOrAddColumn(allocator, i.operands.register);
|
|
||||||
// column.rule = .{ .offset = i.operands.offset * cie.data_alignment_factor };
|
|
||||||
// },
|
|
||||||
inline .restore,
|
inline .restore,
|
||||||
.restore_extended,
|
.restore_extended,
|
||||||
=> |i| {
|
=> |i| {
|
||||||
@ -405,7 +415,7 @@ pub const VirtualMachine = struct {
|
|||||||
const column = try self.getOrAddColumn(allocator, i.operands.register);
|
const column = try self.getOrAddColumn(allocator, i.operands.register);
|
||||||
column.rule = for (self.rowColumns(cie_row)) |cie_column| {
|
column.rule = for (self.rowColumns(cie_row)) |cie_column| {
|
||||||
if (cie_column.register == i.operands.register) break cie_column.rule;
|
if (cie_column.register == i.operands.register) break cie_column.rule;
|
||||||
} else .{ .undefined = {} };
|
} else .{ .default = {} };
|
||||||
} else return error.InvalidOperation;
|
} else return error.InvalidOperation;
|
||||||
},
|
},
|
||||||
.nop => {},
|
.nop => {},
|
||||||
@ -427,13 +437,6 @@ pub const VirtualMachine = struct {
|
|||||||
.remember_state => {
|
.remember_state => {
|
||||||
try self.stack.append(allocator, self.current_row.columns);
|
try self.stack.append(allocator, self.current_row.columns);
|
||||||
self.current_row.copy_on_write = true;
|
self.current_row.copy_on_write = true;
|
||||||
|
|
||||||
// const new_start = self.columns.items.len;
|
|
||||||
// if (self.current_row.columns.len > 0) {
|
|
||||||
// try self.columns.ensureUnusedCapacity(allocator, self.current_row.columns.len);
|
|
||||||
// self.columns.appendSliceAssumeCapacity(self.rowColumns(self.current_row));
|
|
||||||
// self.current_row.columns.start = new_start;
|
|
||||||
// }
|
|
||||||
},
|
},
|
||||||
.restore_state => {
|
.restore_state => {
|
||||||
const restored_columns = self.stack.popOrNull() orelse return error.InvalidOperation;
|
const restored_columns = self.stack.popOrNull() orelse return error.InvalidOperation;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user