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
444444 "c/index.zig"
445445 "c/linux.zig"
446446 "c/windows.zig"
447 "coff.zig"
447448 "crypto/blake2.zig"
448449 "crypto/hmac.zig"
449450 "crypto/index.zig"
......@@ -577,12 +578,14 @@ set(ZIG_STD_FILES
577578 "os/windows/error.zig"
578579 "os/windows/index.zig"
579580 "os/windows/kernel32.zig"
581 "os/windows/ntdll.zig"
580582 "os/windows/ole32.zig"
581583 "os/windows/shell32.zig"
582584 "os/windows/shlwapi.zig"
583585 "os/windows/user32.zig"
584586 "os/windows/util.zig"
585587 "os/zen.zig"
588 "pdb.zig"
586589 "rand/index.zig"
587590 "rand/ziggurat.zig"
588591 "segmented_list.zig"
doc/docgen.zig+2-2
......@@ -40,11 +40,11 @@ pub fn main() !void {
4040 var out_file = try os.File.openWrite(out_file_name);
4141 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
4545 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);
4848 var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
4949
5050 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;
66
77pub fn main() !void {
88 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);
1010 const stdout = &stdout_file_stream.stream;
1111
1212 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 {
272272 try stream.write("\n");
273273 }
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 {
276276 const color_on = switch (color) {
277277 Color.Auto => file.isTty(),
278278 Color.On => true,
src-self-hosted/main.zig+6-6
......@@ -55,11 +55,11 @@ pub fn main() !void {
5555 const allocator = std.heap.c_allocator;
5656
5757 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);
5959 stdout = &stdout_out_stream.stream;
6060
6161 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);
6363 stderr = &stderr_out_stream.stream;
6464
6565 const args = try os.argsAlloc(allocator);
......@@ -491,7 +491,7 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
491491 stderr.print("Build {} compile errors:\n", count) catch os.exit(1);
492492 for (msgs) |msg| {
493493 defer msg.destroy();
494 msg.printToFile(&stderr_file, color) catch os.exit(1);
494 msg.printToFile(stderr_file, color) catch os.exit(1);
495495 }
496496 },
497497 }
......@@ -619,7 +619,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
619619 }
620620
621621 var stdin_file = try io.getStdIn();
622 var stdin = io.FileInStream.init(&stdin_file);
622 var stdin = io.FileInStream.init(stdin_file);
623623
624624 const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);
625625 defer allocator.free(source_code);
......@@ -635,7 +635,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
635635 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");
636636 defer msg.destroy();
637637
638 try msg.printToFile(&stderr_file, color);
638 try msg.printToFile(stderr_file, color);
639639 }
640640 if (tree.errors.len != 0) {
641641 os.exit(1);
......@@ -772,7 +772,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void {
772772 const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path);
773773 defer fmt.loop.allocator.destroy(msg);
774774
775 try msg.printToFile(&stderr_file, fmt.color);
775 try msg.printToFile(stderr_file, fmt.color);
776776 }
777777 if (tree.errors.len != 0) {
778778 fmt.any_error = true;
src-self-hosted/test.zig+2-2
......@@ -185,7 +185,7 @@ pub const TestContext = struct {
185185 try stderr.write("build incorrectly failed:\n");
186186 for (msgs) |msg| {
187187 defer msg.destroy();
188 try msg.printToFile(&stderr, errmsg.Color.Auto);
188 try msg.printToFile(stderr, errmsg.Color.Auto);
189189 }
190190 },
191191 }
......@@ -234,7 +234,7 @@ pub const TestContext = struct {
234234 var stderr = try std.io.getStdErr();
235235 for (msgs) |msg| {
236236 defer msg.destroy();
237 try msg.printToFile(&stderr, errmsg.Color.Auto);
237 try msg.printToFile(stderr, errmsg.Color.Auto);
238238 }
239239 std.debug.warn("============\n");
240240 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;
44const io = std.io;
55const os = std.os;
66const elf = std.elf;
7const macho = std.macho;
87const DW = std.dwarf;
8const macho = std.macho;
9const coff = std.coff;
10const pdb = std.pdb;
11const windows = os.windows;
912const ArrayList = std.ArrayList;
1013const builtin = @import("builtin");
1114
......@@ -17,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {
1720 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
1821};
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
2034/// Tries to write to stderr, unbuffered, and ignores any error returned.
2135/// Does not append a newline.
2236var stderr_file: os.File = undefined;
......@@ -37,7 +51,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {
3751 return st;
3852 } else {
3953 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);
4155 const st = &stderr_file_out_stream.stream;
4256 stderr_stream = st;
4357 return st;
......@@ -70,7 +84,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
7084 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
7185 return;
7286 };
73 writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| {
87 writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
7488 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
7589 return;
7690 };
......@@ -191,7 +205,11 @@ pub inline fn getReturnAddress(frame_count: usize) usize {
191205 return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
192206}
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 }
195213 const AddressState = union(enum) {
196214 NotLookingForStartAddress,
197215 LookingForStartAddress: usize,
......@@ -224,18 +242,296 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_
224242 }
225243}
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
227263pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
228264 switch (builtin.os) {
229265 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
230266 builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
231 builtin.Os.windows => {
232 // TODO https://github.com/ziglang/zig/issues/721
233 return error.UnsupportedOperatingSystem;
234 },
267 builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
235268 else => return error.UnsupportedOperatingSystem,
236269 }
237270}
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
239535fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
240536 var min: usize = 0;
241537 var max: usize = symbols.len - 1; // Exclude sentinel.
......@@ -372,14 +668,185 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
372668 switch (builtin.os) {
373669 builtin.Os.linux => return openSelfDebugInfoLinux(allocator),
374670 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
375 builtin.Os.windows => {
376 // TODO: https://github.com/ziglang/zig/issues/721
377 return error.UnsupportedOperatingSystem;
378 },
671 builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
379672 else => return error.UnsupportedOperatingSystem,
380673 }
381674}
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
383850fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
384851 var di = DebugInfo{
385852 .self_exe_file = undefined,
......@@ -395,7 +862,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
395862 di.self_exe_file = try os.openSelfExe();
396863 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);
399866 errdefer di.elf.close();
400867
401868 di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
......@@ -578,7 +1045,13 @@ pub const DebugInfo = switch (builtin.os) {
5781045 return self.ofiles.allocator;
5791046 }
5801047 },
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 {
5821055 self_exe_file: os.File,
5831056 elf: elf.Elf,
5841057 debug_info: *elf.SectionHeader,
......@@ -594,7 +1067,7 @@ pub const DebugInfo = switch (builtin.os) {
5941067 }
5951068
5961069 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);
5981071 const in_stream = &in_file_stream.stream;
5991072 return readStringRaw(self.allocator(), in_stream);
6001073 }
......@@ -604,6 +1077,7 @@ pub const DebugInfo = switch (builtin.os) {
6041077 self.elf.close();
6051078 }
6061079 },
1080 else => @compileError("Unsupported OS"),
6071081};
6081082
6091083const PcRange = struct {
......@@ -929,7 +1403,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
9291403}
9301404
9311405fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
932 const in_file = &st.self_exe_file;
1406 const in_file = st.self_exe_file;
9331407 var in_file_stream = io.FileInStream.init(in_file);
9341408 const in_stream = &in_file_stream.stream;
9351409 var result = AbbrevTable.init(st.allocator());
......@@ -980,7 +1454,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
9801454}
9811455
9821456fn 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;
9841458 var in_file_stream = io.FileInStream.init(in_file);
9851459 const in_stream = &in_file_stream.stream;
9861460 const abbrev_code = try readULeb128(in_stream);
......@@ -1202,7 +1676,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
12021676fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
12031677 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;
12061680 const debug_line_end = di.debug_line.offset + di.debug_line.size;
12071681 var this_offset = di.debug_line.offset;
12081682 var this_index: usize = 0;
......@@ -1382,7 +1856,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
13821856 var this_unit_offset = st.debug_info.offset;
13831857 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);
13861860 const in_stream = &in_file_stream.stream;
13871861
13881862 while (this_unit_offset < debug_info_end) {
......@@ -1448,7 +1922,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
14481922}
14491923
14501924fn 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);
14521926 const in_stream = &in_file_stream.stream;
14531927 for (st.compile_unit_list.toSlice()) |*compile_unit| {
14541928 if (compile_unit.pc_range) |range| {
std/elf.zig+2-2
......@@ -353,7 +353,7 @@ pub const SectionHeader = struct {
353353};
354354
355355pub const Elf = struct {
356 in_file: *os.File,
356 in_file: os.File,
357357 auto_close_stream: bool,
358358 is_64: bool,
359359 endian: builtin.Endian,
......@@ -376,7 +376,7 @@ pub const Elf = struct {
376376 }
377377
378378 /// 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 {
380380 elf.allocator = allocator;
381381 elf.in_file = file;
382382 elf.auto_close_stream = false;
std/event/tcp.zig+3-3
......@@ -145,11 +145,11 @@ test "listen on a port, send bytes, receive bytes" {
145145 cancel @handle();
146146 }
147147 }
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 {
149149 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733
150 var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
150 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);
153153 var stream = &adapter.stream;
154154 try stream.print("hello from server\n");
155155 }
std/index.zig+4
......@@ -15,6 +15,7 @@ pub const atomic = @import("atomic/index.zig");
1515pub const base64 = @import("base64.zig");
1616pub const build = @import("build.zig");
1717pub const c = @import("c/index.zig");
18pub const coff = @import("coff.zig");
1819pub const crypto = @import("crypto/index.zig");
1920pub const cstr = @import("cstr.zig");
2021pub const debug = @import("debug/index.zig");
......@@ -33,6 +34,7 @@ pub const math = @import("math/index.zig");
3334pub const mem = @import("mem.zig");
3435pub const net = @import("net.zig");
3536pub const os = @import("os/index.zig");
37pub const pdb = @import("pdb.zig");
3638pub const rand = @import("rand/index.zig");
3739pub const rb = @import("rb.zig");
3840pub const sort = @import("sort.zig");
......@@ -56,6 +58,7 @@ test "std" {
5658 _ = @import("base64.zig");
5759 _ = @import("build.zig");
5860 _ = @import("c/index.zig");
61 _ = @import("coff.zig");
5962 _ = @import("crypto/index.zig");
6063 _ = @import("cstr.zig");
6164 _ = @import("debug/index.zig");
......@@ -74,6 +77,7 @@ test "std" {
7477 _ = @import("heap.zig");
7578 _ = @import("os/index.zig");
7679 _ = @import("rand/index.zig");
80 _ = @import("pdb.zig");
7781 _ = @import("sort.zig");
7882 _ = @import("unicode.zig");
7983 _ = @import("zig/index.zig");
std/io.zig+8-8
......@@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File {
3434
3535/// Implementation of InStream trait for File
3636pub const FileInStream = struct {
37 file: *File,
37 file: File,
3838 stream: Stream,
3939
4040 pub const Error = @typeOf(File.read).ReturnType.ErrorSet;
4141 pub const Stream = InStream(Error);
4242
43 pub fn init(file: *File) FileInStream {
43 pub fn init(file: File) FileInStream {
4444 return FileInStream{
4545 .file = file,
4646 .stream = Stream{ .readFn = readFn },
......@@ -55,13 +55,13 @@ pub const FileInStream = struct {
5555
5656/// Implementation of OutStream trait for File
5757pub const FileOutStream = struct {
58 file: *File,
58 file: File,
5959 stream: Stream,
6060
6161 pub const Error = File.WriteError;
6262 pub const Stream = OutStream(Error);
6363
64 pub fn init(file: *File) FileOutStream {
64 pub fn init(file: File) FileOutStream {
6565 return FileOutStream{
6666 .file = file,
6767 .stream = Stream{ .writeFn = writeFn },
......@@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type {
210210
211211 pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void {
212212 // 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);
214214 return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..]));
215215 }
216216 };
......@@ -280,7 +280,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim
280280 const buf = try allocator.alignedAlloc(u8, A, size);
281281 errdefer allocator.free(buf);
282282
283 var adapter = FileInStream.init(&file);
283 var adapter = FileInStream.init(file);
284284 try adapter.stream.readNoEof(buf[0..size]);
285285 return buf;
286286}
......@@ -592,7 +592,7 @@ pub const BufferedAtomicFile = struct {
592592 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.File.default_mode);
593593 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);
596596 self.buffered_stream = BufferedOutStream(FileOutStream.Error).init(&self.file_stream.stream);
597597 return self;
598598 }
......@@ -622,7 +622,7 @@ test "import io tests" {
622622
623623pub fn readLine(buf: []u8) !usize {
624624 var stdin = getStdIn() catch return error.StdInUnavailable;
625 var adapter = FileInStream.init(&stdin);
625 var adapter = FileInStream.init(stdin);
626626 var stream = &adapter.stream;
627627 var index: usize = 0;
628628 while (true) {
std/io_test.zig+2-2
......@@ -19,7 +19,7 @@ test "write a file, read it, then delete it" {
1919 var file = try os.File.openWrite(tmp_file_name);
2020 defer file.close();
2121
22 var file_out_stream = io.FileOutStream.init(&file);
22 var file_out_stream = io.FileOutStream.init(file);
2323 var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream);
2424 const st = &buf_stream.stream;
2525 try st.print("begin");
......@@ -35,7 +35,7 @@ test "write a file, read it, then delete it" {
3535 const expected_file_size = "begin".len + data.len + "end".len;
3636 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);
3939 var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream);
4040 const st = &buf_stream.stream;
4141 const contents = try st.readAllAlloc(allocator, 2 * 1024);
std/os/child_process.zig+2-2
......@@ -209,8 +209,8 @@ pub const ChildProcess = struct {
209209 defer Buffer.deinit(&stdout);
210210 defer Buffer.deinit(&stderr);
211211
212 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
213 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
212 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
213 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
214214
215215 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
216216 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 {
4848 return openReadC(&path_c);
4949 }
5050 if (is_windows) {
51 const handle = try os.windowsOpen(
52 path,
53 windows.GENERIC_READ,
54 windows.FILE_SHARE_READ,
55 windows.OPEN_EXISTING,
56 windows.FILE_ATTRIBUTE_NORMAL,
57 );
58 return openHandle(handle);
51 const path_w = try windows_util.sliceToPrefixedFileW(path);
52 return openReadW(&path_w);
5953 }
6054 @compileError("Unsupported OS");
6155 }
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
6368 /// Calls `openWriteMode` with os.File.default_mode for the mode.
6469 pub fn openWrite(path: []const u8) OpenError!File {
6570 return openWriteMode(path, os.File.default_mode);
......@@ -74,19 +79,24 @@ pub const File = struct {
7479 const fd = try os.posixOpen(path, flags, file_mode);
7580 return openHandle(fd);
7681 } else if (is_windows) {
77 const handle = try os.windowsOpen(
78 path,
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);
82 const path_w = try windows_util.sliceToPrefixedFileW(path);
83 return openWriteModeW(&path_w, file_mode);
8584 } else {
8685 @compileError("TODO implement openWriteMode for this OS");
8786 }
8887 }
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
90100 /// If the path does not exist it will be created.
91101 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
92102 /// Call close to clean up.
......@@ -96,19 +106,24 @@ pub const File = struct {
96106 const fd = try os.posixOpen(path, flags, file_mode);
97107 return openHandle(fd);
98108 } else if (is_windows) {
99 const handle = try os.windowsOpen(
100 path,
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);
109 const path_w = try windows_util.sliceToPrefixedFileW(path);
110 return openWriteNoClobberW(&path_w, file_mode);
107111 } else {
108112 @compileError("TODO implement openWriteMode for this OS");
109113 }
110114 }
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
112127 pub fn openHandle(handle: os.FileHandle) File {
113128 return File{ .handle = handle };
114129 }
......@@ -190,17 +205,16 @@ pub const File = struct {
190205
191206 /// Upon success, the stream is in an uninitialized state. To continue using it,
192207 /// you must use the open() function.
193 pub fn close(self: *File) void {
208 pub fn close(self: File) void {
194209 os.close(self.handle);
195 self.handle = undefined;
196210 }
197211
198212 /// Calls `os.isTty` on `self.handle`.
199 pub fn isTty(self: *File) bool {
213 pub fn isTty(self: File) bool {
200214 return os.isTty(self.handle);
201215 }
202216
203 pub fn seekForward(self: *File, amount: isize) !void {
217 pub fn seekForward(self: File, amount: isize) !void {
204218 switch (builtin.os) {
205219 Os.linux, Os.macosx, Os.ios => {
206220 const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
......@@ -231,7 +245,7 @@ pub const File = struct {
231245 }
232246 }
233247
234 pub fn seekTo(self: *File, pos: usize) !void {
248 pub fn seekTo(self: File, pos: usize) !void {
235249 switch (builtin.os) {
236250 Os.linux, Os.macosx, Os.ios => {
237251 const ipos = try math.cast(isize, pos);
......@@ -256,6 +270,7 @@ pub const File = struct {
256270 const err = windows.GetLastError();
257271 return switch (err) {
258272 windows.ERROR.INVALID_PARAMETER => unreachable,
273 windows.ERROR.INVALID_HANDLE => unreachable,
259274 else => os.unexpectedErrorWindows(err),
260275 };
261276 }
......@@ -264,7 +279,7 @@ pub const File = struct {
264279 }
265280 }
266281
267 pub fn getPos(self: *File) !usize {
282 pub fn getPos(self: File) !usize {
268283 switch (builtin.os) {
269284 Os.linux, Os.macosx, Os.ios => {
270285 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
......@@ -300,7 +315,7 @@ pub const File = struct {
300315 }
301316 }
302317
303 pub fn getEndPos(self: *File) !usize {
318 pub fn getEndPos(self: File) !usize {
304319 if (is_posix) {
305320 const stat = try os.posixFStat(self.handle);
306321 return @intCast(usize, stat.size);
......@@ -325,7 +340,7 @@ pub const File = struct {
325340 Unexpected,
326341 };
327342
328 pub fn mode(self: *File) ModeError!Mode {
343 pub fn mode(self: File) ModeError!Mode {
329344 if (is_posix) {
330345 var stat: posix.Stat = undefined;
331346 const err = posix.getErrno(posix.fstat(self.handle, &stat));
......@@ -359,7 +374,7 @@ pub const File = struct {
359374 Unexpected,
360375 };
361376
362 pub fn read(self: *File, buffer: []u8) ReadError!usize {
377 pub fn read(self: File, buffer: []u8) ReadError!usize {
363378 if (is_posix) {
364379 var index: usize = 0;
365380 while (index < buffer.len) {
......@@ -407,7 +422,7 @@ pub const File = struct {
407422
408423 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 {
411426 if (is_posix) {
412427 try os.posixWrite(self.handle, bytes);
413428 } else if (is_windows) {
std/os/index.zig+26-14
......@@ -57,6 +57,7 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;
5757pub const windowsWrite = windows_util.windowsWrite;
5858pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
5959pub const windowsOpen = windows_util.windowsOpen;
60pub const windowsOpenW = windows_util.windowsOpenW;
6061pub const windowsLoadDll = windows_util.windowsLoadDll;
6162pub const windowsUnloadDll = windows_util.windowsUnloadDll;
6263pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
......@@ -660,6 +661,7 @@ pub fn getBaseAddress() usize {
660661 return phdr - @sizeOf(ElfHeader);
661662 },
662663 builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),
664 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
663665 else => @compileError("Unsupported OS"),
664666 }
665667}
......@@ -2068,7 +2070,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons
20682070}
20692071
20702072// TODO make this a build variable that you can set
2071const unexpected_error_tracing = false;
2073const unexpected_error_tracing = true;
20722074const UnexpectedError = error{
20732075 /// The Operating System returned an undocumented error code.
20742076 Unexpected,
......@@ -2087,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
20872089/// Call this when you made a windows DLL call or something that does SetLastError
20882090/// and you get an unexpected error.
20892091pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2090 if (true) {
2092 if (unexpected_error_tracing) {
20912093 debug.warn("unexpected GetLastError(): {}\n", err);
2094 @breakpoint();
20922095 debug.dumpCurrentStackTrace(null);
20932096 }
20942097 return error.Unexpected;
......@@ -2103,15 +2106,33 @@ pub fn openSelfExe() !os.File {
21032106 buf[self_exe_path.len] = 0;
21042107 return os.File.openReadC(self_exe_path.ptr);
21052108 },
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 },
21062114 else => @compileError("Unsupported OS"),
21072115 }
21082116}
21092117
21102118test "openSelfExe" {
21112119 switch (builtin.os) {
2112 Os.linux, Os.macosx, Os.ios => (try openSelfExe()).close(),
2113 else => return error.SkipZigTest, // Unsupported OS
2120 Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(),
2121 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 }
21142134 }
2135 return out_buffer[0..rc];
21152136}
21162137
21172138/// Get the path to the current executable.
......@@ -2129,16 +2150,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
21292150 Os.linux => return readLink(out_buffer, "/proc/self/exe"),
21302151 Os.windows => {
21312152 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 cast
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];
2153 const utf16le_slice = try selfExePathW(&utf16le_buf);
21422154 // Trust that Windows gives us valid UTF-16LE.
21432155 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
21442156 return out_buffer[0..end_index];
std/os/windows/index.zig+14
......@@ -3,6 +3,7 @@ const assert = std.debug.assert;
33
44pub use @import("advapi32.zig");
55pub use @import("kernel32.zig");
6pub use @import("ntdll.zig");
67pub use @import("ole32.zig");
78pub use @import("shell32.zig");
89pub use @import("shlwapi.zig");
......@@ -14,6 +15,7 @@ test "import" {
1415
1516pub const ERROR = @import("error.zig");
1617
18pub const SHORT = c_short;
1719pub const BOOL = c_int;
1820pub const BOOLEAN = BYTE;
1921pub const BYTE = u8;
......@@ -363,3 +365,15 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
363365pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
364366pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
365367pub 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;
7272
7373pub 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
7577pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD;
7678pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;
7779
......@@ -92,6 +94,8 @@ pub extern "kernel32" stdcallcc fn GetFileAttributesW(lpFileName: [*]const WCHAR
9294pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD;
9395pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD;
9496
97pub extern "kernel32" stdcallcc fn GetModuleHandleW(lpModuleName: ?[*]const WCHAR) HMODULE;
98
9599pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
96100
97101pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
......@@ -177,6 +181,8 @@ pub extern "kernel32" stdcallcc fn ReadFile(
177181
178182pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
179183
184pub extern "kernel32" stdcallcc fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) BOOL;
185
180186pub extern "kernel32" stdcallcc fn SetFilePointerEx(
181187 in_fFile: HANDLE,
182188 in_liDistanceToMove: LARGE_INTEGER,
......@@ -232,3 +238,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
232238pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
233239pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
234240pub 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{
118118 Unexpected,
119119};
120120
121pub fn windowsOpen(
122 file_path: []const u8,
121pub fn windowsOpenW(
122 file_path_w: [*]const u16,
123123 desired_access: windows.DWORD,
124124 share_mode: windows.DWORD,
125125 creation_disposition: windows.DWORD,
126126 flags_and_attrs: windows.DWORD,
127127) OpenError!windows.HANDLE {
128 const file_path_w = try sliceToPrefixedFileW(file_path);
129
130 const result = windows.CreateFileW(&file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
128 const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
131129
132130 if (result == windows.INVALID_HANDLE_VALUE) {
133131 const err = windows.GetLastError();
......@@ -146,6 +144,17 @@ pub fn windowsOpen(
146144 return result;
147145}
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
149158/// Caller must free result.
150159pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 {
151160 // 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 {
4949
5050 var stderr_file = io.getStdErr();
5151 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: {
5353 stderr_file_stream = io.FileOutStream.init(f);
5454 break :x &stderr_file_stream.stream;
5555 } else |err| err;
5656
5757 var stdout_file = io.getStdOut();
5858 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: {
6060 stdout_file_stream = io.FileOutStream.init(f);
6161 break :x &stdout_file_stream.stream;
6262 } else |err| err;
std/zig/parser_test.zig+1-1
......@@ -1865,7 +1865,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
18651865
18661866fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
18671867 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
18701870 var tree = try std.zig.parse(allocator, source);
18711871 defer tree.deinit();
test/compare_output.zig+15-15
......@@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
1919 \\
2020 \\pub fn main() void {
2121 \\ privateFunction();
22 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
22 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
2323 \\ stdout.print("OK 2\n") catch unreachable;
2424 \\}
2525 \\
......@@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
3434 \\// purposefully conflicting function with main.zig
3535 \\// but it's private so it should be OK
3636 \\fn privateFunction() void {
37 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
37 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
3838 \\ stdout.print("OK 1\n") catch unreachable;
3939 \\}
4040 \\
......@@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
6060 tc.addSourceFile("foo.zig",
6161 \\use @import("std").io;
6262 \\pub fn foo_function() void {
63 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
63 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
6464 \\ stdout.print("OK\n") catch unreachable;
6565 \\}
6666 );
......@@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
7171 \\
7272 \\pub fn bar_function() void {
7373 \\ if (foo_function()) {
74 \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream);
74 \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream;
7575 \\ stdout.print("OK\n") catch unreachable;
7676 \\ }
7777 \\}
......@@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
103103 \\pub const a_text = "OK\n";
104104 \\
105105 \\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;
107107 \\ stdout.print(b_text) catch unreachable;
108108 \\}
109109 );
......@@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
121121 \\const io = @import("std").io;
122122 \\
123123 \\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;
125125 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
126126 \\}
127127 , "Hello, world!\n0012 012 a\n");
......@@ -274,7 +274,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
274274 \\ var x_local : i32 = print_ok(x);
275275 \\}
276276 \\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;
278278 \\ stdout.print("OK\n") catch unreachable;
279279 \\ return 0;
280280 \\}
......@@ -356,7 +356,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
356356 \\pub fn main() void {
357357 \\ const bar = Bar {.field2 = 13,};
358358 \\ 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;
360360 \\ if (!foo.method()) {
361361 \\ stdout.print("BAD\n") catch unreachable;
362362 \\ }
......@@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
370370 cases.add("defer with only fallthrough",
371371 \\const io = @import("std").io;
372372 \\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;
374374 \\ stdout.print("before\n") catch unreachable;
375375 \\ defer stdout.print("defer1\n") catch unreachable;
376376 \\ defer stdout.print("defer2\n") catch unreachable;
......@@ -383,7 +383,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
383383 \\const io = @import("std").io;
384384 \\const os = @import("std").os;
385385 \\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;
387387 \\ stdout.print("before\n") catch unreachable;
388388 \\ defer stdout.print("defer1\n") catch unreachable;
389389 \\ defer stdout.print("defer2\n") catch unreachable;
......@@ -400,7 +400,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
400400 \\ do_test() catch return;
401401 \\}
402402 \\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;
404404 \\ stdout.print("before\n") catch unreachable;
405405 \\ defer stdout.print("defer1\n") catch unreachable;
406406 \\ errdefer stdout.print("deferErr\n") catch unreachable;
......@@ -419,7 +419,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
419419 \\ do_test() catch return;
420420 \\}
421421 \\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;
423423 \\ stdout.print("before\n") catch unreachable;
424424 \\ defer stdout.print("defer1\n") catch unreachable;
425425 \\ errdefer stdout.print("deferErr\n") catch unreachable;
......@@ -436,7 +436,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
436436 \\const io = @import("std").io;
437437 \\
438438 \\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;
440440 \\ stdout.print(foo_txt) catch unreachable;
441441 \\}
442442 , "1234\nabcd\n");
......@@ -456,7 +456,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
456456 \\pub fn main() !void {
457457 \\ var args_it = os.args();
458458 \\ var stdout_file = try io.getStdOut();
459 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
459 \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
460460 \\ const stdout = &stdout_adapter.stream;
461461 \\ var index: usize = 0;
462462 \\ _ = args_it.skip();
......@@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
497497 \\pub fn main() !void {
498498 \\ var args_it = os.args();
499499 \\ var stdout_file = try io.getStdOut();
500 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
500 \\ var stdout_adapter = io.FileOutStream.init(stdout_file);
501501 \\ const stdout = &stdout_adapter.stream;
502502 \\ var index: usize = 0;
503503 \\ _ = args_it.skip();
test/tests.zig+6-6
......@@ -263,8 +263,8 @@ pub const CompareOutputContext = struct {
263263 var stdout = Buffer.initNull(b.allocator);
264264 var stderr = Buffer.initNull(b.allocator);
265265
266 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
267 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
266 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
267 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
268268
269269 stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
270270 stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
......@@ -578,8 +578,8 @@ pub const CompileErrorContext = struct {
578578 var stdout_buf = Buffer.initNull(b.allocator);
579579 var stderr_buf = Buffer.initNull(b.allocator);
580580
581 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
582 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
581 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
582 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
583583
584584 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
585585 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
......@@ -842,8 +842,8 @@ pub const TranslateCContext = struct {
842842 var stdout_buf = Buffer.initNull(b.allocator);
843843 var stderr_buf = Buffer.initNull(b.allocator);
844844
845 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
846 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
845 var stdout_file_in_stream = io.FileInStream.init(child.stdout.?);
846 var stderr_file_in_stream = io.FileInStream.init(child.stderr.?);
847847
848848 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
849849 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;