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