authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-02 18:47:48-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-09-02 18:47:48-04:00
logab387bb4c712b257cc2b728a044ad67935dee2dc
treeaa6ae0b006da48dba434fcf5eaa8550134772563
parent86e55567b4b1cccbb69065396391e4a500864dce
parent832caefc2a1b20deb513d43306d6723670ba9c8f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #1460 from ziglang/Sahnvour-windows-coff-issue721

Stack traces for Windows

25 files changed, 1556 insertions(+), 126 deletions(-)

CMakeLists.txt+3
...@@ -444,6 +444,7 @@ set(ZIG_STD_FILES...@@ -444,6 +444,7 @@ set(ZIG_STD_FILES
444 "c/index.zig"444 "c/index.zig"
445 "c/linux.zig"445 "c/linux.zig"
446 "c/windows.zig"446 "c/windows.zig"
447 "coff.zig"
447 "crypto/blake2.zig"448 "crypto/blake2.zig"
448 "crypto/hmac.zig"449 "crypto/hmac.zig"
449 "crypto/index.zig"450 "crypto/index.zig"
...@@ -577,12 +578,14 @@ set(ZIG_STD_FILES...@@ -577,12 +578,14 @@ set(ZIG_STD_FILES
577 "os/windows/error.zig"578 "os/windows/error.zig"
578 "os/windows/index.zig"579 "os/windows/index.zig"
579 "os/windows/kernel32.zig"580 "os/windows/kernel32.zig"
581 "os/windows/ntdll.zig"
580 "os/windows/ole32.zig"582 "os/windows/ole32.zig"
581 "os/windows/shell32.zig"583 "os/windows/shell32.zig"
582 "os/windows/shlwapi.zig"584 "os/windows/shlwapi.zig"
583 "os/windows/user32.zig"585 "os/windows/user32.zig"
584 "os/windows/util.zig"586 "os/windows/util.zig"
585 "os/zen.zig"587 "os/zen.zig"
588 "pdb.zig"
586 "rand/index.zig"589 "rand/index.zig"
587 "rand/ziggurat.zig"590 "rand/ziggurat.zig"
588 "segmented_list.zig"591 "segmented_list.zig"
doc/docgen.zig+2-2
...@@ -40,11 +40,11 @@ pub fn main() !void {...@@ -40,11 +40,11 @@ pub fn main() !void {
40 var out_file = try os.File.openWrite(out_file_name);40 var out_file = try os.File.openWrite(out_file_name);
41 defer out_file.close();41 defer out_file.close();
4242
43 var file_in_stream = io.FileInStream.init(&in_file);43 var file_in_stream = io.FileInStream.init(in_file);
4444
45 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);45 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
4646
47 var file_out_stream = io.FileOutStream.init(&out_file);47 var file_out_stream = io.FileOutStream.init(out_file);
48 var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);48 var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
4949
50 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);50 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
example/guess_number/main.zig+1-1
...@@ -6,7 +6,7 @@ const os = std.os;...@@ -6,7 +6,7 @@ const os = std.os;
66
7pub fn main() !void {7pub fn main() !void {
8 var stdout_file = try io.getStdOut();8 var stdout_file = try io.getStdOut();
9 var stdout_file_stream = io.FileOutStream.init(&stdout_file);9 var stdout_file_stream = io.FileOutStream.init(stdout_file);
10 const stdout = &stdout_file_stream.stream;10 const stdout = &stdout_file_stream.stream;
1111
12 try stdout.print("Welcome to the Guess Number Game in Zig.\n");12 try stdout.print("Welcome to the Guess Number Game in Zig.\n");
src-self-hosted/errmsg.zig+1-1
...@@ -272,7 +272,7 @@ pub const Msg = struct {...@@ -272,7 +272,7 @@ pub const Msg = struct {
272 try stream.write("\n");272 try stream.write("\n");
273 }273 }
274274
275 pub fn printToFile(msg: *const Msg, file: *os.File, color: Color) !void {275 pub fn printToFile(msg: *const Msg, file: os.File, color: Color) !void {
276 const color_on = switch (color) {276 const color_on = switch (color) {
277 Color.Auto => file.isTty(),277 Color.Auto => file.isTty(),
278 Color.On => true,278 Color.On => true,
src-self-hosted/main.zig+6-6
...@@ -55,11 +55,11 @@ pub fn main() !void {...@@ -55,11 +55,11 @@ pub fn main() !void {
55 const allocator = std.heap.c_allocator;55 const allocator = std.heap.c_allocator;
5656
57 var stdout_file = try std.io.getStdOut();57 var stdout_file = try std.io.getStdOut();
58 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);58 var stdout_out_stream = std.io.FileOutStream.init(stdout_file);
59 stdout = &stdout_out_stream.stream;59 stdout = &stdout_out_stream.stream;
6060
61 stderr_file = try std.io.getStdErr();61 stderr_file = try std.io.getStdErr();
62 var stderr_out_stream = std.io.FileOutStream.init(&stderr_file);62 var stderr_out_stream = std.io.FileOutStream.init(stderr_file);
63 stderr = &stderr_out_stream.stream;63 stderr = &stderr_out_stream.stream;
6464
65 const args = try os.argsAlloc(allocator);65 const args = try os.argsAlloc(allocator);
...@@ -491,7 +491,7 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {...@@ -491,7 +491,7 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
491 stderr.print("Build {} compile errors:\n", count) catch os.exit(1);491 stderr.print("Build {} compile errors:\n", count) catch os.exit(1);
492 for (msgs) |msg| {492 for (msgs) |msg| {
493 defer msg.destroy();493 defer msg.destroy();
494 msg.printToFile(&stderr_file, color) catch os.exit(1);494 msg.printToFile(stderr_file, color) catch os.exit(1);
495 }495 }
496 },496 },
497 }497 }
...@@ -619,7 +619,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -619,7 +619,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
619 }619 }
620620
621 var stdin_file = try io.getStdIn();621 var stdin_file = try io.getStdIn();
622 var stdin = io.FileInStream.init(&stdin_file);622 var stdin = io.FileInStream.init(stdin_file);
623623
624 const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);624 const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);
625 defer allocator.free(source_code);625 defer allocator.free(source_code);
...@@ -635,7 +635,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -635,7 +635,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
635 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");635 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");
636 defer msg.destroy();636 defer msg.destroy();
637637
638 try msg.printToFile(&stderr_file, color);638 try msg.printToFile(stderr_file, color);
639 }639 }
640 if (tree.errors.len != 0) {640 if (tree.errors.len != 0) {
641 os.exit(1);641 os.exit(1);
...@@ -772,7 +772,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void {...@@ -772,7 +772,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void {
772 const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path);772 const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path);
773 defer fmt.loop.allocator.destroy(msg);773 defer fmt.loop.allocator.destroy(msg);
774774
775 try msg.printToFile(&stderr_file, fmt.color);775 try msg.printToFile(stderr_file, fmt.color);
776 }776 }
777 if (tree.errors.len != 0) {777 if (tree.errors.len != 0) {
778 fmt.any_error = true;778 fmt.any_error = true;
src-self-hosted/test.zig+2-2
...@@ -185,7 +185,7 @@ pub const TestContext = struct {...@@ -185,7 +185,7 @@ pub const TestContext = struct {
185 try stderr.write("build incorrectly failed:\n");185 try stderr.write("build incorrectly failed:\n");
186 for (msgs) |msg| {186 for (msgs) |msg| {
187 defer msg.destroy();187 defer msg.destroy();
188 try msg.printToFile(&stderr, errmsg.Color.Auto);188 try msg.printToFile(stderr, errmsg.Color.Auto);
189 }189 }
190 },190 },
191 }191 }
...@@ -234,7 +234,7 @@ pub const TestContext = struct {...@@ -234,7 +234,7 @@ pub const TestContext = struct {
234 var stderr = try std.io.getStdErr();234 var stderr = try std.io.getStdErr();
235 for (msgs) |msg| {235 for (msgs) |msg| {
236 defer msg.destroy();236 defer msg.destroy();
237 try msg.printToFile(&stderr, errmsg.Color.Auto);237 try msg.printToFile(stderr, errmsg.Color.Auto);
238 }238 }
239 std.debug.warn("============\n");239 std.debug.warn("============\n");
240 return error.TestFailed;240 return error.TestFailed;
std/coff.zig created+230
...@@ -0,0 +1,230 @@
1const builtin = @import("builtin");
2const std = @import("index.zig");
3const io = std.io;
4const mem = std.mem;
5const os = std.os;
6
7const ArrayList = std.ArrayList;
8
9// CoffHeader.machine values
10// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
11const IMAGE_FILE_MACHINE_I386 = 0x014c;
12const IMAGE_FILE_MACHINE_IA64 = 0x0200;
13const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
14
15// OptionalHeader.magic values
16// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
17const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
18const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
19
20const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
21const DEBUG_DIRECTORY = 6;
22
23pub const CoffError = error {
24 InvalidPEMagic,
25 InvalidPEHeader,
26 InvalidMachine,
27 MissingCoffSection,
28};
29
30pub const Coff = struct {
31 in_file: os.File,
32 allocator: *mem.Allocator,
33
34 coff_header: CoffHeader,
35 pe_header: OptionalHeader,
36 sections: ArrayList(Section),
37
38 guid: [16]u8,
39 age: u32,
40
41 pub fn loadHeader(self: *Coff) !void {
42 const pe_pointer_offset = 0x3C;
43
44 var file_stream = io.FileInStream.init(self.in_file);
45 const in = &file_stream.stream;
46
47 var magic: [2]u8 = undefined;
48 try in.readNoEof(magic[0..]);
49 if (!mem.eql(u8, magic, "MZ"))
50 return error.InvalidPEMagic;
51
52 // Seek to PE File Header (coff header)
53 try self.in_file.seekTo(pe_pointer_offset);
54 const pe_magic_offset = try in.readIntLe(u32);
55 try self.in_file.seekTo(pe_magic_offset);
56
57 var pe_header_magic: [4]u8 = undefined;
58 try in.readNoEof(pe_header_magic[0..]);
59 if (!mem.eql(u8, pe_header_magic, []u8{'P', 'E', 0, 0}))
60 return error.InvalidPEHeader;
61
62 self.coff_header = CoffHeader {
63 .machine = try in.readIntLe(u16),
64 .number_of_sections = try in.readIntLe(u16),
65 .timedate_stamp = try in.readIntLe(u32),
66 .pointer_to_symbol_table = try in.readIntLe(u32),
67 .number_of_symbols = try in.readIntLe(u32),
68 .size_of_optional_header = try in.readIntLe(u16),
69 .characteristics = try in.readIntLe(u16),
70 };
71
72 switch (self.coff_header.machine) {
73 IMAGE_FILE_MACHINE_I386,
74 IMAGE_FILE_MACHINE_AMD64,
75 IMAGE_FILE_MACHINE_IA64
76 => {},
77 else => return error.InvalidMachine,
78 }
79
80 try self.loadOptionalHeader(&file_stream);
81 }
82
83 fn loadOptionalHeader(self: *Coff, file_stream: *io.FileInStream) !void {
84 const in = &file_stream.stream;
85 self.pe_header.magic = try in.readIntLe(u16);
86 // For now we're only interested in finding the reference to the .pdb,
87 // so we'll skip most of this header, which size is different in 32
88 // 64 bits by the way.
89 var skip_size: u16 = undefined;
90 if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
91 skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 18 * @sizeOf(u32);
92 }
93 else if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
94 skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 12 * @sizeOf(u32) + 5 * @sizeOf(u64);
95 }
96 else
97 return error.InvalidPEMagic;
98
99 try self.in_file.seekForward(skip_size);
100
101 const number_of_rva_and_sizes = try in.readIntLe(u32);
102 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
103 return error.InvalidPEHeader;
104
105 for (self.pe_header.data_directory) |*data_dir| {
106 data_dir.* = OptionalHeader.DataDirectory {
107 .virtual_address = try in.readIntLe(u32),
108 .size = try in.readIntLe(u32),
109 };
110 }
111 }
112
113 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
114 try self.loadSections();
115 const header = (self.getSection(".rdata") orelse return error.MissingCoffSection).header;
116
117 // The linker puts a chunk that contains the .pdb path right after the
118 // debug_directory.
119 const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
120 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
121 try self.in_file.seekTo(file_offset + debug_dir.size);
122
123 var file_stream = io.FileInStream.init(self.in_file);
124 const in = &file_stream.stream;
125
126 var cv_signature: [4]u8 = undefined; // CodeView signature
127 try in.readNoEof(cv_signature[0..]);
128 // 'RSDS' indicates PDB70 format, used by lld.
129 if (!mem.eql(u8, cv_signature, "RSDS"))
130 return error.InvalidPEMagic;
131 try in.readNoEof(self.guid[0..]);
132 self.age = try in.readIntLe(u32);
133
134 // Finally read the null-terminated string.
135 var byte = try in.readByte();
136 var i: usize = 0;
137 while (byte != 0 and i < buffer.len) : (i += 1) {
138 buffer[i] = byte;
139 byte = try in.readByte();
140 }
141
142 if (byte != 0 and i == buffer.len)
143 return error.NameTooLong;
144
145 return i;
146 }
147
148 pub fn loadSections(self: *Coff) !void {
149 if (self.sections.len != 0)
150 return;
151
152 self.sections = ArrayList(Section).init(self.allocator);
153
154 var file_stream = io.FileInStream.init(self.in_file);
155 const in = &file_stream.stream;
156
157 var name: [8]u8 = undefined;
158
159 var i: u16 = 0;
160 while (i < self.coff_header.number_of_sections) : (i += 1) {
161 try in.readNoEof(name[0..]);
162 try self.sections.append(Section {
163 .header = SectionHeader {
164 .name = name,
165 .misc = SectionHeader.Misc { .physical_address = try in.readIntLe(u32) },
166 .virtual_address = try in.readIntLe(u32),
167 .size_of_raw_data = try in.readIntLe(u32),
168 .pointer_to_raw_data = try in.readIntLe(u32),
169 .pointer_to_relocations = try in.readIntLe(u32),
170 .pointer_to_line_numbers = try in.readIntLe(u32),
171 .number_of_relocations = try in.readIntLe(u16),
172 .number_of_line_numbers = try in.readIntLe(u16),
173 .characteristics = try in.readIntLe(u32),
174 },
175 });
176 }
177 }
178
179 pub fn getSection(self: *Coff, comptime name: []const u8) ?*Section {
180 for (self.sections.toSlice()) |*sec| {
181 if (mem.eql(u8, sec.header.name[0..name.len], name)) {
182 return sec;
183 }
184 }
185 return null;
186 }
187
188};
189
190const CoffHeader = struct {
191 machine: u16,
192 number_of_sections: u16,
193 timedate_stamp: u32,
194 pointer_to_symbol_table: u32,
195 number_of_symbols: u32,
196 size_of_optional_header: u16,
197 characteristics: u16
198};
199
200const OptionalHeader = struct {
201 const DataDirectory = struct {
202 virtual_address: u32,
203 size: u32
204 };
205
206 magic: u16,
207 data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
208};
209
210pub const Section = struct {
211 header: SectionHeader,
212};
213
214const SectionHeader = struct {
215 const Misc = union {
216 physical_address: u32,
217 virtual_size: u32
218 };
219
220 name: [8]u8,
221 misc: Misc,
222 virtual_address: u32,
223 size_of_raw_data: u32,
224 pointer_to_raw_data: u32,
225 pointer_to_relocations: u32,
226 pointer_to_line_numbers: u32,
227 number_of_relocations: u16,
228 number_of_line_numbers: u16,
229 characteristics: u32,
230};
std/debug/index.zig+494-20
...@@ -4,8 +4,11 @@ const mem = std.mem;...@@ -4,8 +4,11 @@ const mem = std.mem;
4const io = std.io;4const io = std.io;
5const os = std.os;5const os = std.os;
6const elf = std.elf;6const elf = std.elf;
7const macho = std.macho;
8const DW = std.dwarf;7const DW = std.dwarf;
8const macho = std.macho;
9const coff = std.coff;
10const pdb = std.pdb;
11const windows = os.windows;
9const ArrayList = std.ArrayList;12const ArrayList = std.ArrayList;
10const builtin = @import("builtin");13const builtin = @import("builtin");
1114
...@@ -17,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {...@@ -17,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {
17 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,20 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
18};21};
1922
23const Module = struct {
24 mod_info: pdb.ModInfo,
25 module_name: []u8,
26 obj_file_name: []u8,
27
28 populated: bool,
29 symbols: []u8,
30 subsect_info: []u8,
31 checksum_offset: ?usize,
32};
33
20/// Tries to write to stderr, unbuffered, and ignores any error returned.34/// Tries to write to stderr, unbuffered, and ignores any error returned.
21/// Does not append a newline.35/// Does not append a newline.
22var stderr_file: os.File = undefined;36var stderr_file: os.File = undefined;
...@@ -37,7 +51,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {...@@ -37,7 +51,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {
37 return st;51 return st;
38 } else {52 } else {
39 stderr_file = try io.getStdErr();53 stderr_file = try io.getStdErr();
40 stderr_file_out_stream = io.FileOutStream.init(&stderr_file);54 stderr_file_out_stream = io.FileOutStream.init(stderr_file);
41 const st = &stderr_file_out_stream.stream;55 const st = &stderr_file_out_stream.stream;
42 stderr_stream = st;56 stderr_stream = st;
43 return st;57 return st;
...@@ -70,7 +84,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -70,7 +84,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
70 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;84 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
71 return;85 return;
72 };86 };
73 writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| {87 writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
74 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;88 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
75 return;89 return;
76 };90 };
...@@ -191,7 +205,11 @@ pub inline fn getReturnAddress(frame_count: usize) usize {...@@ -191,7 +205,11 @@ pub inline fn getReturnAddress(frame_count: usize) usize {
191 return @intToPtr(*const usize, fp + @sizeOf(usize)).*;205 return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
192}206}
193207
194pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {208pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
209 switch (builtin.os) {
210 builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
211 else => {},
212 }
195 const AddressState = union(enum) {213 const AddressState = union(enum) {
196 NotLookingForStartAddress,214 NotLookingForStartAddress,
197 LookingForStartAddress: usize,215 LookingForStartAddress: usize,
...@@ -224,18 +242,296 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_...@@ -224,18 +242,296 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_
224 }242 }
225}243}
226244
245pub fn writeCurrentStackTraceWindows(out_stream: var, debug_info: *DebugInfo,
246 tty_color: bool, start_addr: ?usize) !void
247{
248 var addr_buf: [1024]usize = undefined;
249 const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast
250 const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null);
251 const addrs = addr_buf[0..n];
252 var start_i: usize = if (start_addr) |saddr| blk: {
253 for (addrs) |addr, i| {
254 if (addr == saddr) break :blk i;
255 }
256 return;
257 } else 0;
258 for (addrs[start_i..]) |addr| {
259 try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
260 }
261}
262
227pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {263pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
228 switch (builtin.os) {264 switch (builtin.os) {
229 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),265 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
230 builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),266 builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
231 builtin.Os.windows => {267 builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
232 // TODO https://github.com/ziglang/zig/issues/721
233 return error.UnsupportedOperatingSystem;
234 },
235 else => return error.UnsupportedOperatingSystem,268 else => return error.UnsupportedOperatingSystem,
236 }269 }
237}270}
238271
272fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
273 const allocator = getDebugInfoAllocator();
274 const base_address = os.getBaseAddress();
275 const relative_address = relocated_address - base_address;
276
277 var coff_section: *coff.Section = undefined;
278 const mod_index = for (di.sect_contribs) |sect_contrib| {
279 if (sect_contrib.Section >= di.coff.sections.len) continue;
280 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section];
281
282 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
283 const vaddr_end = vaddr_start + sect_contrib.Size;
284 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
285 break sect_contrib.ModuleIndex;
286 }
287 } else {
288 // we have no information to add to the address
289 if (tty_color) {
290 try out_stream.print("???:?:?: ");
291 setTtyColor(TtyColor.Dim);
292 try out_stream.print("0x{x} in ??? (???)", relocated_address);
293 setTtyColor(TtyColor.Reset);
294 try out_stream.print("\n\n\n");
295 } else {
296 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
297 }
298 return;
299 };
300
301 const mod = &di.modules[mod_index];
302 try populateModule(di, mod);
303 const obj_basename = os.path.basename(mod.obj_file_name);
304
305 var symbol_i: usize = 0;
306 const symbol_name = while (symbol_i != mod.symbols.len) {
307 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
308 if (prefix.RecordLen < 2)
309 return error.InvalidDebugInfo;
310 switch (prefix.RecordKind) {
311 pdb.SymbolKind.S_LPROC32 => {
312 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
313 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
314 const vaddr_end = vaddr_start + proc_sym.CodeSize;
315 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
316 break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
317 }
318 },
319 else => {},
320 }
321 symbol_i += prefix.RecordLen + @sizeOf(u16);
322 if (symbol_i > mod.symbols.len)
323 return error.InvalidDebugInfo;
324 } else "???";
325
326 const subsect_info = mod.subsect_info;
327
328 var sect_offset: usize = 0;
329 var skip_len: usize = undefined;
330 const opt_line_info = subsections: {
331 const checksum_offset = mod.checksum_offset orelse break :subsections null;
332 while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
333 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
334 skip_len = subsect_hdr.Length;
335 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
336
337 switch (subsect_hdr.Kind) {
338 pdb.DebugSubsectionKind.Lines => {
339 var line_index: usize = sect_offset;
340
341 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
342 if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
343 line_index += @sizeOf(pdb.LineFragmentHeader);
344
345 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
346 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
347
348 const has_column = line_hdr.Flags.LF_HaveColumns;
349
350 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
351 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
352 if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
353 var line_i: usize = 0;
354 const start_line_index = line_index;
355 while (line_i < block_hdr.NumLines) : (line_i += 1) {
356 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
357 line_index += @sizeOf(pdb.LineNumberEntry);
358 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
359 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
360 const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End;
361 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
362 const subsect_index = checksum_offset + block_hdr.NameIndex;
363 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
364 const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
365 try di.pdb.string_table.seekTo(strtab_offset);
366 const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
367 const line = flags.Start;
368 const column = if (has_column) blk: {
369 line_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
370 line_index += @sizeOf(pdb.ColumnNumberEntry) * line_i;
371 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[line_index]);
372 break :blk col_num_entry.StartColumn;
373 } else 0;
374 break :subsections LineInfo{
375 .allocator = allocator,
376 .file_name = source_file_name,
377 .line = line,
378 .column = column,
379 };
380 }
381 }
382 break :subsections null;
383 }
384 },
385 else => {},
386 }
387
388 if (sect_offset > subsect_info.len)
389 return error.InvalidDebugInfo;
390 } else {
391 break :subsections null;
392 }
393 };
394
395 if (tty_color) {
396 setTtyColor(TtyColor.White);
397 if (opt_line_info) |li| {
398 try out_stream.print("{}:{}:{}", li.file_name, li.line, li.column);
399 } else {
400 try out_stream.print("???:?:?");
401 }
402 setTtyColor(TtyColor.Reset);
403 try out_stream.print(": ");
404 setTtyColor(TtyColor.Dim);
405 try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
406 setTtyColor(TtyColor.Reset);
407
408 if (opt_line_info) |line_info| {
409 try out_stream.print("\n");
410 if (printLineFromFile(out_stream, line_info)) {
411 if (line_info.column == 0) {
412 try out_stream.write("\n");
413 } else {
414 {
415 var col_i: usize = 1;
416 while (col_i < line_info.column) : (col_i += 1) {
417 try out_stream.writeByte(' ');
418 }
419 }
420 setTtyColor(TtyColor.Green);
421 try out_stream.write("^");
422 setTtyColor(TtyColor.Reset);
423 try out_stream.write("\n");
424 }
425 } else |err| switch (err) {
426 error.EndOfFile => {},
427 else => return err,
428 }
429 } else {
430 try out_stream.print("\n\n\n");
431 }
432 } else {
433 if (opt_line_info) |li| {
434 try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
435 } else {
436 try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
437 }
438 }
439}
440
441const TtyColor = enum{
442 Red,
443 Green,
444 Cyan,
445 White,
446 Dim,
447 Bold,
448 Reset,
449};
450
451/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
452fn setTtyColor(tty_color: TtyColor) void {
453 const S = struct {
454 var attrs: windows.WORD = undefined;
455 var init_attrs = false;
456 };
457 if (!S.init_attrs) {
458 S.init_attrs = true;
459 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
460 // TODO handle error
461 _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
462 S.attrs = info.wAttributes;
463 }
464
465 // TODO handle errors
466 switch (tty_color) {
467 TtyColor.Red => {
468 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED|windows.FOREGROUND_INTENSITY);
469 },
470 TtyColor.Green => {
471 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN|windows.FOREGROUND_INTENSITY);
472 },
473 TtyColor.Cyan => {
474 _ = windows.SetConsoleTextAttribute(stderr_file.handle,
475 windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
476 },
477 TtyColor.White, TtyColor.Bold => {
478 _ = windows.SetConsoleTextAttribute(stderr_file.handle,
479 windows.FOREGROUND_RED|windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
480 },
481 TtyColor.Dim => {
482 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
483 },
484 TtyColor.Reset => {
485 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
486 },
487 }
488}
489
490fn populateModule(di: *DebugInfo, mod: *Module) !void {
491 if (mod.populated)
492 return;
493 const allocator = getDebugInfoAllocator();
494
495 if (mod.mod_info.C11ByteSize != 0)
496 return error.InvalidDebugInfo;
497
498 if (mod.mod_info.C13ByteSize == 0)
499 return error.MissingDebugInfo;
500
501 const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
502
503 const signature = try modi.stream.readIntLe(u32);
504 if (signature != 4)
505 return error.InvalidDebugInfo;
506
507 mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
508 try modi.stream.readNoEof(mod.symbols);
509
510 mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
511 try modi.stream.readNoEof(mod.subsect_info);
512
513 var sect_offset: usize = 0;
514 var skip_len: usize = undefined;
515 while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
516 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
517 skip_len = subsect_hdr.Length;
518 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
519
520 switch (subsect_hdr.Kind) {
521 pdb.DebugSubsectionKind.FileChecksums => {
522 mod.checksum_offset = sect_offset;
523 break;
524 },
525 else => {},
526 }
527
528 if (sect_offset > mod.subsect_info.len)
529 return error.InvalidDebugInfo;
530 }
531
532 mod.populated = true;
533}
534
239fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {535fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
240 var min: usize = 0;536 var min: usize = 0;
241 var max: usize = symbols.len - 1; // Exclude sentinel.537 var max: usize = symbols.len - 1; // Exclude sentinel.
...@@ -372,14 +668,185 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {...@@ -372,14 +668,185 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
372 switch (builtin.os) {668 switch (builtin.os) {
373 builtin.Os.linux => return openSelfDebugInfoLinux(allocator),669 builtin.Os.linux => return openSelfDebugInfoLinux(allocator),
374 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),670 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
375 builtin.Os.windows => {671 builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
376 // TODO: https://github.com/ziglang/zig/issues/721
377 return error.UnsupportedOperatingSystem;
378 },
379 else => return error.UnsupportedOperatingSystem,672 else => return error.UnsupportedOperatingSystem,
380 }673 }
381}674}
382675
676fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
677 const self_file = try os.openSelfExe();
678 defer self_file.close();
679
680 const coff_obj = try allocator.createOne(coff.Coff);
681 coff_obj.* = coff.Coff{
682 .in_file = self_file,
683 .allocator = allocator,
684 .coff_header = undefined,
685 .pe_header = undefined,
686 .sections = undefined,
687 .guid = undefined,
688 .age = undefined,
689 };
690
691 var di = DebugInfo{
692 .coff = coff_obj,
693 .pdb = undefined,
694 .sect_contribs = undefined,
695 .modules = undefined,
696 };
697
698 try di.coff.loadHeader();
699
700 var path_buf: [windows.MAX_PATH]u8 = undefined;
701 const len = try di.coff.getPdbPath(path_buf[0..]);
702 const raw_path = path_buf[0..len];
703
704 const path = try os.path.resolve(allocator, raw_path);
705
706 try di.pdb.openFile(di.coff, path);
707
708 var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
709 const version = try pdb_stream.stream.readIntLe(u32);
710 const signature = try pdb_stream.stream.readIntLe(u32);
711 const age = try pdb_stream.stream.readIntLe(u32);
712 var guid: [16]u8 = undefined;
713 try pdb_stream.stream.readNoEof(guid[0..]);
714 if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
715 return error.InvalidDebugInfo;
716 // We validated the executable and pdb match.
717
718 const string_table_index = str_tab_index: {
719 const name_bytes_len = try pdb_stream.stream.readIntLe(u32);
720 const name_bytes = try allocator.alloc(u8, name_bytes_len);
721 try pdb_stream.stream.readNoEof(name_bytes);
722
723 const HashTableHeader = packed struct {
724 Size: u32,
725 Capacity: u32,
726
727 fn maxLoad(cap: u32) u32 {
728 return cap * 2 / 3 + 1;
729 }
730 };
731 var hash_tbl_hdr: HashTableHeader = undefined;
732 try pdb_stream.stream.readStruct(HashTableHeader, &hash_tbl_hdr);
733 if (hash_tbl_hdr.Capacity == 0)
734 return error.InvalidDebugInfo;
735
736 if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
737 return error.InvalidDebugInfo;
738
739 const present = try readSparseBitVector(&pdb_stream.stream, allocator);
740 if (present.len != hash_tbl_hdr.Size)
741 return error.InvalidDebugInfo;
742 const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
743
744 const Bucket = struct {
745 first: u32,
746 second: u32,
747 };
748 const bucket_list = try allocator.alloc(Bucket, present.len);
749 for (present) |_| {
750 const name_offset = try pdb_stream.stream.readIntLe(u32);
751 const name_index = try pdb_stream.stream.readIntLe(u32);
752 const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
753 if (mem.eql(u8, name, "/names")) {
754 break :str_tab_index name_index;
755 }
756 }
757 return error.MissingDebugInfo;
758 };
759
760 di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
761 di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
762
763 const dbi = di.pdb.dbi;
764
765 // Dbi Header
766 var dbi_stream_header: pdb.DbiStreamHeader = undefined;
767 try dbi.stream.readStruct(pdb.DbiStreamHeader, &dbi_stream_header);
768 const mod_info_size = dbi_stream_header.ModInfoSize;
769 const section_contrib_size = dbi_stream_header.SectionContributionSize;
770
771 var modules = ArrayList(Module).init(allocator);
772
773 // Module Info Substream
774 var mod_info_offset: usize = 0;
775 while (mod_info_offset != mod_info_size) {
776 var mod_info: pdb.ModInfo = undefined;
777 try dbi.stream.readStruct(pdb.ModInfo, &mod_info);
778 var this_record_len: usize = @sizeOf(pdb.ModInfo);
779
780 const module_name = try dbi.readNullTermString(allocator);
781 this_record_len += module_name.len + 1;
782
783 const obj_file_name = try dbi.readNullTermString(allocator);
784 this_record_len += obj_file_name.len + 1;
785
786 const march_forward_bytes = this_record_len % 4;
787 if (march_forward_bytes != 0) {
788 try dbi.seekForward(march_forward_bytes);
789 this_record_len += march_forward_bytes;
790 }
791
792 try modules.append(Module{
793 .mod_info = mod_info,
794 .module_name = module_name,
795 .obj_file_name = obj_file_name,
796
797 .populated = false,
798 .symbols = undefined,
799 .subsect_info = undefined,
800 .checksum_offset = null,
801 });
802
803 mod_info_offset += this_record_len;
804 if (mod_info_offset > mod_info_size)
805 return error.InvalidDebugInfo;
806 }
807
808 di.modules = modules.toOwnedSlice();
809
810 // Section Contribution Substream
811 var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
812 var sect_cont_offset: usize = 0;
813 if (section_contrib_size != 0) {
814 const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
815 if (ver != pdb.SectionContrSubstreamVersion.Ver60)
816 return error.InvalidDebugInfo;
817 sect_cont_offset += @sizeOf(u32);
818 }
819 while (sect_cont_offset != section_contrib_size) {
820 const entry = try sect_contribs.addOne();
821 try dbi.stream.readStruct(pdb.SectionContribEntry, entry);
822 sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
823
824 if (sect_cont_offset > section_contrib_size)
825 return error.InvalidDebugInfo;
826 }
827
828 di.sect_contribs = sect_contribs.toOwnedSlice();
829
830 return di;
831}
832
833fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
834 const num_words = try stream.readIntLe(u32);
835 var word_i: usize = 0;
836 var list = ArrayList(usize).init(allocator);
837 while (word_i != num_words) : (word_i += 1) {
838 const word = try stream.readIntLe(u32);
839 var bit_i: u5 = 0;
840 while (true) : (bit_i += 1) {
841 if (word & (u32(1) << bit_i) != 0) {
842 try list.append(word_i * 32 + bit_i);
843 }
844 if (bit_i == @maxValue(u5)) break;
845 }
846 }
847 return list.toOwnedSlice();
848}
849
383fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {850fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
384 var di = DebugInfo{851 var di = DebugInfo{
385 .self_exe_file = undefined,852 .self_exe_file = undefined,
...@@ -395,7 +862,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {...@@ -395,7 +862,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
395 di.self_exe_file = try os.openSelfExe();862 di.self_exe_file = try os.openSelfExe();
396 errdefer di.self_exe_file.close();863 errdefer di.self_exe_file.close();
397864
398 try di.elf.openFile(allocator, &di.self_exe_file);865 try di.elf.openFile(allocator, di.self_exe_file);
399 errdefer di.elf.close();866 errdefer di.elf.close();
400867
401 di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;868 di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
...@@ -578,7 +1045,13 @@ pub const DebugInfo = switch (builtin.os) {...@@ -578,7 +1045,13 @@ pub const DebugInfo = switch (builtin.os) {
578 return self.ofiles.allocator;1045 return self.ofiles.allocator;
579 }1046 }
580 },1047 },
581 else => struct {1048 builtin.Os.windows => struct {
1049 pdb: pdb.Pdb,
1050 coff: *coff.Coff,
1051 sect_contribs: []pdb.SectionContribEntry,
1052 modules: []Module,
1053 },
1054 builtin.Os.linux => struct {
582 self_exe_file: os.File,1055 self_exe_file: os.File,
583 elf: elf.Elf,1056 elf: elf.Elf,
584 debug_info: *elf.SectionHeader,1057 debug_info: *elf.SectionHeader,
...@@ -594,7 +1067,7 @@ pub const DebugInfo = switch (builtin.os) {...@@ -594,7 +1067,7 @@ pub const DebugInfo = switch (builtin.os) {
594 }1067 }
5951068
596 pub fn readString(self: *DebugInfo) ![]u8 {1069 pub fn readString(self: *DebugInfo) ![]u8 {
597 var in_file_stream = io.FileInStream.init(&self.self_exe_file);1070 var in_file_stream = io.FileInStream.init(self.self_exe_file);
598 const in_stream = &in_file_stream.stream;1071 const in_stream = &in_file_stream.stream;
599 return readStringRaw(self.allocator(), in_stream);1072 return readStringRaw(self.allocator(), in_stream);
600 }1073 }
...@@ -604,6 +1077,7 @@ pub const DebugInfo = switch (builtin.os) {...@@ -604,6 +1077,7 @@ pub const DebugInfo = switch (builtin.os) {
604 self.elf.close();1077 self.elf.close();
605 }1078 }
606 },1079 },
1080 else => @compileError("Unsupported OS"),
607};1081};
6081082
609const PcRange = struct {1083const PcRange = struct {
...@@ -929,7 +1403,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -929,7 +1403,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
929}1403}
9301404
931fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {1405fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
932 const in_file = &st.self_exe_file;1406 const in_file = st.self_exe_file;
933 var in_file_stream = io.FileInStream.init(in_file);1407 var in_file_stream = io.FileInStream.init(in_file);
934 const in_stream = &in_file_stream.stream;1408 const in_stream = &in_file_stream.stream;
935 var result = AbbrevTable.init(st.allocator());1409 var result = AbbrevTable.init(st.allocator());
...@@ -980,7 +1454,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con...@@ -980,7 +1454,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
980}1454}
9811455
982fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {1456fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
983 const in_file = &st.self_exe_file;1457 const in_file = st.self_exe_file;
984 var in_file_stream = io.FileInStream.init(in_file);1458 var in_file_stream = io.FileInStream.init(in_file);
985 const in_stream = &in_file_stream.stream;1459 const in_stream = &in_file_stream.stream;
986 const abbrev_code = try readULeb128(in_stream);1460 const abbrev_code = try readULeb128(in_stream);
...@@ -1202,7 +1676,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -1202,7 +1676,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
1202fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {1676fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
1203 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);1677 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
12041678
1205 const in_file = &di.self_exe_file;1679 const in_file = di.self_exe_file;
1206 const debug_line_end = di.debug_line.offset + di.debug_line.size;1680 const debug_line_end = di.debug_line.offset + di.debug_line.size;
1207 var this_offset = di.debug_line.offset;1681 var this_offset = di.debug_line.offset;
1208 var this_index: usize = 0;1682 var this_index: usize = 0;
...@@ -1382,7 +1856,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {...@@ -1382,7 +1856,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
1382 var this_unit_offset = st.debug_info.offset;1856 var this_unit_offset = st.debug_info.offset;
1383 var cu_index: usize = 0;1857 var cu_index: usize = 0;
13841858
1385 var in_file_stream = io.FileInStream.init(&st.self_exe_file);1859 var in_file_stream = io.FileInStream.init(st.self_exe_file);
1386 const in_stream = &in_file_stream.stream;1860 const in_stream = &in_file_stream.stream;
13871861
1388 while (this_unit_offset < debug_info_end) {1862 while (this_unit_offset < debug_info_end) {
...@@ -1448,7 +1922,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {...@@ -1448,7 +1922,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
1448}1922}
14491923
1450fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {1924fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
1451 var in_file_stream = io.FileInStream.init(&st.self_exe_file);1925 var in_file_stream = io.FileInStream.init(st.self_exe_file);
1452 const in_stream = &in_file_stream.stream;1926 const in_stream = &in_file_stream.stream;
1453 for (st.compile_unit_list.toSlice()) |*compile_unit| {1927 for (st.compile_unit_list.toSlice()) |*compile_unit| {
1454 if (compile_unit.pc_range) |range| {1928 if (compile_unit.pc_range) |range| {
std/elf.zig+2-2
...@@ -353,7 +353,7 @@ pub const SectionHeader = struct {...@@ -353,7 +353,7 @@ pub const SectionHeader = struct {
353};353};
354354
355pub const Elf = struct {355pub const Elf = struct {
356 in_file: *os.File,356 in_file: os.File,
357 auto_close_stream: bool,357 auto_close_stream: bool,
358 is_64: bool,358 is_64: bool,
359 endian: builtin.Endian,359 endian: builtin.Endian,
...@@ -376,7 +376,7 @@ pub const Elf = struct {...@@ -376,7 +376,7 @@ pub const Elf = struct {
376 }376 }
377377
378 /// Call close when done.378 /// Call close when done.
379 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: *os.File) !void {379 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
380 elf.allocator = allocator;380 elf.allocator = allocator;
381 elf.in_file = file;381 elf.in_file = file;
382 elf.auto_close_stream = false;382 elf.auto_close_stream = false;
std/event/tcp.zig+3-3
...@@ -145,11 +145,11 @@ test "listen on a port, send bytes, receive bytes" {...@@ -145,11 +145,11 @@ test "listen on a port, send bytes, receive bytes" {
145 cancel @handle();145 cancel @handle();
146 }146 }
147 }147 }
148 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: *const std.os.File) !void {148 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: std.os.File) !void {
149 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733149 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733
150 var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733150 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/733
151151
152 var adapter = std.io.FileOutStream.init(&socket);152 var adapter = std.io.FileOutStream.init(socket);
153 var stream = &adapter.stream;153 var stream = &adapter.stream;
154 try stream.print("hello from server\n");154 try stream.print("hello from server\n");
155 }155 }
std/index.zig+4
...@@ -15,6 +15,7 @@ pub const atomic = @import("atomic/index.zig");...@@ -15,6 +15,7 @@ pub const atomic = @import("atomic/index.zig");
15pub const base64 = @import("base64.zig");15pub const base64 = @import("base64.zig");
16pub const build = @import("build.zig");16pub const build = @import("build.zig");
17pub const c = @import("c/index.zig");17pub const c = @import("c/index.zig");
18pub const coff = @import("coff.zig");
18pub const crypto = @import("crypto/index.zig");19pub const crypto = @import("crypto/index.zig");
19pub const cstr = @import("cstr.zig");20pub const cstr = @import("cstr.zig");
20pub const debug = @import("debug/index.zig");21pub const debug = @import("debug/index.zig");
...@@ -33,6 +34,7 @@ pub const math = @import("math/index.zig");...@@ -33,6 +34,7 @@ pub const math = @import("math/index.zig");
33pub const mem = @import("mem.zig");34pub const mem = @import("mem.zig");
34pub const net = @import("net.zig");35pub const net = @import("net.zig");
35pub const os = @import("os/index.zig");36pub const os = @import("os/index.zig");
37pub const pdb = @import("pdb.zig");
36pub const rand = @import("rand/index.zig");38pub const rand = @import("rand/index.zig");
37pub const rb = @import("rb.zig");39pub const rb = @import("rb.zig");
38pub const sort = @import("sort.zig");40pub const sort = @import("sort.zig");
...@@ -56,6 +58,7 @@ test "std" {...@@ -56,6 +58,7 @@ test "std" {
56 _ = @import("base64.zig");58 _ = @import("base64.zig");
57 _ = @import("build.zig");59 _ = @import("build.zig");
58 _ = @import("c/index.zig");60 _ = @import("c/index.zig");
61 _ = @import("coff.zig");
59 _ = @import("crypto/index.zig");62 _ = @import("crypto/index.zig");
60 _ = @import("cstr.zig");63 _ = @import("cstr.zig");
61 _ = @import("debug/index.zig");64 _ = @import("debug/index.zig");
...@@ -74,6 +77,7 @@ test "std" {...@@ -74,6 +77,7 @@ test "std" {
74 _ = @import("heap.zig");77 _ = @import("heap.zig");
75 _ = @import("os/index.zig");78 _ = @import("os/index.zig");
76 _ = @import("rand/index.zig");79 _ = @import("rand/index.zig");
80 _ = @import("pdb.zig");
77 _ = @import("sort.zig");81 _ = @import("sort.zig");
78 _ = @import("unicode.zig");82 _ = @import("unicode.zig");
79 _ = @import("zig/index.zig");83 _ = @import("zig/index.zig");
std/io.zig+8-8
...@@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File {...@@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File {
3434
35/// Implementation of InStream trait for File35/// Implementation of InStream trait for File
36pub const FileInStream = struct {36pub const FileInStream = struct {
37 file: *File,37 file: File,
38 stream: Stream,38 stream: Stream,
3939
40 pub const Error = @typeOf(File.read).ReturnType.ErrorSet;40 pub const Error = @typeOf(File.read).ReturnType.ErrorSet;
41 pub const Stream = InStream(Error);41 pub const Stream = InStream(Error);
4242
43 pub fn init(file: *File) FileInStream {43 pub fn init(file: File) FileInStream {
44 return FileInStream{44 return FileInStream{
45 .file = file,45 .file = file,
46 .stream = Stream{ .readFn = readFn },46 .stream = Stream{ .readFn = readFn },
...@@ -55,13 +55,13 @@ pub const FileInStream = struct {...@@ -55,13 +55,13 @@ pub const FileInStream = struct {
5555
56/// Implementation of OutStream trait for File56/// Implementation of OutStream trait for File
57pub const FileOutStream = struct {57pub const FileOutStream = struct {
58 file: *File,58 file: File,
59 stream: Stream,59 stream: Stream,
6060
61 pub const Error = File.WriteError;61 pub const Error = File.WriteError;
62 pub const Stream = OutStream(Error);62 pub const Stream = OutStream(Error);
6363
64 pub fn init(file: *File) FileOutStream {64 pub fn init(file: File) FileOutStream {
65 return FileOutStream{65 return FileOutStream{
66 .file = file,66 .file = file,
67 .stream = Stream{ .writeFn = writeFn },67 .stream = Stream{ .writeFn = writeFn },
...@@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type {
210210
211 pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void {211 pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void {
212 // Only extern and packed structs have defined in-memory layout.212 // Only extern and packed structs have defined in-memory layout.
213 assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);213 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
214 return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..]));214 return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..]));
215 }215 }
216 };216 };
...@@ -280,7 +280,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim...@@ -280,7 +280,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim
280 const buf = try allocator.alignedAlloc(u8, A, size);280 const buf = try allocator.alignedAlloc(u8, A, size);
281 errdefer allocator.free(buf);281 errdefer allocator.free(buf);
282282
283 var adapter = FileInStream.init(&file);283 var adapter = FileInStream.init(file);
284 try adapter.stream.readNoEof(buf[0..size]);284 try adapter.stream.readNoEof(buf[0..size]);
285 return buf;285 return buf;
286}286}
...@@ -592,7 +592,7 @@ pub const BufferedAtomicFile = struct {...@@ -592,7 +592,7 @@ pub const BufferedAtomicFile = struct {
592 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.File.default_mode);592 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.File.default_mode);
593 errdefer self.atomic_file.deinit();593 errdefer self.atomic_file.deinit();
594594
595 self.file_stream = FileOutStream.init(&self.atomic_file.file);595 self.file_stream = FileOutStream.init(self.atomic_file.file);
596 self.buffered_stream = BufferedOutStream(FileOutStream.Error).init(&self.file_stream.stream);596 self.buffered_stream = BufferedOutStream(FileOutStream.Error).init(&self.file_stream.stream);
597 return self;597 return self;
598 }598 }
...@@ -622,7 +622,7 @@ test "import io tests" {...@@ -622,7 +622,7 @@ test "import io tests" {
622622
623pub fn readLine(buf: []u8) !usize {623pub fn readLine(buf: []u8) !usize {
624 var stdin = getStdIn() catch return error.StdInUnavailable;624 var stdin = getStdIn() catch return error.StdInUnavailable;
625 var adapter = FileInStream.init(&stdin);625 var adapter = FileInStream.init(stdin);
626 var stream = &adapter.stream;626 var stream = &adapter.stream;
627 var index: usize = 0;627 var index: usize = 0;
628 while (true) {628 while (true) {
std/io_test.zig+2-2
...@@ -19,7 +19,7 @@ test "write a file, read it, then delete it" {...@@ -19,7 +19,7 @@ test "write a file, read it, then delete it" {
19 var file = try os.File.openWrite(tmp_file_name);19 var file = try os.File.openWrite(tmp_file_name);
20 defer file.close();20 defer file.close();
2121
22 var file_out_stream = io.FileOutStream.init(&file);22 var file_out_stream = io.FileOutStream.init(file);
23 var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);23 var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
24 const st = &buf_stream.stream;24 const st = &buf_stream.stream;
25 try st.print("begin");25 try st.print("begin");
...@@ -35,7 +35,7 @@ test "write a file, read it, then delete it" {...@@ -35,7 +35,7 @@ test "write a file, read it, then delete it" {
35 const expected_file_size = "begin".len + data.len + "end".len;35 const expected_file_size = "begin".len + data.len + "end".len;
36 assert(file_size == expected_file_size);36 assert(file_size == expected_file_size);
3737
38 var file_in_stream = io.FileInStream.init(&file);38 var file_in_stream = io.FileInStream.init(file);
39 var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream);39 var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream);
40 const st = &buf_stream.stream;40 const st = &buf_stream.stream;
41 const contents = try st.readAllAlloc(allocator, 2 * 1024);41 const contents = try st.readAllAlloc(allocator, 2 * 1024);
std/os/child_process.zig+2-2
...@@ -209,8 +209,8 @@ pub const ChildProcess = struct {...@@ -209,8 +209,8 @@ pub const ChildProcess = struct {
209 defer Buffer.deinit(&stdout);209 defer Buffer.deinit(&stdout);
210 defer Buffer.deinit(&stderr);210 defer Buffer.deinit(&stderr);
211211
212 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);212 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
213 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);213 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
214214
215 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);215 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
216 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);216 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
std/os/file.zig+49-34
...@@ -48,18 +48,23 @@ pub const File = struct {...@@ -48,18 +48,23 @@ pub const File = struct {
48 return openReadC(&path_c);48 return openReadC(&path_c);
49 }49 }
50 if (is_windows) {50 if (is_windows) {
51 const handle = try os.windowsOpen(51 const path_w = try windows_util.sliceToPrefixedFileW(path);
52 path,52 return openReadW(&path_w);
53 windows.GENERIC_READ,
54 windows.FILE_SHARE_READ,
55 windows.OPEN_EXISTING,
56 windows.FILE_ATTRIBUTE_NORMAL,
57 );
58 return openHandle(handle);
59 }53 }
60 @compileError("Unsupported OS");54 @compileError("Unsupported OS");
61 }55 }
6256
57 pub fn openReadW(path_w: [*]const u16) OpenError!File {
58 const handle = try os.windowsOpenW(
59 path_w,
60 windows.GENERIC_READ,
61 windows.FILE_SHARE_READ,
62 windows.OPEN_EXISTING,
63 windows.FILE_ATTRIBUTE_NORMAL,
64 );
65 return openHandle(handle);
66 }
67
63 /// Calls `openWriteMode` with os.File.default_mode for the mode.68 /// Calls `openWriteMode` with os.File.default_mode for the mode.
64 pub fn openWrite(path: []const u8) OpenError!File {69 pub fn openWrite(path: []const u8) OpenError!File {
65 return openWriteMode(path, os.File.default_mode);70 return openWriteMode(path, os.File.default_mode);
...@@ -74,19 +79,24 @@ pub const File = struct {...@@ -74,19 +79,24 @@ pub const File = struct {
74 const fd = try os.posixOpen(path, flags, file_mode);79 const fd = try os.posixOpen(path, flags, file_mode);
75 return openHandle(fd);80 return openHandle(fd);
76 } else if (is_windows) {81 } else if (is_windows) {
77 const handle = try os.windowsOpen(82 const path_w = try windows_util.sliceToPrefixedFileW(path);
78 path,83 return openWriteModeW(&path_w, file_mode);
79 windows.GENERIC_WRITE,
80 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
81 windows.CREATE_ALWAYS,
82 windows.FILE_ATTRIBUTE_NORMAL,
83 );
84 return openHandle(handle);
85 } else {84 } else {
86 @compileError("TODO implement openWriteMode for this OS");85 @compileError("TODO implement openWriteMode for this OS");
87 }86 }
88 }87 }
8988
89 pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
90 const handle = try os.windowsOpenW(
91 path_w,
92 windows.GENERIC_WRITE,
93 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
94 windows.CREATE_ALWAYS,
95 windows.FILE_ATTRIBUTE_NORMAL,
96 );
97 return openHandle(handle);
98 }
99
90 /// If the path does not exist it will be created.100 /// If the path does not exist it will be created.
91 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists101 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
92 /// Call close to clean up.102 /// Call close to clean up.
...@@ -96,19 +106,24 @@ pub const File = struct {...@@ -96,19 +106,24 @@ pub const File = struct {
96 const fd = try os.posixOpen(path, flags, file_mode);106 const fd = try os.posixOpen(path, flags, file_mode);
97 return openHandle(fd);107 return openHandle(fd);
98 } else if (is_windows) {108 } else if (is_windows) {
99 const handle = try os.windowsOpen(109 const path_w = try windows_util.sliceToPrefixedFileW(path);
100 path,110 return openWriteNoClobberW(&path_w, file_mode);
101 windows.GENERIC_WRITE,
102 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
103 windows.CREATE_NEW,
104 windows.FILE_ATTRIBUTE_NORMAL,
105 );
106 return openHandle(handle);
107 } else {111 } else {
108 @compileError("TODO implement openWriteMode for this OS");112 @compileError("TODO implement openWriteMode for this OS");
109 }113 }
110 }114 }
111115
116 pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
117 const handle = try os.windowsOpenW(
118 path_w,
119 windows.GENERIC_WRITE,
120 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
121 windows.CREATE_NEW,
122 windows.FILE_ATTRIBUTE_NORMAL,
123 );
124 return openHandle(handle);
125 }
126
112 pub fn openHandle(handle: os.FileHandle) File {127 pub fn openHandle(handle: os.FileHandle) File {
113 return File{ .handle = handle };128 return File{ .handle = handle };
114 }129 }
...@@ -190,17 +205,16 @@ pub const File = struct {...@@ -190,17 +205,16 @@ pub const File = struct {
190205
191 /// Upon success, the stream is in an uninitialized state. To continue using it,206 /// Upon success, the stream is in an uninitialized state. To continue using it,
192 /// you must use the open() function.207 /// you must use the open() function.
193 pub fn close(self: *File) void {208 pub fn close(self: File) void {
194 os.close(self.handle);209 os.close(self.handle);
195 self.handle = undefined;
196 }210 }
197211
198 /// Calls `os.isTty` on `self.handle`.212 /// Calls `os.isTty` on `self.handle`.
199 pub fn isTty(self: *File) bool {213 pub fn isTty(self: File) bool {
200 return os.isTty(self.handle);214 return os.isTty(self.handle);
201 }215 }
202216
203 pub fn seekForward(self: *File, amount: isize) !void {217 pub fn seekForward(self: File, amount: isize) !void {
204 switch (builtin.os) {218 switch (builtin.os) {
205 Os.linux, Os.macosx, Os.ios => {219 Os.linux, Os.macosx, Os.ios => {
206 const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);220 const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
...@@ -231,7 +245,7 @@ pub const File = struct {...@@ -231,7 +245,7 @@ pub const File = struct {
231 }245 }
232 }246 }
233247
234 pub fn seekTo(self: *File, pos: usize) !void {248 pub fn seekTo(self: File, pos: usize) !void {
235 switch (builtin.os) {249 switch (builtin.os) {
236 Os.linux, Os.macosx, Os.ios => {250 Os.linux, Os.macosx, Os.ios => {
237 const ipos = try math.cast(isize, pos);251 const ipos = try math.cast(isize, pos);
...@@ -256,6 +270,7 @@ pub const File = struct {...@@ -256,6 +270,7 @@ pub const File = struct {
256 const err = windows.GetLastError();270 const err = windows.GetLastError();
257 return switch (err) {271 return switch (err) {
258 windows.ERROR.INVALID_PARAMETER => unreachable,272 windows.ERROR.INVALID_PARAMETER => unreachable,
273 windows.ERROR.INVALID_HANDLE => unreachable,
259 else => os.unexpectedErrorWindows(err),274 else => os.unexpectedErrorWindows(err),
260 };275 };
261 }276 }
...@@ -264,7 +279,7 @@ pub const File = struct {...@@ -264,7 +279,7 @@ pub const File = struct {
264 }279 }
265 }280 }
266281
267 pub fn getPos(self: *File) !usize {282 pub fn getPos(self: File) !usize {
268 switch (builtin.os) {283 switch (builtin.os) {
269 Os.linux, Os.macosx, Os.ios => {284 Os.linux, Os.macosx, Os.ios => {
270 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);285 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
...@@ -300,7 +315,7 @@ pub const File = struct {...@@ -300,7 +315,7 @@ pub const File = struct {
300 }315 }
301 }316 }
302317
303 pub fn getEndPos(self: *File) !usize {318 pub fn getEndPos(self: File) !usize {
304 if (is_posix) {319 if (is_posix) {
305 const stat = try os.posixFStat(self.handle);320 const stat = try os.posixFStat(self.handle);
306 return @intCast(usize, stat.size);321 return @intCast(usize, stat.size);
...@@ -325,7 +340,7 @@ pub const File = struct {...@@ -325,7 +340,7 @@ pub const File = struct {
325 Unexpected,340 Unexpected,
326 };341 };
327342
328 pub fn mode(self: *File) ModeError!Mode {343 pub fn mode(self: File) ModeError!Mode {
329 if (is_posix) {344 if (is_posix) {
330 var stat: posix.Stat = undefined;345 var stat: posix.Stat = undefined;
331 const err = posix.getErrno(posix.fstat(self.handle, &stat));346 const err = posix.getErrno(posix.fstat(self.handle, &stat));
...@@ -359,7 +374,7 @@ pub const File = struct {...@@ -359,7 +374,7 @@ pub const File = struct {
359 Unexpected,374 Unexpected,
360 };375 };
361376
362 pub fn read(self: *File, buffer: []u8) ReadError!usize {377 pub fn read(self: File, buffer: []u8) ReadError!usize {
363 if (is_posix) {378 if (is_posix) {
364 var index: usize = 0;379 var index: usize = 0;
365 while (index < buffer.len) {380 while (index < buffer.len) {
...@@ -407,7 +422,7 @@ pub const File = struct {...@@ -407,7 +422,7 @@ pub const File = struct {
407422
408 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;423 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
409424
410 pub fn write(self: *File, bytes: []const u8) WriteError!void {425 pub fn write(self: File, bytes: []const u8) WriteError!void {
411 if (is_posix) {426 if (is_posix) {
412 try os.posixWrite(self.handle, bytes);427 try os.posixWrite(self.handle, bytes);
413 } else if (is_windows) {428 } else if (is_windows) {
std/os/index.zig+26-14
...@@ -57,6 +57,7 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;...@@ -57,6 +57,7 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;
57pub const windowsWrite = windows_util.windowsWrite;57pub const windowsWrite = windows_util.windowsWrite;
58pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;58pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
59pub const windowsOpen = windows_util.windowsOpen;59pub const windowsOpen = windows_util.windowsOpen;
60pub const windowsOpenW = windows_util.windowsOpenW;
60pub const windowsLoadDll = windows_util.windowsLoadDll;61pub const windowsLoadDll = windows_util.windowsLoadDll;
61pub const windowsUnloadDll = windows_util.windowsUnloadDll;62pub const windowsUnloadDll = windows_util.windowsUnloadDll;
62pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;63pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
...@@ -660,6 +661,7 @@ pub fn getBaseAddress() usize {...@@ -660,6 +661,7 @@ pub fn getBaseAddress() usize {
660 return phdr - @sizeOf(ElfHeader);661 return phdr - @sizeOf(ElfHeader);
661 },662 },
662 builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),663 builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),
664 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
663 else => @compileError("Unsupported OS"),665 else => @compileError("Unsupported OS"),
664 }666 }
665}667}
...@@ -2068,7 +2070,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons...@@ -2068,7 +2070,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons
2068}2070}
20692071
2070// TODO make this a build variable that you can set2072// TODO make this a build variable that you can set
2071const unexpected_error_tracing = false;2073const unexpected_error_tracing = true;
2072const UnexpectedError = error{2074const UnexpectedError = error{
2073 /// The Operating System returned an undocumented error code.2075 /// The Operating System returned an undocumented error code.
2074 Unexpected,2076 Unexpected,
...@@ -2087,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {...@@ -2087,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
2087/// Call this when you made a windows DLL call or something that does SetLastError2089/// Call this when you made a windows DLL call or something that does SetLastError
2088/// and you get an unexpected error.2090/// and you get an unexpected error.
2089pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {2091pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2090 if (true) {2092 if (unexpected_error_tracing) {
2091 debug.warn("unexpected GetLastError(): {}\n", err);2093 debug.warn("unexpected GetLastError(): {}\n", err);
2094 @breakpoint();
2092 debug.dumpCurrentStackTrace(null);2095 debug.dumpCurrentStackTrace(null);
2093 }2096 }
2094 return error.Unexpected;2097 return error.Unexpected;
...@@ -2103,15 +2106,33 @@ pub fn openSelfExe() !os.File {...@@ -2103,15 +2106,33 @@ pub fn openSelfExe() !os.File {
2103 buf[self_exe_path.len] = 0;2106 buf[self_exe_path.len] = 0;
2104 return os.File.openReadC(self_exe_path.ptr);2107 return os.File.openReadC(self_exe_path.ptr);
2105 },2108 },
2109 Os.windows => {
2110 var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2111 const wide_slice = try selfExePathW(&buf);
2112 return os.File.openReadW(wide_slice.ptr);
2113 },
2106 else => @compileError("Unsupported OS"),2114 else => @compileError("Unsupported OS"),
2107 }2115 }
2108}2116}
21092117
2110test "openSelfExe" {2118test "openSelfExe" {
2111 switch (builtin.os) {2119 switch (builtin.os) {
2112 Os.linux, Os.macosx, Os.ios => (try openSelfExe()).close(),2120 Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(),
2113 else => return error.SkipZigTest, // Unsupported OS2121 else => return error.SkipZigTest, // Unsupported OS.
2122 }
2123}
2124
2125pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
2126 const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
2127 const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
2128 assert(rc <= out_buffer.len);
2129 if (rc == 0) {
2130 const err = windows.GetLastError();
2131 switch (err) {
2132 else => return unexpectedErrorWindows(err),
2133 }
2114 }2134 }
2135 return out_buffer[0..rc];
2115}2136}
21162137
2117/// Get the path to the current executable.2138/// Get the path to the current executable.
...@@ -2129,16 +2150,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {...@@ -2129,16 +2150,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
2129 Os.linux => return readLink(out_buffer, "/proc/self/exe"),2150 Os.linux => return readLink(out_buffer, "/proc/self/exe"),
2130 Os.windows => {2151 Os.windows => {
2131 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;2152 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2132 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast2153 const utf16le_slice = try selfExePathW(&utf16le_buf);
2133 const rc = windows.GetModuleFileNameW(null, &utf16le_buf, casted_len);
2134 assert(rc <= utf16le_buf.len);
2135 if (rc == 0) {
2136 const err = windows.GetLastError();
2137 switch (err) {
2138 else => return unexpectedErrorWindows(err),
2139 }
2140 }
2141 const utf16le_slice = utf16le_buf[0..rc];
2142 // Trust that Windows gives us valid UTF-16LE.2154 // Trust that Windows gives us valid UTF-16LE.
2143 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;2155 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
2144 return out_buffer[0..end_index];2156 return out_buffer[0..end_index];
std/os/windows/index.zig+14
...@@ -3,6 +3,7 @@ const assert = std.debug.assert;...@@ -3,6 +3,7 @@ const assert = std.debug.assert;
33
4pub use @import("advapi32.zig");4pub use @import("advapi32.zig");
5pub use @import("kernel32.zig");5pub use @import("kernel32.zig");
6pub use @import("ntdll.zig");
6pub use @import("ole32.zig");7pub use @import("ole32.zig");
7pub use @import("shell32.zig");8pub use @import("shell32.zig");
8pub use @import("shlwapi.zig");9pub use @import("shlwapi.zig");
...@@ -14,6 +15,7 @@ test "import" {...@@ -14,6 +15,7 @@ test "import" {
1415
15pub const ERROR = @import("error.zig");16pub const ERROR = @import("error.zig");
1617
18pub const SHORT = c_short;
17pub const BOOL = c_int;19pub const BOOL = c_int;
18pub const BOOLEAN = BYTE;20pub const BOOLEAN = BYTE;
19pub const BYTE = u8;21pub const BYTE = u8;
...@@ -363,3 +365,15 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;...@@ -363,3 +365,15 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
363pub const FILE_FLAG_SESSION_AWARE = 0x00800000;365pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
364pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;366pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
365pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;367pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
368
369pub const SMALL_RECT = extern struct {
370 Left: SHORT,
371 Top: SHORT,
372 Right: SHORT,
373 Bottom: SHORT,
374};
375
376pub const COORD = extern struct {
377 X: SHORT,
378 Y: SHORT,
379};
std/os/windows/kernel32.zig+20
...@@ -72,6 +72,8 @@ pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;...@@ -72,6 +72,8 @@ pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
7272
73pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;73pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
7474
75pub extern "kernel32" stdcallcc fn GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) BOOL;
76
75pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD;77pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD;
76pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;78pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;
7779
...@@ -92,6 +94,8 @@ pub extern "kernel32" stdcallcc fn GetFileAttributesW(lpFileName: [*]const WCHAR...@@ -92,6 +94,8 @@ pub extern "kernel32" stdcallcc fn GetFileAttributesW(lpFileName: [*]const WCHAR
92pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD;94pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD;
93pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD;95pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD;
9496
97pub extern "kernel32" stdcallcc fn GetModuleHandleW(lpModuleName: ?[*]const WCHAR) HMODULE;
98
95pub extern "kernel32" stdcallcc fn GetLastError() DWORD;99pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
96100
97pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(101pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
...@@ -177,6 +181,8 @@ pub extern "kernel32" stdcallcc fn ReadFile(...@@ -177,6 +181,8 @@ pub extern "kernel32" stdcallcc fn ReadFile(
177181
178pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;182pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
179183
184pub extern "kernel32" stdcallcc fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) BOOL;
185
180pub extern "kernel32" stdcallcc fn SetFilePointerEx(186pub extern "kernel32" stdcallcc fn SetFilePointerEx(
181 in_fFile: HANDLE,187 in_fFile: HANDLE,
182 in_liDistanceToMove: LARGE_INTEGER,188 in_liDistanceToMove: LARGE_INTEGER,
...@@ -232,3 +238,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;...@@ -232,3 +238,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
232pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;238pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
233pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;239pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
234pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;240pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
241
242
243pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
244 dwSize: COORD,
245 dwCursorPosition: COORD,
246 wAttributes: WORD,
247 srWindow: SMALL_RECT,
248 dwMaximumWindowSize: COORD,
249};
250
251pub const FOREGROUND_BLUE = 1;
252pub const FOREGROUND_GREEN = 2;
253pub const FOREGROUND_RED = 4;
254pub const FOREGROUND_INTENSITY = 8;
std/os/windows/ntdll.zig created+3
...@@ -0,0 +1,3 @@
1use @import("index.zig");
2
3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
std/os/windows/util.zig+14-5
...@@ -118,16 +118,14 @@ pub const OpenError = error{...@@ -118,16 +118,14 @@ pub const OpenError = error{
118 Unexpected,118 Unexpected,
119};119};
120120
121pub fn windowsOpen(121pub fn windowsOpenW(
122 file_path: []const u8,122 file_path_w: [*]const u16,
123 desired_access: windows.DWORD,123 desired_access: windows.DWORD,
124 share_mode: windows.DWORD,124 share_mode: windows.DWORD,
125 creation_disposition: windows.DWORD,125 creation_disposition: windows.DWORD,
126 flags_and_attrs: windows.DWORD,126 flags_and_attrs: windows.DWORD,
127) OpenError!windows.HANDLE {127) OpenError!windows.HANDLE {
128 const file_path_w = try sliceToPrefixedFileW(file_path);128 const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
129
130 const result = windows.CreateFileW(&file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
131129
132 if (result == windows.INVALID_HANDLE_VALUE) {130 if (result == windows.INVALID_HANDLE_VALUE) {
133 const err = windows.GetLastError();131 const err = windows.GetLastError();
...@@ -146,6 +144,17 @@ pub fn windowsOpen(...@@ -146,6 +144,17 @@ pub fn windowsOpen(
146 return result;144 return result;
147}145}
148146
147pub fn windowsOpen(
148 file_path: []const u8,
149 desired_access: windows.DWORD,
150 share_mode: windows.DWORD,
151 creation_disposition: windows.DWORD,
152 flags_and_attrs: windows.DWORD,
153) OpenError!windows.HANDLE {
154 const file_path_w = try sliceToPrefixedFileW(file_path);
155 return windowsOpenW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
156}
157
149/// Caller must free result.158/// Caller must free result.
150pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 {159pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 {
151 // count bytes needed160 // count bytes needed
std/pdb.zig created+646
...@@ -0,0 +1,646 @@
1const builtin = @import("builtin");
2const std = @import("index.zig");
3const io = std.io;
4const math = std.math;
5const mem = std.mem;
6const os = std.os;
7const warn = std.debug.warn;
8const coff = std.coff;
9
10const ArrayList = std.ArrayList;
11
12// https://llvm.org/docs/PDB/DbiStream.html#stream-header
13pub const DbiStreamHeader = packed struct {
14 VersionSignature: i32,
15 VersionHeader: u32,
16 Age: u32,
17 GlobalStreamIndex: u16,
18 BuildNumber: u16,
19 PublicStreamIndex: u16,
20 PdbDllVersion: u16,
21 SymRecordStream: u16,
22 PdbDllRbld: u16,
23 ModInfoSize: u32,
24 SectionContributionSize: u32,
25 SectionMapSize: u32,
26 SourceInfoSize: i32,
27 TypeServerSize: i32,
28 MFCTypeServerIndex: u32,
29 OptionalDbgHeaderSize: i32,
30 ECSubstreamSize: i32,
31 Flags: u16,
32 Machine: u16,
33 Padding: u32,
34};
35
36pub const SectionContribEntry = packed struct {
37 Section: u16,
38 Padding1: [2]u8,
39 Offset: u32,
40 Size: u32,
41 Characteristics: u32,
42 ModuleIndex: u16,
43 Padding2: [2]u8,
44 DataCrc: u32,
45 RelocCrc: u32,
46};
47
48pub const ModInfo = packed struct {
49 Unused1: u32,
50 SectionContr: SectionContribEntry,
51 Flags: u16,
52 ModuleSymStream: u16,
53 SymByteSize: u32,
54 C11ByteSize: u32,
55 C13ByteSize: u32,
56 SourceFileCount: u16,
57 Padding: [2]u8,
58 Unused2: u32,
59 SourceFileNameIndex: u32,
60 PdbFilePathNameIndex: u32,
61 // These fields are variable length
62 //ModuleName: char[],
63 //ObjFileName: char[],
64};
65
66pub const SectionMapHeader = packed struct {
67 Count: u16, /// Number of segment descriptors
68 LogCount: u16, /// Number of logical segment descriptors
69};
70
71pub const SectionMapEntry = packed struct {
72 Flags: u16 , /// See the SectionMapEntryFlags enum below.
73 Ovl: u16 , /// Logical overlay number
74 Group: u16 , /// Group index into descriptor array.
75 Frame: u16 ,
76 SectionName: u16 , /// Byte index of segment / group name in string table, or 0xFFFF.
77 ClassName: u16 , /// Byte index of class in string table, or 0xFFFF.
78 Offset: u32 , /// Byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group.
79 SectionLength: u32 , /// Byte count of the segment or group.
80};
81
82pub const StreamType = enum(u16) {
83 Pdb = 1,
84 Tpi = 2,
85 Dbi = 3,
86 Ipi = 4,
87};
88
89/// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful
90/// for reference purposes and when dealing with unknown record types.
91pub const SymbolKind = packed enum(u16) {
92 S_COMPILE = 1,
93 S_REGISTER_16t = 2,
94 S_CONSTANT_16t = 3,
95 S_UDT_16t = 4,
96 S_SSEARCH = 5,
97 S_SKIP = 7,
98 S_CVRESERVE = 8,
99 S_OBJNAME_ST = 9,
100 S_ENDARG = 10,
101 S_COBOLUDT_16t = 11,
102 S_MANYREG_16t = 12,
103 S_RETURN = 13,
104 S_ENTRYTHIS = 14,
105 S_BPREL16 = 256,
106 S_LDATA16 = 257,
107 S_GDATA16 = 258,
108 S_PUB16 = 259,
109 S_LPROC16 = 260,
110 S_GPROC16 = 261,
111 S_THUNK16 = 262,
112 S_BLOCK16 = 263,
113 S_WITH16 = 264,
114 S_LABEL16 = 265,
115 S_CEXMODEL16 = 266,
116 S_VFTABLE16 = 267,
117 S_REGREL16 = 268,
118 S_BPREL32_16t = 512,
119 S_LDATA32_16t = 513,
120 S_GDATA32_16t = 514,
121 S_PUB32_16t = 515,
122 S_LPROC32_16t = 516,
123 S_GPROC32_16t = 517,
124 S_THUNK32_ST = 518,
125 S_BLOCK32_ST = 519,
126 S_WITH32_ST = 520,
127 S_LABEL32_ST = 521,
128 S_CEXMODEL32 = 522,
129 S_VFTABLE32_16t = 523,
130 S_REGREL32_16t = 524,
131 S_LTHREAD32_16t = 525,
132 S_GTHREAD32_16t = 526,
133 S_SLINK32 = 527,
134 S_LPROCMIPS_16t = 768,
135 S_GPROCMIPS_16t = 769,
136 S_PROCREF_ST = 1024,
137 S_DATAREF_ST = 1025,
138 S_ALIGN = 1026,
139 S_LPROCREF_ST = 1027,
140 S_OEM = 1028,
141 S_TI16_MAX = 4096,
142 S_REGISTER_ST = 4097,
143 S_CONSTANT_ST = 4098,
144 S_UDT_ST = 4099,
145 S_COBOLUDT_ST = 4100,
146 S_MANYREG_ST = 4101,
147 S_BPREL32_ST = 4102,
148 S_LDATA32_ST = 4103,
149 S_GDATA32_ST = 4104,
150 S_PUB32_ST = 4105,
151 S_LPROC32_ST = 4106,
152 S_GPROC32_ST = 4107,
153 S_VFTABLE32 = 4108,
154 S_REGREL32_ST = 4109,
155 S_LTHREAD32_ST = 4110,
156 S_GTHREAD32_ST = 4111,
157 S_LPROCMIPS_ST = 4112,
158 S_GPROCMIPS_ST = 4113,
159 S_COMPILE2_ST = 4115,
160 S_MANYREG2_ST = 4116,
161 S_LPROCIA64_ST = 4117,
162 S_GPROCIA64_ST = 4118,
163 S_LOCALSLOT_ST = 4119,
164 S_PARAMSLOT_ST = 4120,
165 S_ANNOTATION = 4121,
166 S_GMANPROC_ST = 4122,
167 S_LMANPROC_ST = 4123,
168 S_RESERVED1 = 4124,
169 S_RESERVED2 = 4125,
170 S_RESERVED3 = 4126,
171 S_RESERVED4 = 4127,
172 S_LMANDATA_ST = 4128,
173 S_GMANDATA_ST = 4129,
174 S_MANFRAMEREL_ST = 4130,
175 S_MANREGISTER_ST = 4131,
176 S_MANSLOT_ST = 4132,
177 S_MANMANYREG_ST = 4133,
178 S_MANREGREL_ST = 4134,
179 S_MANMANYREG2_ST = 4135,
180 S_MANTYPREF = 4136,
181 S_UNAMESPACE_ST = 4137,
182 S_ST_MAX = 4352,
183 S_WITH32 = 4356,
184 S_MANYREG = 4362,
185 S_LPROCMIPS = 4372,
186 S_GPROCMIPS = 4373,
187 S_MANYREG2 = 4375,
188 S_LPROCIA64 = 4376,
189 S_GPROCIA64 = 4377,
190 S_LOCALSLOT = 4378,
191 S_PARAMSLOT = 4379,
192 S_MANFRAMEREL = 4382,
193 S_MANREGISTER = 4383,
194 S_MANSLOT = 4384,
195 S_MANMANYREG = 4385,
196 S_MANREGREL = 4386,
197 S_MANMANYREG2 = 4387,
198 S_UNAMESPACE = 4388,
199 S_DATAREF = 4390,
200 S_ANNOTATIONREF = 4392,
201 S_TOKENREF = 4393,
202 S_GMANPROC = 4394,
203 S_LMANPROC = 4395,
204 S_ATTR_FRAMEREL = 4398,
205 S_ATTR_REGISTER = 4399,
206 S_ATTR_REGREL = 4400,
207 S_ATTR_MANYREG = 4401,
208 S_SEPCODE = 4402,
209 S_LOCAL_2005 = 4403,
210 S_DEFRANGE_2005 = 4404,
211 S_DEFRANGE2_2005 = 4405,
212 S_DISCARDED = 4411,
213 S_LPROCMIPS_ID = 4424,
214 S_GPROCMIPS_ID = 4425,
215 S_LPROCIA64_ID = 4426,
216 S_GPROCIA64_ID = 4427,
217 S_DEFRANGE_HLSL = 4432,
218 S_GDATA_HLSL = 4433,
219 S_LDATA_HLSL = 4434,
220 S_LOCAL_DPC_GROUPSHARED = 4436,
221 S_DEFRANGE_DPC_PTR_TAG = 4439,
222 S_DPC_SYM_TAG_MAP = 4440,
223 S_ARMSWITCHTABLE = 4441,
224 S_POGODATA = 4444,
225 S_INLINESITE2 = 4445,
226 S_MOD_TYPEREF = 4447,
227 S_REF_MINIPDB = 4448,
228 S_PDBMAP = 4449,
229 S_GDATA_HLSL32 = 4450,
230 S_LDATA_HLSL32 = 4451,
231 S_GDATA_HLSL32_EX = 4452,
232 S_LDATA_HLSL32_EX = 4453,
233 S_FASTLINK = 4455,
234 S_INLINEES = 4456,
235 S_END = 6,
236 S_INLINESITE_END = 4430,
237 S_PROC_ID_END = 4431,
238 S_THUNK32 = 4354,
239 S_TRAMPOLINE = 4396,
240 S_SECTION = 4406,
241 S_COFFGROUP = 4407,
242 S_EXPORT = 4408,
243 S_LPROC32 = 4367,
244 S_GPROC32 = 4368,
245 S_LPROC32_ID = 4422,
246 S_GPROC32_ID = 4423,
247 S_LPROC32_DPC = 4437,
248 S_LPROC32_DPC_ID = 4438,
249 S_REGISTER = 4358,
250 S_PUB32 = 4366,
251 S_PROCREF = 4389,
252 S_LPROCREF = 4391,
253 S_ENVBLOCK = 4413,
254 S_INLINESITE = 4429,
255 S_LOCAL = 4414,
256 S_DEFRANGE = 4415,
257 S_DEFRANGE_SUBFIELD = 4416,
258 S_DEFRANGE_REGISTER = 4417,
259 S_DEFRANGE_FRAMEPOINTER_REL = 4418,
260 S_DEFRANGE_SUBFIELD_REGISTER = 4419,
261 S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 4420,
262 S_DEFRANGE_REGISTER_REL = 4421,
263 S_BLOCK32 = 4355,
264 S_LABEL32 = 4357,
265 S_OBJNAME = 4353,
266 S_COMPILE2 = 4374,
267 S_COMPILE3 = 4412,
268 S_FRAMEPROC = 4114,
269 S_CALLSITEINFO = 4409,
270 S_FILESTATIC = 4435,
271 S_HEAPALLOCSITE = 4446,
272 S_FRAMECOOKIE = 4410,
273 S_CALLEES = 4442,
274 S_CALLERS = 4443,
275 S_UDT = 4360,
276 S_COBOLUDT = 4361,
277 S_BUILDINFO = 4428,
278 S_BPREL32 = 4363,
279 S_REGREL32 = 4369,
280 S_CONSTANT = 4359,
281 S_MANCONSTANT = 4397,
282 S_LDATA32 = 4364,
283 S_GDATA32 = 4365,
284 S_LMANDATA = 4380,
285 S_GMANDATA = 4381,
286 S_LTHREAD32 = 4370,
287 S_GTHREAD32 = 4371,
288};
289
290pub const TypeIndex = u32;
291
292pub const ProcSym = packed struct {
293 Parent: u32 ,
294 End: u32 ,
295 Next: u32 ,
296 CodeSize: u32 ,
297 DbgStart: u32 ,
298 DbgEnd: u32 ,
299 FunctionType: TypeIndex ,
300 CodeOffset: u32,
301 Segment: u16,
302 Flags: ProcSymFlags,
303 // following is a null terminated string
304 // Name: [*]u8,
305};
306
307pub const ProcSymFlags = packed struct {
308 HasFP: bool,
309 HasIRET: bool,
310 HasFRET: bool,
311 IsNoReturn: bool,
312 IsUnreachable: bool,
313 HasCustomCallingConv: bool,
314 IsNoInline: bool,
315 HasOptimizedDebugInfo: bool,
316};
317
318pub const SectionContrSubstreamVersion = enum(u32) {
319 Ver60 = 0xeffe0000 + 19970605,
320 V2 = 0xeffe0000 + 20140516
321};
322
323pub const RecordPrefix = packed struct {
324 RecordLen: u16, /// Record length, starting from &RecordKind.
325 RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind)
326};
327
328pub const LineFragmentHeader = packed struct {
329 RelocOffset: u32, /// Code offset of line contribution.
330 RelocSegment: u16, /// Code segment of line contribution.
331 Flags: LineFlags,
332 CodeSize: u32, /// Code size of this line contribution.
333};
334
335pub const LineFlags = packed struct {
336 LF_HaveColumns: bool, /// CV_LINES_HAVE_COLUMNS
337 unused: u15,
338};
339
340/// The following two variable length arrays appear immediately after the
341/// header. The structure definitions follow.
342/// LineNumberEntry Lines[NumLines];
343/// ColumnNumberEntry Columns[NumLines];
344pub const LineBlockFragmentHeader = packed struct {
345 /// Offset of FileChecksum entry in File
346 /// checksums buffer. The checksum entry then
347 /// contains another offset into the string
348 /// table of the actual name.
349 NameIndex: u32,
350 NumLines: u32,
351 BlockSize: u32, /// code size of block, in bytes
352};
353
354
355pub const LineNumberEntry = packed struct {
356 Offset: u32, /// Offset to start of code bytes for line number
357 Flags: u32,
358
359 /// TODO runtime crash when I make the actual type of Flags this
360 const Flags = packed struct {
361 Start: u24,
362 End: u7,
363 IsStatement: bool,
364 };
365};
366
367pub const ColumnNumberEntry = packed struct {
368 StartColumn: u16,
369 EndColumn: u16,
370};
371
372/// Checksum bytes follow.
373pub const FileChecksumEntryHeader = packed struct {
374 FileNameOffset: u32, /// Byte offset of filename in global string table.
375 ChecksumSize: u8, /// Number of bytes of checksum.
376 ChecksumKind: u8, /// FileChecksumKind
377};
378
379pub const DebugSubsectionKind = packed enum(u32) {
380 None = 0,
381 Symbols = 0xf1,
382 Lines = 0xf2,
383 StringTable = 0xf3,
384 FileChecksums = 0xf4,
385 FrameData = 0xf5,
386 InlineeLines = 0xf6,
387 CrossScopeImports = 0xf7,
388 CrossScopeExports = 0xf8,
389
390 // These appear to relate to .Net assembly info.
391 ILLines = 0xf9,
392 FuncMDTokenMap = 0xfa,
393 TypeMDTokenMap = 0xfb,
394 MergedAssemblyInput = 0xfc,
395
396 CoffSymbolRVA = 0xfd,
397};
398
399
400pub const DebugSubsectionHeader = packed struct {
401 Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum
402 Length: u32, /// number of bytes occupied by this record.
403};
404
405
406pub const PDBStringTableHeader = packed struct {
407 Signature: u32, /// PDBStringTableSignature
408 HashVersion: u32, /// 1 or 2
409 ByteSize: u32, /// Number of bytes of names buffer.
410};
411
412pub const Pdb = struct {
413 in_file: os.File,
414 allocator: *mem.Allocator,
415 coff: *coff.Coff,
416 string_table: *MsfStream,
417 dbi: *MsfStream,
418
419 msf: Msf,
420
421 pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {
422 self.in_file = try os.File.openRead(file_name);
423 self.allocator = coff_ptr.allocator;
424 self.coff = coff_ptr;
425
426 try self.msf.openFile(self.allocator, self.in_file);
427 }
428
429 pub fn getStreamById(self: *Pdb, id: u32) ?*MsfStream {
430 if (id >= self.msf.streams.len)
431 return null;
432 return &self.msf.streams[id];
433 }
434
435 pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream {
436 const id = @enumToInt(stream);
437 return self.getStreamById(id);
438 }
439};
440
441// see https://llvm.org/docs/PDB/MsfFile.html
442const Msf = struct {
443 directory: MsfStream,
444 streams: []MsfStream,
445
446 fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {
447 var file_stream = io.FileInStream.init(file);
448 const in = &file_stream.stream;
449
450 var superblock: SuperBlock = undefined;
451 try in.readStruct(SuperBlock, &superblock);
452
453 if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
454 return error.InvalidDebugInfo;
455
456 switch (superblock.BlockSize) {
457 // llvm only supports 4096 but we can handle any of these values
458 512, 1024, 2048, 4096 => {},
459 else => return error.InvalidDebugInfo
460 }
461
462 if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
463 return error.InvalidDebugInfo;
464
465 self.directory = try MsfStream.init(
466 superblock.BlockSize,
467 blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
468 superblock.BlockSize * superblock.BlockMapAddr,
469 file,
470 allocator,
471 );
472
473 const stream_count = try self.directory.stream.readIntLe(u32);
474
475 const stream_sizes = try allocator.alloc(u32, stream_count);
476 for (stream_sizes) |*s| {
477 const size = try self.directory.stream.readIntLe(u32);
478 s.* = blockCountFromSize(size, superblock.BlockSize);
479 }
480
481 self.streams = try allocator.alloc(MsfStream, stream_count);
482 for (self.streams) |*stream, i| {
483 stream.* = try MsfStream.init(
484 superblock.BlockSize,
485 stream_sizes[i],
486 // MsfStream.init expects the file to be at the part where it reads [N]u32
487 try file.getPos(),
488 file,
489 allocator,
490 );
491 }
492 }
493};
494
495fn blockCountFromSize(size: u32, block_size: u32) u32 {
496 return (size + block_size - 1) / block_size;
497}
498
499// https://llvm.org/docs/PDB/MsfFile.html#the-superblock
500const SuperBlock = packed struct {
501 /// The LLVM docs list a space between C / C++ but empirically this is not the case.
502 const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00";
503
504 FileMagic: [file_magic.len]u8,
505
506 /// The block size of the internal file system. Valid values are 512, 1024,
507 /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending
508 /// on the block sizes. For the purposes of LLVM, we handle only block sizes of
509 /// 4KiB, and all further discussion assumes a block size of 4KiB.
510 BlockSize: u32,
511
512 /// The index of a block within the file, at which begins a bitfield representing
513 /// the set of all blocks within the file which are “free” (i.e. the data within
514 /// that block is not used). See The Free Block Map for more information. Important:
515 /// FreeBlockMapBlock can only be 1 or 2!
516 FreeBlockMapBlock: u32,
517
518 /// The total number of blocks in the file. NumBlocks * BlockSize should equal the
519 /// size of the file on disk.
520 NumBlocks: u32,
521
522 /// The size of the stream directory, in bytes. The stream directory contains
523 /// information about each stream’s size and the set of blocks that it occupies.
524 /// It will be described in more detail later.
525 NumDirectoryBytes: u32,
526
527 Unknown: u32,
528
529 /// The index of a block within the MSF file. At this block is an array of
530 /// ulittle32_t’s listing the blocks that the stream directory resides on.
531 /// For large MSF files, the stream directory (which describes the block
532 /// layout of each stream) may not fit entirely on a single block. As a
533 /// result, this extra layer of indirection is introduced, whereby this
534 /// block contains the list of blocks that the stream directory occupies,
535 /// and the stream directory itself can be stitched together accordingly.
536 /// The number of ulittle32_t’s in this array is given by
537 /// ceil(NumDirectoryBytes / BlockSize).
538 BlockMapAddr: u32,
539
540};
541
542const MsfStream = struct {
543 in_file: os.File,
544 pos: usize,
545 blocks: []u32,
546 block_size: u32,
547
548 /// Implementation of InStream trait for Pdb.MsfStream
549 stream: Stream,
550
551 pub const Error = @typeOf(read).ReturnType.ErrorSet;
552 pub const Stream = io.InStream(Error);
553
554 fn init(block_size: u32, block_count: u32, pos: usize, file: os.File, allocator: *mem.Allocator) !MsfStream {
555 var stream = MsfStream {
556 .in_file = file,
557 .pos = 0,
558 .blocks = try allocator.alloc(u32, block_count),
559 .block_size = block_size,
560 .stream = Stream {
561 .readFn = readFn,
562 },
563 };
564
565 var file_stream = io.FileInStream.init(file);
566 const in = &file_stream.stream;
567 try file.seekTo(pos);
568
569 var i: u32 = 0;
570 while (i < block_count) : (i += 1) {
571 stream.blocks[i] = try in.readIntLe(u32);
572 }
573
574 return stream;
575 }
576
577 fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
578 var list = ArrayList(u8).init(allocator);
579 defer list.deinit();
580 while (true) {
581 const byte = try self.stream.readByte();
582 if (byte == 0) {
583 return list.toSlice();
584 }
585 try list.append(byte);
586 }
587 }
588
589 fn read(self: *MsfStream, buffer: []u8) !usize {
590 var block_id = self.pos / self.block_size;
591 var block = self.blocks[block_id];
592 var offset = self.pos % self.block_size;
593
594 try self.in_file.seekTo(block * self.block_size + offset);
595 var file_stream = io.FileInStream.init(self.in_file);
596 const in = &file_stream.stream;
597
598 var size: usize = 0;
599 for (buffer) |*byte| {
600 byte.* = try in.readByte();
601
602 offset += 1;
603 size += 1;
604
605 // If we're at the end of a block, go to the next one.
606 if (offset == self.block_size) {
607 offset = 0;
608 block_id += 1;
609 block = self.blocks[block_id];
610 try self.in_file.seekTo(block * self.block_size);
611 }
612 }
613
614 self.pos += size;
615 return size;
616 }
617
618 fn seekForward(self: *MsfStream, len: usize) !void {
619 self.pos += len;
620 if (self.pos >= self.blocks.len * self.block_size)
621 return error.EOF;
622 }
623
624 fn seekTo(self: *MsfStream, len: usize) !void {
625 self.pos = len;
626 if (self.pos >= self.blocks.len * self.block_size)
627 return error.EOF;
628 }
629
630 fn getSize(self: *const MsfStream) usize {
631 return self.blocks.len * self.block_size;
632 }
633
634 fn getFilePos(self: MsfStream) usize {
635 const block_id = self.pos / self.block_size;
636 const block = self.blocks[block_id];
637 const offset = self.pos % self.block_size;
638
639 return block * self.block_size + offset;
640 }
641
642 fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
643 const self = @fieldParentPtr(MsfStream, "stream", in_stream);
644 return self.read(buffer);
645 }
646};
std/special/build_runner.zig+2-2
...@@ -49,14 +49,14 @@ pub fn main() !void {...@@ -49,14 +49,14 @@ pub fn main() !void {
4949
50 var stderr_file = io.getStdErr();50 var stderr_file = io.getStdErr();
51 var stderr_file_stream: io.FileOutStream = undefined;51 var stderr_file_stream: io.FileOutStream = undefined;
52 var stderr_stream = if (stderr_file) |*f| x: {52 var stderr_stream = if (stderr_file) |f| x: {
53 stderr_file_stream = io.FileOutStream.init(f);53 stderr_file_stream = io.FileOutStream.init(f);
54 break :x &stderr_file_stream.stream;54 break :x &stderr_file_stream.stream;
55 } else |err| err;55 } else |err| err;
5656
57 var stdout_file = io.getStdOut();57 var stdout_file = io.getStdOut();
58 var stdout_file_stream: io.FileOutStream = undefined;58 var stdout_file_stream: io.FileOutStream = undefined;
59 var stdout_stream = if (stdout_file) |*f| x: {59 var stdout_stream = if (stdout_file) |f| x: {
60 stdout_file_stream = io.FileOutStream.init(f);60 stdout_file_stream = io.FileOutStream.init(f);
61 break :x &stdout_file_stream.stream;61 break :x &stdout_file_stream.stream;
62 } else |err| err;62 } else |err| err;
std/zig/parser_test.zig+1-1
...@@ -1865,7 +1865,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;...@@ -1865,7 +1865,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
18651865
1866fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {1866fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
1867 var stderr_file = try io.getStdErr();1867 var stderr_file = try io.getStdErr();
1868 var stderr = &io.FileOutStream.init(&stderr_file).stream;1868 var stderr = &io.FileOutStream.init(stderr_file).stream;
18691869
1870 var tree = try std.zig.parse(allocator, source);1870 var tree = try std.zig.parse(allocator, source);
1871 defer tree.deinit();1871 defer tree.deinit();
test/compare_output.zig+15-15
...@@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
19 \\19 \\
20 \\pub fn main() void {20 \\pub fn main() void {
21 \\ privateFunction();21 \\ privateFunction();
22 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);22 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
23 \\ stdout.print("OK 2\n") catch unreachable;23 \\ stdout.print("OK 2\n") catch unreachable;
24 \\}24 \\}
25 \\25 \\
...@@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
34 \\// purposefully conflicting function with main.zig34 \\// purposefully conflicting function with main.zig
35 \\// but it's private so it should be OK35 \\// but it's private so it should be OK
36 \\fn privateFunction() void {36 \\fn privateFunction() void {
37 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);37 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
38 \\ stdout.print("OK 1\n") catch unreachable;38 \\ stdout.print("OK 1\n") catch unreachable;
39 \\}39 \\}
40 \\40 \\
...@@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
60 tc.addSourceFile("foo.zig",60 tc.addSourceFile("foo.zig",
61 \\use @import("std").io;61 \\use @import("std").io;
62 \\pub fn foo_function() void {62 \\pub fn foo_function() void {
63 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);63 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
64 \\ stdout.print("OK\n") catch unreachable;64 \\ stdout.print("OK\n") catch unreachable;
65 \\}65 \\}
66 );66 );
...@@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
71 \\71 \\
72 \\pub fn bar_function() void {72 \\pub fn bar_function() void {
73 \\ if (foo_function()) {73 \\ if (foo_function()) {
74 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);74 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
75 \\ stdout.print("OK\n") catch unreachable;75 \\ stdout.print("OK\n") catch unreachable;
76 \\ }76 \\ }
77 \\}77 \\}
...@@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
103 \\pub const a_text = "OK\n";103 \\pub const a_text = "OK\n";
104 \\104 \\
105 \\pub fn ok() void {105 \\pub fn ok() void {
106 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);106 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
107 \\ stdout.print(b_text) catch unreachable;107 \\ stdout.print(b_text) catch unreachable;
108 \\}108 \\}
109 );109 );
...@@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
121 \\const io = @import("std").io;121 \\const io = @import("std").io;
122 \\122 \\
123 \\pub fn main() void {123 \\pub fn main() void {
124 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);124 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
125 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;125 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
126 \\}126 \\}
127 , "Hello, world!\n0012 012 a\n");127 , "Hello, world!\n0012 012 a\n");
...@@ -274,7 +274,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -274,7 +274,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
274 \\ var x_local : i32 = print_ok(x);274 \\ var x_local : i32 = print_ok(x);
275 \\}275 \\}
276 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {276 \\fn print_ok(val: @typeOf(x)) @typeOf(foo) {
277 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);277 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
278 \\ stdout.print("OK\n") catch unreachable;278 \\ stdout.print("OK\n") catch unreachable;
279 \\ return 0;279 \\ return 0;
280 \\}280 \\}
...@@ -356,7 +356,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -356,7 +356,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
356 \\pub fn main() void {356 \\pub fn main() void {
357 \\ const bar = Bar {.field2 = 13,};357 \\ const bar = Bar {.field2 = 13,};
358 \\ const foo = Foo {.field1 = bar,};358 \\ const foo = Foo {.field1 = bar,};
359 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);359 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
360 \\ if (!foo.method()) {360 \\ if (!foo.method()) {
361 \\ stdout.print("BAD\n") catch unreachable;361 \\ stdout.print("BAD\n") catch unreachable;
362 \\ }362 \\ }
...@@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
370 cases.add("defer with only fallthrough",370 cases.add("defer with only fallthrough",
371 \\const io = @import("std").io;371 \\const io = @import("std").io;
372 \\pub fn main() void {372 \\pub fn main() void {
373 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);373 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
374 \\ stdout.print("before\n") catch unreachable;374 \\ stdout.print("before\n") catch unreachable;
375 \\ defer stdout.print("defer1\n") catch unreachable;375 \\ defer stdout.print("defer1\n") catch unreachable;
376 \\ defer stdout.print("defer2\n") catch unreachable;376 \\ defer stdout.print("defer2\n") catch unreachable;
...@@ -383,7 +383,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -383,7 +383,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
383 \\const io = @import("std").io;383 \\const io = @import("std").io;
384 \\const os = @import("std").os;384 \\const os = @import("std").os;
385 \\pub fn main() void {385 \\pub fn main() void {
386 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);386 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
387 \\ stdout.print("before\n") catch unreachable;387 \\ stdout.print("before\n") catch unreachable;
388 \\ defer stdout.print("defer1\n") catch unreachable;388 \\ defer stdout.print("defer1\n") catch unreachable;
389 \\ defer stdout.print("defer2\n") catch unreachable;389 \\ defer stdout.print("defer2\n") catch unreachable;
...@@ -400,7 +400,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -400,7 +400,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
400 \\ do_test() catch return;400 \\ do_test() catch return;
401 \\}401 \\}
402 \\fn do_test() !void {402 \\fn do_test() !void {
403 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);403 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
404 \\ stdout.print("before\n") catch unreachable;404 \\ stdout.print("before\n") catch unreachable;
405 \\ defer stdout.print("defer1\n") catch unreachable;405 \\ defer stdout.print("defer1\n") catch unreachable;
406 \\ errdefer stdout.print("deferErr\n") catch unreachable;406 \\ errdefer stdout.print("deferErr\n") catch unreachable;
...@@ -419,7 +419,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -419,7 +419,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
419 \\ do_test() catch return;419 \\ do_test() catch return;
420 \\}420 \\}
421 \\fn do_test() !void {421 \\fn do_test() !void {
422 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);422 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
423 \\ stdout.print("before\n") catch unreachable;423 \\ stdout.print("before\n") catch unreachable;
424 \\ defer stdout.print("defer1\n") catch unreachable;424 \\ defer stdout.print("defer1\n") catch unreachable;
425 \\ errdefer stdout.print("deferErr\n") catch unreachable;425 \\ errdefer stdout.print("deferErr\n") catch unreachable;
...@@ -436,7 +436,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -436,7 +436,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
436 \\const io = @import("std").io;436 \\const io = @import("std").io;
437 \\437 \\
438 \\pub fn main() void {438 \\pub fn main() void {
439 \\ const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);439 \\ const stdout = &io.FileOutStream.init(io.getStdOut() catch unreachable).stream;
440 \\ stdout.print(foo_txt) catch unreachable;440 \\ stdout.print(foo_txt) catch unreachable;
441 \\}441 \\}
442 , "1234\nabcd\n");442 , "1234\nabcd\n");
...@@ -456,7 +456,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -456,7 +456,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
456 \\pub fn main() !void {456 \\pub fn main() !void {
457 \\ var args_it = os.args();457 \\ var args_it = os.args();
458 \\ var stdout_file = try io.getStdOut();458 \\ var stdout_file = try io.getStdOut();
459 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);459 \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
460 \\ const stdout = &stdout_adapter.stream;460 \\ const stdout = &stdout_adapter.stream;
461 \\ var index: usize = 0;461 \\ var index: usize = 0;
462 \\ _ = args_it.skip();462 \\ _ = args_it.skip();
...@@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
497 \\pub fn main() !void {497 \\pub fn main() !void {
498 \\ var args_it = os.args();498 \\ var args_it = os.args();
499 \\ var stdout_file = try io.getStdOut();499 \\ var stdout_file = try io.getStdOut();
500 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);500 \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
501 \\ const stdout = &stdout_adapter.stream;501 \\ const stdout = &stdout_adapter.stream;
502 \\ var index: usize = 0;502 \\ var index: usize = 0;
503 \\ _ = args_it.skip();503 \\ _ = args_it.skip();
test/tests.zig+6-6
...@@ -263,8 +263,8 @@ pub const CompareOutputContext = struct {...@@ -263,8 +263,8 @@ pub const CompareOutputContext = struct {
263 var stdout = Buffer.initNull(b.allocator);263 var stdout = Buffer.initNull(b.allocator);
264 var stderr = Buffer.initNull(b.allocator);264 var stderr = Buffer.initNull(b.allocator);
265265
266 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);266 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
267 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);267 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
268268
269 stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;269 stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
270 stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;270 stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
...@@ -578,8 +578,8 @@ pub const CompileErrorContext = struct {...@@ -578,8 +578,8 @@ pub const CompileErrorContext = struct {
578 var stdout_buf = Buffer.initNull(b.allocator);578 var stdout_buf = Buffer.initNull(b.allocator);
579 var stderr_buf = Buffer.initNull(b.allocator);579 var stderr_buf = Buffer.initNull(b.allocator);
580580
581 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);581 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
582 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);582 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
583583
584 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;584 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
585 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;585 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
...@@ -842,8 +842,8 @@ pub const TranslateCContext = struct {...@@ -842,8 +842,8 @@ pub const TranslateCContext = struct {
842 var stdout_buf = Buffer.initNull(b.allocator);842 var stdout_buf = Buffer.initNull(b.allocator);
843 var stderr_buf = Buffer.initNull(b.allocator);843 var stderr_buf = Buffer.initNull(b.allocator);
844844
845 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);845 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
846 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);846 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
847847
848 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;848 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
849 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;849 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;