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