| 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 | 444 | "c/index.zig" |
| 445 | 445 | "c/linux.zig" |
| 446 | 446 | "c/windows.zig" |
| 447 | "coff.zig" | |
| 447 | 448 | "crypto/blake2.zig" |
| 448 | 449 | "crypto/hmac.zig" |
| 449 | 450 | "crypto/index.zig" |
| ... | ... | @@ -577,12 +578,14 @@ set(ZIG_STD_FILES |
| 577 | 578 | "os/windows/error.zig" |
| 578 | 579 | "os/windows/index.zig" |
| 579 | 580 | "os/windows/kernel32.zig" |
| 581 | "os/windows/ntdll.zig" | |
| 580 | 582 | "os/windows/ole32.zig" |
| 581 | 583 | "os/windows/shell32.zig" |
| 582 | 584 | "os/windows/shlwapi.zig" |
| 583 | 585 | "os/windows/user32.zig" |
| 584 | 586 | "os/windows/util.zig" |
| 585 | 587 | "os/zen.zig" |
| 588 | "pdb.zig" | |
| 586 | 589 | "rand/index.zig" |
| 587 | 590 | "rand/ziggurat.zig" |
| 588 | 591 | "segmented_list.zig" |
doc/docgen.zig+2-2| ... | ... | @@ -40,11 +40,11 @@ pub fn main() !void { |
| 40 | 40 | var out_file = try os.File.openWrite(out_file_name); |
| 41 | 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 | 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 | 48 | var buffered_out_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream); |
| 49 | 49 | |
| 50 | 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 | 6 | |
| 7 | 7 | pub fn main() !void { |
| 8 | 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 | 10 | const stdout = &stdout_file_stream.stream; |
| 11 | 11 | |
| 12 | 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 | 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 | 276 | const color_on = switch (color) { |
| 277 | 277 | Color.Auto => file.isTty(), |
| 278 | 278 | Color.On => true, |
src-self-hosted/main.zig+6-6| ... | ... | @@ -55,11 +55,11 @@ pub fn main() !void { |
| 55 | 55 | const allocator = std.heap.c_allocator; |
| 56 | 56 | |
| 57 | 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 | 59 | stdout = &stdout_out_stream.stream; |
| 60 | 60 | |
| 61 | 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 | 63 | stderr = &stderr_out_stream.stream; |
| 64 | 64 | |
| 65 | 65 | const args = try os.argsAlloc(allocator); |
| ... | ... | @@ -491,7 +491,7 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { |
| 491 | 491 | stderr.print("Build {} compile errors:\n", count) catch os.exit(1); |
| 492 | 492 | for (msgs) |msg| { |
| 493 | 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 | 619 | } |
| 620 | 620 | |
| 621 | 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 | 624 | const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size); |
| 625 | 625 | defer allocator.free(source_code); |
| ... | ... | @@ -635,7 +635,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 635 | 635 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>"); |
| 636 | 636 | defer msg.destroy(); |
| 637 | 637 | |
| 638 | try msg.printToFile(&stderr_file, color); | |
| 638 | try msg.printToFile(stderr_file, color); | |
| 639 | 639 | } |
| 640 | 640 | if (tree.errors.len != 0) { |
| 641 | 641 | os.exit(1); |
| ... | ... | @@ -772,7 +772,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void { |
| 772 | 772 | const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path); |
| 773 | 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 | 777 | if (tree.errors.len != 0) { |
| 778 | 778 | fmt.any_error = true; |
src-self-hosted/test.zig+2-2| ... | ... | @@ -185,7 +185,7 @@ pub const TestContext = struct { |
| 185 | 185 | try stderr.write("build incorrectly failed:\n"); |
| 186 | 186 | for (msgs) |msg| { |
| 187 | 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 | 234 | var stderr = try std.io.getStdErr(); |
| 235 | 235 | for (msgs) |msg| { |
| 236 | 236 | defer msg.destroy(); |
| 237 | try msg.printToFile(&stderr, errmsg.Color.Auto); | |
| 237 | try msg.printToFile(stderr, errmsg.Color.Auto); | |
| 238 | 238 | } |
| 239 | 239 | std.debug.warn("============\n"); |
| 240 | 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 | 4 | const io = std.io; |
| 5 | 5 | const os = std.os; |
| 6 | 6 | const elf = std.elf; |
| 7 | const macho = std.macho; | |
| 8 | 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 | 12 | const ArrayList = std.ArrayList; |
| 10 | 13 | const builtin = @import("builtin"); |
| 11 | 14 | |
| ... | ... | @@ -17,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) { |
| 17 | 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 | 34 | /// Tries to write to stderr, unbuffered, and ignores any error returned. |
| 21 | 35 | /// Does not append a newline. |
| 22 | 36 | var stderr_file: os.File = undefined; |
| ... | ... | @@ -37,7 +51,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) { |
| 37 | 51 | return st; |
| 38 | 52 | } else { |
| 39 | 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 | 55 | const st = &stderr_file_out_stream.stream; |
| 42 | 56 | stderr_stream = st; |
| 43 | 57 | return st; |
| ... | ... | @@ -70,7 +84,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 70 | 84 | stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return; |
| 71 | 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 | 88 | stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return; |
| 75 | 89 | return; |
| 76 | 90 | }; |
| ... | ... | @@ -191,7 +205,11 @@ pub inline fn getReturnAddress(frame_count: usize) usize { |
| 191 | 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 | 213 | const AddressState = union(enum) { |
| 196 | 214 | NotLookingForStartAddress, |
| 197 | 215 | LookingForStartAddress: usize, |
| ... | ... | @@ -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 | 263 | pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { |
| 228 | 264 | switch (builtin.os) { |
| 229 | 265 | builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color), |
| 230 | 266 | builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color), |
| 231 | builtin.Os.windows => { | |
| 232 | // TODO https://github.com/ziglang/zig/issues/721 | |
| 233 | return error.UnsupportedOperatingSystem; | |
| 234 | }, | |
| 267 | builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color), | |
| 235 | 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 | 535 | fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol { |
| 240 | 536 | var min: usize = 0; |
| 241 | 537 | var max: usize = symbols.len - 1; // Exclude sentinel. |
| ... | ... | @@ -372,14 +668,185 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { |
| 372 | 668 | switch (builtin.os) { |
| 373 | 669 | builtin.Os.linux => return openSelfDebugInfoLinux(allocator), |
| 374 | 670 | builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator), |
| 375 | builtin.Os.windows => { | |
| 376 | // TODO: https://github.com/ziglang/zig/issues/721 | |
| 377 | return error.UnsupportedOperatingSystem; | |
| 378 | }, | |
| 671 | builtin.Os.windows => return openSelfDebugInfoWindows(allocator), | |
| 379 | 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 | 850 | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { |
| 384 | 851 | var di = DebugInfo{ |
| 385 | 852 | .self_exe_file = undefined, |
| ... | ... | @@ -395,7 +862,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { |
| 395 | 862 | di.self_exe_file = try os.openSelfExe(); |
| 396 | 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 | 866 | errdefer di.elf.close(); |
| 400 | 867 | |
| 401 | 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 | 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 | 1055 | self_exe_file: os.File, |
| 583 | 1056 | elf: elf.Elf, |
| 584 | 1057 | debug_info: *elf.SectionHeader, |
| ... | ... | @@ -594,7 +1067,7 @@ pub const DebugInfo = switch (builtin.os) { |
| 594 | 1067 | } |
| 595 | 1068 | |
| 596 | 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 | 1071 | const in_stream = &in_file_stream.stream; |
| 599 | 1072 | return readStringRaw(self.allocator(), in_stream); |
| 600 | 1073 | } |
| ... | ... | @@ -604,6 +1077,7 @@ pub const DebugInfo = switch (builtin.os) { |
| 604 | 1077 | self.elf.close(); |
| 605 | 1078 | } |
| 606 | 1079 | }, |
| 1080 | else => @compileError("Unsupported OS"), | |
| 607 | 1081 | }; |
| 608 | 1082 | |
| 609 | 1083 | const PcRange = struct { |
| ... | ... | @@ -929,7 +1403,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 |
| 929 | 1403 | } |
| 930 | 1404 | |
| 931 | 1405 | fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { |
| 932 | const in_file = &st.self_exe_file; | |
| 1406 | const in_file = st.self_exe_file; | |
| 933 | 1407 | var in_file_stream = io.FileInStream.init(in_file); |
| 934 | 1408 | const in_stream = &in_file_stream.stream; |
| 935 | 1409 | var result = AbbrevTable.init(st.allocator()); |
| ... | ... | @@ -980,7 +1454,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con |
| 980 | 1454 | } |
| 981 | 1455 | |
| 982 | 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 | 1458 | var in_file_stream = io.FileInStream.init(in_file); |
| 985 | 1459 | const in_stream = &in_file_stream.stream; |
| 986 | 1460 | const abbrev_code = try readULeb128(in_stream); |
| ... | ... | @@ -1202,7 +1676,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u |
| 1202 | 1676 | fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { |
| 1203 | 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 | 1680 | const debug_line_end = di.debug_line.offset + di.debug_line.size; |
| 1207 | 1681 | var this_offset = di.debug_line.offset; |
| 1208 | 1682 | var this_index: usize = 0; |
| ... | ... | @@ -1382,7 +1856,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { |
| 1382 | 1856 | var this_unit_offset = st.debug_info.offset; |
| 1383 | 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 | 1860 | const in_stream = &in_file_stream.stream; |
| 1387 | 1861 | |
| 1388 | 1862 | while (this_unit_offset < debug_info_end) { |
| ... | ... | @@ -1448,7 +1922,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { |
| 1448 | 1922 | } |
| 1449 | 1923 | |
| 1450 | 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 | 1926 | const in_stream = &in_file_stream.stream; |
| 1453 | 1927 | for (st.compile_unit_list.toSlice()) |*compile_unit| { |
| 1454 | 1928 | if (compile_unit.pc_range) |range| { |
std/elf.zig+2-2| ... | ... | @@ -353,7 +353,7 @@ pub const SectionHeader = struct { |
| 353 | 353 | }; |
| 354 | 354 | |
| 355 | 355 | pub const Elf = struct { |
| 356 | in_file: *os.File, | |
| 356 | in_file: os.File, | |
| 357 | 357 | auto_close_stream: bool, |
| 358 | 358 | is_64: bool, |
| 359 | 359 | endian: builtin.Endian, |
| ... | ... | @@ -376,7 +376,7 @@ pub const Elf = struct { |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | 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 | 380 | elf.allocator = allocator; |
| 381 | 381 | elf.in_file = file; |
| 382 | 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 | 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 | 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 | 153 | var stream = &adapter.stream; |
| 154 | 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 | 15 | pub const base64 = @import("base64.zig"); |
| 16 | 16 | pub const build = @import("build.zig"); |
| 17 | 17 | pub const c = @import("c/index.zig"); |
| 18 | pub const coff = @import("coff.zig"); | |
| 18 | 19 | pub const crypto = @import("crypto/index.zig"); |
| 19 | 20 | pub const cstr = @import("cstr.zig"); |
| 20 | 21 | pub const debug = @import("debug/index.zig"); |
| ... | ... | @@ -33,6 +34,7 @@ pub const math = @import("math/index.zig"); |
| 33 | 34 | pub const mem = @import("mem.zig"); |
| 34 | 35 | pub const net = @import("net.zig"); |
| 35 | 36 | pub const os = @import("os/index.zig"); |
| 37 | pub const pdb = @import("pdb.zig"); | |
| 36 | 38 | pub const rand = @import("rand/index.zig"); |
| 37 | 39 | pub const rb = @import("rb.zig"); |
| 38 | 40 | pub const sort = @import("sort.zig"); |
| ... | ... | @@ -56,6 +58,7 @@ test "std" { |
| 56 | 58 | _ = @import("base64.zig"); |
| 57 | 59 | _ = @import("build.zig"); |
| 58 | 60 | _ = @import("c/index.zig"); |
| 61 | _ = @import("coff.zig"); | |
| 59 | 62 | _ = @import("crypto/index.zig"); |
| 60 | 63 | _ = @import("cstr.zig"); |
| 61 | 64 | _ = @import("debug/index.zig"); |
| ... | ... | @@ -74,6 +77,7 @@ test "std" { |
| 74 | 77 | _ = @import("heap.zig"); |
| 75 | 78 | _ = @import("os/index.zig"); |
| 76 | 79 | _ = @import("rand/index.zig"); |
| 80 | _ = @import("pdb.zig"); | |
| 77 | 81 | _ = @import("sort.zig"); |
| 78 | 82 | _ = @import("unicode.zig"); |
| 79 | 83 | _ = @import("zig/index.zig"); |
std/io.zig+8-8| ... | ... | @@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File { |
| 34 | 34 | |
| 35 | 35 | /// Implementation of InStream trait for File |
| 36 | 36 | pub const FileInStream = struct { |
| 37 | file: *File, | |
| 37 | file: File, | |
| 38 | 38 | stream: Stream, |
| 39 | 39 | |
| 40 | 40 | pub const Error = @typeOf(File.read).ReturnType.ErrorSet; |
| 41 | 41 | pub const Stream = InStream(Error); |
| 42 | 42 | |
| 43 | pub fn init(file: *File) FileInStream { | |
| 43 | pub fn init(file: File) FileInStream { | |
| 44 | 44 | return FileInStream{ |
| 45 | 45 | .file = file, |
| 46 | 46 | .stream = Stream{ .readFn = readFn }, |
| ... | ... | @@ -55,13 +55,13 @@ pub const FileInStream = struct { |
| 55 | 55 | |
| 56 | 56 | /// Implementation of OutStream trait for File |
| 57 | 57 | pub const FileOutStream = struct { |
| 58 | file: *File, | |
| 58 | file: File, | |
| 59 | 59 | stream: Stream, |
| 60 | 60 | |
| 61 | 61 | pub const Error = File.WriteError; |
| 62 | 62 | pub const Stream = OutStream(Error); |
| 63 | 63 | |
| 64 | pub fn init(file: *File) FileOutStream { | |
| 64 | pub fn init(file: File) FileOutStream { | |
| 65 | 65 | return FileOutStream{ |
| 66 | 66 | .file = file, |
| 67 | 67 | .stream = Stream{ .writeFn = writeFn }, |
| ... | ... | @@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type { |
| 210 | 210 | |
| 211 | 211 | pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void { |
| 212 | 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 | 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 | 280 | const buf = try allocator.alignedAlloc(u8, A, size); |
| 281 | 281 | errdefer allocator.free(buf); |
| 282 | 282 | |
| 283 | var adapter = FileInStream.init(&file); | |
| 283 | var adapter = FileInStream.init(file); | |
| 284 | 284 | try adapter.stream.readNoEof(buf[0..size]); |
| 285 | 285 | return buf; |
| 286 | 286 | } |
| ... | ... | @@ -592,7 +592,7 @@ pub const BufferedAtomicFile = struct { |
| 592 | 592 | self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.File.default_mode); |
| 593 | 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 | 596 | self.buffered_stream = BufferedOutStream(FileOutStream.Error).init(&self.file_stream.stream); |
| 597 | 597 | return self; |
| 598 | 598 | } |
| ... | ... | @@ -622,7 +622,7 @@ test "import io tests" { |
| 622 | 622 | |
| 623 | 623 | pub fn readLine(buf: []u8) !usize { |
| 624 | 624 | var stdin = getStdIn() catch return error.StdInUnavailable; |
| 625 | var adapter = FileInStream.init(&stdin); | |
| 625 | var adapter = FileInStream.init(stdin); | |
| 626 | 626 | var stream = &adapter.stream; |
| 627 | 627 | var index: usize = 0; |
| 628 | 628 | while (true) { |
std/io_test.zig+2-2| ... | ... | @@ -19,7 +19,7 @@ test "write a file, read it, then delete it" { |
| 19 | 19 | var file = try os.File.openWrite(tmp_file_name); |
| 20 | 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 | 23 | var buf_stream = io.BufferedOutStream(io.FileOutStream.Error).init(&file_out_stream.stream); |
| 24 | 24 | const st = &buf_stream.stream; |
| 25 | 25 | try st.print("begin"); |
| ... | ... | @@ -35,7 +35,7 @@ test "write a file, read it, then delete it" { |
| 35 | 35 | const expected_file_size = "begin".len + data.len + "end".len; |
| 36 | 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 | 39 | var buf_stream = io.BufferedInStream(io.FileInStream.Error).init(&file_in_stream.stream); |
| 40 | 40 | const st = &buf_stream.stream; |
| 41 | 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 | 209 | defer Buffer.deinit(&stdout); |
| 210 | 210 | defer Buffer.deinit(&stderr); |
| 211 | 211 | |
| 212 | var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); | |
| 213 | var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); | |
| 212 | var stdout_file_in_stream = io.FileInStream.init(child.stdout.?); | |
| 213 | var stderr_file_in_stream = io.FileInStream.init(child.stderr.?); | |
| 214 | 214 | |
| 215 | 215 | try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); |
| 216 | 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 | 48 | return openReadC(&path_c); |
| 49 | 49 | } |
| 50 | 50 | if (is_windows) { |
| 51 | const handle = try os.windowsOpen( | |
| 52 | path, | |
| 53 | windows.GENERIC_READ, | |
| 54 | windows.FILE_SHARE_READ, | |
| 55 | windows.OPEN_EXISTING, | |
| 56 | windows.FILE_ATTRIBUTE_NORMAL, | |
| 57 | ); | |
| 58 | return openHandle(handle); | |
| 51 | const path_w = try windows_util.sliceToPrefixedFileW(path); | |
| 52 | return openReadW(&path_w); | |
| 59 | 53 | } |
| 60 | 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 | 68 | /// Calls `openWriteMode` with os.File.default_mode for the mode. |
| 64 | 69 | pub fn openWrite(path: []const u8) OpenError!File { |
| 65 | 70 | return openWriteMode(path, os.File.default_mode); |
| ... | ... | @@ -74,19 +79,24 @@ pub const File = struct { |
| 74 | 79 | const fd = try os.posixOpen(path, flags, file_mode); |
| 75 | 80 | return openHandle(fd); |
| 76 | 81 | } else if (is_windows) { |
| 77 | const handle = try os.windowsOpen( | |
| 78 | path, | |
| 79 | windows.GENERIC_WRITE, | |
| 80 | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE, | |
| 81 | windows.CREATE_ALWAYS, | |
| 82 | windows.FILE_ATTRIBUTE_NORMAL, | |
| 83 | ); | |
| 84 | return openHandle(handle); | |
| 82 | const path_w = try windows_util.sliceToPrefixedFileW(path); | |
| 83 | return openWriteModeW(&path_w, file_mode); | |
| 85 | 84 | } else { |
| 86 | 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 | 100 | /// If the path does not exist it will be created. |
| 91 | 101 | /// If a file already exists in the destination this returns OpenError.PathAlreadyExists |
| 92 | 102 | /// Call close to clean up. |
| ... | ... | @@ -96,19 +106,24 @@ pub const File = struct { |
| 96 | 106 | const fd = try os.posixOpen(path, flags, file_mode); |
| 97 | 107 | return openHandle(fd); |
| 98 | 108 | } else if (is_windows) { |
| 99 | const handle = try os.windowsOpen( | |
| 100 | path, | |
| 101 | windows.GENERIC_WRITE, | |
| 102 | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE, | |
| 103 | windows.CREATE_NEW, | |
| 104 | windows.FILE_ATTRIBUTE_NORMAL, | |
| 105 | ); | |
| 106 | return openHandle(handle); | |
| 109 | const path_w = try windows_util.sliceToPrefixedFileW(path); | |
| 110 | return openWriteNoClobberW(&path_w, file_mode); | |
| 107 | 111 | } else { |
| 108 | 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 | 127 | pub fn openHandle(handle: os.FileHandle) File { |
| 113 | 128 | return File{ .handle = handle }; |
| 114 | 129 | } |
| ... | ... | @@ -190,17 +205,16 @@ pub const File = struct { |
| 190 | 205 | |
| 191 | 206 | /// Upon success, the stream is in an uninitialized state. To continue using it, |
| 192 | 207 | /// you must use the open() function. |
| 193 | pub fn close(self: *File) void { | |
| 208 | pub fn close(self: File) void { | |
| 194 | 209 | os.close(self.handle); |
| 195 | self.handle = undefined; | |
| 196 | 210 | } |
| 197 | 211 | |
| 198 | 212 | /// Calls `os.isTty` on `self.handle`. |
| 199 | pub fn isTty(self: *File) bool { | |
| 213 | pub fn isTty(self: File) bool { | |
| 200 | 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 | 218 | switch (builtin.os) { |
| 205 | 219 | Os.linux, Os.macosx, Os.ios => { |
| 206 | 220 | const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); |
| ... | ... | @@ -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 | 249 | switch (builtin.os) { |
| 236 | 250 | Os.linux, Os.macosx, Os.ios => { |
| 237 | 251 | const ipos = try math.cast(isize, pos); |
| ... | ... | @@ -256,6 +270,7 @@ pub const File = struct { |
| 256 | 270 | const err = windows.GetLastError(); |
| 257 | 271 | return switch (err) { |
| 258 | 272 | windows.ERROR.INVALID_PARAMETER => unreachable, |
| 273 | windows.ERROR.INVALID_HANDLE => unreachable, | |
| 259 | 274 | else => os.unexpectedErrorWindows(err), |
| 260 | 275 | }; |
| 261 | 276 | } |
| ... | ... | @@ -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 | 283 | switch (builtin.os) { |
| 269 | 284 | Os.linux, Os.macosx, Os.ios => { |
| 270 | 285 | const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); |
| ... | ... | @@ -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 | 319 | if (is_posix) { |
| 305 | 320 | const stat = try os.posixFStat(self.handle); |
| 306 | 321 | return @intCast(usize, stat.size); |
| ... | ... | @@ -325,7 +340,7 @@ pub const File = struct { |
| 325 | 340 | Unexpected, |
| 326 | 341 | }; |
| 327 | 342 | |
| 328 | pub fn mode(self: *File) ModeError!Mode { | |
| 343 | pub fn mode(self: File) ModeError!Mode { | |
| 329 | 344 | if (is_posix) { |
| 330 | 345 | var stat: posix.Stat = undefined; |
| 331 | 346 | const err = posix.getErrno(posix.fstat(self.handle, &stat)); |
| ... | ... | @@ -359,7 +374,7 @@ pub const File = struct { |
| 359 | 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 | 378 | if (is_posix) { |
| 364 | 379 | var index: usize = 0; |
| 365 | 380 | while (index < buffer.len) { |
| ... | ... | @@ -407,7 +422,7 @@ pub const File = struct { |
| 407 | 422 | |
| 408 | 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 | 426 | if (is_posix) { |
| 412 | 427 | try os.posixWrite(self.handle, bytes); |
| 413 | 428 | } else if (is_windows) { |
std/os/index.zig+26-14| ... | ... | @@ -57,6 +57,7 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle; |
| 57 | 57 | pub const windowsWrite = windows_util.windowsWrite; |
| 58 | 58 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; |
| 59 | 59 | pub const windowsOpen = windows_util.windowsOpen; |
| 60 | pub const windowsOpenW = windows_util.windowsOpenW; | |
| 60 | 61 | pub const windowsLoadDll = windows_util.windowsLoadDll; |
| 61 | 62 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; |
| 62 | 63 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; |
| ... | ... | @@ -660,6 +661,7 @@ pub fn getBaseAddress() usize { |
| 660 | 661 | return phdr - @sizeOf(ElfHeader); |
| 661 | 662 | }, |
| 662 | 663 | builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header), |
| 664 | builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), | |
| 663 | 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 | 2070 | } |
| 2069 | 2071 | |
| 2070 | 2072 | // TODO make this a build variable that you can set |
| 2071 | const unexpected_error_tracing = false; | |
| 2073 | const unexpected_error_tracing = true; | |
| 2072 | 2074 | const UnexpectedError = error{ |
| 2073 | 2075 | /// The Operating System returned an undocumented error code. |
| 2074 | 2076 | Unexpected, |
| ... | ... | @@ -2087,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError { |
| 2087 | 2089 | /// Call this when you made a windows DLL call or something that does SetLastError |
| 2088 | 2090 | /// and you get an unexpected error. |
| 2089 | 2091 | pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError { |
| 2090 | if (true) { | |
| 2092 | if (unexpected_error_tracing) { | |
| 2091 | 2093 | debug.warn("unexpected GetLastError(): {}\n", err); |
| 2094 | @breakpoint(); | |
| 2092 | 2095 | debug.dumpCurrentStackTrace(null); |
| 2093 | 2096 | } |
| 2094 | 2097 | return error.Unexpected; |
| ... | ... | @@ -2103,15 +2106,33 @@ pub fn openSelfExe() !os.File { |
| 2103 | 2106 | buf[self_exe_path.len] = 0; |
| 2104 | 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 | 2114 | else => @compileError("Unsupported OS"), |
| 2107 | 2115 | } |
| 2108 | 2116 | } |
| 2109 | 2117 | |
| 2110 | 2118 | test "openSelfExe" { |
| 2111 | 2119 | switch (builtin.os) { |
| 2112 | Os.linux, Os.macosx, Os.ios => (try openSelfExe()).close(), | |
| 2113 | else => return error.SkipZigTest, // Unsupported OS | |
| 2120 | Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(), | |
| 2121 | else => return error.SkipZigTest, // Unsupported OS. | |
| 2122 | } | |
| 2123 | } | |
| 2124 | ||
| 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 | 2138 | /// Get the path to the current executable. |
| ... | ... | @@ -2129,16 +2150,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 2129 | 2150 | Os.linux => return readLink(out_buffer, "/proc/self/exe"), |
| 2130 | 2151 | Os.windows => { |
| 2131 | 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 | |
| 2133 | const rc = windows.GetModuleFileNameW(null, &utf16le_buf, casted_len); | |
| 2134 | assert(rc <= utf16le_buf.len); | |
| 2135 | if (rc == 0) { | |
| 2136 | const err = windows.GetLastError(); | |
| 2137 | switch (err) { | |
| 2138 | else => return unexpectedErrorWindows(err), | |
| 2139 | } | |
| 2140 | } | |
| 2141 | const utf16le_slice = utf16le_buf[0..rc]; | |
| 2153 | const utf16le_slice = try selfExePathW(&utf16le_buf); | |
| 2142 | 2154 | // Trust that Windows gives us valid UTF-16LE. |
| 2143 | 2155 | const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable; |
| 2144 | 2156 | return out_buffer[0..end_index]; |
std/os/windows/index.zig+14| ... | ... | @@ -3,6 +3,7 @@ const assert = std.debug.assert; |
| 3 | 3 | |
| 4 | 4 | pub use @import("advapi32.zig"); |
| 5 | 5 | pub use @import("kernel32.zig"); |
| 6 | pub use @import("ntdll.zig"); | |
| 6 | 7 | pub use @import("ole32.zig"); |
| 7 | 8 | pub use @import("shell32.zig"); |
| 8 | 9 | pub use @import("shlwapi.zig"); |
| ... | ... | @@ -14,6 +15,7 @@ test "import" { |
| 14 | 15 | |
| 15 | 16 | pub const ERROR = @import("error.zig"); |
| 16 | 17 | |
| 18 | pub const SHORT = c_short; | |
| 17 | 19 | pub const BOOL = c_int; |
| 18 | 20 | pub const BOOLEAN = BYTE; |
| 19 | 21 | pub const BYTE = u8; |
| ... | ... | @@ -363,3 +365,15 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000; |
| 363 | 365 | pub const FILE_FLAG_SESSION_AWARE = 0x00800000; |
| 364 | 366 | pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; |
| 365 | 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 | 72 | |
| 73 | 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 | 77 | pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD; |
| 76 | 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 | 94 | pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: [*]u8, nSize: DWORD) DWORD; |
| 93 | 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 | 99 | pub extern "kernel32" stdcallcc fn GetLastError() DWORD; |
| 96 | 100 | |
| 97 | 101 | pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx( |
| ... | ... | @@ -177,6 +181,8 @@ pub extern "kernel32" stdcallcc fn ReadFile( |
| 177 | 181 | |
| 178 | 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 | 186 | pub extern "kernel32" stdcallcc fn SetFilePointerEx( |
| 181 | 187 | in_fFile: HANDLE, |
| 182 | 188 | in_liDistanceToMove: LARGE_INTEGER, |
| ... | ... | @@ -232,3 +238,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16; |
| 232 | 238 | pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2; |
| 233 | 239 | pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1; |
| 234 | 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 | 118 | Unexpected, |
| 119 | 119 | }; |
| 120 | 120 | |
| 121 | pub fn windowsOpen( | |
| 122 | file_path: []const u8, | |
| 121 | pub fn windowsOpenW( | |
| 122 | file_path_w: [*]const u16, | |
| 123 | 123 | desired_access: windows.DWORD, |
| 124 | 124 | share_mode: windows.DWORD, |
| 125 | 125 | creation_disposition: windows.DWORD, |
| 126 | 126 | flags_and_attrs: windows.DWORD, |
| 127 | 127 | ) OpenError!windows.HANDLE { |
| 128 | const file_path_w = try sliceToPrefixedFileW(file_path); | |
| 129 | ||
| 130 | const result = windows.CreateFileW(&file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null); | |
| 128 | const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null); | |
| 131 | 129 | |
| 132 | 130 | if (result == windows.INVALID_HANDLE_VALUE) { |
| 133 | 131 | const err = windows.GetLastError(); |
| ... | ... | @@ -146,6 +144,17 @@ pub fn windowsOpen( |
| 146 | 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 | 158 | /// Caller must free result. |
| 150 | 159 | pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 { |
| 151 | 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 | 49 | |
| 50 | 50 | var stderr_file = io.getStdErr(); |
| 51 | 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 | 53 | stderr_file_stream = io.FileOutStream.init(f); |
| 54 | 54 | break :x &stderr_file_stream.stream; |
| 55 | 55 | } else |err| err; |
| 56 | 56 | |
| 57 | 57 | var stdout_file = io.getStdOut(); |
| 58 | 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 | 60 | stdout_file_stream = io.FileOutStream.init(f); |
| 61 | 61 | break :x &stdout_file_stream.stream; |
| 62 | 62 | } else |err| err; |
std/zig/parser_test.zig+1-1| ... | ... | @@ -1865,7 +1865,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined; |
| 1865 | 1865 | |
| 1866 | 1866 | fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 { |
| 1867 | 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 | 1870 | var tree = try std.zig.parse(allocator, source); |
| 1871 | 1871 | defer tree.deinit(); |
test/compare_output.zig+15-15| ... | ... | @@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 19 | 19 | \\ |
| 20 | 20 | \\pub fn main() void { |
| 21 | 21 | \\ privateFunction(); |
| 22 | \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream); | |
| 22 | \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream; | |
| 23 | 23 | \\ stdout.print("OK 2\n") catch unreachable; |
| 24 | 24 | \\} |
| 25 | 25 | \\ |
| ... | ... | @@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 34 | 34 | \\// purposefully conflicting function with main.zig |
| 35 | 35 | \\// but it's private so it should be OK |
| 36 | 36 | \\fn privateFunction() void { |
| 37 | \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream); | |
| 37 | \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream; | |
| 38 | 38 | \\ stdout.print("OK 1\n") catch unreachable; |
| 39 | 39 | \\} |
| 40 | 40 | \\ |
| ... | ... | @@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 60 | 60 | tc.addSourceFile("foo.zig", |
| 61 | 61 | \\use @import("std").io; |
| 62 | 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 | 64 | \\ stdout.print("OK\n") catch unreachable; |
| 65 | 65 | \\} |
| 66 | 66 | ); |
| ... | ... | @@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 71 | 71 | \\ |
| 72 | 72 | \\pub fn bar_function() void { |
| 73 | 73 | \\ if (foo_function()) { |
| 74 | \\ const stdout = &(FileOutStream.init(&(getStdOut() catch unreachable)).stream); | |
| 74 | \\ const stdout = &FileOutStream.init(getStdOut() catch unreachable).stream; | |
| 75 | 75 | \\ stdout.print("OK\n") catch unreachable; |
| 76 | 76 | \\ } |
| 77 | 77 | \\} |
| ... | ... | @@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 103 | 103 | \\pub const a_text = "OK\n"; |
| 104 | 104 | \\ |
| 105 | 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 | 107 | \\ stdout.print(b_text) catch unreachable; |
| 108 | 108 | \\} |
| 109 | 109 | ); |
| ... | ... | @@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 121 | 121 | \\const io = @import("std").io; |
| 122 | 122 | \\ |
| 123 | 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 | 125 | \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable; |
| 126 | 126 | \\} |
| 127 | 127 | , "Hello, world!\n0012 012 a\n"); |
| ... | ... | @@ -274,7 +274,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 274 | 274 | \\ var x_local : i32 = print_ok(x); |
| 275 | 275 | \\} |
| 276 | 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 | 278 | \\ stdout.print("OK\n") catch unreachable; |
| 279 | 279 | \\ return 0; |
| 280 | 280 | \\} |
| ... | ... | @@ -356,7 +356,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 356 | 356 | \\pub fn main() void { |
| 357 | 357 | \\ const bar = Bar {.field2 = 13,}; |
| 358 | 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 | 360 | \\ if (!foo.method()) { |
| 361 | 361 | \\ stdout.print("BAD\n") catch unreachable; |
| 362 | 362 | \\ } |
| ... | ... | @@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 370 | 370 | cases.add("defer with only fallthrough", |
| 371 | 371 | \\const io = @import("std").io; |
| 372 | 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 | 374 | \\ stdout.print("before\n") catch unreachable; |
| 375 | 375 | \\ defer stdout.print("defer1\n") catch unreachable; |
| 376 | 376 | \\ defer stdout.print("defer2\n") catch unreachable; |
| ... | ... | @@ -383,7 +383,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 383 | 383 | \\const io = @import("std").io; |
| 384 | 384 | \\const os = @import("std").os; |
| 385 | 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 | 387 | \\ stdout.print("before\n") catch unreachable; |
| 388 | 388 | \\ defer stdout.print("defer1\n") catch unreachable; |
| 389 | 389 | \\ defer stdout.print("defer2\n") catch unreachable; |
| ... | ... | @@ -400,7 +400,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 400 | 400 | \\ do_test() catch return; |
| 401 | 401 | \\} |
| 402 | 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 | 404 | \\ stdout.print("before\n") catch unreachable; |
| 405 | 405 | \\ defer stdout.print("defer1\n") catch unreachable; |
| 406 | 406 | \\ errdefer stdout.print("deferErr\n") catch unreachable; |
| ... | ... | @@ -419,7 +419,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 419 | 419 | \\ do_test() catch return; |
| 420 | 420 | \\} |
| 421 | 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 | 423 | \\ stdout.print("before\n") catch unreachable; |
| 424 | 424 | \\ defer stdout.print("defer1\n") catch unreachable; |
| 425 | 425 | \\ errdefer stdout.print("deferErr\n") catch unreachable; |
| ... | ... | @@ -436,7 +436,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 436 | 436 | \\const io = @import("std").io; |
| 437 | 437 | \\ |
| 438 | 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 | 440 | \\ stdout.print(foo_txt) catch unreachable; |
| 441 | 441 | \\} |
| 442 | 442 | , "1234\nabcd\n"); |
| ... | ... | @@ -456,7 +456,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 456 | 456 | \\pub fn main() !void { |
| 457 | 457 | \\ var args_it = os.args(); |
| 458 | 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 | 460 | \\ const stdout = &stdout_adapter.stream; |
| 461 | 461 | \\ var index: usize = 0; |
| 462 | 462 | \\ _ = args_it.skip(); |
| ... | ... | @@ -497,7 +497,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 497 | 497 | \\pub fn main() !void { |
| 498 | 498 | \\ var args_it = os.args(); |
| 499 | 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 | 501 | \\ const stdout = &stdout_adapter.stream; |
| 502 | 502 | \\ var index: usize = 0; |
| 503 | 503 | \\ _ = args_it.skip(); |
test/tests.zig+6-6| ... | ... | @@ -263,8 +263,8 @@ pub const CompareOutputContext = struct { |
| 263 | 263 | var stdout = Buffer.initNull(b.allocator); |
| 264 | 264 | var stderr = Buffer.initNull(b.allocator); |
| 265 | 265 | |
| 266 | var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); | |
| 267 | var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); | |
| 266 | var stdout_file_in_stream = io.FileInStream.init(child.stdout.?); | |
| 267 | var stderr_file_in_stream = io.FileInStream.init(child.stderr.?); | |
| 268 | 268 | |
| 269 | 269 | stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable; |
| 270 | 270 | stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable; |
| ... | ... | @@ -578,8 +578,8 @@ pub const CompileErrorContext = struct { |
| 578 | 578 | var stdout_buf = Buffer.initNull(b.allocator); |
| 579 | 579 | var stderr_buf = Buffer.initNull(b.allocator); |
| 580 | 580 | |
| 581 | var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); | |
| 582 | var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); | |
| 581 | var stdout_file_in_stream = io.FileInStream.init(child.stdout.?); | |
| 582 | var stderr_file_in_stream = io.FileInStream.init(child.stderr.?); | |
| 583 | 583 | |
| 584 | 584 | stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable; |
| 585 | 585 | stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable; |
| ... | ... | @@ -842,8 +842,8 @@ pub const TranslateCContext = struct { |
| 842 | 842 | var stdout_buf = Buffer.initNull(b.allocator); |
| 843 | 843 | var stderr_buf = Buffer.initNull(b.allocator); |
| 844 | 844 | |
| 845 | var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); | |
| 846 | var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); | |
| 845 | var stdout_file_in_stream = io.FileInStream.init(child.stdout.?); | |
| 846 | var stderr_file_in_stream = io.FileInStream.init(child.stderr.?); | |
| 847 | 847 | |
| 848 | 848 | stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable; |
| 849 | 849 | stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable; |