Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp
35295 views
//===-- LVCodeViewReader.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This implements the LVCodeViewReader class.9//10//===----------------------------------------------------------------------===//1112#include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"13#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"14#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"15#include "llvm/DebugInfo/CodeView/EnumTables.h"16#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"17#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"18#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"19#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"20#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"21#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"22#include "llvm/DebugInfo/LogicalView/Core/LVType.h"23#include "llvm/DebugInfo/PDB/GenericError.h"24#include "llvm/DebugInfo/PDB/Native/DbiStream.h"25#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"26#include "llvm/DebugInfo/PDB/Native/InfoStream.h"27#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"28#include "llvm/DebugInfo/PDB/Native/PDBFile.h"29#include "llvm/DebugInfo/PDB/Native/RawConstants.h"30#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"31#include "llvm/DebugInfo/PDB/Native/TpiStream.h"32#include "llvm/Demangle/Demangle.h"33#include "llvm/Object/COFF.h"34#include "llvm/Support/Errc.h"35#include "llvm/Support/Error.h"36#include "llvm/Support/FormatAdapters.h"37#include "llvm/Support/FormatVariadic.h"38#include "llvm/Support/WithColor.h"3940using namespace llvm;41using namespace llvm::codeview;42using namespace llvm::logicalview;43using namespace llvm::msf;44using namespace llvm::object;45using namespace llvm::pdb;4647#define DEBUG_TYPE "CodeViewReader"4849StringRef LVCodeViewReader::getSymbolKindName(SymbolKind Kind) {50switch (Kind) {51#define SYMBOL_RECORD(EnumName, EnumVal, Name) \52case EnumName: \53return #EnumName;54#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"55default:56return "UnknownSym";57}58llvm_unreachable("Unknown SymbolKind::Kind");59}6061std::string LVCodeViewReader::formatRegisterId(RegisterId Register,62CPUType CPU) {63#define RETURN_CASE(Enum, X, Ret) \64case Enum::X: \65return Ret;6667if (CPU == CPUType::ARMNT) {68switch (Register) {69#define CV_REGISTERS_ARM70#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)71#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"72#undef CV_REGISTER73#undef CV_REGISTERS_ARM7475default:76break;77}78} else if (CPU == CPUType::ARM64) {79switch (Register) {80#define CV_REGISTERS_ARM6481#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)82#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"83#undef CV_REGISTER84#undef CV_REGISTERS_ARM648586default:87break;88}89} else {90switch (Register) {91#define CV_REGISTERS_X8692#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)93#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"94#undef CV_REGISTER95#undef CV_REGISTERS_X869697default:98break;99}100}101return "formatUnknownEnum(Id)";102}103104void LVCodeViewReader::printRelocatedField(StringRef Label,105const coff_section *CoffSection,106uint32_t RelocOffset,107uint32_t Offset,108StringRef *RelocSym) {109StringRef SymStorage;110StringRef &Symbol = RelocSym ? *RelocSym : SymStorage;111if (!resolveSymbolName(CoffSection, RelocOffset, Symbol))112W.printSymbolOffset(Label, Symbol, Offset);113else114W.printHex(Label, RelocOffset);115}116117void LVCodeViewReader::getLinkageName(const coff_section *CoffSection,118uint32_t RelocOffset, uint32_t Offset,119StringRef *RelocSym) {120StringRef SymStorage;121StringRef &Symbol = RelocSym ? *RelocSym : SymStorage;122if (resolveSymbolName(CoffSection, RelocOffset, Symbol))123Symbol = "";124}125126Expected<StringRef>127LVCodeViewReader::getFileNameForFileOffset(uint32_t FileOffset,128const SymbolGroup *SG) {129if (SG) {130Expected<StringRef> Filename = SG->getNameFromChecksums(FileOffset);131if (!Filename) {132consumeError(Filename.takeError());133return StringRef("");134}135return *Filename;136}137138// The file checksum subsection should precede all references to it.139if (!CVFileChecksumTable.valid() || !CVStringTable.valid())140return createStringError(object_error::parse_failed, getFileName());141142VarStreamArray<FileChecksumEntry>::Iterator Iter =143CVFileChecksumTable.getArray().at(FileOffset);144145// Check if the file checksum table offset is valid.146if (Iter == CVFileChecksumTable.end())147return createStringError(object_error::parse_failed, getFileName());148149Expected<StringRef> NameOrErr = CVStringTable.getString(Iter->FileNameOffset);150if (!NameOrErr)151return createStringError(object_error::parse_failed, getFileName());152return *NameOrErr;153}154155Error LVCodeViewReader::printFileNameForOffset(StringRef Label,156uint32_t FileOffset,157const SymbolGroup *SG) {158Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG);159if (!NameOrErr)160return NameOrErr.takeError();161W.printHex(Label, *NameOrErr, FileOffset);162return Error::success();163}164165void LVCodeViewReader::cacheRelocations() {166for (const SectionRef &Section : getObj().sections()) {167const coff_section *CoffSection = getObj().getCOFFSection(Section);168169for (const RelocationRef &Relocacion : Section.relocations())170RelocMap[CoffSection].push_back(Relocacion);171172// Sort relocations by address.173llvm::sort(RelocMap[CoffSection], [](RelocationRef L, RelocationRef R) {174return L.getOffset() < R.getOffset();175});176}177}178179// Given a section and an offset into this section the function returns the180// symbol used for the relocation at the offset.181Error LVCodeViewReader::resolveSymbol(const coff_section *CoffSection,182uint64_t Offset, SymbolRef &Sym) {183const auto &Relocations = RelocMap[CoffSection];184basic_symbol_iterator SymI = getObj().symbol_end();185for (const RelocationRef &Relocation : Relocations) {186uint64_t RelocationOffset = Relocation.getOffset();187188if (RelocationOffset == Offset) {189SymI = Relocation.getSymbol();190break;191}192}193if (SymI == getObj().symbol_end())194return make_error<StringError>("Unknown Symbol", inconvertibleErrorCode());195Sym = *SymI;196return ErrorSuccess();197}198199// Given a section and an offset into this section the function returns the200// name of the symbol used for the relocation at the offset.201Error LVCodeViewReader::resolveSymbolName(const coff_section *CoffSection,202uint64_t Offset, StringRef &Name) {203SymbolRef Symbol;204if (Error E = resolveSymbol(CoffSection, Offset, Symbol))205return E;206Expected<StringRef> NameOrErr = Symbol.getName();207if (!NameOrErr)208return NameOrErr.takeError();209Name = *NameOrErr;210return ErrorSuccess();211}212213// CodeView and DWARF can have references to compiler generated elements,214// used for initialization. The MSVC includes in the PDBs, internal compile215// units, associated with the MS runtime support. We mark them as 'system'216// and they are printed only if the command line option 'internal=system'.217bool LVCodeViewReader::isSystemEntry(LVElement *Element, StringRef Name) const {218Name = Name.empty() ? Element->getName() : Name;219auto Find = [=](const char *String) -> bool { return Name.contains(String); };220auto Starts = [=](const char *Pattern) -> bool {221return Name.starts_with(Pattern);222};223auto CheckExclude = [&]() -> bool {224if (Starts("__") || Starts("_PMD") || Starts("_PMFN"))225return true;226if (Find("_s__"))227return true;228if (Find("_CatchableType") || Find("_TypeDescriptor"))229return true;230if (Find("Intermediate\\vctools"))231return true;232if (Find("$initializer$") || Find("dynamic initializer"))233return true;234if (Find("`vftable'") || Find("_GLOBAL__sub"))235return true;236return false;237};238bool Excluded = CheckExclude();239if (Excluded)240Element->setIsSystem();241242return Excluded;243}244245Error LVCodeViewReader::collectInlineeInfo(246DebugInlineeLinesSubsectionRef &Lines, const llvm::pdb::SymbolGroup *SG) {247for (const InlineeSourceLine &Line : Lines) {248TypeIndex TIInlinee = Line.Header->Inlinee;249uint32_t LineNumber = Line.Header->SourceLineNum;250uint32_t FileOffset = Line.Header->FileID;251LLVM_DEBUG({252DictScope S(W, "InlineeSourceLine");253LogicalVisitor.printTypeIndex("Inlinee", TIInlinee, StreamTPI);254if (Error Err = printFileNameForOffset("FileID", FileOffset, SG))255return Err;256W.printNumber("SourceLineNum", LineNumber);257258if (Lines.hasExtraFiles()) {259W.printNumber("ExtraFileCount", Line.ExtraFiles.size());260ListScope ExtraFiles(W, "ExtraFiles");261for (const ulittle32_t &FID : Line.ExtraFiles)262if (Error Err = printFileNameForOffset("FileID", FID, SG))263return Err;264}265});266Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG);267if (!NameOrErr)268return NameOrErr.takeError();269LogicalVisitor.addInlineeInfo(TIInlinee, LineNumber, *NameOrErr);270}271272return Error::success();273}274275Error LVCodeViewReader::traverseInlineeLines(StringRef Subsection) {276BinaryStreamReader SR(Subsection, llvm::endianness::little);277DebugInlineeLinesSubsectionRef Lines;278if (Error E = Lines.initialize(SR))279return createStringError(errorToErrorCode(std::move(E)), getFileName());280281return collectInlineeInfo(Lines);282}283284Error LVCodeViewReader::createLines(285const FixedStreamArray<LineNumberEntry> &LineNumbers, LVAddress Addendum,286uint32_t Segment, uint32_t Begin, uint32_t Size, uint32_t NameIndex,287const SymbolGroup *SG) {288LLVM_DEBUG({289uint32_t End = Begin + Size;290W.getOStream() << formatv("{0:x-4}:{1:x-8}-{2:x-8}\n", Segment, Begin, End);291});292293for (const LineNumberEntry &Line : LineNumbers) {294if (Line.Offset >= Size)295return createStringError(object_error::parse_failed, getFileName());296297LineInfo LI(Line.Flags);298299LLVM_DEBUG({300W.getOStream() << formatv(301"{0} {1:x-8}\n", utostr(LI.getStartLine()),302fmt_align(Begin + Line.Offset, AlignStyle::Right, 8, '0'));303});304305// The 'processLines()' function will move each created logical line306// to its enclosing logical scope, using the debug ranges information307// and they will be released when its scope parent is deleted.308LVLineDebug *LineDebug = createLineDebug();309CULines.push_back(LineDebug);310LVAddress Address = linearAddress(Segment, Begin + Line.Offset);311LineDebug->setAddress(Address + Addendum);312313if (LI.isAlwaysStepInto())314LineDebug->setIsAlwaysStepInto();315else if (LI.isNeverStepInto())316LineDebug->setIsNeverStepInto();317else318LineDebug->setLineNumber(LI.getStartLine());319320if (LI.isStatement())321LineDebug->setIsNewStatement();322323Expected<StringRef> NameOrErr = getFileNameForFileOffset(NameIndex, SG);324if (!NameOrErr)325return NameOrErr.takeError();326LineDebug->setFilename(*NameOrErr);327}328329return Error::success();330}331332Error LVCodeViewReader::initializeFileAndStringTables(333BinaryStreamReader &Reader) {334while (Reader.bytesRemaining() > 0 &&335(!CVFileChecksumTable.valid() || !CVStringTable.valid())) {336// The section consists of a number of subsection in the following format:337// |SubSectionType|SubSectionSize|Contents...|338uint32_t SubType, SubSectionSize;339340if (Error E = Reader.readInteger(SubType))341return createStringError(errorToErrorCode(std::move(E)), getFileName());342if (Error E = Reader.readInteger(SubSectionSize))343return createStringError(errorToErrorCode(std::move(E)), getFileName());344345StringRef Contents;346if (Error E = Reader.readFixedString(Contents, SubSectionSize))347return createStringError(errorToErrorCode(std::move(E)), getFileName());348349BinaryStreamRef ST(Contents, llvm::endianness::little);350switch (DebugSubsectionKind(SubType)) {351case DebugSubsectionKind::FileChecksums:352if (Error E = CVFileChecksumTable.initialize(ST))353return createStringError(errorToErrorCode(std::move(E)), getFileName());354break;355case DebugSubsectionKind::StringTable:356if (Error E = CVStringTable.initialize(ST))357return createStringError(errorToErrorCode(std::move(E)), getFileName());358break;359default:360break;361}362363uint32_t PaddedSize = alignTo(SubSectionSize, 4);364if (Error E = Reader.skip(PaddedSize - SubSectionSize))365return createStringError(errorToErrorCode(std::move(E)), getFileName());366}367368return Error::success();369}370371Error LVCodeViewReader::loadTypeServer(TypeServer2Record &TS) {372LLVM_DEBUG({373W.printString("Guid", formatv("{0}", TS.getGuid()).str());374W.printNumber("Age", TS.getAge());375W.printString("Name", TS.getName());376});377378SmallString<128> ServerName(TS.getName());379BuffOrErr = MemoryBuffer::getFile(ServerName);380if (BuffOrErr.getError()) {381// The server name does not exist. Try in the same directory as the382// input file.383ServerName = createAlternativePath(ServerName);384BuffOrErr = MemoryBuffer::getFile(ServerName);385if (BuffOrErr.getError()) {386// For the error message, use the original type server name.387return createStringError(errc::bad_file_descriptor,388"File '%s' does not exist.",389TS.getName().str().c_str());390}391}392MemBuffer = std::move(BuffOrErr.get());393394// Check if the buffer corresponds to a PDB file.395assert(identify_magic((*MemBuffer).getBuffer()) == file_magic::pdb &&396"Invalid PDB file.");397398if (Error Err = loadDataForPDB(PDB_ReaderType::Native, ServerName, Session))399return createStringError(errorToErrorCode(std::move(Err)), "%s",400ServerName.c_str());401402PdbSession.reset(static_cast<NativeSession *>(Session.release()));403PDBFile &Pdb = PdbSession->getPDBFile();404405// Just because a file with a matching name was found and it was an actual406// PDB file doesn't mean it matches. For it to match the InfoStream's GUID407// must match the GUID specified in the TypeServer2 record.408Expected<InfoStream &> expectedInfo = Pdb.getPDBInfoStream();409if (!expectedInfo || expectedInfo->getGuid() != TS.getGuid())410return createStringError(errc::invalid_argument, "signature_out_of_date");411412// The reader needs to switch to a type server, to process the types from413// the server. We need to keep the original input source, as reading other414// sections will require the input associated with the loaded object file.415TypeServer = std::make_shared<InputFile>(&Pdb);416LogicalVisitor.setInput(TypeServer);417418LazyRandomTypeCollection &Types = types();419LazyRandomTypeCollection &Ids = ids();420if (Error Err = traverseTypes(Pdb, Types, Ids))421return Err;422423return Error::success();424}425426Error LVCodeViewReader::loadPrecompiledObject(PrecompRecord &Precomp,427CVTypeArray &CVTypesObj) {428LLVM_DEBUG({429W.printHex("Count", Precomp.getTypesCount());430W.printHex("Signature", Precomp.getSignature());431W.printString("PrecompFile", Precomp.getPrecompFilePath());432});433434SmallString<128> ServerName(Precomp.getPrecompFilePath());435BuffOrErr = MemoryBuffer::getFile(ServerName);436if (BuffOrErr.getError()) {437// The server name does not exist. Try in the directory as the input file.438ServerName = createAlternativePath(ServerName);439if (BuffOrErr.getError()) {440// For the error message, use the original type server name.441return createStringError(errc::bad_file_descriptor,442"File '%s' does not exist.",443Precomp.getPrecompFilePath().str().c_str());444}445}446MemBuffer = std::move(BuffOrErr.get());447448Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(*MemBuffer);449if (errorToErrorCode(BinOrErr.takeError()))450return createStringError(errc::not_supported,451"Binary object format in '%s' is not supported.",452ServerName.c_str());453454Binary &BinaryObj = *BinOrErr.get();455if (!BinaryObj.isCOFF())456return createStringError(errc::not_supported, "'%s' is not a COFF object.",457ServerName.c_str());458459Builder = std::make_unique<AppendingTypeTableBuilder>(BuilderAllocator);460461// The MSVC precompiled header object file, should contain just a single462// ".debug$P" section.463COFFObjectFile &Obj = *cast<COFFObjectFile>(&BinaryObj);464for (const SectionRef &Section : Obj.sections()) {465Expected<StringRef> SectionNameOrErr = Section.getName();466if (!SectionNameOrErr)467return SectionNameOrErr.takeError();468if (*SectionNameOrErr == ".debug$P") {469Expected<StringRef> DataOrErr = Section.getContents();470if (!DataOrErr)471return DataOrErr.takeError();472uint32_t Magic;473if (Error Err = consume(*DataOrErr, Magic))474return Err;475if (Magic != COFF::DEBUG_SECTION_MAGIC)476return errorCodeToError(object_error::parse_failed);477478ReaderPrecomp = std::make_unique<BinaryStreamReader>(479*DataOrErr, llvm::endianness::little);480cantFail(481ReaderPrecomp->readArray(CVTypesPrecomp, ReaderPrecomp->getLength()));482483// Append all the type records up to the LF_ENDPRECOMP marker and484// check if the signatures match.485for (const CVType &Type : CVTypesPrecomp) {486ArrayRef<uint8_t> TypeData = Type.data();487if (Type.kind() == LF_ENDPRECOMP) {488EndPrecompRecord EndPrecomp = cantFail(489TypeDeserializer::deserializeAs<EndPrecompRecord>(TypeData));490if (Precomp.getSignature() != EndPrecomp.getSignature())491return createStringError(errc::invalid_argument, "no matching pch");492break;493}494Builder->insertRecordBytes(TypeData);495}496// Done processing .debug$P, break out of section loop.497break;498}499}500501// Append all the type records, skipping the first record which is the502// reference to the precompiled header object information.503for (const CVType &Type : CVTypesObj) {504ArrayRef<uint8_t> TypeData = Type.data();505if (Type.kind() != LF_PRECOMP)506Builder->insertRecordBytes(TypeData);507}508509// Set up a type stream that refers to the added type records.510Builder->ForEachRecord(511[&](TypeIndex TI, const CVType &Type) { TypeArray.push_back(Type); });512513ItemStream =514std::make_unique<BinaryItemStream<CVType>>(llvm::endianness::little);515ItemStream->setItems(TypeArray);516TypeStream.setUnderlyingStream(*ItemStream);517518PrecompHeader =519std::make_shared<LazyRandomTypeCollection>(TypeStream, TypeArray.size());520521// Change the original input source to use the collected type records.522LogicalVisitor.setInput(PrecompHeader);523524LazyRandomTypeCollection &Types = types();525LazyRandomTypeCollection &Ids = ids();526LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI,527LogicalVisitor.getShared());528return visitTypeStream(Types, TDV);529}530531Error LVCodeViewReader::traverseTypeSection(StringRef SectionName,532const SectionRef &Section) {533LLVM_DEBUG({534ListScope D(W, "CodeViewTypes");535W.printNumber("Section", SectionName, getObj().getSectionID(Section));536});537538Expected<StringRef> DataOrErr = Section.getContents();539if (!DataOrErr)540return DataOrErr.takeError();541uint32_t Magic;542if (Error Err = consume(*DataOrErr, Magic))543return Err;544if (Magic != COFF::DEBUG_SECTION_MAGIC)545return errorCodeToError(object_error::parse_failed);546547// Get the first type record. It will indicate if this object uses a type548// server (/Zi) or a PCH file (/Yu).549CVTypeArray CVTypes;550BinaryStreamReader Reader(*DataOrErr, llvm::endianness::little);551cantFail(Reader.readArray(CVTypes, Reader.getLength()));552CVTypeArray::Iterator FirstType = CVTypes.begin();553554// The object was compiled with /Zi. It uses types from a type server PDB.555if (FirstType->kind() == LF_TYPESERVER2) {556TypeServer2Record TS = cantFail(557TypeDeserializer::deserializeAs<TypeServer2Record>(FirstType->data()));558return loadTypeServer(TS);559}560561// The object was compiled with /Yc or /Yu. It uses types from another562// object file with a matching signature.563if (FirstType->kind() == LF_PRECOMP) {564PrecompRecord Precomp = cantFail(565TypeDeserializer::deserializeAs<PrecompRecord>(FirstType->data()));566return loadPrecompiledObject(Precomp, CVTypes);567}568569LazyRandomTypeCollection &Types = types();570LazyRandomTypeCollection &Ids = ids();571Types.reset(*DataOrErr, 100);572LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI,573LogicalVisitor.getShared());574return visitTypeStream(Types, TDV);575}576577Error LVCodeViewReader::traverseTypes(PDBFile &Pdb,578LazyRandomTypeCollection &Types,579LazyRandomTypeCollection &Ids) {580// Traverse types (TPI and IPI).581auto VisitTypes = [&](LazyRandomTypeCollection &Types,582LazyRandomTypeCollection &Ids,583SpecialStream StreamIdx) -> Error {584LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamIdx,585LogicalVisitor.getShared());586return visitTypeStream(Types, TDV);587};588589Expected<TpiStream &> StreamTpiOrErr = Pdb.getPDBTpiStream();590if (!StreamTpiOrErr)591return StreamTpiOrErr.takeError();592TpiStream &StreamTpi = *StreamTpiOrErr;593StreamTpi.buildHashMap();594LLVM_DEBUG({595W.getOStream() << formatv("Showing {0:N} TPI records\n",596StreamTpi.getNumTypeRecords());597});598if (Error Err = VisitTypes(Types, Ids, StreamTPI))599return Err;600601Expected<TpiStream &> StreamIpiOrErr = Pdb.getPDBIpiStream();602if (!StreamIpiOrErr)603return StreamIpiOrErr.takeError();604TpiStream &StreamIpi = *StreamIpiOrErr;605StreamIpi.buildHashMap();606LLVM_DEBUG({607W.getOStream() << formatv("Showing {0:N} IPI records\n",608StreamIpi.getNumTypeRecords());609});610return VisitTypes(Ids, Ids, StreamIPI);611}612613Error LVCodeViewReader::traverseSymbolsSubsection(StringRef Subsection,614const SectionRef &Section,615StringRef SectionContents) {616ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(),617Subsection.bytes_end());618LVSymbolVisitorDelegate VisitorDelegate(this, Section, &getObj(),619SectionContents);620CVSymbolArray Symbols;621BinaryStreamReader Reader(BinaryData, llvm::endianness::little);622if (Error E = Reader.readArray(Symbols, Reader.getLength()))623return createStringError(errorToErrorCode(std::move(E)), getFileName());624625LazyRandomTypeCollection &Types = types();626LazyRandomTypeCollection &Ids = ids();627SymbolVisitorCallbackPipeline Pipeline;628SymbolDeserializer Deserializer(&VisitorDelegate,629CodeViewContainer::ObjectFile);630// As we are processing a COFF format, use TPI as IPI, so the generic code631// to process the CodeView format does not contain any additional checks.632LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids,633&VisitorDelegate, LogicalVisitor.getShared());634635Pipeline.addCallbackToPipeline(Deserializer);636Pipeline.addCallbackToPipeline(Traverser);637CVSymbolVisitor Visitor(Pipeline);638return Visitor.visitSymbolStream(Symbols);639}640641Error LVCodeViewReader::traverseSymbolSection(StringRef SectionName,642const SectionRef &Section) {643LLVM_DEBUG({644ListScope D(W, "CodeViewDebugInfo");645W.printNumber("Section", SectionName, getObj().getSectionID(Section));646});647648Expected<StringRef> SectionOrErr = Section.getContents();649if (!SectionOrErr)650return SectionOrErr.takeError();651StringRef SectionContents = *SectionOrErr;652StringRef Data = SectionContents;653654SmallVector<StringRef, 10> SymbolNames;655StringMap<StringRef> FunctionLineTables;656657uint32_t Magic;658if (Error E = consume(Data, Magic))659return createStringError(errorToErrorCode(std::move(E)), getFileName());660661if (Magic != COFF::DEBUG_SECTION_MAGIC)662return createStringError(object_error::parse_failed, getFileName());663664BinaryStreamReader FSReader(Data, llvm::endianness::little);665if (Error Err = initializeFileAndStringTables(FSReader))666return Err;667668while (!Data.empty()) {669// The section consists of a number of subsection in the following format:670// |SubSectionType|SubSectionSize|Contents...|671uint32_t SubType, SubSectionSize;672if (Error E = consume(Data, SubType))673return createStringError(errorToErrorCode(std::move(E)), getFileName());674if (Error E = consume(Data, SubSectionSize))675return createStringError(errorToErrorCode(std::move(E)), getFileName());676677// Process the subsection as normal even if the ignore bit is set.678SubType &= ~SubsectionIgnoreFlag;679680// Get the contents of the subsection.681if (SubSectionSize > Data.size())682return createStringError(object_error::parse_failed, getFileName());683StringRef Contents = Data.substr(0, SubSectionSize);684685// Add SubSectionSize to the current offset and align that offset686// to find the next subsection.687size_t SectionOffset = Data.data() - SectionContents.data();688size_t NextOffset = SectionOffset + SubSectionSize;689NextOffset = alignTo(NextOffset, 4);690if (NextOffset > SectionContents.size())691return createStringError(object_error::parse_failed, getFileName());692Data = SectionContents.drop_front(NextOffset);693694switch (DebugSubsectionKind(SubType)) {695case DebugSubsectionKind::Symbols:696if (Error Err =697traverseSymbolsSubsection(Contents, Section, SectionContents))698return Err;699break;700701case DebugSubsectionKind::InlineeLines:702if (Error Err = traverseInlineeLines(Contents))703return Err;704break;705706case DebugSubsectionKind::Lines:707// Holds a PC to file:line table. Some data to parse this subsection708// is stored in the other subsections, so just check sanity and store709// the pointers for deferred processing.710711// Collect function and ranges only if we need to print logical lines.712if (options().getGeneralCollectRanges()) {713714if (SubSectionSize < 12) {715// There should be at least three words to store two function716// relocations and size of the code.717return createStringError(object_error::parse_failed, getFileName());718}719720StringRef SymbolName;721if (Error Err = resolveSymbolName(getObj().getCOFFSection(Section),722SectionOffset, SymbolName))723return createStringError(errorToErrorCode(std::move(Err)),724getFileName());725726LLVM_DEBUG({ W.printString("Symbol Name", SymbolName); });727if (FunctionLineTables.count(SymbolName) != 0) {728// Saw debug info for this function already?729return createStringError(object_error::parse_failed, getFileName());730}731732FunctionLineTables[SymbolName] = Contents;733SymbolNames.push_back(SymbolName);734}735break;736737// Do nothing for unrecognized subsections.738default:739break;740}741W.flush();742}743744// Traverse the line tables now that we've read all the subsections and745// know all the required information.746for (StringRef SymbolName : SymbolNames) {747LLVM_DEBUG({748ListScope S(W, "FunctionLineTable");749W.printString("Symbol Name", SymbolName);750});751752BinaryStreamReader Reader(FunctionLineTables[SymbolName],753llvm::endianness::little);754755DebugLinesSubsectionRef Lines;756if (Error E = Lines.initialize(Reader))757return createStringError(errorToErrorCode(std::move(E)), getFileName());758759// Find the associated symbol table information.760LVSymbolTableEntry SymbolTableEntry = getSymbolTableEntry(SymbolName);761LVScope *Function = SymbolTableEntry.Scope;762if (!Function)763continue;764765LVAddress Addendum = SymbolTableEntry.Address;766LVSectionIndex SectionIndex = SymbolTableEntry.SectionIndex;767768// The given scope represents the function that contains the line numbers.769// Collect all generated debug lines associated with the function.770CULines.clear();771772// For the given scope, collect all scopes ranges.773LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);774ScopesWithRanges->clear();775Function->getRanges(*ScopesWithRanges);776ScopesWithRanges->sort();777778uint16_t Segment = Lines.header()->RelocSegment;779uint32_t Begin = Lines.header()->RelocOffset;780uint32_t Size = Lines.header()->CodeSize;781for (const LineColumnEntry &Block : Lines)782if (Error Err = createLines(Block.LineNumbers, Addendum, Segment, Begin,783Size, Block.NameIndex))784return Err;785786// Include lines from any inlined functions within the current function.787includeInlineeLines(SectionIndex, Function);788789if (Error Err = createInstructions(Function, SectionIndex))790return Err;791792processLines(&CULines, SectionIndex, Function);793}794795return Error::success();796}797798void LVCodeViewReader::sortScopes() { Root->sort(); }799800void LVCodeViewReader::print(raw_ostream &OS) const {801LLVM_DEBUG(dbgs() << "CreateReaders\n");802}803804void LVCodeViewReader::mapRangeAddress(const ObjectFile &Obj,805const SectionRef &Section,806bool IsComdat) {807if (!Obj.isCOFF())808return;809810const COFFObjectFile *Object = cast<COFFObjectFile>(&Obj);811812for (const SymbolRef &Sym : Object->symbols()) {813if (!Section.containsSymbol(Sym))814continue;815816COFFSymbolRef Symbol = Object->getCOFFSymbol(Sym);817if (Symbol.getComplexType() != llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION)818continue;819820StringRef SymbolName;821Expected<StringRef> SymNameOrErr = Object->getSymbolName(Symbol);822if (!SymNameOrErr) {823W.startLine() << "Invalid symbol name: " << Symbol.getSectionNumber()824<< "\n";825consumeError(SymNameOrErr.takeError());826continue;827}828SymbolName = *SymNameOrErr;829830LLVM_DEBUG({831Expected<const coff_section *> SectionOrErr =832Object->getSection(Symbol.getSectionNumber());833if (!SectionOrErr) {834W.startLine() << "Invalid section number: " << Symbol.getSectionNumber()835<< "\n";836consumeError(SectionOrErr.takeError());837return;838}839W.printNumber("Section #", Symbol.getSectionNumber());840W.printString("Name", SymbolName);841W.printHex("Value", Symbol.getValue());842});843844// Record the symbol name (linkage) and its loading address.845addToSymbolTable(SymbolName, Symbol.getValue(), Symbol.getSectionNumber(),846IsComdat);847}848}849850Error LVCodeViewReader::createScopes(COFFObjectFile &Obj) {851if (Error Err = loadTargetInfo(Obj))852return Err;853854// Initialization required when processing a COFF file:855// Cache the symbols relocations.856// Create a mapping for virtual addresses.857// Get the functions entry points.858cacheRelocations();859mapVirtualAddress(Obj);860861for (const SectionRef &Section : Obj.sections()) {862Expected<StringRef> SectionNameOrErr = Section.getName();863if (!SectionNameOrErr)864return SectionNameOrErr.takeError();865// .debug$T is a standard CodeView type section, while .debug$P is the866// same format but used for MSVC precompiled header object files.867if (*SectionNameOrErr == ".debug$T" || *SectionNameOrErr == ".debug$P")868if (Error Err = traverseTypeSection(*SectionNameOrErr, Section))869return Err;870}871872// Process collected namespaces.873LogicalVisitor.processNamespaces();874875for (const SectionRef &Section : Obj.sections()) {876Expected<StringRef> SectionNameOrErr = Section.getName();877if (!SectionNameOrErr)878return SectionNameOrErr.takeError();879if (*SectionNameOrErr == ".debug$S")880if (Error Err = traverseSymbolSection(*SectionNameOrErr, Section))881return Err;882}883884// Check if we have to close the Compile Unit scope.885LogicalVisitor.closeScope();886887// Traverse the strings recorded and transform them into filenames.888LogicalVisitor.processFiles();889890// Process collected element lines.891LogicalVisitor.processLines();892893// Translate composite names into a single component.894Root->transformScopedName();895return Error::success();896}897898Error LVCodeViewReader::createScopes(PDBFile &Pdb) {899if (Error Err = loadTargetInfo(Pdb))900return Err;901902if (!Pdb.hasPDBTpiStream() || !Pdb.hasPDBDbiStream())903return Error::success();904905// Open the executable associated with the PDB file and get the section906// addresses used to calculate linear addresses for CodeView Symbols.907if (!ExePath.empty()) {908ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =909MemoryBuffer::getFileOrSTDIN(ExePath);910if (BuffOrErr.getError()) {911return createStringError(errc::bad_file_descriptor,912"File '%s' does not exist.", ExePath.c_str());913}914BinaryBuffer = std::move(BuffOrErr.get());915916// Check if the buffer corresponds to a PECOFF executable.917assert(identify_magic(BinaryBuffer->getBuffer()) ==918file_magic::pecoff_executable &&919"Invalid PECOFF executable file.");920921Expected<std::unique_ptr<Binary>> BinOrErr =922createBinary(BinaryBuffer->getMemBufferRef());923if (errorToErrorCode(BinOrErr.takeError())) {924return createStringError(errc::not_supported,925"Binary object format in '%s' is not supported.",926ExePath.c_str());927}928BinaryExecutable = std::move(*BinOrErr);929if (COFFObjectFile *COFFObject =930dyn_cast<COFFObjectFile>(BinaryExecutable.get()))931mapVirtualAddress(*COFFObject);932}933934// In order to generate a full logical view, we have to traverse both935// streams TPI and IPI if they are present. The following table gives936// the stream where a specified type is located. If the IPI stream is937// not present, all the types are located in the TPI stream.938//939// TPI Stream:940// LF_POINTER LF_MODIFIER LF_PROCEDURE LF_MFUNCTION941// LF_LABEL LF_ARGLIST LF_FIELDLIST LF_ARRAY942// LF_CLASS LF_STRUCTURE LF_INTERFACE LF_UNION943// LF_ENUM LF_TYPESERVER2 LF_VFTABLE LF_VTSHAPE944// LF_BITFIELD LF_METHODLIST LF_PRECOMP LF_ENDPRECOMP945//946// IPI stream:947// LF_FUNC_ID LF_MFUNC_ID LF_BUILDINFO948// LF_SUBSTR_LIST LF_STRING_ID LF_UDT_SRC_LINE949// LF_UDT_MOD_SRC_LINE950951LazyRandomTypeCollection &Types = types();952LazyRandomTypeCollection &Ids = ids();953if (Error Err = traverseTypes(Pdb, Types, Ids))954return Err;955956// Process collected namespaces.957LogicalVisitor.processNamespaces();958959LLVM_DEBUG({ W.getOStream() << "Traversing inlined lines\n"; });960961auto VisitInlineeLines = [&](int32_t Modi, const SymbolGroup &SG,962DebugInlineeLinesSubsectionRef &Lines) -> Error {963return collectInlineeInfo(Lines, &SG);964};965966FilterOptions Filters = {};967LinePrinter Printer(/*Indent=*/2, false, nulls(), Filters);968const PrintScope HeaderScope(Printer, /*IndentLevel=*/2);969if (Error Err = iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(970Input, HeaderScope, VisitInlineeLines))971return Err;972973// Traverse global symbols.974LLVM_DEBUG({ W.getOStream() << "Traversing global symbols\n"; });975if (Pdb.hasPDBGlobalsStream()) {976Expected<GlobalsStream &> GlobalsOrErr = Pdb.getPDBGlobalsStream();977if (!GlobalsOrErr)978return GlobalsOrErr.takeError();979GlobalsStream &Globals = *GlobalsOrErr;980const GSIHashTable &Table = Globals.getGlobalsTable();981Expected<SymbolStream &> ExpectedSyms = Pdb.getPDBSymbolStream();982if (ExpectedSyms) {983984SymbolVisitorCallbackPipeline Pipeline;985SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);986LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr,987LogicalVisitor.getShared());988989// As the global symbols do not have an associated Compile Unit, create990// one, as the container for all global symbols.991RecordPrefix Prefix(SymbolKind::S_COMPILE3);992CVSymbol Symbol(&Prefix, sizeof(Prefix));993uint32_t Offset = 0;994if (Error Err = Traverser.visitSymbolBegin(Symbol, Offset))995consumeError(std::move(Err));996else {997// The CodeView compile unit containing the global symbols does not998// have a name; generate one using its parent name (object filename)999// follow by the '_global' string.1000std::string Name(CompileUnit->getParentScope()->getName());1001CompileUnit->setName(Name.append("_global"));10021003Pipeline.addCallbackToPipeline(Deserializer);1004Pipeline.addCallbackToPipeline(Traverser);1005CVSymbolVisitor Visitor(Pipeline);10061007BinaryStreamRef SymStream =1008ExpectedSyms->getSymbolArray().getUnderlyingStream();1009for (uint32_t PubSymOff : Table) {1010Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);1011if (Sym) {1012if (Error Err = Visitor.visitSymbolRecord(*Sym, PubSymOff))1013return createStringError(errorToErrorCode(std::move(Err)),1014getFileName());1015} else {1016consumeError(Sym.takeError());1017}1018}1019}10201021LogicalVisitor.closeScope();1022} else {1023consumeError(ExpectedSyms.takeError());1024}1025}10261027// Traverse symbols (DBI).1028LLVM_DEBUG({ W.getOStream() << "Traversing symbol groups\n"; });10291030auto VisitSymbolGroup = [&](uint32_t Modi, const SymbolGroup &SG) -> Error {1031Expected<ModuleDebugStreamRef> ExpectedModS =1032getModuleDebugStream(Pdb, Modi);1033if (ExpectedModS) {1034ModuleDebugStreamRef &ModS = *ExpectedModS;10351036LLVM_DEBUG({1037W.getOStream() << formatv("Traversing Group: Mod {0:4}\n", Modi);1038});10391040SymbolVisitorCallbackPipeline Pipeline;1041SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);1042LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr,1043LogicalVisitor.getShared());10441045Pipeline.addCallbackToPipeline(Deserializer);1046Pipeline.addCallbackToPipeline(Traverser);1047CVSymbolVisitor Visitor(Pipeline);1048BinarySubstreamRef SS = ModS.getSymbolsSubstream();1049if (Error Err =1050Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset))1051return createStringError(errorToErrorCode(std::move(Err)),1052getFileName());1053} else {1054// If the module stream does not exist, it is not an error condition.1055consumeError(ExpectedModS.takeError());1056}10571058return Error::success();1059};10601061if (Error Err = iterateSymbolGroups(Input, HeaderScope, VisitSymbolGroup))1062return Err;10631064// At this stage, the logical view contains all scopes, symbols and types.1065// For PDBs we can use the module id, to access its specific compile unit.1066// The line record addresses has been already resolved, so we can apply the1067// flow as when processing DWARF.10681069LLVM_DEBUG({ W.getOStream() << "Traversing lines\n"; });10701071// Record all line records for a Compile Unit.1072CULines.clear();10731074auto VisitDebugLines = [this](int32_t Modi, const SymbolGroup &SG,1075DebugLinesSubsectionRef &Lines) -> Error {1076if (!options().getPrintLines())1077return Error::success();10781079uint16_t Segment = Lines.header()->RelocSegment;1080uint32_t Begin = Lines.header()->RelocOffset;1081uint32_t Size = Lines.header()->CodeSize;10821083LLVM_DEBUG({ W.getOStream() << formatv("Modi = {0}\n", Modi); });10841085// We have line information for a new module; finish processing the1086// collected information for the current module. Once it is done, start1087// recording the line information for the new module.1088if (CurrentModule != Modi) {1089if (Error Err = processModule())1090return Err;1091CULines.clear();1092CurrentModule = Modi;1093}10941095for (const LineColumnEntry &Block : Lines)1096if (Error Err = createLines(Block.LineNumbers, /*Addendum=*/0, Segment,1097Begin, Size, Block.NameIndex, &SG))1098return Err;10991100return Error::success();1101};11021103if (Error Err = iterateModuleSubsections<DebugLinesSubsectionRef>(1104Input, HeaderScope, VisitDebugLines))1105return Err;11061107// Check if we have to close the Compile Unit scope.1108LogicalVisitor.closeScope();11091110// Process collected element lines.1111LogicalVisitor.processLines();11121113// Translate composite names into a single component.1114Root->transformScopedName();1115return Error::success();1116}11171118Error LVCodeViewReader::processModule() {1119if (LVScope *Scope = getScopeForModule(CurrentModule)) {1120CompileUnit = static_cast<LVScopeCompileUnit *>(Scope);11211122LLVM_DEBUG({ dbgs() << "Processing Scope: " << Scope->getName() << "\n"; });11231124// For the given compile unit, collect all scopes ranges.1125// For a complete ranges and lines mapping, the logical view support1126// needs for the compile unit to have a low and high pc values. We1127// can traverse the 'Modules' section and get the information for the1128// specific module. Another option, is from all the ranges collected1129// to take the first and last values.1130LVSectionIndex SectionIndex = DotTextSectionIndex;1131LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);1132ScopesWithRanges->clear();1133CompileUnit->getRanges(*ScopesWithRanges);1134if (!ScopesWithRanges->empty())1135CompileUnit->addObject(ScopesWithRanges->getLower(),1136ScopesWithRanges->getUpper());1137ScopesWithRanges->sort();11381139if (Error Err = createInstructions())1140return Err;11411142// Include lines from any inlined functions within the current function.1143includeInlineeLines(SectionIndex, Scope);11441145processLines(&CULines, SectionIndex, nullptr);1146}11471148return Error::success();1149}11501151// In order to create the scopes, the CodeView Reader will:1152// = Traverse the TPI/IPI stream (Type visitor):1153// Collect forward references, scoped names, type indexes that will represent1154// a logical element, strings, line records, linkage names.1155// = Traverse the symbols section (Symbol visitor):1156// Create the scopes tree and creates the required logical elements, by1157// using the collected indexes from the type visitor.1158Error LVCodeViewReader::createScopes() {1159LLVM_DEBUG({1160W.startLine() << "\n";1161W.printString("File", getFileName().str());1162W.printString("Exe", ExePath);1163W.printString("Format", FileFormatName);1164});11651166if (Error Err = LVReader::createScopes())1167return Err;11681169LogicalVisitor.setRoot(Root);11701171if (isObj()) {1172if (Error Err = createScopes(getObj()))1173return Err;1174} else {1175if (Error Err = createScopes(getPdb()))1176return Err;1177}11781179return Error::success();1180}11811182Error LVCodeViewReader::loadTargetInfo(const ObjectFile &Obj) {1183// Detect the architecture from the object file. We usually don't need OS1184// info to lookup a target and create register info.1185Triple TT;1186TT.setArch(Triple::ArchType(Obj.getArch()));1187TT.setVendor(Triple::UnknownVendor);1188TT.setOS(Triple::UnknownOS);11891190// Features to be passed to target/subtarget1191Expected<SubtargetFeatures> Features = Obj.getFeatures();1192SubtargetFeatures FeaturesValue;1193if (!Features) {1194consumeError(Features.takeError());1195FeaturesValue = SubtargetFeatures();1196}1197FeaturesValue = *Features;1198return loadGenericTargetInfo(TT.str(), FeaturesValue.getString());1199}12001201Error LVCodeViewReader::loadTargetInfo(const PDBFile &Pdb) {1202Triple TT;1203TT.setArch(Triple::ArchType::x86_64);1204TT.setVendor(Triple::UnknownVendor);1205TT.setOS(Triple::Win32);12061207StringRef TheFeature = "";12081209return loadGenericTargetInfo(TT.str(), TheFeature);1210}12111212std::string LVCodeViewReader::getRegisterName(LVSmall Opcode,1213ArrayRef<uint64_t> Operands) {1214// Get Compilation Unit CPU Type.1215CPUType CPU = getCompileUnitCPUType();1216// For CodeView the register always is in Operands[0];1217RegisterId Register = (RegisterId(Operands[0]));1218return formatRegisterId(Register, CPU);1219}122012211222