| ... | ... | @@ -248,7 +248,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c |
| 248 | 248 | } |
| 249 | 249 | |
| 250 | 250 | switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) { |
| 251 | | 0 => { |
| 251 | 0, 1 => { |
| 252 | 252 | const stderr = getStderrStream(); |
| 253 | 253 | noasync stderr.print(format ++ "\n", args) catch os.abort(); |
| 254 | 254 | if (trace) |t| { |
| ... | ... | @@ -256,7 +256,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c |
| 256 | 256 | } |
| 257 | 257 | dumpCurrentStackTrace(first_trace_addr); |
| 258 | 258 | }, |
| 259 | | 1 => { |
| 259 | 2 => { |
| 260 | 260 | // TODO detect if a different thread caused the panic, because in that case |
| 261 | 261 | // we would want to return here instead of calling abort, so that the thread |
| 262 | 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 | 404 | |
| 405 | 405 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 406 | 406 | fn printSourceAtAddressWindows( |
| 407 | | di: *DebugInfo, |
| 407 | di1: *DebugInfo, |
| 408 | 408 | out_stream: var, |
| 409 | 409 | relocated_address: usize, |
| 410 | 410 | tty_config: TTY.Config, |
| 411 | 411 | ) !void { |
| 412 | const di = try di1.lookupByAddress(relocated_address); |
| 413 | |
| 412 | 414 | const allocator = getDebugInfoAllocator(); |
| 413 | | const base_address = process.getBaseAddress(); |
| 415 | const base_address = di.base_address; |
| 414 | 416 | const relative_address = relocated_address - base_address; |
| 415 | 417 | |
| 416 | 418 | var coff_section: *coff.Section = undefined; |
| ... | ... | @@ -630,7 +632,7 @@ pub const TTY = struct { |
| 630 | 632 | }; |
| 631 | 633 | |
| 632 | 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 | 636 | if (mod.populated) |
| 635 | 637 | return; |
| 636 | 638 | const allocator = getDebugInfoAllocator(); |
| ... | ... | @@ -824,27 +826,28 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { |
| 824 | 826 | if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) { |
| 825 | 827 | return noasync root.os.debug.openSelfDebugInfo(allocator); |
| 826 | 828 | } |
| 827 | | if (builtin.os == .windows) { |
| 828 | | return noasync openSelfDebugInfoWindows(allocator); |
| 829 | | } |
| 830 | 829 | if (comptime std.Target.current.isDarwin()) { |
| 831 | 830 | return noasync openSelfDebugInfoMacOs(allocator); |
| 832 | 831 | } |
| 833 | | if (builtin.os == .linux) { |
| 832 | if (builtin.os == .linux or builtin.os == .windows) { |
| 834 | 833 | _ = try allocator.create(u32); |
| 835 | 834 | return DebugInfo.init(allocator); |
| 836 | 835 | } |
| 837 | 836 | return noasync openSelfDebugInfoPosix(allocator); |
| 838 | 837 | } |
| 839 | 838 | |
| 840 | | fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { |
| 839 | fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !ObjectDebugInfo { |
| 841 | 840 | const self_file = try fs.openSelfExe(); |
| 842 | 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 | 846 | const coff_obj = try allocator.create(coff.Coff); |
| 845 | 847 | coff_obj.* = coff.Coff.init(allocator, self_file); |
| 846 | 848 | |
| 847 | | var di = DebugInfo{ |
| 849 | var di = ObjectDebugInfo{ |
| 850 | .base_address = 0, |
| 848 | 851 | .coff = coff_obj, |
| 849 | 852 | .pdb = undefined, |
| 850 | 853 | .sect_contribs = undefined, |
| ... | ... | @@ -1202,24 +1205,97 @@ const MachoSymbol = struct { |
| 1202 | 1205 | |
| 1203 | 1206 | pub const DebugInfo = struct { |
| 1204 | 1207 | allocator: *mem.Allocator, |
| 1205 | | address_map: std.StringHashMap(*ObjectDebugInfo), |
| 1208 | address_map: std.AutoHashMap(usize, *ObjectDebugInfo), |
| 1206 | 1209 | |
| 1207 | 1210 | pub fn init(allocator: *mem.Allocator) DebugInfo { |
| 1208 | 1211 | return DebugInfo{ |
| 1209 | 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 | 1217 | pub fn deinit(self: *DebugInfo) void { |
| 1218 | // XXX Free the values |
| 1215 | 1219 | self.address_map.deinit(); |
| 1216 | 1220 | } |
| 1217 | 1221 | |
| 1218 | 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 | 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 | 1299 | fn lookupModuleDl(self: *DebugInfo, address: usize) !*ObjectDebugInfo { |
| 1224 | 1300 | var ctx = DIPContext{ .address = address }; |
| 1225 | 1301 | |
| ... | ... | @@ -1231,7 +1307,7 @@ pub const DebugInfo = struct { |
| 1231 | 1307 | |
| 1232 | 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 | 1311 | warn("cache hit!\n", .{}); |
| 1236 | 1312 | return obj_di; |
| 1237 | 1313 | } |
| ... | ... | @@ -1257,7 +1333,7 @@ pub const DebugInfo = struct { |
| 1257 | 1333 | const obj_di = try self.allocator.create(ObjectDebugInfo); |
| 1258 | 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 | 1338 | obj_di.* = .{ |
| 1263 | 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 | 1365 | const seg_start = info.dlpi_addr + phdr.p_vaddr; |
| 1290 | 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 | 1369 | // Android libc uses NULL instead of an empty string to mark the |
| 1294 | 1370 | // main program |
| 1295 | 1371 | context.?.name = if (info.dlpi_name) |dlpi_name| |
| ... | ... | @@ -1324,6 +1400,7 @@ pub const ObjectDebugInfo = switch (builtin.os) { |
| 1324 | 1400 | } |
| 1325 | 1401 | }, |
| 1326 | 1402 | .uefi, .windows => struct { |
| 1403 | base_address: usize, |
| 1327 | 1404 | pdb: pdb.Pdb, |
| 1328 | 1405 | coff: *coff.Coff, |
| 1329 | 1406 | sect_contribs: []pdb.SectionContribEntry, |