Commit 686663239a

Andrew Kelley <superjoe30@gmail.com>
2018-08-30 01:00:24
printing info from the ModuleInfo substream of DebugInfo
1 parent f1b7105
Changed files (5)
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;
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) {
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
+};
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 },
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);