236 lines · cpp
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-exception6//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 24using namespace llvm;25using namespace llvm::codeview;26using namespace llvm::pdb;27 28NativeInlineSiteSymbol::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 34NativeInlineSiteSymbol::~NativeInlineSiteSymbol() = default;35 36void 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 43static std::optional<InlineeSourceLine>44findInlineeByTypeIndex(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 63std::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 101void 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 else123 NextLineOffset = LineOffset;124 };125 auto UpdateFileOffset = [&](uint32_t Offset) {126 if (!CodeOffsetBase)127 FileOffset = Offset;128 else129 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 186std::unique_ptr<IPDBEnumLineNumbers>187NativeInlineSiteSymbol::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