1 | //===- NativeInlineSiteSymbol.cpp - info about inline sites -----*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h" |
10 | |
11 | #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" |
12 | #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" |
13 | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" |
14 | #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" |
15 | #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" |
16 | #include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" |
17 | #include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h" |
18 | #include "llvm/DebugInfo/PDB/Native/NativeSession.h" |
19 | #include "llvm/DebugInfo/PDB/Native/PDBFile.h" |
20 | #include "llvm/DebugInfo/PDB/Native/SymbolCache.h" |
21 | #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
22 | #include "llvm/DebugInfo/PDB/PDBExtras.h" |
23 | |
24 | using namespace llvm; |
25 | using namespace llvm::codeview; |
26 | using namespace llvm::pdb; |
27 | |
28 | NativeInlineSiteSymbol::NativeInlineSiteSymbol( |
29 | NativeSession &Session, SymIndexId Id, const codeview::InlineSiteSym &Sym, |
30 | uint64_t ParentAddr) |
31 | : NativeRawSymbol(Session, PDB_SymType::InlineSite, Id), Sym(Sym), |
32 | ParentAddr(ParentAddr) {} |
33 | |
34 | NativeInlineSiteSymbol::~NativeInlineSiteSymbol() = default; |
35 | |
36 | void NativeInlineSiteSymbol::dump(raw_ostream &OS, int Indent, |
37 | PdbSymbolIdField ShowIdFields, |
38 | PdbSymbolIdField RecurseIdFields) const { |
39 | NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); |
40 | dumpSymbolField(OS, Name: "name" , Value: getName(), Indent); |
41 | } |
42 | |
43 | static std::optional<InlineeSourceLine> |
44 | findInlineeByTypeIndex(TypeIndex Id, ModuleDebugStreamRef &ModS) { |
45 | for (const auto &SS : ModS.getSubsectionsArray()) { |
46 | if (SS.kind() != DebugSubsectionKind::InlineeLines) |
47 | continue; |
48 | |
49 | DebugInlineeLinesSubsectionRef InlineeLines; |
50 | BinaryStreamReader Reader(SS.getRecordData()); |
51 | if (auto EC = InlineeLines.initialize(Reader)) { |
52 | consumeError(Err: std::move(EC)); |
53 | continue; |
54 | } |
55 | |
56 | for (const InlineeSourceLine &Line : InlineeLines) |
57 | if (Line.Header->Inlinee == Id) |
58 | return Line; |
59 | } |
60 | return std::nullopt; |
61 | } |
62 | |
63 | std::string NativeInlineSiteSymbol::getName() const { |
64 | auto Tpi = Session.getPDBFile().getPDBTpiStream(); |
65 | if (!Tpi) { |
66 | consumeError(Err: Tpi.takeError()); |
67 | return "" ; |
68 | } |
69 | auto Ipi = Session.getPDBFile().getPDBIpiStream(); |
70 | if (!Ipi) { |
71 | consumeError(Err: Ipi.takeError()); |
72 | return "" ; |
73 | } |
74 | |
75 | LazyRandomTypeCollection &Types = Tpi->typeCollection(); |
76 | LazyRandomTypeCollection &Ids = Ipi->typeCollection(); |
77 | CVType InlineeType = Ids.getType(Index: Sym.Inlinee); |
78 | std::string QualifiedName; |
79 | if (InlineeType.kind() == LF_MFUNC_ID) { |
80 | MemberFuncIdRecord MFRecord; |
81 | cantFail(Err: TypeDeserializer::deserializeAs<MemberFuncIdRecord>(CVT&: InlineeType, |
82 | Record&: MFRecord)); |
83 | TypeIndex ClassTy = MFRecord.getClassType(); |
84 | QualifiedName.append(str: std::string(Types.getTypeName(Index: ClassTy))); |
85 | QualifiedName.append(s: "::" ); |
86 | } else if (InlineeType.kind() == LF_FUNC_ID) { |
87 | FuncIdRecord FRecord; |
88 | cantFail( |
89 | Err: TypeDeserializer::deserializeAs<FuncIdRecord>(CVT&: InlineeType, Record&: FRecord)); |
90 | TypeIndex ParentScope = FRecord.getParentScope(); |
91 | if (!ParentScope.isNoneType()) { |
92 | QualifiedName.append(str: std::string(Ids.getTypeName(Index: ParentScope))); |
93 | QualifiedName.append(s: "::" ); |
94 | } |
95 | } |
96 | |
97 | QualifiedName.append(str: std::string(Ids.getTypeName(Index: Sym.Inlinee))); |
98 | return QualifiedName; |
99 | } |
100 | |
101 | void NativeInlineSiteSymbol::getLineOffset(uint32_t OffsetInFunc, |
102 | uint32_t &LineOffset, |
103 | uint32_t &FileOffset) const { |
104 | LineOffset = 0; |
105 | FileOffset = 0; |
106 | uint32_t CodeOffset = 0; |
107 | std::optional<uint32_t> CodeOffsetBase; |
108 | std::optional<uint32_t> CodeOffsetEnd; |
109 | std::optional<int32_t> CurLineOffset; |
110 | std::optional<int32_t> NextLineOffset; |
111 | std::optional<uint32_t> NextFileOffset; |
112 | auto UpdateCodeOffset = [&](uint32_t Delta) { |
113 | if (!CodeOffsetBase) |
114 | CodeOffsetBase = CodeOffset; |
115 | else if (!CodeOffsetEnd) |
116 | CodeOffsetEnd = *CodeOffsetBase + Delta; |
117 | }; |
118 | auto UpdateLineOffset = [&](int32_t Delta) { |
119 | LineOffset += Delta; |
120 | if (!CodeOffsetBase || !CurLineOffset) |
121 | CurLineOffset = LineOffset; |
122 | else |
123 | NextLineOffset = LineOffset; |
124 | }; |
125 | auto UpdateFileOffset = [&](uint32_t Offset) { |
126 | if (!CodeOffsetBase) |
127 | FileOffset = Offset; |
128 | else |
129 | NextFileOffset = Offset; |
130 | }; |
131 | auto ValidateAndReset = [&]() { |
132 | // Current range is finished. Check if OffsetInFunc is in the range. |
133 | if (CodeOffsetBase && CodeOffsetEnd && CurLineOffset) { |
134 | if (CodeOffsetBase <= OffsetInFunc && OffsetInFunc < CodeOffsetEnd) { |
135 | LineOffset = *CurLineOffset; |
136 | return true; |
137 | } |
138 | // Set base, end, file offset and line offset for next range. |
139 | if (NextFileOffset) |
140 | FileOffset = *NextFileOffset; |
141 | if (NextLineOffset) { |
142 | CurLineOffset = NextLineOffset; |
143 | NextLineOffset = std::nullopt; |
144 | } |
145 | CodeOffsetBase = CodeOffsetEnd; |
146 | CodeOffsetEnd = NextFileOffset = std::nullopt; |
147 | } |
148 | return false; |
149 | }; |
150 | for (const auto &Annot : Sym.annotations()) { |
151 | switch (Annot.OpCode) { |
152 | case BinaryAnnotationsOpCode::CodeOffset: |
153 | case BinaryAnnotationsOpCode::ChangeCodeOffset: |
154 | case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: |
155 | CodeOffset += Annot.U1; |
156 | UpdateCodeOffset(Annot.U1); |
157 | break; |
158 | case BinaryAnnotationsOpCode::ChangeCodeLength: |
159 | UpdateCodeOffset(Annot.U1); |
160 | break; |
161 | case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: |
162 | CodeOffset += Annot.U2; |
163 | UpdateCodeOffset(Annot.U2); |
164 | UpdateCodeOffset(Annot.U1); |
165 | break; |
166 | case BinaryAnnotationsOpCode::ChangeLineOffset: |
167 | UpdateLineOffset(Annot.S1); |
168 | break; |
169 | case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: |
170 | CodeOffset += Annot.U1; |
171 | UpdateCodeOffset(Annot.U1); |
172 | UpdateLineOffset(Annot.S1); |
173 | break; |
174 | case BinaryAnnotationsOpCode::ChangeFile: |
175 | UpdateFileOffset(Annot.U1); |
176 | break; |
177 | default: |
178 | break; |
179 | } |
180 | |
181 | if (ValidateAndReset()) |
182 | return; |
183 | } |
184 | } |
185 | |
186 | std::unique_ptr<IPDBEnumLineNumbers> |
187 | NativeInlineSiteSymbol::findInlineeLinesByVA(uint64_t VA, |
188 | uint32_t Length) const { |
189 | uint16_t Modi; |
190 | if (!Session.moduleIndexForVA(VA, ModuleIndex&: Modi)) |
191 | return nullptr; |
192 | |
193 | Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Index: Modi); |
194 | if (!ModS) { |
195 | consumeError(Err: ModS.takeError()); |
196 | return nullptr; |
197 | } |
198 | |
199 | Expected<DebugChecksumsSubsectionRef> Checksums = |
200 | ModS->findChecksumsSubsection(); |
201 | if (!Checksums) { |
202 | consumeError(Err: Checksums.takeError()); |
203 | return nullptr; |
204 | } |
205 | |
206 | // Get the line number offset and source file offset. |
207 | uint32_t SrcLineOffset; |
208 | uint32_t SrcFileOffset; |
209 | getLineOffset(OffsetInFunc: VA - ParentAddr, LineOffset&: SrcLineOffset, FileOffset&: SrcFileOffset); |
210 | |
211 | // Get line info from inlinee line table. |
212 | std::optional<InlineeSourceLine> Inlinee = |
213 | findInlineeByTypeIndex(Id: Sym.Inlinee, ModS&: ModS.get()); |
214 | |
215 | if (!Inlinee) |
216 | return nullptr; |
217 | |
218 | uint32_t SrcLine = Inlinee->Header->SourceLineNum + SrcLineOffset; |
219 | uint32_t SrcCol = 0; // Inline sites don't seem to have column info. |
220 | uint32_t FileChecksumOffset = |
221 | (SrcFileOffset == 0) ? Inlinee->Header->FileID : SrcFileOffset; |
222 | |
223 | auto ChecksumIter = Checksums->getArray().at(Offset: FileChecksumOffset); |
224 | uint32_t SrcFileId = |
225 | Session.getSymbolCache().getOrCreateSourceFile(Checksum: *ChecksumIter); |
226 | |
227 | uint32_t LineSect, LineOff; |
228 | Session.addressForVA(VA, Section&: LineSect, Offset&: LineOff); |
229 | NativeLineNumber LineNum(Session, SrcLine, SrcCol, LineSect, LineOff, Length, |
230 | SrcFileId, Modi); |
231 | auto SrcFile = Session.getSymbolCache().getSourceFileById(FileId: SrcFileId); |
232 | std::vector<NativeLineNumber> Lines{LineNum}; |
233 | |
234 | return std::make_unique<NativeEnumLineNumbers>(args: std::move(Lines)); |
235 | } |
236 | |