| ... | @@ -62,6 +62,7 @@ fn wantTtyColor() bool { | ... | @@ -62,6 +62,7 @@ fn wantTtyColor() bool { |
| 62 | } | 62 | } |
| 63 | | 63 | |
| 64 | /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. | 64 | /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. |
| | 65 | /// TODO multithreaded awareness |
| 65 | pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | 66 | pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 66 | const stderr = getStderrStream() catch return; | 67 | const stderr = getStderrStream() catch return; |
| 67 | const debug_info = getSelfDebugInfo() catch |err| { | 68 | const debug_info = getSelfDebugInfo() catch |err| { |
| ... | @@ -75,6 +76,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | ... | @@ -75,6 +76,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 75 | } | 76 | } |
| 76 | | 77 | |
| 77 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. | 78 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. |
| | 79 | /// TODO multithreaded awareness |
| 78 | pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { | 80 | pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { |
| 79 | const stderr = getStderrStream() catch return; | 81 | const stderr = getStderrStream() catch return; |
| 80 | const debug_info = getSelfDebugInfo() catch |err| { | 82 | const debug_info = getSelfDebugInfo() catch |err| { |
| ... | @@ -460,6 +462,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -460,6 +462,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| 460 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); | 462 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); |
| 461 | | 463 | |
| 462 | return DebugInfo{ | 464 | return DebugInfo{ |
| | 465 | .ofiles = DebugInfo.OFileTable.init(allocator), |
| 463 | .symbols = symbols, | 466 | .symbols = symbols, |
| 464 | .strings = strings, | 467 | .strings = strings, |
| 465 | }; | 468 | }; |
| ... | @@ -511,10 +514,22 @@ const MachoSymbol = struct { | ... | @@ -511,10 +514,22 @@ const MachoSymbol = struct { |
| 511 | } | 514 | } |
| 512 | }; | 515 | }; |
| 513 | | 516 | |
| | 517 | const MachOFile = struct { |
| | 518 | bytes: []align(@alignOf(std.c.mach_header_64)) const u8, |
| | 519 | }; |
| | 520 | |
| 514 | pub const DebugInfo = switch (builtin.os) { | 521 | pub const DebugInfo = switch (builtin.os) { |
| 515 | builtin.Os.macosx => struct { | 522 | builtin.Os.macosx => struct { |
| 516 | symbols: []const MachoSymbol, | 523 | symbols: []const MachoSymbol, |
| 517 | strings: []const u8, | 524 | strings: []const u8, |
| | 525 | ofiles: OFileTable, |
| | 526 | |
| | 527 | const OFileTable = std.HashMap( |
| | 528 | *std.c.nlist_64, |
| | 529 | MachOFile, |
| | 530 | std.hash_map.getHashPtrAddrFn(*std.c.nlist_64), |
| | 531 | std.hash_map.getTrivialEqlFn(*std.c.nlist_64), |
| | 532 | ); |
| 518 | }, | 533 | }, |
| 519 | else => struct { | 534 | else => struct { |
| 520 | self_exe_file: os.File, | 535 | self_exe_file: os.File, |
| ... | @@ -940,6 +955,44 @@ fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die | ... | @@ -940,6 +955,44 @@ fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die |
| 940 | } | 955 | } |
| 941 | | 956 | |
| 942 | fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo { | 957 | fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo { |
| | 958 | const ofile = symbol.ofile orelse return error.MissingDebugInfo; |
| | 959 | const gop = try di.ofiles.getOrPut(ofile); |
| | 960 | const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: { |
| | 961 | errdefer _ = di.ofiles.remove(ofile); |
| | 962 | const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); |
| | 963 | std.debug.warn("reading .o file: {}\n", ofile_path); |
| | 964 | |
| | 965 | gop.kv.value = MachOFile{ |
| | 966 | .bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(std.c.mach_header_64)), |
| | 967 | }; |
| | 968 | const hdr = @ptrCast(*const std.c.mach_header_64, gop.kv.value.bytes.ptr); |
| | 969 | assert(hdr.magic == std.c.MH_MAGIC_64); |
| | 970 | |
| | 971 | const hdr_base = @ptrCast([*]const u8, hdr); |
| | 972 | var ptr = hdr_base + @sizeOf(std.c.mach_header_64); |
| | 973 | var ncmd: u32 = hdr.ncmds; |
| | 974 | const segcmd = while (ncmd != 0) : (ncmd -= 1) { |
| | 975 | const lc = @ptrCast(*const std.c.load_command, ptr); |
| | 976 | switch (lc.cmd) { |
| | 977 | std.c.LC_SEGMENT_64 => break @ptrCast(*const std.c.segment_command_64, ptr), |
| | 978 | else => {}, |
| | 979 | } |
| | 980 | ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403 |
| | 981 | } else { |
| | 982 | return error.MissingDebugInfo; |
| | 983 | }; |
| | 984 | const sections = @ptrCast([*]const std.c.section_64, ptr + @sizeOf(std.c.segment_command_64))[0..segcmd.nsects]; |
| | 985 | for (sections) |sect| { |
| | 986 | if (sect.flags & std.c.SECTION_TYPE == std.c.S_REGULAR and |
| | 987 | (sect.flags & std.c.SECTION_ATTRIBUTES) & std.c.S_ATTR_DEBUG == std.c.S_ATTR_DEBUG) { |
| | 988 | const sect_name = mem.toSliceConst(u8, &sect.sectname); |
| | 989 | std.debug.warn("sect: {}\n", sect_name); |
| | 990 | } |
| | 991 | } |
| | 992 | |
| | 993 | break :blk &gop.kv.value; |
| | 994 | }; |
| | 995 | |
| 943 | return error.MissingDebugInfo; | 996 | return error.MissingDebugInfo; |
| 944 | } | 997 | } |
| 945 | | 998 | |