954 lines · cpp
1//===- CodeViewYAMLDebugSections.cpp - CodeView YAMLIO debug sections -----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines classes for handling the YAML representation of CodeView10// Debug Info.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"15#include "llvm/ADT/STLExtras.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/BinaryFormat/COFF.h"19#include "llvm/DebugInfo/CodeView/CodeView.h"20#include "llvm/DebugInfo/CodeView/CodeViewError.h"21#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"22#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"23#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"24#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"25#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"26#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"27#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"28#include "llvm/DebugInfo/CodeView/DebugSubsection.h"29#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"30#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"31#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"32#include "llvm/DebugInfo/CodeView/Line.h"33#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"34#include "llvm/DebugInfo/CodeView/TypeIndex.h"35#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"36#include "llvm/Support/Allocator.h"37#include "llvm/Support/BinaryStreamReader.h"38#include "llvm/Support/Endian.h"39#include "llvm/Support/Error.h"40#include "llvm/Support/ErrorHandling.h"41#include "llvm/Support/YAMLTraits.h"42#include "llvm/Support/raw_ostream.h"43#include <cassert>44#include <cstdint>45#include <memory>46#include <string>47#include <vector>48 49using namespace llvm;50using namespace llvm::codeview;51using namespace llvm::CodeViewYAML;52using namespace llvm::CodeViewYAML::detail;53using namespace llvm::yaml;54 55LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry)56LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry)57LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry)58LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock)59LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo)60LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite)61LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo)62LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport)63LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport)64LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData)65 66LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, QuotingType::None)67LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind)68LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind)69LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags)70 71LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport)72LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData)73LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport)74LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem)75LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry)76LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry)77LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry)78LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock)79LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite)80 81namespace llvm {82namespace CodeViewYAML {83namespace detail {84 85struct YAMLSubsectionBase {86 explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {}87 virtual ~YAMLSubsectionBase() = default;88 89 virtual void map(IO &IO) = 0;90 virtual std::shared_ptr<DebugSubsection>91 toCodeViewSubsection(BumpPtrAllocator &Allocator,92 const codeview::StringsAndChecksums &SC) const = 0;93 94 DebugSubsectionKind Kind;95};96 97} // end namespace detail98} // end namespace CodeViewYAML99} // end namespace llvm100 101namespace {102 103struct YAMLChecksumsSubsection : public YAMLSubsectionBase {104 YAMLChecksumsSubsection()105 : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {}106 107 void map(IO &IO) override;108 std::shared_ptr<DebugSubsection>109 toCodeViewSubsection(BumpPtrAllocator &Allocator,110 const codeview::StringsAndChecksums &SC) const override;111 static Expected<std::shared_ptr<YAMLChecksumsSubsection>>112 fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,113 const DebugChecksumsSubsectionRef &FC);114 115 std::vector<SourceFileChecksumEntry> Checksums;116};117 118struct YAMLLinesSubsection : public YAMLSubsectionBase {119 YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {}120 121 void map(IO &IO) override;122 std::shared_ptr<DebugSubsection>123 toCodeViewSubsection(BumpPtrAllocator &Allocator,124 const codeview::StringsAndChecksums &SC) const override;125 static Expected<std::shared_ptr<YAMLLinesSubsection>>126 fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,127 const DebugChecksumsSubsectionRef &Checksums,128 const DebugLinesSubsectionRef &Lines);129 130 SourceLineInfo Lines;131};132 133struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {134 YAMLInlineeLinesSubsection()135 : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {}136 137 void map(IO &IO) override;138 std::shared_ptr<DebugSubsection>139 toCodeViewSubsection(BumpPtrAllocator &Allocator,140 const codeview::StringsAndChecksums &SC) const override;141 static Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>142 fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,143 const DebugChecksumsSubsectionRef &Checksums,144 const DebugInlineeLinesSubsectionRef &Lines);145 146 InlineeInfo InlineeLines;147};148 149struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {150 YAMLCrossModuleExportsSubsection()151 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports) {}152 153 void map(IO &IO) override;154 std::shared_ptr<DebugSubsection>155 toCodeViewSubsection(BumpPtrAllocator &Allocator,156 const codeview::StringsAndChecksums &SC) const override;157 static Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>158 fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef &Exports);159 160 std::vector<CrossModuleExport> Exports;161};162 163struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {164 YAMLCrossModuleImportsSubsection()165 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports) {}166 167 void map(IO &IO) override;168 std::shared_ptr<DebugSubsection>169 toCodeViewSubsection(BumpPtrAllocator &Allocator,170 const codeview::StringsAndChecksums &SC) const override;171 static Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>172 fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,173 const DebugCrossModuleImportsSubsectionRef &Imports);174 175 std::vector<YAMLCrossModuleImport> Imports;176};177 178struct YAMLSymbolsSubsection : public YAMLSubsectionBase {179 YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols) {}180 181 void map(IO &IO) override;182 std::shared_ptr<DebugSubsection>183 toCodeViewSubsection(BumpPtrAllocator &Allocator,184 const codeview::StringsAndChecksums &SC) const override;185 static Expected<std::shared_ptr<YAMLSymbolsSubsection>>186 fromCodeViewSubsection(const DebugSymbolsSubsectionRef &Symbols);187 188 std::vector<CodeViewYAML::SymbolRecord> Symbols;189};190 191struct YAMLStringTableSubsection : public YAMLSubsectionBase {192 YAMLStringTableSubsection()193 : YAMLSubsectionBase(DebugSubsectionKind::StringTable) {}194 195 void map(IO &IO) override;196 std::shared_ptr<DebugSubsection>197 toCodeViewSubsection(BumpPtrAllocator &Allocator,198 const codeview::StringsAndChecksums &SC) const override;199 static Expected<std::shared_ptr<YAMLStringTableSubsection>>200 fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings);201 202 std::vector<StringRef> Strings;203};204 205struct YAMLFrameDataSubsection : public YAMLSubsectionBase {206 YAMLFrameDataSubsection()207 : YAMLSubsectionBase(DebugSubsectionKind::FrameData) {}208 209 void map(IO &IO) override;210 std::shared_ptr<DebugSubsection>211 toCodeViewSubsection(BumpPtrAllocator &Allocator,212 const codeview::StringsAndChecksums &SC) const override;213 static Expected<std::shared_ptr<YAMLFrameDataSubsection>>214 fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,215 const DebugFrameDataSubsectionRef &Frames);216 217 std::vector<YAMLFrameData> Frames;218};219 220struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {221 YAMLCoffSymbolRVASubsection()222 : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA) {}223 224 void map(IO &IO) override;225 std::shared_ptr<DebugSubsection>226 toCodeViewSubsection(BumpPtrAllocator &Allocator,227 const codeview::StringsAndChecksums &SC) const override;228 static Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>229 fromCodeViewSubsection(const DebugSymbolRVASubsectionRef &RVAs);230 231 std::vector<uint32_t> RVAs;232};233 234} // end anonymous namespace235 236void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {237 io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);238 io.enumFallback<Hex16>(Flags);239}240 241void ScalarEnumerationTraits<FileChecksumKind>::enumeration(242 IO &io, FileChecksumKind &Kind) {243 io.enumCase(Kind, "None", FileChecksumKind::None);244 io.enumCase(Kind, "MD5", FileChecksumKind::MD5);245 io.enumCase(Kind, "SHA1", FileChecksumKind::SHA1);246 io.enumCase(Kind, "SHA256", FileChecksumKind::SHA256);247}248 249void ScalarTraits<HexFormattedString>::output(const HexFormattedString &Value,250 void *ctx, raw_ostream &Out) {251 StringRef Bytes(reinterpret_cast<const char *>(Value.Bytes.data()),252 Value.Bytes.size());253 Out << toHex(Bytes);254}255 256StringRef ScalarTraits<HexFormattedString>::input(StringRef Scalar, void *ctxt,257 HexFormattedString &Value) {258 std::string H = fromHex(Scalar);259 Value.Bytes.assign(H.begin(), H.end());260 return StringRef();261}262 263void MappingTraits<SourceLineEntry>::mapping(IO &IO, SourceLineEntry &Obj) {264 IO.mapRequired("Offset", Obj.Offset);265 IO.mapRequired("LineStart", Obj.LineStart);266 IO.mapRequired("IsStatement", Obj.IsStatement);267 IO.mapRequired("EndDelta", Obj.EndDelta);268}269 270void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {271 IO.mapRequired("StartColumn", Obj.StartColumn);272 IO.mapRequired("EndColumn", Obj.EndColumn);273}274 275void MappingTraits<SourceLineBlock>::mapping(IO &IO, SourceLineBlock &Obj) {276 IO.mapRequired("FileName", Obj.FileName);277 IO.mapRequired("Lines", Obj.Lines);278 IO.mapRequired("Columns", Obj.Columns);279}280 281void MappingTraits<CrossModuleExport>::mapping(IO &IO, CrossModuleExport &Obj) {282 IO.mapRequired("LocalId", Obj.Local);283 IO.mapRequired("GlobalId", Obj.Global);284}285 286void MappingTraits<YAMLCrossModuleImport>::mapping(IO &IO,287 YAMLCrossModuleImport &Obj) {288 IO.mapRequired("Module", Obj.ModuleName);289 IO.mapRequired("Imports", Obj.ImportIds);290}291 292void MappingTraits<SourceFileChecksumEntry>::mapping(293 IO &IO, SourceFileChecksumEntry &Obj) {294 IO.mapRequired("FileName", Obj.FileName);295 IO.mapRequired("Kind", Obj.Kind);296 IO.mapRequired("Checksum", Obj.ChecksumBytes);297}298 299void MappingTraits<InlineeSite>::mapping(IO &IO, InlineeSite &Obj) {300 IO.mapRequired("FileName", Obj.FileName);301 IO.mapRequired("LineNum", Obj.SourceLineNum);302 IO.mapRequired("Inlinee", Obj.Inlinee);303 IO.mapOptional("ExtraFiles", Obj.ExtraFiles);304}305 306void MappingTraits<YAMLFrameData>::mapping(IO &IO, YAMLFrameData &Obj) {307 IO.mapRequired("CodeSize", Obj.CodeSize);308 IO.mapRequired("FrameFunc", Obj.FrameFunc);309 IO.mapRequired("LocalSize", Obj.LocalSize);310 IO.mapOptional("MaxStackSize", Obj.MaxStackSize);311 IO.mapOptional("ParamsSize", Obj.ParamsSize);312 IO.mapOptional("PrologSize", Obj.PrologSize);313 IO.mapOptional("RvaStart", Obj.RvaStart);314 IO.mapOptional("SavedRegsSize", Obj.SavedRegsSize);315}316 317void YAMLChecksumsSubsection::map(IO &IO) {318 IO.mapTag("!FileChecksums", true);319 IO.mapRequired("Checksums", Checksums);320}321 322void YAMLLinesSubsection::map(IO &IO) {323 IO.mapTag("!Lines", true);324 IO.mapRequired("CodeSize", Lines.CodeSize);325 326 IO.mapRequired("Flags", Lines.Flags);327 IO.mapRequired("RelocOffset", Lines.RelocOffset);328 IO.mapRequired("RelocSegment", Lines.RelocSegment);329 IO.mapRequired("Blocks", Lines.Blocks);330}331 332void YAMLInlineeLinesSubsection::map(IO &IO) {333 IO.mapTag("!InlineeLines", true);334 IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);335 IO.mapRequired("Sites", InlineeLines.Sites);336}337 338void YAMLCrossModuleExportsSubsection::map(IO &IO) {339 IO.mapTag("!CrossModuleExports", true);340 IO.mapOptional("Exports", Exports);341}342 343void YAMLCrossModuleImportsSubsection::map(IO &IO) {344 IO.mapTag("!CrossModuleImports", true);345 IO.mapOptional("Imports", Imports);346}347 348void YAMLSymbolsSubsection::map(IO &IO) {349 IO.mapTag("!Symbols", true);350 IO.mapRequired("Records", Symbols);351}352 353void YAMLStringTableSubsection::map(IO &IO) {354 IO.mapTag("!StringTable", true);355 IO.mapRequired("Strings", Strings);356}357 358void YAMLFrameDataSubsection::map(IO &IO) {359 IO.mapTag("!FrameData", true);360 IO.mapRequired("Frames", Frames);361}362 363void YAMLCoffSymbolRVASubsection::map(IO &IO) {364 IO.mapTag("!COFFSymbolRVAs", true);365 IO.mapRequired("RVAs", RVAs);366}367 368void MappingTraits<YAMLDebugSubsection>::mapping(369 IO &IO, YAMLDebugSubsection &Subsection) {370 if (!IO.outputting()) {371 if (IO.mapTag("!FileChecksums")) {372 auto SS = std::make_shared<YAMLChecksumsSubsection>();373 Subsection.Subsection = SS;374 } else if (IO.mapTag("!Lines")) {375 Subsection.Subsection = std::make_shared<YAMLLinesSubsection>();376 } else if (IO.mapTag("!InlineeLines")) {377 Subsection.Subsection = std::make_shared<YAMLInlineeLinesSubsection>();378 } else if (IO.mapTag("!CrossModuleExports")) {379 Subsection.Subsection =380 std::make_shared<YAMLCrossModuleExportsSubsection>();381 } else if (IO.mapTag("!CrossModuleImports")) {382 Subsection.Subsection =383 std::make_shared<YAMLCrossModuleImportsSubsection>();384 } else if (IO.mapTag("!Symbols")) {385 Subsection.Subsection = std::make_shared<YAMLSymbolsSubsection>();386 } else if (IO.mapTag("!StringTable")) {387 Subsection.Subsection = std::make_shared<YAMLStringTableSubsection>();388 } else if (IO.mapTag("!FrameData")) {389 Subsection.Subsection = std::make_shared<YAMLFrameDataSubsection>();390 } else if (IO.mapTag("!COFFSymbolRVAs")) {391 Subsection.Subsection = std::make_shared<YAMLCoffSymbolRVASubsection>();392 } else {393 llvm_unreachable("Unexpected subsection tag!");394 }395 }396 Subsection.Subsection->map(IO);397}398 399std::shared_ptr<DebugSubsection> YAMLChecksumsSubsection::toCodeViewSubsection(400 BumpPtrAllocator &Allocator,401 const codeview::StringsAndChecksums &SC) const {402 assert(SC.hasStrings());403 auto Result = std::make_shared<DebugChecksumsSubsection>(*SC.strings());404 for (const auto &CS : Checksums) {405 Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes);406 }407 return Result;408}409 410std::shared_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(411 BumpPtrAllocator &Allocator,412 const codeview::StringsAndChecksums &SC) const {413 assert(SC.hasStrings() && SC.hasChecksums());414 auto Result =415 std::make_shared<DebugLinesSubsection>(*SC.checksums(), *SC.strings());416 Result->setCodeSize(Lines.CodeSize);417 Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset);418 Result->setFlags(Lines.Flags);419 for (const auto &LC : Lines.Blocks) {420 Result->createBlock(LC.FileName);421 if (Result->hasColumnInfo()) {422 for (auto Item : zip(LC.Lines, LC.Columns)) {423 auto &L = std::get<0>(Item);424 auto &C = std::get<1>(Item);425 uint32_t LE = L.LineStart + L.EndDelta;426 Result->addLineAndColumnInfo(L.Offset,427 LineInfo(L.LineStart, LE, L.IsStatement),428 C.StartColumn, C.EndColumn);429 }430 } else {431 for (const auto &L : LC.Lines) {432 uint32_t LE = L.LineStart + L.EndDelta;433 Result->addLineInfo(L.Offset, LineInfo(L.LineStart, LE, L.IsStatement));434 }435 }436 }437 return Result;438}439 440std::shared_ptr<DebugSubsection>441YAMLInlineeLinesSubsection::toCodeViewSubsection(442 BumpPtrAllocator &Allocator,443 const codeview::StringsAndChecksums &SC) const {444 assert(SC.hasChecksums());445 auto Result = std::make_shared<DebugInlineeLinesSubsection>(446 *SC.checksums(), InlineeLines.HasExtraFiles);447 448 for (const auto &Site : InlineeLines.Sites) {449 Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,450 Site.SourceLineNum);451 if (!InlineeLines.HasExtraFiles)452 continue;453 454 for (auto EF : Site.ExtraFiles) {455 Result->addExtraFile(EF);456 }457 }458 return Result;459}460 461std::shared_ptr<DebugSubsection>462YAMLCrossModuleExportsSubsection::toCodeViewSubsection(463 BumpPtrAllocator &Allocator,464 const codeview::StringsAndChecksums &SC) const {465 auto Result = std::make_shared<DebugCrossModuleExportsSubsection>();466 for (const auto &M : Exports)467 Result->addMapping(M.Local, M.Global);468 return Result;469}470 471std::shared_ptr<DebugSubsection>472YAMLCrossModuleImportsSubsection::toCodeViewSubsection(473 BumpPtrAllocator &Allocator,474 const codeview::StringsAndChecksums &SC) const {475 assert(SC.hasStrings());476 477 auto Result =478 std::make_shared<DebugCrossModuleImportsSubsection>(*SC.strings());479 for (const auto &M : Imports) {480 for (const auto Id : M.ImportIds)481 Result->addImport(M.ModuleName, Id);482 }483 return Result;484}485 486std::shared_ptr<DebugSubsection> YAMLSymbolsSubsection::toCodeViewSubsection(487 BumpPtrAllocator &Allocator,488 const codeview::StringsAndChecksums &SC) const {489 auto Result = std::make_shared<DebugSymbolsSubsection>();490 for (const auto &Sym : Symbols)491 Result->addSymbol(492 Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile));493 return Result;494}495 496std::shared_ptr<DebugSubsection>497YAMLStringTableSubsection::toCodeViewSubsection(498 BumpPtrAllocator &Allocator,499 const codeview::StringsAndChecksums &SC) const {500 auto Result = std::make_shared<DebugStringTableSubsection>();501 for (const auto &Str : this->Strings)502 Result->insert(Str);503 return Result;504}505 506std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(507 BumpPtrAllocator &Allocator,508 const codeview::StringsAndChecksums &SC) const {509 assert(SC.hasStrings());510 511 auto Result = std::make_shared<DebugFrameDataSubsection>(true);512 for (const auto &YF : Frames) {513 codeview::FrameData F;514 F.CodeSize = YF.CodeSize;515 F.Flags = YF.Flags;516 F.LocalSize = YF.LocalSize;517 F.MaxStackSize = YF.MaxStackSize;518 F.ParamsSize = YF.ParamsSize;519 F.PrologSize = YF.PrologSize;520 F.RvaStart = YF.RvaStart;521 F.SavedRegsSize = YF.SavedRegsSize;522 F.FrameFunc = SC.strings()->insert(YF.FrameFunc);523 Result->addFrameData(F);524 }525 return Result;526}527 528std::shared_ptr<DebugSubsection>529YAMLCoffSymbolRVASubsection::toCodeViewSubsection(530 BumpPtrAllocator &Allocator,531 const codeview::StringsAndChecksums &SC) const {532 auto Result = std::make_shared<DebugSymbolRVASubsection>();533 for (const auto &RVA : RVAs)534 Result->addRVA(RVA);535 return Result;536}537 538static Expected<SourceFileChecksumEntry>539convertOneChecksum(const DebugStringTableSubsectionRef &Strings,540 const FileChecksumEntry &CS) {541 auto ExpectedString = Strings.getString(CS.FileNameOffset);542 if (!ExpectedString)543 return ExpectedString.takeError();544 545 SourceFileChecksumEntry Result;546 Result.ChecksumBytes.Bytes = CS.Checksum;547 Result.Kind = CS.Kind;548 Result.FileName = *ExpectedString;549 return Result;550}551 552static Expected<StringRef>553getFileName(const DebugStringTableSubsectionRef &Strings,554 const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {555 auto Iter = Checksums.getArray().at(FileID);556 if (Iter == Checksums.getArray().end())557 return make_error<CodeViewError>(cv_error_code::no_records);558 uint32_t Offset = Iter->FileNameOffset;559 return Strings.getString(Offset);560}561 562Expected<std::shared_ptr<YAMLChecksumsSubsection>>563YAMLChecksumsSubsection::fromCodeViewSubsection(564 const DebugStringTableSubsectionRef &Strings,565 const DebugChecksumsSubsectionRef &FC) {566 auto Result = std::make_shared<YAMLChecksumsSubsection>();567 568 for (const auto &CS : FC) {569 auto ConvertedCS = convertOneChecksum(Strings, CS);570 if (!ConvertedCS)571 return ConvertedCS.takeError();572 Result->Checksums.push_back(*ConvertedCS);573 }574 return Result;575}576 577Expected<std::shared_ptr<YAMLLinesSubsection>>578YAMLLinesSubsection::fromCodeViewSubsection(579 const DebugStringTableSubsectionRef &Strings,580 const DebugChecksumsSubsectionRef &Checksums,581 const DebugLinesSubsectionRef &Lines) {582 auto Result = std::make_shared<YAMLLinesSubsection>();583 Result->Lines.CodeSize = Lines.header()->CodeSize;584 Result->Lines.RelocOffset = Lines.header()->RelocOffset;585 Result->Lines.RelocSegment = Lines.header()->RelocSegment;586 Result->Lines.Flags = static_cast<LineFlags>(uint16_t(Lines.header()->Flags));587 for (const auto &L : Lines) {588 SourceLineBlock Block;589 auto EF = getFileName(Strings, Checksums, L.NameIndex);590 if (!EF)591 return EF.takeError();592 Block.FileName = *EF;593 if (Lines.hasColumnInfo()) {594 for (const auto &C : L.Columns) {595 SourceColumnEntry SCE;596 SCE.EndColumn = C.EndColumn;597 SCE.StartColumn = C.StartColumn;598 Block.Columns.push_back(SCE);599 }600 }601 for (const auto &LN : L.LineNumbers) {602 SourceLineEntry SLE;603 LineInfo LI(LN.Flags);604 SLE.Offset = LN.Offset;605 SLE.LineStart = LI.getStartLine();606 SLE.EndDelta = LI.getLineDelta();607 SLE.IsStatement = LI.isStatement();608 Block.Lines.push_back(SLE);609 }610 Result->Lines.Blocks.push_back(Block);611 }612 return Result;613}614 615Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>616YAMLInlineeLinesSubsection::fromCodeViewSubsection(617 const DebugStringTableSubsectionRef &Strings,618 const DebugChecksumsSubsectionRef &Checksums,619 const DebugInlineeLinesSubsectionRef &Lines) {620 auto Result = std::make_shared<YAMLInlineeLinesSubsection>();621 622 Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles();623 for (const auto &IL : Lines) {624 InlineeSite Site;625 auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID);626 if (!ExpF)627 return ExpF.takeError();628 Site.FileName = *ExpF;629 Site.Inlinee = IL.Header->Inlinee.getIndex();630 Site.SourceLineNum = IL.Header->SourceLineNum;631 if (Lines.hasExtraFiles()) {632 for (const auto EF : IL.ExtraFiles) {633 auto ExpF2 = getFileName(Strings, Checksums, EF);634 if (!ExpF2)635 return ExpF2.takeError();636 Site.ExtraFiles.push_back(*ExpF2);637 }638 }639 Result->InlineeLines.Sites.push_back(Site);640 }641 return Result;642}643 644Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>645YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(646 const DebugCrossModuleExportsSubsectionRef &Exports) {647 auto Result = std::make_shared<YAMLCrossModuleExportsSubsection>();648 Result->Exports.assign(Exports.begin(), Exports.end());649 return Result;650}651 652Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>653YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(654 const DebugStringTableSubsectionRef &Strings,655 const DebugCrossModuleImportsSubsectionRef &Imports) {656 auto Result = std::make_shared<YAMLCrossModuleImportsSubsection>();657 for (const auto &CMI : Imports) {658 YAMLCrossModuleImport YCMI;659 auto ExpectedStr = Strings.getString(CMI.Header->ModuleNameOffset);660 if (!ExpectedStr)661 return ExpectedStr.takeError();662 YCMI.ModuleName = *ExpectedStr;663 YCMI.ImportIds.assign(CMI.Imports.begin(), CMI.Imports.end());664 Result->Imports.push_back(YCMI);665 }666 return Result;667}668 669Expected<std::shared_ptr<YAMLSymbolsSubsection>>670YAMLSymbolsSubsection::fromCodeViewSubsection(671 const DebugSymbolsSubsectionRef &Symbols) {672 auto Result = std::make_shared<YAMLSymbolsSubsection>();673 for (const auto &Sym : Symbols) {674 auto S = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym);675 if (!S)676 return joinErrors(make_error<CodeViewError>(677 cv_error_code::corrupt_record,678 "Invalid CodeView Symbol Record in SymbolRecord "679 "subsection of .debug$S while converting to YAML!"),680 S.takeError());681 682 Result->Symbols.push_back(*S);683 }684 return Result;685}686 687Expected<std::shared_ptr<YAMLStringTableSubsection>>688YAMLStringTableSubsection::fromCodeViewSubsection(689 const DebugStringTableSubsectionRef &Strings) {690 auto Result = std::make_shared<YAMLStringTableSubsection>();691 BinaryStreamReader Reader(Strings.getBuffer());692 StringRef S;693 // First item is a single null string, skip it.694 if (auto EC = Reader.readCString(S))695 return std::move(EC);696 assert(S.empty());697 while (Reader.bytesRemaining() > 0) {698 if (auto EC = Reader.readCString(S))699 return std::move(EC);700 Result->Strings.push_back(S);701 }702 return Result;703}704 705Expected<std::shared_ptr<YAMLFrameDataSubsection>>706YAMLFrameDataSubsection::fromCodeViewSubsection(707 const DebugStringTableSubsectionRef &Strings,708 const DebugFrameDataSubsectionRef &Frames) {709 auto Result = std::make_shared<YAMLFrameDataSubsection>();710 for (const auto &F : Frames) {711 YAMLFrameData YF;712 YF.CodeSize = F.CodeSize;713 YF.Flags = F.Flags;714 YF.LocalSize = F.LocalSize;715 YF.MaxStackSize = F.MaxStackSize;716 YF.ParamsSize = F.ParamsSize;717 YF.PrologSize = F.PrologSize;718 YF.RvaStart = F.RvaStart;719 YF.SavedRegsSize = F.SavedRegsSize;720 721 auto ES = Strings.getString(F.FrameFunc);722 if (!ES)723 return joinErrors(724 make_error<CodeViewError>(725 cv_error_code::no_records,726 "Could not find string for string id while mapping FrameData!"),727 ES.takeError());728 YF.FrameFunc = *ES;729 Result->Frames.push_back(YF);730 }731 return Result;732}733 734Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>735YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(736 const DebugSymbolRVASubsectionRef &Section) {737 auto Result = std::make_shared<YAMLCoffSymbolRVASubsection>();738 llvm::append_range(Result->RVAs, Section);739 return Result;740}741 742Expected<std::vector<std::shared_ptr<DebugSubsection>>>743llvm::CodeViewYAML::toCodeViewSubsectionList(744 BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,745 const codeview::StringsAndChecksums &SC) {746 std::vector<std::shared_ptr<DebugSubsection>> Result;747 if (Subsections.empty())748 return std::move(Result);749 750 for (const auto &SS : Subsections) {751 std::shared_ptr<DebugSubsection> CVS;752 CVS = SS.Subsection->toCodeViewSubsection(Allocator, SC);753 assert(CVS != nullptr);754 Result.push_back(std::move(CVS));755 }756 return std::move(Result);757}758 759namespace {760 761struct SubsectionConversionVisitor : public DebugSubsectionVisitor {762 SubsectionConversionVisitor() = default;763 764 Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override;765 Error visitLines(DebugLinesSubsectionRef &Lines,766 const StringsAndChecksumsRef &State) override;767 Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,768 const StringsAndChecksumsRef &State) override;769 Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,770 const StringsAndChecksumsRef &State) override;771 Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &Checksums,772 const StringsAndChecksumsRef &State) override;773 Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &Inlinees,774 const StringsAndChecksumsRef &State) override;775 Error visitStringTable(DebugStringTableSubsectionRef &ST,776 const StringsAndChecksumsRef &State) override;777 Error visitSymbols(DebugSymbolsSubsectionRef &Symbols,778 const StringsAndChecksumsRef &State) override;779 Error visitFrameData(DebugFrameDataSubsectionRef &Symbols,780 const StringsAndChecksumsRef &State) override;781 Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &Symbols,782 const StringsAndChecksumsRef &State) override;783 784 YAMLDebugSubsection Subsection;785};786 787} // end anonymous namespace788 789Error SubsectionConversionVisitor::visitUnknown(790 DebugUnknownSubsectionRef &Unknown) {791 return make_error<CodeViewError>(cv_error_code::operation_unsupported);792}793 794Error SubsectionConversionVisitor::visitLines(795 DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {796 auto Result = YAMLLinesSubsection::fromCodeViewSubsection(797 State.strings(), State.checksums(), Lines);798 if (!Result)799 return Result.takeError();800 Subsection.Subsection = *Result;801 return Error::success();802}803 804Error SubsectionConversionVisitor::visitFileChecksums(805 DebugChecksumsSubsectionRef &Checksums,806 const StringsAndChecksumsRef &State) {807 auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),808 Checksums);809 if (!Result)810 return Result.takeError();811 Subsection.Subsection = *Result;812 return Error::success();813}814 815Error SubsectionConversionVisitor::visitInlineeLines(816 DebugInlineeLinesSubsectionRef &Inlinees,817 const StringsAndChecksumsRef &State) {818 auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(819 State.strings(), State.checksums(), Inlinees);820 if (!Result)821 return Result.takeError();822 Subsection.Subsection = *Result;823 return Error::success();824}825 826Error SubsectionConversionVisitor::visitCrossModuleExports(827 DebugCrossModuleExportsSubsectionRef &Exports,828 const StringsAndChecksumsRef &State) {829 auto Result =830 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);831 if (!Result)832 return Result.takeError();833 Subsection.Subsection = *Result;834 return Error::success();835}836 837Error SubsectionConversionVisitor::visitCrossModuleImports(838 DebugCrossModuleImportsSubsectionRef &Imports,839 const StringsAndChecksumsRef &State) {840 auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(841 State.strings(), Imports);842 if (!Result)843 return Result.takeError();844 Subsection.Subsection = *Result;845 return Error::success();846}847 848Error SubsectionConversionVisitor::visitStringTable(849 DebugStringTableSubsectionRef &Strings,850 const StringsAndChecksumsRef &State) {851 auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);852 if (!Result)853 return Result.takeError();854 Subsection.Subsection = *Result;855 return Error::success();856}857 858Error SubsectionConversionVisitor::visitSymbols(859 DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {860 auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);861 if (!Result)862 return Result.takeError();863 Subsection.Subsection = *Result;864 return Error::success();865}866 867Error SubsectionConversionVisitor::visitFrameData(868 DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {869 auto Result =870 YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);871 if (!Result)872 return Result.takeError();873 Subsection.Subsection = *Result;874 return Error::success();875}876 877Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(878 DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) {879 auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);880 if (!Result)881 return Result.takeError();882 Subsection.Subsection = *Result;883 return Error::success();884}885 886Expected<YAMLDebugSubsection>887YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef &SC,888 const DebugSubsectionRecord &SS) {889 SubsectionConversionVisitor V;890 if (auto EC = visitDebugSubsection(SS, V, SC))891 return std::move(EC);892 893 return V.Subsection;894}895 896std::vector<YAMLDebugSubsection>897llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,898 const StringsAndChecksumsRef &SC) {899 BinaryStreamReader Reader(Data, llvm::endianness::little);900 uint32_t Magic;901 902 ExitOnError Err("Invalid .debug$S section!");903 Err(Reader.readInteger(Magic));904 assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");905 906 DebugSubsectionArray Subsections;907 Err(Reader.readArray(Subsections, Reader.bytesRemaining()));908 909 std::vector<YAMLDebugSubsection> Result;910 911 for (const auto &SS : Subsections) {912 auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));913 Result.push_back(YamlSS);914 }915 return Result;916}917 918void llvm::CodeViewYAML::initializeStringsAndChecksums(919 ArrayRef<YAMLDebugSubsection> Sections, codeview::StringsAndChecksums &SC) {920 // String Table and Checksums subsections don't use the allocator.921 BumpPtrAllocator Allocator;922 923 // It's possible for checksums and strings to even appear in different debug$S924 // sections, so we have to make this a stateful function that can build up925 // the strings and checksums field over multiple iterations.926 927 // File Checksums require the string table, but may become before it, so we928 // have to scan for strings first, then scan for checksums again from the929 // beginning.930 if (!SC.hasStrings()) {931 for (const auto &SS : Sections) {932 if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)933 continue;934 935 auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);936 SC.setStrings(937 std::static_pointer_cast<DebugStringTableSubsection>(Result));938 break;939 }940 }941 942 if (SC.hasStrings() && !SC.hasChecksums()) {943 for (const auto &SS : Sections) {944 if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)945 continue;946 947 auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);948 SC.setChecksums(949 std::static_pointer_cast<DebugChecksumsSubsection>(Result));950 break;951 }952 }953}954