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 51 using namespace llvm; 52 using namespace llvm::codeview; 53 using namespace llvm::CodeViewYAML; 54 using namespace llvm::CodeViewYAML::detail; 55 using namespace llvm::yaml; 56 57 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry) 58 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry) 59 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry) 60 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock) 61 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo) 62 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite) 63 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo) 64 LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport) 65 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport) 66 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData) 67 68 LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, QuotingType::None) 69 LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind) 70 LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind) 71 LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags) 72 73 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport) 74 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData) 75 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport) 76 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem) 77 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry) 78 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry) 79 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry) 80 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock) 81 LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite) 82 83 namespace llvm { 84 namespace CodeViewYAML { 85 namespace detail { 86 87 struct 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 103 namespace { 104 105 struct 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 120 struct 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 135 struct 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 151 struct 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 165 struct 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 180 struct 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 193 struct 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 207 struct 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 222 struct 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 238 void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) { 239 io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns); 240 io.enumFallback<Hex16>(Flags); 241 } 242 243 void 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 251 void 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 258 StringRef 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 265 void 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 272 void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) { 273 IO.mapRequired("StartColumn", Obj.StartColumn); 274 IO.mapRequired("EndColumn", Obj.EndColumn); 275 } 276 277 void 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 283 void MappingTraits<CrossModuleExport>::mapping(IO &IO, CrossModuleExport &Obj) { 284 IO.mapRequired("LocalId", Obj.Local); 285 IO.mapRequired("GlobalId", Obj.Global); 286 } 287 288 void MappingTraits<YAMLCrossModuleImport>::mapping(IO &IO, 289 YAMLCrossModuleImport &Obj) { 290 IO.mapRequired("Module", Obj.ModuleName); 291 IO.mapRequired("Imports", Obj.ImportIds); 292 } 293 294 void 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 301 void 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 308 void 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 319 void YAMLChecksumsSubsection::map(IO &IO) { 320 IO.mapTag("!FileChecksums", true); 321 IO.mapRequired("Checksums", Checksums); 322 } 323 324 void 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 334 void YAMLInlineeLinesSubsection::map(IO &IO) { 335 IO.mapTag("!InlineeLines", true); 336 IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles); 337 IO.mapRequired("Sites", InlineeLines.Sites); 338 } 339 340 void YAMLCrossModuleExportsSubsection::map(IO &IO) { 341 IO.mapTag("!CrossModuleExports", true); 342 IO.mapOptional("Exports", Exports); 343 } 344 345 void YAMLCrossModuleImportsSubsection::map(IO &IO) { 346 IO.mapTag("!CrossModuleImports", true); 347 IO.mapOptional("Imports", Imports); 348 } 349 350 void YAMLSymbolsSubsection::map(IO &IO) { 351 IO.mapTag("!Symbols", true); 352 IO.mapRequired("Records", Symbols); 353 } 354 355 void YAMLStringTableSubsection::map(IO &IO) { 356 IO.mapTag("!StringTable", true); 357 IO.mapRequired("Strings", Strings); 358 } 359 360 void YAMLFrameDataSubsection::map(IO &IO) { 361 IO.mapTag("!FrameData", true); 362 IO.mapRequired("Frames", Frames); 363 } 364 365 void YAMLCoffSymbolRVASubsection::map(IO &IO) { 366 IO.mapTag("!COFFSymbolRVAs", true); 367 IO.mapRequired("RVAs", RVAs); 368 } 369 370 void 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 401 std::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 412 std::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 442 std::shared_ptr<DebugSubsection> 443 YAMLInlineeLinesSubsection::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 463 std::shared_ptr<DebugSubsection> 464 YAMLCrossModuleExportsSubsection::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 473 std::shared_ptr<DebugSubsection> 474 YAMLCrossModuleImportsSubsection::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 488 std::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 498 std::shared_ptr<DebugSubsection> 499 YAMLStringTableSubsection::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 508 std::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 530 std::shared_ptr<DebugSubsection> 531 YAMLCoffSymbolRVASubsection::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 540 static Expected<SourceFileChecksumEntry> 541 convertOneChecksum(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 554 static Expected<StringRef> 555 getFileName(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 564 Expected<std::shared_ptr<YAMLChecksumsSubsection>> 565 YAMLChecksumsSubsection::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 579 Expected<std::shared_ptr<YAMLLinesSubsection>> 580 YAMLLinesSubsection::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 617 Expected<std::shared_ptr<YAMLInlineeLinesSubsection>> 618 YAMLInlineeLinesSubsection::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 646 Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>> 647 YAMLCrossModuleExportsSubsection::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 654 Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>> 655 YAMLCrossModuleImportsSubsection::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 671 Expected<std::shared_ptr<YAMLSymbolsSubsection>> 672 YAMLSymbolsSubsection::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 689 Expected<std::shared_ptr<YAMLStringTableSubsection>> 690 YAMLStringTableSubsection::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 707 Expected<std::shared_ptr<YAMLFrameDataSubsection>> 708 YAMLFrameDataSubsection::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 736 Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>> 737 YAMLCoffSymbolRVASubsection::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 746 Expected<std::vector<std::shared_ptr<DebugSubsection>>> 747 llvm::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 763 namespace { 764 765 struct 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 793 Error SubsectionConversionVisitor::visitUnknown( 794 DebugUnknownSubsectionRef &Unknown) { 795 return make_error<CodeViewError>(cv_error_code::operation_unsupported); 796 } 797 798 Error 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 808 Error 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 819 Error 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 830 Error 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 841 Error 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 852 Error 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 862 Error 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 871 Error 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 881 Error 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 890 Expected<YAMLDebugSubsection> 891 YAMLDebugSubsection::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 900 std::vector<YAMLDebugSubsection> 901 llvm::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 922 void 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