llvm.org GIT mirror llvm / 524187c
[llvm-pdbutil] Dump inline call site line table annotations This ports and improves on some existing llvm-readobj -codeview dumping functionality that llvm-pdbutil lacked. Helpful for comparing inline line tables between MSVC and clang. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@362037 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 2 months ago
3 changed file(s) with 136 addition(s) and 31 deletion(s). Raw diff Collapse all Expand all
1212 #include "llvm/ADT/ArrayRef.h"
1313 #include "llvm/ADT/Optional.h"
1414 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ADT/iterator.h"
1516 #include "llvm/ADT/iterator_range.h"
1617 #include "llvm/DebugInfo/CodeView/CVRecord.h"
1718 #include "llvm/DebugInfo/CodeView/CodeView.h"
154155 uint32_t RecordOffset;
155156 };
156157
157 struct BinaryAnnotationIterator {
158 struct AnnotationData {
159 BinaryAnnotationsOpCode OpCode;
160 StringRef Name;
161 uint32_t U1;
162 uint32_t U2;
163 int32_t S1;
164 };
165
158 struct DecodedAnnotation {
159 StringRef Name;
160 ArrayRef Bytes;
161 BinaryAnnotationsOpCode OpCode;
162 uint32_t U1 = 0;
163 uint32_t U2 = 0;
164 int32_t S1 = 0;
165 };
166
167 struct BinaryAnnotationIterator
168 : public iterator_facade_base
169 std::forward_iterator_tag,
170 DecodedAnnotation> {
166171 BinaryAnnotationIterator() = default;
167172 BinaryAnnotationIterator(ArrayRef Annotations) : Data(Annotations) {}
168173 BinaryAnnotationIterator(const BinaryAnnotationIterator &Other)
170175
171176 bool operator==(BinaryAnnotationIterator Other) const {
172177 return Data == Other.Data;
173 }
174
175 bool operator!=(const BinaryAnnotationIterator &Other) const {
176 return !(*this == Other);
177178 }
178179
179180 BinaryAnnotationIterator &operator=(const BinaryAnnotationIterator Other) {
192193 return *this;
193194 }
194195
195 BinaryAnnotationIterator operator++(int) {
196 BinaryAnnotationIterator Orig(*this);
197 ++(*this);
198 return Orig;
199 }
200
201 const AnnotationData &operator*() {
196 const DecodedAnnotation &operator*() {
202197 ParseCurrentAnnotation();
203198 return Current.getValue();
204199 }
240235 (ThirdByte << 8) | FourthByte;
241236
242237 return -1;
243 };
238 }
244239
245240 static int32_t DecodeSignedOperand(uint32_t Operand) {
246241 if (Operand & 1)
247242 return -(Operand >> 1);
248243 return Operand >> 1;
249 };
244 }
250245
251246 static int32_t DecodeSignedOperand(ArrayRef &Annotations) {
252247 return DecodeSignedOperand(GetCompressedAnnotation(Annotations));
253 };
248 }
254249
255250 bool ParseCurrentAnnotation() {
256251 if (Current.hasValue())
258253
259254 Next = Data;
260255 uint32_t Op = GetCompressedAnnotation(Next);
261 AnnotationData Result;
256 DecodedAnnotation Result;
262257 Result.OpCode = static_cast(Op);
263258 switch (Result.OpCode) {
264259 case BinaryAnnotationsOpCode::Invalid:
323318 break;
324319 }
325320 }
321 Result.Bytes = Data.take_front(Data.size() - Next.size());
326322 Current = Result;
327323 return true;
328324 }
329325
330 Optional<AnnotationData> Current;
326 Optional<DecodedAnnotation> Current;
331327 ArrayRef Data;
332328 ArrayRef Next;
333329 };
None # RUN: llvm-mc -triple=i686-pc-win32 -filetype=obj < %s | llvm-readobj --codeview | FileCheck %s
0 # RUN: llvm-mc -triple=i686-pc-win32 -filetype=obj %s -o %t.o
1 # RUN: llvm-readobj --codeview %t.o | FileCheck %s
2 # RUN: llvm-objdump -d %t.o | FileCheck %s --check-prefix=ASM
3 # RUN: llvm-pdbutil dump -symbols %t.o | FileCheck %s --check-prefix=PDB
14 .text
25 .def @feat.00;
36 .scl 3;
4245 retl
4346 Lfunc_end0:
4447
48 # Check the disassembly so we have accurate instruction offsets in hex.
49 # ASM-LABEL: ?baz@@YAXXZ:
50 # ASM-NEXT: 0: {{.*}} pushl %eax
51 # ASM-NEXT: 1: {{.*}} addl $6, 0
52 # ASM-NEXT: 8: {{.*}} addl $4, 0
53 # ASM-NEXT: f: {{.*}} movl $1, (%esp)
54 # ASM-NEXT: 16: {{.*}} leal (%esp), %eax
55 # ASM-NEXT: 19: {{.*}} addl %eax, 0
56 # ASM-NEXT: 1f: {{.*}} addl $2, 0
57 # ASM-NEXT: 26: {{.*}} addl $3, 0
58 # ASM-NEXT: 2d: {{.*}} addl $5, 0
59 # ASM-NEXT: 34: {{.*}} addl $7, 0
60 # ASM-NEXT: 3b: {{.*}} popl %eax
61 # ASM-NEXT: 3c: {{.*}} retl
62
63 # PDB: S_GPROC32_ID {{.*}} `baz`
64 # PDB: S_INLINESITE
65 # PDB-NEXT: inlinee = 0x1003 (bar), parent = 0, end = 0
66 # PDB-NEXT: 0B08 code 0x8 (+0x8) line 0 (-0)
67 # PDB-NEXT: 0B27 code 0xF (+0x7) line 1 (+1)
68 # PDB-NEXT: 0602 line 2 (+1)
69 # PDB-NEXT: 031E code 0x2D (+0x1E)
70 # PDB-NEXT: 0407 code end 0x34 (+0x7)
71 # PDB: S_INLINESITE
72 # PDB-NEXT: inlinee = 0x1004 (foo), parent = 0, end = 0
73 # PDB-NEXT: 0B0F code 0xF (+0xF) line 0 (-0)
74 # PDB-NEXT: 0B2A code 0x19 (+0xA) line 1 (+1)
75 # PDB-NEXT: 0B26 code 0x1F (+0x6) line 2 (+1)
76 # PDB-NEXT: 0B27 code 0x26 (+0x7) line 3 (+1)
77 # PDB-NEXT: 0407 code end 0x2D (+0x7)
78 # PEB: S_INLINESITE_END
79 # PEB: S_INLINESITE_END
80 # PEB: S_PROC_ID_END
81
4582 .section .debug$T,"dr"
4683 .long 4
4784 .short 6
649649
650650 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, InlineSiteSym &IS) {
651651 AutoIndent Indent(P, 7);
652 auto Bytes = makeArrayRef(IS.AnnotationData);
653 StringRef Annotations(reinterpret_cast(Bytes.begin()),
654 Bytes.size());
655
656652 P.formatLine("inlinee = {0}, parent = {1}, end = {2}", idIndex(IS.Inlinee),
657653 IS.Parent, IS.End);
658 P.formatLine("annotations = {0}", toHex(Annotations));
654
655 // Break down the annotation byte code and calculate code and line offsets.
656 // FIXME: It would be helpful if we could look up the initial file and inlinee
657 // lines offset using the inlinee index above.
658 uint32_t CodeOffset = 0;
659 int32_t LineOffset = 0;
660 for (auto &Annot : IS.annotations()) {
661 P.formatLine(" {0}", fmt_align(toHex(Annot.Bytes), AlignStyle::Left, 9));
662
663 auto formatCodeOffset = [&](uint32_t Delta) {
664 CodeOffset += Delta;
665 P.format(" code 0x{0} (+0x{1})", utohexstr(CodeOffset), utohexstr(Delta));
666 };
667 auto formatCodeLength = [&](uint32_t Length) {
668 // Notably, changing the code length does not affect the code offset.
669 P.format(" code end 0x{0} (+0x{1})", utohexstr(CodeOffset + Length),
670 utohexstr(Length));
671 };
672 auto formatLineOffset = [&](int32_t Delta) {
673 LineOffset += Delta;
674 char Sign = Delta > 0 ? '+' : '-';
675 P.format(" line {0} ({1}{2})", LineOffset, Sign, std::abs(Delta));
676 };
677
678 // Use the opcode to interpret the integer values.
679 switch (Annot.OpCode) {
680 case BinaryAnnotationsOpCode::Invalid:
681 break;
682 case BinaryAnnotationsOpCode::CodeOffset:
683 case BinaryAnnotationsOpCode::ChangeCodeOffset:
684 formatCodeOffset(Annot.U1);
685 break;
686 case BinaryAnnotationsOpCode::ChangeLineOffset:
687 formatLineOffset(Annot.S1);
688 break;
689 case BinaryAnnotationsOpCode::ChangeCodeLength:
690 formatCodeLength(Annot.U1);
691 break;
692 case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
693 formatCodeOffset(Annot.U1);
694 formatLineOffset(Annot.S1);
695 break;
696 case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
697 formatCodeOffset(Annot.U2);
698 formatCodeLength(Annot.U1);
699 break;
700
701 case BinaryAnnotationsOpCode::ChangeFile: {
702 uint32_t FileOffset = Annot.U1;
703 StringRef Filename = "";
704 if (SymGroup) {
705 if (Expected MaybeFile =
706 SymGroup->getNameFromStringTable(FileOffset))
707 Filename = *MaybeFile;
708 else
709 return MaybeFile.takeError();
710 }
711 P.format(" setfile {0} 0x{1}", utohexstr(FileOffset));
712 break;
713 }
714
715 // The rest of these are hard to convince MSVC to emit, so they are not as
716 // well understood.
717 case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
718 formatCodeOffset(Annot.U1);
719 break;
720 case BinaryAnnotationsOpCode::ChangeLineEndDelta:
721 case BinaryAnnotationsOpCode::ChangeRangeKind:
722 case BinaryAnnotationsOpCode::ChangeColumnStart:
723 case BinaryAnnotationsOpCode::ChangeColumnEnd:
724 P.format(" {0} {1}", Annot.Name, Annot.U1);
725 break;
726 case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
727 P.format(" {0} {1}", Annot.Name, Annot.S1);
728 break;
729 }
730 }
659731 return Error::success();
660732 }
661733