| ... | ... | @@ -312,7 +312,7 @@ pub const BinaryAnnotation = union(enum) { |
| 312 | 312 | |
| 313 | 313 | const PartialRange = struct { |
| 314 | 314 | line_offset: u32, |
| 315 | | file_offset: u32, |
| 315 | file_id: ?u32, |
| 316 | 316 | code_offset: u32, |
| 317 | 317 | code_length: ?u32, |
| 318 | 318 | }; |
| ... | ... | @@ -322,7 +322,7 @@ pub const BinaryAnnotation = union(enum) { |
| 322 | 322 | .annotations = annotations, |
| 323 | 323 | .curr = .{ |
| 324 | 324 | .line_offset = 0, |
| 325 | | .file_offset = 0, |
| 325 | .file_id = null, |
| 326 | 326 | .code_offset = 0, |
| 327 | 327 | .code_length = null, |
| 328 | 328 | }, |
| ... | ... | @@ -332,7 +332,7 @@ pub const BinaryAnnotation = union(enum) { |
| 332 | 332 | |
| 333 | 333 | pub const Range = struct { |
| 334 | 334 | line_offset: u32, |
| 335 | | file_offset: u32, |
| 335 | file_id: ?u32, |
| 336 | 336 | code_offset: u32, |
| 337 | 337 | code_length: u32, |
| 338 | 338 | |
| ... | ... | @@ -352,7 +352,11 @@ pub const BinaryAnnotation = union(enum) { |
| 352 | 352 | if (self.prev) |*prev| prev.code_length = prev.code_length orelse length; |
| 353 | 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 | 360 | // LLVM never emits this opcode, but it's clear enough how to interpret it so we may as |
| 357 | 361 | // well in case they use it in the future |
| 358 | 362 | .change_code_length_and_code_offset => |info| { |
| ... | ... | @@ -402,7 +406,7 @@ pub const BinaryAnnotation = union(enum) { |
| 402 | 406 | .code_offset = self.curr.code_offset, |
| 403 | 407 | .code_length = self.curr.code_length, |
| 404 | 408 | .line_offset = self.curr.line_offset, |
| 405 | | .file_offset = self.curr.file_offset, |
| 409 | .file_id = self.curr.file_id, |
| 406 | 410 | }; |
| 407 | 411 | const prev = self.prev orelse continue; |
| 408 | 412 | const prev_code_length = prev.code_length orelse continue; |
| ... | ... | @@ -410,7 +414,7 @@ pub const BinaryAnnotation = union(enum) { |
| 410 | 414 | .code_offset = prev.code_offset, |
| 411 | 415 | .code_length = prev_code_length, |
| 412 | 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 | 425 | .code_offset = prev.code_offset, |
| 422 | 426 | .code_length = prev_code_length, |
| 423 | 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 | 592 | return .{ .reader = Io.Reader.fixed(slice) }; |
| 589 | 593 | } |
| 590 | 594 | |
| 591 | | pub fn calculateOffset( |
| 595 | pub fn getInlineSiteSourceLocation( |
| 592 | 596 | self: *Pdb, |
| 597 | mod: *Module, |
| 593 | 598 | site: *align(1) const pdb.InlineSiteSym, |
| 594 | | loc: std.debug.SourceLocation, |
| 599 | inlinee_src_line: *align(1) const pdb.InlineeSourceLine, |
| 595 | 600 | offset_in_func: usize, |
| 596 | | ) error{InvalidDebugInfo, MissingDebugInfo, ReadFailed}!?std.debug.SourceLocation { |
| 601 | ) !?std.debug.SourceLocation { |
| 597 | 602 | var ranges: BinaryAnnotation.RangeIterator = .init(self.getBinaryAnnotations(site)); |
| 598 | 603 | while (try ranges.next()) |range| { |
| 599 | | if (range.contains(offset_in_func)) { |
| 600 | | var result: std.debug.SourceLocation = loc; |
| 601 | | result.line += range.line_offset; |
| 602 | | return result; |
| 603 | | } |
| 604 | if (!range.contains(offset_in_func)) continue; |
| 605 | |
| 606 | const file_id = range.file_id orelse inlinee_src_line.file_id; |
| 607 | const file_name = try self.getFileName(mod, file_id); |
| 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 | 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 | 635 | pub fn getSymbolName(self: *Pdb, proc_sym: *align(1) const pdb.ProcSym) []const u8 { |
| 609 | 636 | _ = self; |
| 610 | 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 { |
| 614 | | const gpa = self.allocator; |
| 640 | pub const InlineeSourceLine = struct { |
| 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 | 651 | var sect_offset: usize = 0; |
| 616 | 652 | var skip_len: usize = undefined; |
| 617 | 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 | 667 | }; |
| 632 | 668 | |
| 633 | 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 | 671 | offset += @sizeOf(pdb.InlineeSourceLine); |
| 636 | 672 | |
| 637 | 673 | if (has_extra_files) { |
| ... | ... | @@ -640,33 +676,14 @@ pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceL |
| 640 | 676 | offset += file_count.* * @sizeOf(u32); |
| 641 | 677 | } |
| 642 | 678 | |
| 643 | | if (entry.inlinee == inlinee) { |
| 644 | | const source_file_name = s: { |
| 645 | | const checksum_offset = mod.checksum_offset orelse return error.MissingDebugInfo; |
| 646 | | const subsect_index = checksum_offset + entry.file_id; |
| 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 | | } |
| 679 | if (inlinee_src_line.inlinee == inlinee) return .{ |
| 680 | .signature = signature.*, |
| 681 | .info = inlinee_src_line, |
| 682 | }; |
| 666 | 683 | } |
| 667 | 684 | } |
| 668 | 685 | } |
| 669 | | return error.MissingDebugInfo; |
| 686 | return null; |
| 670 | 687 | } |
| 671 | 688 | |
| 672 | 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 | 693 | |
| 677 | 694 | var sect_offset: usize = 0; |
| 678 | 695 | var skip_len: usize = undefined; |
| 679 | | const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; |
| 680 | 696 | while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { |
| 681 | 697 | const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&subsect_info[sect_offset]); |
| 682 | 698 | skip_len = subsect_hdr.length; |
| ... | ... | @@ -723,20 +739,8 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 723 | 739 | |
| 724 | 740 | // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. |
| 725 | 741 | if (line_i > 0) { |
| 726 | | const subsect_index = checksum_offset + block_hdr.name_index; |
| 727 | | const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&module.subsect_info[subsect_index]); |
| 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); |
| 742 | const file_name = try self.getFileName(module, block_hdr.name_index); |
| 743 | errdefer gpa.free(file_name); |
| 740 | 744 | |
| 741 | 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 | 755 | const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[found_line_index]); |
| 752 | 756 | |
| 753 | 757 | return .{ |
| 754 | | .file_name = source_file_name, |
| 758 | .file_name = file_name, |
| 755 | 759 | .line = line_num_entry.flags.start, |
| 756 | 760 | .column = column, |
| 757 | 761 | }; |