mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
sky pirates! which are even better!
This commit is contained in:
parent
89d862180f
commit
3f6a90766c
@ -2,7 +2,7 @@
|
||||
|
||||
pub const VirtualMachine = @import("Unwind/VirtualMachine.zig");
|
||||
|
||||
frame_section: ?struct {
|
||||
frame_section: struct {
|
||||
id: Section,
|
||||
/// The virtual address of the start of the section. "Virtual address" refers to the address in
|
||||
/// the binary (e.g. `sh_addr` in an ELF file); the equivalent runtime address may be relocated
|
||||
@ -42,10 +42,41 @@ const SortedFdeEntry = struct {
|
||||
const Section = enum { debug_frame, eh_frame };
|
||||
|
||||
// MLUGG TODO deinit?
|
||||
pub const init: Unwind = .{
|
||||
.frame_section = null,
|
||||
.lookup = null,
|
||||
};
|
||||
|
||||
/// Initialize with unwind information from the contents of a `.debug_frame` or `.eh_frame` section.
|
||||
///
|
||||
/// If the `.eh_frame_hdr` section is available, consider instead using `initEhFrameHdr`. This
|
||||
/// allows the implementation to use a search table embedded in that section if it is available.
|
||||
pub fn initSection(section: Section, section_vaddr: u64, section_bytes: []const u8) Unwind {
|
||||
return .{
|
||||
.frame_section = .{
|
||||
.id = section,
|
||||
.bytes = section_bytes,
|
||||
.vaddr = section_vaddr,
|
||||
},
|
||||
.lookup = null,
|
||||
};
|
||||
}
|
||||
|
||||
/// Initialize with unwind information from a header loaded from an `.eh_frame_hdr` section, and a
|
||||
/// pointer to the contents of the `.eh_frame` section.
|
||||
///
|
||||
/// This differs from `loadFromSection` because `.eh_frame_hdr` may embed a binary search table, and
|
||||
/// if it does, this function will use that for address lookups instead of constructing our own
|
||||
/// search table.
|
||||
pub fn initEhFrameHdr(header: EhFrameHeader, section_vaddr: u64, section_bytes_ptr: [*]const u8) Unwind {
|
||||
return .{
|
||||
.frame_section = .{
|
||||
.id = .eh_frame,
|
||||
.bytes = maxSlice(section_bytes_ptr),
|
||||
.vaddr = header.eh_frame_vaddr,
|
||||
},
|
||||
.lookup = if (header.search_table) |table| .{ .eh_frame_hdr = .{
|
||||
.vaddr = section_vaddr,
|
||||
.table = table,
|
||||
} } else null,
|
||||
};
|
||||
}
|
||||
|
||||
/// This represents the decoded .eh_frame_hdr header
|
||||
pub const EhFrameHeader = struct {
|
||||
@ -371,51 +402,11 @@ pub const FrameDescriptionEntry = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// Load unwind information from the contents of an `.eh_frame` or `.debug_frame` section.
|
||||
///
|
||||
/// If the `.eh_frame_hdr` section is available, consider instead using `loadFromEhFrameHdr`. This
|
||||
/// allows the implementation to use a search table embedded in that section if it is available.
|
||||
pub fn loadFromSection(unwind: *Unwind, section: Section, section_vaddr: u64, section_bytes: []const u8) void {
|
||||
assert(unwind.frame_section == null);
|
||||
assert(unwind.lookup == null);
|
||||
unwind.frame_section = .{
|
||||
.id = section,
|
||||
.bytes = section_bytes,
|
||||
.vaddr = section_vaddr,
|
||||
};
|
||||
}
|
||||
|
||||
/// Load unwind information from a header loaded from an `.eh_frame_hdr` section, and a pointer to
|
||||
/// the contents of the `.eh_frame` section.
|
||||
///
|
||||
/// This differs from `loadFromSection` because `.eh_frame_hdr` may embed a binary search table, and
|
||||
/// if it does, this function will use that for address lookups instead of constructing our own
|
||||
/// search table.
|
||||
pub fn loadFromEhFrameHdr(
|
||||
unwind: *Unwind,
|
||||
header: EhFrameHeader,
|
||||
section_vaddr: u64,
|
||||
section_bytes_ptr: [*]const u8,
|
||||
) !void {
|
||||
assert(unwind.frame_section == null);
|
||||
assert(unwind.lookup == null);
|
||||
unwind.frame_section = .{
|
||||
.id = .eh_frame,
|
||||
.bytes = maxSlice(section_bytes_ptr),
|
||||
.vaddr = header.eh_frame_vaddr,
|
||||
};
|
||||
if (header.search_table) |table| {
|
||||
unwind.lookup = .{ .eh_frame_hdr = .{
|
||||
.vaddr = section_vaddr,
|
||||
.table = table,
|
||||
} };
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepareLookup(unwind: *Unwind, gpa: Allocator, addr_size_bytes: u8, endian: Endian) !void {
|
||||
const section = unwind.frame_section.?;
|
||||
if (unwind.lookup != null) return;
|
||||
|
||||
const section = unwind.frame_section;
|
||||
|
||||
var r: Reader = .fixed(section.bytes);
|
||||
var fde_list: std.ArrayList(SortedFdeEntry) = .empty;
|
||||
defer fde_list.deinit(gpa);
|
||||
@ -477,7 +468,7 @@ pub fn lookupPc(unwind: *const Unwind, pc: u64, addr_size_bytes: u8, endian: End
|
||||
addr_size_bytes,
|
||||
endian,
|
||||
) orelse return null;
|
||||
return std.math.sub(u64, fde_vaddr, unwind.frame_section.?.vaddr) catch bad(); // convert vaddr to offset
|
||||
return std.math.sub(u64, fde_vaddr, unwind.frame_section.vaddr) catch bad(); // convert vaddr to offset
|
||||
},
|
||||
.sorted_fdes => |sorted_fdes| sorted_fdes,
|
||||
};
|
||||
@ -493,7 +484,7 @@ pub fn lookupPc(unwind: *const Unwind, pc: u64, addr_size_bytes: u8, endian: End
|
||||
}
|
||||
|
||||
pub fn getFde(unwind: *const Unwind, fde_offset: u64, addr_size_bytes: u8, endian: Endian) !struct { Format, CommonInformationEntry, FrameDescriptionEntry } {
|
||||
const section = unwind.frame_section.?;
|
||||
const section = unwind.frame_section;
|
||||
|
||||
var fde_reader: Reader = .fixed(section.bytes[fde_offset..]);
|
||||
const fde_info = switch (try EntryHeader.read(&fde_reader, fde_offset, section.id, endian)) {
|
||||
|
||||
@ -73,44 +73,26 @@ pub fn deinit(self: *SelfInfo) void {
|
||||
|
||||
pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usize {
|
||||
comptime assert(target_supported);
|
||||
const module: Module = try .lookup(&self.lookup_cache, gpa, context.pc); // MLUGG TODO: don't take gpa
|
||||
const module: Module = try .lookup(&self.lookup_cache, gpa, context.pc);
|
||||
const gop = try self.modules.getOrPut(gpa, module.load_offset);
|
||||
if (!gop.found_existing) gop.value_ptr.* = .init;
|
||||
if (!gop.value_ptr.loaded_unwind) {
|
||||
try module.loadUnwindInfo(gpa, &gop.value_ptr.di);
|
||||
gop.value_ptr.loaded_unwind = true;
|
||||
}
|
||||
// MLUGG TODO: the stuff below is impl!
|
||||
if (native_os.isDarwin()) {
|
||||
// __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding
|
||||
// via DWARF before attempting to use the compact unwind info will produce incorrect results.
|
||||
if (gop.value_ptr.di.unwind_info) |unwind_info| {
|
||||
if (unwindFrameMachO(
|
||||
module.text_base,
|
||||
module.load_offset,
|
||||
context,
|
||||
unwind_info,
|
||||
gop.value_ptr.di.eh_frame,
|
||||
)) |return_address| {
|
||||
return return_address;
|
||||
} else |err| {
|
||||
if (err != error.RequiresDWARFUnwind) return err;
|
||||
}
|
||||
}
|
||||
return error.MissingUnwindInfo;
|
||||
}
|
||||
return unwindFrameDwarf(&gop.value_ptr.di.unwind, module.load_offset, context, null);
|
||||
return module.unwindFrame(gpa, &gop.value_ptr.di, context);
|
||||
}
|
||||
|
||||
pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std.debug.Symbol {
|
||||
comptime assert(target_supported);
|
||||
const module: Module = try .lookup(&self.lookup_cache, gpa, address); // MLUGG TODO: don't take gpa
|
||||
const module: Module = try .lookup(&self.lookup_cache, gpa, address);
|
||||
const gop = try self.modules.getOrPut(gpa, module.key());
|
||||
if (!gop.found_existing) gop.value_ptr.* = .init;
|
||||
if (!gop.value_ptr.loaded_debug) {
|
||||
// MLUGG TODO: this overloads the name 'debug info' with including vs excluding unwind info
|
||||
// figure out a better name for one or the other (i think the inner one is maybe 'symbol info' or something idk)
|
||||
try module.loadDebugInfo(gpa, &gop.value_ptr.di);
|
||||
gop.value_ptr.loaded_debug = true;
|
||||
}
|
||||
return module.getSymbolAtAddress(gpa, &gop.value_ptr.di, address);
|
||||
}
|
||||
@ -120,7 +102,7 @@ pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std.
|
||||
/// a path that doesn't rely on any side-effects of a prior successful module lookup.
|
||||
pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize) error{ Unexpected, OutOfMemory, MissingDebugInfo }![]const u8 {
|
||||
comptime assert(target_supported);
|
||||
const module: Module = try .lookup(&self.lookup_cache, gpa, address); // MLUGG TODO: don't take gpa
|
||||
const module: Module = try .lookup(&self.lookup_cache, gpa, address);
|
||||
return module.name;
|
||||
}
|
||||
|
||||
@ -251,6 +233,18 @@ const Module = switch (native_os) {
|
||||
},
|
||||
};
|
||||
}
|
||||
fn unwindFrame(module: *const Module, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize {
|
||||
_ = gpa;
|
||||
const unwind_info = di.unwind_info orelse return error.MissingUnwindInfo;
|
||||
// MLUGG TODO: inline
|
||||
return unwindFrameMachO(
|
||||
module.text_base,
|
||||
module.load_offset,
|
||||
context,
|
||||
unwind_info,
|
||||
di.eh_frame,
|
||||
);
|
||||
}
|
||||
const LookupCache = void;
|
||||
const DebugInfo = struct {
|
||||
mapped_memory: []align(std.heap.page_size_min) const u8,
|
||||
@ -499,12 +493,16 @@ const Module = switch (native_os) {
|
||||
const section_bytes = module.gnu_eh_frame orelse return error.MissingUnwindInfo; // MLUGG TODO: load from file
|
||||
const section_vaddr: u64 = @intFromPtr(section_bytes.ptr) - module.load_offset;
|
||||
const header: Dwarf.Unwind.EhFrameHeader = try .parse(section_vaddr, section_bytes, @sizeOf(usize), native_endian);
|
||||
try di.unwind.loadFromEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr));
|
||||
di.unwind = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr));
|
||||
try di.unwind.prepareLookup(gpa, @sizeOf(usize), native_endian);
|
||||
}
|
||||
fn getSymbolAtAddress(module: *const Module, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol {
|
||||
return di.em.getSymbolAtAddress(gpa, native_endian, module.load_offset, address);
|
||||
}
|
||||
fn unwindFrame(module: *const Module, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize {
|
||||
_ = gpa;
|
||||
return unwindFrameDwarf(&di.unwind, module.load_offset, context, null);
|
||||
}
|
||||
},
|
||||
.uefi, .windows => struct {
|
||||
base_address: usize,
|
||||
@ -1507,9 +1505,12 @@ fn unwindFrameMachO(
|
||||
.DWARF => {
|
||||
const eh_frame = opt_eh_frame orelse return error.MissingEhFrame;
|
||||
const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - load_offset;
|
||||
var dwarf_unwind: Dwarf.Unwind = .init;
|
||||
dwarf_unwind.loadFromSection(.eh_frame, eh_frame_vaddr, eh_frame);
|
||||
return unwindFrameDwarf(&dwarf_unwind, load_offset, context, @intCast(encoding.value.x86_64.dwarf));
|
||||
return unwindFrameDwarf(
|
||||
&.initSection(.eh_frame, eh_frame_vaddr, eh_frame),
|
||||
load_offset,
|
||||
context,
|
||||
@intCast(encoding.value.x86_64.dwarf),
|
||||
);
|
||||
},
|
||||
},
|
||||
.aarch64, .aarch64_be => switch (encoding.mode.arm64) {
|
||||
@ -1524,9 +1525,12 @@ fn unwindFrameMachO(
|
||||
.DWARF => {
|
||||
const eh_frame = opt_eh_frame orelse return error.MissingEhFrame;
|
||||
const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - load_offset;
|
||||
var dwarf_unwind: Dwarf.Unwind = .init;
|
||||
dwarf_unwind.loadFromSection(.eh_frame, eh_frame_vaddr, eh_frame);
|
||||
return unwindFrameDwarf(dwarf_unwind, load_offset, context, @intCast(encoding.value.arm64.dwarf));
|
||||
return unwindFrameDwarf(
|
||||
&.initSection(.eh_frame, eh_frame_vaddr, eh_frame),
|
||||
load_offset,
|
||||
context,
|
||||
@intCast(encoding.value.x86_64.dwarf),
|
||||
);
|
||||
},
|
||||
.FRAME => ip: {
|
||||
const frame = encoding.value.arm64.frame;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user