Commit 975c185b92

Andrew Kelley <andrew@ziglang.org>
2024-08-02 21:00:08
fix compilation on powerpc GNU systems
...which have a ucontext_t but not a PC register. The current stack unwinding implementation does not yet support this architecture. Also fix name of `std.debug.SelfInfo.openSelf` to remove redundancy. Also removed this hook into root providing an "openSelfDebugInfo" function. Sorry, this debugging code is not of sufficient quality to offer a plugin API right now.
1 parent 48d584e
Changed files (6)
lib
test
standalone
coff_dwarf
lib/std/debug/Dwarf/abi.zig
@@ -5,35 +5,14 @@ const mem = std.mem;
 const posix = std.posix;
 const Arch = std.Target.Cpu.Arch;
 
-pub fn supportsUnwinding(target: std.Target) bool {
-    return switch (target.cpu.arch) {
-        .x86 => switch (target.os.tag) {
-            .linux, .netbsd, .solaris, .illumos => true,
-            else => false,
-        },
-        .x86_64 => switch (target.os.tag) {
-            .linux, .netbsd, .freebsd, .openbsd, .macos, .ios, .solaris, .illumos => true,
-            else => false,
-        },
-        .arm => switch (target.os.tag) {
-            .linux => true,
-            else => false,
-        },
-        .aarch64 => switch (target.os.tag) {
-            .linux, .netbsd, .freebsd, .macos, .ios => true,
-            else => false,
-        },
-        else => false,
-    };
-}
-
-pub fn ipRegNum(arch: Arch) u8 {
+/// Returns `null` for CPU architectures without an instruction pointer register.
+pub fn ipRegNum(arch: Arch) ?u8 {
     return switch (arch) {
         .x86 => 8,
         .x86_64 => 16,
         .arm => 15,
         .aarch64 => 32,
-        else => unreachable,
+        else => null,
     };
 }
 
lib/std/debug/Dwarf/expression.zig
@@ -1190,11 +1190,11 @@ test "DWARF expressions" {
             mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);
             (try abi.regValueNative(&thread_context, abi.fpRegNum(native_arch, reg_context), reg_context)).* = 1;
             (try abi.regValueNative(&thread_context, abi.spRegNum(native_arch, reg_context), reg_context)).* = 2;
-            (try abi.regValueNative(&thread_context, abi.ipRegNum(native_arch), reg_context)).* = 3;
+            (try abi.regValueNative(&thread_context, abi.ipRegNum(native_arch).?, reg_context)).* = 3;
 
             try b.writeBreg(writer, abi.fpRegNum(native_arch, reg_context), @as(usize, 100));
             try b.writeBreg(writer, abi.spRegNum(native_arch, reg_context), @as(usize, 200));
-            try b.writeBregx(writer, abi.ipRegNum(native_arch), @as(usize, 300));
+            try b.writeBregx(writer, abi.ipRegNum(native_arch).?, @as(usize, 300));
             try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));
 
             _ = try stack_machine.run(program.items, allocator, context, 0);
lib/std/debug/Dwarf.zig
@@ -2023,3 +2023,27 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize {
         return std.math.add(usize, field_ptr, @as(usize, @intCast(pc_rel_offset)));
     }
 }
+
+pub fn supportsUnwinding(target: std.Target) bool {
+    return switch (target.cpu.arch) {
+        .x86 => switch (target.os.tag) {
+            .linux, .netbsd, .solaris, .illumos => true,
+            else => false,
+        },
+        .x86_64 => switch (target.os.tag) {
+            .linux, .netbsd, .freebsd, .openbsd, .macos, .ios, .solaris, .illumos => true,
+            else => false,
+        },
+        .arm => switch (target.os.tag) {
+            .linux => true,
+            else => false,
+        },
+        .aarch64 => switch (target.os.tag) {
+            .linux, .netbsd, .freebsd, .macos, .ios => true,
+            else => false,
+        },
+        // Unwinding is possible on other targets but this implementation does
+        // not support them...yet!
+        else => false,
+    };
+}
lib/std/debug/SelfInfo.zig
@@ -34,18 +34,15 @@ allocator: Allocator,
 address_map: std.AutoHashMap(usize, *Module),
 modules: if (native_os == .windows) std.ArrayListUnmanaged(WindowsModule) else void,
 
