commit ab387bb4c712b257cc2b728a044ad67935dee2dc (tree)
parent 86e55567b4b1cccbb69065396391e4a500864dce
Author: Andrew Kelley <superjoe30@gmail.com>
Date: Sun, 2 Sep 2018 18:47:48 -0400
Merge pull request #1460 from ziglang/Sahnvour-windows-coff-issue721
Stack traces for Windows
Diffstat:
25 files changed, 1556 insertions(+), 126 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -444,6 +444,7 @@ set(ZIG_STD_FILES
"c/index.zig"
"c/linux.zig"
"c/windows.zig"
+ "coff.zig"
"crypto/blake2.zig"
"crypto/hmac.zig"
"crypto/index.zig"
@@ -577,12 +578,14 @@ set(ZIG_STD_FILES
"os/windows/error.zig"
"os/windows/index.zig"
"os/windows/kernel32.zig"
+ "os/windows/ntdll.zig"
"os/windows/ole32.zig"
"os/windows/shell32.zig"
"os/windows/shlwapi.zig"
"os/windows/user32.zig"
"os/windows/util.zig"
"os/zen.zig"
+ "pdb.zig"
"rand/index.zig"
"rand/ziggurat.zig"
"segmented_list.zig"
diff --git a/doc/docgen.zig b/doc/docgen.zig
@@ -40,11 +40,11 @@ pub fn main() !void {
var out_file = try os.File.openWrite(out_file_name);
defer out_file.close();
- var file_in_stream = io.FileInStream.init(&in_file);
+ var file_in_stream = io.FileInStream.init(in_file);
const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
- var file_out_stream = io.FileOutStream.init(&out_file);
+ var file_out_stream = io.FileOutStream.init(out_file);
var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig
@@ -6,7 +6,7 @@ const os = std.os;
pub fn main() !void {
var stdout_file = try io.getStdOut();
- var stdout_file_stream = io.FileOutStream.init(&stdout_file);
+ var stdout_file_stream = io.FileOutStream.init(stdout_file);
const stdout = &stdout_file_stream.stream;
try stdout.print("Welcome to the Guess Number Game in Zig.\n");
diff --git a/src-self-hosted/errmsg.zig b/src-self-hosted/errmsg.zig
@@ -272,7 +272,7 @@ pub const Msg = struct {
try stream.write("\n");
}
- pub fn printToFile(msg: *const Msg, file: *os.File, color: Color) !void {
+ pub fn printToFile(msg: *const Msg, file: os.File, color: Color) !void {
const color_on = switch (color) {
Color.Auto => file.isTty(),
Color.On => true,
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
@@ -55,11 +55,11 @@ pub fn main() !void {
const allocator = std.heap.c_allocator;
var stdout_file = try std.io.getStdOut();
- var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
+ var stdout_out_stream = std.io.FileOutStream.init(stdout_file);
stdout = &stdout_out_stream.stream;
stderr_file = try std.io.getStdErr();
- var stderr_out_stream = std.io.FileOutStream.init(&stderr_file);
+ var stderr_out_stream = std.io.FileOutStream.init(stderr_file);
stderr = &stderr_out_stream.stream;
const args = try os.argsAlloc(allocator);
@@ -491,7 +491,7 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
stderr.print("Build {} compile errors:\n", count) catch os.exit(1);
for (msgs) |msg| {
defer msg.destroy();
- msg.printToFile(&stderr_file, color) catch os.exit(1);
+ msg.printToFile(stderr_file, color) catch os.exit(1);
}
},
}
@@ -619,7 +619,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
}
var stdin_file = try io.getStdIn();
- var stdin = io.FileInStream.init(&stdin_file);
+ var stdin = io.FileInStream.init(stdin_file);
const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);
defer allocator.free(source_code);
@@ -635,7 +635,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");
defer msg.destroy();
- try msg.printToFile(&stderr_file, color);
+ try msg.printToFile(stderr_file, color);
}
if (tree.errors.len != 0) {
os.exit(1);
@@ -772,7 +772,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void {
const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path);
defer fmt.loop.allocator.destroy(msg);
- try msg.printToFile(&stderr_file, fmt.color);
+ try msg.printToFile(stderr_file, fmt.color);
}
if (tree.errors.len != 0) {
fmt.any_error = true;
diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig
@@ -185,7 +185,7 @@ pub const TestContext = struct {
try stderr.write("build incorrectly failed:\n");
for (msgs) |msg| {
defer msg.destroy();
- try msg.printToFile(&stderr, errmsg.Color.Auto);
+ try msg.printToFile(stderr, errmsg.Color.Auto);
}
},
}
@@ -234,7 +234,7 @@ pub const TestContext = struct {
var stderr = try std.io.getStdErr();
for (msgs) |msg| {
defer msg.destroy();
- try msg.printToFile(&stderr, errmsg.Color.Auto);
+ try msg.printToFile(stderr, errmsg.Color.Auto);
}
std.debug.warn("============\n");
return error.TestFailed;
diff --git a/std/coff.zig b/std/coff.zig
@@ -0,0 +1,230 @@
+const builtin = @import("builtin");
+const std = @import("index.zig");
+const io = std.io;
+const mem = std.mem;
+const os = std.os;
+
+const ArrayList = std.ArrayList;
+
+// CoffHeader.machine values
+// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
+const IMAGE_FILE_MACHINE_I386 = 0x014c;
+const IMAGE_FILE_MACHINE_IA64 = 0x0200;
+const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
+
+// OptionalHeader.magic values
+// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
+const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
+const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
+
+const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
+const DEBUG_DIRECTORY = 6;
+
+pub const CoffError = error {
+ InvalidPEMagic,
+ InvalidPEHeader,
+ InvalidMachine,
+ MissingCoffSection,
+};
+
+pub const Coff = struct {
+ in_file: os.File,
+ allocator: *mem.Allocator,
+
+ coff_header: CoffHeader,
+ pe_header: OptionalHeader,
+ sections: ArrayList(Section),
+
+ guid: [16]u8,
+ age: u32,
+
+ pub fn loadHeader(self: *Coff) !void {
+ const pe_pointer_offset = 0x3C;
+
+ var file_stream = io.FileInStream.init(self.in_file);
+ const in = &file_stream.stream;
+
+ var magic: [2]u8 = undefined;
+ try in.readNoEof(magic[0..]);
+ if (!mem.eql(u8, magic, "MZ"))
+ return error.InvalidPEMagic;
+
+ // Seek to PE File Header (coff header)
+ try self.in_file.seekTo(pe_pointer_offset);
+ const pe_magic_offset = try in.readIntLe(u32);
+ try self.in_file.seekTo(pe_magic_offset);
+
+ var pe_header_magic: [4]u8 = undefined;
+ try in.readNoEof(pe_header_magic[0..]);
+ if (!mem.eql(u8, pe_header_magic, []u8{'P', 'E', 0, 0}))
+ return error.InvalidPEHeader;
+
+ self.coff_header = CoffHeader {
+ .machine = try in.readIntLe(u16),
+ .number_of_sections = try in.readIntLe(u16),
+ .timedate_stamp = try in.readIntLe(u32),
+ .pointer_to_symbol_table = try in.readIntLe(u32),
+ .number_of_symbols = try in.readIntLe(u32),
+ .size_of_optional_header = try in.readIntLe(u16),
+ .characteristics = try in.readIntLe(u16),
+ };
+
+ switch (self.coff_header.machine) {
+ IMAGE_FILE_MACHINE_I386,
+ IMAGE_FILE_MACHINE_AMD64,
+ IMAGE_FILE_MACHINE_IA64
+ => {},
+ else => return error.InvalidMachine,
+ }
+
+ try self.loadOptionalHeader(&file_stream);
+ }
+
+ fn loadOptionalHeader(self: *Coff, file_stream: *io.FileInStream) !void {
+ const in = &file_stream.stream;
+ self.pe_header.magic = try in.readIntLe(u16);
+ // For now we're only interested in finding the reference to the .pdb,
+ // so we'll skip most of this header, which size is different in 32
+ // 64 bits by the way.
+ var skip_size: u16 = undefined;
+ if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 18 * @sizeOf(u32);
+ }
+ else if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 12 * @sizeOf(u32) + 5 * @sizeOf(u64);
+ }
+ else
+ return error.InvalidPEMagic;
+
+ try self.in_file.seekForward(skip_size);
+
+ const number_of_rva_and_sizes = try in.readIntLe(u32);
+ if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+ return error.InvalidPEHeader;
+
+ for (self.pe_header.data_directory) |*data_dir| {
+ data_dir.* = OptionalHeader.DataDirectory {
+ .virtual_address = try in.readIntLe(u32),
+ .size = try in.readIntLe(u32),
+ };
+ }
+ }
+
+ pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
+ try self.loadSections();
+ const header = (self.getSection(".rdata") orelse return error.MissingCoffSection).header;
+
+ // The linker puts a chunk that contains the .pdb path right after the
+ // debug_directory.
+ const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
+ const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
+ try self.in_file.seekTo(file_offset + debug_dir.size);
+
+ var file_stream = io.FileInStream.init(self.in_file);
+ const in = &file_stream.stream;
+
+ var cv_signature: [4]u8 = undefined; // CodeView signature
+ try in.readNoEof(cv_signature[0..]);
+ // 'RSDS' indicates PDB70 format, used by lld.
+ if (!mem.eql(u8, cv_signature, "RSDS"))
+ return error.InvalidPEMagic;
+ try in.readNoEof(self.guid[0..]);
+ self.age = try in.readIntLe(u32);
+
+ // Finally read the null-terminated string.
+ var byte = try in.readByte();
+ var i: usize = 0;
+ while (byte != 0 and i < buffer.len) : (i += 1) {
+ buffer[i] = byte;
+ byte = try in.readByte();
+ }
+
+ if (byte != 0 and i == buffer.len)
+ return error.NameTooLong;
+
+ return i;
+ }
+
+ pub fn loadSections(self: *Coff) !void {
+ if (self.sections.len != 0)
+ return;
+
+ self.sections = ArrayList(Section).init(self.allocator);
+
+ var file_stream = io.FileInStream.init(self.in_file);
+ const in = &file_stream.stream;
+
+ var name: [8]u8 = undefined;
+
+ var i: u16 = 0;
+ while (i < self.coff_header.number_of_sections) : (i += 1) {
+ try in.readNoEof(name[0..]);
+ try self.sections.append(Section {
+ .header = SectionHeader {
+ .name = name,
+ .misc = SectionHeader.Misc { .physical_address = try in.readIntLe(u32) },
+ .virtual_address = try in.readIntLe(u32),
+ .size_of_raw_data = try in.readIntLe(u32),
+ .pointer_to_raw_data = try in.readIntLe(u32),
+ .pointer_to_relocations = try in.readIntLe(u32),
+ .pointer_to_line_numbers = try in.readIntLe(u32),
+ .number_of_relocations = try in.readIntLe(u16),
+ .number_of_line_numbers = try in.readIntLe(u16),
+ .characteristics = try in.readIntLe(u32),
+ },
+ });
+ }
+ }
+
+ pub fn getSection(self: *Coff, comptime name: []const u8) ?*Section {
+ for (self.sections.toSlice()) |*sec| {
+ if (mem.eql(u8, sec.header.name[0..name.len], name)) {
+ return sec;
+ }
+ }
+ return null;
+ }
+
+};
+
+const CoffHeader = struct {
+ machine: u16,
+ number_of_sections: u16,
+ timedate_stamp: u32,
+ pointer_to_symbol_table: u32,
+ number_of_symbols: u32,
+ size_of_optional_header: u16,
+ characteristics: u16
+};
+
+const OptionalHeader = struct {
+ const DataDirectory = struct {
+ virtual_address: u32,
+ size: u32
+ };
+
+ magic: u16,
+ data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
+};
+
+pub const Section = struct {
+ header: SectionHeader,
+};
+
+const SectionHeader = struct {
+ const Misc = union {
+ physical_address: u32,
+ virtual_size: u32
+ };
+
+ name: [8]u8,
+ misc: Misc,
+ virtual_address: u32,
+ size_of_raw_data: u32,
+ pointer_to_raw_data: u32,
+ pointer_to_relocations: u32,
+ pointer_to_line_numbers: u32,
+ number_of_relocations: u16,
+ number_of_line_numbers: u16,
+ characteristics: u32,
+};
diff --git a/std/debug/index.zig b/std/debug/index.zig
@@ -4,8 +4,11 @@ const mem = std.mem;
const io = std.io;
const os = std.os;
const elf = std.elf;
-const macho = std.macho;
const DW = std.dwarf;
+const macho = std.macho;
+const coff = std.coff;
+const pdb = std.pdb;
+const windows = os.windows;
const ArrayList = std.ArrayList;
const builtin = @import("builtin");
@@ -17,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {
builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
};
+const Module = struct {
+ mod_info: pdb.ModInfo,
+ module_name: []u8,
+ obj_file_name: []u8,
+
+ populated: bool,
+ symbols: []u8,
+ subsect_info: []u8,
+ checksum_offset: ?usize,
+};
+
/// Tries to write to stderr, unbuffered, and ignores any error returned.
/// Does not append a newline.
var stderr_file: os.File = undefined;
@@ -37,7 +51,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {
return st;
} else {
stderr_file = try io.getStdErr();
- stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
+ stderr_file_out_stream = io.FileOutStream.init(stderr_file);
const st = &stderr_file_out_stream.stream;
stderr_stream = st;
return st;
@@ -70,7 +84,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
return;
};
- writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| {
+ writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
return;
};
@@ -191,7 +205,11 @@ pub inline fn getReturnAddress(frame_count: usize) usize {
return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
}
-pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
+pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
+ switch (builtin.os) {
+ builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
+ else => {},
+ }
const AddressState = union(enum) {
NotLookingForStartAddress,
LookingForStartAddress: usize,
@@ -224,18 +242,296 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_
}
}
+pub fn writeCurrentStackTraceWindows(out_stream: var, debug_info: *DebugInfo,
+ tty_color: bool, start_addr: ?usize) !void
+{
+ var addr_buf: [1024]usize = undefined;
+ const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast
+ const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null);
+ const addrs = addr_buf[0..n];
+ var start_i: usize = if (start_addr) |saddr| blk: {
+ for (addrs) |addr, i| {
+ if (addr == saddr) break :blk i;
+ }
+ return;
+ } else 0;
+ for (addrs[start_i..]) |addr| {
+ try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
+ }
+}
+
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
switch (builtin.os) {
builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
- builtin.Os.windows => {
- // TODO https://github.com/ziglang/zig/issues/721
- return error.UnsupportedOperatingSystem;
- },
+ builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
else => return error.UnsupportedOperatingSystem,
}
}
+fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
+ const allocator = getDebugInfoAllocator();
+ const base_address = os.getBaseAddress();
+ const relative_address = relocated_address - base_address;
+
+ var coff_section: *coff.Section = undefined;
+ const mod_index = for (di.sect_contribs) |sect_contrib| {
+ if (sect_contrib.Section >= di.coff.sections.len) continue;
+ coff_section = &di.coff.sections.toSlice()[sect_contrib.Section];
+
+ const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
+ const vaddr_end = vaddr_start + sect_contrib.Size;
+ if (relative_address >= vaddr_start and relative_address < vaddr_end) {
+ break sect_contrib.ModuleIndex;
+ }
+ } else {
+ // we have no information to add to the address
+ if (tty_color) {
+ try out_stream.print("???:?:?: ");
+ setTtyColor(TtyColor.Dim);
+ try out_stream.print("0x{x} in ??? (???)", relocated_address);
+ setTtyColor(TtyColor.Reset);
+ try out_stream.print("\n\n\n");
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
+ }
+ return;
+ };
+
+ const mod = &di.modules[mod_index];
+ try populateModule(di, mod);
+ const obj_basename = os.path.basename(mod.obj_file_name);
+
+ var symbol_i: usize = 0;
+ const symbol_name = while (symbol_i != mod.symbols.len) {
+ const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
+ if (prefix.RecordLen < 2)
+ return error.InvalidDebugInfo;
+ switch (prefix.RecordKind) {
+ pdb.SymbolKind.S_LPROC32 => {
+ const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
+ const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
+ const vaddr_end = vaddr_start + proc_sym.CodeSize;
+ if (relative_address >= vaddr_start and relative_address < vaddr_end) {
+ break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
+ }
+ },
+ else => {},
+ }
+ symbol_i += prefix.RecordLen + @sizeOf(u16);
+ if (symbol_i > mod.symbols.len)
+ return error.InvalidDebugInfo;
+ } else "???";
+
+ const subsect_info = mod.subsect_info;
+
+ var sect_offset: usize = 0;
+ var skip_len: usize = undefined;
+ const opt_line_info = subsections: {
+ const checksum_offset = mod.checksum_offset orelse break :subsections null;
+ while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
+ const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
+ skip_len = subsect_hdr.Length;
+ sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
+
+ switch (subsect_hdr.Kind) {
+ pdb.DebugSubsectionKind.Lines => {
+ var line_index: usize = sect_offset;
+
+ const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
+ if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
+ line_index += @sizeOf(pdb.LineFragmentHeader);
+
+ const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
+ line_index += @sizeOf(pdb.LineBlockFragmentHeader);
+
+ const has_column = line_hdr.Flags.LF_HaveColumns;
+
+ const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
+ const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
+ if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
+ var line_i: usize = 0;
+ const start_line_index = line_index;
+ while (line_i < block_hdr.NumLines) : (line_i += 1) {
+ const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
+ line_index += @sizeOf(pdb.LineNumberEntry);
+ const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
+ const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
+ const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End;
+ if (relative_address >= vaddr_start and relative_address < vaddr_end) {
+ const subsect_index = checksum_offset + block_hdr.NameIndex;
+ const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
+ const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
+ try di.pdb.string_table.seekTo(strtab_offset);
+ const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
+ const line = flags.Start;
+ const column = if (has_column) blk: {
+ line_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
+ line_index += @sizeOf(pdb.ColumnNumberEntry) * line_i;
+ const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[line_index]);
+ break :blk col_num_entry.StartColumn;
+ } else 0;
+ break :subsections LineInfo{
+ .allocator = allocator,
+ .file_name = source_file_name,
+ .line = line,
+ .column = column,
+ };
+ }
+ }
+ break :subsections null;
+ }
+ },
+ else => {},
+ }
+
+ if (sect_offset > subsect_info.len)
+ return error.InvalidDebugInfo;
+ } else {
+ break :subsections null;
+ }
+ };
+
+ if (tty_color) {
+ setTtyColor(TtyColor.White);
+ if (opt_line_info) |li| {
+ try out_stream.print("{}:{}:{}", li.file_name, li.line, li.column);
+ } else {
+ try out_stream.print("???:?:?");
+ }
+ setTtyColor(TtyColor.Reset);
+ try out_stream.print(": ");
+ setTtyColor(TtyColor.Dim);
+ try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
+ setTtyColor(TtyColor.Reset);
+
+ if (opt_line_info) |line_info| {
+ try out_stream.print("\n");
+ if (printLineFromFile(out_stream, line_info)) {
+ if (line_info.column == 0) {
+ try out_stream.write("\n");
+ } else {
+ {
+ var col_i: usize = 1;
+ while (col_i < line_info.column) : (col_i += 1) {
+ try out_stream.writeByte(' ');
+ }
+ }
+ setTtyColor(TtyColor.Green);
+ try out_stream.write("^");
+ setTtyColor(TtyColor.Reset);
+ try out_stream.write("\n");
+ }
+ } else |err| switch (err) {
+ error.EndOfFile => {},
+ else => return err,
+ }
+ } else {
+ try out_stream.print("\n\n\n");
+ }
+ } else {
+ if (opt_line_info) |li| {
+ try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
+ }
+ }
+}
+
+const TtyColor = enum{
+ Red,
+ Green,
+ Cyan,
+ White,
+ Dim,
+ Bold,
+ Reset,
+};
+
+/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
+fn setTtyColor(tty_color: TtyColor) void {
+ const S = struct {
+ var attrs: windows.WORD = undefined;
+ var init_attrs = false;
+ };
+ if (!S.init_attrs) {
+ S.init_attrs = true;
+ var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
+ // TODO handle error
+ _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
+ S.attrs = info.wAttributes;
+ }
+
+ // TODO handle errors
+ switch (tty_color) {
+ TtyColor.Red => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED|windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Green => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN|windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Cyan => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle,
+ windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.White, TtyColor.Bold => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle,
+ windows.FOREGROUND_RED|windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Dim => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Reset => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
+ },
+ }
+}
+
+fn populateModule(di: *DebugInfo, mod: *Module) !void {
+ if (mod.populated)
+ return;
+ const allocator = getDebugInfoAllocator();
+
+ if (mod.mod_info.C11ByteSize != 0)
+ return error.InvalidDebugInfo;
+
+ if (mod.mod_info.C13ByteSize == 0)
+ return error.MissingDebugInfo;
+
+ const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
+
+ const signature = try modi.stream.readIntLe(u32);
+ if (signature != 4)
+ return error.InvalidDebugInfo;
+
+ mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
+ try modi.stream.readNoEof(mod.symbols);
+
+ mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
+ try modi.stream.readNoEof(mod.subsect_info);
+
+ var sect_offset: usize = 0;
+ var skip_len: usize = undefined;
+ while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
+ const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
+ skip_len = subsect_hdr.Length;
+ sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
+
+ switch (subsect_hdr.Kind) {
+ pdb.DebugSubsectionKind.FileChecksums => {
+ mod.checksum_offset = sect_offset;
+ break;
+ },
+ else => {},
+ }
+
+ if (sect_offset > mod.subsect_info.len)
+ return error.InvalidDebugInfo;
+ }
+
+ mod.populated = true;
+}
+
fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
var min: usize = 0;
var max: usize = symbols.len - 1; // Exclude sentinel.
@@ -372,14 +668,185 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
switch (builtin.os) {
builtin.Os.linux => return openSelfDebugInfoLinux(allocator),
builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
- builtin.Os.windows => {
- // TODO: https://github.com/ziglang/zig/issues/721
- return error.UnsupportedOperatingSystem;
- },
+ builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
else => return error.UnsupportedOperatingSystem,
}
}
+fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
+ const self_file = try os.openSelfExe();
+ defer self_file.close();
+
+ const coff_obj = try allocator.createOne(coff.Coff);
+ coff_obj.* = coff.Coff{
+ .in_file = self_file,
+ .allocator = allocator,
+ .coff_header = undefined,
+ .pe_header = undefined,
+ .sections = undefined,
+ .guid = undefined,
+ .age = undefined,
+ };
+
+ var di = DebugInfo{
+ .coff = coff_obj,
+ .pdb = undefined,
+ .sect_contribs = undefined,
+ .modules = undefined,
+ };
+
+ try di.coff.loadHeader();
+
+ var path_buf: [windows.MAX_PATH]u8 = undefined;
+ const len = try di.coff.getPdbPath(path_buf[0..]);
+ const raw_path = path_buf[0..len];
+
+ const path = try os.path.resolve(allocator, raw_path);
+
+ try di.pdb.openFile(di.coff, path);
+
+ var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
+ const version = try pdb_stream.stream.readIntLe(u32);
+ const signature = try pdb_stream.stream.readIntLe(u32);
+ const age = try pdb_stream.stream.readIntLe(u32);
+ var guid: [16]u8 = undefined;
+ try pdb_stream.stream.readNoEof(guid[0..]);
+ if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
+ return error.InvalidDebugInfo;
+ // We validated the executable and pdb match.
+
+ const string_table_index = str_tab_index: {
+ const name_bytes_len = try pdb_stream.stream.readIntLe(u32);
+ const name_bytes = try allocator.alloc(u8, name_bytes_len);
+ try pdb_stream.stream.readNoEof(name_bytes);
+
+ const HashTableHeader = packed struct {
+ Size: u32,
+ Capacity: u32,
+
+ fn maxLoad(cap: u32) u32 {
+ return cap * 2 / 3 + 1;
+ }
+ };
+ var hash_tbl_hdr: HashTableHeader = undefined;
+ try pdb_stream.stream.readStruct(HashTableHeader, &hash_tbl_hdr);
+ if (hash_tbl_hdr.Capacity == 0)
+ return error.InvalidDebugInfo;
+
+ if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
+ return error.InvalidDebugInfo;
+
+ const present = try readSparseBitVector(&pdb_stream.stream, allocator);
+ if (present.len != hash_tbl_hdr.Size)
+ return error.InvalidDebugInfo;
+ const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
+
+ const Bucket = struct {
+ first: u32,
+ second: u32,
+ };
+ const bucket_list = try allocator.alloc(Bucket, present.len);
+ for (present) |_| {
+ const name_offset = try pdb_stream.stream.readIntLe(u32);
+ const name_index = try pdb_stream.stream.readIntLe(u32);
+ const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
+ if (mem.eql(u8, name, "/names")) {
+ break :str_tab_index name_index;
+ }
+ }
+ return error.MissingDebugInfo;
+ };
+
+ di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
+ di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
+
+ const dbi = di.pdb.dbi;
+
+ // Dbi Header
+ var dbi_stream_header: pdb.DbiStreamHeader = undefined;
+ try dbi.stream.readStruct(pdb.DbiStreamHeader, &dbi_stream_header);
+ const mod_info_size = dbi_stream_header.ModInfoSize;
+ const section_contrib_size = dbi_stream_header.SectionContributionSize;
+
+ var modules = ArrayList(Module).init(allocator);
+
+ // Module Info Substream
+ var mod_info_offset: usize = 0;
+ while (mod_info_offset != mod_info_size) {
+ var mod_info: pdb.ModInfo = undefined;
+ try dbi.stream.readStruct(pdb.ModInfo, &mod_info);
+ var this_record_len: usize = @sizeOf(pdb.ModInfo);
+
+ const module_name = try dbi.readNullTermString(allocator);
+ this_record_len += module_name.len + 1;
+
+ const obj_file_name = try dbi.readNullTermString(allocator);
+ this_record_len += obj_file_name.len + 1;
+
+ const march_forward_bytes = this_record_len % 4;
+ if (march_forward_bytes != 0) {
+ try dbi.seekForward(march_forward_bytes);
+ this_record_len += march_forward_bytes;
+ }
+
+ try modules.append(Module{
+ .mod_info = mod_info,
+ .module_name = module_name,
+ .obj_file_name = obj_file_name,
+
+ .populated = false,
+ .symbols = undefined,
+ .subsect_info = undefined,
+ .checksum_offset = null,
+ });
+
+ mod_info_offset += this_record_len;
+ if (mod_info_offset > mod_info_size)
+ return error.InvalidDebugInfo;
+ }
+
+ di.modules = modules.toOwnedSlice();
+
+ // Section Contribution Substream
+ var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
+ var sect_cont_offset: usize = 0;
+ if (section_contrib_size != 0) {
+ const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
+ if (ver != pdb.SectionContrSubstreamVersion.Ver60)
+ return error.InvalidDebugInfo;
+ sect_cont_offset += @sizeOf(u32);
+ }
+ while (sect_cont_offset != section_contrib_size) {
+ const entry = try sect_contribs.addOne();
+ try dbi.stream.readStruct(pdb.SectionContribEntry, entry);
+ sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
+
+ if (sect_cont_offset > section_contrib_size)
+ return error.InvalidDebugInfo;
+ }
+
+ di.sect_contribs = sect_contribs.toOwnedSlice();
+
+ return di;
+}
+
+fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
+ const num_words = try stream.readIntLe(u32);
+ var word_i: usize = 0;
+ var list = ArrayList(usize).init(allocator);
+ while (word_i != num_words) : (word_i += 1) {
+ const word = try stream.readIntLe(u32);
+ var bit_i: u5 = 0;
+ while (true) : (bit_i += 1) {
+ if (word & (u32(1) << bit_i) != 0) {
+ try list.append(word_i * 32 + bit_i);
+ }
+ if (bit_i == @maxValue(u5)) break;
+ }
+ }
+ return list.toOwnedSlice();
+}
+
fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
var di = DebugInfo{
.self_exe_file = undefined,
@@ -395,7 +862,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
di.self_exe_file = try os.openSelfExe();
errdefer di.self_exe_file.close();
- try di.elf.openFile(allocator, &di.self_exe_file);
+ try di.elf.openFile(allocator, di.self_exe_file);
errdefer di.elf.close();
di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
@@ -578,7 +1045,13 @@ pub const DebugInfo = switch (builtin.os) {
return self.ofiles.allocator;
}
},
- else => struct {
+ builtin.Os.windows => struct {
+ pdb: pdb.Pdb,
+ coff: *coff.Coff,
+ sect_contribs: []pdb.SectionContribEntry,
+ modules: []Module,
+ },
+ builtin.Os.linux => struct {
self_exe_file: os.File,
elf: elf.Elf,
debug_info: *elf.SectionHeader,
@@ -594,7 +1067,7 @@ pub const DebugInfo = switch (builtin.os) {
}
pub fn readString(self: *DebugInfo) ![]u8 {
- var in_file_stream = io.FileInStream.init(&self.self_exe_file);
+ var in_file_stream = io.FileInStream.init(self.self_exe_file);
const in_stream = &in_file_stream.stream;
return readStringRaw(self.allocator(), in_stream);
}
@@ -604,6 +1077,7 @@ pub const DebugInfo = switch (builtin.os) {
self.elf.close();
}
},
+ else => @compileError("Unsupported OS"),
};
const PcRange = struct {
@@ -929,7 +1403,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
}
fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
- const in_file = &st.self_exe_file;
+ const in_file = st.self_exe_file;
var in_file_stream = io.FileInStream.init(in_file);
const in_stream = &in_file_stream.stream;
var result = AbbrevTable.init(st.allocator());
@@ -980,7 +1454,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
}
fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
- const in_file = &st.self_exe_file;
+ const in_file = st.self_exe_file;
var in_file_stream = io.FileInStream.init(in_file);
const in_stream = &in_file_stream.stream;
const abbrev_code = try readULeb128(in_stream);
@@ -1202,7 +1676,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
- const in_file = &di.self_exe_file;
+ const in_file = di.self_exe_file;
const debug_line_end = di.debug_line.offset + di.debug_line.size;
var this_offset = di.debug_line.offset;
var this_index: usize = 0;
@@ -1382,7 +1856,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
var this_unit_offset = st.debug_info.offset;
var cu_index: usize = 0;
- var in_file_stream = io.FileInStream.init(&st.self_exe_file);
+ var in_file_stream = io.FileInStream.init(st.self_exe_file);
const in_stream = &in_file_stream.stream;
while (this_unit_offset < debug_info_end) {
@@ -1448,7 +1922,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
}
fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
- var in_file_stream = io.FileInStream.init(&st.self_exe_file);
+ var in_file_stream = io.FileInStream.init(st.self_exe_file);
const in_stream = &in_file_stream.stream;
for (st.compile_unit_list.toSlice()) |*compile_unit| {
if (compile_unit.pc_range) |range| {
diff --git a/std/elf.zig b/std/elf.zig
@@ -353,7 +353,7 @@ pub const SectionHeader = struct {
};
pub const Elf = struct {
- in_file: *os.File,
+ in_file: os.File,
auto_close_stream: bool,
is_64: bool,
endian: builtin.Endian,
@@ -376,7 +376,7 @@ pub const Elf = struct {
}
/// Call close when done.
- pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: *os.File) !void {
+ pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
elf.allocator = allocator;
elf.in_file = file;
elf.auto_close_stream = false;
diff --git a/std/event/tcp.zig b/std/event/tcp.zig
@@ -145,11 +145,11 @@ test "listen on a port, send bytes, receive bytes" {
cancel @handle();
}
}
- async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: *const std.os.File) !void {
+ async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: std.os.File) !void {
const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733
- var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
+ var socket = _socket; // TODO https://github.com/ziglang/zig/issues/733
- var adapter = std.io.FileOutStream.init(&socket);
+ var adapter = std.io.FileOutStream.init(socket);
var stream = &adapter.stream;
try stream.print("hello from server\n");
}
diff --git a/std/index.zig b/std/index.zig
@@ -15,6 +15,7 @@ pub const atomic = @import("atomic/index.zig");
pub const base64 = @import("base64.zig");
pub const build = @import("build.zig");
pub const c = @import("c/index.zig");
+pub const coff = @import("coff.zig");
pub const crypto = @import("crypto/index.zig");
pub const cstr = @import("cstr.zig");
pub const debug = @import("debug/index.zig");
@@ -33,6 +34,7 @@ pub const math = @import("math/index.zig");
pub const mem = @import("mem.zig");
pub const net = @import("net.zig");
pub const os = @import("os/index.zig");
+pub const pdb = @import("pdb.zig");
pub const rand = @import("rand/index.zig");
pub const rb = @import("rb.zig");
pub const sort = @import("sort.zig");
@@ -56,6 +58,7 @@ test "std" {
_ = @import("base64.zig");
_ = @import("build.zig");
_ = @import("c/index.zig");
+ _ = @import("coff.zig");
_ = @import("crypto/index.zig");
_ = @import("cstr.zig");
_ = @import("debug/index.zig");
@@ -74,6 +77,7 @@ test "std" {
_ = @import("heap.zig");
_ = @import("os/index.zig");
_ = @import("rand/index.zig");
+ _ = @import("pdb.zig");
_ = @import("sort.zig");
_ = @import("unicode.zig");
_ = @import("zig/index.zig");
diff --git a/std/io.zig b/std/io.zig
@@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File {
/// Implementation of InStream trait for File
pub const FileInStream = struct {
- file: *File,
+ file: File,
stream: Stream,
pub const Error = @typeOf(File.read).ReturnType.ErrorSet;
pub const Stream = InStream(Error);
- pub fn init(file: *File) FileInStream {
+ pub fn init(file: File) FileInStream {
return FileInStream{
.file = file,
.stream = Stream{ .readFn = readFn },
@@ -55,13 +55,13 @@ pub const FileInStream = struct {
/// Implementation of OutStream trait for File
pub const FileOutStream = struct {
- file: *File,
+ file: File,
stream: Stream,
pub const Error = File.WriteError;
pub const Stream = OutStream(Error);
- pub fn init(file: *File) FileOutStream {
+ pub fn init(file: File) FileOutStream {
return FileOutStream{
.file = file,
.stream = Stream{ .writeFn = writeFn },
@@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type {
pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void {
// Only extern and packed structs have defined in-memory layout.
- assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
+ comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..]));
}
};
@@ -280,7 +280,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim
const buf = try allocator.alignedAlloc(u8, A, size);
errdefer allocator.free(buf);
- var adapter = FileInStream.init(&file);
+ var adapter = FileInStream.init(file);
try adapter.stream.readNoEof(buf[0..size]);
return buf;
}
@@ -592,7 +592,7 @@ pub const BufferedAtomicFile = struct {
self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.File.default_mode);
errdefer self.atomic_file.deinit();
- self.file_stream = FileOutStream.init(&self.atomic_file.file);
+ self.file_stream = FileOutStream.init(self.atomic_file.file);
self.buffered_stream = BufferedOutStream(FileOutStream.Error).init(&self.file_stream.stream);
return self;
}
@@ -622,7 +622,7 @@ test "import io tests" {
pub fn readLine(buf: []u8) !usize {
var stdin = getStdIn() catch return error.StdInUnavailable;
- var adapter = FileInStream.init(&stdin);
+ var adapter = FileInStream.init(stdin);
var stream = &adapter.stream;
var index: usize = 0;
while (true) {
diff --git a/std/io_test.zig b/std/io_test.zig
@@ -19,7 +19,7 @@ test "write a file, read it, then delete it" {
var file = try os.File.openWrite(tmp_file_name);
defer file.close();
- var file_out_stream = io.FileOutStream.init(&file);
+ var file_out_stream = io.FileOutStream.init(file);
var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
const st = &buf_stream.stream;
try st.print("begin");
@@ -35,7 +35,7 @@ test "write a file, read it, then delete it" {
const expected_file_size = "begin".len + data.len + "end".len;
assert(file_size == expected_file_size);
- var file_in_stream = io.FileInStream.init(&file);
+ var file_in_stream = io.FileInStream.init(file);
var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream);
const st = &buf_stream.stream;
const contents = try st.readAllAlloc(allocator, 2 * 1024);
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
@@ -209,8 +209,8 @@ pub const ChildProcess = struct {
defer Buffer.deinit(&stdout);
defer Buffer.deinit(&stderr);
- var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
- var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
+ var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
+ var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
diff --git a/std/os/file.zig b/std/os/file.zig
@@ -48,18 +48,23 @@ pub const File = struct {
return openReadC(&path_c);
}
if (is_windows) {
- const handle = try os.windowsOpen(
- path,
- windows.GENERIC_READ,
- windows.FILE_SHARE_READ,
- windows.OPEN_EXISTING,
- windows.FILE_ATTRIBUTE_NORMAL,
- );
- return openHandle(handle);
+ const path_w = try windows_util.sliceToPrefixedFileW(path);
+ return openReadW(&path_w);
}
@compileError("Unsupported OS");
}
+ pub fn openReadW(path_w: [*]const u16) OpenError!File {
+ const handle = try os.windowsOpenW(
+ path_w,
+ windows.GENERIC_READ,
+ windows.FILE_SHARE_READ,
+ windows.OPEN_EXISTING,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ );
+ return openHandle(handle);
+ }
+
/// Calls `openWriteMode` with os.File.default_mode for the mode.
pub fn openWrite(path: []const u8) OpenError!File {
return openWriteMode(path, os.File.default_mode);
@@ -74,19 +79,24 @@ pub const File = struct {
const fd = try os.posixOpen(path, flags, file_mode);
return openHandle(fd);
} else if (is_windows) {
- const handle = try os.windowsOpen(
- path,
- windows.GENERIC_WRITE,
- windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
- windows.CREATE_ALWAYS,
- windows.FILE_ATTRIBUTE_NORMAL,
- );
- return openHandle(handle);
+ const path_w = try windows_util.sliceToPrefixedFileW(path);
+ return openWriteModeW(&path_w, file_mode);
} else {
@compileError("TODO implement openWriteMode for this OS");
}
}
+ pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
+ const handle = try os.windowsOpenW(
+ path_w,
+ windows.GENERIC_WRITE,
+ windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
+ windows.CREATE_ALWAYS,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ );
+ return openHandle(handle);
+ }
+
/// If the path does not exist it will be created.
/// If a file already exists in the destination this returns OpenError.PathAlreadyExists
/// Call close to clean up.
@@ -96,19 +106,24 @@ pub const File = struct {
const fd = try os.posixOpen(path, flags, file_mode);
return openHandle(fd);
} else if (is_windows) {
- const handle = try os.windowsOpen(
- path,
- windows.GENERIC_WRITE,
- windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
- windows.CREATE_NEW,
- windows.FILE_ATTRIBUTE_NORMAL,
- );
- return openHandle(handle);
+ const path_w = try windows_util.sliceToPrefixedFileW(path);
+ return openWriteNoClobberW(&path_w, file_mode);
} else {
@compileError("TODO implement openWriteMode for this OS");
}
}
+ pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
+ const handle = try os.windowsOpenW(
+ path_w,
+ windows.GENERIC_WRITE,
+ windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
+ windows.CREATE_NEW,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ );
+ return openHandle(handle);
+ }
+
pub fn openHandle(handle: os.FileHandle) File {
return File{ .handle = handle };
}
@@ -190,17 +205,16 @@ pub const File = struct {
/// Upon success, the stream is in an uninitialized state. To continue using it,
/// you must use the open() function.
- pub fn close(self: *File) void {
+ pub fn close(self: File) void {
os.close(self.handle);
- self.handle = undefined;
}
/// Calls `os.isTty` on `self.handle`.
- pub fn isTty(self: *File) bool {
+ pub fn isTty(self: File) bool {
return os.isTty(self.handle);
}
- pub fn seekForward(self: *File, amount: isize) !void {
+ pub fn seekForward(self: File, amount: isize) !void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
@@ -231,7 +245,7 @@ pub const File = struct {
}
}
- pub fn seekTo(self: *File, pos: usize) !void {
+ pub fn seekTo(self: File, pos: usize) !void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
const ipos = try math.cast(isize, pos);
@@ -256,6 +270,7 @@ pub const File = struct {
const err = windows.GetLastError();
return switch (err) {
windows.ERROR.INVALID_PARAMETER => unreachable,
+ windows.ERROR.INVALID_HANDLE => unreachable,
else => os.unexpectedErrorWindows(err),
};
}
@@ -264,7 +279,7 @@ pub const File = struct {
}
}
- pub fn getPos(self: *File) !usize {
+ pub fn getPos(self: File) !usize {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
@@ -300,7 +315,7 @@ pub const File = struct {
}
}
- pub fn getEndPos(self: *File) !usize {
+ pub fn getEndPos(self: File) !usize {
if (is_posix) {
const stat = try os.posixFStat(self.handle);
return @intCast(usize, stat.size);
@@ -325,7 +340,7 @@ pub const File = struct {
Unexpected,
};
- pub fn mode(self: *File) ModeError!Mode {
+ pub fn mode(self: File) ModeError!Mode {
if (is_posix) {
var stat: posix.Stat = undefined;
const err = posix.getErrno(posix.fstat(self.handle, &stat));
@@ -359,7 +374,7 @@ pub const File = struct {
Unexpected,
};
- pub fn read(self: *File, buffer: []u8) ReadError!usize {
+ pub fn read(self: File, buffer: []u8) ReadError!usize {
if (is_posix) {
var index: usize = 0;
while (index < buffer.len) {
@@ -407,7 +422,7 @@ pub const File = struct {
pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
- pub fn write(self: *File, bytes: []const u8) WriteError!void {
+ pub fn write(self: File, bytes: []const u8) WriteError!void {
if (is_posix) {
try os.posixWrite(self.handle, bytes);
} else if (is_windows) {
diff --git a/std/os/index.zig b/std/os/index.zig
@@ -57,6 +57,7 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;
pub const windowsWrite = windows_util.windowsWrite;
pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
pub const windowsOpen = windows_util.windowsOpen;
+pub const windowsOpenW = windows_util.windowsOpenW;
pub const windowsLoadDll = windows_util.windowsLoadDll;
pub const windowsUnloadDll = windows_util.windowsUnloadDll;
pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
@@ -660,6 +661,7 @@ pub fn getBaseAddress() usize {
return phdr - @sizeOf(ElfHeader);
},
builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),
+ builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
else => @compileError("Unsupported OS"),
}
}
@@ -2068,7 +2070,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons
}
// TODO make this a build variable that you can set
-const unexpected_error_tracing = false;
+const unexpected_error_tracing = true;
const UnexpectedError = error{
/// The Operating System returned an undocumented error code.
Unexpected,
@@ -2087,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
/// Call this when you made a windows DLL call or something that does SetLastError
/// and you get an unexpected error.
pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
- if (true) {
+ if (unexpected_error_tracing) {
debug.warn("unexpected GetLastError(): {}\n", err);
+ @breakpoint();
debug.dumpCurrentStackTrace(null);
}
return error.Unexpected;
@@ -2103,15 +2106,33 @@ pub fn openSelfExe() !os.File {
buf[self_exe_path.len] = 0;
return os.File.openReadC(self_exe_path.ptr);
},
+ Os.windows => {
+ var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
+ const wide_slice = try selfExePathW(&buf);
+ return os.File.openReadW(wide_slice.ptr);
+ },
else => @compileError("Unsupported OS"),
}
}
test "openSelfExe" {
switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios => (try openSelfExe()).close(),
- else => return error.SkipZigTest, // Unsupported OS
+ Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(),
+ else => return error.SkipZigTest, // Unsupported OS.
+ }
+}
+
+pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
+ const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
+ const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
+ assert(rc <= out_buffer.len);
+ if (rc == 0) {
+ const err = windows.GetLastError();
+ switch (err) {
+ else => return unexpectedErrorWindows(err),
+ }
}
+ return out_buffer[0..rc];
}
/// Get the path to the current executable.
@@ -2129,16 +2150,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
Os.linux => return readLink(out_buffer, "/proc/self/exe"),
Os.windows => {
var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
- const rc = windows.GetModuleFileNameW(null, &utf16le_buf, casted_len);
- assert(rc <= utf16le_buf.len);
- if (rc == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
- const utf16le_slice = utf16le_buf[0..rc];
+ const utf16le_slice = try selfExePathW(&utf16le_buf);
// Trust that Windows gives us valid UTF-16LE.
const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
return out_buffer[0..end_index];
diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig
@@ -3,6 +3,7 @@ const assert = std.debug.assert;
pub use @import("advapi32.zig");
pub use @import("kernel32.zig");
+pub use @import("ntdll.zig");
pub use @import("ole32.zig");
pub use @import("shell32.zig");
pub use @import("shlwapi.zig");
@@ -14,6 +15,7 @@ test "import" {
pub const ERROR = @import("error.zig");
+pub const SHORT = c_short;
pub const BOOL = c_int;
pub const BOOLEAN = BYTE;
pub const BYTE = u8;
@@ -363,3 +365,15 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
+
+pub const SMALL_RECT = extern struct {
+ Left: SHORT,
+ Top: SHORT,
+ Right: SHORT,
+ Bottom: SHORT,
+};
+
+pub const COORD = extern struct {
+ X: SHORT,
+ Y: SHORT,
+};
diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig
@@ -72,6 +72,8 @@ pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
+pub extern "kernel32" stdcallcc fn GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) BOOL;
+
pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD;
pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;
@@ -92,6 +94,8 @@ pub extern "kernel32" stdcallcc fn GetFileAttributesW(lpFileName: [*]const WCHAR
pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD;
pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD;
+pub extern "kernel32" stdcallcc fn GetModuleHandleW(lpModuleName: ?[*]const WCHAR) HMODULE;
+
pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
@@ -177,6 +181,8 @@ pub extern "kernel32" stdcallcc fn ReadFile(
pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
+pub extern "kernel32" stdcallcc fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) BOOL;
+
pub extern "kernel32" stdcallcc fn SetFilePointerEx(
in_fFile: HANDLE,
in_liDistanceToMove: LARGE_INTEGER,
@@ -232,3 +238,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
+
+
+pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
+ dwSize: COORD,
+ dwCursorPosition: COORD,
+ wAttributes: WORD,
+ srWindow: SMALL_RECT,
+ dwMaximumWindowSize: COORD,
+};
+
+pub const FOREGROUND_BLUE = 1;
+pub const FOREGROUND_GREEN = 2;
+pub const FOREGROUND_RED = 4;
+pub const FOREGROUND_INTENSITY = 8;
diff --git a/std/os/windows/ntdll.zig b/std/os/windows/ntdll.zig
@@ -0,0 +1,3 @@
+use @import("index.zig");
+
+pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig
@@ -118,16 +118,14 @@ pub const OpenError = error{
Unexpected,
};
-pub fn windowsOpen(
- file_path: []const u8,
+pub fn windowsOpenW(
+ file_path_w: [*]const u16,
desired_access: windows.DWORD,
share_mode: windows.DWORD,
creation_disposition: windows.DWORD,
flags_and_attrs: windows.DWORD,
) OpenError!windows.HANDLE {
- const file_path_w = try sliceToPrefixedFileW(file_path);
-
- const result = windows.CreateFileW(&file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
+ const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
if (result == windows.INVALID_HANDLE_VALUE) {
const err = windows.GetLastError();
@@ -146,6 +144,17 @@ pub fn windowsOpen(
return result;
}
+pub fn windowsOpen(
+ file_path: []const u8,
+ desired_access: windows.DWORD,
+ share_mode: windows.DWORD,
+ creation_disposition: windows.DWORD,
+ flags_and_attrs: windows.DWORD,
+) OpenError!windows.HANDLE {
+ const file_path_w = try sliceToPrefixedFileW(file_path);
+ return windowsOpenW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
+}
+
/// Caller must free result.
pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 {
// count bytes needed
diff --git a/std/pdb.zig b/std/pdb.zig
@@ -0,0 +1,646 @@
+const builtin = @import("builtin");
+const std = @import("index.zig");
+const io = std.io;
+const math = std.math;
+const mem = std.mem;
+const os = std.os;
+const warn = std.debug.warn;
+const coff = std.coff;
+
+const ArrayList = std.ArrayList;
+
+// https://llvm.org/docs/PDB/DbiStream.html#stream-header
+pub const DbiStreamHeader = packed struct {
+ VersionSignature: i32,
+ VersionHeader: u32,
+ Age: u32,
+ GlobalStreamIndex: u16,
+ BuildNumber: u16,
+ PublicStreamIndex: u16,
+ PdbDllVersion: u16,
+ SymRecordStream: u16,
+ PdbDllRbld: u16,
+ ModInfoSize: u32,
+ SectionContributionSize: u32,
+ SectionMapSize: u32,
+ SourceInfoSize: i32,
+ TypeServerSize: i32,
+ MFCTypeServerIndex: u32,
+ OptionalDbgHeaderSize: i32,
+ ECSubstreamSize: i32,
+ Flags: u16,
+ Machine: u16,
+ Padding: u32,
+};
+
+pub const SectionContribEntry = packed struct {
+ Section: u16,
+ Padding1: [2]u8,
+ Offset: u32,
+ Size: u32,
+ Characteristics: u32,
+ ModuleIndex: u16,
+ Padding2: [2]u8,
+ DataCrc: u32,
+ RelocCrc: u32,
+};
+
+pub const ModInfo = packed struct {
+ Unused1: u32,
+ SectionContr: SectionContribEntry,
+ Flags: u16,
+ ModuleSymStream: u16,
+ SymByteSize: u32,
+ C11ByteSize: u32,
+ C13ByteSize: u32,
+ SourceFileCount: u16,
+ Padding: [2]u8,
+ Unused2: u32,
+ SourceFileNameIndex: u32,
+ PdbFilePathNameIndex: u32,
+ // These fields are variable length
+ //ModuleName: char[],
+ //ObjFileName: char[],
+};
+
+pub const SectionMapHeader = packed struct {
+ Count: u16, /// Number of segment descriptors
+ LogCount: u16, /// Number of logical segment descriptors
+};
+
+pub const SectionMapEntry = packed struct {
+ Flags: u16 , /// See the SectionMapEntryFlags enum below.
+ Ovl: u16 , /// Logical overlay number
+ Group: u16 , /// Group index into descriptor array.
+ Frame: u16 ,
+ SectionName: u16 , /// Byte index of segment / group name in string table, or 0xFFFF.
+ ClassName: u16 , /// Byte index of class in string table, or 0xFFFF.
+ Offset: u32 , /// Byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group.
+ SectionLength: u32 , /// Byte count of the segment or group.
+};
+
+pub const StreamType = enum(u16) {
+ Pdb = 1,
+ Tpi = 2,
+ Dbi = 3,
+ Ipi = 4,
+};
+
+/// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful
+/// for reference purposes and when dealing with unknown record types.
+pub const SymbolKind = packed enum(u16) {
+ S_COMPILE = 1,
+ S_REGISTER_16t = 2,
+ S_CONSTANT_16t = 3,
+ S_UDT_16t = 4,
+ S_SSEARCH = 5,
+ S_SKIP = 7,
+ S_CVRESERVE = 8,
+ S_OBJNAME_ST = 9,
+ S_ENDARG = 10,
+ S_COBOLUDT_16t = 11,
+ S_MANYREG_16t = 12,
+ S_RETURN = 13,
+ S_ENTRYTHIS = 14,
+ S_BPREL16 = 256,
+ S_LDATA16 = 257,
+ S_GDATA16 = 258,
+ S_PUB16 = 259,
+ S_LPROC16 = 260,
+ S_GPROC16 = 261,
+ S_THUNK16 = 262,
+ S_BLOCK16 = 263,
+ S_WITH16 = 264,
+ S_LABEL16 = 265,
+ S_CEXMODEL16 = 266,
+ S_VFTABLE16 = 267,
+ S_REGREL16 = 268,
+ S_BPREL32_16t = 512,
+ S_LDATA32_16t = 513,
+ S_GDATA32_16t = 514,
+ S_PUB32_16t = 515,
+ S_LPROC32_16t = 516,
+ S_GPROC32_16t = 517,
+ S_THUNK32_ST = 518,
+ S_BLOCK32_ST = 519,
+ S_WITH32_ST = 520,
+ S_LABEL32_ST = 521,
+ S_CEXMODEL32 = 522,
+ S_VFTABLE32_16t = 523,
+ S_REGREL32_16t = 524,
+ S_LTHREAD32_16t = 525,
+ S_GTHREAD32_16t = 526,
+ S_SLINK32 = 527,
+ S_LPROCMIPS_16t = 768,
+ S_GPROCMIPS_16t = 769,
+ S_PROCREF_ST = 1024,
+ S_DATAREF_ST = 1025,
+ S_ALIGN = 1026,
+ S_LPROCREF_ST = 1027,
+ S_OEM = 1028,
+ S_TI16_MAX = 4096,
+ S_REGISTER_ST = 4097,
+ S_CONSTANT_ST = 4098,
+ S_UDT_ST = 4099,
+ S_COBOLUDT_ST = 4100,
+ S_MANYREG_ST = 4101,
+ S_BPREL32_ST = 4102,
+ S_LDATA32_ST = 4103,
+ S_GDATA32_ST = 4104,
+ S_PUB32_ST = 4105,
+ S_LPROC32_ST = 4106,
+ S_GPROC32_ST = 4107,
+ S_VFTABLE32 = 4108,
+ S_REGREL32_ST = 4109,
+ S_LTHREAD32_ST = 4110,
+ S_GTHREAD32_ST = 4111,
+ S_LPROCMIPS_ST = 4112,
+ S_GPROCMIPS_ST = 4113,
+ S_COMPILE2_ST = 4115,
+ S_MANYREG2_ST = 4116,
+ S_LPROCIA64_ST = 4117,
+ S_GPROCIA64_ST = 4118,
+ S_LOCALSLOT_ST = 4119,
+ S_PARAMSLOT_ST = 4120,
+ S_ANNOTATION = 4121,
+ S_GMANPROC_ST = 4122,
+ S_LMANPROC_ST = 4123,
+ S_RESERVED1 = 4124,
+ S_RESERVED2 = 4125,
+ S_RESERVED3 = 4126,
+ S_RESERVED4 = 4127,
+ S_LMANDATA_ST = 4128,
+ S_GMANDATA_ST = 4129,
+ S_MANFRAMEREL_ST = 4130,
+ S_MANREGISTER_ST = 4131,
+ S_MANSLOT_ST = 4132,
+ S_MANMANYREG_ST = 4133,
+ S_MANREGREL_ST = 4134,
+ S_MANMANYREG2_ST = 4135,
+ S_MANTYPREF = 4136,
+ S_UNAMESPACE_ST = 4137,
+ S_ST_MAX = 4352,
+ S_WITH32 = 4356,
+ S_MANYREG = 4362,
+ S_LPROCMIPS = 4372,
+ S_GPROCMIPS = 4373,
+ S_MANYREG2 = 4375,
+ S_LPROCIA64 = 4376,
+ S_GPROCIA64 = 4377,
+ S_LOCALSLOT = 4378,
+ S_PARAMSLOT = 4379,
+ S_MANFRAMEREL = 4382,
+ S_MANREGISTER = 4383,
+ S_MANSLOT = 4384,
+ S_MANMANYREG = 4385,
+ S_MANREGREL = 4386,
+ S_MANMANYREG2 = 4387,
+ S_UNAMESPACE = 4388,
+ S_DATAREF = 4390,
+ S_ANNOTATIONREF = 4392,
+ S_TOKENREF = 4393,
+ S_GMANPROC = 4394,
+ S_LMANPROC = 4395,
+ S_ATTR_FRAMEREL = 4398,
+ S_ATTR_REGISTER = 4399,
+ S_ATTR_REGREL = 4400,
+ S_ATTR_MANYREG = 4401,
+ S_SEPCODE = 4402,
+ S_LOCAL_2005 = 4403,
+ S_DEFRANGE_2005 = 4404,
+ S_DEFRANGE2_2005 = 4405,
+ S_DISCARDED = 4411,
+ S_LPROCMIPS_ID = 4424,
+ S_GPROCMIPS_ID = 4425,
+ S_LPROCIA64_ID = 4426,
+ S_GPROCIA64_ID = 4427,
+ S_DEFRANGE_HLSL = 4432,
+ S_GDATA_HLSL = 4433,
+ S_LDATA_HLSL = 4434,
+ S_LOCAL_DPC_GROUPSHARED = 4436,
+ S_DEFRANGE_DPC_PTR_TAG = 4439,
+ S_DPC_SYM_TAG_MAP = 4440,
+ S_ARMSWITCHTABLE = 4441,
+ S_POGODATA = 4444,
+ S_INLINESITE2 = 4445,
+ S_MOD_TYPEREF = 4447,
+ S_REF_MINIPDB = 4448,
+ S_PDBMAP = 4449,
+ S_GDATA_HLSL32 = 4450,
+ S_LDATA_HLSL32 = 4451,
+ S_GDATA_HLSL32_EX = 4452,
+ S_LDATA_HLSL32_EX = 4453,
+ S_FASTLINK = 4455,
+ S_INLINEES = 4456,
+ S_END = 6,
+ S_INLINESITE_END = 4430,
+ S_PROC_ID_END = 4431,
+ S_THUNK32 = 4354,
+ S_TRAMPOLINE = 4396,
+ S_SECTION = 4406,
+ S_COFFGROUP = 4407,
+ S_EXPORT = 4408,
+ S_LPROC32 = 4367,
+ S_GPROC32 = 4368,
+ S_LPROC32_ID = 4422,
+ S_GPROC32_ID = 4423,
+ S_LPROC32_DPC = 4437,
+ S_LPROC32_DPC_ID = 4438,
+ S_REGISTER = 4358,
+ S_PUB32 = 4366,
+ S_PROCREF = 4389,
+ S_LPROCREF = 4391,
+ S_ENVBLOCK = 4413,
+ S_INLINESITE = 4429,
+ S_LOCAL = 4414,
+ S_DEFRANGE = 4415,
+ S_DEFRANGE_SUBFIELD = 4416,
+ S_DEFRANGE_REGISTER = 4417,
+ S_DEFRANGE_FRAMEPOINTER_REL = 4418,
+ S_DEFRANGE_SUBFIELD_REGISTER = 4419,
+ S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 4420,
+ S_DEFRANGE_REGISTER_REL = 4421,
+ S_BLOCK32 = 4355,
+ S_LABEL32 = 4357,
+ S_OBJNAME = 4353,
+ S_COMPILE2 = 4374,
+ S_COMPILE3 = 4412,
+ S_FRAMEPROC = 4114,
+ S_CALLSITEINFO = 4409,
+ S_FILESTATIC = 4435,
+ S_HEAPALLOCSITE = 4446,
+ S_FRAMECOOKIE = 4410,
+ S_CALLEES = 4442,
+ S_CALLERS = 4443,
+ S_UDT = 4360,
+ S_COBOLUDT = 4361,
+ S_BUILDINFO = 4428,
+ S_BPREL32 = 4363,
+ S_REGREL32 = 4369,
+ S_CONSTANT = 4359,
+ S_MANCONSTANT = 4397,
+ S_LDATA32 = 4364,
+ S_GDATA32 = 4365,
+ S_LMANDATA = 4380,
+ S_GMANDATA = 4381,
+ S_LTHREAD32 = 4370,
+ S_GTHREAD32 = 4371,
+};
+
+pub const TypeIndex = u32;
+
+pub const ProcSym = packed struct {
+ Parent: u32 ,
+ End: u32 ,
+ Next: u32 ,
+ CodeSize: u32 ,
+ DbgStart: u32 ,
+ DbgEnd: u32 ,
+ FunctionType: TypeIndex ,
+ CodeOffset: u32,
+ Segment: u16,
+ Flags: ProcSymFlags,
+ // following is a null terminated string
+ // Name: [*]u8,
+};
+
+pub const ProcSymFlags = packed struct {
+ HasFP: bool,
+ HasIRET: bool,
+ HasFRET: bool,
+ IsNoReturn: bool,
+ IsUnreachable: bool,
+ HasCustomCallingConv: bool,
+ IsNoInline: bool,
+ HasOptimizedDebugInfo: bool,
+};
+
+pub const SectionContrSubstreamVersion = enum(u32) {
+ Ver60 = 0xeffe0000 + 19970605,
+ V2 = 0xeffe0000 + 20140516
+};
+
+pub const RecordPrefix = packed struct {
+ RecordLen: u16, /// Record length, starting from &RecordKind.
+ RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind)
+};
+
+pub const LineFragmentHeader = packed struct {
+ RelocOffset: u32, /// Code offset of line contribution.
+ RelocSegment: u16, /// Code segment of line contribution.
+ Flags: LineFlags,
+ CodeSize: u32, /// Code size of this line contribution.
+};
+
+pub const LineFlags = packed struct {
+ LF_HaveColumns: bool, /// CV_LINES_HAVE_COLUMNS
+ unused: u15,
+};
+
+/// The following two variable length arrays appear immediately after the
+/// header. The structure definitions follow.
+/// LineNumberEntry Lines[NumLines];
+/// ColumnNumberEntry Columns[NumLines];
+pub const LineBlockFragmentHeader = packed struct {
+ /// Offset of FileChecksum entry in File
+ /// checksums buffer. The checksum entry then
+ /// contains another offset into the string
+ /// table of the actual name.
+ NameIndex: u32,
+ NumLines: u32,
+ BlockSize: u32, /// code size of block, in bytes
+};
+
+
+pub const LineNumberEntry = packed struct {
+ Offset: u32, /// Offset to start of code bytes for line number
+ Flags: u32,
+
+ /// TODO runtime crash when I make the actual type of Flags this
+ const Flags = packed struct {
+ Start: u24,
+ End: u7,
+ IsStatement: bool,
+ };
+};
+
+pub const ColumnNumberEntry = packed struct {
+ StartColumn: u16,
+ EndColumn: u16,
+};
+
+/// Checksum bytes follow.
+pub const FileChecksumEntryHeader = packed struct {
+ FileNameOffset: u32, /// Byte offset of filename in global string table.
+ ChecksumSize: u8, /// Number of bytes of checksum.
+ ChecksumKind: u8, /// FileChecksumKind
+};
+
+pub const DebugSubsectionKind = packed enum(u32) {
+ None = 0,
+ Symbols = 0xf1,
+ Lines = 0xf2,
+ StringTable = 0xf3,
+ FileChecksums = 0xf4,
+ FrameData = 0xf5,
+ InlineeLines = 0xf6,
+ CrossScopeImports = 0xf7,
+ CrossScopeExports = 0xf8,
+
+ // These appear to relate to .Net assembly info.
+ ILLines = 0xf9,
+ FuncMDTokenMap = 0xfa,
+ TypeMDTokenMap = 0xfb,
+ MergedAssemblyInput = 0xfc,
+
+ CoffSymbolRVA = 0xfd,
+};
+
+
+pub const DebugSubsectionHeader = packed struct {
+ Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum
+ Length: u32, /// number of bytes occupied by this record.
+};
+
+
+pub const PDBStringTableHeader = packed struct {
+ Signature: u32, /// PDBStringTableSignature
+ HashVersion: u32, /// 1 or 2
+ ByteSize: u32, /// Number of bytes of names buffer.
+};
+
+pub const Pdb = struct {
+ in_file: os.File,
+ allocator: *mem.Allocator,
+ coff: *coff.Coff,
+ string_table: *MsfStream,
+ dbi: *MsfStream,
+
+ msf: Msf,
+
+ pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {
+ self.in_file = try os.File.openRead(file_name);
+ self.allocator = coff_ptr.allocator;
+ self.coff = coff_ptr;
+
+ try self.msf.openFile(self.allocator, self.in_file);
+ }
+
+ pub fn getStreamById(self: *Pdb, id: u32) ?*MsfStream {
+ if (id >= self.msf.streams.len)
+ return null;
+ return &self.msf.streams[id];
+ }
+
+ pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream {
+ const id = @enumToInt(stream);
+ return self.getStreamById(id);
+ }
+};
+
+// see https://llvm.org/docs/PDB/MsfFile.html
+const Msf = struct {
+ directory: MsfStream,
+ streams: []MsfStream,
+
+ fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {
+ var file_stream = io.FileInStream.init(file);
+ const in = &file_stream.stream;
+
+ var superblock: SuperBlock = undefined;
+ try in.readStruct(SuperBlock, &superblock);
+
+ if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
+ return error.InvalidDebugInfo;
+
+ switch (superblock.BlockSize) {
+ // llvm only supports 4096 but we can handle any of these values
+ 512, 1024, 2048, 4096 => {},
+ else => return error.InvalidDebugInfo
+ }
+
+ if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
+ return error.InvalidDebugInfo;
+
+ self.directory = try MsfStream.init(
+ superblock.BlockSize,
+ blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
+ superblock.BlockSize * superblock.BlockMapAddr,
+ file,
+ allocator,
+ );
+
+ const stream_count = try self.directory.stream.readIntLe(u32);
+
+ const stream_sizes = try allocator.alloc(u32, stream_count);
+ for (stream_sizes) |*s| {
+ const size = try self.directory.stream.readIntLe(u32);
+ s.* = blockCountFromSize(size, superblock.BlockSize);
+ }
+
+ self.streams = try allocator.alloc(MsfStream, stream_count);
+ for (self.streams) |*stream, i| {
+ stream.* = try MsfStream.init(
+ superblock.BlockSize,
+ stream_sizes[i],
+ // MsfStream.init expects the file to be at the part where it reads [N]u32
+ try file.getPos(),
+ file,
+ allocator,
+ );
+ }
+ }
+};
+
+fn blockCountFromSize(size: u32, block_size: u32) u32 {
+ return (size + block_size - 1) / block_size;
+}
+
+// https://llvm.org/docs/PDB/MsfFile.html#the-superblock
+const SuperBlock = packed struct {
+ /// The LLVM docs list a space between C / C++ but empirically this is not the case.
+ const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00";
+
+ FileMagic: [file_magic.len]u8,
+
+ /// The block size of the internal file system. Valid values are 512, 1024,
+ /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending
+ /// on the block sizes. For the purposes of LLVM, we handle only block sizes of
+ /// 4KiB, and all further discussion assumes a block size of 4KiB.
+ BlockSize: u32,
+
+ /// The index of a block within the file, at which begins a bitfield representing
+ /// the set of all blocks within the file which are “free” (i.e. the data within
+ /// that block is not used). See The Free Block Map for more information. Important:
+ /// FreeBlockMapBlock can only be 1 or 2!
+ FreeBlockMapBlock: u32,
+
+ /// The total number of blocks in the file. NumBlocks * BlockSize should equal the
+ /// size of the file on disk.
+ NumBlocks: u32,
+
+ /// The size of the stream directory, in bytes. The stream directory contains
+ /// information about each stream’s size and the set of blocks that it occupies.
+ /// It will be described in more detail later.
+ NumDirectoryBytes: u32,
+
+ Unknown: u32,
+
+ /// The index of a block within the MSF file. At this block is an array of
+ /// ulittle32_t’s listing the blocks that the stream directory resides on.
+ /// For large MSF files, the stream directory (which describes the block
+ /// layout of each stream) may not fit entirely on a single block. As a
+ /// result, this extra layer of indirection is introduced, whereby this
+ /// block contains the list of blocks that the stream directory occupies,
+ /// and the stream directory itself can be stitched together accordingly.
+ /// The number of ulittle32_t’s in this array is given by
+ /// ceil(NumDirectoryBytes / BlockSize).
+ BlockMapAddr: u32,
+
+};
+
+const MsfStream = struct {
+ in_file: os.File,
+ pos: usize,
+ blocks: []u32,
+ block_size: u32,
+
+ /// Implementation of InStream trait for Pdb.MsfStream
+ stream: Stream,
+
+ pub const Error = @typeOf(read).ReturnType.ErrorSet;
+ pub const Stream = io.InStream(Error);
+
+ fn init(block_size: u32, block_count: u32, pos: usize, file: os.File, allocator: *mem.Allocator) !MsfStream {
+ var stream = MsfStream {
+ .in_file = file,
+ .pos = 0,
+ .blocks = try allocator.alloc(u32, block_count),
+ .block_size = block_size,
+ .stream = Stream {
+ .readFn = readFn,
+ },
+ };
+
+ var file_stream = io.FileInStream.init(file);
+ const in = &file_stream.stream;
+ try file.seekTo(pos);
+
+ var i: u32 = 0;
+ while (i < block_count) : (i += 1) {
+ stream.blocks[i] = try in.readIntLe(u32);
+ }
+
+ return stream;
+ }
+
+ fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
+ var list = ArrayList(u8).init(allocator);
+ defer list.deinit();
+ while (true) {
+ const byte = try self.stream.readByte();
+ if (byte == 0) {
+ return list.toSlice();
+ }
+ try list.append(byte);
+ }
+ }
+
+ fn read(self: *MsfStream, buffer: []u8) !usize {
+ var block_id = self.pos / self.block_size;
+ var block = self.blocks[block_id];
+ var offset = self.pos % self.block_size;
+
+ try self.in_file.seekTo(block * self.block_size + offset);
+ var file_stream = io.FileInStream.init(self.in_file);
+ const in = &file_stream.stream;
+
+ var size: usize = 0;
+ for (buffer) |*byte| {
+ byte.* = try in.readByte();
+
+ offset += 1;
+ size += 1;
+
+ // If we're at the end of a block, go to the next one.
+ if (offset == self.block_size) {
+ offset = 0;
+ block_id += 1;
+ block = self.blocks[block_id];
+ try self.in_file.seekTo(block * self.block_size);
+ }
+ }
+
+ self.pos += size;
+ return size;
+ }
+
+ fn seekForward(self: *MsfStream, len: usize) !void {
+ self.pos += len;
+ if (self.pos >= self.blocks.len * self.block_size)
+ return error.EOF;
+ }
+
+ fn seekTo(self: *MsfStream, len: usize) !void {
+ self.pos = len;
+ if (self.pos >= self.blocks.len * self.block_size)
+ return error.EOF;
+ }
+
+ fn getSize(self: *const MsfStream) usize {
+ return self.blocks.len * self.block_size;
+ }
+
+ fn getFilePos(self: MsfStream) usize {
+ const block_id = self.pos / self.block_size;
+ const block = self.blocks[block_id];
+ const offset = self.pos % self.block_size;
+
+ return block * self.block_size + offset;
+ }
+
+ fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
+ const self = @fieldParentPtr(MsfStream, "stream", in_stream);
+ return self.read(buffer);
+ }
+};
diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig
@@ -49,14 +49,14 @@ pub fn main() !void {
var stderr_file = io.getStdErr();
var stderr_file_stream: io.FileOutStream = undefined;
- var stderr_stream = if (stderr_file) |*f| x: {
+ var stderr_stream = if (stderr_file) |f| x: {
stderr_file_stream = io.FileOutStream.init(f);
break :x &stderr_file_stream.stream;
} else |err| err;
var stdout_file = io.getStdOut();
var stdout_file_stream: io.FileOutStream = undefined;
- var stdout_stream = if (stdout_file) |*f| x: {
+ var stdout_stream = if (stdout_file) |f| x: {
stdout_file_stream = io.FileOutStream.init(f);
break :x &stdout_file_stream.stream;
} else |err| err;
diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig
@@ -1865,7 +1865,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
var stderr_file = try io.getStdErr();
- var stderr = &io.FileOutStream.init(&stderr_file).stream;
+ var stderr = &io.FileOutStream.init(stderr_file).stream;
var tree = try std.zig.parse(allocator, source);
defer tree.deinit();
diff --git a/test/compare_output.zig b/test/compare_output.zig
@@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn main() void {
\\ privateFunction();
- \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
+ \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
\\ stdout.print("OK 2\n") catch unreachable;
\\}
\\
@@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\// purposefully conflicting function with main.zig
\\// but it's private so it should be OK
\\fn privateFunction() void {
- \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
+ \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
\\ stdout.print("OK 1\n") catch unreachable;
\\}
\\
@@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
tc.addSourceFile("foo.zig",
\\use @import("std").io;
\\pub fn foo_function() void {
- \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
+ \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
\\ stdout.print("OK\n") catch unreachable;
\\}
);
@@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn bar_function() void {
\\ if (foo_function()) {
- \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
+ \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
\\ stdout.print("OK\n") catch unreachable;
\\ }
\\}
@@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub const a_text = "OK\n";
\\
\\pub fn ok() void {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print(b_text) catch unreachable;
\\}
);
@@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\
\\pub fn main() void {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
\\}
, "Hello, world!\n0012 012 a\n");
@@ -274,7 +274,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ var x_local : i32 = print_ok(x);
\\}
\\fn print_ok(val: @typeOf(x)) @typeOf(foo) {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print("OK\n") catch unreachable;
\\ return 0;
\\}
@@ -356,7 +356,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub fn main() void {
\\ const bar = Bar {.field2 = 13,};
\\ const foo = Foo {.field1 = bar,};
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ if (!foo.method()) {
\\ stdout.print("BAD\n") catch unreachable;
\\ }
@@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.add("defer with only fallthrough",
\\const io = @import("std").io;
\\pub fn main() void {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ defer stdout.print("defer2\n") catch unreachable;
@@ -383,7 +383,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\const os = @import("std").os;
\\pub fn main() void {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ defer stdout.print("defer2\n") catch unreachable;
@@ -400,7 +400,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ errdefer stdout.print("deferErr\n") catch unreachable;
@@ -419,7 +419,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ errdefer stdout.print("deferErr\n") catch unreachable;
@@ -436,7 +436,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\
\\pub fn main() void {
- \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
+ \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
\\ stdout.print(foo_txt) catch unreachable;
\\}
, "1234\nabcd\n");
@@ -456,7 +456,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub fn main() !void {
\\ var args_it = os.args();
\\ var stdout_file = try io.getStdOut();
- \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
+ \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
\\ const stdout = &stdout_adapter.stream;
\\ var index: usize = 0;
\\ _ = args_it.skip();
@@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub fn main() !void {
\\ var args_it = os.args();
\\ var stdout_file = try io.getStdOut();
- \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
+ \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
\\ const stdout = &stdout_adapter.stream;
\\ var index: usize = 0;
\\ _ = args_it.skip();
diff --git a/test/tests.zig b/test/tests.zig
@@ -263,8 +263,8 @@ pub const CompareOutputContext = struct {
var stdout = Buffer.initNull(b.allocator);
var stderr = Buffer.initNull(b.allocator);
- var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
- var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
+ var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
+ var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
@@ -578,8 +578,8 @@ pub const CompileErrorContext = struct {
var stdout_buf = Buffer.initNull(b.allocator);
var stderr_buf = Buffer.initNull(b.allocator);
- var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
- var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
+ var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
+ var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
@@ -842,8 +842,8 @@ pub const TranslateCContext = struct {
var stdout_buf = Buffer.initNull(b.allocator);
var stderr_buf = Buffer.initNull(b.allocator);
- var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
- var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
+ var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
+ var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;