diff --git a/std/debug/index.zig b/std/debug/index.zig index ec7f2ceb34..265e114cd5 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -62,6 +62,7 @@ fn wantTtyColor() bool { } /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. +/// TODO multithreaded awareness pub fn dumpCurrentStackTrace(start_addr: ?usize) void { const stderr = getStderrStream() catch return; const debug_info = getSelfDebugInfo() catch |err| { @@ -75,6 +76,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { } /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. +/// TODO multithreaded awareness pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { const stderr = getStderrStream() catch return; const debug_info = getSelfDebugInfo() catch |err| { @@ -460,6 +462,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); return DebugInfo{ + .ofiles = DebugInfo.OFileTable.init(allocator), .symbols = symbols, .strings = strings, }; @@ -511,10 +514,22 @@ const MachoSymbol = struct { } }; +const MachOFile = struct { + bytes: []align(@alignOf(std.c.mach_header_64)) const u8, +}; + pub const DebugInfo = switch (builtin.os) { builtin.Os.macosx => struct { symbols: []const MachoSymbol, strings: []const u8, + ofiles: OFileTable, + + const OFileTable = std.HashMap( + *std.c.nlist_64, + MachOFile, + std.hash_map.getHashPtrAddrFn(*std.c.nlist_64), + std.hash_map.getTrivialEqlFn(*std.c.nlist_64), + ); }, else => struct { self_exe_file: os.File, @@ -940,6 +955,44 @@ fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die } fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo { + const ofile = symbol.ofile orelse return error.MissingDebugInfo; + const gop = try di.ofiles.getOrPut(ofile); + const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: { + errdefer _ = di.ofiles.remove(ofile); + const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); + std.debug.warn("reading .o file: {}\n", ofile_path); + + gop.kv.value = MachOFile{ + .bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(std.c.mach_header_64)), + }; + const hdr = @ptrCast(*const std.c.mach_header_64, gop.kv.value.bytes.ptr); + assert(hdr.magic == std.c.MH_MAGIC_64); + + const hdr_base = @ptrCast([*]const u8, hdr); + var ptr = hdr_base + @sizeOf(std.c.mach_header_64); + var ncmd: u32 = hdr.ncmds; + const segcmd = while (ncmd != 0) : (ncmd -= 1) { + const lc = @ptrCast(*const std.c.load_command, ptr); + switch (lc.cmd) { + std.c.LC_SEGMENT_64 => break @ptrCast(*const std.c.segment_command_64, ptr), + else => {}, + } + ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403 + } else { + return error.MissingDebugInfo; + }; + const sections = @ptrCast([*]const std.c.section_64, ptr + @sizeOf(std.c.segment_command_64))[0..segcmd.nsects]; + for (sections) |sect| { + if (sect.flags & std.c.SECTION_TYPE == std.c.S_REGULAR and + (sect.flags & std.c.SECTION_ATTRIBUTES) & std.c.S_ATTR_DEBUG == std.c.S_ATTR_DEBUG) { + const sect_name = mem.toSliceConst(u8, §.sectname); + std.debug.warn("sect: {}\n", sect_name); + } + } + + break :blk &gop.kv.value; + }; + return error.MissingDebugInfo; } diff --git a/std/hash_map.zig b/std/hash_map.zig index 0c100e15d9..9654d612a5 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -408,6 +408,22 @@ test "iterator hash map" { assert(entry.value == values[0]); } +pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) { + return struct { + fn hash(key: K) u32 { + return getAutoHashFn(usize)(@ptrToInt(key)); + } + }.hash; +} + +pub fn getTrivialEqlFn(comptime K: type) (fn (K, K) bool) { + return struct { + fn eql(a: K, b: K) bool { + return a == b; + } + }.eql; +} + pub fn getAutoHashFn(comptime K: type) (fn (K) u32) { return struct { fn hash(key: K) u32 { diff --git a/std/index.zig b/std/index.zig index 59f54fa9d7..8dfc59b1d2 100644 --- a/std/index.zig +++ b/std/index.zig @@ -24,6 +24,7 @@ pub const empty_import = @import("empty.zig"); pub const event = @import("event.zig"); pub const fmt = @import("fmt/index.zig"); pub const hash = @import("hash/index.zig"); +pub const hash_map = @import("hash_map.zig"); pub const heap = @import("heap.zig"); pub const io = @import("io.zig"); pub const json = @import("json.zig");