aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp')
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp1221
1 files changed, 1221 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp
new file mode 100644
index 000000000000..d72fe2683f92
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp
@@ -0,0 +1,1221 @@
+//===-- LVCodeViewReader.cpp ----------------------------------------------===//
+//
+// 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 implements the LVCodeViewReader class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/WithColor.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::logicalview;
+using namespace llvm::msf;
+using namespace llvm::object;
+using namespace llvm::pdb;
+
+#define DEBUG_TYPE "CodeViewReader"
+
+StringRef LVCodeViewReader::getSymbolKindName(SymbolKind Kind) {
+ switch (Kind) {
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: \
+ return #EnumName;
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+ default:
+ return "UnknownSym";
+ }
+ llvm_unreachable("Unknown SymbolKind::Kind");
+}
+
+std::string LVCodeViewReader::formatRegisterId(RegisterId Register,
+ CPUType CPU) {
+#define RETURN_CASE(Enum, X, Ret) \
+ case Enum::X: \
+ return Ret;
+
+ if (CPU == CPUType::ARMNT) {
+ switch (Register) {
+#define CV_REGISTERS_ARM
+#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM
+
+ default:
+ break;
+ }
+ } else if (CPU == CPUType::ARM64) {
+ switch (Register) {
+#define CV_REGISTERS_ARM64
+#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM64
+
+ default:
+ break;
+ }
+ } else {
+ switch (Register) {
+#define CV_REGISTERS_X86
+#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_X86
+
+ default:
+ break;
+ }
+ }
+ return "formatUnknownEnum(Id)";
+}
+
+void LVCodeViewReader::printRelocatedField(StringRef Label,
+ const coff_section *CoffSection,
+ uint32_t RelocOffset,
+ uint32_t Offset,
+ StringRef *RelocSym) {
+ StringRef SymStorage;
+ StringRef &Symbol = RelocSym ? *RelocSym : SymStorage;
+ if (!resolveSymbolName(CoffSection, RelocOffset, Symbol))
+ W.printSymbolOffset(Label, Symbol, Offset);
+ else
+ W.printHex(Label, RelocOffset);
+}
+
+void LVCodeViewReader::getLinkageName(const coff_section *CoffSection,
+ uint32_t RelocOffset, uint32_t Offset,
+ StringRef *RelocSym) {
+ StringRef SymStorage;
+ StringRef &Symbol = RelocSym ? *RelocSym : SymStorage;
+ if (resolveSymbolName(CoffSection, RelocOffset, Symbol))
+ Symbol = "";
+}
+
+Expected<StringRef>
+LVCodeViewReader::getFileNameForFileOffset(uint32_t FileOffset,
+ const SymbolGroup *SG) {
+ if (SG) {
+ Expected<StringRef> Filename = SG->getNameFromChecksums(FileOffset);
+ if (!Filename) {
+ consumeError(Filename.takeError());
+ return StringRef("");
+ }
+ return *Filename;
+ }
+
+ // The file checksum subsection should precede all references to it.
+ if (!CVFileChecksumTable.valid() || !CVStringTable.valid())
+ return createStringError(object_error::parse_failed, getFileName());
+
+ VarStreamArray<FileChecksumEntry>::Iterator Iter =
+ CVFileChecksumTable.getArray().at(FileOffset);
+
+ // Check if the file checksum table offset is valid.
+ if (Iter == CVFileChecksumTable.end())
+ return createStringError(object_error::parse_failed, getFileName());
+
+ Expected<StringRef> NameOrErr = CVStringTable.getString(Iter->FileNameOffset);
+ if (!NameOrErr)
+ return createStringError(object_error::parse_failed, getFileName());
+ return *NameOrErr;
+}
+
+Error LVCodeViewReader::printFileNameForOffset(StringRef Label,
+ uint32_t FileOffset,
+ const SymbolGroup *SG) {
+ Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ W.printHex(Label, *NameOrErr, FileOffset);
+ return Error::success();
+}
+
+void LVCodeViewReader::cacheRelocations() {
+ for (const SectionRef &Section : getObj().sections()) {
+ const coff_section *CoffSection = getObj().getCOFFSection(Section);
+
+ for (const RelocationRef &Relocacion : Section.relocations())
+ RelocMap[CoffSection].push_back(Relocacion);
+
+ // Sort relocations by address.
+ llvm::sort(RelocMap[CoffSection], [](RelocationRef L, RelocationRef R) {
+ return L.getOffset() < R.getOffset();
+ });
+ }
+}
+
+// Given a section and an offset into this section the function returns the
+// symbol used for the relocation at the offset.
+Error LVCodeViewReader::resolveSymbol(const coff_section *CoffSection,
+ uint64_t Offset, SymbolRef &Sym) {
+ const auto &Relocations = RelocMap[CoffSection];
+ basic_symbol_iterator SymI = getObj().symbol_end();
+ for (const RelocationRef &Relocation : Relocations) {
+ uint64_t RelocationOffset = Relocation.getOffset();
+
+ if (RelocationOffset == Offset) {
+ SymI = Relocation.getSymbol();
+ break;
+ }
+ }
+ if (SymI == getObj().symbol_end())
+ return make_error<StringError>("Unknown Symbol", inconvertibleErrorCode());
+ Sym = *SymI;
+ return ErrorSuccess();
+}
+
+// Given a section and an offset into this section the function returns the
+// name of the symbol used for the relocation at the offset.
+Error LVCodeViewReader::resolveSymbolName(const coff_section *CoffSection,
+ uint64_t Offset, StringRef &Name) {
+ SymbolRef Symbol;
+ if (Error E = resolveSymbol(CoffSection, Offset, Symbol))
+ return E;
+ Expected<StringRef> NameOrErr = Symbol.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ Name = *NameOrErr;
+ return ErrorSuccess();
+}
+
+// CodeView and DWARF can have references to compiler generated elements,
+// used for initialization. The MSVC includes in the PDBs, internal compile
+// units, associated with the MS runtime support. We mark them as 'system'
+// and they are printed only if the command line option 'internal=system'.
+bool LVCodeViewReader::isSystemEntry(LVElement *Element, StringRef Name) const {
+ Name = Name.empty() ? Element->getName() : Name;
+ auto Find = [=](const char *String) -> bool {
+ return StringRef::npos != Name.find(String);
+ };
+ auto Starts = [=](const char *Pattern) -> bool {
+ return Name.startswith(Pattern);
+ };
+ auto CheckExclude = [&]() -> bool {
+ if (Starts("__") || Starts("_PMD") || Starts("_PMFN"))
+ return true;
+ if (Find("_s__"))
+ return true;
+ if (Find("_CatchableType") || Find("_TypeDescriptor"))
+ return true;
+ if (Find("Intermediate\\vctools"))
+ return true;
+ if (Find("$initializer$") || Find("dynamic initializer"))
+ return true;
+ if (Find("`vftable'") || Find("_GLOBAL__sub"))
+ return true;
+ return false;
+ };
+ bool Excluded = CheckExclude();
+ if (Excluded)
+ Element->setIsSystem();
+
+ return Excluded;
+}
+
+Error LVCodeViewReader::collectInlineeInfo(
+ DebugInlineeLinesSubsectionRef &Lines, const llvm::pdb::SymbolGroup *SG) {
+ for (const InlineeSourceLine &Line : Lines) {
+ TypeIndex TIInlinee = Line.Header->Inlinee;
+ uint32_t LineNumber = Line.Header->SourceLineNum;
+ uint32_t FileOffset = Line.Header->FileID;
+ LLVM_DEBUG({
+ DictScope S(W, "InlineeSourceLine");
+ LogicalVisitor.printTypeIndex("Inlinee", TIInlinee, StreamTPI);
+ if (Error Err = printFileNameForOffset("FileID", FileOffset, SG))
+ return Err;
+ W.printNumber("SourceLineNum", LineNumber);
+
+ if (Lines.hasExtraFiles()) {
+ W.printNumber("ExtraFileCount", Line.ExtraFiles.size());
+ ListScope ExtraFiles(W, "ExtraFiles");
+ for (const ulittle32_t &FID : Line.ExtraFiles)
+ if (Error Err = printFileNameForOffset("FileID", FID, SG))
+ return Err;
+ }
+ });
+ Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ LogicalVisitor.addInlineeInfo(TIInlinee, LineNumber, *NameOrErr);
+ }
+
+ return Error::success();
+}
+
+Error LVCodeViewReader::traverseInlineeLines(StringRef Subsection) {
+ BinaryStreamReader SR(Subsection, llvm::support::little);
+ DebugInlineeLinesSubsectionRef Lines;
+ if (Error E = Lines.initialize(SR))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+
+ return collectInlineeInfo(Lines);
+}
+
+Error LVCodeViewReader::createLines(
+ const FixedStreamArray<LineNumberEntry> &LineNumbers, LVAddress Addendum,
+ uint32_t Segment, uint32_t Begin, uint32_t Size, uint32_t NameIndex,
+ const SymbolGroup *SG) {
+ LLVM_DEBUG({
+ uint32_t End = Begin + Size;
+ W.getOStream() << formatv("{0:x-4}:{1:x-8}-{2:x-8}\n", Segment, Begin, End);
+ });
+
+ for (const LineNumberEntry &Line : LineNumbers) {
+ if (Line.Offset >= Size)
+ return createStringError(object_error::parse_failed, getFileName());
+
+ LineInfo LI(Line.Flags);
+
+ LLVM_DEBUG({
+ W.getOStream() << formatv(
+ "{0} {1:x-8}\n", utostr(LI.getStartLine()),
+ fmt_align(Begin + Line.Offset, AlignStyle::Right, 8, '0'));
+ });
+
+ // The 'processLines()' function will move each created logical line
+ // to its enclosing logical scope, using the debug ranges information
+ // and they will be released when its scope parent is deleted.
+ LVLineDebug *LineDebug = createLineDebug();
+ CULines.push_back(LineDebug);
+ LVAddress Address = linearAddress(Segment, Begin + Line.Offset);
+ LineDebug->setAddress(Address + Addendum);
+
+ if (LI.isAlwaysStepInto())
+ LineDebug->setIsAlwaysStepInto();
+ else if (LI.isNeverStepInto())
+ LineDebug->setIsNeverStepInto();
+ else
+ LineDebug->setLineNumber(LI.getStartLine());
+
+ if (LI.isStatement())
+ LineDebug->setIsNewStatement();
+
+ Expected<StringRef> NameOrErr = getFileNameForFileOffset(NameIndex, SG);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ LineDebug->setFilename(*NameOrErr);
+ }
+
+ return Error::success();
+}
+
+Error LVCodeViewReader::initializeFileAndStringTables(
+ BinaryStreamReader &Reader) {
+ while (Reader.bytesRemaining() > 0 &&
+ (!CVFileChecksumTable.valid() || !CVStringTable.valid())) {
+ // The section consists of a number of subsection in the following format:
+ // |SubSectionType|SubSectionSize|Contents...|
+ uint32_t SubType, SubSectionSize;
+
+ if (Error E = Reader.readInteger(SubType))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+ if (Error E = Reader.readInteger(SubSectionSize))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+
+ StringRef Contents;
+ if (Error E = Reader.readFixedString(Contents, SubSectionSize))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+
+ BinaryStreamRef ST(Contents, support::little);
+ switch (DebugSubsectionKind(SubType)) {
+ case DebugSubsectionKind::FileChecksums:
+ if (Error E = CVFileChecksumTable.initialize(ST))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+ break;
+ case DebugSubsectionKind::StringTable:
+ if (Error E = CVStringTable.initialize(ST))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+ break;
+ default:
+ break;
+ }
+
+ uint32_t PaddedSize = alignTo(SubSectionSize, 4);
+ if (Error E = Reader.skip(PaddedSize - SubSectionSize))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+ }
+
+ return Error::success();
+}
+
+Error LVCodeViewReader::loadTypeServer(TypeServer2Record &TS) {
+ LLVM_DEBUG({
+ W.printString("Guid", formatv("{0}", TS.getGuid()).str());
+ W.printNumber("Age", TS.getAge());
+ W.printString("Name", TS.getName());
+ });
+
+ SmallString<128> ServerName(TS.getName());
+ BuffOrErr = MemoryBuffer::getFile(ServerName);
+ if (BuffOrErr.getError()) {
+ // The server name does not exist. Try in the same directory as the
+ // input file.
+ ServerName = createAlternativePath(ServerName);
+ BuffOrErr = MemoryBuffer::getFile(ServerName);
+ if (BuffOrErr.getError()) {
+ // For the error message, use the original type server name.
+ return createStringError(errc::bad_file_descriptor,
+ "File '%s' does not exist.",
+ TS.getName().str().c_str());
+ }
+ }
+ MemBuffer = std::move(BuffOrErr.get());
+
+ // Check if the buffer corresponds to a PDB file.
+ assert(identify_magic((*MemBuffer).getBuffer()) == file_magic::pdb &&
+ "Invalid PDB file.");
+
+ if (Error Err = loadDataForPDB(PDB_ReaderType::Native, ServerName, Session))
+ return createStringError(errorToErrorCode(std::move(Err)), "%s",
+ ServerName.c_str());
+
+ PdbSession.reset(static_cast<NativeSession *>(Session.release()));
+ PDBFile &Pdb = PdbSession->getPDBFile();
+
+ // Just because a file with a matching name was found and it was an actual
+ // PDB file doesn't mean it matches. For it to match the InfoStream's GUID
+ // must match the GUID specified in the TypeServer2 record.
+ Expected<InfoStream &> expectedInfo = Pdb.getPDBInfoStream();
+ if (!expectedInfo || expectedInfo->getGuid() != TS.getGuid())
+ return createStringError(errc::invalid_argument, "signature_out_of_date");
+
+ // The reader needs to switch to a type server, to process the types from
+ // the server. We need to keep the original input source, as reading other
+ // sections will require the input associated with the loaded object file.
+ TypeServer = std::make_shared<InputFile>(&Pdb);
+ LogicalVisitor.setInput(TypeServer);
+
+ LazyRandomTypeCollection &Types = types();
+ LazyRandomTypeCollection &Ids = ids();
+ if (Error Err = traverseTypes(Pdb, Types, Ids))
+ return Err;
+
+ return Error::success();
+}
+
+Error LVCodeViewReader::loadPrecompiledObject(PrecompRecord &Precomp,
+ CVTypeArray &CVTypesObj) {
+ LLVM_DEBUG({
+ W.printHex("Count", Precomp.getTypesCount());
+ W.printHex("Signature", Precomp.getSignature());
+ W.printString("PrecompFile", Precomp.getPrecompFilePath());
+ });
+
+ SmallString<128> ServerName(Precomp.getPrecompFilePath());
+ BuffOrErr = MemoryBuffer::getFile(ServerName);
+ if (BuffOrErr.getError()) {
+ // The server name does not exist. Try in the directory as the input file.
+ ServerName = createAlternativePath(ServerName);
+ if (BuffOrErr.getError()) {
+ // For the error message, use the original type server name.
+ return createStringError(errc::bad_file_descriptor,
+ "File '%s' does not exist.",
+ Precomp.getPrecompFilePath().str().c_str());
+ }
+ }
+ MemBuffer = std::move(BuffOrErr.get());
+
+ Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(*MemBuffer);
+ if (errorToErrorCode(BinOrErr.takeError()))
+ return createStringError(errc::not_supported,
+ "Binary object format in '%s' is not supported.",
+ ServerName.c_str());
+
+ Binary &BinaryObj = *BinOrErr.get();
+ if (!BinaryObj.isCOFF())
+ return createStringError(errc::not_supported, "'%s' is not a COFF object.",
+ ServerName.c_str());
+
+ Builder = std::make_unique<AppendingTypeTableBuilder>(BuilderAllocator);
+
+ // The MSVC precompiled header object file, should contain just a single
+ // ".debug$P" section.
+ COFFObjectFile &Obj = *cast<COFFObjectFile>(&BinaryObj);
+ for (const SectionRef &Section : Obj.sections()) {
+ Expected<StringRef> SectionNameOrErr = Section.getName();
+ if (!SectionNameOrErr)
+ return SectionNameOrErr.takeError();
+ if (*SectionNameOrErr == ".debug$P") {
+ Expected<StringRef> DataOrErr = Section.getContents();
+ if (!DataOrErr)
+ return DataOrErr.takeError();
+ uint32_t Magic;
+ if (Error Err = consume(*DataOrErr, Magic))
+ return Err;
+ if (Magic != COFF::DEBUG_SECTION_MAGIC)
+ return errorCodeToError(object_error::parse_failed);
+
+ ReaderPrecomp =
+ std::make_unique<BinaryStreamReader>(*DataOrErr, support::little);
+ cantFail(
+ ReaderPrecomp->readArray(CVTypesPrecomp, ReaderPrecomp->getLength()));
+
+ // Append all the type records up to the LF_ENDPRECOMP marker and
+ // check if the signatures match.
+ for (const CVType &Type : CVTypesPrecomp) {
+ ArrayRef<uint8_t> TypeData = Type.data();
+ if (Type.kind() == LF_ENDPRECOMP) {
+ EndPrecompRecord EndPrecomp = cantFail(
+ TypeDeserializer::deserializeAs<EndPrecompRecord>(TypeData));
+ if (Precomp.getSignature() != EndPrecomp.getSignature())
+ return createStringError(errc::invalid_argument, "no matching pch");
+ break;
+ }
+ Builder->insertRecordBytes(TypeData);
+ }
+ // Done processing .debug$P, break out of section loop.
+ break;
+ }
+ }
+
+ // Append all the type records, skipping the first record which is the
+ // reference to the precompiled header object information.
+ for (const CVType &Type : CVTypesObj) {
+ ArrayRef<uint8_t> TypeData = Type.data();
+ if (Type.kind() != LF_PRECOMP)
+ Builder->insertRecordBytes(TypeData);
+ }
+
+ // Set up a type stream that refers to the added type records.
+ Builder->ForEachRecord(
+ [&](TypeIndex TI, const CVType &Type) { TypeArray.push_back(Type); });
+
+ ItemStream =
+ std::make_unique<BinaryItemStream<CVType>>(llvm::support::little);
+ ItemStream->setItems(TypeArray);
+ TypeStream.setUnderlyingStream(*ItemStream);
+
+ PrecompHeader =
+ std::make_shared<LazyRandomTypeCollection>(TypeStream, TypeArray.size());
+
+ // Change the original input source to use the collected type records.
+ LogicalVisitor.setInput(PrecompHeader);
+
+ LazyRandomTypeCollection &Types = types();
+ LazyRandomTypeCollection &Ids = ids();
+ LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI,
+ LogicalVisitor.getShared());
+ return visitTypeStream(Types, TDV);
+}
+
+Error LVCodeViewReader::traverseTypeSection(StringRef SectionName,
+ const SectionRef &Section) {
+ LLVM_DEBUG({
+ ListScope D(W, "CodeViewTypes");
+ W.printNumber("Section", SectionName, getObj().getSectionID(Section));
+ });
+
+ Expected<StringRef> DataOrErr = Section.getContents();
+ if (!DataOrErr)
+ return DataOrErr.takeError();
+ uint32_t Magic;
+ if (Error Err = consume(*DataOrErr, Magic))
+ return Err;
+ if (Magic != COFF::DEBUG_SECTION_MAGIC)
+ return errorCodeToError(object_error::parse_failed);
+
+ // Get the first type record. It will indicate if this object uses a type
+ // server (/Zi) or a PCH file (/Yu).
+ CVTypeArray CVTypes;
+ BinaryStreamReader Reader(*DataOrErr, support::little);
+ cantFail(Reader.readArray(CVTypes, Reader.getLength()));
+ CVTypeArray::Iterator FirstType = CVTypes.begin();
+
+ // The object was compiled with /Zi. It uses types from a type server PDB.
+ if (FirstType->kind() == LF_TYPESERVER2) {
+ TypeServer2Record TS = cantFail(
+ TypeDeserializer::deserializeAs<TypeServer2Record>(FirstType->data()));
+ return loadTypeServer(TS);
+ }
+
+ // The object was compiled with /Yc or /Yu. It uses types from another
+ // object file with a matching signature.
+ if (FirstType->kind() == LF_PRECOMP) {
+ PrecompRecord Precomp = cantFail(
+ TypeDeserializer::deserializeAs<PrecompRecord>(FirstType->data()));
+ return loadPrecompiledObject(Precomp, CVTypes);
+ }
+
+ LazyRandomTypeCollection &Types = types();
+ LazyRandomTypeCollection &Ids = ids();
+ Types.reset(*DataOrErr, 100);
+ LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI,
+ LogicalVisitor.getShared());
+ return visitTypeStream(Types, TDV);
+}
+
+Error LVCodeViewReader::traverseTypes(PDBFile &Pdb,
+ LazyRandomTypeCollection &Types,
+ LazyRandomTypeCollection &Ids) {
+ // Traverse types (TPI and IPI).
+ auto VisitTypes = [&](LazyRandomTypeCollection &Types,
+ LazyRandomTypeCollection &Ids,
+ SpecialStream StreamIdx) -> Error {
+ LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamIdx,
+ LogicalVisitor.getShared());
+ return visitTypeStream(Types, TDV);
+ };
+
+ Expected<TpiStream &> StreamTpiOrErr = Pdb.getPDBTpiStream();
+ if (!StreamTpiOrErr)
+ return StreamTpiOrErr.takeError();
+ TpiStream &StreamTpi = *StreamTpiOrErr;
+ StreamTpi.buildHashMap();
+ LLVM_DEBUG({
+ W.getOStream() << formatv("Showing {0:N} TPI records\n",
+ StreamTpi.getNumTypeRecords());
+ });
+ if (Error Err = VisitTypes(Types, Ids, StreamTPI))
+ return Err;
+
+ Expected<TpiStream &> StreamIpiOrErr = Pdb.getPDBIpiStream();
+ if (!StreamIpiOrErr)
+ return StreamIpiOrErr.takeError();
+ TpiStream &StreamIpi = *StreamIpiOrErr;
+ StreamIpi.buildHashMap();
+ LLVM_DEBUG({
+ W.getOStream() << formatv("Showing {0:N} IPI records\n",
+ StreamIpi.getNumTypeRecords());
+ });
+ return VisitTypes(Ids, Ids, StreamIPI);
+}
+
+Error LVCodeViewReader::traverseSymbolsSubsection(StringRef Subsection,
+ const SectionRef &Section,
+ StringRef SectionContents) {
+ ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(),
+ Subsection.bytes_end());
+ LVSymbolVisitorDelegate VisitorDelegate(this, Section, &getObj(),
+ SectionContents);
+ CVSymbolArray Symbols;
+ BinaryStreamReader Reader(BinaryData, llvm::support::little);
+ if (Error E = Reader.readArray(Symbols, Reader.getLength()))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+
+ LazyRandomTypeCollection &Types = types();
+ LazyRandomTypeCollection &Ids = ids();
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(&VisitorDelegate,
+ CodeViewContainer::ObjectFile);
+ // As we are processing a COFF format, use TPI as IPI, so the generic code
+ // to process the CodeView format does not contain any additional checks.
+ LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids,
+ &VisitorDelegate, LogicalVisitor.getShared());
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Traverser);
+ CVSymbolVisitor Visitor(Pipeline);
+ return Visitor.visitSymbolStream(Symbols);
+}
+
+Error LVCodeViewReader::traverseSymbolSection(StringRef SectionName,
+ const SectionRef &Section) {
+ LLVM_DEBUG({
+ ListScope D(W, "CodeViewDebugInfo");
+ W.printNumber("Section", SectionName, getObj().getSectionID(Section));
+ });
+
+ Expected<StringRef> SectionOrErr = Section.getContents();
+ if (!SectionOrErr)
+ return SectionOrErr.takeError();
+ StringRef SectionContents = *SectionOrErr;
+ StringRef Data = SectionContents;
+
+ SmallVector<StringRef, 10> SymbolNames;
+ StringMap<StringRef> FunctionLineTables;
+
+ uint32_t Magic;
+ if (Error E = consume(Data, Magic))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+
+ if (Magic != COFF::DEBUG_SECTION_MAGIC)
+ return createStringError(object_error::parse_failed, getFileName());
+
+ BinaryStreamReader FSReader(Data, support::little);
+ if (Error Err = initializeFileAndStringTables(FSReader))
+ return Err;
+
+ while (!Data.empty()) {
+ // The section consists of a number of subsection in the following format:
+ // |SubSectionType|SubSectionSize|Contents...|
+ uint32_t SubType, SubSectionSize;
+ if (Error E = consume(Data, SubType))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+ if (Error E = consume(Data, SubSectionSize))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+
+ // Process the subsection as normal even if the ignore bit is set.
+ SubType &= ~SubsectionIgnoreFlag;
+
+ // Get the contents of the subsection.
+ if (SubSectionSize > Data.size())
+ return createStringError(object_error::parse_failed, getFileName());
+ StringRef Contents = Data.substr(0, SubSectionSize);
+
+ // Add SubSectionSize to the current offset and align that offset
+ // to find the next subsection.
+ size_t SectionOffset = Data.data() - SectionContents.data();
+ size_t NextOffset = SectionOffset + SubSectionSize;
+ NextOffset = alignTo(NextOffset, 4);
+ if (NextOffset > SectionContents.size())
+ return createStringError(object_error::parse_failed, getFileName());
+ Data = SectionContents.drop_front(NextOffset);
+
+ switch (DebugSubsectionKind(SubType)) {
+ case DebugSubsectionKind::Symbols:
+ if (Error Err =
+ traverseSymbolsSubsection(Contents, Section, SectionContents))
+ return Err;
+ break;
+
+ case DebugSubsectionKind::InlineeLines:
+ if (Error Err = traverseInlineeLines(Contents))
+ return Err;
+ break;
+
+ case DebugSubsectionKind::Lines:
+ // Holds a PC to file:line table. Some data to parse this subsection
+ // is stored in the other subsections, so just check sanity and store
+ // the pointers for deferred processing.
+
+ // Collect function and ranges only if we need to print logical lines.
+ if (options().getGeneralCollectRanges()) {
+
+ if (SubSectionSize < 12) {
+ // There should be at least three words to store two function
+ // relocations and size of the code.
+ return createStringError(object_error::parse_failed, getFileName());
+ }
+
+ StringRef SymbolName;
+ if (Error Err = resolveSymbolName(getObj().getCOFFSection(Section),
+ SectionOffset, SymbolName))
+ return createStringError(errorToErrorCode(std::move(Err)),
+ getFileName());
+
+ LLVM_DEBUG({ W.printString("Symbol Name", SymbolName); });
+ if (FunctionLineTables.count(SymbolName) != 0) {
+ // Saw debug info for this function already?
+ return createStringError(object_error::parse_failed, getFileName());
+ }
+
+ FunctionLineTables[SymbolName] = Contents;
+ SymbolNames.push_back(SymbolName);
+ }
+ break;
+
+ // Do nothing for unrecognized subsections.
+ default:
+ break;
+ }
+ W.flush();
+ }
+
+ // Traverse the line tables now that we've read all the subsections and
+ // know all the required information.
+ for (StringRef SymbolName : SymbolNames) {
+ LLVM_DEBUG({
+ ListScope S(W, "FunctionLineTable");
+ W.printString("Symbol Name", SymbolName);
+ });
+
+ BinaryStreamReader Reader(FunctionLineTables[SymbolName], support::little);
+
+ DebugLinesSubsectionRef Lines;
+ if (Error E = Lines.initialize(Reader))
+ return createStringError(errorToErrorCode(std::move(E)), getFileName());
+
+ // Find the associated symbol table information.
+ LVSymbolTableEntry SymbolTableEntry = getSymbolTableEntry(SymbolName);
+ LVScope *Function = SymbolTableEntry.Scope;
+ if (!Function)
+ continue;
+
+ LVAddress Addendum = SymbolTableEntry.Address;
+ LVSectionIndex SectionIndex = SymbolTableEntry.SectionIndex;
+
+ // The given scope represents the function that contains the line numbers.
+ // Collect all generated debug lines associated with the function.
+ CULines.clear();
+
+ // For the given scope, collect all scopes ranges.
+ LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+ ScopesWithRanges->clear();
+ Function->getRanges(*ScopesWithRanges);
+ ScopesWithRanges->sort();
+
+ uint16_t Segment = Lines.header()->RelocSegment;
+ uint32_t Begin = Lines.header()->RelocOffset;
+ uint32_t Size = Lines.header()->CodeSize;
+ for (const LineColumnEntry &Block : Lines)
+ if (Error Err = createLines(Block.LineNumbers, Addendum, Segment, Begin,
+ Size, Block.NameIndex))
+ return Err;
+
+ // Include lines from any inlined functions within the current function.
+ includeInlineeLines(SectionIndex, Function);
+
+ if (Error Err = createInstructions(Function, SectionIndex))
+ return Err;
+
+ processLines(&CULines, SectionIndex, Function);
+ }
+
+ return Error::success();
+}
+
+void LVCodeViewReader::sortScopes() { Root->sort(); }
+
+void LVCodeViewReader::print(raw_ostream &OS) const {
+ LLVM_DEBUG(dbgs() << "CreateReaders\n");
+}
+
+void LVCodeViewReader::mapRangeAddress(const ObjectFile &Obj,
+ const SectionRef &Section,
+ bool IsComdat) {
+ if (!Obj.isCOFF())
+ return;
+
+ const COFFObjectFile *Object = cast<COFFObjectFile>(&Obj);
+
+ for (const SymbolRef &Sym : Object->symbols()) {
+ if (!Section.containsSymbol(Sym))
+ continue;
+
+ COFFSymbolRef Symbol = Object->getCOFFSymbol(Sym);
+ if (Symbol.getComplexType() != llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ continue;
+
+ StringRef SymbolName;
+ Expected<StringRef> SymNameOrErr = Object->getSymbolName(Symbol);
+ if (!SymNameOrErr) {
+ W.startLine() << "Invalid symbol name: " << Symbol.getSectionNumber()
+ << "\n";
+ consumeError(SymNameOrErr.takeError());
+ continue;
+ }
+ SymbolName = *SymNameOrErr;
+
+ LLVM_DEBUG({
+ Expected<const coff_section *> SectionOrErr =
+ Object->getSection(Symbol.getSectionNumber());
+ if (!SectionOrErr) {
+ W.startLine() << "Invalid section number: " << Symbol.getSectionNumber()
+ << "\n";
+ consumeError(SectionOrErr.takeError());
+ return;
+ }
+ W.printNumber("Section #", Symbol.getSectionNumber());
+ W.printString("Name", SymbolName);
+ W.printHex("Value", Symbol.getValue());
+ });
+
+ // Record the symbol name (linkage) and its loading address.
+ addToSymbolTable(SymbolName, Symbol.getValue(), Symbol.getSectionNumber(),
+ IsComdat);
+ }
+}
+
+Error LVCodeViewReader::createScopes(COFFObjectFile &Obj) {
+ if (Error Err = loadTargetInfo(Obj))
+ return Err;
+
+ // Initialization required when processing a COFF file:
+ // Cache the symbols relocations.
+ // Create a mapping for virtual addresses.
+ // Get the functions entry points.
+ cacheRelocations();
+ mapVirtualAddress(Obj);
+
+ for (const SectionRef &Section : Obj.sections()) {
+ Expected<StringRef> SectionNameOrErr = Section.getName();
+ if (!SectionNameOrErr)
+ return SectionNameOrErr.takeError();
+ // .debug$T is a standard CodeView type section, while .debug$P is the
+ // same format but used for MSVC precompiled header object files.
+ if (*SectionNameOrErr == ".debug$T" || *SectionNameOrErr == ".debug$P")
+ if (Error Err = traverseTypeSection(*SectionNameOrErr, Section))
+ return Err;
+ }
+
+ // Process collected namespaces.
+ LogicalVisitor.processNamespaces();
+
+ for (const SectionRef &Section : Obj.sections()) {
+ Expected<StringRef> SectionNameOrErr = Section.getName();
+ if (!SectionNameOrErr)
+ return SectionNameOrErr.takeError();
+ if (*SectionNameOrErr == ".debug$S")
+ if (Error Err = traverseSymbolSection(*SectionNameOrErr, Section))
+ return Err;
+ }
+
+ // Check if we have to close the Compile Unit scope.
+ LogicalVisitor.closeScope();
+
+ // Traverse the strings recorded and transform them into filenames.
+ LogicalVisitor.processFiles();
+
+ // Process collected element lines.
+ LogicalVisitor.processLines();
+
+ // Translate composite names into a single component.
+ Root->transformScopedName();
+ return Error::success();
+}
+
+Error LVCodeViewReader::createScopes(PDBFile &Pdb) {
+ if (Error Err = loadTargetInfo(Pdb))
+ return Err;
+
+ if (!Pdb.hasPDBTpiStream() || !Pdb.hasPDBDbiStream())
+ return Error::success();
+
+ // Open the executable associated with the PDB file and get the section
+ // addresses used to calculate linear addresses for CodeView Symbols.
+ if (!ExePath.empty()) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
+ MemoryBuffer::getFileOrSTDIN(ExePath);
+ if (BuffOrErr.getError()) {
+ return createStringError(errc::bad_file_descriptor,
+ "File '%s' does not exist.", ExePath.c_str());
+ }
+ BinaryBuffer = std::move(BuffOrErr.get());
+
+ // Check if the buffer corresponds to a PECOFF executable.
+ assert(identify_magic(BinaryBuffer->getBuffer()) ==
+ file_magic::pecoff_executable &&
+ "Invalid PECOFF executable file.");
+
+ Expected<std::unique_ptr<Binary>> BinOrErr =
+ createBinary(BinaryBuffer->getMemBufferRef());
+ if (errorToErrorCode(BinOrErr.takeError())) {
+ return createStringError(errc::not_supported,
+ "Binary object format in '%s' is not supported.",
+ ExePath.c_str());
+ }
+ BinaryExecutable = std::move(*BinOrErr);
+ if (COFFObjectFile *COFFObject =
+ dyn_cast<COFFObjectFile>(BinaryExecutable.get()))
+ mapVirtualAddress(*COFFObject);
+ }
+
+ // In order to generate a full logical view, we have to traverse both
+ // streams TPI and IPI if they are present. The following table gives
+ // the stream where a specified type is located. If the IPI stream is
+ // not present, all the types are located in the TPI stream.
+ //
+ // TPI Stream:
+ // LF_POINTER LF_MODIFIER LF_PROCEDURE LF_MFUNCTION
+ // LF_LABEL LF_ARGLIST LF_FIELDLIST LF_ARRAY
+ // LF_CLASS LF_STRUCTURE LF_INTERFACE LF_UNION
+ // LF_ENUM LF_TYPESERVER2 LF_VFTABLE LF_VTSHAPE
+ // LF_BITFIELD LF_METHODLIST LF_PRECOMP LF_ENDPRECOMP
+ //
+ // IPI stream:
+ // LF_FUNC_ID LF_MFUNC_ID LF_BUILDINFO
+ // LF_SUBSTR_LIST LF_STRING_ID LF_UDT_SRC_LINE
+ // LF_UDT_MOD_SRC_LINE
+
+ LazyRandomTypeCollection &Types = types();
+ LazyRandomTypeCollection &Ids = ids();
+ if (Error Err = traverseTypes(Pdb, Types, Ids))
+ return Err;
+
+ // Process collected namespaces.
+ LogicalVisitor.processNamespaces();
+
+ LLVM_DEBUG({ W.getOStream() << "Traversing inlined lines\n"; });
+
+ auto VisitInlineeLines = [&](int32_t Modi, const SymbolGroup &SG,
+ DebugInlineeLinesSubsectionRef &Lines) -> Error {
+ return collectInlineeInfo(Lines, &SG);
+ };
+
+ FilterOptions Filters = {};
+ LinePrinter Printer(/*Indent=*/2, false, nulls(), Filters);
+ const PrintScope HeaderScope(Printer, /*IndentLevel=*/2);
+ if (Error Err = iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
+ Input, HeaderScope, VisitInlineeLines))
+ return Err;
+
+ // Traverse global symbols.
+ LLVM_DEBUG({ W.getOStream() << "Traversing global symbols\n"; });
+ if (Pdb.hasPDBGlobalsStream()) {
+ Expected<GlobalsStream &> GlobalsOrErr = Pdb.getPDBGlobalsStream();
+ if (!GlobalsOrErr)
+ return GlobalsOrErr.takeError();
+ GlobalsStream &Globals = *GlobalsOrErr;
+ const GSIHashTable &Table = Globals.getGlobalsTable();
+ Expected<SymbolStream &> ExpectedSyms = Pdb.getPDBSymbolStream();
+ if (ExpectedSyms) {
+
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+ LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr,
+ LogicalVisitor.getShared());
+
+ // As the global symbols do not have an associated Compile Unit, create
+ // one, as the container for all global symbols.
+ RecordPrefix Prefix(SymbolKind::S_COMPILE3);
+ CVSymbol Symbol(&Prefix, sizeof(Prefix));
+ uint32_t Offset = 0;
+ if (Error Err = Traverser.visitSymbolBegin(Symbol, Offset))
+ consumeError(std::move(Err));
+ else {
+ // The CodeView compile unit containing the global symbols does not
+ // have a name; generate one using its parent name (object filename)
+ // follow by the '_global' string.
+ std::string Name(CompileUnit->getParentScope()->getName());
+ CompileUnit->setName(Name.append("_global"));
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Traverser);
+ CVSymbolVisitor Visitor(Pipeline);
+
+ BinaryStreamRef SymStream =
+ ExpectedSyms->getSymbolArray().getUnderlyingStream();
+ for (uint32_t PubSymOff : Table) {
+ Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
+ if (Sym) {
+ if (Error Err = Visitor.visitSymbolRecord(*Sym, PubSymOff))
+ return createStringError(errorToErrorCode(std::move(Err)),
+ getFileName());
+ } else {
+ consumeError(Sym.takeError());
+ }
+ }
+ }
+
+ LogicalVisitor.closeScope();
+ } else {
+ consumeError(ExpectedSyms.takeError());
+ }
+ }
+
+ // Traverse symbols (DBI).
+ LLVM_DEBUG({ W.getOStream() << "Traversing symbol groups\n"; });
+
+ auto VisitSymbolGroup = [&](uint32_t Modi, const SymbolGroup &SG) -> Error {
+ Expected<ModuleDebugStreamRef> ExpectedModS =
+ getModuleDebugStream(Pdb, Modi);
+ if (ExpectedModS) {
+ ModuleDebugStreamRef &ModS = *ExpectedModS;
+
+ LLVM_DEBUG({
+ W.getOStream() << formatv("Traversing Group: Mod {0:4}\n", Modi);
+ });
+
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+ LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr,
+ LogicalVisitor.getShared());
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Traverser);
+ CVSymbolVisitor Visitor(Pipeline);
+ BinarySubstreamRef SS = ModS.getSymbolsSubstream();
+ if (Error Err =
+ Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset))
+ return createStringError(errorToErrorCode(std::move(Err)),
+ getFileName());
+ } else {
+ // If the module stream does not exist, it is not an error condition.
+ consumeError(ExpectedModS.takeError());
+ }
+
+ return Error::success();
+ };
+
+ if (Error Err = iterateSymbolGroups(Input, HeaderScope, VisitSymbolGroup))
+ return Err;
+
+ // At this stage, the logical view contains all scopes, symbols and types.
+ // For PDBs we can use the module id, to access its specific compile unit.
+ // The line record addresses has been already resolved, so we can apply the
+ // flow as when processing DWARF.
+
+ LLVM_DEBUG({ W.getOStream() << "Traversing lines\n"; });
+
+ // Record all line records for a Compile Unit.
+ CULines.clear();
+
+ auto VisitDebugLines = [this](int32_t Modi, const SymbolGroup &SG,
+ DebugLinesSubsectionRef &Lines) -> Error {
+ if (!options().getPrintLines())
+ return Error::success();
+
+ uint16_t Segment = Lines.header()->RelocSegment;
+ uint32_t Begin = Lines.header()->RelocOffset;
+ uint32_t Size = Lines.header()->CodeSize;
+
+ LLVM_DEBUG({ W.getOStream() << formatv("Modi = {0}\n", Modi); });
+
+ // We have line information for a new module; finish processing the
+ // collected information for the current module. Once it is done, start
+ // recording the line information for the new module.
+ if (CurrentModule != Modi) {
+ if (Error Err = processModule())
+ return Err;
+ CULines.clear();
+ CurrentModule = Modi;
+ }
+
+ for (const LineColumnEntry &Block : Lines)
+ if (Error Err = createLines(Block.LineNumbers, /*Addendum=*/0, Segment,
+ Begin, Size, Block.NameIndex, &SG))
+ return Err;
+
+ return Error::success();
+ };
+
+ if (Error Err = iterateModuleSubsections<DebugLinesSubsectionRef>(
+ Input, HeaderScope, VisitDebugLines))
+ return Err;
+
+ // Check if we have to close the Compile Unit scope.
+ LogicalVisitor.closeScope();
+
+ // Process collected element lines.
+ LogicalVisitor.processLines();
+
+ // Translate composite names into a single component.
+ Root->transformScopedName();
+ return Error::success();
+}
+
+Error LVCodeViewReader::processModule() {
+ if (LVScope *Scope = getScopeForModule(CurrentModule)) {
+ CompileUnit = static_cast<LVScopeCompileUnit *>(Scope);
+
+ LLVM_DEBUG({ dbgs() << "Processing Scope: " << Scope->getName() << "\n"; });
+
+ // For the given compile unit, collect all scopes ranges.
+ // For a complete ranges and lines mapping, the logical view support
+ // needs for the compile unit to have a low and high pc values. We
+ // can traverse the 'Modules' section and get the information for the
+ // specific module. Another option, is from all the ranges collected
+ // to take the first and last values.
+ LVSectionIndex SectionIndex = DotTextSectionIndex;
+ LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+ ScopesWithRanges->clear();
+ CompileUnit->getRanges(*ScopesWithRanges);
+ if (!ScopesWithRanges->empty())
+ CompileUnit->addObject(ScopesWithRanges->getLower(),
+ ScopesWithRanges->getUpper());
+ ScopesWithRanges->sort();
+
+ if (Error Err = createInstructions())
+ return Err;
+
+ // Include lines from any inlined functions within the current function.
+ includeInlineeLines(SectionIndex, Scope);
+
+ processLines(&CULines, SectionIndex, nullptr);
+ }
+
+ return Error::success();
+}
+
+// In order to create the scopes, the CodeView Reader will:
+// = Traverse the TPI/IPI stream (Type visitor):
+// Collect forward references, scoped names, type indexes that will represent
+// a logical element, strings, line records, linkage names.
+// = Traverse the symbols section (Symbol visitor):
+// Create the scopes tree and creates the required logical elements, by
+// using the collected indexes from the type visitor.
+Error LVCodeViewReader::createScopes() {
+ LLVM_DEBUG({
+ W.startLine() << "\n";
+ W.printString("File", getFileName().str());
+ W.printString("Exe", ExePath);
+ W.printString("Format", FileFormatName);
+ });
+
+ if (Error Err = LVReader::createScopes())
+ return Err;
+
+ LogicalVisitor.setRoot(Root);
+
+ if (isObj()) {
+ if (Error Err = createScopes(getObj()))
+ return Err;
+ } else {
+ if (Error Err = createScopes(getPdb()))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+Error LVCodeViewReader::loadTargetInfo(const ObjectFile &Obj) {
+ // Detect the architecture from the object file. We usually don't need OS
+ // info to lookup a target and create register info.
+ Triple TT;
+ TT.setArch(Triple::ArchType(Obj.getArch()));
+ TT.setVendor(Triple::UnknownVendor);
+ TT.setOS(Triple::UnknownOS);
+
+ // Features to be passed to target/subtarget
+ Expected<SubtargetFeatures> Features = Obj.getFeatures();
+ SubtargetFeatures FeaturesValue;
+ if (!Features) {
+ consumeError(Features.takeError());
+ FeaturesValue = SubtargetFeatures();
+ }
+ FeaturesValue = *Features;
+ return loadGenericTargetInfo(TT.str(), FeaturesValue.getString());
+}
+
+Error LVCodeViewReader::loadTargetInfo(const PDBFile &Pdb) {
+ Triple TT;
+ TT.setArch(Triple::ArchType::x86_64);
+ TT.setVendor(Triple::UnknownVendor);
+ TT.setOS(Triple::Win32);
+
+ StringRef TheFeature = "";
+
+ return loadGenericTargetInfo(TT.str(), TheFeature);
+}
+
+std::string LVCodeViewReader::getRegisterName(LVSmall Opcode,
+ ArrayRef<uint64_t> Operands) {
+ // Get Compilation Unit CPU Type.
+ CPUType CPU = getCompileUnitCPUType();
+ // For CodeView the register always is in Operands[0];
+ RegisterId Register = (RegisterId(Operands[0]));
+ return formatRegisterId(Register, CPU);
+}