| ... | @@ -312,7 +312,7 @@ pub const BinaryAnnotation = union(enum) { | ... | @@ -312,7 +312,7 @@ pub const BinaryAnnotation = union(enum) { |
| 312 | | 312 | |
| 313 | const PartialRange = struct { | 313 | const PartialRange = struct { |
| 314 | line_offset: u32, | 314 | line_offset: u32, |
| 315 | file_offset: u32, | 315 | file_id: ?u32, |
| 316 | code_offset: u32, | 316 | code_offset: u32, |
| 317 | code_length: ?u32, | 317 | code_length: ?u32, |
| 318 | }; | 318 | }; |
| ... | @@ -322,7 +322,7 @@ pub const BinaryAnnotation = union(enum) { | ... | @@ -322,7 +322,7 @@ pub const BinaryAnnotation = union(enum) { |
| 322 | .annotations = annotations, | 322 | .annotations = annotations, |
| 323 | .curr = .{ | 323 | .curr = .{ |
| 324 | .line_offset = 0, | 324 | .line_offset = 0, |
| 325 | .file_offset = 0, | 325 | .file_id = null, |
| 326 | .code_offset = 0, | 326 | .code_offset = 0, |
| 327 | .code_length = null, | 327 | .code_length = null, |
| 328 | }, | 328 | }, |
| ... | @@ -332,7 +332,7 @@ pub const BinaryAnnotation = union(enum) { | ... | @@ -332,7 +332,7 @@ pub const BinaryAnnotation = union(enum) { |
| 332 | | 332 | |
| 333 | pub const Range = struct { | 333 | pub const Range = struct { |
| 334 | line_offset: u32, | 334 | line_offset: u32, |
| 335 | file_offset: u32, | 335 | file_id: ?u32, |
| 336 | code_offset: u32, | 336 | code_offset: u32, |
| 337 | code_length: u32, | 337 | code_length: u32, |
| 338 | | 338 | |
| ... | @@ -352,7 +352,11 @@ pub const BinaryAnnotation = union(enum) { | ... | @@ -352,7 +352,11 @@ pub const BinaryAnnotation = union(enum) { |
| 352 | if (self.prev) |*prev| prev.code_length = prev.code_length orelse length; | 352 | if (self.prev) |*prev| prev.code_length = prev.code_length orelse length; |
| 353 | self.curr.code_offset += length; | 353 | self.curr.code_offset += length; |
| 354 | }, | 354 | }, |
| 355 | .change_file => @panic("unimplemented"), | 355 | // LLVM has code to emit these, but I wasn't able to figure out how trigger it |
| | 356 | // so this logic is untested. |
| | 357 | .change_file => |file_id| { |
| | 358 | self.curr.file_id = file_id; |
| | 359 | }, |
| 356 | // LLVM never emits this opcode, but it's clear enough how to interpret it so we may as | 360 | // LLVM never emits this opcode, but it's clear enough how to interpret it so we may as |
| 357 | // well in case they use it in the future | 361 | // well in case they use it in the future |
| 358 | .change_code_length_and_code_offset => |info| { | 362 | .change_code_length_and_code_offset => |info| { |
| ... | @@ -402,7 +406,7 @@ pub const BinaryAnnotation = union(enum) { | ... | @@ -402,7 +406,7 @@ pub const BinaryAnnotation = union(enum) { |
| 402 | .code_offset = self.curr.code_offset, | 406 | .code_offset = self.curr.code_offset, |
| 403 | .code_length = self.curr.code_length, | 407 | .code_length = self.curr.code_length, |
| 404 | .line_offset = self.curr.line_offset, | 408 | .line_offset = self.curr.line_offset, |
| 405 | .file_offset = self.curr.file_offset, | 409 | .file_id = self.curr.file_id, |
| 406 | }; | 410 | }; |
| 407 | const prev = self.prev orelse continue; | 411 | const prev = self.prev orelse continue; |
| 408 | const prev_code_length = prev.code_length orelse continue; | 412 | const prev_code_length = prev.code_length orelse continue; |
| ... | @@ -410,7 +414,7 @@ pub const BinaryAnnotation = union(enum) { | ... | @@ -410,7 +414,7 @@ pub const BinaryAnnotation = union(enum) { |
| 410 | .code_offset = prev.code_offset, | 414 | .code_offset = prev.code_offset, |
| 411 | .code_length = prev_code_length, | 415 | .code_length = prev_code_length, |
| 412 | .line_offset = prev.line_offset, | 416 | .line_offset = prev.line_offset, |
| 413 | .file_offset = prev.file_offset, | 417 | .file_id = prev.file_id, |
| 414 | }; | 418 | }; |
| 415 | } | 419 | } |
| 416 | | 420 | |
| ... | @@ -421,7 +425,7 @@ pub const BinaryAnnotation = union(enum) { | ... | @@ -421,7 +425,7 @@ pub const BinaryAnnotation = union(enum) { |
| 421 | .code_offset = prev.code_offset, | 425 | .code_offset = prev.code_offset, |
| 422 | .code_length = prev_code_length, | 426 | .code_length = prev_code_length, |
| 423 | .line_offset = prev.line_offset, | 427 | .line_offset = prev.line_offset, |
| 424 | .file_offset = prev.file_offset, | 428 | .file_id = prev.file_id, |
| 425 | }; | 429 | }; |
| 426 | } | 430 | } |
| 427 | }; | 431 | }; |
| ... | @@ -588,30 +592,62 @@ pub fn getBinaryAnnotations(self: *Pdb, site: *align(1) const pdb.InlineSiteSym) | ... | @@ -588,30 +592,62 @@ pub fn getBinaryAnnotations(self: *Pdb, site: *align(1) const pdb.InlineSiteSym) |
| 588 | return .{ .reader = Io.Reader.fixed(slice) }; | 592 | return .{ .reader = Io.Reader.fixed(slice) }; |
| 589 | } | 593 | } |
| 590 | | 594 | |
| 591 | pub fn calculateOffset( | 595 | pub fn getInlineSiteSourceLocation( |
| 592 | self: *Pdb, | 596 | self: *Pdb, |
| | 597 | mod: *Module, |
| 593 | site: *align(1) const pdb.InlineSiteSym, | 598 | site: *align(1) const pdb.InlineSiteSym, |
| 594 | loc: std.debug.SourceLocation, | 599 | inlinee_src_line: *align(1) const pdb.InlineeSourceLine, |
| 595 | offset_in_func: usize, | 600 | offset_in_func: usize, |
| 596 | ) error{InvalidDebugInfo, MissingDebugInfo, ReadFailed}!?std.debug.SourceLocation { | 601 | ) !?std.debug.SourceLocation { |
| 597 | var ranges: BinaryAnnotation.RangeIterator = .init(self.getBinaryAnnotations(site)); | 602 | var ranges: BinaryAnnotation.RangeIterator = .init(self.getBinaryAnnotations(site)); |
| 598 | while (try ranges.next()) |range| { | 603 | while (try ranges.next()) |range| { |
| 599 | if (range.contains(offset_in_func)) { | 604 | if (!range.contains(offset_in_func)) continue; |
| 600 | var result: std.debug.SourceLocation = loc; | 605 | |
| 601 | result.line += range.line_offset; | 606 | const file_id = range.file_id orelse inlinee_src_line.file_id; |
| 602 | return result; | 607 | const file_name = try self.getFileName(mod, file_id); |
| 603 | } | 608 | errdefer self.allocator.free(file_name); |
| | 609 | |
| | 610 | return .{ |
| | 611 | .line = inlinee_src_line.source_line_num + range.line_offset, |
| | 612 | // LLVM doesn't currently emit column information for inlined calls in PDBs. |
| | 613 | .column = 0, |
| | 614 | .file_name = file_name, |
| | 615 | }; |
| 604 | } | 616 | } |
| 605 | return null; | 617 | return null; |
| 606 | } | 618 | } |
| 607 | | 619 | |
| | 620 | pub fn getFileName(self: *Pdb, mod: *Module, file_id: u32) ![]const u8 { |
| | 621 | const checksum_offset = mod.checksum_offset orelse return error.MissingDebugInfo; |
| | 622 | const subsect_index = checksum_offset + file_id; |
| | 623 | const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&mod.subsect_info[subsect_index]); |
| | 624 | const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; |
| | 625 | self.string_table.?.seekTo(strtab_offset) catch return error.InvalidDebugInfo; |
| | 626 | const string_reader = &self.string_table.?.interface; |
| | 627 | var source_file_name: Io.Writer.Allocating = .init(self.allocator); |
| | 628 | defer source_file_name.deinit(); |
| | 629 | _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); |
| | 630 | assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API |
| | 631 | string_reader.toss(1); |
| | 632 | return try source_file_name.toOwnedSlice(); |
| | 633 | } |
| | 634 | |
| 608 | pub fn getSymbolName(self: *Pdb, proc_sym: *align(1) const pdb.ProcSym) []const u8 { | 635 | pub fn getSymbolName(self: *Pdb, proc_sym: *align(1) const pdb.ProcSym) []const u8 { |
| 609 | _ = self; | 636 | _ = self; |
| 610 | return std.mem.sliceTo(@as([*:0]const u8, @ptrCast(&proc_sym.name[0])), 0); | 637 | return std.mem.sliceTo(@as([*:0]const u8, @ptrCast(&proc_sym.name[0])), 0); |
| 611 | } | 638 | } |
| 612 | | 639 | |
| 613 | pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceLocation { | 640 | pub const InlineeSourceLine = struct { |
| 614 | const gpa = self.allocator; | 641 | signature: pdb.InlineeSourceLineSignature, |
| | 642 | info: *align(1) const pdb.InlineeSourceLine, |
| | 643 | }; |
| | 644 | |
| | 645 | pub fn getInlineeSourceLine( |
| | 646 | self: *Pdb, |
| | 647 | mod: *Module, |
| | 648 | inlinee: u32, |
| | 649 | ) ?InlineeSourceLine { |
| | 650 | _ = self; |
| 615 | var sect_offset: usize = 0; | 651 | var sect_offset: usize = 0; |
| 616 | var skip_len: usize = undefined; | 652 | var skip_len: usize = undefined; |
| 617 | while (sect_offset < mod.subsect_info.len) : (sect_offset += skip_len) { | 653 | while (sect_offset < mod.subsect_info.len) : (sect_offset += skip_len) { |
| ... | @@ -631,7 +667,7 @@ pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceL | ... | @@ -631,7 +667,7 @@ pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceL |
| 631 | }; | 667 | }; |
| 632 | | 668 | |
| 633 | while (offset < sect_offset + subsect_hdr.length) { | 669 | while (offset < sect_offset + subsect_hdr.length) { |
| 634 | const entry: *const align(1) pdb.InlineeSourceLine = @ptrCast(&mod.subsect_info[offset]); | 670 | const inlinee_src_line: *const align(1) pdb.InlineeSourceLine = @ptrCast(&mod.subsect_info[offset]); |
| 635 | offset += @sizeOf(pdb.InlineeSourceLine); | 671 | offset += @sizeOf(pdb.InlineeSourceLine); |
| 636 | | 672 | |
| 637 | if (has_extra_files) { | 673 | if (has_extra_files) { |
| ... | @@ -640,33 +676,14 @@ pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceL | ... | @@ -640,33 +676,14 @@ pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceL |
| 640 | offset += file_count.* * @sizeOf(u32); | 676 | offset += file_count.* * @sizeOf(u32); |
| 641 | } | 677 | } |
| 642 | | 678 | |
| 643 | if (entry.inlinee == inlinee) { | 679 | if (inlinee_src_line.inlinee == inlinee) return .{ |
| 644 | const source_file_name = s: { | 680 | .signature = signature.*, |
| 645 | const checksum_offset = mod.checksum_offset orelse return error.MissingDebugInfo; | 681 | .info = inlinee_src_line, |
| 646 | const subsect_index = checksum_offset + entry.file_id; | 682 | }; |
| 647 | const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&mod.subsect_info[subsect_index]); | | |
| 648 | const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; | | |
| 649 | try self.string_table.?.seekTo(strtab_offset); | | |
| 650 | const string_reader = &self.string_table.?.interface; | | |
| 651 | var source_file_name: Io.Writer.Allocating = .init(gpa); | | |
| 652 | defer source_file_name.deinit(); | | |
| 653 | _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); | | |
| 654 | assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API | | |
| 655 | string_reader.toss(1); | | |
| 656 | break :s try source_file_name.toOwnedSlice(); | | |
| 657 | }; | | |
| 658 | errdefer gpa.free(source_file_name); | | |
| 659 | | | |
| 660 | return .{ | | |
| 661 | .line = entry.source_line_num, | | |
| 662 | .column = 0, | | |
| 663 | .file_name = source_file_name, | | |
| 664 | }; | | |
| 665 | } | | |
| 666 | } | 683 | } |
| 667 | } | 684 | } |
| 668 | } | 685 | } |
| 669 | return error.MissingDebugInfo; | 686 | return null; |
| 670 | } | 687 | } |
| 671 | | 688 | |
| 672 | pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation { | 689 | pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation { |
| ... | @@ -676,7 +693,6 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S | ... | @@ -676,7 +693,6 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 676 | | 693 | |
| 677 | var sect_offset: usize = 0; | 694 | var sect_offset: usize = 0; |
| 678 | var skip_len: usize = undefined; | 695 | var skip_len: usize = undefined; |
| 679 | const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; | | |
| 680 | while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { | 696 | while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { |
| 681 | const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&subsect_info[sect_offset]); | 697 | const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&subsect_info[sect_offset]); |
| 682 | skip_len = subsect_hdr.length; | 698 | skip_len = subsect_hdr.length; |
| ... | @@ -723,20 +739,8 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S | ... | @@ -723,20 +739,8 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 723 | | 739 | |
| 724 | // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. | 740 | // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. |
| 725 | if (line_i > 0) { | 741 | if (line_i > 0) { |
| 726 | const subsect_index = checksum_offset + block_hdr.name_index; | 742 | const file_name = try self.getFileName(module, block_hdr.name_index); |
| 727 | const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&module.subsect_info[subsect_index]); | 743 | errdefer gpa.free(file_name); |
| 728 | const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; | | |
| 729 | try self.string_table.?.seekTo(strtab_offset); | | |
| 730 | const source_file_name = s: { | | |
| 731 | const string_reader = &self.string_table.?.interface; | | |
| 732 | var source_file_name: Io.Writer.Allocating = .init(gpa); | | |
| 733 | defer source_file_name.deinit(); | | |
| 734 | _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); | | |
| 735 | assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API | | |
| 736 | string_reader.toss(1); | | |
| 737 | break :s try source_file_name.toOwnedSlice(); | | |
| 738 | }; | | |
| 739 | errdefer gpa.free(source_file_name); | | |
| 740 | | 744 | |
| 741 | const line_entry_idx = line_i - 1; | 745 | const line_entry_idx = line_i - 1; |
| 742 | | 746 | |
| ... | @@ -751,7 +755,7 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S | ... | @@ -751,7 +755,7 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 751 | const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[found_line_index]); | 755 | const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[found_line_index]); |
| 752 | | 756 | |
| 753 | return .{ | 757 | return .{ |
| 754 | .file_name = source_file_name, | 758 | .file_name = file_name, |
| 755 | .line = line_num_entry.flags.start, | 759 | .line = line_num_entry.flags.start, |
| 756 | .column = column, | 760 | .column = column, |
| 757 | }; | 761 | }; |