144 lines
4.8 KiB
C++
144 lines
4.8 KiB
C++
|
//===- 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));
|
||
|
}
|