blob: 3c461fd9e1e92603bed8dad4471a7660d44480ec [file] [log] [blame]
//===-- LVCodeViewVisitor.h -------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the LVCodeViewVisitor class, which is used to describe a
// debug information (CodeView) visitor.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWVISITOR_H
#define LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWVISITOR_H
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/iterator.h"
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h"
#include "llvm/DebugInfo/PDB/Native/InputFile.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"
#include <stack>
#include <utility>
namespace llvm {
namespace logicalview {
using namespace llvm::codeview;
class LVCodeViewReader;
class LVLogicalVisitor;
struct LVShared;
class LVTypeVisitor final : public TypeVisitorCallbacks {
ScopedPrinter &W;
LVLogicalVisitor *LogicalVisitor;
LazyRandomTypeCollection &Types;
LazyRandomTypeCollection &Ids;
uint32_t StreamIdx;
LVShared *Shared = nullptr;
// In a PDB, a type index may refer to a type (TPI) or an item ID (IPI).
// In a COFF or PDB (/Z7), the type index always refer to a type (TPI).
// When creating logical elements, we must access the correct element
// table, while searching for a type index.
bool HasIds = false;
// Current type index during the types traversal.
TypeIndex CurrentTypeIndex = TypeIndex::None();
void printTypeIndex(StringRef FieldName, TypeIndex TI,
uint32_t StreamIdx) const;
public:
LVTypeVisitor(ScopedPrinter &W, LVLogicalVisitor *LogicalVisitor,
LazyRandomTypeCollection &Types, LazyRandomTypeCollection &Ids,
uint32_t StreamIdx, LVShared *Shared)
: TypeVisitorCallbacks(), W(W), LogicalVisitor(LogicalVisitor),
Types(Types), Ids(Ids), StreamIdx(StreamIdx), Shared(Shared) {
HasIds = &Types != &Ids;
}
Error visitTypeBegin(CVType &Record) override;
Error visitTypeBegin(CVType &Record, TypeIndex TI) override;
Error visitMemberBegin(CVMemberRecord &Record) override;
Error visitMemberEnd(CVMemberRecord &Record) override;
Error visitUnknownMember(CVMemberRecord &Record) override;
Error visitKnownRecord(CVType &Record, BuildInfoRecord &Args) override;
Error visitKnownRecord(CVType &Record, ClassRecord &Class) override;
Error visitKnownRecord(CVType &Record, EnumRecord &Enum) override;
Error visitKnownRecord(CVType &Record, FuncIdRecord &Func) override;
Error visitKnownRecord(CVType &Record, ProcedureRecord &Proc) override;
Error visitKnownRecord(CVType &Record, StringIdRecord &String) override;
Error visitKnownRecord(CVType &Record, UdtSourceLineRecord &Line) override;
Error visitKnownRecord(CVType &Record, UnionRecord &Union) override;
Error visitUnknownType(CVType &Record) override;
};
class LVSymbolVisitorDelegate final : public SymbolVisitorDelegate {
LVCodeViewReader *Reader;
const llvm::object::coff_section *CoffSection;
StringRef SectionContents;
public:
LVSymbolVisitorDelegate(LVCodeViewReader *Reader,
const llvm::object::SectionRef &Section,
const llvm::object::COFFObjectFile *Obj,
StringRef SectionContents)
: Reader(Reader), SectionContents(SectionContents) {
CoffSection = Obj->getCOFFSection(Section);
}
uint32_t getRecordOffset(BinaryStreamReader Reader) override {
ArrayRef<uint8_t> Data;
if (Error Err = Reader.readLongestContiguousChunk(Data)) {
llvm::consumeError(std::move(Err));
return 0;
}
return Data.data() - SectionContents.bytes_begin();
}
void printRelocatedField(StringRef Label, uint32_t RelocOffset,
uint32_t Offset, StringRef *RelocSym = nullptr);
void getLinkageName(uint32_t RelocOffset, uint32_t Offset,
StringRef *RelocSym = nullptr);
StringRef getFileNameForFileOffset(uint32_t FileOffset) override;
DebugStringTableSubsectionRef getStringTable() override;
};
class LVElement;
class LVScope;
class LVSymbol;
class LVType;
// Visitor for CodeView symbol streams found in COFF object files and PDB files.
class LVSymbolVisitor final : public SymbolVisitorCallbacks {
LVCodeViewReader *Reader;
ScopedPrinter &W;
LVLogicalVisitor *LogicalVisitor;
LazyRandomTypeCollection &Types;
LazyRandomTypeCollection &Ids;
LVSymbolVisitorDelegate *ObjDelegate;
LVShared *Shared;
// Symbol offset when processing PDB streams.
uint32_t CurrentOffset = 0;
// Current object name collected from S_OBJNAME.
StringRef CurrentObjectName;
// Last symbol processed by S_LOCAL.
LVSymbol *LocalSymbol = nullptr;
bool HasIds;
bool InFunctionScope = false;
bool IsCompileUnit = false;
// Register for the locals and parameters symbols in the current frame.
RegisterId LocalFrameRegister = RegisterId::NONE;
RegisterId ParamFrameRegister = RegisterId::NONE;
void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
uint32_t RelocationOffset);
void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
void printTypeIndex(StringRef FieldName, TypeIndex TI) const;
// Return true if this symbol is a Compile Unit.
bool symbolIsCompileUnit(SymbolKind Kind) {
switch (Kind) {
case SymbolKind::S_COMPILE2:
case SymbolKind::S_COMPILE3:
return true;
default:
return false;
}
}
// Determine symbol kind (local or parameter).
void determineSymbolKind(LVSymbol *Symbol, RegisterId Register) {
if (Register == LocalFrameRegister) {
Symbol->setIsVariable();
return;
}
if (Register == ParamFrameRegister) {
Symbol->setIsParameter();
return;
}
// Assume is a variable.
Symbol->setIsVariable();
}
public:
LVSymbolVisitor(LVCodeViewReader *Reader, ScopedPrinter &W,
LVLogicalVisitor *LogicalVisitor,
LazyRandomTypeCollection &Types,
LazyRandomTypeCollection &Ids,
LVSymbolVisitorDelegate *ObjDelegate, LVShared *Shared)
: Reader(Reader), W(W), LogicalVisitor(LogicalVisitor), Types(Types),
Ids(Ids), ObjDelegate(ObjDelegate), Shared(Shared) {
HasIds = &Types != &Ids;
}
Error visitSymbolBegin(CVSymbol &Record) override;
Error visitSymbolBegin(CVSymbol &Record, uint32_t Offset) override;
Error visitSymbolEnd(CVSymbol &Record) override;
Error visitUnknownSymbol(CVSymbol &Record) override;
Error visitKnownRecord(CVSymbol &Record, BlockSym &Block) override;
Error visitKnownRecord(CVSymbol &Record, BPRelativeSym &Local) override;
Error visitKnownRecord(CVSymbol &Record, BuildInfoSym &BuildInfo) override;
Error visitKnownRecord(CVSymbol &Record, Compile2Sym &Compile2) override;
Error visitKnownRecord(CVSymbol &Record, Compile3Sym &Compile3) override;
Error visitKnownRecord(CVSymbol &Record, ConstantSym &Constant) override;
Error visitKnownRecord(CVSymbol &Record, DataSym &Data) override;
Error visitKnownRecord(CVSymbol &Record,
DefRangeFramePointerRelFullScopeSym
&DefRangeFramePointerRelFullScope) override;
Error visitKnownRecord(
CVSymbol &Record,
DefRangeFramePointerRelSym &DefRangeFramePointerRel) override;
Error visitKnownRecord(CVSymbol &Record,
DefRangeRegisterRelSym &DefRangeRegisterRel) override;
Error visitKnownRecord(CVSymbol &Record,
DefRangeRegisterSym &DefRangeRegister) override;
Error visitKnownRecord(
CVSymbol &Record,
DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) override;
Error visitKnownRecord(CVSymbol &Record,
DefRangeSubfieldSym &DefRangeSubfield) override;
Error visitKnownRecord(CVSymbol &Record, DefRangeSym &DefRange) override;
Error visitKnownRecord(CVSymbol &Record, FrameProcSym &FrameProc) override;
Error visitKnownRecord(CVSymbol &Record, InlineSiteSym &InlineSite) override;
Error visitKnownRecord(CVSymbol &Record, LocalSym &Local) override;
Error visitKnownRecord(CVSymbol &Record, ObjNameSym &ObjName) override;
Error visitKnownRecord(CVSymbol &Record, ProcSym &Proc) override;
Error visitKnownRecord(CVSymbol &Record, RegRelativeSym &Local) override;
Error visitKnownRecord(CVSymbol &Record, ScopeEndSym &ScopeEnd) override;
Error visitKnownRecord(CVSymbol &Record, Thunk32Sym &Thunk) override;
Error visitKnownRecord(CVSymbol &Record, UDTSym &UDT) override;
Error visitKnownRecord(CVSymbol &Record, UsingNamespaceSym &UN) override;
};
// Visitor for CodeView types and symbols to populate elements.
class LVLogicalVisitor final {
LVCodeViewReader *Reader;
ScopedPrinter &W;
// Encapsulates access to the input file and any dependent type server,
// including any precompiled header object.
llvm::pdb::InputFile &Input;
std::shared_ptr<llvm::pdb::InputFile> TypeServer = nullptr;
std::shared_ptr<LazyRandomTypeCollection> PrecompHeader = nullptr;
std::shared_ptr<LVShared> Shared;
// Object files have only one type stream that contains both types and ids.
// Precompiled header objects don't contain an IPI stream. Use the TPI.
LazyRandomTypeCollection &types() {
return TypeServer ? TypeServer->types()
: (PrecompHeader ? *PrecompHeader : Input.types());
}
LazyRandomTypeCollection &ids() {
return TypeServer ? TypeServer->ids()
: (PrecompHeader ? *PrecompHeader : Input.ids());
}
using LVScopeStack = std::stack<LVScope *>;
LVScopeStack ScopeStack;
LVScope *ReaderParent = nullptr;
LVScope *ReaderScope = nullptr;
bool InCompileUnitScope = false;
// Allow processing of argument list.
bool ProcessArgumentList = false;
StringRef OverloadedMethodName;
std::string CompileUnitName;
// Inlined functions source information.
using LVInlineeEntry = std::pair<uint32_t, StringRef>;
using LVInlineeInfo = std::map<TypeIndex, LVInlineeEntry>;
LVInlineeInfo InlineeInfo;
Error visitFieldListMemberStream(TypeIndex TI, LVElement *Element,
ArrayRef<uint8_t> FieldList);
LVType *createBaseType(TypeIndex TI, StringRef TypeName);
LVType *createPointerType(TypeIndex TI, StringRef TypeName);
LVSymbol *createParameter(TypeIndex TI, StringRef Name, LVScope *Parent);
LVSymbol *createParameter(LVElement *Element, StringRef Name,
LVScope *Parent);
void createDataMember(CVMemberRecord &Record, LVScope *Parent, StringRef Name,
TypeIndex Type, MemberAccess Access);
void createParents(StringRef ScopedName, LVElement *Element);
public:
LVLogicalVisitor(LVCodeViewReader *Reader, ScopedPrinter &W,
llvm::pdb::InputFile &Input);
// Current elements during the processing of a RecordType or RecordSymbol.
// They are shared with the SymbolVisitor.
LVElement *CurrentElement = nullptr;
LVScope *CurrentScope = nullptr;
LVSymbol *CurrentSymbol = nullptr;
LVType *CurrentType = nullptr;
// Input source in the case of type server or precompiled header.
void setInput(std::shared_ptr<llvm::pdb::InputFile> TypeServer) {
this->TypeServer = TypeServer;
}
void setInput(std::shared_ptr<LazyRandomTypeCollection> PrecompHeader) {
this->PrecompHeader = PrecompHeader;
}
void addInlineeInfo(TypeIndex TI, uint32_t LineNumber, StringRef Filename) {
InlineeInfo.emplace(std::piecewise_construct, std::forward_as_tuple(TI),
std::forward_as_tuple(LineNumber, Filename));
}
void printTypeIndex(StringRef FieldName, TypeIndex TI, uint32_t StreamIdx);
void printMemberAttributes(MemberAttributes Attrs);
void printMemberAttributes(MemberAccess Access, MethodKind Kind,
MethodOptions Options);
LVElement *createElement(TypeLeafKind Kind);
LVElement *createElement(SymbolKind Kind);
LVElement *createElement(TypeIndex TI, TypeLeafKind Kind);
// Break down the annotation byte code and calculate code and line offsets.
Error inlineSiteAnnotation(LVScope *AbstractFunction,
LVScope *InlinedFunction,
InlineSiteSym &InlineSite);
void pushScope(LVScope *Scope) {
ScopeStack.push(ReaderParent);
ReaderParent = ReaderScope;
ReaderScope = Scope;
}
void popScope() {
ReaderScope = ReaderParent;
ReaderParent = ScopeStack.top();
ScopeStack.pop();
}
void closeScope() {
if (InCompileUnitScope) {
InCompileUnitScope = false;
popScope();
}
}
void setRoot(LVScope *Root) { ReaderScope = Root; }
void addElement(LVScope *Scope, bool IsCompileUnit);
void addElement(LVSymbol *Symbol);
void addElement(LVType *Type);
std::string getCompileUnitName() { return CompileUnitName; }
void setCompileUnitName(std::string Name) {
CompileUnitName = std::move(Name);
}
LVElement *getElement(uint32_t StreamIdx, TypeIndex TI,
LVScope *Parent = nullptr);
LVShared *getShared() { return Shared.get(); }
LVScope *getReaderScope() const { return ReaderScope; }
void printTypeBegin(CVType &Record, TypeIndex TI, LVElement *Element,
uint32_t StreamIdx);
void printTypeEnd(CVType &Record);
void printMemberBegin(CVMemberRecord &Record, TypeIndex TI,
LVElement *Element, uint32_t StreamIdx);
void printMemberEnd(CVMemberRecord &Record);
void startProcessArgumentList() { ProcessArgumentList = true; }
void stopProcessArgumentList() { ProcessArgumentList = false; }
void processFiles();
void processLines();
void processNamespaces();
void printRecords(raw_ostream &OS) const;
Error visitUnknownType(CVType &Record, TypeIndex TI);
Error visitKnownRecord(CVType &Record, ArgListRecord &Args, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, ArrayRecord &AT, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, BitFieldRecord &BF, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, BuildInfoRecord &BI, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, ClassRecord &Class, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, EnumRecord &Enum, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, FieldListRecord &FieldList,
TypeIndex TI, LVElement *Element);
Error visitKnownRecord(CVType &Record, FuncIdRecord &Func, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, LabelRecord &LR, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, ModifierRecord &Mod, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, MemberFuncIdRecord &Id, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, MemberFunctionRecord &MF, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, MethodOverloadListRecord &Overloads,
TypeIndex TI, LVElement *Element);
Error visitKnownRecord(CVType &Record, PointerRecord &Ptr, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, ProcedureRecord &Proc, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, UnionRecord &Union, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, TypeServer2Record &TS, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, VFTableRecord &VFT, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, VFTableShapeRecord &Shape,
TypeIndex TI, LVElement *Element);
Error visitKnownRecord(CVType &Record, StringListRecord &Strings,
TypeIndex TI, LVElement *Element);
Error visitKnownRecord(CVType &Record, StringIdRecord &String, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, UdtSourceLineRecord &SourceLine,
TypeIndex TI, LVElement *Element);
Error visitKnownRecord(CVType &Record, UdtModSourceLineRecord &ModSourceLine,
TypeIndex TI, LVElement *Element);
Error visitKnownRecord(CVType &Record, PrecompRecord &Precomp, TypeIndex TI,
LVElement *Element);
Error visitKnownRecord(CVType &Record, EndPrecompRecord &EndPrecomp,
TypeIndex TI, LVElement *Element);
Error visitUnknownMember(CVMemberRecord &Record, TypeIndex TI);
Error visitKnownMember(CVMemberRecord &Record, BaseClassRecord &Base,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, DataMemberRecord &Field,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, EnumeratorRecord &Enum,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, ListContinuationRecord &Cont,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, NestedTypeRecord &Nested,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, OneMethodRecord &Method,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, OverloadedMethodRecord &Method,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, StaticDataMemberRecord &Field,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, VFPtrRecord &VFTable,
TypeIndex TI, LVElement *Element);
Error visitKnownMember(CVMemberRecord &Record, VirtualBaseClassRecord &Base,
TypeIndex TI, LVElement *Element);
template <typename T>
Error visitKnownMember(CVMemberRecord &Record,
TypeVisitorCallbacks &Callbacks, TypeIndex TI,
LVElement *Element) {
TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
T KnownRecord(RK);
if (Error Err = Callbacks.visitKnownMember(Record, KnownRecord))
return Err;
if (Error Err = visitKnownMember(Record, KnownRecord, TI, Element))
return Err;
return Error::success();
}
template <typename T>
Error visitKnownRecord(CVType &Record, TypeIndex TI, LVElement *Element) {
TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind());
T KnownRecord(RK);
if (Error Err = TypeDeserializer::deserializeAs(
const_cast<CVType &>(Record), KnownRecord))
return Err;
if (Error Err = visitKnownRecord(Record, KnownRecord, TI, Element))
return Err;
return Error::success();
}
Error visitMemberRecord(CVMemberRecord &Record,
TypeVisitorCallbacks &Callbacks, TypeIndex TI,
LVElement *Element);
Error finishVisitation(CVType &Record, TypeIndex TI, LVElement *Element);
};
} // namespace logicalview
} // namespace llvm
#endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWVISITOR_H