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/NativeSession.h"
18 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
19 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
20 #include "llvm/DebugInfo/PDB/PDBExtras.h"
21 
22 using namespace llvm;
23 using namespace llvm::codeview;
24 using namespace llvm::pdb;
25 
26 NativeInlineSiteSymbol::NativeInlineSiteSymbol(
27     NativeSession &Session, SymIndexId Id, const codeview::InlineSiteSym &Sym,
28     uint64_t ParentAddr)
29     : NativeRawSymbol(Session, PDB_SymType::InlineSite, Id), Sym(Sym),
30       ParentAddr(ParentAddr) {}
31 
32 NativeInlineSiteSymbol::~NativeInlineSiteSymbol() = default;
33 
34 void NativeInlineSiteSymbol::dump(raw_ostream &OS, int Indent,
35                                   PdbSymbolIdField ShowIdFields,
36                                   PdbSymbolIdField RecurseIdFields) const {
37   NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
38   dumpSymbolField(OS, "name", getName(), Indent);
39 }
40 
41 static Optional<InlineeSourceLine>
42 findInlineeByTypeIndex(TypeIndex Id, ModuleDebugStreamRef &ModS) {
43   for (const auto &SS : ModS.getSubsectionsArray()) {
44     if (SS.kind() != DebugSubsectionKind::InlineeLines)
45       continue;
46 
47     DebugInlineeLinesSubsectionRef InlineeLines;
48     BinaryStreamReader Reader(SS.getRecordData());
49     if (auto EC = InlineeLines.initialize(Reader)) {
50       consumeError(std::move(EC));
51       continue;
52     }
53 
54     for (const InlineeSourceLine &Line : InlineeLines)
55       if (Line.Header->Inlinee == Id)
56         return Line;
57   }
58   return None;
59 }
60 
61 std::string NativeInlineSiteSymbol::getName() const {
62   auto Tpi = Session.getPDBFile().getPDBTpiStream();
63   if (!Tpi) {
64     consumeError(Tpi.takeError());
65     return "";
66   }
67   auto Ipi = Session.getPDBFile().getPDBIpiStream();
68   if (!Ipi) {
69     consumeError(Ipi.takeError());
70     return "";
71   }
72 
73   LazyRandomTypeCollection &Types = Tpi->typeCollection();
74   LazyRandomTypeCollection &Ids = Ipi->typeCollection();
75   CVType InlineeType = Ids.getType(Sym.Inlinee);
76   std::string QualifiedName;
77   if (InlineeType.kind() == LF_MFUNC_ID) {
78     MemberFuncIdRecord MFRecord;
79     cantFail(TypeDeserializer::deserializeAs<MemberFuncIdRecord>(InlineeType,
80                                                                  MFRecord));
81     TypeIndex ClassTy = MFRecord.getClassType();
82     QualifiedName.append(std::string(Types.getTypeName(ClassTy)));
83     QualifiedName.append("::");
84   } else if (InlineeType.kind() == LF_FUNC_ID) {
85     FuncIdRecord FRecord;
86     cantFail(
87         TypeDeserializer::deserializeAs<FuncIdRecord>(InlineeType, FRecord));
88     TypeIndex ParentScope = FRecord.getParentScope();
89     if (!ParentScope.isNoneType()) {
90       QualifiedName.append(std::string(Ids.getTypeName(ParentScope)));
91       QualifiedName.append("::");
92     }
93   }
94 
95   QualifiedName.append(std::string(Ids.getTypeName(Sym.Inlinee)));
96   return QualifiedName;
97 }
98 
99 void NativeInlineSiteSymbol::getLineOffset(uint32_t OffsetInFunc,
100                                            uint32_t &LineOffset,
101                                            uint32_t &FileOffset) const {
102   LineOffset = 0;
103   FileOffset = 0;
104   uint32_t CodeOffset = 0;
105   for (const auto &Annot : Sym.annotations()) {
106     switch (Annot.OpCode) {
107     case BinaryAnnotationsOpCode::CodeOffset:
108     case BinaryAnnotationsOpCode::ChangeCodeOffset:
109     case BinaryAnnotationsOpCode::ChangeCodeLength:
110       CodeOffset += Annot.U1;
111       break;
112     case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
113       CodeOffset += Annot.U2;
114       break;
115     case BinaryAnnotationsOpCode::ChangeLineOffset:
116     case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
117       CodeOffset += Annot.U1;
118       LineOffset += Annot.S1;
119       break;
120     case BinaryAnnotationsOpCode::ChangeFile:
121       FileOffset = Annot.U1;
122       break;
123     default:
124       break;
125     }
126 
127     if (CodeOffset >= OffsetInFunc)
128       return;
129   }
130 }
131 
132 std::unique_ptr<IPDBEnumLineNumbers>
133 NativeInlineSiteSymbol::findInlineeLinesByVA(uint64_t VA,
134                                              uint32_t Length) const {
135   uint16_t Modi;
136   if (!Session.moduleIndexForVA(VA, Modi))
137     return nullptr;
138 
139   Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
140   if (!ModS) {
141     consumeError(ModS.takeError());
142     return nullptr;
143   }
144 
145   Expected<DebugChecksumsSubsectionRef> Checksums =
146       ModS->findChecksumsSubsection();
147   if (!Checksums) {
148     consumeError(Checksums.takeError());
149     return nullptr;
150   }
151 
152   // Get the line number offset and source file offset.
153   uint32_t SrcLineOffset;
154   uint32_t SrcFileOffset;
155   getLineOffset(VA - ParentAddr, SrcLineOffset, SrcFileOffset);
156 
157   // Get line info from inlinee line table.
158   Optional<InlineeSourceLine> Inlinee =
159       findInlineeByTypeIndex(Sym.Inlinee, ModS.get());
160 
161   if (!Inlinee)
162     return nullptr;
163 
164   uint32_t SrcLine = Inlinee->Header->SourceLineNum + SrcLineOffset;
165   uint32_t SrcCol = 0; // Inline sites don't seem to have column info.
166   uint32_t FileChecksumOffset =
167       (SrcFileOffset == 0) ? Inlinee->Header->FileID : SrcFileOffset;
168 
169   auto ChecksumIter = Checksums->getArray().at(FileChecksumOffset);
170   uint32_t SrcFileId =
171       Session.getSymbolCache().getOrCreateSourceFile(*ChecksumIter);
172 
173   uint32_t LineSect, LineOff;
174   Session.addressForVA(VA, LineSect, LineOff);
175   NativeLineNumber LineNum(Session, SrcLine, SrcCol, LineSect, LineOff, Length,
176                            SrcFileId, Modi);
177   auto SrcFile = Session.getSymbolCache().getSourceFileById(SrcFileId);
178   std::vector<NativeLineNumber> Lines{LineNum};
179 
180   return std::make_unique<NativeEnumLineNumbers>(std::move(Lines));
181 }
182