//===- NativeInlineSiteSymbol.cpp - info about inline sites -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" using namespace llvm; using namespace llvm::codeview; using namespace llvm::pdb; NativeInlineSiteSymbol::NativeInlineSiteSymbol( NativeSession &Session, SymIndexId Id, const codeview::InlineSiteSym &Sym, uint64_t ParentAddr) : NativeRawSymbol(Session, PDB_SymType::InlineSite, Id), Sym(Sym), ParentAddr(ParentAddr) {} NativeInlineSiteSymbol::~NativeInlineSiteSymbol() {} void NativeInlineSiteSymbol::dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields, PdbSymbolIdField RecurseIdFields) const { NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); dumpSymbolField(OS, "name", getName(), Indent); } static Optional findInlineeByTypeIndex(TypeIndex Id, ModuleDebugStreamRef &ModS) { for (const auto &SS : ModS.getSubsectionsArray()) { if (SS.kind() != DebugSubsectionKind::InlineeLines) continue; DebugInlineeLinesSubsectionRef InlineeLines; BinaryStreamReader Reader(SS.getRecordData()); if (auto EC = InlineeLines.initialize(Reader)) { consumeError(std::move(EC)); continue; } for (const InlineeSourceLine &Line : InlineeLines) if (Line.Header->Inlinee == Id) return Line; } return None; } std::string NativeInlineSiteSymbol::getName() const { auto Tpi = Session.getPDBFile().getPDBTpiStream(); if (!Tpi) { consumeError(Tpi.takeError()); return ""; } auto Ipi = Session.getPDBFile().getPDBIpiStream(); if (!Ipi) { consumeError(Ipi.takeError()); return ""; } LazyRandomTypeCollection &Types = Tpi->typeCollection(); LazyRandomTypeCollection &Ids = Ipi->typeCollection(); CVType InlineeType = Ids.getType(Sym.Inlinee); std::string QualifiedName; if (InlineeType.kind() == LF_MFUNC_ID) { MemberFuncIdRecord MFRecord; cantFail(TypeDeserializer::deserializeAs(InlineeType, MFRecord)); TypeIndex ClassTy = MFRecord.getClassType(); QualifiedName.append(std::string(Types.getTypeName(ClassTy))); QualifiedName.append("::"); } else if (InlineeType.kind() == LF_FUNC_ID) { FuncIdRecord FRecord; cantFail( TypeDeserializer::deserializeAs(InlineeType, FRecord)); TypeIndex ParentScope = FRecord.getParentScope(); if (!ParentScope.isNoneType()) { QualifiedName.append(std::string(Ids.getTypeName(ParentScope))); QualifiedName.append("::"); } } QualifiedName.append(std::string(Ids.getTypeName(Sym.Inlinee))); return QualifiedName; } void NativeInlineSiteSymbol::getLineOffset(uint32_t OffsetInFunc, uint32_t &LineOffset, uint32_t &FileOffset) const { LineOffset = 0; FileOffset = 0; uint32_t CodeOffset = 0; for (const auto &Annot : Sym.annotations()) { switch (Annot.OpCode) { case BinaryAnnotationsOpCode::CodeOffset: case BinaryAnnotationsOpCode::ChangeCodeOffset: case BinaryAnnotationsOpCode::ChangeCodeLength: CodeOffset += Annot.U1; break; case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: CodeOffset += Annot.U2; break; case BinaryAnnotationsOpCode::ChangeLineOffset: case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: CodeOffset += Annot.U1; LineOffset += Annot.S1; break; case BinaryAnnotationsOpCode::ChangeFile: FileOffset = Annot.U1; break; default: break; } if (CodeOffset >= OffsetInFunc) return; } } std::unique_ptr NativeInlineSiteSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { uint16_t Modi; if (!Session.moduleIndexForVA(VA, Modi)) return nullptr; Expected ModS = Session.getModuleDebugStream(Modi); if (!ModS) { consumeError(ModS.takeError()); return nullptr; } Expected Checksums = ModS->findChecksumsSubsection(); if (!Checksums) { consumeError(Checksums.takeError()); return nullptr; } // Get the line number offset and source file offset. uint32_t SrcLineOffset; uint32_t SrcFileOffset; getLineOffset(VA - ParentAddr, SrcLineOffset, SrcFileOffset); // Get line info from inlinee line table. Optional Inlinee = findInlineeByTypeIndex(Sym.Inlinee, ModS.get()); if (!Inlinee) return nullptr; uint32_t SrcLine = Inlinee->Header->SourceLineNum + SrcLineOffset; uint32_t SrcCol = 0; // Inline sites don't seem to have column info. uint32_t FileChecksumOffset = (SrcFileOffset == 0) ? Inlinee->Header->FileID : SrcFileOffset; auto ChecksumIter = Checksums->getArray().at(FileChecksumOffset); uint32_t SrcFileId = Session.getSymbolCache().getOrCreateSourceFile(*ChecksumIter); uint32_t LineSect, LineOff; Session.addressForVA(VA, LineSect, LineOff); NativeLineNumber LineNum(Session, SrcLine, SrcCol, LineSect, LineOff, Length, SrcFileId, Modi); auto SrcFile = Session.getSymbolCache().getSourceFileById(SrcFileId); std::vector Lines{LineNum}; return std::make_unique(std::move(Lines)); }