authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-21 18:48:59+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-21 18:48:59+03:00
log8a6de78e0787015153707361a58659834d4c39c2
tree18fb97ac91195813754f80506807db4a22923baa
parente13a182990c638bb69cd04e253ad6e0ecd734407
parent24b1a0027fc663cbb648c265ba19067b108d0dcb
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8717 from mchudleigh/dwarf-on-windows

Dwarf on windows

4 files changed, 156 insertions(+), 51 deletions(-)

lib/std/Progress.zig+15-5
......@@ -22,6 +22,10 @@ const Progress = @This();
2222/// not print on update()
2323terminal: ?std.fs.File = undefined,
2424
25/// Is this a windows API terminal (note: this is not the same as being run on windows
26/// because other terminals exist like MSYS/git-bash)
27is_windows_terminal: bool = false,
28
2529/// Whether the terminal supports ANSI escape codes.
2630supports_ansi_escape_codes: bool = false,
2731
......@@ -143,6 +147,7 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) !*
143147 self.terminal = stderr;
144148 self.supports_ansi_escape_codes = true;
145149 } else if (std.builtin.os.tag == .windows and stderr.isTty()) {
150 self.is_windows_terminal = true;
146151 self.terminal = stderr;
147152 } else if (std.builtin.os.tag != .windows) {
148153 // we are in a "dumb" terminal like in acme or writing to a file
......@@ -192,8 +197,9 @@ const DECRC = "\x1b8";
192197// supported by some terminals (eg. Terminal.app).
193198
194199fn refreshWithHeldLock(self: *Progress) void {
195 const is_dumb = !self.supports_ansi_escape_codes and !(std.builtin.os.tag == .windows);
200 const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal;
196201 if (is_dumb and self.dont_print_on_dumb) return;
202
197203 const file = self.terminal orelse return;
198204
199205 var end: usize = 0;
......@@ -206,6 +212,8 @@ fn refreshWithHeldLock(self: *Progress) void {
206212 std.mem.copy(u8, self.output_buffer[end..], seq_before);
207213 end += seq_before.len;
208214 } else if (std.builtin.os.tag == .windows) winapi: {
215 std.debug.assert(self.is_windows_terminal);
216
209217 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
210218 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE)
211219 unreachable;
......@@ -282,7 +290,7 @@ fn refreshWithHeldLock(self: *Progress) void {
282290 const seq_after = DECRC;
283291 std.mem.copy(u8, self.output_buffer[end..], seq_after);
284292 end += seq_after.len;
285 } else if (std.builtin.os.tag != .windows) {
293 } else if (!self.is_windows_terminal) {
286294 self.output_buffer[end] = '\n';
287295 end += 1;
288296 }
......@@ -293,8 +301,10 @@ fn refreshWithHeldLock(self: *Progress) void {
293301 };
294302
295303 if (std.builtin.os.tag == .windows) {
296 if (windows.kernel32.SetConsoleCursorPosition(file.handle, saved_cursor_pos) != windows.TRUE)
297 unreachable;
304 if (self.is_windows_terminal) {
305 const res = windows.kernel32.SetConsoleCursorPosition(file.handle, saved_cursor_pos);
306 std.debug.assert(res == windows.TRUE);
307 }
298308 }
299309
300310 self.prev_refresh_timestamp = self.timer.read();
......@@ -318,7 +328,7 @@ fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: any
318328 end.* = self.output_buffer.len;
319329 },
320330 }
321 const bytes_needed_for_esc_codes_at_end = if (std.builtin.os.tag == .windows) 0 else 11;
331 const bytes_needed_for_esc_codes_at_end: u8 = if (self.is_windows_terminal) 0 else 11;
322332 const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end;
323333 if (end.* > max_end) {
324334 const suffix = "... ";
lib/std/coff.zig+67-10
......@@ -98,6 +98,7 @@ pub const CoffError = error{
9898 InvalidPEHeader,
9999 InvalidMachine,
100100 MissingCoffSection,
101 MissingStringTable,
101102};
102103
103104// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
......@@ -162,20 +163,47 @@ pub const Coff = struct {
162163 try self.loadOptionalHeader();
163164 }
164165
166 fn readStringFromTable(self: *Coff, offset: usize, buf: []u8) ![]const u8 {
167 if (self.coff_header.pointer_to_symbol_table == 0) {
168 // No symbol table therefore no string table
169 return error.MissingStringTable;
170 }
171 // The string table is at the end of the symbol table and symbols are 18 bytes long
172 const string_table_offset = self.coff_header.pointer_to_symbol_table + (self.coff_header.number_of_symbols * 18) + offset;
173 const in = self.in_file.reader();
174 const old_pos = try self.in_file.getPos();
175
176 try self.in_file.seekTo(string_table_offset);
177 defer {
178 self.in_file.seekTo(old_pos) catch unreachable;
179 }
180
181 const str = try in.readUntilDelimiterOrEof(buf, 0);
182 return str orelse "";
183 }
184
165185 fn loadOptionalHeader(self: *Coff) !void {
166186 const in = self.in_file.reader();
187 const opt_header_pos = try self.in_file.getPos();
188
167189 self.pe_header.magic = try in.readIntLittle(u16);
168 // For now we're only interested in finding the reference to the .pdb,
169 // so we'll skip most of this header, which size is different in 32
170 // 64 bits by the way.
171 var skip_size: u16 = undefined;
190 // All we care about is the image base value and PDB info
191 // The header structure is different for 32 or 64 bit
192 var num_rva_pos: u64 = undefined;
172193 if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
173 skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 18 * @sizeOf(u32);
194 num_rva_pos = opt_header_pos + 92;
195
196 try self.in_file.seekTo(opt_header_pos + 28);
197 const image_base32 = try in.readIntLittle(u32);
198 self.pe_header.image_base = image_base32;
174199 } else if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
175 skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 12 * @sizeOf(u32) + 5 * @sizeOf(u64);
200 num_rva_pos = opt_header_pos + 108;
201
202 try self.in_file.seekTo(opt_header_pos + 24);
203 self.pe_header.image_base = try in.readIntLittle(u64);
176204 } else return error.InvalidPEMagic;
177205
178 try self.in_file.seekBy(skip_size);
206 try self.in_file.seekTo(num_rva_pos);
179207
180208 const number_of_rva_and_sizes = try in.readIntLittle(u32);
181209 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
......@@ -258,11 +286,23 @@ pub const Coff = struct {
258286
259287 const in = self.in_file.reader();
260288
261 var name: [8]u8 = undefined;
289 var name: [32]u8 = undefined;
262290
263291 var i: u16 = 0;
264292 while (i < self.coff_header.number_of_sections) : (i += 1) {
265 try in.readNoEof(name[0..]);
293 try in.readNoEof(name[0..8]);
294
295 if (name[0] == '/') {
296 // This is a long name and stored in the string table
297 const offset_len = mem.indexOfScalar(u8, name[1..], 0) orelse 7;
298
299 const str_offset = try std.fmt.parseInt(u32, name[1 .. offset_len + 1], 10);
300 const str = try self.readStringFromTable(str_offset, &name);
301 std.mem.set(u8, name[str.len..], 0);
302 } else {
303 std.mem.set(u8, name[8..], 0);
304 }
305
266306 try self.sections.append(Section{
267307 .header = SectionHeader{
268308 .name = name,
......@@ -288,6 +328,22 @@ pub const Coff = struct {
288328 }
289329 return null;
290330 }
331
332 // Return an owned slice full of the section data
333 pub fn getSectionData(self: *Coff, comptime name: []const u8, allocator: *mem.Allocator) ![]u8 {
334 const sec = for (self.sections.items) |*sec| {
335 if (mem.eql(u8, sec.header.name[0..name.len], name)) {
336 break sec;
337 }
338 } else {
339 return error.MissingCoffSection;
340 };
341 const in = self.in_file.reader();
342 try self.in_file.seekTo(sec.header.pointer_to_raw_data);
343 const out_buff = try allocator.alloc(u8, sec.header.misc.virtual_size);
344 try in.readNoEof(out_buff);
345 return out_buff;
346 }
291347};
292348
293349const CoffHeader = struct {
......@@ -308,6 +364,7 @@ const OptionalHeader = struct {
308364
309365 magic: u16,
310366 data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
367 image_base: u64,
311368};
312369
313370const DebugDirectoryEntry = packed struct {
......@@ -331,7 +388,7 @@ const SectionHeader = struct {
331388 virtual_size: u32,
332389 };
333390
334 name: [8]u8,
391 name: [32]u8,
335392 misc: Misc,
336393 virtual_address: u32,
337394 size_of_raw_data: u32,
lib/std/debug.zig+69-31
......@@ -53,6 +53,10 @@ pub const SymbolInfo = struct {
5353 }
5454 }
5555};
56const PdbOrDwarf = union(enum) {
57 pdb: pdb.Pdb,
58 dwarf: DW.DwarfInfo,
59};
5660
5761var stderr_mutex = std.Thread.Mutex{};
5862
......@@ -669,10 +673,32 @@ fn readCoffDebugInfo(allocator: *mem.Allocator, coff_file: File) !ModuleDebugInf
669673 var di = ModuleDebugInfo{
670674 .base_address = undefined,
671675 .coff = coff_obj,
672 .pdb = undefined,
676 .debug_data = undefined,
673677 };
674678
675679 try di.coff.loadHeader();
680 try di.coff.loadSections();
681 if (di.coff.getSection(".debug_info")) |sec| {
682 // This coff file has embedded DWARF debug info
683 // TODO: free the section data slices
684 const debug_info_data = di.coff.getSectionData(".debug_info", allocator) catch null;
685 const debug_abbrev_data = di.coff.getSectionData(".debug_abbrev", allocator) catch null;
686 const debug_str_data = di.coff.getSectionData(".debug_str", allocator) catch null;
687 const debug_line_data = di.coff.getSectionData(".debug_line", allocator) catch null;
688 const debug_ranges_data = di.coff.getSectionData(".debug_ranges", allocator) catch null;
689
690 var dwarf = DW.DwarfInfo{
691 .endian = native_endian,
692 .debug_info = debug_info_data orelse return error.MissingDebugInfo,
693 .debug_abbrev = debug_abbrev_data orelse return error.MissingDebugInfo,
694 .debug_str = debug_str_data orelse return error.MissingDebugInfo,
695 .debug_line = debug_line_data orelse return error.MissingDebugInfo,
696 .debug_ranges = debug_ranges_data,
697 };
698 try DW.openDwarfDebugInfo(&dwarf, allocator);
699 di.debug_data = PdbOrDwarf{ .dwarf = dwarf };
700 return di;
701 }
676702
677703 var path_buf: [windows.MAX_PATH]u8 = undefined;
678704 const len = try di.coff.getPdbPath(path_buf[0..]);
......@@ -681,11 +707,12 @@ fn readCoffDebugInfo(allocator: *mem.Allocator, coff_file: File) !ModuleDebugInf
681707 const path = try fs.path.resolve(allocator, &[_][]const u8{raw_path});
682708 defer allocator.free(path);
683709
684 di.pdb = try pdb.Pdb.init(allocator, path);
685 try di.pdb.parseInfoStream();
686 try di.pdb.parseDbiStream();
710 di.debug_data = PdbOrDwarf{ .pdb = undefined };
711 di.debug_data.pdb = try pdb.Pdb.init(allocator, path);
712 try di.debug_data.pdb.parseInfoStream();
713 try di.debug_data.pdb.parseDbiStream();
687714
688 if (!mem.eql(u8, &di.coff.guid, &di.pdb.guid) or di.coff.age != di.pdb.age)
715 if (!mem.eql(u8, &di.coff.guid, &di.debug_data.pdb.guid) or di.coff.age != di.debug_data.pdb.age)
689716 return error.InvalidDebugInfo;
690717
691718 return di;
......@@ -1331,7 +1358,7 @@ pub const ModuleDebugInfo = switch (native_os) {
13311358 },
13321359 .uefi, .windows => struct {
13331360 base_address: usize,
1334 pdb: pdb.Pdb,
1361 debug_data: PdbOrDwarf,
13351362 coff: *coff.Coff,
13361363
13371364 pub fn allocator(self: @This()) *mem.Allocator {
......@@ -1342,8 +1369,18 @@ pub const ModuleDebugInfo = switch (native_os) {
13421369 // Translate the VA into an address into this object
13431370 const relocated_address = address - self.base_address;
13441371
1372 switch (self.debug_data) {
1373 .dwarf => |*dwarf| {
1374 const dwarf_address = relocated_address + self.coff.pe_header.image_base;
1375 return getSymbolFromDwarf(dwarf_address, dwarf);
1376 },
1377 .pdb => {
1378 // fallthrough to pdb handling
1379 },
1380 }
1381
13451382 var coff_section: *coff.Section = undefined;
1346 const mod_index = for (self.pdb.sect_contribs) |sect_contrib| {
1383 const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| {
13471384 if (sect_contrib.Section > self.coff.sections.items.len) continue;
13481385 // Remember that SectionContribEntry.Section is 1-based.
13491386 coff_section = &self.coff.sections.items[sect_contrib.Section - 1];
......@@ -1358,15 +1395,15 @@ pub const ModuleDebugInfo = switch (native_os) {
13581395 return SymbolInfo{};
13591396 };
13601397
1361 const module = (try self.pdb.getModule(mod_index)) orelse
1398 const module = (try self.debug_data.pdb.getModule(mod_index)) orelse
13621399 return error.InvalidDebugInfo;
13631400 const obj_basename = fs.path.basename(module.obj_file_name);
13641401
1365 const symbol_name = self.pdb.getSymbolName(
1402 const symbol_name = self.debug_data.pdb.getSymbolName(
13661403 module,
13671404 relocated_address - coff_section.header.virtual_address,
13681405 ) orelse "???";
1369 const opt_line_info = try self.pdb.getLineNumberInfo(
1406 const opt_line_info = try self.debug_data.pdb.getLineNumberInfo(
13701407 module,
13711408 relocated_address - coff_section.header.virtual_address,
13721409 );
......@@ -1386,32 +1423,33 @@ pub const ModuleDebugInfo = switch (native_os) {
13861423 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
13871424 // Translate the VA into an address into this object
13881425 const relocated_address = address - self.base_address;
1389
1390 if (nosuspend self.dwarf.findCompileUnit(relocated_address)) |compile_unit| {
1391 return SymbolInfo{
1392 .symbol_name = nosuspend self.dwarf.getSymbolName(relocated_address) orelse "???",
1393 .compile_unit_name = compile_unit.die.getAttrString(&self.dwarf, DW.AT_name) catch |err| switch (err) {
1394 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1395 else => return err,
1396 },
1397 .line_info = nosuspend self.dwarf.getLineNumberInfo(compile_unit.*, relocated_address) catch |err| switch (err) {
1398 error.MissingDebugInfo, error.InvalidDebugInfo => null,
1399 else => return err,
1400 },
1401 };
1402 } else |err| switch (err) {
1403 error.MissingDebugInfo, error.InvalidDebugInfo => {
1404 return SymbolInfo{};
1405 },
1406 else => return err,
1407 }
1408
1409 unreachable;
1426 return getSymbolFromDwarf(relocated_address, &self.dwarf);
14101427 }
14111428 },
14121429 else => DW.DwarfInfo,
14131430};
14141431
1432fn getSymbolFromDwarf(address: u64, di: *DW.DwarfInfo) !SymbolInfo {
1433 if (nosuspend di.findCompileUnit(address)) |compile_unit| {
1434 return SymbolInfo{
1435 .symbol_name = nosuspend di.getSymbolName(address) orelse "???",
1436 .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT_name) catch |err| switch (err) {
1437 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1438 else => return err,
1439 },
1440 .line_info = nosuspend di.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) {
1441 error.MissingDebugInfo, error.InvalidDebugInfo => null,
1442 else => return err,
1443 },
1444 };
1445 } else |err| switch (err) {
1446 error.MissingDebugInfo, error.InvalidDebugInfo => {
1447 return SymbolInfo{};
1448 },
1449 else => return err,
1450 }
1451}
1452
14151453/// TODO multithreaded awareness
14161454var debug_info_allocator: ?*mem.Allocator = null;
14171455var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
lib/std/dwarf.zig+5-5
......@@ -144,7 +144,7 @@ const FileEntry = struct {
144144};
145145
146146const LineNumberProgram = struct {
147 address: usize,
147 address: u64,
148148 file: usize,
149149 line: i64,
150150 column: u64,
......@@ -153,12 +153,12 @@ const LineNumberProgram = struct {
153153 end_sequence: bool,
154154
155155 default_is_stmt: bool,
156 target_address: usize,
156 target_address: u64,
157157 include_dirs: []const []const u8,
158158 file_entries: *ArrayList(FileEntry),
159159
160160 prev_valid: bool,
161 prev_address: usize,
161 prev_address: u64,
162162 prev_file: usize,
163163 prev_line: i64,
164164 prev_column: u64,
......@@ -186,7 +186,7 @@ const LineNumberProgram = struct {
186186 self.prev_end_sequence = undefined;
187187 }
188188
189 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
189 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: u64) LineNumberProgram {
190190 return LineNumberProgram{
191191 .address = 0,
192192 .file = 1,
......@@ -691,7 +691,7 @@ pub const DwarfInfo = struct {
691691 return result;
692692 }
693693
694 pub fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {
694 pub fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: u64) !debug.LineInfo {
695695 var stream = io.fixedBufferStream(di.debug_line);
696696 const in = &stream.reader();
697697 const seekable = &stream.seekableStream();