| //===- NativeFunctionSymbol.cpp - info about function symbols----*- 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/NativeFunctionSymbol.h" |
| |
| #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" |
| #include "llvm/DebugInfo/CodeView/SymbolRecord.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" |
| |
| using namespace llvm; |
| using namespace llvm::codeview; |
| using namespace llvm::pdb; |
| |
| NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session, |
| SymIndexId Id, |
| const codeview::ProcSym &Sym, |
| uint32_t Offset) |
| : NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym), |
| RecordOffset(Offset) {} |
| |
| NativeFunctionSymbol::~NativeFunctionSymbol() {} |
| |
| void NativeFunctionSymbol::dump(raw_ostream &OS, int Indent, |
| PdbSymbolIdField ShowIdFields, |
| PdbSymbolIdField RecurseIdFields) const { |
| NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); |
| dumpSymbolField(OS, "name", getName(), Indent); |
| dumpSymbolField(OS, "length", getLength(), Indent); |
| dumpSymbolField(OS, "offset", getAddressOffset(), Indent); |
| dumpSymbolField(OS, "section", getAddressSection(), Indent); |
| } |
| |
| uint32_t NativeFunctionSymbol::getAddressOffset() const { |
| return Sym.CodeOffset; |
| } |
| |
| uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; } |
| std::string NativeFunctionSymbol::getName() const { |
| return std::string(Sym.Name); |
| } |
| |
| uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; } |
| |
| uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const { |
| return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset); |
| } |
| |
| uint64_t NativeFunctionSymbol::getVirtualAddress() const { |
| return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset); |
| } |
| |
| static bool inlineSiteContainsAddress(InlineSiteSym &IS, |
| uint32_t OffsetInFunc) { |
| // Returns true if inline site contains the offset. |
| bool Found = false; |
| uint32_t CodeOffset = 0; |
| for (auto &Annot : IS.annotations()) { |
| switch (Annot.OpCode) { |
| case BinaryAnnotationsOpCode::CodeOffset: |
| case BinaryAnnotationsOpCode::ChangeCodeOffset: |
| case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: |
| CodeOffset += Annot.U1; |
| if (OffsetInFunc >= CodeOffset) |
| Found = true; |
| break; |
| case BinaryAnnotationsOpCode::ChangeCodeLength: |
| CodeOffset += Annot.U1; |
| if (Found && OffsetInFunc < CodeOffset) |
| return true; |
| Found = false; |
| break; |
| case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: |
| CodeOffset += Annot.U2; |
| if (OffsetInFunc >= CodeOffset && OffsetInFunc < CodeOffset + Annot.U1) |
| return true; |
| Found = false; |
| break; |
| default: |
| break; |
| } |
| } |
| return false; |
| } |
| |
| std::unique_ptr<IPDBEnumSymbols> |
| NativeFunctionSymbol::findInlineFramesByVA(uint64_t VA) const { |
| uint16_t Modi; |
| if (!Session.moduleIndexForVA(VA, Modi)) |
| return nullptr; |
| |
| Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi); |
| if (!ModS) { |
| consumeError(ModS.takeError()); |
| return nullptr; |
| } |
| CVSymbolArray Syms = ModS->getSymbolArray(); |
| |
| // Search for inline sites. There should be one matching top level inline |
| // site. Then search in its nested inline sites. |
| std::vector<SymIndexId> Frames; |
| uint32_t CodeOffset = VA - getVirtualAddress(); |
| auto Start = Syms.at(RecordOffset); |
| auto End = Syms.at(Sym.End); |
| while (Start != End) { |
| bool Found = false; |
| // Find matching inline site within Start and End. |
| for (; Start != End; ++Start) { |
| if (Start->kind() != S_INLINESITE) |
| continue; |
| |
| InlineSiteSym IS = |
| cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(*Start)); |
| if (inlineSiteContainsAddress(IS, CodeOffset)) { |
| // Insert frames in reverse order. |
| SymIndexId Id = Session.getSymbolCache().getOrCreateInlineSymbol( |
| IS, getVirtualAddress(), Modi, Start.offset()); |
| Frames.insert(Frames.begin(), Id); |
| |
| // Update offsets to search within this inline site. |
| ++Start; |
| End = Syms.at(IS.End); |
| Found = true; |
| break; |
| } |
| |
| Start = Syms.at(IS.End); |
| if (Start == End) |
| break; |
| } |
| |
| if (!Found) |
| break; |
| } |
| |
| return std::make_unique<NativeEnumSymbols>(Session, std::move(Frames)); |
| } |