diff options
author | Zachary Turner <zturner@google.com> | 2017-06-14 05:31:00 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2017-06-14 05:31:00 +0000 |
commit | a3da4467fa8ed514130736c6c15f01422159d00d (patch) | |
tree | 12356bbf4e58c9d059fb2899b240256e75d75a81 /llvm/tools/yaml2obj/yaml2coff.cpp | |
parent | f4ea23d3a58ee23d13b719e525e0575a29e510da (diff) | |
download | bcm5719-llvm-a3da4467fa8ed514130736c6c15f01422159d00d.tar.gz bcm5719-llvm-a3da4467fa8ed514130736c6c15f01422159d00d.zip |
[codeview] Make obj2yaml/yaml2obj support .debug$S/T sections.
This allows us to use yaml2obj and obj2yaml to round-trip CodeView
symbol and type information without having to manually specify the bytes
of the section. This makes for much easier to maintain tests. See the
tests under lld/COFF in this patch for example. Before they just said
SectionData: <blob> whereas now we can use meaningful record
descriptions. Note that it still supports the SectionData yaml field,
which could be useful for initializing a section to invalid bytes for
testing, for example.
Differential Revision: https://reviews.llvm.org/D34127
llvm-svn: 305366
Diffstat (limited to 'llvm/tools/yaml2obj/yaml2coff.cpp')
-rw-r--r-- | llvm/tools/yaml2obj/yaml2coff.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/llvm/tools/yaml2obj/yaml2coff.cpp b/llvm/tools/yaml2obj/yaml2coff.cpp index 8f3f5217952..b41cc9a8f06 100644 --- a/llvm/tools/yaml2obj/yaml2coff.cpp +++ b/llvm/tools/yaml2obj/yaml2coff.cpp @@ -17,6 +17,8 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" #include "llvm/Object/COFF.h" #include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/Endian.h" @@ -27,6 +29,33 @@ using namespace llvm; +namespace { +template <typename T> struct WeakishPtr { +public: + WeakishPtr() : Ref(nullptr) {} + + WeakishPtr(std::unique_ptr<T> Value) + : Ref(Value.get()), UniquePtr(std::move(Value)) {} + + WeakishPtr(std::unique_ptr<T> &&Value) + : Ref(Value.get()), UniquePtr(std::move(Value)) {} + + WeakishPtr<T> &operator=(std::unique_ptr<T> &&Value) { + Owned = std::move(Value); + Ref = Owned.get(); + return *this; + } + + T *get() { return Ref; } + T &operator*() { return *Ref; } + + operator bool() const { return Ref != nullptr; } + + T *Ref; + std::unique_ptr<T> Owned; +}; +} // namespace + /// This parses a yaml stream that represents a COFF object file. /// See docs/yaml2obj for the yaml scheema. struct COFFParser { @@ -142,6 +171,8 @@ struct COFFParser { COFFYAML::Object &Obj; + codeview::StringsAndChecksums StringsAndChecksums; + BumpPtrAllocator Allocator; StringMap<unsigned> StringTableMap; std::string StringTable; uint32_t SectionTableStart; @@ -165,6 +196,32 @@ namespace { enum { DOSStubSize = 128 }; } +static yaml::BinaryRef +toDebugS(ArrayRef<CodeViewYAML::YAMLDebugSubsection> Subsections, + const codeview::StringsAndChecksums &SC, BumpPtrAllocator &Allocator) { + using namespace codeview; + ExitOnError Err("Error occurred writing .debug$S section"); + auto CVSS = + Err(CodeViewYAML::toCodeViewSubsectionList(Allocator, Subsections, SC)); + + std::vector<DebugSubsectionRecordBuilder> Builders; + uint32_t Size = sizeof(uint32_t); + for (auto &SS : CVSS) { + DebugSubsectionRecordBuilder B(SS, CodeViewContainer::ObjectFile); + Size += B.calculateSerializedLength(); + Builders.push_back(std::move(B)); + } + uint8_t *Buffer = Allocator.Allocate<uint8_t>(Size); + MutableArrayRef<uint8_t> Output(Buffer, Size); + BinaryStreamWriter Writer(Output, support::little); + + Err(Writer.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC)); + for (const auto &B : Builders) { + Err(B.commit(Writer)); + } + return {Output}; +} + // Take a CP and assign addresses and sizes to everything. Returns false if the // layout is not valid to do. static bool layoutCOFF(COFFParser &CP) { @@ -179,8 +236,33 @@ static bool layoutCOFF(COFFParser &CP) { uint32_t CurrentSectionDataOffset = CP.SectionTableStart + CP.SectionTableSize; + for (COFFYAML::Section &S : CP.Obj.Sections) { + // We support specifying exactly one of SectionData or Subsections. So if + // there is already some SectionData, then we don't need to do any of this. + if (S.Name == ".debug$S" && S.SectionData.binary_size() == 0) { + CodeViewYAML::initializeStringsAndChecksums(S.DebugS, + CP.StringsAndChecksums); + if (CP.StringsAndChecksums.hasChecksums() && + CP.StringsAndChecksums.hasStrings()) + break; + } + } + // Assign each section data address consecutively. for (COFFYAML::Section &S : CP.Obj.Sections) { + if (S.Name == ".debug$S") { + if (S.SectionData.binary_size() == 0) { + assert(CP.StringsAndChecksums.hasStrings() && + "Object file does not have debug string table!"); + + S.SectionData = + toDebugS(S.DebugS, CP.StringsAndChecksums, CP.Allocator); + } + } else if (S.Name == ".debug$T") { + if (S.SectionData.binary_size() == 0) + S.SectionData = CodeViewYAML::toDebugT(S.DebugT, CP.Allocator); + } + if (S.SectionData.binary_size() > 0) { CurrentSectionDataOffset = alignTo(CurrentSectionDataOffset, CP.isPE() ? CP.getFileAlignment() : 4); @@ -543,6 +625,7 @@ int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) { errs() << "yaml2obj: Failed to layout optional header for COFF file!\n"; return 1; } + if (!layoutCOFF(CP)) { errs() << "yaml2obj: Failed to layout COFF file!\n"; return 1; |