mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
windows: rework DebugInfo to use less file operations and fix some memory management issues
This commit is contained in:
parent
fcee1bf993
commit
461fb499f3
@ -1061,65 +1061,55 @@ pub const CoffError = error{
|
||||
|
||||
// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
pub const Coff = struct {
|
||||
allocator: mem.Allocator,
|
||||
data: []const u8 = undefined,
|
||||
is_image: bool = false,
|
||||
coff_header_offset: usize = 0,
|
||||
data: []const u8,
|
||||
is_image: bool,
|
||||
coff_header_offset: usize,
|
||||
|
||||
guid: [16]u8 = undefined,
|
||||
age: u32 = undefined,
|
||||
|
||||
pub fn deinit(self: *Coff) void {
|
||||
self.allocator.free(self.data);
|
||||
}
|
||||
|
||||
/// Takes ownership of `data`.
|
||||
pub fn parse(self: *Coff, data: []const u8) !void {
|
||||
self.data = data;
|
||||
|
||||
// The lifetime of `data` must be longer than the lifetime of the returned Coff
|
||||
pub fn init(data: []const u8) !Coff {
|
||||
const pe_pointer_offset = 0x3C;
|
||||
const pe_magic = "PE\x00\x00";
|
||||
|
||||
var stream = std.io.fixedBufferStream(self.data);
|
||||
var stream = std.io.fixedBufferStream(data);
|
||||
const reader = stream.reader();
|
||||
try stream.seekTo(pe_pointer_offset);
|
||||
const coff_header_offset = try reader.readIntLittle(u32);
|
||||
var coff_header_offset = try reader.readIntLittle(u32);
|
||||
try stream.seekTo(coff_header_offset);
|
||||
var buf: [4]u8 = undefined;
|
||||
try reader.readNoEof(&buf);
|
||||
self.is_image = mem.eql(u8, pe_magic, &buf);
|
||||
const is_image = mem.eql(u8, pe_magic, &buf);
|
||||
|
||||
var coff = @This(){
|
||||
.data = data,
|
||||
.is_image = is_image,
|
||||
.coff_header_offset = coff_header_offset,
|
||||
};
|
||||
|
||||
// Do some basic validation upfront
|
||||
if (self.is_image) {
|
||||
self.coff_header_offset = coff_header_offset + 4;
|
||||
const coff_header = self.getCoffHeader();
|
||||
if (is_image) {
|
||||
coff.coff_header_offset = coff.coff_header_offset + 4;
|
||||
const coff_header = coff.getCoffHeader();
|
||||
if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;
|
||||
}
|
||||
|
||||
// JK: we used to check for architecture here and throw an error if not x86 or derivative.
|
||||
// However I am willing to take a leap of faith and let aarch64 have a shot also.
|
||||
|
||||
return coff;
|
||||
}
|
||||
|
||||
pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
|
||||
assert(self.is_image);
|
||||
|
||||
const header = blk: {
|
||||
if (self.getSectionByName(".buildid")) |hdr| {
|
||||
break :blk hdr;
|
||||
} else if (self.getSectionByName(".rdata")) |hdr| {
|
||||
break :blk hdr;
|
||||
} else {
|
||||
return error.MissingCoffSection;
|
||||
}
|
||||
};
|
||||
|
||||
const data_dirs = self.getDataDirectories();
|
||||
const debug_dir = data_dirs[@enumToInt(DirectoryEntry.DEBUG)];
|
||||
const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
|
||||
|
||||
var stream = std.io.fixedBufferStream(self.data);
|
||||
const reader = stream.reader();
|
||||
try stream.seekTo(file_offset);
|
||||
try stream.seekTo(debug_dir.virtual_address);
|
||||
|
||||
// Find the correct DebugDirectoryEntry, and where its data is stored.
|
||||
// It can be in any section.
|
||||
@ -1128,16 +1118,8 @@ pub const Coff = struct {
|
||||
blk: while (i < debug_dir_entry_count) : (i += 1) {
|
||||
const debug_dir_entry = try reader.readStruct(DebugDirectoryEntry);
|
||||
if (debug_dir_entry.type == .CODEVIEW) {
|
||||
for (self.getSectionHeaders()) |*section| {
|
||||
const section_start = section.virtual_address;
|
||||
const section_size = section.virtual_size;
|
||||
const rva = debug_dir_entry.address_of_raw_data;
|
||||
const offset = rva - section_start;
|
||||
if (section_start <= rva and offset < section_size and debug_dir_entry.size_of_data <= section_size - offset) {
|
||||
try stream.seekTo(section.pointer_to_raw_data + offset);
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
try stream.seekTo(debug_dir_entry.address_of_raw_data);
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1238,6 +1220,16 @@ pub const Coff = struct {
|
||||
return @ptrCast([*]align(1) const SectionHeader, self.data.ptr + offset)[0..coff_header.number_of_sections];
|
||||
}
|
||||
|
||||
pub fn getSectionHeadersAlloc(self: *const Coff, allocator: mem.Allocator) ![]SectionHeader {
|
||||
const section_headers = self.getSectionHeaders();
|
||||
const out_buff = try allocator.alloc(SectionHeader, section_headers.len);
|
||||
for (out_buff) |*section_header, i| {
|
||||
section_header.* = section_headers[i];
|
||||
}
|
||||
|
||||
return out_buff;
|
||||
}
|
||||
|
||||
pub fn getSectionName(self: *const Coff, sect_hdr: *align(1) const SectionHeader) []const u8 {
|
||||
const name = sect_hdr.getName() orelse blk: {
|
||||
const strtab = self.getStrtab().?;
|
||||
@ -1256,12 +1248,15 @@ pub const Coff = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn getSectionData(self: *const Coff, comptime name: []const u8) ![]const u8 {
|
||||
const sec = self.getSectionByName(name) orelse return error.MissingCoffSection;
|
||||
return self.data[sec.pointer_to_raw_data..][0..sec.virtual_size];
|
||||
}
|
||||
|
||||
// Return an owned slice full of the section data
|
||||
pub fn getSectionDataAlloc(self: *const Coff, comptime name: []const u8, allocator: mem.Allocator) ![]u8 {
|
||||
const sec = self.getSectionByName(name) orelse return error.MissingCoffSection;
|
||||
const out_buff = try allocator.alloc(u8, sec.virtual_size);
|
||||
mem.copy(u8, out_buff, self.data[sec.pointer_to_raw_data..][0..sec.virtual_size]);
|
||||
return out_buff;
|
||||
const section_data = try self.getSectionData(name);
|
||||
return allocator.dupe(u8, section_data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -811,7 +811,7 @@ fn printLineInfo(
|
||||
pub const OpenSelfDebugInfoError = error{
|
||||
MissingDebugInfo,
|
||||
UnsupportedOperatingSystem,
|
||||
};
|
||||
} || @typeInfo(@typeInfo(@TypeOf(DebugInfo.init)).Fn.return_type.?).ErrorUnion.error_set;
|
||||
|
||||
pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugInfo {
|
||||
nosuspend {
|
||||
@ -827,60 +827,56 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugI
|
||||
.dragonfly,
|
||||
.openbsd,
|
||||
.macos,
|
||||
.windows,
|
||||
.solaris,
|
||||
=> return DebugInfo.init(allocator),
|
||||
.windows,
|
||||
=> return try DebugInfo.init(allocator),
|
||||
else => return error.UnsupportedOperatingSystem,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This takes ownership of coff_file: users of this function should not close
|
||||
/// it themselves, even on error.
|
||||
/// TODO it's weird to take ownership even on error, rework this code.
|
||||
fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {
|
||||
fn readCoffDebugInfo(allocator: mem.Allocator, coff_bytes: []const u8) !ModuleDebugInfo {
|
||||
nosuspend {
|
||||
defer coff_file.close();
|
||||
|
||||
const coff_obj = try allocator.create(coff.Coff);
|
||||
errdefer allocator.destroy(coff_obj);
|
||||
coff_obj.* = .{ .allocator = allocator };
|
||||
coff_obj.* = try coff.Coff.init(coff_bytes);
|
||||
|
||||
var di = ModuleDebugInfo{
|
||||
.base_address = undefined,
|
||||
.coff = coff_obj,
|
||||
.coff_image_base = coff_obj.getImageBase(),
|
||||
.coff_section_headers = undefined,
|
||||
.debug_data = undefined,
|
||||
};
|
||||
|
||||
// TODO convert to Windows' memory-mapped file API
|
||||
const file_len = math.cast(usize, try coff_file.getEndPos()) orelse math.maxInt(usize);
|
||||
const data = try coff_file.readToEndAlloc(allocator, file_len);
|
||||
try di.coff.parse(data);
|
||||
|
||||
if (di.coff.getSectionByName(".debug_info")) |sec| {
|
||||
if (coff_obj.getSectionByName(".debug_info")) |sec| {
|
||||
// This coff file has embedded DWARF debug info
|
||||
_ = sec;
|
||||
// TODO: free the section data slices
|
||||
const debug_info = di.coff.getSectionDataAlloc(".debug_info", allocator) catch null;
|
||||
const debug_abbrev = di.coff.getSectionDataAlloc(".debug_abbrev", allocator) catch null;
|
||||
const debug_str = di.coff.getSectionDataAlloc(".debug_str", allocator) catch null;
|
||||
const debug_str_offsets = di.coff.getSectionDataAlloc(".debug_str_offsets", allocator) catch null;
|
||||
const debug_line = di.coff.getSectionDataAlloc(".debug_line", allocator) catch null;
|
||||
const debug_line_str = di.coff.getSectionDataAlloc(".debug_line_str", allocator) catch null;
|
||||
const debug_ranges = di.coff.getSectionDataAlloc(".debug_ranges", allocator) catch null;
|
||||
const debug_loclists = di.coff.getSectionDataAlloc(".debug_loclists", allocator) catch null;
|
||||
const debug_rnglists = di.coff.getSectionDataAlloc(".debug_rnglists", allocator) catch null;
|
||||
const debug_addr = di.coff.getSectionDataAlloc(".debug_addr", allocator) catch null;
|
||||
const debug_names = di.coff.getSectionDataAlloc(".debug_names", allocator) catch null;
|
||||
const debug_frame = di.coff.getSectionDataAlloc(".debug_frame", allocator) catch null;
|
||||
|
||||
const debug_info = coff_obj.getSectionDataAlloc(".debug_info", allocator) catch return error.MissingDebugInfo;
|
||||
errdefer allocator.free(debug_info);
|
||||
const debug_abbrev = coff_obj.getSectionDataAlloc(".debug_abbrev", allocator) catch return error.MissingDebugInfo;
|
||||
errdefer allocator.free(debug_abbrev);
|
||||
const debug_str = coff_obj.getSectionDataAlloc(".debug_str", allocator) catch return error.MissingDebugInfo;
|
||||
errdefer allocator.free(debug_str);
|
||||
const debug_line = coff_obj.getSectionDataAlloc(".debug_line", allocator) catch return error.MissingDebugInfo;
|
||||
errdefer allocator.free(debug_line);
|
||||
|
||||
const debug_str_offsets = coff_obj.getSectionDataAlloc(".debug_str_offsets", allocator) catch null;
|
||||
const debug_line_str = coff_obj.getSectionDataAlloc(".debug_line_str", allocator) catch null;
|
||||
const debug_ranges = coff_obj.getSectionDataAlloc(".debug_ranges", allocator) catch null;
|
||||
const debug_loclists = coff_obj.getSectionDataAlloc(".debug_loclists", allocator) catch null;
|
||||
const debug_rnglists = coff_obj.getSectionDataAlloc(".debug_rnglists", allocator) catch null;
|
||||
const debug_addr = coff_obj.getSectionDataAlloc(".debug_addr", allocator) catch null;
|
||||
const debug_names = coff_obj.getSectionDataAlloc(".debug_names", allocator) catch null;
|
||||
const debug_frame = coff_obj.getSectionDataAlloc(".debug_frame", allocator) catch null;
|
||||
|
||||
var dwarf = DW.DwarfInfo{
|
||||
.endian = native_endian,
|
||||
.debug_info = debug_info orelse return error.MissingDebugInfo,
|
||||
.debug_abbrev = debug_abbrev orelse return error.MissingDebugInfo,
|
||||
.debug_str = debug_str orelse return error.MissingDebugInfo,
|
||||
.debug_info = debug_info,
|
||||
.debug_abbrev = debug_abbrev,
|
||||
.debug_str = debug_str,
|
||||
.debug_str_offsets = debug_str_offsets,
|
||||
.debug_line = debug_line orelse return error.MissingDebugInfo,
|
||||
.debug_line = debug_line,
|
||||
.debug_line_str = debug_line_str,
|
||||
.debug_ranges = debug_ranges,
|
||||
.debug_loclists = debug_loclists,
|
||||
@ -889,13 +885,28 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
|
||||
.debug_names = debug_names,
|
||||
.debug_frame = debug_frame,
|
||||
};
|
||||
try DW.openDwarfDebugInfo(&dwarf, allocator);
|
||||
|
||||
DW.openDwarfDebugInfo(&dwarf, allocator) catch |err| {
|
||||
if (debug_str_offsets) |d| allocator.free(d);
|
||||
if (debug_line_str) |d| allocator.free(d);
|
||||
if (debug_ranges) |d| allocator.free(d);
|
||||
if (debug_loclists) |d| allocator.free(d);
|
||||
if (debug_rnglists) |d| allocator.free(d);
|
||||
if (debug_addr) |d| allocator.free(d);
|
||||
if (debug_names) |d| allocator.free(d);
|
||||
if (debug_frame) |d| allocator.free(d);
|
||||
return err;
|
||||
};
|
||||
|
||||
di.debug_data = PdbOrDwarf{ .dwarf = dwarf };
|
||||
return di;
|
||||
}
|
||||
|
||||
// Only used by pdb path
|
||||
di.coff_section_headers = try coff_obj.getSectionHeadersAlloc(allocator);
|
||||
|
||||
var path_buf: [windows.MAX_PATH]u8 = undefined;
|
||||
const len = try di.coff.getPdbPath(path_buf[0..]);
|
||||
const len = try coff_obj.getPdbPath(path_buf[0..]);
|
||||
const raw_path = path_buf[0..len];
|
||||
|
||||
const path = try fs.path.resolve(allocator, &[_][]const u8{raw_path});
|
||||
@ -909,7 +920,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
|
||||
try di.debug_data.pdb.parseInfoStream();
|
||||
try di.debug_data.pdb.parseDbiStream();
|
||||
|
||||
if (!mem.eql(u8, &di.coff.guid, &di.debug_data.pdb.guid) or di.coff.age != di.debug_data.pdb.age)
|
||||
if (!mem.eql(u8, &coff_obj.guid, &di.debug_data.pdb.guid) or coff_obj.age != di.debug_data.pdb.age)
|
||||
return error.InvalidDebugInfo;
|
||||
|
||||
return di;
|
||||
@ -1225,15 +1236,49 @@ fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 {
|
||||
}
|
||||
}
|
||||
|
||||
pub const ModuleInfo = struct {
|
||||
base_address: usize,
|
||||
size: u32,
|
||||
};
|
||||
|
||||
pub const DebugInfo = struct {
|
||||
allocator: mem.Allocator,
|
||||
address_map: std.AutoHashMap(usize, *ModuleDebugInfo),
|
||||
modules: if (native_os == .windows) std.ArrayListUnmanaged(ModuleInfo) else void,
|
||||
|
||||
pub fn init(allocator: mem.Allocator) DebugInfo {
|
||||
return DebugInfo{
|
||||
pub fn init(allocator: mem.Allocator) !DebugInfo {
|
||||
var debug_info = DebugInfo{
|
||||
.allocator = allocator,
|
||||
.address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator),
|
||||
.modules = if (native_os == .windows) .{} else {},
|
||||
};
|
||||
|
||||
if (native_os == .windows) {
|
||||
const handle = windows.kernel32.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE | windows.TH32CS_SNAPMODULE32, 0);
|
||||
if (handle == windows.INVALID_HANDLE_VALUE) {
|
||||
switch (windows.kernel32.GetLastError()) {
|
||||
else => |err| return windows.unexpectedError(err),
|
||||
}
|
||||
}
|
||||
|
||||
defer windows.CloseHandle(handle);
|
||||
|
||||
var module_entry: windows.MODULEENTRY32 = undefined;
|
||||
module_entry.dwSize = @sizeOf(windows.MODULEENTRY32);
|
||||
if (windows.kernel32.Module32First(handle, &module_entry) == 0) {
|
||||
return error.MissingDebugInfo;
|
||||
}
|
||||
|
||||
var module_valid = true;
|
||||
while (module_valid) {
|
||||
const module_info = try debug_info.modules.addOne(allocator);
|
||||
module_info.base_address = @ptrToInt(module_entry.modBaseAddr);
|
||||
module_info.size = module_entry.modBaseSize;
|
||||
module_valid = windows.kernel32.Module32Next(handle, &module_entry) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
return debug_info;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *DebugInfo) void {
|
||||
@ -1322,79 +1367,20 @@ pub const DebugInfo = struct {
|
||||
}
|
||||
|
||||
fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
|
||||
const process_handle = windows.kernel32.GetCurrentProcess();
|
||||
|
||||
// Find how many modules are actually loaded
|
||||
var dummy: windows.HMODULE = undefined;
|
||||
var bytes_needed: windows.DWORD = undefined;
|
||||
if (windows.kernel32.K32EnumProcessModules(
|
||||
process_handle,
|
||||
@ptrCast([*]windows.HMODULE, &dummy),
|
||||
0,
|
||||
&bytes_needed,
|
||||
) == 0)
|
||||
return error.MissingDebugInfo;
|
||||
|
||||
const needed_modules = bytes_needed / @sizeOf(windows.HMODULE);
|
||||
|
||||
// Fetch the complete module list
|
||||
var modules = try self.allocator.alloc(windows.HMODULE, needed_modules);
|
||||
defer self.allocator.free(modules);
|
||||
if (windows.kernel32.K32EnumProcessModules(
|
||||
process_handle,
|
||||
modules.ptr,
|
||||
math.cast(windows.DWORD, modules.len * @sizeOf(windows.HMODULE)) orelse return error.Overflow,
|
||||
&bytes_needed,
|
||||
) == 0)
|
||||
return error.MissingDebugInfo;
|
||||
|
||||
// There's an unavoidable TOCTOU problem here, the module list may have
|
||||
// changed between the two EnumProcessModules call.
|
||||
// Pick the smallest amount of elements to avoid processing garbage.
|
||||
const needed_modules_after = bytes_needed / @sizeOf(windows.HMODULE);
|
||||
const loaded_modules = math.min(needed_modules, needed_modules_after);
|
||||
|
||||
for (modules[0..loaded_modules]) |module| {
|
||||
var info: windows.MODULEINFO = undefined;
|
||||
if (windows.kernel32.K32GetModuleInformation(
|
||||
process_handle,
|
||||
module,
|
||||
&info,
|
||||
@sizeOf(@TypeOf(info)),
|
||||
) == 0)
|
||||
return error.MissingDebugInfo;
|
||||
|
||||
const seg_start = @ptrToInt(info.lpBaseOfDll);
|
||||
const seg_end = seg_start + info.SizeOfImage;
|
||||
|
||||
if (address >= seg_start and address < seg_end) {
|
||||
if (self.address_map.get(seg_start)) |obj_di| {
|
||||
for (self.modules.items) |module| {
|
||||
if (address >= module.base_address and address < module.base_address + module.size) {
|
||||
if (self.address_map.get(module.base_address)) |obj_di| {
|
||||
return obj_di;
|
||||
}
|
||||
|
||||
var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined;
|
||||
// openFileAbsoluteW requires the prefix to be present
|
||||
mem.copy(u16, name_buffer[0..4], &[_]u16{ '\\', '?', '?', '\\' });
|
||||
const len = windows.kernel32.K32GetModuleFileNameExW(
|
||||
process_handle,
|
||||
module,
|
||||
@ptrCast(windows.LPWSTR, &name_buffer[4]),
|
||||
windows.PATH_MAX_WIDE,
|
||||
);
|
||||
assert(len > 0);
|
||||
|
||||
const mapped_module = @intToPtr([*]const u8, module.base_address)[0..module.size];
|
||||
const obj_di = try self.allocator.create(ModuleDebugInfo);
|
||||
errdefer self.allocator.destroy(obj_di);
|
||||
|
||||
const coff_file = fs.openFileAbsoluteW(name_buffer[0 .. len + 4 :0], .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return error.MissingDebugInfo,
|
||||
else => return err,
|
||||
};
|
||||
obj_di.* = try readCoffDebugInfo(self.allocator, coff_file);
|
||||
obj_di.base_address = seg_start;
|
||||
|
||||
try self.address_map.putNoClobber(seg_start, obj_di);
|
||||
obj_di.* = try readCoffDebugInfo(self.allocator, mapped_module);
|
||||
obj_di.base_address = module.base_address;
|
||||
|
||||
try self.address_map.putNoClobber(module.base_address, obj_di);
|
||||
return obj_di;
|
||||
}
|
||||
}
|
||||
@ -1727,12 +1713,31 @@ pub const ModuleDebugInfo = switch (native_os) {
|
||||
.uefi, .windows => struct {
|
||||
base_address: usize,
|
||||
debug_data: PdbOrDwarf,
|
||||
coff: *coff.Coff,
|
||||
coff_image_base: u64,
|
||||
coff_section_headers: []coff.SectionHeader,
|
||||
|
||||
fn deinit(self: *@This(), allocator: mem.Allocator) void {
|
||||
switch (self.debug_data) {
|
||||
.dwarf => |*dwarf| {
|
||||
allocator.free(dwarf.debug_info);
|
||||
allocator.free(dwarf.debug_abbrev);
|
||||
allocator.free(dwarf.debug_str);
|
||||
allocator.free(dwarf.debug_line);
|
||||
if (dwarf.debug_str_offsets) |d| allocator.free(d);
|
||||
if (dwarf.debug_line_str) |d| allocator.free(d);
|
||||
if (dwarf.debug_ranges) |d| allocator.free(d);
|
||||
if (dwarf.debug_loclists) |d| allocator.free(d);
|
||||
if (dwarf.debug_rnglists) |d| allocator.free(d);
|
||||
if (dwarf.debug_addr) |d| allocator.free(d);
|
||||
if (dwarf.debug_names) |d| allocator.free(d);
|
||||
if (dwarf.debug_frame) |d| allocator.free(d);
|
||||
},
|
||||
.pdb => {
|
||||
allocator.free(self.coff_section_headers);
|
||||
},
|
||||
}
|
||||
|
||||
self.debug_data.deinit(allocator);
|
||||
self.coff.deinit();
|
||||
allocator.destroy(self.coff);
|
||||
}
|
||||
|
||||
pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
|
||||
@ -1741,7 +1746,7 @@ pub const ModuleDebugInfo = switch (native_os) {
|
||||
|
||||
switch (self.debug_data) {
|
||||
.dwarf => |*dwarf| {
|
||||
const dwarf_address = relocated_address + self.coff.getImageBase();
|
||||
const dwarf_address = relocated_address + self.coff_image_base;
|
||||
return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
|
||||
},
|
||||
.pdb => {
|
||||
@ -1751,10 +1756,9 @@ pub const ModuleDebugInfo = switch (native_os) {
|
||||
|
||||
var coff_section: *align(1) const coff.SectionHeader = undefined;
|
||||
const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| {
|
||||
const sections = self.coff.getSectionHeaders();
|
||||
if (sect_contrib.Section > sections.len) continue;
|
||||
if (sect_contrib.Section > self.coff_section_headers.len) continue;
|
||||
// Remember that SectionContribEntry.Section is 1-based.
|
||||
coff_section = §ions[sect_contrib.Section - 1];
|
||||
coff_section = &self.coff_section_headers[sect_contrib.Section - 1];
|
||||
|
||||
const vaddr_start = coff_section.virtual_address + sect_contrib.Offset;
|
||||
const vaddr_end = vaddr_start + sect_contrib.Size;
|
||||
|
||||
@ -3801,6 +3801,26 @@ pub const PEB_LDR_DATA = extern struct {
|
||||
ShutdownThreadId: HANDLE,
|
||||
};
|
||||
|
||||
/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
|
||||
/// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data
|
||||
/// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm
|
||||
pub const LDR_DATA_TABLE_ENTRY = extern struct {
|
||||
Reserved1: [2]PVOID,
|
||||
InMemoryOrderLinks: LIST_ENTRY,
|
||||
Reserved2: [2]PVOID,
|
||||
DllBase: PVOID,
|
||||
EntryPoint: PVOID,
|
||||
SizeOfImage: ULONG,
|
||||
FullDllName: UNICODE_STRING,
|
||||
Reserved4: [8]BYTE,
|
||||
Reserved5: [3]PVOID,
|
||||
DUMMYUNIONNAME: extern union {
|
||||
CheckSum: ULONG,
|
||||
Reserved6: PVOID,
|
||||
},
|
||||
TimeDateStamp: ULONG,
|
||||
};
|
||||
|
||||
pub const RTL_USER_PROCESS_PARAMETERS = extern struct {
|
||||
AllocationSize: ULONG,
|
||||
Size: ULONG,
|
||||
@ -4349,3 +4369,25 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool {
|
||||
if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false;
|
||||
return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1;
|
||||
}
|
||||
|
||||
pub const TH32CS_SNAPHEAPLIST = 0x00000001;
|
||||
pub const TH32CS_SNAPPROCESS = 0x00000002;
|
||||
pub const TH32CS_SNAPTHREAD = 0x00000004;
|
||||
pub const TH32CS_SNAPMODULE = 0x00000008;
|
||||
pub const TH32CS_SNAPMODULE32 = 0x00000010;
|
||||
pub const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE;
|
||||
pub const TH32CS_INHERIT = 0x80000000;
|
||||
|
||||
pub const MAX_MODULE_NAME32 = 255;
|
||||
pub const MODULEENTRY32 = extern struct {
|
||||
dwSize: DWORD,
|
||||
th32ModuleID: DWORD,
|
||||
th32ProcessID: DWORD,
|
||||
GlblcntUsage: DWORD,
|
||||
ProccntUsage: DWORD,
|
||||
modBaseAddr: *BYTE,
|
||||
modBaseSize: DWORD,
|
||||
hModule: HMODULE,
|
||||
szModule: [MAX_MODULE_NAME32 + 1]CHAR,
|
||||
szExePath: [MAX_PATH]CHAR,
|
||||
};
|
||||
|
||||
@ -66,6 +66,7 @@ const UNWIND_HISTORY_TABLE = windows.UNWIND_HISTORY_TABLE;
|
||||
const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION;
|
||||
const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS;
|
||||
const EXCEPTION_ROUTINE = windows.EXCEPTION_ROUTINE;
|
||||
const MODULEENTRY32 = windows.MODULEENTRY32;
|
||||
|
||||
pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
|
||||
pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
|
||||
@ -132,6 +133,8 @@ pub extern "kernel32" fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingComp
|
||||
|
||||
pub extern "kernel32" fn CreateThread(lpThreadAttributes: ?*SECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?*DWORD) callconv(WINAPI) ?HANDLE;
|
||||
|
||||
pub extern "kernel32" fn CreateToolhelp32Snapshot(dwFlags: DWORD, th32ProcessID: DWORD) callconv(WINAPI) HANDLE;
|
||||
|
||||
pub extern "kernel32" fn DeviceIoControl(
|
||||
h: HANDLE,
|
||||
dwIoControlCode: DWORD,
|
||||
@ -265,6 +268,10 @@ pub extern "kernel32" fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASI
|
||||
|
||||
pub extern "kernel32" fn LocalFree(hMem: HLOCAL) callconv(WINAPI) ?HLOCAL;
|
||||
|
||||
pub extern "kernel32" fn Module32First(hSnapshot: HANDLE, lpme: *MODULEENTRY32) callconv(WINAPI) BOOL;
|
||||
|
||||
pub extern "kernel32" fn Module32Next(hSnapshot: HANDLE, lpme: *MODULEENTRY32) callconv(WINAPI) BOOL;
|
||||
|
||||
pub extern "kernel32" fn MoveFileExW(
|
||||
lpExistingFileName: [*:0]const u16,
|
||||
lpNewFileName: [*:0]const u16,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user