| ... | @@ -239,7 +239,7 @@ pub const Die = struct { | ... | @@ -239,7 +239,7 @@ pub const Die = struct { |
| 239 | return switch (form_value.*) { | 239 | return switch (form_value.*) { |
| 240 | .addr => |value| value, | 240 | .addr => |value| value, |
| 241 | .addrx => |index| di.readDebugAddr(compile_unit, index), | 241 | .addrx => |index| di.readDebugAddr(compile_unit, index), |
| 242 | else => error.InvalidDebugInfo, | 242 | else => bad(), |
| 243 | }; | 243 | }; |
| 244 | } | 244 | } |
| 245 | | 245 | |
| ... | @@ -252,7 +252,7 @@ pub const Die = struct { | ... | @@ -252,7 +252,7 @@ pub const Die = struct { |
| 252 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 252 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 253 | return switch (form_value.*) { | 253 | return switch (form_value.*) { |
| 254 | .Const => |value| value.asUnsignedLe(), | 254 | .Const => |value| value.asUnsignedLe(), |
| 255 | else => error.InvalidDebugInfo, | 255 | else => bad(), |
| 256 | }; | 256 | }; |
| 257 | } | 257 | } |
| 258 | | 258 | |
| ... | @@ -260,7 +260,7 @@ pub const Die = struct { | ... | @@ -260,7 +260,7 @@ pub const Die = struct { |
| 260 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 260 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 261 | return switch (form_value.*) { | 261 | return switch (form_value.*) { |
| 262 | .ref => |value| value, | 262 | .ref => |value| value, |
| 263 | else => error.InvalidDebugInfo, | 263 | else => bad(), |
| 264 | }; | 264 | }; |
| 265 | } | 265 | } |
| 266 | | 266 | |
| ... | @@ -2159,7 +2159,7 @@ pub const ElfModule = struct { | ... | @@ -2159,7 +2159,7 @@ pub const ElfModule = struct { |
| 2159 | if (mem.eql(u8, name, ".gnu_debuglink")) { | 2159 | if (mem.eql(u8, name, ".gnu_debuglink")) { |
| 2160 | const gnu_debuglink = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); | 2160 | const gnu_debuglink = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); |
| 2161 | const debug_filename = mem.sliceTo(@as([*:0]const u8, @ptrCast(gnu_debuglink.ptr)), 0); | 2161 | const debug_filename = mem.sliceTo(@as([*:0]const u8, @ptrCast(gnu_debuglink.ptr)), 0); |
| 2162 | const crc_offset = mem.alignForward(usize, @intFromPtr(&debug_filename[debug_filename.len]) + 1, 4) - @intFromPtr(gnu_debuglink.ptr); | 2162 | const crc_offset = mem.alignForward(usize, debug_filename.len + 1, 4); |
| 2163 | const crc_bytes = gnu_debuglink[crc_offset..][0..4]; | 2163 | const crc_bytes = gnu_debuglink[crc_offset..][0..4]; |
| 2164 | separate_debug_crc = mem.readInt(u32, crc_bytes, native_endian); | 2164 | separate_debug_crc = mem.readInt(u32, crc_bytes, native_endian); |
| 2165 | separate_debug_filename = debug_filename; | 2165 | separate_debug_filename = debug_filename; |
| ... | @@ -2215,6 +2215,46 @@ pub const ElfModule = struct { | ... | @@ -2215,6 +2215,46 @@ pub const ElfModule = struct { |
| 2215 | return error.MissingDebugInfo; | 2215 | return error.MissingDebugInfo; |
| 2216 | } | 2216 | } |
| 2217 | | 2217 | |
| | 2218 | // $XDG_CACHE_HOME/debuginfod_client/<buildid>/debuginfo |
| | 2219 | // This only opportunisticly tries to load from the debuginfod cache, but doesn't try to populate it. |
| | 2220 | // One can manually run `debuginfod-find debuginfo PATH` to download the symbols |
| | 2221 | if (build_id) |id| blk: { |
| | 2222 | var debuginfod_dir: std.fs.Dir = switch (builtin.os.tag) { |
| | 2223 | .wasi, .windows => break :blk, |
| | 2224 | else => dir: { |
| | 2225 | if (std.posix.getenv("DEBUGINFOD_CACHE_PATH")) |path| { |
| | 2226 | break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk; |
| | 2227 | } |
| | 2228 | if (std.posix.getenv("XDG_CACHE_HOME")) |cache_path| { |
| | 2229 | const path = std.fs.path.join(gpa, &[_][]const u8{ cache_path, "debuginfod_client" }) catch break :blk; |
| | 2230 | defer gpa.free(path); |
| | 2231 | break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk; |
| | 2232 | } |
| | 2233 | if (std.posix.getenv("HOME")) |home_path| { |
| | 2234 | const path = std.fs.path.join(gpa, &[_][]const u8{ home_path, ".cache", "debuginfod_client" }) catch break :blk; |
| | 2235 | defer gpa.free(path); |
| | 2236 | break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk; |
| | 2237 | } |
| | 2238 | break :blk; |
| | 2239 | }, |
| | 2240 | }; |
| | 2241 | defer debuginfod_dir.close(); |
| | 2242 | |
| | 2243 | const filename = std.fmt.allocPrint( |
| | 2244 | gpa, |
| | 2245 | "{s}/debuginfo", |
| | 2246 | .{std.fmt.fmtSliceHexLower(id)}, |
| | 2247 | ) catch break :blk; |
| | 2248 | defer gpa.free(filename); |
| | 2249 | |
| | 2250 | const path: Path = .{ |
| | 2251 | .root_dir = .{ .path = null, .handle = debuginfod_dir }, |
| | 2252 | .sub_path = filename, |
| | 2253 | }; |
| | 2254 | |
| | 2255 | return loadPath(gpa, path, null, separate_debug_crc, &sections, mapped_mem) catch break :blk; |
| | 2256 | } |
| | 2257 | |
| 2218 | const global_debug_directories = [_][]const u8{ | 2258 | const global_debug_directories = [_][]const u8{ |
| 2219 | "/usr/lib/debug", | 2259 | "/usr/lib/debug", |
| 2220 | }; | 2260 | }; |
| ... | @@ -2253,25 +2293,30 @@ pub const ElfModule = struct { | ... | @@ -2253,25 +2293,30 @@ pub const ElfModule = struct { |
| 2253 | if (elf_filename != null and mem.eql(u8, elf_filename.?, separate_filename)) | 2293 | if (elf_filename != null and mem.eql(u8, elf_filename.?, separate_filename)) |
| 2254 | return error.MissingDebugInfo; | 2294 | return error.MissingDebugInfo; |
| 2255 | | 2295 | |
| 2256 | // <cwd>/<gnu_debuglink> | 2296 | exe_dir: { |
| 2257 | if (loadPath( | 2297 | var exe_dir_buf: [std.fs.max_path_bytes]u8 = undefined; |
| 2258 | gpa, | 2298 | const exe_dir_path = std.fs.selfExeDirPath(&exe_dir_buf) catch break :exe_dir; |
| 2259 | .{ | 2299 | var exe_dir = std.fs.openDirAbsolute(exe_dir_path, .{}) catch break :exe_dir; |
| 2260 | .root_dir = std.Build.Cache.Directory.cwd(), | 2300 | defer exe_dir.close(); |
| 2261 | .sub_path = separate_filename, | 2301 | |
| 2262 | }, | 2302 | // <exe_dir>/<gnu_debuglink> |
| 2263 | null, | 2303 | if (loadPath( |
| 2264 | separate_debug_crc, | 2304 | gpa, |
| 2265 | &sections, | 2305 | .{ |
| 2266 | mapped_mem, | 2306 | .root_dir = .{ .path = null, .handle = exe_dir }, |
| 2267 | )) |debug_info| { | 2307 | .sub_path = separate_filename, |
| 2268 | return debug_info; | 2308 | }, |
| 2269 | } else |_| {} | 2309 | null, |
| 2270 | | 2310 | separate_debug_crc, |
| 2271 | // <cwd>/.debug/<gnu_debuglink> | 2311 | &sections, |
| 2272 | { | 2312 | mapped_mem, |
| | 2313 | )) |debug_info| { |
| | 2314 | return debug_info; |
| | 2315 | } else |_| {} |
| | 2316 | |
| | 2317 | // <exe_dir>/.debug/<gnu_debuglink> |
| 2273 | const path: Path = .{ | 2318 | const path: Path = .{ |
| 2274 | .root_dir = std.Build.Cache.Directory.cwd(), | 2319 | .root_dir = .{ .path = null, .handle = exe_dir }, |
| 2275 | .sub_path = try std.fs.path.join(gpa, &.{ ".debug", separate_filename }), | 2320 | .sub_path = try std.fs.path.join(gpa, &.{ ".debug", separate_filename }), |
| 2276 | }; | 2321 | }; |
| 2277 | defer gpa.free(path.sub_path); | 2322 | defer gpa.free(path.sub_path); |