Commit c060cae3ce
Changed files (1)
lib
std
lib/std/debug.zig
@@ -396,9 +396,6 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us
if (builtin.os == .windows) {
return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config);
}
- if (comptime std.Target.current.isDarwin()) {
- return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_config);
- }
return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config);
}
@@ -411,7 +408,7 @@ fn printSourceAtAddressWindows(
) !void {
const allocator = debug_info.allocator;
- const module = debug_info.lookupByAddress(address) catch |err| switch (err) {
+ const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs);
},
@@ -637,7 +634,7 @@ pub const TTY = struct {
};
/// TODO resources https://github.com/ziglang/zig/issues/4353
-fn populateModule(di: *ObjectDebugInfo, mod: *Module) !void {
+fn populateModule(di: *ModuleDebugInfo, mod: *Module) !void {
if (mod.populated)
return;
const allocator = getDebugInfoAllocator();
@@ -701,46 +698,8 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
return null;
}
-fn printSourceAtAddressMacOs(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
- const module = debug_info.lookupByAddress(address) catch |err| switch (err) {
- error.MissingDebugInfo, error.InvalidDebugInfo => {
- return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs);
- },
- else => return err,
- };
-
- const relocated_address = address - module.base_address;
- assert(relocated_address >= 0x100000000);
-
- const symbol = machoSearchSymbols(module.symbols, relocated_address) orelse {
- return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs);
- };
-
- const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, module.strings.ptr + symbol.nlist.n_strx));
- const compile_unit_name = if (symbol.ofile) |ofile| blk: {
- const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, module.strings.ptr + ofile.n_strx));
- break :blk fs.path.basename(ofile_path);
- } else "???";
-
- const line_info = getLineNumberInfoMacOs(module, symbol.*, relocated_address) catch |err| switch (err) {
- error.MissingDebugInfo, error.InvalidDebugInfo => null,
- else => return err,
- };
- defer if (line_info) |li| li.deinit();
-
- try printLineInfo(
- out_stream,
- line_info,
- address,
- symbol_name,
- compile_unit_name,
- tty_config,
- printLineFromFileAnyOs,
- );
-}
-
pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
- const module = debug_info.lookupByAddress(address) catch |err| switch (err) {
+ const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs);
},
@@ -748,7 +707,7 @@ pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, addres
};
const info = try module.getSymbolAtAddress(address);
- defer if (info.line_info) |li| li.deinit();
+ defer info.deinit();
return printLineInfo(
out_stream,
@@ -833,14 +792,14 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
}
/// TODO resources https://github.com/ziglang/zig/issues/4353
-fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ObjectDebugInfo {
+fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ModuleDebugInfo {
const coff_file = try std.fs.openFileAbsoluteW(coff_file_path.ptr, .{});
errdefer coff_file.close();
const coff_obj = try allocator.create(coff.Coff);
coff_obj.* = coff.Coff.init(allocator, coff_file);
- var di = ObjectDebugInfo{
+ var di = ModuleDebugInfo{
.base_address = undefined,
.coff = coff_obj,
.pdb = undefined,
@@ -1012,7 +971,7 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {
}
/// TODO resources https://github.com/ziglang/zig/issues/4353
-pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ObjectDebugInfo {
+pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo {
const mapped_mem = mapWholeFile(elf_file_path) catch |_| return error.InvalidDebugInfo;
var seekable_stream = io.SliceSeekableInStream.init(mapped_mem);
@@ -1047,7 +1006,7 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !O
try DW.openDwarfDebugInfo(&di, allocator);
- return ObjectDebugInfo{
+ return ModuleDebugInfo{
.base_address = undefined,
.dwarf = di,
.mapped_memory = mapped_mem,
@@ -1055,14 +1014,15 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !O
}
/// TODO resources https://github.com/ziglang/zig/issues/4353
-fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !ObjectDebugInfo {
+fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !ModuleDebugInfo {
const mapped_mem = mapWholeFile(macho_file_path) catch |_| return error.InvalidDebugInfo;
const hdr = @ptrCast(
*const macho.mach_header_64,
@alignCast(@alignOf(macho.mach_header_64), mapped_mem.ptr),
);
- assert(hdr.magic == std.macho.MH_MAGIC_64);
+ if (hdr.magic != macho.MH_MAGIC_64)
+ return error.InvalidDebugInfo;
const hdr_base = @ptrCast([*]const u8, hdr);
var ptr = hdr_base + @sizeOf(macho.mach_header_64);
@@ -1078,7 +1038,7 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !O
return error.MissingDebugInfo;
};
const syms = @ptrCast([*]const macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
- const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0..symtab.strsize];
+ const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0..symtab.strsize :0];
const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
@@ -1130,10 +1090,10 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !O
// This sort is so that we can binary search later.
std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);
- return ObjectDebugInfo{
+ return ModuleDebugInfo{
.base_address = undefined,
.mapped_memory = mapped_mem,
- .ofiles = ObjectDebugInfo.OFileTable.init(allocator),
+ .ofiles = ModuleDebugInfo.OFileTable.init(allocator),
.symbols = symbols,
.strings = strings,
};
@@ -1206,12 +1166,12 @@ fn mapWholeFile(path: []const u8) ![]const u8 {
pub const DebugInfo = struct {
allocator: *mem.Allocator,
- address_map: std.AutoHashMap(usize, *ObjectDebugInfo),
+ address_map: std.AutoHashMap(usize, *ModuleDebugInfo),
pub fn init(allocator: *mem.Allocator) DebugInfo {
return DebugInfo{
.allocator = allocator,
- .address_map = std.AutoHashMap(usize, *ObjectDebugInfo).init(allocator),
+ .address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator),
};
}
@@ -1220,17 +1180,16 @@ pub const DebugInfo = struct {
self.address_map.deinit();
}
- pub fn lookupByAddress(self: *DebugInfo, address: usize) !*ObjectDebugInfo {
- const obj_di = if (comptime std.Target.current.isDarwin())
- try self.lookupModuleDyld(address)
+ pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
+ if (comptime std.Target.current.isDarwin())
+ return self.lookupModuleDyld(address)
else if (builtin.os == .windows)
- try self.lookupModuleWin32(address)
+ return self.lookupModuleWin32(address)
else
- try self.lookupModuleDl(address);
- return obj_di;
+ return self.lookupModuleDl(address);
}
- fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ObjectDebugInfo {
+ fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
const image_count = std.c._dyld_image_count();
var i: u32 = 0;
@@ -1266,7 +1225,7 @@ pub const DebugInfo = struct {
return obj_di;
}
- const obj_di = try self.allocator.create(ObjectDebugInfo);
+ const obj_di = try self.allocator.create(ModuleDebugInfo);
errdefer self.allocator.destroy(obj_di);
try self.address_map.putNoClobber(base_address, obj_di);
@@ -1283,7 +1242,7 @@ pub const DebugInfo = struct {
return error.MissingDebugInfo;
}
- fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ObjectDebugInfo {
+ fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
const process_handle = windows.kernel32.GetCurrentProcess();
// Find how many modules are actually loaded
@@ -1345,7 +1304,7 @@ pub const DebugInfo = struct {
);
assert(len > 0);
- const obj_di = try self.allocator.create(ObjectDebugInfo);
+ const obj_di = try self.allocator.create(ModuleDebugInfo);
errdefer self.allocator.destroy(obj_di);
try self.address_map.putNoClobber(seg_start, obj_di);
@@ -1360,7 +1319,7 @@ pub const DebugInfo = struct {
return error.MissingDebugInfo;
}
- fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo {
+ fn lookupModuleDl(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
var ctx: struct {
// Input
address: usize,
@@ -1414,7 +1373,7 @@ pub const DebugInfo = struct {
break :blk try fs.selfExePath(&buf);
};
- const obj_di = try self.allocator.create(ObjectDebugInfo);
+ const obj_di = try self.allocator.create(ModuleDebugInfo);
errdefer self.allocator.destroy(obj_di);
try self.address_map.putNoClobber(ctx.base_address, obj_di);
@@ -1427,29 +1386,173 @@ pub const DebugInfo = struct {
};
const SymbolInfo = struct {
- symbol_name: []const u8,
- compile_unit_name: []const u8,
- line_info: ?LineInfo,
+ symbol_name: []const u8 = "???",
+ compile_unit_name: []const u8 = "???",
+ line_info: ?LineInfo = null,
+
+ fn deinit(self: @This()) void {
+ if (self.line_info) |li| {
+ li.deinit();
+ }
+ }
};
-pub const ObjectDebugInfo = switch (builtin.os) {
+pub const ModuleDebugInfo = switch (builtin.os) {
.macosx, .ios, .watchos, .tvos => struct {
base_address: usize,
mapped_memory: []const u8,
symbols: []const MachoSymbol,
- strings: []const u8,
+ strings: [:0]const u8,
ofiles: OFileTable,
- const OFileTable = std.HashMap(
- *const macho.nlist_64,
- DW.DwarfInfo,
- std.hash_map.getHashPtrAddrFn(*const macho.nlist_64),
- std.hash_map.getTrivialEqlFn(*const macho.nlist_64),
- );
+ const OFileTable = std.StringHashMap(DW.DwarfInfo);
pub fn allocator(self: @This()) *mem.Allocator {
return self.ofiles.allocator;
}
+
+ fn loadOFile(self: *@This(), o_file_path: []const u8) !DW.DwarfInfo {
+ const mapped_mem = mapWholeFile(o_file_path) catch |_| return error.InvalidDebugInfo;
+
+ const hdr = @ptrCast(
+ *const macho.mach_header_64,
+ @alignCast(@alignOf(macho.mach_header_64), mapped_mem.ptr),
+ );
+ if (hdr.magic != std.macho.MH_MAGIC_64)
+ return error.InvalidDebugInfo;
+
+ const hdr_base = @ptrCast([*]const u8, hdr);
+ var ptr = hdr_base + @sizeOf(macho.mach_header_64);
+ var ncmd: u32 = hdr.ncmds;
+ const segcmd = while (ncmd != 0) : (ncmd -= 1) {
+ const lc = @ptrCast(*const std.macho.load_command, ptr);
+ switch (lc.cmd) {
+ std.macho.LC_SEGMENT_64 => {
+ break @ptrCast(
+ *const std.macho.segment_command_64,
+ @alignCast(@alignOf(std.macho.segment_command_64), ptr),
+ );
+ },
+ else => {},
+ }
+ ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
+ } else {
+ return error.MissingDebugInfo;
+ };
+
+ var opt_debug_line: ?*const macho.section_64 = null;
+ var opt_debug_info: ?*const macho.section_64 = null;
+ var opt_debug_abbrev: ?*const macho.section_64 = null;
+ var opt_debug_str: ?*const macho.section_64 = null;
+ var opt_debug_ranges: ?*const macho.section_64 = null;
+
+ const sections = @ptrCast(
+ [*]const macho.section_64,
+ @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)),
+ )[0..segcmd.nsects];
+ for (sections) |*sect| {
+ // The section name may not exceed 16 chars and a trailing null may
+ // not be present
+ const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
+ sect.sectname[0..last]
+ else
+ sect.sectname[0..];
+
+ if (mem.eql(u8, name, "__debug_line")) {
+ opt_debug_line = sect;
+ } else if (mem.eql(u8, name, "__debug_info")) {
+ opt_debug_info = sect;
+ } else if (mem.eql(u8, name, "__debug_abbrev")) {
+ opt_debug_abbrev = sect;
+ } else if (mem.eql(u8, name, "__debug_str")) {
+ opt_debug_str = sect;
+ } else if (mem.eql(u8, name, "__debug_ranges")) {
+ opt_debug_ranges = sect;
+ }
+ }
+
+ const debug_line = opt_debug_line orelse
+ return error.MissingDebugInfo;
+ const debug_info = opt_debug_info orelse
+ return error.MissingDebugInfo;
+ const debug_str = opt_debug_str orelse
+ return error.MissingDebugInfo;
+ const debug_abbrev = opt_debug_abbrev orelse
+ return error.MissingDebugInfo;
+
+ var di = DW.DwarfInfo{
+ .endian = .Little,
+ .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
+ .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
+ .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
+ .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),
+ .debug_ranges = if (opt_debug_ranges) |debug_ranges|
+ try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)
+ else
+ null,
+ };
+
+ try DW.openDwarfDebugInfo(&di, self.allocator());
+
+ // Add the debug info to the cache
+ try self.ofiles.putNoClobber(o_file_path, di);
+
+ return di;
+ }
+
+ fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
+ // Translate the VA into an address into this object
+ const relocated_address = address - self.base_address;
+ assert(relocated_address >= 0x100000000);
+
+ // Find the .o file where this symbol is defined
+ const symbol = machoSearchSymbols(self.symbols, relocated_address) orelse
+ return SymbolInfo{};
+
+ // XXX: Return the symbol name
+ if (symbol.ofile == null)
+ return SymbolInfo{};
+
+ assert(symbol.ofile.?.n_strx < self.strings.len);
+ const o_file_path = mem.toSliceConst(u8, self.strings.ptr + symbol.ofile.?.n_strx);
+
+ warn("Loading .o file: {s}\n", .{o_file_path});
+
+ // Check if its debug infos are already in the cache
+ var o_file_di = self.ofiles.getValue(o_file_path) orelse
+ (self.loadOFile(o_file_path) catch |err| switch (err) {
+ error.MissingDebugInfo, error.InvalidDebugInfo => {
+ // XXX: Return the symbol name
+ return SymbolInfo{};
+ },
+ else => return err,
+ });
+
+ // Translate again the address, this time into an address inside the
+ // .o file
+ const relocated_address_o = relocated_address - symbol.reloc;
+
+ if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| {
+ return SymbolInfo{
+ .symbol_name = o_file_di.getSymbolName(relocated_address_o) orelse "???",
+ .compile_unit_name = compile_unit.die.getAttrString(&o_file_di, DW.AT_name) catch |err| switch (err) {
+ error.MissingDebugInfo, error.InvalidDebugInfo => "???",
+ else => return err,
+ },
+ .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o) catch |err| switch (err) {
+ error.MissingDebugInfo, error.InvalidDebugInfo => null,
+ else => return err,
+ },
+ };
+ } else |err| switch (err) {
+ error.MissingDebugInfo, error.InvalidDebugInfo => {
+ return SymbolInfo{};
+ },
+ else => return err,
+ }
+
+ unreachable;
+ }
},
.uefi, .windows => struct {
base_address: usize,
@@ -1481,11 +1584,7 @@ pub const ObjectDebugInfo = switch (builtin.os) {
};
} else |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
- return SymbolInfo{
- .symbol_name = "???",
- .compile_unit_name = "???",
- .line_info = null,
- };
+ return SymbolInfo{};
},
else => return err,
}
@@ -1496,115 +1595,6 @@ pub const ObjectDebugInfo = switch (builtin.os) {
else => DW.DwarfInfo,
};
-/// TODO resources https://github.com/ziglang/zig/issues/4353
-fn getLineNumberInfoMacOs(di: *ObjectDebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {
- const ofile = symbol.ofile orelse return error.MissingDebugInfo;
- const gop = try di.ofiles.getOrPut(ofile);
- const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: {
- errdefer _ = di.ofiles.remove(ofile);
- const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));
-
- var exe_file = try std.fs.openFileAbsoluteC(ofile_path, .{});
- errdefer exe_file.close();
-
- const exe_len = math.cast(usize, try exe_file.getEndPos()) catch
- return error.DebugInfoTooLarge;
- const exe_mmap = try os.mmap(
- null,
- exe_len,
- os.PROT_READ,
- os.MAP_SHARED,
- exe_file.handle,
- 0,
- );
- errdefer os.munmap(exe_mmap);
-
- const hdr = @ptrCast(
- *const macho.mach_header_64,
- @alignCast(@alignOf(macho.mach_header_64), exe_mmap.ptr),
- );
- if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo;
-
- const hdr_base = @ptrCast([*]const u8, hdr);
- var ptr = hdr_base + @sizeOf(macho.mach_header_64);
- var ncmd: u32 = hdr.ncmds;
- const segcmd = while (ncmd != 0) : (ncmd -= 1) {
- const lc = @ptrCast(*const std.macho.load_command, ptr);
- switch (lc.cmd) {
- std.macho.LC_SEGMENT_64 => {
- break @ptrCast(
- *const std.macho.segment_command_64,
- @alignCast(@alignOf(std.macho.segment_command_64), ptr),
- );
- },
- else => {},
- }
- ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
- } else {
- return error.MissingDebugInfo;
- };
-
- var opt_debug_line: ?*const macho.section_64 = null;
- var opt_debug_info: ?*const macho.section_64 = null;
- var opt_debug_abbrev: ?*const macho.section_64 = null;
- var opt_debug_str: ?*const macho.section_64 = null;
- var opt_debug_ranges: ?*const macho.section_64 = null;
-
- const sections = @ptrCast(
- [*]const macho.section_64,
- @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)),
- )[0..segcmd.nsects];
- for (sections) |*sect| {
- // The section name may not exceed 16 chars and a trailing null may
- // not be present
- const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
- sect.sectname[0..last]
- else
- sect.sectname[0..];
-
- if (mem.eql(u8, name, "__debug_line")) {
- opt_debug_line = sect;
- } else if (mem.eql(u8, name, "__debug_info")) {
- opt_debug_info = sect;
- } else if (mem.eql(u8, name, "__debug_abbrev")) {
- opt_debug_abbrev = sect;
- } else if (mem.eql(u8, name, "__debug_str")) {
- opt_debug_str = sect;
- } else if (mem.eql(u8, name, "__debug_ranges")) {
- opt_debug_ranges = sect;
- }
- }
-
- var debug_line = opt_debug_line orelse
- return error.MissingDebugInfo;
- var debug_info = opt_debug_info orelse
- return error.MissingDebugInfo;
- var debug_str = opt_debug_str orelse
- return error.MissingDebugInfo;
- var debug_abbrev = opt_debug_abbrev orelse
- return error.MissingDebugInfo;
-
- gop.kv.value = DW.DwarfInfo{
- .endian = .Little,
- .debug_info = try chopSlice(exe_mmap, debug_info.offset, debug_info.size),
- .debug_abbrev = try chopSlice(exe_mmap, debug_abbrev.offset, debug_abbrev.size),
- .debug_str = try chopSlice(exe_mmap, debug_str.offset, debug_str.size),
- .debug_line = try chopSlice(exe_mmap, debug_line.offset, debug_line.size),
- .debug_ranges = if (opt_debug_ranges) |debug_ranges|
- try chopSlice(exe_mmap, debug_ranges.offset, debug_ranges.size)
- else
- null,
- };
- try DW.openDwarfDebugInfo(&gop.kv.value, di.allocator());
-
- break :blk &gop.kv.value;
- };
-
- const o_file_address = address - symbol.reloc;
- const compile_unit = try dwarf_info.findCompileUnit(o_file_address);
- return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address);
-}
-
/// TODO multithreaded awareness
var debug_info_allocator: ?*mem.Allocator = null;
var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;