From b36b93fb3ef3ce96ecc457d0e379740b39d37f80 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 31 Aug 2018 15:02:41 -0400 Subject: [PATCH] awareness of debug subsections --- std/debug/index.zig | 28 ++++++ std/pdb.zig | 237 +++++++++++++++++++++----------------------- 2 files changed, 142 insertions(+), 123 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 5bdfb52186..3b32eafb01 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -451,6 +451,34 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { std.debug.warn("v {} s {} a {}\n", version, signature, age); // We validated the executable and pdb match. + const name_bytes_len = try pdb_stream.stream.readIntLe(u32); + const name_bytes = try allocator.alloc(u8, name_bytes_len); + try pdb_stream.stream.readNoEof(name_bytes); + + //const HashTableHeader = packed struct { + // Size: u32, + // Capacity: u32, + + // fn maxLoad(cap: u32) u32 { + // return cap * 2 / 3 + 1; + // } + //}; + //var hash_tbl_hdr: HashTableHeader = undefined; + //try pdb_stream.stream.readStruct(Header, &hash_tbl_hdr); + //if (hash_tbl_hdr.Capacity == 0) + // return error.InvalidDebugInfo; + + //if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity)) + // return error.InvalidDebugInfo; + + //std.debug.warn("{}\n", hash_tbl_hdr); + + //var more_buf: [100]u8 = undefined; + //const more_len = try pdb_stream.stream.read(more_buf[0..]); + //for (more_buf[0..more_len]) |x| { + // std.debug.warn("{x2} {c}\n", x, x); + //} + return di; } diff --git a/std/pdb.zig b/std/pdb.zig index c1fb863b67..1ee9b23383 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -92,65 +92,6 @@ const Module = struct { obj_file_name: []u8, }; -/// Distinguishes individual records in the Symbols subsection of a .debug$S -/// section. Equivalent to SYM_ENUM_e in cvinfo.h. -pub const SymbolRecordKind = enum(u16) { - InlineesSym = 4456, - ScopeEndSym = 6, - InlineSiteEnd = 4430, - ProcEnd = 4431, - Thunk32Sym = 4354, - TrampolineSym = 4396, - SectionSym = 4406, - CoffGroupSym = 4407, - ExportSym = 4408, - ProcSym = 4367, - GlobalProcSym = 4368, - ProcIdSym = 4422, - GlobalProcIdSym = 4423, - DPCProcSym = 4437, - DPCProcIdSym = 4438, - RegisterSym = 4358, - PublicSym32 = 4366, - ProcRefSym = 4389, - LocalProcRef = 4391, - EnvBlockSym = 4413, - InlineSiteSym = 4429, - LocalSym = 4414, - DefRangeSym = 4415, - DefRangeSubfieldSym = 4416, - DefRangeRegisterSym = 4417, - DefRangeFramePointerRelSym = 4418, - DefRangeSubfieldRegisterSym = 4419, - DefRangeFramePointerRelFullScopeSym = 4420, - DefRangeRegisterRelSym = 4421, - BlockSym = 4355, - LabelSym = 4357, - ObjNameSym = 4353, - Compile2Sym = 4374, - Compile3Sym = 4412, - FrameProcSym = 4114, - CallSiteInfoSym = 4409, - FileStaticSym = 4435, - HeapAllocationSiteSym = 4446, - FrameCookieSym = 4410, - CallerSym = 4442, - CalleeSym = 4443, - UDTSym = 4360, - CobolUDT = 4361, - BuildInfoSym = 4428, - BPRelativeSym = 4363, - RegRelativeSym = 4369, - ConstantSym = 4359, - ManagedConstant = 4397, - DataSym = 4364, - GlobalData = 4365, - ManagedLocalData = 4380, - ManagedGlobalData = 4381, - ThreadLocalDataSym = 4370, - GlobalTLS = 4371, -}; - /// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful /// for reference purposes and when dealing with unknown record types. pub const SymbolKind = packed enum(u16) { @@ -434,6 +375,32 @@ const ColumnNumberEntry = packed struct { EndColumn: u16, }; +/// Checksum bytes follow. +const FileChecksumEntryHeader = packed struct { + FileNameOffset: u32, /// Byte offset of filename in global string table. + ChecksumSize: u8, /// Number of bytes of checksum. + ChecksumKind: u8, /// FileChecksumKind +}; + +const DebugSubsectionKind = packed enum(u32) { + None = 0, + Symbols = 0xf1, + Lines = 0xf2, + StringTable = 0xf3, + FileChecksums = 0xf4, + FrameData = 0xf5, + InlineeLines = 0xf6, + CrossScopeImports = 0xf7, + CrossScopeExports = 0xf8, + + // These appear to relate to .Net assembly info. + ILLines = 0xf9, + FuncMDTokenMap = 0xfa, + TypeMDTokenMap = 0xfb, + MergedAssemblyInput = 0xfc, + + CoffSymbolRVA = 0xfd, +}; pub const Pdb = struct { in_file: os.File, @@ -569,14 +536,17 @@ pub const Pdb = struct { const prefix = @ptrCast(*RecordPrefix, &symbols[symbol_i]); if (prefix.RecordLen < 2) return error.InvalidDebugInfo; - if (prefix.RecordKind == SymbolKind.S_LPROC32) { - const proc_sym = @ptrCast(*ProcSym, &symbols[symbol_i + @sizeOf(RecordPrefix)]); - const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset; - const vaddr_end = vaddr_start + proc_sym.CodeSize; - std.debug.warn(" {}\n", proc_sym); - if (address >= vaddr_start and address < vaddr_end) { - break proc_sym; - } + switch (prefix.RecordKind) { + SymbolKind.S_LPROC32 => { + const proc_sym = @ptrCast(*ProcSym, &symbols[symbol_i + @sizeOf(RecordPrefix)]); + const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset; + const vaddr_end = vaddr_start + proc_sym.CodeSize; + std.debug.warn(" {}\n", proc_sym); + if (address >= vaddr_start and address < vaddr_end) { + break proc_sym; + } + }, + else => {}, } symbol_i += prefix.RecordLen + @sizeOf(u16); if (symbol_i > symbols.len) @@ -592,73 +562,94 @@ pub const Pdb = struct { 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); + const subsect_info = try self.allocator.alloc(u8, mod.mod_info.C13ByteSize); + std.debug.warn("read C13 line info {} bytes\n", subsect_info.len); + const line_info_file_pos = modi.getFilePos(); + try modi.stream.readNoEof(subsect_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 DebugSubsectionHeader = packed struct { + Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum + Length: u32, /// number of bytes occupied by this record. + }; + var sect_offset: usize = 0; + var skip_len: usize = undefined; + var have_line_info: bool = false; + subsections: while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { + const subsect_hdr = @ptrCast(*DebugSubsectionHeader, &subsect_info[sect_offset]); + skip_len = subsect_hdr.Length; + sect_offset += @sizeOf(DebugSubsectionHeader); - 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); + switch (subsect_hdr.Kind) { + DebugSubsectionKind.Lines => { + if (have_line_info) + continue :subsections; - const block_hdr = @ptrCast(*LineBlockFragmentHeader, &line_info[line_index]); - std.debug.warn("{}\n", block_hdr); - line_index += @sizeOf(LineBlockFragmentHeader); + var line_index: usize = sect_offset; - const has_column = line_hdr.Flags.LF_HaveColumns; - std.debug.warn("has column: {}\n", has_column); + const line_hdr = @ptrCast(*LineFragmentHeader, &subsect_info[line_index]); + if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo; + std.debug.warn("{}\n", line_hdr); + line_index += @sizeOf(LineFragmentHeader); - 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); + const block_hdr = @ptrCast(*LineBlockFragmentHeader, &subsect_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, &subsect_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, &subsect_info[line_index]); + std.debug.warn("col {}\n", col_num_entry.StartColumn); + } + have_line_info = true; + continue :subsections; + } } - return; + return error.MissingDebugInfo; } - } - return error.MissingDebugInfo; - } else { - line_index += @sizeOf(LineNumberEntry) * block_hdr.NumLines; - if (has_column) - line_index += @sizeOf(ColumnNumberEntry) * block_hdr.NumLines; + + }, + DebugSubsectionKind.FileChecksums => { + var chksum_index: usize = sect_offset; + + while (chksum_index != subsect_info.len) { + const chksum_hdr = @ptrCast(*FileChecksumEntryHeader, &subsect_info[chksum_index]); + std.debug.warn("{}\n", chksum_hdr); + const len = @sizeOf(FileChecksumEntryHeader) + chksum_hdr.ChecksumSize; + chksum_index += len + (len % 4); + if (chksum_index > subsect_info.len) + return error.InvalidDebugInfo; + } + + }, + else => { + std.debug.warn("ignore subsection {}\n", @tagName(subsect_hdr.Kind)); + }, } - if (line_index > mod.mod_info.C13ByteSize) + if (sect_offset > subsect_info.len) return error.InvalidDebugInfo; } - - std.debug.warn("end line info\n"); + std.debug.warn("end subsections\n"); } };