Path: blob/main/contrib/llvm-project/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp
35232 views
//===- CodeViewYAMLDebugSections.cpp - CodeView YAMLIO debug sections -----===//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 file defines classes for handling the YAML representation of CodeView9// Debug Info.10//11//===----------------------------------------------------------------------===//1213#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/StringExtras.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/BinaryFormat/COFF.h"18#include "llvm/DebugInfo/CodeView/CodeView.h"19#include "llvm/DebugInfo/CodeView/CodeViewError.h"20#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"21#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"22#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"23#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"24#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"25#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"26#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"27#include "llvm/DebugInfo/CodeView/DebugSubsection.h"28#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"29#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"30#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"31#include "llvm/DebugInfo/CodeView/Line.h"32#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"33#include "llvm/DebugInfo/CodeView/TypeIndex.h"34#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"35#include "llvm/Support/Allocator.h"36#include "llvm/Support/BinaryStreamReader.h"37#include "llvm/Support/Endian.h"38#include "llvm/Support/Error.h"39#include "llvm/Support/ErrorHandling.h"40#include "llvm/Support/YAMLTraits.h"41#include "llvm/Support/raw_ostream.h"42#include <algorithm>43#include <cassert>44#include <cstdint>45#include <memory>46#include <string>47#include <tuple>48#include <vector>4950using namespace llvm;51using namespace llvm::codeview;52using namespace llvm::CodeViewYAML;53using namespace llvm::CodeViewYAML::detail;54using namespace llvm::yaml;5556LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry)57LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry)58LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry)59LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock)60LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo)61LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite)62LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo)63LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport)64LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport)65LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData)6667LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, QuotingType::None)68LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind)69LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind)70LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags)7172LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport)73LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData)74LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport)75LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem)76LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry)77LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry)78LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry)79LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock)80LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite)8182namespace llvm {83namespace CodeViewYAML {84namespace detail {8586struct YAMLSubsectionBase {87explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {}88virtual ~YAMLSubsectionBase() = default;8990virtual void map(IO &IO) = 0;91virtual std::shared_ptr<DebugSubsection>92toCodeViewSubsection(BumpPtrAllocator &Allocator,93const codeview::StringsAndChecksums &SC) const = 0;9495DebugSubsectionKind Kind;96};9798} // end namespace detail99} // end namespace CodeViewYAML100} // end namespace llvm101102namespace {103104struct YAMLChecksumsSubsection : public YAMLSubsectionBase {105YAMLChecksumsSubsection()106: YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {}107108void map(IO &IO) override;109std::shared_ptr<DebugSubsection>110toCodeViewSubsection(BumpPtrAllocator &Allocator,111const codeview::StringsAndChecksums &SC) const override;112static Expected<std::shared_ptr<YAMLChecksumsSubsection>>113fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,114const DebugChecksumsSubsectionRef &FC);115116std::vector<SourceFileChecksumEntry> Checksums;117};118119struct YAMLLinesSubsection : public YAMLSubsectionBase {120YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {}121122void map(IO &IO) override;123std::shared_ptr<DebugSubsection>124toCodeViewSubsection(BumpPtrAllocator &Allocator,125const codeview::StringsAndChecksums &SC) const override;126static Expected<std::shared_ptr<YAMLLinesSubsection>>127fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,128const DebugChecksumsSubsectionRef &Checksums,129const DebugLinesSubsectionRef &Lines);130131SourceLineInfo Lines;132};133134struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {135YAMLInlineeLinesSubsection()136: YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {}137138void map(IO &IO) override;139std::shared_ptr<DebugSubsection>140toCodeViewSubsection(BumpPtrAllocator &Allocator,141const codeview::StringsAndChecksums &SC) const override;142static Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>143fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,144const DebugChecksumsSubsectionRef &Checksums,145const DebugInlineeLinesSubsectionRef &Lines);146147InlineeInfo InlineeLines;148};149150struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {151YAMLCrossModuleExportsSubsection()152: YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports) {}153154void map(IO &IO) override;155std::shared_ptr<DebugSubsection>156toCodeViewSubsection(BumpPtrAllocator &Allocator,157const codeview::StringsAndChecksums &SC) const override;158static Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>159fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef &Exports);160161std::vector<CrossModuleExport> Exports;162};163164struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {165YAMLCrossModuleImportsSubsection()166: YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports) {}167168void map(IO &IO) override;169std::shared_ptr<DebugSubsection>170toCodeViewSubsection(BumpPtrAllocator &Allocator,171const codeview::StringsAndChecksums &SC) const override;172static Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>173fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,174const DebugCrossModuleImportsSubsectionRef &Imports);175176std::vector<YAMLCrossModuleImport> Imports;177};178179struct YAMLSymbolsSubsection : public YAMLSubsectionBase {180YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols) {}181182void map(IO &IO) override;183std::shared_ptr<DebugSubsection>184toCodeViewSubsection(BumpPtrAllocator &Allocator,185const codeview::StringsAndChecksums &SC) const override;186static Expected<std::shared_ptr<YAMLSymbolsSubsection>>187fromCodeViewSubsection(const DebugSymbolsSubsectionRef &Symbols);188189std::vector<CodeViewYAML::SymbolRecord> Symbols;190};191192struct YAMLStringTableSubsection : public YAMLSubsectionBase {193YAMLStringTableSubsection()194: YAMLSubsectionBase(DebugSubsectionKind::StringTable) {}195196void map(IO &IO) override;197std::shared_ptr<DebugSubsection>198toCodeViewSubsection(BumpPtrAllocator &Allocator,199const codeview::StringsAndChecksums &SC) const override;200static Expected<std::shared_ptr<YAMLStringTableSubsection>>201fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings);202203std::vector<StringRef> Strings;204};205206struct YAMLFrameDataSubsection : public YAMLSubsectionBase {207YAMLFrameDataSubsection()208: YAMLSubsectionBase(DebugSubsectionKind::FrameData) {}209210void map(IO &IO) override;211std::shared_ptr<DebugSubsection>212toCodeViewSubsection(BumpPtrAllocator &Allocator,213const codeview::StringsAndChecksums &SC) const override;214static Expected<std::shared_ptr<YAMLFrameDataSubsection>>215fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,216const DebugFrameDataSubsectionRef &Frames);217218std::vector<YAMLFrameData> Frames;219};220221struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {222YAMLCoffSymbolRVASubsection()223: YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA) {}224225void map(IO &IO) override;226std::shared_ptr<DebugSubsection>227toCodeViewSubsection(BumpPtrAllocator &Allocator,228const codeview::StringsAndChecksums &SC) const override;229static Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>230fromCodeViewSubsection(const DebugSymbolRVASubsectionRef &RVAs);231232std::vector<uint32_t> RVAs;233};234235} // end anonymous namespace236237void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {238io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);239io.enumFallback<Hex16>(Flags);240}241242void ScalarEnumerationTraits<FileChecksumKind>::enumeration(243IO &io, FileChecksumKind &Kind) {244io.enumCase(Kind, "None", FileChecksumKind::None);245io.enumCase(Kind, "MD5", FileChecksumKind::MD5);246io.enumCase(Kind, "SHA1", FileChecksumKind::SHA1);247io.enumCase(Kind, "SHA256", FileChecksumKind::SHA256);248}249250void ScalarTraits<HexFormattedString>::output(const HexFormattedString &Value,251void *ctx, raw_ostream &Out) {252StringRef Bytes(reinterpret_cast<const char *>(Value.Bytes.data()),253Value.Bytes.size());254Out << toHex(Bytes);255}256257StringRef ScalarTraits<HexFormattedString>::input(StringRef Scalar, void *ctxt,258HexFormattedString &Value) {259std::string H = fromHex(Scalar);260Value.Bytes.assign(H.begin(), H.end());261return StringRef();262}263264void MappingTraits<SourceLineEntry>::mapping(IO &IO, SourceLineEntry &Obj) {265IO.mapRequired("Offset", Obj.Offset);266IO.mapRequired("LineStart", Obj.LineStart);267IO.mapRequired("IsStatement", Obj.IsStatement);268IO.mapRequired("EndDelta", Obj.EndDelta);269}270271void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {272IO.mapRequired("StartColumn", Obj.StartColumn);273IO.mapRequired("EndColumn", Obj.EndColumn);274}275276void MappingTraits<SourceLineBlock>::mapping(IO &IO, SourceLineBlock &Obj) {277IO.mapRequired("FileName", Obj.FileName);278IO.mapRequired("Lines", Obj.Lines);279IO.mapRequired("Columns", Obj.Columns);280}281282void MappingTraits<CrossModuleExport>::mapping(IO &IO, CrossModuleExport &Obj) {283IO.mapRequired("LocalId", Obj.Local);284IO.mapRequired("GlobalId", Obj.Global);285}286287void MappingTraits<YAMLCrossModuleImport>::mapping(IO &IO,288YAMLCrossModuleImport &Obj) {289IO.mapRequired("Module", Obj.ModuleName);290IO.mapRequired("Imports", Obj.ImportIds);291}292293void MappingTraits<SourceFileChecksumEntry>::mapping(294IO &IO, SourceFileChecksumEntry &Obj) {295IO.mapRequired("FileName", Obj.FileName);296IO.mapRequired("Kind", Obj.Kind);297IO.mapRequired("Checksum", Obj.ChecksumBytes);298}299300void MappingTraits<InlineeSite>::mapping(IO &IO, InlineeSite &Obj) {301IO.mapRequired("FileName", Obj.FileName);302IO.mapRequired("LineNum", Obj.SourceLineNum);303IO.mapRequired("Inlinee", Obj.Inlinee);304IO.mapOptional("ExtraFiles", Obj.ExtraFiles);305}306307void MappingTraits<YAMLFrameData>::mapping(IO &IO, YAMLFrameData &Obj) {308IO.mapRequired("CodeSize", Obj.CodeSize);309IO.mapRequired("FrameFunc", Obj.FrameFunc);310IO.mapRequired("LocalSize", Obj.LocalSize);311IO.mapOptional("MaxStackSize", Obj.MaxStackSize);312IO.mapOptional("ParamsSize", Obj.ParamsSize);313IO.mapOptional("PrologSize", Obj.PrologSize);314IO.mapOptional("RvaStart", Obj.RvaStart);315IO.mapOptional("SavedRegsSize", Obj.SavedRegsSize);316}317318void YAMLChecksumsSubsection::map(IO &IO) {319IO.mapTag("!FileChecksums", true);320IO.mapRequired("Checksums", Checksums);321}322323void YAMLLinesSubsection::map(IO &IO) {324IO.mapTag("!Lines", true);325IO.mapRequired("CodeSize", Lines.CodeSize);326327IO.mapRequired("Flags", Lines.Flags);328IO.mapRequired("RelocOffset", Lines.RelocOffset);329IO.mapRequired("RelocSegment", Lines.RelocSegment);330IO.mapRequired("Blocks", Lines.Blocks);331}332333void YAMLInlineeLinesSubsection::map(IO &IO) {334IO.mapTag("!InlineeLines", true);335IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);336IO.mapRequired("Sites", InlineeLines.Sites);337}338339void YAMLCrossModuleExportsSubsection::map(IO &IO) {340IO.mapTag("!CrossModuleExports", true);341IO.mapOptional("Exports", Exports);342}343344void YAMLCrossModuleImportsSubsection::map(IO &IO) {345IO.mapTag("!CrossModuleImports", true);346IO.mapOptional("Imports", Imports);347}348349void YAMLSymbolsSubsection::map(IO &IO) {350IO.mapTag("!Symbols", true);351IO.mapRequired("Records", Symbols);352}353354void YAMLStringTableSubsection::map(IO &IO) {355IO.mapTag("!StringTable", true);356IO.mapRequired("Strings", Strings);357}358359void YAMLFrameDataSubsection::map(IO &IO) {360IO.mapTag("!FrameData", true);361IO.mapRequired("Frames", Frames);362}363364void YAMLCoffSymbolRVASubsection::map(IO &IO) {365IO.mapTag("!COFFSymbolRVAs", true);366IO.mapRequired("RVAs", RVAs);367}368369void MappingTraits<YAMLDebugSubsection>::mapping(370IO &IO, YAMLDebugSubsection &Subsection) {371if (!IO.outputting()) {372if (IO.mapTag("!FileChecksums")) {373auto SS = std::make_shared<YAMLChecksumsSubsection>();374Subsection.Subsection = SS;375} else if (IO.mapTag("!Lines")) {376Subsection.Subsection = std::make_shared<YAMLLinesSubsection>();377} else if (IO.mapTag("!InlineeLines")) {378Subsection.Subsection = std::make_shared<YAMLInlineeLinesSubsection>();379} else if (IO.mapTag("!CrossModuleExports")) {380Subsection.Subsection =381std::make_shared<YAMLCrossModuleExportsSubsection>();382} else if (IO.mapTag("!CrossModuleImports")) {383Subsection.Subsection =384std::make_shared<YAMLCrossModuleImportsSubsection>();385} else if (IO.mapTag("!Symbols")) {386Subsection.Subsection = std::make_shared<YAMLSymbolsSubsection>();387} else if (IO.mapTag("!StringTable")) {388Subsection.Subsection = std::make_shared<YAMLStringTableSubsection>();389} else if (IO.mapTag("!FrameData")) {390Subsection.Subsection = std::make_shared<YAMLFrameDataSubsection>();391} else if (IO.mapTag("!COFFSymbolRVAs")) {392Subsection.Subsection = std::make_shared<YAMLCoffSymbolRVASubsection>();393} else {394llvm_unreachable("Unexpected subsection tag!");395}396}397Subsection.Subsection->map(IO);398}399400std::shared_ptr<DebugSubsection> YAMLChecksumsSubsection::toCodeViewSubsection(401BumpPtrAllocator &Allocator,402const codeview::StringsAndChecksums &SC) const {403assert(SC.hasStrings());404auto Result = std::make_shared<DebugChecksumsSubsection>(*SC.strings());405for (const auto &CS : Checksums) {406Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes);407}408return Result;409}410411std::shared_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(412BumpPtrAllocator &Allocator,413const codeview::StringsAndChecksums &SC) const {414assert(SC.hasStrings() && SC.hasChecksums());415auto Result =416std::make_shared<DebugLinesSubsection>(*SC.checksums(), *SC.strings());417Result->setCodeSize(Lines.CodeSize);418Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset);419Result->setFlags(Lines.Flags);420for (const auto &LC : Lines.Blocks) {421Result->createBlock(LC.FileName);422if (Result->hasColumnInfo()) {423for (auto Item : zip(LC.Lines, LC.Columns)) {424auto &L = std::get<0>(Item);425auto &C = std::get<1>(Item);426uint32_t LE = L.LineStart + L.EndDelta;427Result->addLineAndColumnInfo(L.Offset,428LineInfo(L.LineStart, LE, L.IsStatement),429C.StartColumn, C.EndColumn);430}431} else {432for (const auto &L : LC.Lines) {433uint32_t LE = L.LineStart + L.EndDelta;434Result->addLineInfo(L.Offset, LineInfo(L.LineStart, LE, L.IsStatement));435}436}437}438return Result;439}440441std::shared_ptr<DebugSubsection>442YAMLInlineeLinesSubsection::toCodeViewSubsection(443BumpPtrAllocator &Allocator,444const codeview::StringsAndChecksums &SC) const {445assert(SC.hasChecksums());446auto Result = std::make_shared<DebugInlineeLinesSubsection>(447*SC.checksums(), InlineeLines.HasExtraFiles);448449for (const auto &Site : InlineeLines.Sites) {450Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,451Site.SourceLineNum);452if (!InlineeLines.HasExtraFiles)453continue;454455for (auto EF : Site.ExtraFiles) {456Result->addExtraFile(EF);457}458}459return Result;460}461462std::shared_ptr<DebugSubsection>463YAMLCrossModuleExportsSubsection::toCodeViewSubsection(464BumpPtrAllocator &Allocator,465const codeview::StringsAndChecksums &SC) const {466auto Result = std::make_shared<DebugCrossModuleExportsSubsection>();467for (const auto &M : Exports)468Result->addMapping(M.Local, M.Global);469return Result;470}471472std::shared_ptr<DebugSubsection>473YAMLCrossModuleImportsSubsection::toCodeViewSubsection(474BumpPtrAllocator &Allocator,475const codeview::StringsAndChecksums &SC) const {476assert(SC.hasStrings());477478auto Result =479std::make_shared<DebugCrossModuleImportsSubsection>(*SC.strings());480for (const auto &M : Imports) {481for (const auto Id : M.ImportIds)482Result->addImport(M.ModuleName, Id);483}484return Result;485}486487std::shared_ptr<DebugSubsection> YAMLSymbolsSubsection::toCodeViewSubsection(488BumpPtrAllocator &Allocator,489const codeview::StringsAndChecksums &SC) const {490auto Result = std::make_shared<DebugSymbolsSubsection>();491for (const auto &Sym : Symbols)492Result->addSymbol(493Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile));494return Result;495}496497std::shared_ptr<DebugSubsection>498YAMLStringTableSubsection::toCodeViewSubsection(499BumpPtrAllocator &Allocator,500const codeview::StringsAndChecksums &SC) const {501auto Result = std::make_shared<DebugStringTableSubsection>();502for (const auto &Str : this->Strings)503Result->insert(Str);504return Result;505}506507std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(508BumpPtrAllocator &Allocator,509const codeview::StringsAndChecksums &SC) const {510assert(SC.hasStrings());511512auto Result = std::make_shared<DebugFrameDataSubsection>(true);513for (const auto &YF : Frames) {514codeview::FrameData F;515F.CodeSize = YF.CodeSize;516F.Flags = YF.Flags;517F.LocalSize = YF.LocalSize;518F.MaxStackSize = YF.MaxStackSize;519F.ParamsSize = YF.ParamsSize;520F.PrologSize = YF.PrologSize;521F.RvaStart = YF.RvaStart;522F.SavedRegsSize = YF.SavedRegsSize;523F.FrameFunc = SC.strings()->insert(YF.FrameFunc);524Result->addFrameData(F);525}526return Result;527}528529std::shared_ptr<DebugSubsection>530YAMLCoffSymbolRVASubsection::toCodeViewSubsection(531BumpPtrAllocator &Allocator,532const codeview::StringsAndChecksums &SC) const {533auto Result = std::make_shared<DebugSymbolRVASubsection>();534for (const auto &RVA : RVAs)535Result->addRVA(RVA);536return Result;537}538539static Expected<SourceFileChecksumEntry>540convertOneChecksum(const DebugStringTableSubsectionRef &Strings,541const FileChecksumEntry &CS) {542auto ExpectedString = Strings.getString(CS.FileNameOffset);543if (!ExpectedString)544return ExpectedString.takeError();545546SourceFileChecksumEntry Result;547Result.ChecksumBytes.Bytes = CS.Checksum;548Result.Kind = CS.Kind;549Result.FileName = *ExpectedString;550return Result;551}552553static Expected<StringRef>554getFileName(const DebugStringTableSubsectionRef &Strings,555const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {556auto Iter = Checksums.getArray().at(FileID);557if (Iter == Checksums.getArray().end())558return make_error<CodeViewError>(cv_error_code::no_records);559uint32_t Offset = Iter->FileNameOffset;560return Strings.getString(Offset);561}562563Expected<std::shared_ptr<YAMLChecksumsSubsection>>564YAMLChecksumsSubsection::fromCodeViewSubsection(565const DebugStringTableSubsectionRef &Strings,566const DebugChecksumsSubsectionRef &FC) {567auto Result = std::make_shared<YAMLChecksumsSubsection>();568569for (const auto &CS : FC) {570auto ConvertedCS = convertOneChecksum(Strings, CS);571if (!ConvertedCS)572return ConvertedCS.takeError();573Result->Checksums.push_back(*ConvertedCS);574}575return Result;576}577578Expected<std::shared_ptr<YAMLLinesSubsection>>579YAMLLinesSubsection::fromCodeViewSubsection(580const DebugStringTableSubsectionRef &Strings,581const DebugChecksumsSubsectionRef &Checksums,582const DebugLinesSubsectionRef &Lines) {583auto Result = std::make_shared<YAMLLinesSubsection>();584Result->Lines.CodeSize = Lines.header()->CodeSize;585Result->Lines.RelocOffset = Lines.header()->RelocOffset;586Result->Lines.RelocSegment = Lines.header()->RelocSegment;587Result->Lines.Flags = static_cast<LineFlags>(uint16_t(Lines.header()->Flags));588for (const auto &L : Lines) {589SourceLineBlock Block;590auto EF = getFileName(Strings, Checksums, L.NameIndex);591if (!EF)592return EF.takeError();593Block.FileName = *EF;594if (Lines.hasColumnInfo()) {595for (const auto &C : L.Columns) {596SourceColumnEntry SCE;597SCE.EndColumn = C.EndColumn;598SCE.StartColumn = C.StartColumn;599Block.Columns.push_back(SCE);600}601}602for (const auto &LN : L.LineNumbers) {603SourceLineEntry SLE;604LineInfo LI(LN.Flags);605SLE.Offset = LN.Offset;606SLE.LineStart = LI.getStartLine();607SLE.EndDelta = LI.getLineDelta();608SLE.IsStatement = LI.isStatement();609Block.Lines.push_back(SLE);610}611Result->Lines.Blocks.push_back(Block);612}613return Result;614}615616Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>617YAMLInlineeLinesSubsection::fromCodeViewSubsection(618const DebugStringTableSubsectionRef &Strings,619const DebugChecksumsSubsectionRef &Checksums,620const DebugInlineeLinesSubsectionRef &Lines) {621auto Result = std::make_shared<YAMLInlineeLinesSubsection>();622623Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles();624for (const auto &IL : Lines) {625InlineeSite Site;626auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID);627if (!ExpF)628return ExpF.takeError();629Site.FileName = *ExpF;630Site.Inlinee = IL.Header->Inlinee.getIndex();631Site.SourceLineNum = IL.Header->SourceLineNum;632if (Lines.hasExtraFiles()) {633for (const auto EF : IL.ExtraFiles) {634auto ExpF2 = getFileName(Strings, Checksums, EF);635if (!ExpF2)636return ExpF2.takeError();637Site.ExtraFiles.push_back(*ExpF2);638}639}640Result->InlineeLines.Sites.push_back(Site);641}642return Result;643}644645Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>646YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(647const DebugCrossModuleExportsSubsectionRef &Exports) {648auto Result = std::make_shared<YAMLCrossModuleExportsSubsection>();649Result->Exports.assign(Exports.begin(), Exports.end());650return Result;651}652653Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>654YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(655const DebugStringTableSubsectionRef &Strings,656const DebugCrossModuleImportsSubsectionRef &Imports) {657auto Result = std::make_shared<YAMLCrossModuleImportsSubsection>();658for (const auto &CMI : Imports) {659YAMLCrossModuleImport YCMI;660auto ExpectedStr = Strings.getString(CMI.Header->ModuleNameOffset);661if (!ExpectedStr)662return ExpectedStr.takeError();663YCMI.ModuleName = *ExpectedStr;664YCMI.ImportIds.assign(CMI.Imports.begin(), CMI.Imports.end());665Result->Imports.push_back(YCMI);666}667return Result;668}669670Expected<std::shared_ptr<YAMLSymbolsSubsection>>671YAMLSymbolsSubsection::fromCodeViewSubsection(672const DebugSymbolsSubsectionRef &Symbols) {673auto Result = std::make_shared<YAMLSymbolsSubsection>();674for (const auto &Sym : Symbols) {675auto S = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym);676if (!S)677return joinErrors(make_error<CodeViewError>(678cv_error_code::corrupt_record,679"Invalid CodeView Symbol Record in SymbolRecord "680"subsection of .debug$S while converting to YAML!"),681S.takeError());682683Result->Symbols.push_back(*S);684}685return Result;686}687688Expected<std::shared_ptr<YAMLStringTableSubsection>>689YAMLStringTableSubsection::fromCodeViewSubsection(690const DebugStringTableSubsectionRef &Strings) {691auto Result = std::make_shared<YAMLStringTableSubsection>();692BinaryStreamReader Reader(Strings.getBuffer());693StringRef S;694// First item is a single null string, skip it.695if (auto EC = Reader.readCString(S))696return std::move(EC);697assert(S.empty());698while (Reader.bytesRemaining() > 0) {699if (auto EC = Reader.readCString(S))700return std::move(EC);701Result->Strings.push_back(S);702}703return Result;704}705706Expected<std::shared_ptr<YAMLFrameDataSubsection>>707YAMLFrameDataSubsection::fromCodeViewSubsection(708const DebugStringTableSubsectionRef &Strings,709const DebugFrameDataSubsectionRef &Frames) {710auto Result = std::make_shared<YAMLFrameDataSubsection>();711for (const auto &F : Frames) {712YAMLFrameData YF;713YF.CodeSize = F.CodeSize;714YF.Flags = F.Flags;715YF.LocalSize = F.LocalSize;716YF.MaxStackSize = F.MaxStackSize;717YF.ParamsSize = F.ParamsSize;718YF.PrologSize = F.PrologSize;719YF.RvaStart = F.RvaStart;720YF.SavedRegsSize = F.SavedRegsSize;721722auto ES = Strings.getString(F.FrameFunc);723if (!ES)724return joinErrors(725make_error<CodeViewError>(726cv_error_code::no_records,727"Could not find string for string id while mapping FrameData!"),728ES.takeError());729YF.FrameFunc = *ES;730Result->Frames.push_back(YF);731}732return Result;733}734735Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>736YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(737const DebugSymbolRVASubsectionRef &Section) {738auto Result = std::make_shared<YAMLCoffSymbolRVASubsection>();739for (const auto &RVA : Section) {740Result->RVAs.push_back(RVA);741}742return Result;743}744745Expected<std::vector<std::shared_ptr<DebugSubsection>>>746llvm::CodeViewYAML::toCodeViewSubsectionList(747BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,748const codeview::StringsAndChecksums &SC) {749std::vector<std::shared_ptr<DebugSubsection>> Result;750if (Subsections.empty())751return std::move(Result);752753for (const auto &SS : Subsections) {754std::shared_ptr<DebugSubsection> CVS;755CVS = SS.Subsection->toCodeViewSubsection(Allocator, SC);756assert(CVS != nullptr);757Result.push_back(std::move(CVS));758}759return std::move(Result);760}761762namespace {763764struct SubsectionConversionVisitor : public DebugSubsectionVisitor {765SubsectionConversionVisitor() = default;766767Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override;768Error visitLines(DebugLinesSubsectionRef &Lines,769const StringsAndChecksumsRef &State) override;770Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,771const StringsAndChecksumsRef &State) override;772Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,773const StringsAndChecksumsRef &State) override;774Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &Checksums,775const StringsAndChecksumsRef &State) override;776Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &Inlinees,777const StringsAndChecksumsRef &State) override;778Error visitStringTable(DebugStringTableSubsectionRef &ST,779const StringsAndChecksumsRef &State) override;780Error visitSymbols(DebugSymbolsSubsectionRef &Symbols,781const StringsAndChecksumsRef &State) override;782Error visitFrameData(DebugFrameDataSubsectionRef &Symbols,783const StringsAndChecksumsRef &State) override;784Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &Symbols,785const StringsAndChecksumsRef &State) override;786787YAMLDebugSubsection Subsection;788};789790} // end anonymous namespace791792Error SubsectionConversionVisitor::visitUnknown(793DebugUnknownSubsectionRef &Unknown) {794return make_error<CodeViewError>(cv_error_code::operation_unsupported);795}796797Error SubsectionConversionVisitor::visitLines(798DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {799auto Result = YAMLLinesSubsection::fromCodeViewSubsection(800State.strings(), State.checksums(), Lines);801if (!Result)802return Result.takeError();803Subsection.Subsection = *Result;804return Error::success();805}806807Error SubsectionConversionVisitor::visitFileChecksums(808DebugChecksumsSubsectionRef &Checksums,809const StringsAndChecksumsRef &State) {810auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),811Checksums);812if (!Result)813return Result.takeError();814Subsection.Subsection = *Result;815return Error::success();816}817818Error SubsectionConversionVisitor::visitInlineeLines(819DebugInlineeLinesSubsectionRef &Inlinees,820const StringsAndChecksumsRef &State) {821auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(822State.strings(), State.checksums(), Inlinees);823if (!Result)824return Result.takeError();825Subsection.Subsection = *Result;826return Error::success();827}828829Error SubsectionConversionVisitor::visitCrossModuleExports(830DebugCrossModuleExportsSubsectionRef &Exports,831const StringsAndChecksumsRef &State) {832auto Result =833YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);834if (!Result)835return Result.takeError();836Subsection.Subsection = *Result;837return Error::success();838}839840Error SubsectionConversionVisitor::visitCrossModuleImports(841DebugCrossModuleImportsSubsectionRef &Imports,842const StringsAndChecksumsRef &State) {843auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(844State.strings(), Imports);845if (!Result)846return Result.takeError();847Subsection.Subsection = *Result;848return Error::success();849}850851Error SubsectionConversionVisitor::visitStringTable(852DebugStringTableSubsectionRef &Strings,853const StringsAndChecksumsRef &State) {854auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);855if (!Result)856return Result.takeError();857Subsection.Subsection = *Result;858return Error::success();859}860861Error SubsectionConversionVisitor::visitSymbols(862DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {863auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);864if (!Result)865return Result.takeError();866Subsection.Subsection = *Result;867return Error::success();868}869870Error SubsectionConversionVisitor::visitFrameData(871DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {872auto Result =873YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);874if (!Result)875return Result.takeError();876Subsection.Subsection = *Result;877return Error::success();878}879880Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(881DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) {882auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);883if (!Result)884return Result.takeError();885Subsection.Subsection = *Result;886return Error::success();887}888889Expected<YAMLDebugSubsection>890YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef &SC,891const DebugSubsectionRecord &SS) {892SubsectionConversionVisitor V;893if (auto EC = visitDebugSubsection(SS, V, SC))894return std::move(EC);895896return V.Subsection;897}898899std::vector<YAMLDebugSubsection>900llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,901const StringsAndChecksumsRef &SC) {902BinaryStreamReader Reader(Data, llvm::endianness::little);903uint32_t Magic;904905ExitOnError Err("Invalid .debug$S section!");906Err(Reader.readInteger(Magic));907assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");908909DebugSubsectionArray Subsections;910Err(Reader.readArray(Subsections, Reader.bytesRemaining()));911912std::vector<YAMLDebugSubsection> Result;913914for (const auto &SS : Subsections) {915auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));916Result.push_back(YamlSS);917}918return Result;919}920921void llvm::CodeViewYAML::initializeStringsAndChecksums(922ArrayRef<YAMLDebugSubsection> Sections, codeview::StringsAndChecksums &SC) {923// String Table and Checksums subsections don't use the allocator.924BumpPtrAllocator Allocator;925926// It's possible for checksums and strings to even appear in different debug$S927// sections, so we have to make this a stateful function that can build up928// the strings and checksums field over multiple iterations.929930// File Checksums require the string table, but may become before it, so we931// have to scan for strings first, then scan for checksums again from the932// beginning.933if (!SC.hasStrings()) {934for (const auto &SS : Sections) {935if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)936continue;937938auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);939SC.setStrings(940std::static_pointer_cast<DebugStringTableSubsection>(Result));941break;942}943}944945if (SC.hasStrings() && !SC.hasChecksums()) {946for (const auto &SS : Sections) {947if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)948continue;949950auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);951SC.setChecksums(952std::static_pointer_cast<DebugChecksumsSubsection>(Result));953break;954}955}956}957958959