| ... | @@ -248,7 +248,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c | ... | @@ -248,7 +248,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c |
| 248 | } | 248 | } |
| 249 | | 249 | |
| 250 | switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) { | 250 | switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) { |
| 251 | 0 => { | 251 | 0, 1 => { |
| 252 | const stderr = getStderrStream(); | 252 | const stderr = getStderrStream(); |
| 253 | noasync stderr.print(format ++ "\n", args) catch os.abort(); | 253 | noasync stderr.print(format ++ "\n", args) catch os.abort(); |
| 254 | if (trace) |t| { | 254 | if (trace) |t| { |
| ... | @@ -256,7 +256,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c | ... | @@ -256,7 +256,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c |
| 256 | } | 256 | } |
| 257 | dumpCurrentStackTrace(first_trace_addr); | 257 | dumpCurrentStackTrace(first_trace_addr); |
| 258 | }, | 258 | }, |
| 259 | 1 => { | 259 | 2 => { |
| 260 | // TODO detect if a different thread caused the panic, because in that case | 260 | // TODO detect if a different thread caused the panic, because in that case |
| 261 | // we would want to return here instead of calling abort, so that the thread | 261 | // we would want to return here instead of calling abort, so that the thread |
| 262 | // which first called panic can finish printing a stack trace. | 262 | // which first called panic can finish printing a stack trace. |
| ... | @@ -404,13 +404,15 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us | ... | @@ -404,13 +404,15 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us |
| 404 | | 404 | |
| 405 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 405 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 406 | fn printSourceAtAddressWindows( | 406 | fn printSourceAtAddressWindows( |
| 407 | di: *DebugInfo, | 407 | di1: *DebugInfo, |
| 408 | out_stream: var, | 408 | out_stream: var, |
| 409 | relocated_address: usize, | 409 | relocated_address: usize, |
| 410 | tty_config: TTY.Config, | 410 | tty_config: TTY.Config, |
| 411 | ) !void { | 411 | ) !void { |
| | 412 | const di = try di1.lookupByAddress(relocated_address); |
| | 413 | |
| 412 | const allocator = getDebugInfoAllocator(); | 414 | const allocator = getDebugInfoAllocator(); |
| 413 | const base_address = process.getBaseAddress(); | 415 | const base_address = di.base_address; |
| 414 | const relative_address = relocated_address - base_address; | 416 | const relative_address = relocated_address - base_address; |
| 415 | | 417 | |
| 416 | var coff_section: *coff.Section = undefined; | 418 | var coff_section: *coff.Section = undefined; |
| ... | @@ -630,7 +632,7 @@ pub const TTY = struct { | ... | @@ -630,7 +632,7 @@ pub const TTY = struct { |
| 630 | }; | 632 | }; |
| 631 | | 633 | |
| 632 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 634 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 633 | fn populateModule(di: *DebugInfo, mod: *Module) !void { | 635 | fn populateModule(di: *ObjectDebugInfo, mod: *Module) !void { |
| 634 | if (mod.populated) | 636 | if (mod.populated) |
| 635 | return; | 637 | return; |
| 636 | const allocator = getDebugInfoAllocator(); | 638 | const allocator = getDebugInfoAllocator(); |
| ... | @@ -824,27 +826,28 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -824,27 +826,28 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { |
| 824 | if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) { | 826 | if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) { |
| 825 | return noasync root.os.debug.openSelfDebugInfo(allocator); | 827 | return noasync root.os.debug.openSelfDebugInfo(allocator); |
| 826 | } | 828 | } |
| 827 | if (builtin.os == .windows) { | | |
| 828 | return noasync openSelfDebugInfoWindows(allocator); | | |
| 829 | } | | |
| 830 | if (comptime std.Target.current.isDarwin()) { | 829 | if (comptime std.Target.current.isDarwin()) { |
| 831 | return noasync openSelfDebugInfoMacOs(allocator); | 830 | return noasync openSelfDebugInfoMacOs(allocator); |
| 832 | } | 831 | } |
| 833 | if (builtin.os == .linux) { | 832 | if (builtin.os == .linux or builtin.os == .windows) { |
| 834 | _ = try allocator.create(u32); | 833 | _ = try allocator.create(u32); |
| 835 | return DebugInfo.init(allocator); | 834 | return DebugInfo.init(allocator); |
| 836 | } | 835 | } |
| 837 | return noasync openSelfDebugInfoPosix(allocator); | 836 | return noasync openSelfDebugInfoPosix(allocator); |
| 838 | } | 837 | } |
| 839 | | 838 | |
| 840 | fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { | 839 | fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !ObjectDebugInfo { |
| 841 | const self_file = try fs.openSelfExe(); | 840 | const self_file = try fs.openSelfExe(); |
| 842 | defer self_file.close(); | 841 | defer self_file.close(); |
| | 842 | return openCoffDebugInfo(allocator, self_file); |
| | 843 | } |
| 843 | | 844 | |
| | 845 | fn openCoffDebugInfo(allocator: *mem.Allocator, self_file: fs.File) !ObjectDebugInfo { |
| 844 | const coff_obj = try allocator.create(coff.Coff); | 846 | const coff_obj = try allocator.create(coff.Coff); |
| 845 | coff_obj.* = coff.Coff.init(allocator, self_file); | 847 | coff_obj.* = coff.Coff.init(allocator, self_file); |
| 846 | | 848 | |
| 847 | var di = DebugInfo{ | 849 | var di = ObjectDebugInfo{ |
| | 850 | .base_address = 0, |
| 848 | .coff = coff_obj, | 851 | .coff = coff_obj, |
| 849 | .pdb = undefined, | 852 | .pdb = undefined, |
| 850 | .sect_contribs = undefined, | 853 | .sect_contribs = undefined, |
| ... | @@ -1202,24 +1205,97 @@ const MachoSymbol = struct { | ... | @@ -1202,24 +1205,97 @@ const MachoSymbol = struct { |
| 1202 | | 1205 | |
| 1203 | pub const DebugInfo = struct { | 1206 | pub const DebugInfo = struct { |
| 1204 | allocator: *mem.Allocator, | 1207 | allocator: *mem.Allocator, |
| 1205 | address_map: std.StringHashMap(*ObjectDebugInfo), | 1208 | address_map: std.AutoHashMap(usize, *ObjectDebugInfo), |
| 1206 | | 1209 | |
| 1207 | pub fn init(allocator: *mem.Allocator) DebugInfo { | 1210 | pub fn init(allocator: *mem.Allocator) DebugInfo { |
| 1208 | return DebugInfo{ | 1211 | return DebugInfo{ |
| 1209 | .allocator = allocator, | 1212 | .allocator = allocator, |
| 1210 | .address_map = std.StringHashMap(*ObjectDebugInfo).init(allocator), | 1213 | .address_map = std.AutoHashMap(usize, *ObjectDebugInfo).init(allocator), |
| 1211 | }; | 1214 | }; |
| 1212 | } | 1215 | } |
| 1213 | | 1216 | |
| 1214 | pub fn deinit(self: *DebugInfo) void { | 1217 | pub fn deinit(self: *DebugInfo) void { |
| | 1218 | // XXX Free the values |
| 1215 | self.address_map.deinit(); | 1219 | self.address_map.deinit(); |
| 1216 | } | 1220 | } |
| 1217 | | 1221 | |
| 1218 | pub fn lookupByAddress(self: *DebugInfo, address: usize) !*ObjectDebugInfo { | 1222 | pub fn lookupByAddress(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1219 | const obj_di = try self.lookupModuleDl(address); | 1223 | const obj_di = if (builtin.os == .windows) |
| | 1224 | try self.lookupModuleWin32(address) |
| | 1225 | else |
| | 1226 | try self.lookupModuleDl(address); |
| 1220 | return obj_di; | 1227 | return obj_di; |
| 1221 | } | 1228 | } |
| 1222 | | 1229 | |
| | 1230 | fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| | 1231 | const process_handle = windows.kernel32.GetCurrentProcess(); |
| | 1232 | |
| | 1233 | var modules: [32]windows.HMODULE = undefined; |
| | 1234 | var modules_needed: windows.DWORD = undefined; |
| | 1235 | // XXX Ask for the number of modules by passing size zero |
| | 1236 | if (windows.kernel32.K32EnumProcessModules( |
| | 1237 | process_handle, |
| | 1238 | @ptrCast([*]windows.HMODULE, &modules), |
| | 1239 | @sizeOf(@TypeOf(modules)), |
| | 1240 | &modules_needed, |
| | 1241 | ) == 0) |
| | 1242 | return error.DebugInfoNotFound; |
| | 1243 | |
| | 1244 | for (modules[0..modules_needed]) |module| { |
| | 1245 | var info: windows.MODULEINFO = undefined; |
| | 1246 | if (windows.kernel32.K32GetModuleInformation( |
| | 1247 | process_handle, |
| | 1248 | module, |
| | 1249 | &info, |
| | 1250 | @sizeOf(@TypeOf(info)), |
| | 1251 | ) == 0) |
| | 1252 | return error.DebugInfoNotFound; |
| | 1253 | |
| | 1254 | const seg_start = @ptrToInt(info.lpBaseOfDll); |
| | 1255 | const seg_end = seg_start + info.SizeOfImage; |
| | 1256 | |
| | 1257 | if (address >= seg_start and address < seg_end) { |
| | 1258 | var name_buffer: [windows.PATH_MAX_WIDE]u16 = [_]u16{0} ** windows.PATH_MAX_WIDE; |
| | 1259 | // XXX Use W variant |
| | 1260 | const len = windows.kernel32.K32GetModuleFileNameExW( |
| | 1261 | process_handle, |
| | 1262 | module, |
| | 1263 | @ptrCast(windows.LPWSTR, &name_buffer), |
| | 1264 | @sizeOf(@TypeOf(name_buffer)) / @sizeOf(u16), |
| | 1265 | ); |
| | 1266 | assert(len > 0); |
| | 1267 | const name_slice = mem.toSlice(u16, name_buffer[0..:0]); |
| | 1268 | warn("slice len {}\n", .{name_slice.len}); |
| | 1269 | |
| | 1270 | const x = try std.unicode.utf16leToUtf8Alloc(self.allocator, name_buffer[0..]); |
| | 1271 | warn("ask for {s} len {}\n", .{ x, name_slice.len }); |
| | 1272 | self.allocator.free(x); |
| | 1273 | |
| | 1274 | if (self.address_map.getValue(seg_start)) |obj_di| { |
| | 1275 | warn("cache hit!\n", .{}); |
| | 1276 | return obj_di; |
| | 1277 | } |
| | 1278 | |
| | 1279 | warn("loading?\n", .{}); |
| | 1280 | const file_obj = try fs.openFileAbsoluteW(name_slice, .{}); |
| | 1281 | errdefer file_obj.close(); |
| | 1282 | warn("loaded!\n", .{}); |
| | 1283 | |
| | 1284 | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| | 1285 | errdefer self.allocator.destroy(obj_di); |
| | 1286 | |
| | 1287 | try self.address_map.putNoClobber(seg_start, obj_di); |
| | 1288 | |
| | 1289 | obj_di.* = try openCoffDebugInfo(self.allocator, file_obj); |
| | 1290 | obj_di.base_address = seg_start; |
| | 1291 | |
| | 1292 | return obj_di; |
| | 1293 | } |
| | 1294 | } |
| | 1295 | |
| | 1296 | return error.DebugInfoNotFound; |
| | 1297 | } |
| | 1298 | |
| 1223 | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo { | 1299 | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1224 | var ctx = DIPContext{ .address = address }; | 1300 | var ctx = DIPContext{ .address = address }; |
| 1225 | | 1301 | |
| ... | @@ -1231,7 +1307,7 @@ pub const DebugInfo = struct { | ... | @@ -1231,7 +1307,7 @@ pub const DebugInfo = struct { |
| 1231 | | 1307 | |
| 1232 | warn("found in \"{s}\"\n", .{ctx.name}); | 1308 | warn("found in \"{s}\"\n", .{ctx.name}); |
| 1233 | | 1309 | |
| 1234 | if (self.address_map.getValue(ctx.name)) |obj_di| { | 1310 | if (self.address_map.getValue(ctx.base_address)) |obj_di| { |
| 1235 | warn("cache hit!\n", .{}); | 1311 | warn("cache hit!\n", .{}); |
| 1236 | return obj_di; | 1312 | return obj_di; |
| 1237 | } | 1313 | } |
| ... | @@ -1257,7 +1333,7 @@ pub const DebugInfo = struct { | ... | @@ -1257,7 +1333,7 @@ pub const DebugInfo = struct { |
| 1257 | const obj_di = try self.allocator.create(ObjectDebugInfo); | 1333 | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| 1258 | errdefer self.allocator.destroy(obj_di); | 1334 | errdefer self.allocator.destroy(obj_di); |
| 1259 | | 1335 | |
| 1260 | try self.address_map.putNoClobber(ctx.name, obj_di); | 1336 | try self.address_map.putNoClobber(ctx.base_address, obj_di); |
| 1261 | | 1337 | |
| 1262 | obj_di.* = .{ | 1338 | obj_di.* = .{ |
| 1263 | .dwarf = try openElfDebugInfo(self.allocator, exe_mmap), | 1339 | .dwarf = try openElfDebugInfo(self.allocator, exe_mmap), |
| ... | @@ -1289,7 +1365,7 @@ fn dl_iterate_phdr_callback(info: *os.dl_phdr_info, size: usize, context: ?*DIPC | ... | @@ -1289,7 +1365,7 @@ fn dl_iterate_phdr_callback(info: *os.dl_phdr_info, size: usize, context: ?*DIPC |
| 1289 | const seg_start = info.dlpi_addr + phdr.p_vaddr; | 1365 | const seg_start = info.dlpi_addr + phdr.p_vaddr; |
| 1290 | const seg_end = seg_start + phdr.p_memsz; | 1366 | const seg_end = seg_start + phdr.p_memsz; |
| 1291 | | 1367 | |
| 1292 | if (address > seg_start and address <= seg_end) { | 1368 | if (address >= seg_start and address < seg_end) { |
| 1293 | // Android libc uses NULL instead of an empty string to mark the | 1369 | // Android libc uses NULL instead of an empty string to mark the |
| 1294 | // main program | 1370 | // main program |
| 1295 | context.?.name = if (info.dlpi_name) |dlpi_name| | 1371 | context.?.name = if (info.dlpi_name) |dlpi_name| |
| ... | @@ -1324,6 +1400,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { | ... | @@ -1324,6 +1400,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { |
| 1324 | } | 1400 | } |
| 1325 | }, | 1401 | }, |
| 1326 | .uefi, .windows => struct { | 1402 | .uefi, .windows => struct { |
| | 1403 | base_address: usize, |
| 1327 | pdb: pdb.Pdb, | 1404 | pdb: pdb.Pdb, |
| 1328 | coff: *coff.Coff, | 1405 | coff: *coff.Coff, |
| 1329 | sect_contribs: []pdb.SectionContribEntry, | 1406 | sect_contribs: []pdb.SectionContribEntry, |