authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-23 23:08:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-23 23:08:34-04:00
log3173c90f14c2729e129c409d2191fa2e28d2eba6
treee90d16c8a6bd1d93e54ee4347da6ae1508abf440
parent5c1ec20c9a5c788af9f3402b9a065389eb818e76

macos stack traces: read debug info sections from .o files


3 files changed, 70 insertions(+), 0 deletions(-)

std/debug/index.zig+53
...@@ -62,6 +62,7 @@ fn wantTtyColor() bool {...@@ -62,6 +62,7 @@ fn wantTtyColor() bool {
62}62}
6363
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
65pub fn dumpCurrentStackTrace(start_addr: ?usize) void {66pub 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}
7677
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
78pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {80pub 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);
461463
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};
513516
517const MachOFile = struct {
518 bytes: []align(@alignOf(std.c.mach_header_64)) const u8,
519};
520
514pub const DebugInfo = switch (builtin.os) {521pub 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}
941956
942fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {957fn 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}
945998
std/hash_map.zig+16
...@@ -408,6 +408,22 @@ test "iterator hash map" {...@@ -408,6 +408,22 @@ test "iterator hash map" {
408 assert(entry.value == values[0]);408 assert(entry.value == values[0]);
409}409}
410410
411pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
412 return struct {
413 fn hash(key: K) u32 {
414 return getAutoHashFn(usize)(@ptrToInt(key));
415 }
416 }.hash;
417}
418
419pub fn getTrivialEqlFn(comptime K: type) (fn (K, K) bool) {
420 return struct {
421 fn eql(a: K, b: K) bool {
422 return a == b;
423 }
424 }.eql;
425}
426
411pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {427pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {
412 return struct {428 return struct {
413 fn hash(key: K) u32 {429 fn hash(key: K) u32 {
std/index.zig+1
...@@ -24,6 +24,7 @@ pub const empty_import = @import("empty.zig");...@@ -24,6 +24,7 @@ pub const empty_import = @import("empty.zig");
24pub const event = @import("event.zig");24pub const event = @import("event.zig");
25pub const fmt = @import("fmt/index.zig");25pub const fmt = @import("fmt/index.zig");
26pub const hash = @import("hash/index.zig");26pub const hash = @import("hash/index.zig");
27pub const hash_map = @import("hash_map.zig");
27pub const heap = @import("heap.zig");28pub const heap = @import("heap.zig");
28pub const io = @import("io.zig");29pub const io = @import("io.zig");
29pub const json = @import("json.zig");30pub const json = @import("json.zig");