summaryrefslogtreecommitdiffstats
path: root/llvm/tools/yaml2obj/yaml2coff.cpp
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-06-14 05:31:00 +0000
committerZachary Turner <zturner@google.com>2017-06-14 05:31:00 +0000
commita3da4467fa8ed514130736c6c15f01422159d00d (patch)
tree12356bbf4e58c9d059fb2899b240256e75d75a81 /llvm/tools/yaml2obj/yaml2coff.cpp
parentf4ea23d3a58ee23d13b719e525e0575a29e510da (diff)
downloadbcm5719-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.cpp83
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;
OpenPOWER on IntegriCloud