Commit 7e966de45e

Xavier Bouchoux <xavierb@gmail.com>
2024-02-28 08:15:40
std.debug.Dwarf: fix loading external debuginfo in the ".debuglink" case. - look up the debuglink file in the directory of the executable file (instead of the cwd) - fix parsing of debuglink section (the 4-byte alignement is within the file, unrelated to the in-memory address)
1 parent 7a7421c
Changed files (2)
lib
std
debug
test
standalone
stack_iterator
lib/std/debug/Dwarf.zig
@@ -239,7 +239,7 @@ pub const Die = struct {
         return switch (form_value.*) {
             .addr => |value| value,
             .addrx => |index| di.readDebugAddr(compile_unit, index),
-            else => error.InvalidDebugInfo,
+            else => bad(),
         };
     }
 
@@ -252,7 +252,7 @@ pub const Die = struct {
         const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
         return switch (form_value.*) {
             .Const => |value| value.asUnsignedLe(),
-            else => error.InvalidDebugInfo,
+            else => bad(),
         };
     }
 
@@ -260,7 +260,7 @@ pub const Die = struct {
         const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
         return switch (form_value.*) {
             .ref => |value| value,
-            else => error.InvalidDebugInfo,
+            else => bad(),
         };
     }
 
@@ -2159,7 +2159,7 @@ pub const ElfModule = struct {
             if (mem.eql(u8, name, ".gnu_debuglink")) {
                 const gnu_debuglink = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
                 const debug_filename = mem.sliceTo(@as([*:0]const u8, @ptrCast(gnu_debuglink.ptr)), 0);
-                const crc_offset = mem.alignForward(usize, @intFromPtr(&debug_filename[debug_filename.len]) + 1, 4) - @intFromPtr(gnu_debuglink.ptr);
+                const crc_offset = mem.alignForward(usize, debug_filename.len + 1, 4);
                 const crc_bytes = gnu_debuglink[crc_offset..][0..4];
                 separate_debug_crc = mem.readInt(u32, crc_bytes, native_endian);
                 separate_debug_filename = debug_filename;
@@ -2253,25 +2253,30 @@ pub const ElfModule = struct {
                 if (elf_filename != null and mem.eql(u8, elf_filename.?, separate_filename))
                     return error.MissingDebugInfo;
 
-                // <cwd>/<gnu_debuglink>
-                if (loadPath(
-                    gpa,
-                    .{
-                        .root_dir = std.Build.Cache.Directory.cwd(),
-                        .sub_path = separate_filename,
-                    },
-                    null,
-                    separate_debug_crc,
-                    &sections,
-                    mapped_mem,
-                )) |debug_info| {
-                    return debug_info;
-                } else |_| {}
-
-                // <cwd>/.debug/<gnu_debuglink>
-                {
+                exe_dir: {
+                    var exe_dir_buf: [std.fs.max_path_bytes]u8 = undefined;
+                    const exe_dir_path = std.fs.selfExeDirPath(&exe_dir_buf) catch break :exe_dir;
+                    var exe_dir = std.fs.openDirAbsolute(exe_dir_path, .{}) catch break :exe_dir;
+                    defer exe_dir.close();
+
+                    // <exe_dir>/<gnu_debuglink>
+                    if (loadPath(
+                        gpa,
+                        .{
+                            .root_dir = .{ .path = null, .handle = exe_dir },
+                            .sub_path = separate_filename,
+                        },
+                        null,
+                        separate_debug_crc,
+                        &sections,
+                        mapped_mem,
+                    )) |debug_info| {
+                        return debug_info;
+                    } else |_| {}
+
+                    // <exe_dir>/.debug/<gnu_debuglink>
                     const path: Path = .{
-                        .root_dir = std.Build.Cache.Directory.cwd(),
+                        .root_dir = .{ .path = null, .handle = exe_dir },
                         .sub_path = try std.fs.path.join(gpa, &.{ ".debug", separate_filename }),
                     };
                     defer gpa.free(path.sub_path);
test/standalone/stack_iterator/build.zig
@@ -93,6 +93,21 @@ pub fn build(b: *std.Build) void {
 
         const run_cmd = b.addRunArtifact(exe);
         test_step.dependOn(&run_cmd.step);
+
+        // Separate debug info ELF file
+        if (target.result.ofmt == .elf) {
+            const filename = b.fmt("{s}_stripped", .{exe.out_filename});
+            const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
+                .basename = filename, // set the name for the debuglink
+                .compress_debug = true,
+                .strip = .debug,
+                .extract_to_separate_file = true,
+            });
+
+            const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
+            run_stripped.addFileArg(stripped_exe.getOutput());
+            test_step.dependOn(&run_stripped.step);
+        }
     }
 
     // Unwinding without libc/posix