authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-10 18:08:12-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-10 18:08:12-05:00
log9b807f9c171e9e5998447ab3846d29de921cf8dd
treee52212b34832435f3f7118eec44540c509da4b34
parentbb4cb342048a9feee7e5408c4f444439197a96af
parent58e558822a2980bcaf29ce2a07474093702cabc6
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14247 from kcbanner/windows_improve_module_lookup

Windows debug info lookup improvements

4 files changed, 208 insertions(+), 159 deletions(-)

lib/std/coff.zig+39-44
......@@ -1061,65 +1061,55 @@ pub const CoffError = error{
10611061
10621062// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
10631063pub const Coff = struct {
1064 allocator: mem.Allocator,
1065 data: []const u8 = undefined,
1066 is_image: bool = false,
1067 coff_header_offset: usize = 0,
1064 data: []const u8,
1065 is_image: bool,
1066 coff_header_offset: usize,
10681067
10691068 guid: [16]u8 = undefined,
10701069 age: u32 = undefined,
10711070
1072 pub fn deinit(self: *Coff) void {
1073 self.allocator.free(self.data);
1074 }
1075
1076 /// Takes ownership of `data`.
1077 pub fn parse(self: *Coff, data: []const u8) !void {
1078 self.data = data;
1079
1071 // The lifetime of `data` must be longer than the lifetime of the returned Coff
1072 pub fn init(data: []const u8) !Coff {
10801073 const pe_pointer_offset = 0x3C;
10811074 const pe_magic = "PE\x00\x00";
10821075
1083 var stream = std.io.fixedBufferStream(self.data);
1076 var stream = std.io.fixedBufferStream(data);
10841077 const reader = stream.reader();
10851078 try stream.seekTo(pe_pointer_offset);
1086 const coff_header_offset = try reader.readIntLittle(u32);
1079 var coff_header_offset = try reader.readIntLittle(u32);
10871080 try stream.seekTo(coff_header_offset);
10881081 var buf: [4]u8 = undefined;
10891082 try reader.readNoEof(&buf);
1090 self.is_image = mem.eql(u8, pe_magic, &buf);
1083 const is_image = mem.eql(u8, pe_magic, &buf);
1084
1085 var coff = @This(){
1086 .data = data,
1087 .is_image = is_image,
1088 .coff_header_offset = coff_header_offset,
1089 };
10911090
10921091 // Do some basic validation upfront
1093 if (self.is_image) {
1094 self.coff_header_offset = coff_header_offset + 4;
1095 const coff_header = self.getCoffHeader();
1092 if (is_image) {
1093 coff.coff_header_offset = coff.coff_header_offset + 4;
1094 const coff_header = coff.getCoffHeader();
10961095 if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;
10971096 }
10981097
10991098 // JK: we used to check for architecture here and throw an error if not x86 or derivative.
11001099 // However I am willing to take a leap of faith and let aarch64 have a shot also.
1100
1101 return coff;
11011102 }
11021103
11031104 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
11041105 assert(self.is_image);
11051106
1106 const header = blk: {
1107 if (self.getSectionByName(".buildid")) |hdr| {
1108 break :blk hdr;
1109 } else if (self.getSectionByName(".rdata")) |hdr| {
1110 break :blk hdr;
1111 } else {
1112 return error.MissingCoffSection;
1113 }
1114 };
1115
11161107 const data_dirs = self.getDataDirectories();
11171108 const debug_dir = data_dirs[@enumToInt(DirectoryEntry.DEBUG)];
1118 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
11191109
11201110 var stream = std.io.fixedBufferStream(self.data);
11211111 const reader = stream.reader();
1122 try stream.seekTo(file_offset);
1112 try stream.seekTo(debug_dir.virtual_address);
11231113
11241114 // Find the correct DebugDirectoryEntry, and where its data is stored.
11251115 // It can be in any section.
......@@ -1128,16 +1118,8 @@ pub const Coff = struct {
11281118 blk: while (i < debug_dir_entry_count) : (i += 1) {
11291119 const debug_dir_entry = try reader.readStruct(DebugDirectoryEntry);
11301120 if (debug_dir_entry.type == .CODEVIEW) {
1131 for (self.getSectionHeaders()) |*section| {
1132 const section_start = section.virtual_address;
1133 const section_size = section.virtual_size;
1134 const rva = debug_dir_entry.address_of_raw_data;
1135 const offset = rva - section_start;
1136 if (section_start <= rva and offset < section_size and debug_dir_entry.size_of_data <= section_size - offset) {
1137 try stream.seekTo(section.pointer_to_raw_data + offset);
1138 break :blk;
1139 }
1140 }
1121 try stream.seekTo(debug_dir_entry.address_of_raw_data);
1122 break :blk;
11411123 }
11421124 }
11431125
......@@ -1238,6 +1220,16 @@ pub const Coff = struct {
12381220 return @ptrCast([*]align(1) const SectionHeader, self.data.ptr + offset)[0..coff_header.number_of_sections];
12391221 }
12401222
1223 pub fn getSectionHeadersAlloc(self: *const Coff, allocator: mem.Allocator) ![]SectionHeader {
1224 const section_headers = self.getSectionHeaders();
1225 const out_buff = try allocator.alloc(SectionHeader, section_headers.len);
1226 for (out_buff) |*section_header, i| {
1227 section_header.* = section_headers[i];
1228 }
1229
1230 return out_buff;
1231 }
1232
12411233 pub fn getSectionName(self: *const Coff, sect_hdr: *align(1) const SectionHeader) []const u8 {
12421234 const name = sect_hdr.getName() orelse blk: {
12431235 const strtab = self.getStrtab().?;
......@@ -1256,12 +1248,15 @@ pub const Coff = struct {
12561248 return null;
12571249 }
12581250
1251 pub fn getSectionData(self: *const Coff, comptime name: []const u8) ![]const u8 {
1252 const sec = self.getSectionByName(name) orelse return error.MissingCoffSection;
1253 return self.data[sec.pointer_to_raw_data..][0..sec.virtual_size];
1254 }
1255
12591256 // Return an owned slice full of the section data
12601257 pub fn getSectionDataAlloc(self: *const Coff, comptime name: []const u8, allocator: mem.Allocator) ![]u8 {
1261 const sec = self.getSectionByName(name) orelse return error.MissingCoffSection;
1262 const out_buff = try allocator.alloc(u8, sec.virtual_size);
1263 mem.copy(u8, out_buff, self.data[sec.pointer_to_raw_data..][0..sec.virtual_size]);
1264 return out_buff;
1258 const section_data = try self.getSectionData(name);
1259 return allocator.dupe(u8, section_data);
12651260 }
12661261};
12671262
lib/std/debug.zig+118-113
......@@ -811,7 +811,7 @@ fn printLineInfo(
811811pub const OpenSelfDebugInfoError = error{
812812 MissingDebugInfo,
813813 UnsupportedOperatingSystem,
814};
814} || @typeInfo(@typeInfo(@TypeOf(DebugInfo.init)).Fn.return_type.?).ErrorUnion.error_set;
815815
816816pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugInfo {
817817 nosuspend {
......@@ -827,60 +827,56 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugI
827827 .dragonfly,
828828 .openbsd,
829829 .macos,
830 .windows,
831830 .solaris,
832 => return DebugInfo.init(allocator),
831 .windows,
832 => return try DebugInfo.init(allocator),
833833 else => return error.UnsupportedOperatingSystem,
834834 }
835835 }
836836}
837837
838/// This takes ownership of coff_file: users of this function should not close
839/// it themselves, even on error.
840/// TODO it's weird to take ownership even on error, rework this code.
841fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {
838fn readCoffDebugInfo(allocator: mem.Allocator, coff_bytes: []const u8) !ModuleDebugInfo {
842839 nosuspend {
843 defer coff_file.close();
844
845840 const coff_obj = try allocator.create(coff.Coff);
846 errdefer allocator.destroy(coff_obj);
847 coff_obj.* = .{ .allocator = allocator };
841 defer allocator.destroy(coff_obj);
842 coff_obj.* = try coff.Coff.init(coff_bytes);
848843
849844 var di = ModuleDebugInfo{
850845 .base_address = undefined,
851 .coff = coff_obj,
846 .coff_image_base = coff_obj.getImageBase(),
847 .coff_section_headers = undefined,
852848 .debug_data = undefined,
853849 };
854850
855 // TODO convert to Windows' memory-mapped file API
856 const file_len = math.cast(usize, try coff_file.getEndPos()) orelse math.maxInt(usize);
857 const data = try coff_file.readToEndAlloc(allocator, file_len);
858 try di.coff.parse(data);
859
860 if (di.coff.getSectionByName(".debug_info")) |sec| {
851 if (coff_obj.getSectionByName(".debug_info")) |sec| {
861852 // This coff file has embedded DWARF debug info
862853 _ = sec;
863 // TODO: free the section data slices
864 const debug_info = di.coff.getSectionDataAlloc(".debug_info", allocator) catch null;
865 const debug_abbrev = di.coff.getSectionDataAlloc(".debug_abbrev", allocator) catch null;
866 const debug_str = di.coff.getSectionDataAlloc(".debug_str", allocator) catch null;
867 const debug_str_offsets = di.coff.getSectionDataAlloc(".debug_str_offsets", allocator) catch null;
868 const debug_line = di.coff.getSectionDataAlloc(".debug_line", allocator) catch null;
869 const debug_line_str = di.coff.getSectionDataAlloc(".debug_line_str", allocator) catch null;
870 const debug_ranges = di.coff.getSectionDataAlloc(".debug_ranges", allocator) catch null;
871 const debug_loclists = di.coff.getSectionDataAlloc(".debug_loclists", allocator) catch null;
872 const debug_rnglists = di.coff.getSectionDataAlloc(".debug_rnglists", allocator) catch null;
873 const debug_addr = di.coff.getSectionDataAlloc(".debug_addr", allocator) catch null;
874 const debug_names = di.coff.getSectionDataAlloc(".debug_names", allocator) catch null;
875 const debug_frame = di.coff.getSectionDataAlloc(".debug_frame", allocator) catch null;
854
855 const debug_info = coff_obj.getSectionDataAlloc(".debug_info", allocator) catch return error.MissingDebugInfo;
856 errdefer allocator.free(debug_info);
857 const debug_abbrev = coff_obj.getSectionDataAlloc(".debug_abbrev", allocator) catch return error.MissingDebugInfo;
858 errdefer allocator.free(debug_abbrev);
859 const debug_str = coff_obj.getSectionDataAlloc(".debug_str", allocator) catch return error.MissingDebugInfo;
860 errdefer allocator.free(debug_str);
861 const debug_line = coff_obj.getSectionDataAlloc(".debug_line", allocator) catch return error.MissingDebugInfo;
862 errdefer allocator.free(debug_line);
863
864 const debug_str_offsets = coff_obj.getSectionDataAlloc(".debug_str_offsets", allocator) catch null;
865 const debug_line_str = coff_obj.getSectionDataAlloc(".debug_line_str", allocator) catch null;
866 const debug_ranges = coff_obj.getSectionDataAlloc(".debug_ranges", allocator) catch null;
867 const debug_loclists = coff_obj.getSectionDataAlloc(".debug_loclists", allocator) catch null;
868 const debug_rnglists = coff_obj.getSectionDataAlloc(".debug_rnglists", allocator) catch null;
869 const debug_addr = coff_obj.getSectionDataAlloc(".debug_addr", allocator) catch null;
870 const debug_names = coff_obj.getSectionDataAlloc(".debug_names", allocator) catch null;
871 const debug_frame = coff_obj.getSectionDataAlloc(".debug_frame", allocator) catch null;
876872
877873 var dwarf = DW.DwarfInfo{
878874 .endian = native_endian,
879 .debug_info = debug_info orelse return error.MissingDebugInfo,
880 .debug_abbrev = debug_abbrev orelse return error.MissingDebugInfo,
881 .debug_str = debug_str orelse return error.MissingDebugInfo,
875 .debug_info = debug_info,
876 .debug_abbrev = debug_abbrev,
877 .debug_str = debug_str,
882878 .debug_str_offsets = debug_str_offsets,
883 .debug_line = debug_line orelse return error.MissingDebugInfo,
879 .debug_line = debug_line,
884880 .debug_line_str = debug_line_str,
885881 .debug_ranges = debug_ranges,
886882 .debug_loclists = debug_loclists,
......@@ -889,13 +885,28 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
889885 .debug_names = debug_names,
890886 .debug_frame = debug_frame,
891887 };
892 try DW.openDwarfDebugInfo(&dwarf, allocator);
888
889 DW.openDwarfDebugInfo(&dwarf, allocator) catch |err| {
890 if (debug_str_offsets) |d| allocator.free(d);
891 if (debug_line_str) |d| allocator.free(d);
892 if (debug_ranges) |d| allocator.free(d);
893 if (debug_loclists) |d| allocator.free(d);
894 if (debug_rnglists) |d| allocator.free(d);
895 if (debug_addr) |d| allocator.free(d);
896 if (debug_names) |d| allocator.free(d);
897 if (debug_frame) |d| allocator.free(d);
898 return err;
899 };
900
893901 di.debug_data = PdbOrDwarf{ .dwarf = dwarf };
894902 return di;
895903 }
896904
905 // Only used by pdb path
906 di.coff_section_headers = try coff_obj.getSectionHeadersAlloc(allocator);
907
897908 var path_buf: [windows.MAX_PATH]u8 = undefined;
898 const len = try di.coff.getPdbPath(path_buf[0..]);
909 const len = try coff_obj.getPdbPath(path_buf[0..]);
899910 const raw_path = path_buf[0..len];
900911
901912 const path = try fs.path.resolve(allocator, &[_][]const u8{raw_path});
......@@ -909,7 +920,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
909920 try di.debug_data.pdb.parseInfoStream();
910921 try di.debug_data.pdb.parseDbiStream();
911922
912 if (!mem.eql(u8, &di.coff.guid, &di.debug_data.pdb.guid) or di.coff.age != di.debug_data.pdb.age)
923 if (!mem.eql(u8, &coff_obj.guid, &di.debug_data.pdb.guid) or coff_obj.age != di.debug_data.pdb.age)
913924 return error.InvalidDebugInfo;
914925
915926 return di;
......@@ -1225,15 +1236,49 @@ fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 {
12251236 }
12261237}
12271238
1239pub const ModuleInfo = struct {
1240 base_address: usize,
1241 size: u32,
1242};
1243
12281244pub const DebugInfo = struct {
12291245 allocator: mem.Allocator,
12301246 address_map: std.AutoHashMap(usize, *ModuleDebugInfo),
1247 modules: if (native_os == .windows) std.ArrayListUnmanaged(ModuleInfo) else void,
12311248
1232 pub fn init(allocator: mem.Allocator) DebugInfo {
1233 return DebugInfo{
1249 pub fn init(allocator: mem.Allocator) !DebugInfo {
1250 var debug_info = DebugInfo{
12341251 .allocator = allocator,
12351252 .address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator),
1253 .modules = if (native_os == .windows) .{} else {},
12361254 };
1255
1256 if (native_os == .windows) {
1257 const handle = windows.kernel32.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE | windows.TH32CS_SNAPMODULE32, 0);
1258 if (handle == windows.INVALID_HANDLE_VALUE) {
1259 switch (windows.kernel32.GetLastError()) {
1260 else => |err| return windows.unexpectedError(err),
1261 }
1262 }
1263
1264 defer windows.CloseHandle(handle);
1265
1266 var module_entry: windows.MODULEENTRY32 = undefined;
1267 module_entry.dwSize = @sizeOf(windows.MODULEENTRY32);
1268 if (windows.kernel32.Module32First(handle, &module_entry) == 0) {
1269 return error.MissingDebugInfo;
1270 }
1271
1272 var module_valid = true;
1273 while (module_valid) {
1274 const module_info = try debug_info.modules.addOne(allocator);
1275 module_info.base_address = @ptrToInt(module_entry.modBaseAddr);
1276 module_info.size = module_entry.modBaseSize;
1277 module_valid = windows.kernel32.Module32Next(handle, &module_entry) == 1;
1278 }
1279 }
1280
1281 return debug_info;
12371282 }
12381283
12391284 pub fn deinit(self: *DebugInfo) void {
......@@ -1244,6 +1289,7 @@ pub const DebugInfo = struct {
12441289 self.allocator.destroy(mdi);
12451290 }
12461291 self.address_map.deinit();
1292 if (native_os == .windows) self.modules.deinit(self.allocator);
12471293 }
12481294
12491295 pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
......@@ -1322,79 +1368,20 @@ pub const DebugInfo = struct {
13221368 }
13231369
13241370 fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
1325 const process_handle = windows.kernel32.GetCurrentProcess();
1326
1327 // Find how many modules are actually loaded
1328 var dummy: windows.HMODULE = undefined;
1329 var bytes_needed: windows.DWORD = undefined;
1330 if (windows.kernel32.K32EnumProcessModules(
1331 process_handle,
1332 @ptrCast([*]windows.HMODULE, &dummy),
1333 0,
1334 &bytes_needed,
1335 ) == 0)
1336 return error.MissingDebugInfo;
1337
1338 const needed_modules = bytes_needed / @sizeOf(windows.HMODULE);
1339
1340 // Fetch the complete module list
1341 var modules = try self.allocator.alloc(windows.HMODULE, needed_modules);
1342 defer self.allocator.free(modules);
1343 if (windows.kernel32.K32EnumProcessModules(
1344 process_handle,
1345 modules.ptr,
1346 math.cast(windows.DWORD, modules.len * @sizeOf(windows.HMODULE)) orelse return error.Overflow,
1347 &bytes_needed,
1348 ) == 0)
1349 return error.MissingDebugInfo;
1350
1351 // There's an unavoidable TOCTOU problem here, the module list may have
1352 // changed between the two EnumProcessModules call.
1353 // Pick the smallest amount of elements to avoid processing garbage.
1354 const needed_modules_after = bytes_needed / @sizeOf(windows.HMODULE);
1355 const loaded_modules = math.min(needed_modules, needed_modules_after);
1356
1357 for (modules[0..loaded_modules]) |module| {
1358 var info: windows.MODULEINFO = undefined;
1359 if (windows.kernel32.K32GetModuleInformation(
1360 process_handle,
1361 module,
1362 &info,
1363 @sizeOf(@TypeOf(info)),
1364 ) == 0)
1365 return error.MissingDebugInfo;
1366
1367 const seg_start = @ptrToInt(info.lpBaseOfDll);
1368 const seg_end = seg_start + info.SizeOfImage;
1369
1370 if (address >= seg_start and address < seg_end) {
1371 if (self.address_map.get(seg_start)) |obj_di| {
1371 for (self.modules.items) |module| {
1372 if (address >= module.base_address and address < module.base_address + module.size) {
1373 if (self.address_map.get(module.base_address)) |obj_di| {
13721374 return obj_di;
13731375 }
13741376
1375 var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined;
1376 // openFileAbsoluteW requires the prefix to be present
1377 mem.copy(u16, name_buffer[0..4], &[_]u16{ '\\', '?', '?', '\\' });
1378 const len = windows.kernel32.K32GetModuleFileNameExW(
1379 process_handle,
1380 module,
1381 @ptrCast(windows.LPWSTR, &name_buffer[4]),
1382 windows.PATH_MAX_WIDE,
1383 );
1384 assert(len > 0);
1385
1377 const mapped_module = @intToPtr([*]const u8, module.base_address)[0..module.size];
13861378 const obj_di = try self.allocator.create(ModuleDebugInfo);
13871379 errdefer self.allocator.destroy(obj_di);
13881380
1389 const coff_file = fs.openFileAbsoluteW(name_buffer[0 .. len + 4 :0], .{}) catch |err| switch (err) {
1390 error.FileNotFound => return error.MissingDebugInfo,
1391 else => return err,
1392 };
1393 obj_di.* = try readCoffDebugInfo(self.allocator, coff_file);
1394 obj_di.base_address = seg_start;
1395
1396 try self.address_map.putNoClobber(seg_start, obj_di);
1381 obj_di.* = try readCoffDebugInfo(self.allocator, mapped_module);
1382 obj_di.base_address = module.base_address;
13971383
1384 try self.address_map.putNoClobber(module.base_address, obj_di);
13981385 return obj_di;
13991386 }
14001387 }
......@@ -1727,12 +1714,31 @@ pub const ModuleDebugInfo = switch (native_os) {
17271714 .uefi, .windows => struct {
17281715 base_address: usize,
17291716 debug_data: PdbOrDwarf,
1730 coff: *coff.Coff,
1717 coff_image_base: u64,
1718 coff_section_headers: []coff.SectionHeader,
17311719
17321720 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1721 switch (self.debug_data) {
1722 .dwarf => |*dwarf| {
1723 allocator.free(dwarf.debug_info);
1724 allocator.free(dwarf.debug_abbrev);
1725 allocator.free(dwarf.debug_str);
1726 allocator.free(dwarf.debug_line);
1727 if (dwarf.debug_str_offsets) |d| allocator.free(d);
1728 if (dwarf.debug_line_str) |d| allocator.free(d);
1729 if (dwarf.debug_ranges) |d| allocator.free(d);
1730 if (dwarf.debug_loclists) |d| allocator.free(d);
1731 if (dwarf.debug_rnglists) |d| allocator.free(d);
1732 if (dwarf.debug_addr) |d| allocator.free(d);
1733 if (dwarf.debug_names) |d| allocator.free(d);
1734 if (dwarf.debug_frame) |d| allocator.free(d);
1735 },
1736 .pdb => {
1737 allocator.free(self.coff_section_headers);
1738 },
1739 }
1740
17331741 self.debug_data.deinit(allocator);
1734 self.coff.deinit();
1735 allocator.destroy(self.coff);
17361742 }
17371743
17381744 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
......@@ -1741,7 +1747,7 @@ pub const ModuleDebugInfo = switch (native_os) {
17411747
17421748 switch (self.debug_data) {
17431749 .dwarf => |*dwarf| {
1744 const dwarf_address = relocated_address + self.coff.getImageBase();
1750 const dwarf_address = relocated_address + self.coff_image_base;
17451751 return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
17461752 },
17471753 .pdb => {
......@@ -1751,10 +1757,9 @@ pub const ModuleDebugInfo = switch (native_os) {
17511757
17521758 var coff_section: *align(1) const coff.SectionHeader = undefined;
17531759 const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| {
1754 const sections = self.coff.getSectionHeaders();
1755 if (sect_contrib.Section > sections.len) continue;
1760 if (sect_contrib.Section > self.coff_section_headers.len) continue;
17561761 // Remember that SectionContribEntry.Section is 1-based.
1757 coff_section = &sections[sect_contrib.Section - 1];
1762 coff_section = &self.coff_section_headers[sect_contrib.Section - 1];
17581763
17591764 const vaddr_start = coff_section.virtual_address + sect_contrib.Offset;
17601765 const vaddr_end = vaddr_start + sect_contrib.Size;
lib/std/os/windows.zig+44-2
......@@ -2077,7 +2077,7 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
20772077 );
20782078 _ = std.unicode.utf16leToUtf8(&buf_utf8, buf_wstr[0..len]) catch unreachable;
20792079 std.debug.print("error.Unexpected: GetLastError({}): {s}\n", .{ @enumToInt(err), buf_utf8[0..len] });
2080 std.debug.dumpCurrentStackTrace(null);
2080 std.debug.dumpCurrentStackTrace(@returnAddress());
20812081 }
20822082 return error.Unexpected;
20832083}
......@@ -2091,7 +2091,7 @@ pub fn unexpectedWSAError(err: ws2_32.WinsockError) std.os.UnexpectedError {
20912091pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
20922092 if (std.os.unexpected_error_tracing) {
20932093 std.debug.print("error.Unexpected NTSTATUS=0x{x}\n", .{@enumToInt(status)});
2094 std.debug.dumpCurrentStackTrace(null);
2094 std.debug.dumpCurrentStackTrace(@returnAddress());
20952095 }
20962096 return error.Unexpected;
20972097}
......@@ -3801,6 +3801,26 @@ pub const PEB_LDR_DATA = extern struct {
38013801 ShutdownThreadId: HANDLE,
38023802};
38033803
3804/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
3805/// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data
3806/// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm
3807pub const LDR_DATA_TABLE_ENTRY = extern struct {
3808 Reserved1: [2]PVOID,
3809 InMemoryOrderLinks: LIST_ENTRY,
3810 Reserved2: [2]PVOID,
3811 DllBase: PVOID,
3812 EntryPoint: PVOID,
3813 SizeOfImage: ULONG,
3814 FullDllName: UNICODE_STRING,
3815 Reserved4: [8]BYTE,
3816 Reserved5: [3]PVOID,
3817 DUMMYUNIONNAME: extern union {
3818 CheckSum: ULONG,
3819 Reserved6: PVOID,
3820 },
3821 TimeDateStamp: ULONG,
3822};
3823
38043824pub const RTL_USER_PROCESS_PARAMETERS = extern struct {
38053825 AllocationSize: ULONG,
38063826 Size: ULONG,
......@@ -4349,3 +4369,25 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool {
43494369 if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false;
43504370 return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1;
43514371}
4372
4373pub const TH32CS_SNAPHEAPLIST = 0x00000001;
4374pub const TH32CS_SNAPPROCESS = 0x00000002;
4375pub const TH32CS_SNAPTHREAD = 0x00000004;
4376pub const TH32CS_SNAPMODULE = 0x00000008;
4377pub const TH32CS_SNAPMODULE32 = 0x00000010;
4378pub const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE;
4379pub const TH32CS_INHERIT = 0x80000000;
4380
4381pub const MAX_MODULE_NAME32 = 255;
4382pub const MODULEENTRY32 = extern struct {
4383 dwSize: DWORD,
4384 th32ModuleID: DWORD,
4385 th32ProcessID: DWORD,
4386 GlblcntUsage: DWORD,
4387 ProccntUsage: DWORD,
4388 modBaseAddr: *BYTE,
4389 modBaseSize: DWORD,
4390 hModule: HMODULE,
4391 szModule: [MAX_MODULE_NAME32 + 1]CHAR,
4392 szExePath: [MAX_PATH]CHAR,
4393};
lib/std/os/windows/kernel32.zig+7
......@@ -66,6 +66,7 @@ const UNWIND_HISTORY_TABLE = windows.UNWIND_HISTORY_TABLE;
6666const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION;
6767const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS;
6868const EXCEPTION_ROUTINE = windows.EXCEPTION_ROUTINE;
69const MODULEENTRY32 = windows.MODULEENTRY32;
6970
7071pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
7172pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
......@@ -132,6 +133,8 @@ pub extern "kernel32" fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingComp
132133
133134pub extern "kernel32" fn CreateThread(lpThreadAttributes: ?*SECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?*DWORD) callconv(WINAPI) ?HANDLE;
134135
136pub extern "kernel32" fn CreateToolhelp32Snapshot(dwFlags: DWORD, th32ProcessID: DWORD) callconv(WINAPI) HANDLE;
137
135138pub extern "kernel32" fn DeviceIoControl(
136139 h: HANDLE,
137140 dwIoControlCode: DWORD,
......@@ -265,6 +268,10 @@ pub extern "kernel32" fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASI
265268
266269pub extern "kernel32" fn LocalFree(hMem: HLOCAL) callconv(WINAPI) ?HLOCAL;
267270
271pub extern "kernel32" fn Module32First(hSnapshot: HANDLE, lpme: *MODULEENTRY32) callconv(WINAPI) BOOL;
272
273pub extern "kernel32" fn Module32Next(hSnapshot: HANDLE, lpme: *MODULEENTRY32) callconv(WINAPI) BOOL;
274
268275pub extern "kernel32" fn MoveFileExW(
269276 lpExistingFileName: [*:0]const u16,
270277 lpNewFileName: [*:0]const u16,