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", 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(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(Tpi.takeError()); 67 return ""; 68 } 69 auto Ipi = Session.getPDBFile().getPDBIpiStream(); 70 if (!Ipi) { 71 consumeError(Ipi.takeError()); 72 return ""; 73 } 74 75 LazyRandomTypeCollection &Types = Tpi->typeCollection(); 76 LazyRandomTypeCollection &Ids = Ipi->typeCollection(); 77 CVType InlineeType = Ids.getType(Sym.Inlinee); 78 std::string QualifiedName; 79 if (InlineeType.kind() == LF_MFUNC_ID) { 80 MemberFuncIdRecord MFRecord; 81 cantFail(TypeDeserializer::deserializeAs<MemberFuncIdRecord>(InlineeType, 82 MFRecord)); 83 TypeIndex ClassTy = MFRecord.getClassType(); 84 QualifiedName.append(std::string(Types.getTypeName(ClassTy))); 85 QualifiedName.append("::"); 86 } else if (InlineeType.kind() == LF_FUNC_ID) { 87 FuncIdRecord FRecord; 88 cantFail( 89 TypeDeserializer::deserializeAs<FuncIdRecord>(InlineeType, FRecord)); 90 TypeIndex ParentScope = FRecord.getParentScope(); 91 if (!ParentScope.isNoneType()) { 92 QualifiedName.append(std::string(Ids.getTypeName(ParentScope))); 93 QualifiedName.append("::"); 94 } 95 } 96 97 QualifiedName.append(std::string(Ids.getTypeName(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, Modi)) 191 return nullptr; 192 193 Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi); 194 if (!ModS) { 195 consumeError(ModS.takeError()); 196 return nullptr; 197 } 198 199 Expected<DebugChecksumsSubsectionRef> Checksums = 200 ModS->findChecksumsSubsection(); 201 if (!Checksums) { 202 consumeError(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(VA - ParentAddr, SrcLineOffset, SrcFileOffset); 210 211 // Get line info from inlinee line table. 212 std::optional<InlineeSourceLine> Inlinee = 213 findInlineeByTypeIndex(Sym.Inlinee, 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(FileChecksumOffset); 224 uint32_t SrcFileId = 225 Session.getSymbolCache().getOrCreateSourceFile(*ChecksumIter); 226 227 uint32_t LineSect, LineOff; 228 Session.addressForVA(VA, LineSect, LineOff); 229 NativeLineNumber LineNum(Session, SrcLine, SrcCol, LineSect, LineOff, Length, 230 SrcFileId, Modi); 231 auto SrcFile = Session.getSymbolCache().getSourceFileById(SrcFileId); 232 std::vector<NativeLineNumber> Lines{LineNum}; 233 234 return std::make_unique<NativeEnumLineNumbers>(std::move(Lines)); 235 } 236