| ... | ... | @@ -92,65 +92,6 @@ const Module = struct { |
| 92 | 92 | obj_file_name: []u8, |
| 93 | 93 | }; |
| 94 | 94 | |
| 95 | | /// Distinguishes individual records in the Symbols subsection of a .debug$S |
| 96 | | /// section. Equivalent to SYM_ENUM_e in cvinfo.h. |
| 97 | | pub const SymbolRecordKind = enum(u16) { |
| 98 | | InlineesSym = 4456, |
| 99 | | ScopeEndSym = 6, |
| 100 | | InlineSiteEnd = 4430, |
| 101 | | ProcEnd = 4431, |
| 102 | | Thunk32Sym = 4354, |
| 103 | | TrampolineSym = 4396, |
| 104 | | SectionSym = 4406, |
| 105 | | CoffGroupSym = 4407, |
| 106 | | ExportSym = 4408, |
| 107 | | ProcSym = 4367, |
| 108 | | GlobalProcSym = 4368, |
| 109 | | ProcIdSym = 4422, |
| 110 | | GlobalProcIdSym = 4423, |
| 111 | | DPCProcSym = 4437, |
| 112 | | DPCProcIdSym = 4438, |
| 113 | | RegisterSym = 4358, |
| 114 | | PublicSym32 = 4366, |
| 115 | | ProcRefSym = 4389, |
| 116 | | LocalProcRef = 4391, |
| 117 | | EnvBlockSym = 4413, |
| 118 | | InlineSiteSym = 4429, |
| 119 | | LocalSym = 4414, |
| 120 | | DefRangeSym = 4415, |
| 121 | | DefRangeSubfieldSym = 4416, |
| 122 | | DefRangeRegisterSym = 4417, |
| 123 | | DefRangeFramePointerRelSym = 4418, |
| 124 | | DefRangeSubfieldRegisterSym = 4419, |
| 125 | | DefRangeFramePointerRelFullScopeSym = 4420, |
| 126 | | DefRangeRegisterRelSym = 4421, |
| 127 | | BlockSym = 4355, |
| 128 | | LabelSym = 4357, |
| 129 | | ObjNameSym = 4353, |
| 130 | | Compile2Sym = 4374, |
| 131 | | Compile3Sym = 4412, |
| 132 | | FrameProcSym = 4114, |
| 133 | | CallSiteInfoSym = 4409, |
| 134 | | FileStaticSym = 4435, |
| 135 | | HeapAllocationSiteSym = 4446, |
| 136 | | FrameCookieSym = 4410, |
| 137 | | CallerSym = 4442, |
| 138 | | CalleeSym = 4443, |
| 139 | | UDTSym = 4360, |
| 140 | | CobolUDT = 4361, |
| 141 | | BuildInfoSym = 4428, |
| 142 | | BPRelativeSym = 4363, |
| 143 | | RegRelativeSym = 4369, |
| 144 | | ConstantSym = 4359, |
| 145 | | ManagedConstant = 4397, |
| 146 | | DataSym = 4364, |
| 147 | | GlobalData = 4365, |
| 148 | | ManagedLocalData = 4380, |
| 149 | | ManagedGlobalData = 4381, |
| 150 | | ThreadLocalDataSym = 4370, |
| 151 | | GlobalTLS = 4371, |
| 152 | | }; |
| 153 | | |
| 154 | 95 | /// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful |
| 155 | 96 | /// for reference purposes and when dealing with unknown record types. |
| 156 | 97 | pub const SymbolKind = packed enum(u16) { |
| ... | ... | @@ -434,6 +375,32 @@ const ColumnNumberEntry = packed struct { |
| 434 | 375 | EndColumn: u16, |
| 435 | 376 | }; |
| 436 | 377 | |
| 378 | /// Checksum bytes follow. |
| 379 | const FileChecksumEntryHeader = packed struct { |
| 380 | FileNameOffset: u32, /// Byte offset of filename in global string table. |
| 381 | ChecksumSize: u8, /// Number of bytes of checksum. |
| 382 | ChecksumKind: u8, /// FileChecksumKind |
| 383 | }; |
| 384 | |
| 385 | const DebugSubsectionKind = packed enum(u32) { |
| 386 | None = 0, |
| 387 | Symbols = 0xf1, |
| 388 | Lines = 0xf2, |
| 389 | StringTable = 0xf3, |
| 390 | FileChecksums = 0xf4, |
| 391 | FrameData = 0xf5, |
| 392 | InlineeLines = 0xf6, |
| 393 | CrossScopeImports = 0xf7, |
| 394 | CrossScopeExports = 0xf8, |
| 395 | |
| 396 | // These appear to relate to .Net assembly info. |
| 397 | ILLines = 0xf9, |
| 398 | FuncMDTokenMap = 0xfa, |
| 399 | TypeMDTokenMap = 0xfb, |
| 400 | MergedAssemblyInput = 0xfc, |
| 401 | |
| 402 | CoffSymbolRVA = 0xfd, |
| 403 | }; |
| 437 | 404 | |
| 438 | 405 | pub const Pdb = struct { |
| 439 | 406 | in_file: os.File, |
| ... | ... | @@ -569,14 +536,17 @@ pub const Pdb = struct { |
| 569 | 536 | const prefix = @ptrCast(*RecordPrefix, &symbols[symbol_i]); |
| 570 | 537 | if (prefix.RecordLen < 2) |
| 571 | 538 | return error.InvalidDebugInfo; |
| 572 | | if (prefix.RecordKind == SymbolKind.S_LPROC32) { |
| 573 | | const proc_sym = @ptrCast(*ProcSym, &symbols[symbol_i + @sizeOf(RecordPrefix)]); |
| 574 | | const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset; |
| 575 | | const vaddr_end = vaddr_start + proc_sym.CodeSize; |
| 576 | | std.debug.warn(" {}\n", proc_sym); |
| 577 | | if (address >= vaddr_start and address < vaddr_end) { |
| 578 | | break proc_sym; |
| 579 | | } |
| 539 | switch (prefix.RecordKind) { |
| 540 | SymbolKind.S_LPROC32 => { |
| 541 | const proc_sym = @ptrCast(*ProcSym, &symbols[symbol_i + @sizeOf(RecordPrefix)]); |
| 542 | const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset; |
| 543 | const vaddr_end = vaddr_start + proc_sym.CodeSize; |
| 544 | std.debug.warn(" {}\n", proc_sym); |
| 545 | if (address >= vaddr_start and address < vaddr_end) { |
| 546 | break proc_sym; |
| 547 | } |
| 548 | }, |
| 549 | else => {}, |
| 580 | 550 | } |
| 581 | 551 | symbol_i += prefix.RecordLen + @sizeOf(u16); |
| 582 | 552 | if (symbol_i > symbols.len) |
| ... | ... | @@ -592,73 +562,94 @@ pub const Pdb = struct { |
| 592 | 562 | return error.MissingDebugInfo; |
| 593 | 563 | } |
| 594 | 564 | |
| 595 | | const line_info = try self.allocator.alloc(u8, mod.mod_info.C13ByteSize); |
| 596 | | std.debug.warn("read C13 line info {} bytes\n", line_info.len); |
| 597 | | try modi.stream.readNoEof(line_info); |
| 598 | | |
| 599 | | var line_index: usize = 0; |
| 600 | | while (line_index != line_info.len) { |
| 601 | | std.debug.warn("unknown bytes: {x2} {x2} {x2} {x2} {x2} {x2} {x2} {x2}\n", |
| 602 | | line_info[line_index+0], |
| 603 | | line_info[line_index+1], |
| 604 | | line_info[line_index+2], |
| 605 | | line_info[line_index+3], |
| 606 | | line_info[line_index+4], |
| 607 | | line_info[line_index+5], |
| 608 | | line_info[line_index+6], |
| 609 | | line_info[line_index+7], |
| 610 | | ); |
| 611 | | line_index += 8; |
| 612 | | |
| 613 | | const line_hdr = @ptrCast(*LineFragmentHeader, &line_info[line_index]); |
| 614 | | if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo; |
| 615 | | std.debug.warn("{}\n", line_hdr); |
| 616 | | line_index += @sizeOf(LineFragmentHeader); |
| 617 | | |
| 618 | | const block_hdr = @ptrCast(*LineBlockFragmentHeader, &line_info[line_index]); |
| 619 | | std.debug.warn("{}\n", block_hdr); |
| 620 | | line_index += @sizeOf(LineBlockFragmentHeader); |
| 621 | | |
| 622 | | const has_column = line_hdr.Flags.LF_HaveColumns; |
| 623 | | std.debug.warn("has column: {}\n", has_column); |
| 624 | | |
| 625 | | const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset; |
| 626 | | const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; |
| 627 | | if (address >= frag_vaddr_start and address < frag_vaddr_end) { |
| 628 | | std.debug.warn("found line listing\n"); |
| 629 | | var line_i: usize = 0; |
| 630 | | const start_line_index = line_index; |
| 631 | | while (line_i < block_hdr.NumLines) : (line_i += 1) { |
| 632 | | const line_num_entry = @ptrCast(*LineNumberEntry, &line_info[line_index]); |
| 633 | | line_index += @sizeOf(LineNumberEntry); |
| 634 | | const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags); |
| 635 | | std.debug.warn("{} {}\n", line_num_entry, flags); |
| 636 | | const vaddr_start = frag_vaddr_start + line_num_entry.Offset; |
| 637 | | const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End; |
| 638 | | std.debug.warn("test {x} <= {x} < {x}\n", vaddr_start, address, vaddr_end); |
| 639 | | if (address >= vaddr_start and address < vaddr_end) { |
| 640 | | std.debug.warn("{} line {}\n", block_hdr.NameIndex, flags.Start); |
| 641 | | if (has_column) { |
| 642 | | line_index = start_line_index + @sizeOf(LineNumberEntry) * block_hdr.NumLines; |
| 643 | | line_index += @sizeOf(ColumnNumberEntry) * line_i; |
| 644 | | const col_num_entry = @ptrCast(*ColumnNumberEntry, &line_info[line_index]); |
| 645 | | std.debug.warn("col {}\n", col_num_entry.StartColumn); |
| 565 | const subsect_info = try self.allocator.alloc(u8, mod.mod_info.C13ByteSize); |
| 566 | std.debug.warn("read C13 line info {} bytes\n", subsect_info.len); |
| 567 | const line_info_file_pos = modi.getFilePos(); |
| 568 | try modi.stream.readNoEof(subsect_info); |
| 569 | |
| 570 | const DebugSubsectionHeader = packed struct { |
| 571 | Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum |
| 572 | Length: u32, /// number of bytes occupied by this record. |
| 573 | }; |
| 574 | var sect_offset: usize = 0; |
| 575 | var skip_len: usize = undefined; |
| 576 | var have_line_info: bool = false; |
| 577 | subsections: while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { |
| 578 | const subsect_hdr = @ptrCast(*DebugSubsectionHeader, &subsect_info[sect_offset]); |
| 579 | skip_len = subsect_hdr.Length; |
| 580 | sect_offset += @sizeOf(DebugSubsectionHeader); |
| 581 | |
| 582 | switch (subsect_hdr.Kind) { |
| 583 | DebugSubsectionKind.Lines => { |
| 584 | if (have_line_info) |
| 585 | continue :subsections; |
| 586 | |
| 587 | var line_index: usize = sect_offset; |
| 588 | |
| 589 | const line_hdr = @ptrCast(*LineFragmentHeader, &subsect_info[line_index]); |
| 590 | if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo; |
| 591 | std.debug.warn("{}\n", line_hdr); |
| 592 | line_index += @sizeOf(LineFragmentHeader); |
| 593 | |
| 594 | const block_hdr = @ptrCast(*LineBlockFragmentHeader, &subsect_info[line_index]); |
| 595 | std.debug.warn("{}\n", block_hdr); |
| 596 | line_index += @sizeOf(LineBlockFragmentHeader); |
| 597 | |
| 598 | const has_column = line_hdr.Flags.LF_HaveColumns; |
| 599 | std.debug.warn("has column: {}\n", has_column); |
| 600 | |
| 601 | const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset; |
| 602 | const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; |
| 603 | if (address >= frag_vaddr_start and address < frag_vaddr_end) { |
| 604 | std.debug.warn("found line listing\n"); |
| 605 | var line_i: usize = 0; |
| 606 | const start_line_index = line_index; |
| 607 | while (line_i < block_hdr.NumLines) : (line_i += 1) { |
| 608 | const line_num_entry = @ptrCast(*LineNumberEntry, &subsect_info[line_index]); |
| 609 | line_index += @sizeOf(LineNumberEntry); |
| 610 | const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags); |
| 611 | std.debug.warn("{} {}\n", line_num_entry, flags); |
| 612 | const vaddr_start = frag_vaddr_start + line_num_entry.Offset; |
| 613 | const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End; |
| 614 | std.debug.warn("test {x} <= {x} < {x}\n", vaddr_start, address, vaddr_end); |
| 615 | if (address >= vaddr_start and address < vaddr_end) { |
| 616 | std.debug.warn("{} line {}\n", block_hdr.NameIndex, flags.Start); |
| 617 | if (has_column) { |
| 618 | line_index = start_line_index + @sizeOf(LineNumberEntry) * block_hdr.NumLines; |
| 619 | line_index += @sizeOf(ColumnNumberEntry) * line_i; |
| 620 | const col_num_entry = @ptrCast(*ColumnNumberEntry, &subsect_info[line_index]); |
| 621 | std.debug.warn("col {}\n", col_num_entry.StartColumn); |
| 622 | } |
| 623 | have_line_info = true; |
| 624 | continue :subsections; |
| 625 | } |
| 646 | 626 | } |
| 647 | | return; |
| 627 | return error.MissingDebugInfo; |
| 648 | 628 | } |
| 649 | | } |
| 650 | | return error.MissingDebugInfo; |
| 651 | | } else { |
| 652 | | line_index += @sizeOf(LineNumberEntry) * block_hdr.NumLines; |
| 653 | | if (has_column) |
| 654 | | line_index += @sizeOf(ColumnNumberEntry) * block_hdr.NumLines; |
| 629 | |
| 630 | }, |
| 631 | DebugSubsectionKind.FileChecksums => { |
| 632 | var chksum_index: usize = sect_offset; |
| 633 | |
| 634 | while (chksum_index != subsect_info.len) { |
| 635 | const chksum_hdr = @ptrCast(*FileChecksumEntryHeader, &subsect_info[chksum_index]); |
| 636 | std.debug.warn("{}\n", chksum_hdr); |
| 637 | const len = @sizeOf(FileChecksumEntryHeader) + chksum_hdr.ChecksumSize; |
| 638 | chksum_index += len + (len % 4); |
| 639 | if (chksum_index > subsect_info.len) |
| 640 | return error.InvalidDebugInfo; |
| 641 | } |
| 642 | |
| 643 | }, |
| 644 | else => { |
| 645 | std.debug.warn("ignore subsection {}\n", @tagName(subsect_hdr.Kind)); |
| 646 | }, |
| 655 | 647 | } |
| 656 | 648 | |
| 657 | | if (line_index > mod.mod_info.C13ByteSize) |
| 649 | if (sect_offset > subsect_info.len) |
| 658 | 650 | return error.InvalidDebugInfo; |
| 659 | 651 | } |
| 660 | | |
| 661 | | std.debug.warn("end line info\n"); |
| 652 | std.debug.warn("end subsections\n"); |
| 662 | 653 | } |
| 663 | 654 | }; |
| 664 | 655 | |