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