Commit 99170aa13d

Andrew Kelley <superjoe30@gmail.com>
2018-08-31 07:01:37
finding source file, line, and column info
1 parent 72185e7
Changed files (2)
std/io.zig
@@ -210,7 +210,7 @@ pub fn InStream(comptime ReadError: type) type {
 
         pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void {
             // Only extern and packed structs have defined in-memory layout.
-            assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
+            comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
             return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..]));
         }
     };
std/pdb.zig
@@ -365,7 +365,8 @@ const ProcSym = packed struct {
     CodeOffset: u32,
     Segment: u16,
     Flags: ProcSymFlags,
-    Name: u8,
+    // following is a null terminated string
+    // Name: [*]u8,
 };
 
 const ProcSymFlags = packed struct {
@@ -389,6 +390,51 @@ const RecordPrefix = packed struct {
     RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind)
 };
 
+const LineFragmentHeader = packed struct {
+    RelocOffset: u32, /// Code offset of line contribution.
+    RelocSegment: u16, /// Code segment of line contribution.
+    Flags: LineFlags,
+    CodeSize: u32, /// Code size of this line contribution.
+};
+
+const LineFlags = packed struct {
+    LF_HaveColumns: bool, /// CV_LINES_HAVE_COLUMNS
+    unused: u15,
+};
+
+/// The following two variable length arrays appear immediately after the
+/// header.  The structure definitions follow.
+/// LineNumberEntry   Lines[NumLines];
+/// ColumnNumberEntry Columns[NumLines];
+const LineBlockFragmentHeader = packed struct {
+    /// Offset of FileChecksum entry in File
+    /// checksums buffer.  The checksum entry then
+    /// contains another offset into the string
+    /// table of the actual name.
+    NameIndex: u32,
+    NumLines: u32,
+    BlockSize: u32, /// code size of block, in bytes
+};
+
+
+const LineNumberEntry = packed struct {
+    Offset: u32, /// Offset to start of code bytes for line number
+    Flags: u32,
+
+    /// TODO runtime crash when I make the actual type of Flags this
+    const Flags = packed struct {
+        Start: u24,
+        End: u7,
+        IsStatement: bool,
+    };
+};
+
+const ColumnNumberEntry = packed struct {
+    StartColumn: u16,
+    EndColumn: u16,
+};
+
+
 pub const Pdb = struct {
     in_file: os.File,
     allocator: *mem.Allocator,
@@ -537,16 +583,82 @@ pub const Pdb = struct {
                 return error.InvalidDebugInfo;
         } else return error.MissingDebugInfo;
 
-        std.debug.warn("found in {s}: {}\n", ([*]u8)((*[1]u8)(&proc_sym.Name)), proc_sym);
+        std.debug.warn("found in {s}: {}\n", @ptrCast([*]u8, proc_sym) + @sizeOf(ProcSym), proc_sym);
 
         if (mod.mod_info.C11ByteSize != 0)
             return error.InvalidDebugInfo;
 
-        if (mod.mod_info.C13ByteSize != 0) {
-            std.debug.warn("read C13 line info\n");
+        if (mod.mod_info.C13ByteSize == 0) {
+            return error.MissingDebugInfo;
+        }
+
+        const line_info = try self.allocator.alloc(u8, mod.mod_info.C13ByteSize);
+        std.debug.warn("read C13 line info {} bytes\n", line_info.len);
+        try modi.stream.readNoEof(line_info);
+
+        var line_index: usize = 0;
+        while (line_index != line_info.len) {
+            std.debug.warn("unknown bytes: {x2} {x2} {x2} {x2}  {x2} {x2} {x2} {x2}\n",
+                line_info[line_index+0],
+                line_info[line_index+1],
+                line_info[line_index+2],
+                line_info[line_index+3],
+                line_info[line_index+4],
+                line_info[line_index+5],
+                line_info[line_index+6],
+                line_info[line_index+7],
+            );
+            line_index += 8;
+
+            const line_hdr = @ptrCast(*LineFragmentHeader, &line_info[line_index]);
+            if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
+            std.debug.warn("{}\n", line_hdr);
+            line_index += @sizeOf(LineFragmentHeader);
+
+            const block_hdr = @ptrCast(*LineBlockFragmentHeader, &line_info[line_index]);
+            std.debug.warn("{}\n", block_hdr);
+            line_index += @sizeOf(LineBlockFragmentHeader);
+
+            const has_column = line_hdr.Flags.LF_HaveColumns;
+            std.debug.warn("has column: {}\n", has_column);
+
+            const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
+            const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
+            if (address >= frag_vaddr_start and address < frag_vaddr_end) {
+                std.debug.warn("found line listing\n");
+                var line_i: usize = 0;
+                const start_line_index = line_index;
+                while (line_i < block_hdr.NumLines) : (line_i += 1) {
+                    const line_num_entry = @ptrCast(*LineNumberEntry, &line_info[line_index]);
+                    line_index += @sizeOf(LineNumberEntry);
+                    const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags);
+                    std.debug.warn("{} {}\n", line_num_entry, flags);
+                    const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
+                    const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End;
+                    std.debug.warn("test {x} <= {x} < {x}\n", vaddr_start, address, vaddr_end);
+                    if (address >= vaddr_start and address < vaddr_end) {
+                        std.debug.warn("{} line {}\n", block_hdr.NameIndex, flags.Start);
+                        if (has_column) {
+                            line_index = start_line_index + @sizeOf(LineNumberEntry) * block_hdr.NumLines;
+                            line_index += @sizeOf(ColumnNumberEntry) * line_i;
+                            const col_num_entry = @ptrCast(*ColumnNumberEntry, &line_info[line_index]);
+                            std.debug.warn("col {}\n", col_num_entry.StartColumn);
+                        }
+                        return;
+                    }
+                }
+                return error.MissingDebugInfo;
+            } else {
+                line_index += @sizeOf(LineNumberEntry) * block_hdr.NumLines;
+                if (has_column)
+                    line_index += @sizeOf(ColumnNumberEntry) * block_hdr.NumLines;
+            }
+
+            if (line_index > mod.mod_info.C13ByteSize)
+                return error.InvalidDebugInfo;
         }
 
-        // TODO: locate corresponding source line information
+        std.debug.warn("end line info\n");
     }
 };