Skip to content

Commit 290966c

Browse files
committed
std.debug: rename Info to SelfInfo
This code has the hard-coded goal of supporting the executable's own debug information and makes design choices along that goal, such as memory-mapping the inputs, using dl_iterate_phdr, and doing conditional compilation on the host target. A more general-purpose implementation of debug information may be able to share code with this, but there are some fundamental incompatibilities. For example, the "SelfInfo" implementation wants to avoid bloating the binary with PDB on POSIX systems, and likewise DWARF on Windows systems, while a general-purpose implementation needs to support both PDB and DWARF from the same binary. It might, for example, inspect the debug information from a cross-compiled binary. `SourceLocation` now lives at `std.debug.SourceLocation` and is documented. Deprecate `std.debug.runtime_safety` because it returns the optimization mode of the standard library, when the caller probably wants to use the optimization mode of their own module. `std.pdb.Pdb` is moved to `std.debug.Pdb`, mirroring the recent extraction of `std.debug.Dwarf` from `std.dwarf`. I have no idea why we have both Module (with a Windows-specific definition) and WindowsModule. I left some passive aggressive doc comments to express my frustration.
1 parent ab0253f commit 290966c

File tree

5 files changed

+668
-659
lines changed

5 files changed

+668
-659
lines changed

lib/std/debug.zig

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ const io = std.io;
66
const posix = std.posix;
77
const fs = std.fs;
88
const testing = std.testing;
9-
const elf = std.elf;
10-
const DW = std.dwarf;
11-
const macho = std.macho;
12-
const coff = std.coff;
13-
const pdb = std.pdb;
149
const root = @import("root");
1510
const File = std.fs.File;
1611
const windows = std.os.windows;
@@ -19,8 +14,22 @@ const native_os = builtin.os.tag;
1914
const native_endian = native_arch.endian();
2015

2116
pub const Dwarf = @import("debug/Dwarf.zig");
22-
pub const Info = @import("debug/Info.zig");
17+
pub const Pdb = @import("debug/Pdb.zig");
18+
pub const SelfInfo = @import("debug/SelfInfo.zig");
19+
20+
/// Unresolved source locations can be represented with a single `usize` that
21+
/// corresponds to a virtual memory address of the program counter. Combined
22+
/// with debug information, those values can be converted into a resolved
23+
/// source location, including file, line, and column.
24+
pub const SourceLocation = struct {
25+
line: u64,
26+
column: u64,
27+
file_name: []const u8,
28+
};
2329