-pub const OpenSelfError = error{
+pub const OpenError = error{
     MissingDebugInfo,
     UnsupportedOperatingSystem,
 } || @typeInfo(@typeInfo(@TypeOf(SelfInfo.init)).Fn.return_type.?).ErrorUnion.error_set;
 
-pub fn openSelf(allocator: Allocator) OpenSelfError!SelfInfo {
+pub fn open(allocator: Allocator) OpenError!SelfInfo {
     nosuspend {
         if (builtin.strip_debug_info)
             return error.MissingDebugInfo;
-        if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
-            return root.os.debug.openSelfDebugInfo(allocator);
-        }
         switch (native_os) {
             .linux,
             .freebsd,
@@ -1721,6 +1718,8 @@ pub const UnwindContext = struct {
         allocator: Allocator,
         thread_context: *std.debug.ThreadContext,
     ) !UnwindContext {
+        comptime assert(supports_unwinding);
+
         const pc = stripInstructionPtrAuthCode(
             (try regValueNative(thread_context, ip_reg_num, null)).*,
         );
@@ -1982,8 +1981,8 @@ fn spRegNum(reg_context: Dwarf.abi.RegisterContext) u8 {
     return Dwarf.abi.spRegNum(native_arch, reg_context);
 }
 
-const ip_reg_num = Dwarf.abi.ipRegNum(native_arch);
-const supports_unwinding = Dwarf.abi.supportsUnwinding(builtin.target);
+const ip_reg_num = Dwarf.abi.ipRegNum(native_arch).?;
+pub const supports_unwinding = Dwarf.supportsUnwinding(builtin.target);
 
 fn unwindFrameMachODwarf(
     context: *UnwindContext,
lib/std/debug.zig
@@ -88,7 +88,7 @@ pub fn getSelfDebugInfo() !*SelfInfo {
     if (self_debug_info) |*info| {
         return info;
     } else {
-        self_debug_info = try SelfInfo.openSelf(getDebugInfoAllocator());
+        self_debug_info = try SelfInfo.open(getDebugInfoAllocator());
         return &self_debug_info.?;
     }
 }
@@ -573,17 +573,19 @@ pub const StackIterator = struct {
     pub fn initWithContext(first_address: ?usize, debug_info: *SelfInfo, context: *posix.ucontext_t) !StackIterator {
         // The implementation of DWARF unwinding on aarch64-macos is not complete. However, Apple mandates that
         // the frame pointer register is always used, so on this platform we can safely use the FP-based unwinder.
-        if (builtin.target.isDarwin() and native_arch == .aarch64) {
+        if (builtin.target.isDarwin() and native_arch == .aarch64)
             return init(first_address, context.mcontext.ss.fp);
-        } else {
+
+        if (SelfInfo.supports_unwinding) {
             var iterator = init(first_address, null);
             iterator.unwind_state = .{
                 .debug_info = debug_info,
                 .dwarf_context = try SelfInfo.UnwindContext.init(debug_info.allocator, context),
             };
-
             return iterator;
         }
+
+        return init(first_address, null);
     }
 
     pub fn deinit(it: *StackIterator) void {
@@ -725,11 +727,13 @@ pub fn writeCurrentStackTrace(
     tty_config: io.tty.Config,
     start_addr: ?usize,
 ) !void {
-    var context: ThreadContext = undefined;
-    const has_context = getContext(&context);
     if (native_os == .windows) {
+        var context: ThreadContext = undefined;
+        assert(getContext(&context));
         return writeStackTraceWindows(out_stream, debug_info, tty_config, &context, start_addr);
     }
+    var context: ThreadContext = undefined;
+    const has_context = getContext(&context);
 
     var it = (if (has_context) blk: {
         break :blk StackIterator.initWithContext(start_addr, debug_info, &context) catch null;
@@ -1340,7 +1344,7 @@ test "manage resources correctly" {
     }
 
     const writer = std.io.null_writer;
-    var di = try SelfInfo.openSelf(testing.allocator);
+    var di = try SelfInfo.open(testing.allocator);
     defer di.deinit();
     try printSourceAtAddress(&di, writer, showMyTrace(), io.tty.detectConfig(std.io.getStdErr()));
 }
@@ -1581,5 +1585,9 @@ pub inline fn inValgrind() bool {
 }
 
 test {
+    _ = &Dwarf;
+    _ = &MemoryAccessor;
+    _ = &Pdb;
+    _ = &SelfInfo;
     _ = &dumpHex;
 }
test/standalone/coff_dwarf/main.zig
@@ -9,7 +9,7 @@ pub fn main() !void {
     defer assert(gpa.deinit() == .ok);
     const allocator = gpa.allocator();
 
-    var debug_info = try std.debug.openSelfDebugInfo(allocator);
+    var debug_info = try std.debug.SelfInfo.open(allocator);
     defer debug_info.deinit();
 
     var add_addr: usize = undefined;