diff --git a/std/coff.zig b/std/coff.zig index 475b4fcbc1..cce001d618 100644 --- a/std/coff.zig +++ b/std/coff.zig @@ -41,7 +41,7 @@ pub const Coff = struct { pub fn loadHeader(self: *Coff) !void { const pe_pointer_offset = 0x3C; - var file_stream = io.FileInStream.init(&self.in_file); + var file_stream = io.FileInStream.init(self.in_file); const in = &file_stream.stream; var magic: [2]u8 = undefined; @@ -126,7 +126,7 @@ pub const Coff = struct { std.debug.warn("file offset {x}\n", file_offset); try self.in_file.seekTo(file_offset + debug_dir.size); - var file_stream = io.FileInStream.init(&self.in_file); + var file_stream = io.FileInStream.init(self.in_file); const in = &file_stream.stream; var cv_signature: [4]u8 = undefined; // CodeView signature @@ -158,7 +158,7 @@ pub const Coff = struct { self.sections = ArrayList(Section).init(self.allocator); - var file_stream = io.FileInStream.init(&self.in_file); + var file_stream = io.FileInStream.init(self.in_file); const in = &file_stream.stream; var name: [8]u8 = undefined; @@ -235,4 +235,4 @@ const SectionHeader = struct { number_of_relocations: u16, number_of_line_numbers: u16, characteristics: u32, -}; \ No newline at end of file +}; diff --git a/std/debug/index.zig b/std/debug/index.zig index 1bf38a9fbe..36c5a6bdc9 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -40,7 +40,7 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) { return st; } else { stderr_file = try io.getStdErr(); - stderr_file_out_stream = io.FileOutStream.init(&stderr_file); + stderr_file_out_stream = io.FileOutStream.init(stderr_file); const st = &stderr_file_out_stream.stream; stderr_stream = st; return st; @@ -73,7 +73,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return; return; }; - writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| { + writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| { stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return; return; }; @@ -194,9 +194,9 @@ pub inline fn getReturnAddress(frame_count: usize) usize { return @intToPtr(*const usize, fp + @sizeOf(usize)).*; } -pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { +pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { switch (builtin.os) { - builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, allocator, debug_info, tty_color, start_addr), + builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr), else => {}, } const AddressState = union(enum) { @@ -231,7 +231,7 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_ } } -pub fn writeCurrentStackTraceWindows(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, +pub fn writeCurrentStackTraceWindows(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { var addr_buf: [1024]usize = undefined; diff --git a/std/io.zig b/std/io.zig index 369f6eede3..2de52493b1 100644 --- a/std/io.zig +++ b/std/io.zig @@ -34,13 +34,13 @@ pub fn getStdIn() GetStdIoErrs!File { /// Implementation of InStream trait for File pub const FileInStream = struct { - file: *File, + file: File, stream: Stream, pub const Error = @typeOf(File.read).ReturnType.ErrorSet; pub const Stream = InStream(Error); - pub fn init(file: *File) FileInStream { + pub fn init(file: File) FileInStream { return FileInStream{ .file = file, .stream = Stream{ .readFn = readFn }, @@ -55,13 +55,13 @@ pub const FileInStream = struct { /// Implementation of OutStream trait for File pub const FileOutStream = struct { - file: *File, + file: File, stream: Stream, pub const Error = File.WriteError; pub const Stream = OutStream(Error); - pub fn init(file: *File) FileOutStream { + pub fn init(file: File) FileOutStream { return FileOutStream{ .file = file, .stream = Stream{ .writeFn = writeFn }, diff --git a/std/os/file.zig b/std/os/file.zig index e90275ec7f..020a5dca54 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -205,17 +205,16 @@ pub const File = struct { /// Upon success, the stream is in an uninitialized state. To continue using it, /// you must use the open() function. - pub fn close(self: *File) void { + pub fn close(self: File) void { os.close(self.handle); - self.handle = undefined; } /// Calls `os.isTty` on `self.handle`. - pub fn isTty(self: *File) bool { + pub fn isTty(self: File) bool { return os.isTty(self.handle); } - pub fn seekForward(self: *File, amount: isize) !void { + pub fn seekForward(self: File, amount: isize) !void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios => { const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); @@ -246,7 +245,7 @@ pub const File = struct { } } - pub fn seekTo(self: *File, pos: usize) !void { + pub fn seekTo(self: File, pos: usize) !void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios => { const ipos = try math.cast(isize, pos); @@ -280,7 +279,7 @@ pub const File = struct { } } - pub fn getPos(self: *File) !usize { + pub fn getPos(self: File) !usize { switch (builtin.os) { Os.linux, Os.macosx, Os.ios => { const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); @@ -316,7 +315,7 @@ pub const File = struct { } } - pub fn getEndPos(self: *File) !usize { + pub fn getEndPos(self: File) !usize { if (is_posix) { const stat = try os.posixFStat(self.handle); return @intCast(usize, stat.size); @@ -341,7 +340,7 @@ pub const File = struct { Unexpected, }; - pub fn mode(self: *File) ModeError!Mode { + pub fn mode(self: File) ModeError!Mode { if (is_posix) { var stat: posix.Stat = undefined; const err = posix.getErrno(posix.fstat(self.handle, &stat)); @@ -375,7 +374,7 @@ pub const File = struct { Unexpected, }; - pub fn read(self: *File, buffer: []u8) ReadError!usize { + pub fn read(self: File, buffer: []u8) ReadError!usize { if (is_posix) { var index: usize = 0; while (index < buffer.len) { @@ -423,7 +422,7 @@ pub const File = struct { pub const WriteError = os.WindowsWriteError || os.PosixWriteError; - pub fn write(self: *File, bytes: []const u8) WriteError!void { + pub fn write(self: File, bytes: []const u8) WriteError!void { if (is_posix) { try os.posixWrite(self.handle, bytes); } else if (is_windows) { diff --git a/std/pdb.zig b/std/pdb.zig index 08c1d25f65..a83011df6a 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -8,9 +8,58 @@ const warn = std.debug.warn; const ArrayList = std.ArrayList; -pub const PdbError = error { - InvalidPdbMagic, - CorruptedFile, +// https://llvm.org/docs/PDB/DbiStream.html#stream-header +const DbiStreamHeader = packed struct { + VersionSignature: i32, + VersionHeader: u32, + Age: u32, + GlobalStreamIndex: u16, + BuildNumber: u16, + PublicStreamIndex: u16, + PdbDllVersion: u16, + SymRecordStream: u16, + PdbDllRbld: u16, + ModInfoSize: u32, + SectionContributionSize: i32, + SectionMapSize: i32, + SourceInfoSize: i32, + TypeServerSize: i32, + MFCTypeServerIndex: u32, + OptionalDbgHeaderSize: i32, + ECSubstreamSize: i32, + Flags: u16, + Machine: u16, + Padding: u32, +}; + +const SectionContribEntry = packed struct { + Section: u16, + Padding1: [2]u8, + Offset: i32, + Size: i32, + Characteristics: u32, + ModuleIndex: u16, + Padding2: [2]u8, + DataCrc: u32, + RelocCrc: u32, +}; + +const ModInfo = packed struct { + Unused1: u32, + SectionContr: SectionContribEntry, + Flags: u16, + ModuleSymStream: u16, + SymByteSize: u32, + C11ByteSize: u32, + C13ByteSize: u32, + SourceFileCount: u16, + Padding: [2]u8, + Unused2: u32, + SourceFileNameIndex: u32, + PdbFilePathNameIndex: u32, + // These fields are variable length + //ModuleName: char[], + //ObjFileName: char[], }; pub const StreamType = enum(u16) { @@ -30,7 +79,7 @@ pub const Pdb = struct { self.in_file = try os.File.openRead(file_name[0..]); self.allocator = allocator; - try self.msf.openFile(allocator, &self.in_file); + try self.msf.openFile(allocator, self.in_file); } pub fn getStream(self: *Pdb, stream: StreamType) ?*MsfStream { @@ -41,29 +90,32 @@ pub const Pdb = struct { } pub fn getSourceLine(self: *Pdb, address: usize) !void { - const dbi = self.getStream(StreamType.Dbi) orelse return error.CorruptedFile; + const dbi = self.getStream(StreamType.Dbi) orelse return error.InvalidDebugInfo; // Dbi Header - try dbi.seekForward(@sizeOf(u32) * 3 + @sizeOf(u16) * 6); - warn("dbi stream at {} (file offset)\n", dbi.getFilePos()); - const module_info_size = try dbi.stream.readIntLe(u32); - const section_contribution_size = try dbi.stream.readIntLe(u32); - const section_map_size = try dbi.stream.readIntLe(u32); - const source_info_size = try dbi.stream.readIntLe(u32); - warn("module_info_size: {}\n", module_info_size); - warn("section_contribution_size: {}\n", section_contribution_size); - warn("section_map_size: {}\n", section_map_size); - warn("source_info_size: {}\n", source_info_size); - try dbi.seekForward(@sizeOf(u32) * 5 + @sizeOf(u16) * 2); + var header: DbiStreamHeader = undefined; + try dbi.stream.readStruct(DbiStreamHeader, &header); + std.debug.warn("{}\n", header); warn("after header dbi stream at {} (file offset)\n", dbi.getFilePos()); // Module Info Substream - try dbi.seekForward(@sizeOf(u32) + @sizeOf(u16) + @sizeOf(u8) * 2); - const offset = try dbi.stream.readIntLe(u32); - const size = try dbi.stream.readIntLe(u32); - try dbi.seekForward(@sizeOf(u32)); - const module_index = try dbi.stream.readIntLe(u16); - warn("module {} of size {} at {}\n", module_index, size, offset); + var mod_info_offset: usize = 0; + while (mod_info_offset < header.ModInfoSize) { + var mod_info: ModInfo = undefined; + try dbi.stream.readStruct(ModInfo, &mod_info); + std.debug.warn("{}\n", mod_info); + mod_info_offset += @sizeOf(ModInfo); + + const module_name = try dbi.readNullTermString(self.allocator); + std.debug.warn("module_name {}\n", module_name); + mod_info_offset += module_name.len + 1; + + const obj_file_name = try dbi.readNullTermString(self.allocator); + std.debug.warn("obj_file_name {}\n", obj_file_name); + mod_info_offset += obj_file_name.len + 1; + } + std.debug.warn("end modules\n"); + // TODO: locate corresponding source line information } @@ -75,7 +127,7 @@ const Msf = struct { directory: MsfStream, streams: ArrayList(MsfStream), - fn openFile(self: *Msf, allocator: *mem.Allocator, file: *os.File) !void { + fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void { var file_stream = io.FileInStream.init(file); const in = &file_stream.stream; @@ -84,7 +136,7 @@ const Msf = struct { warn("magic: '{}'\n", magic); if (!mem.eql(u8, magic, SuperBlock.FileMagic)) - return error.InvalidPdbMagic; + return error.InvalidDebugInfo; self.superblock = SuperBlock { .block_size = try in.readIntLe(u32), @@ -97,11 +149,11 @@ const Msf = struct { switch (self.superblock.block_size) { 512, 1024, 2048, 4096 => {}, // llvm only uses 4096 - else => return error.InvalidPdbMagic + else => return error.InvalidDebugInfo } if (self.superblock.fileSize() != try file.getEndPos()) - return error.CorruptedFile; // Should always stand. + return error.InvalidDebugInfo; // Should always stand. self.directory = try MsfStream.init( self.superblock.block_size, @@ -165,12 +217,18 @@ const SuperBlock = struct { }; const MsfStream = struct { - in_file: *os.File, + in_file: os.File, pos: usize, blocks: ArrayList(u32), block_size: u32, - fn init(block_size: u32, block_count: u32, pos: usize, file: *os.File, allocator: *mem.Allocator) !MsfStream { + /// Implementation of InStream trait for Pdb.MsfStream + stream: Stream, + + pub const Error = @typeOf(read).ReturnType.ErrorSet; + pub const Stream = io.InStream(Error); + + fn init(block_size: u32, block_count: u32, pos: usize, file: os.File, allocator: *mem.Allocator) !MsfStream { var stream = MsfStream { .in_file = file, .pos = 0, @@ -198,6 +256,18 @@ const MsfStream = struct { return stream; } + fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 { + var list = ArrayList(u8).init(allocator); + defer list.deinit(); + while (true) { + const byte = try self.stream.readByte(); + if (byte == 0) { + return list.toSlice(); + } + try list.append(byte); + } + } + fn read(self: *MsfStream, buffer: []u8) !usize { var block_id = self.pos / self.block_size; var block = self.blocks.items[block_id]; @@ -252,12 +322,6 @@ const MsfStream = struct { return block * self.block_size + offset; } - /// Implementation of InStream trait for Pdb.MsfStream - pub const Error = @typeOf(read).ReturnType.ErrorSet; - pub const Stream = io.InStream(Error); - - stream: Stream, - fn readFn(in_stream: *Stream, buffer: []u8) Error!usize { const self = @fieldParentPtr(MsfStream, "stream", in_stream); return self.read(buffer);