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