30+
/// Deprecated because it returns the optimization mode of the standard
31+
/// library, when the caller probably wants to use the optimization mode of
32+
/// their own module.
2433
pub const runtime_safety = switch (builtin.mode) {
2534
.Debug, .ReleaseSafe => true,
2635
.ReleaseFast, .ReleaseSmall => false,
@@ -72,13 +81,13 @@ pub fn getStderrMutex() *std.Thread.Mutex {
7281
}
7382

7483
/// TODO multithreaded awareness
75-
var self_debug_info: ?Info = null;
84+
var self_debug_info: ?SelfInfo = null;
7685

77-
pub fn getSelfDebugInfo() !*Info {
86+
pub fn getSelfDebugInfo() !*SelfInfo {
7887
if (self_debug_info) |*info| {
7988
return info;
8089
} else {
81-
self_debug_info = try Info.openSelf(getDebugInfoAllocator());
90+
self_debug_info = try SelfInfo.openSelf(getDebugInfoAllocator());
8291
return &self_debug_info.?;
8392
}
8493
}
@@ -316,7 +325,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT
316325
stack_trace.index = slice.len;
317326
} else {
318327
// TODO: This should use the DWARF unwinder if .eh_frame_hdr is available (so that full debug info parsing isn't required).
319-
// A new path for loading Info needs to be created which will only attempt to parse in-memory sections, because
328+
// A new path for loading SelfInfo needs to be created which will only attempt to parse in-memory sections, because
320329
// stopping to load other debug info (ie. source line info) from disk here is not required for unwinding.
321330
var it = StackIterator.init(first_address, null);
322331
defer it.deinit();
@@ -494,7 +503,7 @@ pub fn writeStackTrace(
494503
stack_trace: std.builtin.StackTrace,
495504
out_stream: anytype,
496505
allocator: mem.Allocator,
497-
debug_info: *Info,
506+
debug_info: *SelfInfo,
498507
tty_config: io.tty.Config,
499508
) !void {
500509
_ = allocator;
@@ -531,11 +540,11 @@ pub const StackIterator = struct {
531540
fp: usize,
532541
ma: MemoryAccessor = MemoryAccessor.init,
533542

534-
// When Info and a register context is available, this iterator can unwind
543+
// When SelfInfo and a register context is available, this iterator can unwind
535544
// stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer),
536545
// using DWARF and MachO unwind info.
537546
unwind_state: if (have_ucontext) ?struct {
538-
debug_info: *Info,
547+
debug_info: *SelfInfo,
539548
dwarf_context: Dwarf.UnwindContext,
540549
last_error: ?UnwindError = null,
541550
failed: bool = false,
@@ -560,7 +569,7 @@ pub const StackIterator = struct {
560569
};
561570
}
562571

563-
pub fn initWithContext(first_address: ?usize, debug_info: *Info, context: *const posix.ucontext_t) !StackIterator {
572+
pub fn initWithContext(first_address: ?usize, debug_info: *SelfInfo, context: *const posix.ucontext_t) !StackIterator {
564573
// The implementation of DWARF unwinding on aarch64-macos is not complete. However, Apple mandates that
565574
// the frame pointer register is always used, so on this platform we can safely use the FP-based unwinder.
566575
if (comptime builtin.target.isDarwin() and native_arch == .aarch64) {
@@ -820,7 +829,7 @@ const have_msync = switch (native_os) {
820829

821830
pub fn writeCurrentStackTrace(
822831
out_stream: anytype,
823-
debug_info: *Info,
832+
debug_info: *SelfInfo,
824833
tty_config: io.tty.Config,
825834
start_addr: ?usize,
826835
) !void {
@@ -906,7 +915,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w
906915

907916
pub fn writeStackTraceWindows(
908917
out_stream: anytype,
909-
debug_info: *Info,
918+
debug_info: *SelfInfo,
910919
tty_config: io.tty.Config,
911920
context: *const windows.CONTEXT,
912921
start_addr: ?usize,
@@ -925,7 +934,7 @@ pub fn writeStackTraceWindows(
925934
}
926935
}
927936

928-
fn printUnknownSource(debug_info: *Info, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
937+
fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
929938
const module_name = debug_info.getModuleNameForAddress(address);
930939
return printLineInfo(
931940
out_stream,
@@ -938,14 +947,14 @@ fn printUnknownSource(debug_info: *Info, out_stream: anytype, address: usize, tt
938947
);
939948
}
940949

941-
fn printLastUnwindError(it: *StackIterator, debug_info: *Info, out_stream: anytype, tty_config: io.tty.Config) void {
950+
fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, out_stream: anytype, tty_config: io.tty.Config) void {
942951
if (!have_ucontext) return;
943952
if (it.getLastError()) |unwind_error| {
944953
printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config) catch {};
945954
}
946955
}
947956

948-
fn printUnwindError(debug_info: *Info, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
957+
fn printUnwindError(debug_info: *SelfInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
949958
const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
950959
try tty_config.setColor(out_stream, .dim);
951960
if (err == error.MissingDebugInfo) {
@@ -956,7 +965,7 @@ fn printUnwindError(debug_info: *Info, out_stream: anytype, address: usize, err:
956965
try tty_config.setColor(out_stream, .reset);
957966
}
958967

959-
pub fn printSourceAtAddress(debug_info: *Info, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
968+
pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
960969
const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
961970
error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
962971
else => return err,
@@ -981,7 +990,7 @@ pub fn printSourceAtAddress(debug_info: *Info, out_stream: anytype, address: usi
981990

982991
fn printLineInfo(
983992
out_stream: anytype,
984-
line_info: ?Info.SourceLocation,
993+
line_info: ?SourceLocation,
985994
address: usize,
986995
symbol_name: []const u8,
987996
compile_unit_name: []const u8,
@@ -1027,7 +1036,7 @@ fn printLineInfo(
10271036
}
10281037
}
10291038

1030-
fn printLineFromFileAnyOs(out_stream: anytype, line_info: Info.SourceLocation) !void {
1039+
fn printLineFromFileAnyOs(out_stream: anytype, line_info: SourceLocation) !void {
10311040
// Need this to always block even in async I/O mode, because this could potentially
10321041
// be called from e.g. the event loop code crashing.
10331042
var f = try fs.cwd().openFile(line_info.file_name, .{});
@@ -1093,7 +1102,7 @@ test printLineFromFileAnyOs {
10931102

10941103
var test_dir = std.testing.tmpDir(.{});
10951104
defer test_dir.cleanup();
1096-
// Relies on testing.tmpDir internals which is not ideal, but Info.SourceLocation requires paths.
1105+
// Relies on testing.tmpDir internals which is not ideal, but SourceLocation requires paths.
10971106
const test_dir_path = try join(allocator, &.{ ".zig-cache", "tmp", test_dir.sub_path[0..] });
10981107
defer allocator.free(test_dir_path);
10991108

@@ -1439,7 +1448,7 @@ test "manage resources correctly" {
14391448
}
14401449

14411450
const writer = std.io.null_writer;
1442-
var di = try Info.openSelf(testing.allocator);
1451+
var di = try SelfInfo.openSelf(testing.allocator);
14431452
defer di.deinit();
14441453
try printSourceAtAddress(&di, writer, showMyTrace(), io.tty.detectConfig(std.io.getStdErr()));
14451454
}

lib/std/debug/Dwarf.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,7 @@ pub fn getLineNumberInfo(
13531353
allocator: Allocator,
13541354
compile_unit: CompileUnit,
13551355
target_address: u64,
1356-
) !std.debug.Info.SourceLocation {
1356+
) !std.debug.SourceLocation {
13571357
const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.section(.debug_line_str), compile_unit);
13581358
const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);
13591359

@@ -2084,7 +2084,7 @@ const LineNumberProgram = struct {
20842084
self: *LineNumberProgram,
20852085
allocator: Allocator,
20862086
file_entries: []const FileEntry,
2087-
) !?std.debug.Info.SourceLocation {
2087+
) !?std.debug.SourceLocation {
20882088
if (self.prev_valid and
20892089
self.target_address >= self.prev_address and
20902090
self.target_address < self.address)
@@ -2104,7 +2104,7 @@ const LineNumberProgram = struct {
21042104
dir_name, file_entry.path,
21052105
});
21062106

2107-
return std.debug.Info.SourceLocation{
2107+
return std.debug.SourceLocation{
21082108
.line = if (self.prev_line >= 0) @as(u64, @intCast(self.prev_line)) else 0,
21092109
.column = self.prev_column,
21102110
.file_name = file_name,

0 commit comments

Comments
 (0)