| author | |
| committer | |
| log | ab387bb4c712b257cc2b728a044ad67935dee2dc |
| tree | aa6ae0b006da48dba434fcf5eaa8550134772563 |
| parent | 86e55567b4b1cccbb69065396391e4a500864dce |
| parent | 832caefc2a1b20deb513d43306d6723670ba9c8f |
| signature |
Stack traces for Windows25 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(); |
| 42 | 42 | ||
| 43 | var file_in_stream = io.FileInStream.init(&in_file); | 43 | var file_in_stream = io.FileInStream.init(in_file); |
| 44 | 44 | ||
| 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); |
| 46 | 46 | ||
| 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); |
| 49 | 49 | ||
| 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; |
| 6 | 6 | ||
| 7 | pub fn main() !void { | 7 | pub 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; |
| 11 | 11 | ||
| 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 | } |
| 274 | 274 | ||
| 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; |
| 56 | 56 | ||
| 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; |
| 60 | 60 | ||
| 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; |
| 64 | 64 | ||
| 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 | } |
| 620 | 620 | ||
| 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); |
| 623 | 623 | ||
| 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(); |
| 637 | 637 | ||
| 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); |
| 774 | 774 | ||
| 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 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("index.zig"); | ||
| 3 | const io = std.io; | ||
| 4 | const mem = std.mem; | ||
| 5 | const os = std.os; | ||
| 6 | |||
| 7 | const ArrayList = std.ArrayList; | ||
| 8 | |||
| 9 | // CoffHeader.machine values | ||
| 10 | // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx | ||
| 11 | const IMAGE_FILE_MACHINE_I386 = 0x014c; | ||
| 12 | const IMAGE_FILE_MACHINE_IA64 = 0x0200; | ||
| 13 | const 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 | ||
| 17 | const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; | ||
| 18 | const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; | ||
| 19 | |||
| 20 | const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; | ||
| 21 | const DEBUG_DIRECTORY = 6; | ||
| 22 | |||
| 23 | pub const CoffError = error { | ||
| 24 | InvalidPEMagic, | ||
| 25 | InvalidPEHeader, | ||
| 26 | InvalidMachine, | ||
| 27 | MissingCoffSection, | ||
| 28 | }; | ||
| 29 | |||
| 30 | pub 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 | |||
| 190 | const 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 | |||
| 200 | const 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 | |||
| 210 | pub const Section = struct { | ||
| 211 | header: SectionHeader, | ||
| 212 | }; | ||
| 213 | |||
| 214 | const 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; |
| 4 | const io = std.io; | 4 | const io = std.io; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| 6 | const elf = std.elf; | 6 | const elf = std.elf; |
| 7 | const macho = std.macho; | ||
| 8 | const DW = std.dwarf; | 7 | const DW = std.dwarf; |
| 8 | const macho = std.macho; | ||
| 9 | const coff = std.coff; | ||
| 10 | const pdb = std.pdb; | ||
| 11 | const windows = os.windows; | ||
| 9 | const ArrayList = std.ArrayList; | 12 | const ArrayList = std.ArrayList; |
| 10 | const builtin = @import("builtin"); | 13 | const builtin = @import("builtin"); |
| 11 | 14 | ||
| ... | @@ -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 | }; |
| 19 | 22 | ||
| 23 | const 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. |
| 22 | var stderr_file: os.File = undefined; | 36 | var 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 | } |
| 193 | 207 | ||
| 194 | pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { | 208 | pub 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 | } |
| 226 | 244 | ||
| 245 | pub 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 | |||
| 227 | pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { | 263 | pub 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 | } |
| 238 | 271 | ||
| 272 | fn 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 | |||
| 441 | const 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 | ||
| 452 | fn 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 | |||
| 490 | fn 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 | |||
| 239 | fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol { | 535 | fn 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 | } |
| 382 | 675 | ||
| 676 | fn 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 | |||
| 833 | fn 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 | |||
| 383 | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { | 850 | fn 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(); |
| 397 | 864 | ||
| 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(); |
| 400 | 867 | ||
| 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 | } |
| 595 | 1068 | ||
| 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 | }; |
| 608 | 1082 | ||
| 609 | const PcRange = struct { | 1083 | const 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 | } |
| 930 | 1404 | ||
| 931 | fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { | 1405 | fn 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 | } |
| 981 | 1455 | ||
| 982 | fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { | 1456 | fn 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 |
| 1202 | fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { | 1676 | fn 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); |
| 1204 | 1678 | ||
| 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; |
| 1384 | 1858 | ||
| 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; |
| 1387 | 1861 | ||
| 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 | } |
| 1449 | 1923 | ||
| 1450 | fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit { | 1924 | fn 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 | }; |
| 354 | 354 | ||
| 355 | pub const Elf = struct { | 355 | pub 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 | } |
| 377 | 377 | ||
| 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/733 | 149 | 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 |
| 151 | 151 | ||
| 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"); |
| 15 | pub const base64 = @import("base64.zig"); | 15 | pub const base64 = @import("base64.zig"); |
| 16 | pub const build = @import("build.zig"); | 16 | pub const build = @import("build.zig"); |
| 17 | pub const c = @import("c/index.zig"); | 17 | pub const c = @import("c/index.zig"); |
| 18 | pub const coff = @import("coff.zig"); | ||
| 18 | pub const crypto = @import("crypto/index.zig"); | 19 | pub const crypto = @import("crypto/index.zig"); |
| 19 | pub const cstr = @import("cstr.zig"); | 20 | pub const cstr = @import("cstr.zig"); |
| 20 | pub const debug = @import("debug/index.zig"); | 21 | pub 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"); |
| 33 | pub const mem = @import("mem.zig"); | 34 | pub const mem = @import("mem.zig"); |
| 34 | pub const net = @import("net.zig"); | 35 | pub const net = @import("net.zig"); |
| 35 | pub const os = @import("os/index.zig"); | 36 | pub const os = @import("os/index.zig"); |
| 37 | pub const pdb = @import("pdb.zig"); | ||
| 36 | pub const rand = @import("rand/index.zig"); | 38 | pub const rand = @import("rand/index.zig"); |
| 37 | pub const rb = @import("rb.zig"); | 39 | pub const rb = @import("rb.zig"); |
| 38 | pub const sort = @import("sort.zig"); | 40 | pub 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 { |
| 34 | 34 | ||
| 35 | /// Implementation of InStream trait for File | 35 | /// Implementation of InStream trait for File |
| 36 | pub const FileInStream = struct { | 36 | pub const FileInStream = struct { |
| 37 | file: *File, | 37 | file: File, |
| 38 | stream: Stream, | 38 | stream: Stream, |
| 39 | 39 | ||
| 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); |
| 42 | 42 | ||
| 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 { |
| 55 | 55 | ||
| 56 | /// Implementation of OutStream trait for File | 56 | /// Implementation of OutStream trait for File |
| 57 | pub const FileOutStream = struct { | 57 | pub const FileOutStream = struct { |
| 58 | file: *File, | 58 | file: File, |
| 59 | stream: Stream, | 59 | stream: Stream, |
| 60 | 60 | ||
| 61 | pub const Error = File.WriteError; | 61 | pub const Error = File.WriteError; |
| 62 | pub const Stream = OutStream(Error); | 62 | pub const Stream = OutStream(Error); |
| 63 | 63 | ||
| 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 { |
| 210 | 210 | ||
| 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); |
| 282 | 282 | ||
| 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(); |
| 594 | 594 | ||
| 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" { |
| 622 | 622 | ||
| 623 | pub fn readLine(buf: []u8) !usize { | 623 | pub 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(); |
| 21 | 21 | ||
| 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); |
| 37 | 37 | ||
| 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); |
| 211 | 211 | ||
| 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.?); |
| 214 | 214 | ||
| 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 | } |
| 62 | 56 | ||
| 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 | } |
| 89 | 88 | ||
| 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.PathAlreadyExists | 101 | /// 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 | } |
| 111 | 115 | ||
| 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 { |
| 190 | 205 | ||
| 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 | } |
| 197 | 211 | ||
| 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 | } |
| 202 | 216 | ||
| 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 | } |
| 233 | 247 | ||
| 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 | } |
| 266 | 281 | ||
| 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 | } |
| 302 | 317 | ||
| 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 | }; |
| 327 | 342 | ||
| 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 | }; |
| 361 | 376 | ||
| 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 { |
| 407 | 422 | ||
| 408 | pub const WriteError = os.WindowsWriteError || os.PosixWriteError; | 423 | pub const WriteError = os.WindowsWriteError || os.PosixWriteError; |
| 409 | 424 | ||
| 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; |
| 57 | pub const windowsWrite = windows_util.windowsWrite; | 57 | pub const windowsWrite = windows_util.windowsWrite; |
| 58 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; | 58 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; |
| 59 | pub const windowsOpen = windows_util.windowsOpen; | 59 | pub const windowsOpen = windows_util.windowsOpen; |
| 60 | pub const windowsOpenW = windows_util.windowsOpenW; | ||
| 60 | pub const windowsLoadDll = windows_util.windowsLoadDll; | 61 | pub const windowsLoadDll = windows_util.windowsLoadDll; |
| 61 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; | 62 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; |
| 62 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | 63 | pub 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 | } |
| 2069 | 2071 | ||
| 2070 | // TODO make this a build variable that you can set | 2072 | // TODO make this a build variable that you can set |
| 2071 | const unexpected_error_tracing = false; | 2073 | const unexpected_error_tracing = true; |
| 2072 | const UnexpectedError = error{ | 2074 | const 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 SetLastError | 2089 | /// 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. |
| 2089 | pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError { | 2091 | pub 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 | } |
| 2109 | 2117 | ||
| 2110 | test "openSelfExe" { | 2118 | test "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 OS | 2121 | else => return error.SkipZigTest, // Unsupported OS. |
| 2122 | } | ||
| 2123 | } | ||
| 2124 | |||
| 2125 | pub 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 | } |
| 2116 | 2137 | ||
| 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 cast | 2153 | 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; |
| 3 | 3 | ||
| 4 | pub use @import("advapi32.zig"); | 4 | pub use @import("advapi32.zig"); |
| 5 | pub use @import("kernel32.zig"); | 5 | pub use @import("kernel32.zig"); |
| 6 | pub use @import("ntdll.zig"); | ||
| 6 | pub use @import("ole32.zig"); | 7 | pub use @import("ole32.zig"); |
| 7 | pub use @import("shell32.zig"); | 8 | pub use @import("shell32.zig"); |
| 8 | pub use @import("shlwapi.zig"); | 9 | pub use @import("shlwapi.zig"); |
| ... | @@ -14,6 +15,7 @@ test "import" { | ... | @@ -14,6 +15,7 @@ test "import" { |
| 14 | 15 | ||
| 15 | pub const ERROR = @import("error.zig"); | 16 | pub const ERROR = @import("error.zig"); |
| 16 | 17 | ||
| 18 | pub const SHORT = c_short; | ||
| 17 | pub const BOOL = c_int; | 19 | pub const BOOL = c_int; |
| 18 | pub const BOOLEAN = BYTE; | 20 | pub const BOOLEAN = BYTE; |
| 19 | pub const BYTE = u8; | 21 | pub 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; |
| 363 | pub const FILE_FLAG_SESSION_AWARE = 0x00800000; | 365 | pub const FILE_FLAG_SESSION_AWARE = 0x00800000; |
| 364 | pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; | 366 | pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; |
| 365 | pub const FILE_FLAG_WRITE_THROUGH = 0x80000000; | 367 | pub const FILE_FLAG_WRITE_THROUGH = 0x80000000; |
| 368 | |||
| 369 | pub const SMALL_RECT = extern struct { | ||
| 370 | Left: SHORT, | ||
| 371 | Top: SHORT, | ||
| 372 | Right: SHORT, | ||
| 373 | Bottom: SHORT, | ||
| 374 | }; | ||
| 375 | |||
| 376 | pub 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; |
| 72 | 72 | ||
| 73 | pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL; | 73 | pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL; |
| 74 | 74 | ||
| 75 | pub extern "kernel32" stdcallcc fn GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) BOOL; | ||
| 76 | |||
| 75 | pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD; | 77 | pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD; |
| 76 | pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD; | 78 | pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD; |
| 77 | 79 | ||
| ... | @@ -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 |
| 92 | pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD; | 94 | pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD; |
| 93 | pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD; | 95 | pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD; |
| 94 | 96 | ||
| 97 | pub extern "kernel32" stdcallcc fn GetModuleHandleW(lpModuleName: ?[*]const WCHAR) HMODULE; | ||
| 98 | |||
| 95 | pub extern "kernel32" stdcallcc fn GetLastError() DWORD; | 99 | pub extern "kernel32" stdcallcc fn GetLastError() DWORD; |
| 96 | 100 | ||
| 97 | pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx( | 101 | pub 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( |
| 177 | 181 | ||
| 178 | pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL; | 182 | pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL; |
| 179 | 183 | ||
| 184 | pub extern "kernel32" stdcallcc fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) BOOL; | ||
| 185 | |||
| 180 | pub extern "kernel32" stdcallcc fn SetFilePointerEx( | 186 | pub 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; |
| 232 | pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2; | 238 | pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2; |
| 233 | pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1; | 239 | pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1; |
| 234 | pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4; | 240 | pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4; |
| 241 | |||
| 242 | |||
| 243 | pub 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 | |||
| 251 | pub const FOREGROUND_BLUE = 1; | ||
| 252 | pub const FOREGROUND_GREEN = 2; | ||
| 253 | pub const FOREGROUND_RED = 4; | ||
| 254 | pub const FOREGROUND_INTENSITY = 8; |
std/os/windows/ntdll.zig created+3| ... | @@ -0,0 +1,3 @@ | ||
| 1 | use @import("index.zig"); | ||
| 2 | |||
| 3 | pub 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 | }; |
| 120 | 120 | ||
| 121 | pub fn windowsOpen( | 121 | pub 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); | ||
| 131 | 129 | ||
| 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 | } |
| 148 | 146 | ||
| 147 | pub 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. |
| 150 | pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 { | 159 | pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 { |
| 151 | // count bytes needed | 160 | // count bytes needed |
std/pdb.zig created+646| ... | @@ -0,0 +1,646 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("index.zig"); | ||
| 3 | const io = std.io; | ||
| 4 | const math = std.math; | ||
| 5 | const mem = std.mem; | ||
| 6 | const os = std.os; | ||
| 7 | const warn = std.debug.warn; | ||
| 8 | const coff = std.coff; | ||
| 9 | |||
| 10 | const ArrayList = std.ArrayList; | ||
| 11 | |||
| 12 | // https://llvm.org/docs/PDB/DbiStream.html#stream-header | ||
| 13 | pub 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 | |||
| 36 | pub 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 | |||
| 48 | pub 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 | |||
| 66 | pub const SectionMapHeader = packed struct { | ||
| 67 | Count: u16, /// Number of segment descriptors | ||
| 68 | LogCount: u16, /// Number of logical segment descriptors | ||
| 69 | }; | ||
| 70 | |||
| 71 | pub 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 | |||
| 82 | pub 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. | ||
| 91 | pub 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 | |||
| 290 | pub const TypeIndex = u32; | ||
| 291 | |||
| 292 | pub 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 | |||
| 307 | pub 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 | |||
| 318 | pub const SectionContrSubstreamVersion = enum(u32) { | ||
| 319 | Ver60 = 0xeffe0000 + 19970605, | ||
| 320 | V2 = 0xeffe0000 + 20140516 | ||
| 321 | }; | ||
| 322 | |||
| 323 | pub const RecordPrefix = packed struct { | ||
| 324 | RecordLen: u16, /// Record length, starting from &RecordKind. | ||
| 325 | RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind) | ||
| 326 | }; | ||
| 327 | |||
| 328 | pub 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 | |||
| 335 | pub 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]; | ||
| 344 | pub 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 | |||
| 355 | pub 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 | |||
| 367 | pub const ColumnNumberEntry = packed struct { | ||
| 368 | StartColumn: u16, | ||
| 369 | EndColumn: u16, | ||
| 370 | }; | ||
| 371 | |||
| 372 | /// Checksum bytes follow. | ||
| 373 | pub 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 | |||
| 379 | pub 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 | |||
| 400 | pub const DebugSubsectionHeader = packed struct { | ||
| 401 | Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum | ||
| 402 | Length: u32, /// number of bytes occupied by this record. | ||
| 403 | }; | ||
| 404 | |||
| 405 | |||
| 406 | pub 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 | |||
| 412 | pub 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 | ||
| 442 | const 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 | |||
| 495 | fn 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 | ||
| 500 | const 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 | |||
| 542 | const 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 { |
| 49 | 49 | ||
| 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; |
| 56 | 56 | ||
| 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; |
| 1865 | 1865 | ||
| 1866 | fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 { | 1866 | fn 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; |
| 1869 | 1869 | ||
| 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.zig | 34 | \\// purposefully conflicting function with main.zig |
| 35 | \\// but it's private so it should be OK | 35 | \\// 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); |
| 265 | 265 | ||
| 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.?); |
| 268 | 268 | ||
| 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); |
| 580 | 580 | ||
| 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.?); |
| 583 | 583 | ||
| 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); |
| 844 | 844 | ||
| 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.?); |
| 847 | 847 | ||
| 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; |