summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/llvm-readobj
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/llvm-readobj')
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp665
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h124
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h552
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp735
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h117
-rw-r--r--contrib/llvm/tools/llvm-readobj/COFFDumper.cpp1142
-rw-r--r--contrib/llvm/tools/llvm-readobj/ELFDumper.cpp1424
-rw-r--r--contrib/llvm/tools/llvm-readobj/Error.cpp54
-rw-r--r--contrib/llvm/tools/llvm-readobj/Error.h41
-rw-r--r--contrib/llvm/tools/llvm-readobj/MachODumper.cpp563
-rw-r--r--contrib/llvm/tools/llvm-readobj/ObjDumper.cpp31
-rw-r--r--contrib/llvm/tools/llvm-readobj/ObjDumper.h71
-rw-r--r--contrib/llvm/tools/llvm-readobj/StreamWriter.cpp79
-rw-r--r--contrib/llvm/tools/llvm-readobj/StreamWriter.h304
-rw-r--r--contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp329
-rw-r--r--contrib/llvm/tools/llvm-readobj/Win64EHDumper.h63
-rw-r--r--contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp393
-rw-r--r--contrib/llvm/tools/llvm-readobj/llvm-readobj.h48
18 files changed, 6735 insertions, 0 deletions
diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp
new file mode 100644
index 0000000..e2d7191
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp
@@ -0,0 +1,665 @@
+//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMAttributeParser.h"
+#include "StreamWriter.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/LEB128.h"
+
+using namespace llvm;
+using namespace llvm::ARMBuildAttrs;
+
+
+static const EnumEntry<unsigned> TagNames[] = {
+ { "Tag_File", ARMBuildAttrs::File },
+ { "Tag_Section", ARMBuildAttrs::Section },
+ { "Tag_Symbol", ARMBuildAttrs::Symbol },
+};
+
+namespace llvm {
+#define ATTRIBUTE_HANDLER(Attr_) \
+ { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ }
+
+const ARMAttributeParser::DisplayHandler
+ARMAttributeParser::DisplayRoutines[] = {
+ { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, },
+ { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute },
+ ATTRIBUTE_HANDLER(CPU_arch),
+ ATTRIBUTE_HANDLER(CPU_arch_profile),
+ ATTRIBUTE_HANDLER(ARM_ISA_use),
+ ATTRIBUTE_HANDLER(THUMB_ISA_use),
+ ATTRIBUTE_HANDLER(FP_arch),
+ ATTRIBUTE_HANDLER(WMMX_arch),
+ ATTRIBUTE_HANDLER(Advanced_SIMD_arch),
+ ATTRIBUTE_HANDLER(PCS_config),
+ ATTRIBUTE_HANDLER(ABI_PCS_R9_use),
+ ATTRIBUTE_HANDLER(ABI_PCS_RW_data),
+ ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
+ ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
+ ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
+ ATTRIBUTE_HANDLER(ABI_FP_rounding),
+ ATTRIBUTE_HANDLER(ABI_FP_denormal),
+ ATTRIBUTE_HANDLER(ABI_FP_exceptions),
+ ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
+ ATTRIBUTE_HANDLER(ABI_FP_number_model),
+ ATTRIBUTE_HANDLER(ABI_align_needed),
+ ATTRIBUTE_HANDLER(ABI_align_preserved),
+ ATTRIBUTE_HANDLER(ABI_enum_size),
+ ATTRIBUTE_HANDLER(ABI_HardFP_use),
+ ATTRIBUTE_HANDLER(ABI_VFP_args),
+ ATTRIBUTE_HANDLER(ABI_WMMX_args),
+ ATTRIBUTE_HANDLER(ABI_optimization_goals),
+ ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
+ ATTRIBUTE_HANDLER(compatibility),
+ ATTRIBUTE_HANDLER(CPU_unaligned_access),
+ ATTRIBUTE_HANDLER(FP_HP_extension),
+ ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
+ ATTRIBUTE_HANDLER(MPextension_use),
+ ATTRIBUTE_HANDLER(DIV_use),
+ ATTRIBUTE_HANDLER(T2EE_use),
+ ATTRIBUTE_HANDLER(Virtualization_use),
+ ATTRIBUTE_HANDLER(nodefaults)
+};
+
+#undef ATTRIBUTE_HANDLER
+
+uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data,
+ uint32_t &Offset) {
+ unsigned Length;
+ uint64_t Value = decodeULEB128(Data + Offset, &Length);
+ Offset = Offset + Length;
+ return Value;
+}
+
+StringRef ARMAttributeParser::ParseString(const uint8_t *Data,
+ uint32_t &Offset) {
+ const char *String = reinterpret_cast<const char*>(Data + Offset);
+ size_t Length = std::strlen(String);
+ Offset = Offset + Length + 1;
+ return StringRef(String, Length);
+}
+
+void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ SW.printNumber(ARMBuildAttrs::AttrTypeAsString(Tag),
+ ParseInteger(Data, Offset));
+}
+
+void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
+
+ DictScope AS(SW, "Attribute");
+ SW.printNumber("Tag", Tag);
+ if (!TagName.empty())
+ SW.printString("TagName", TagName);
+ SW.printString("Value", ParseString(Data, Offset));
+}
+
+void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value,
+ StringRef ValueDesc) {
+ StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
+
+ DictScope AS(SW, "Attribute");
+ SW.printNumber("Tag", Tag);
+ SW.printNumber("Value", Value);
+ if (!TagName.empty())
+ SW.printString("TagName", TagName);
+ if (!ValueDesc.empty())
+ SW.printString("Description", ValueDesc);
+}
+
+void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
+ "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M",
+ "ARM v7E-M", "ARM v8"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ uint64_t Encoded = ParseInteger(Data, Offset);
+
+ StringRef Profile;
+ switch (Encoded) {
+ default: Profile = "Unknown"; break;
+ case 'A': Profile = "Application"; break;
+ case 'R': Profile = "Real-time"; break;
+ case 'M': Profile = "Microcontroller"; break;
+ case 'S': Profile = "Classic"; break;
+ case 0: Profile = "None"; break;
+ }
+
+ PrintAttribute(Tag, Encoded, Profile);
+}
+
+void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4",
+ "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004",
+ "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "v6", "Static Base", "TLS", "Unused" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Absolute", "PC-relative", "SB-relative", "Not Permitted"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Absolute", "PC-relative", "Not Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "Direct", "GOT-Indirect" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "IEEE-754", "Runtime" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Unsupported", "IEEE-754", "Sign Only" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "IEEE-754" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag,
+ const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "IEEE-754" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Permitted", "Finite Only", "RTABI", "IEEE-754"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+
+ std::string Description;
+ if (Value < array_lengthof(Strings))
+ Description = std::string(Strings[Value]);
+ else if (Value <= 12)
+ Description = std::string("8-byte alignment, ") + utostr(1 << Value)
+ + std::string("-byte extended alignment");
+ else
+ Description = "Invalid";
+
+ PrintAttribute(Tag, Value, Description);
+}
+
+void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Required", "8-byte data alignment", "8-byte data and code alignment",
+ "Reserved"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+
+ std::string Description;
+ if (Value < array_lengthof(Strings))
+ Description = std::string(Strings[Value]);
+ else if (Value <= 12)
+ Description = std::string("8-byte stack alignment, ") + utostr(1 << Value)
+ + std::string("-byte data alignment");
+ else
+ Description = "Invalid";
+
+ PrintAttribute(Tag, Value, Description);
+}
+
+void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Permitted", "Packed", "Int32", "External Int32"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "AAPCS", "AAPCS VFP", "Custom", "Not Permitted"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "AAPCS", "iWMMX", "Custom" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_optimization_goals(AttrType Tag,
+ const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging",
+ "Best Debugging"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag,
+ const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy",
+ "Best Accuracy"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ uint64_t Integer = ParseInteger(Data, Offset);
+ StringRef String = ParseString(Data, Offset);
+
+ DictScope AS(SW, "Attribute");
+ SW.printNumber("Tag", Tag);
+ SW.startLine() << "Value: " << Integer << ", " << String << '\n';
+ SW.printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false));
+ switch (Integer) {
+ case 0:
+ SW.printString("Description", StringRef("No Specific Requirements"));
+ break;
+ case 1:
+ SW.printString("Description", StringRef("AEABI Conformant"));
+ break;
+ default:
+ SW.printString("Description", StringRef("AEABI Non-Conformant"));
+ break;
+ }
+}
+
+void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "v6-style" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "If Available", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "If Available", "Not Permitted", "Permitted"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = { "Not Permitted", "Permitted" };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ static const char *Strings[] = {
+ "Not Permitted", "TrustZone", "Virtualization Extensions",
+ "TrustZone + Virtualization Extensions"
+ };
+
+ uint64_t Value = ParseInteger(Data, Offset);
+ StringRef ValueDesc =
+ (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
+ PrintAttribute(Tag, Value, ValueDesc);
+}
+
+void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset) {
+ uint64_t Value = ParseInteger(Data, Offset);
+ PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED");
+}
+
+void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset,
+ SmallVectorImpl<uint8_t> &IndexList) {
+ for (;;) {
+ unsigned Length;
+ uint64_t Value = decodeULEB128(Data + Offset, &Length);
+ Offset = Offset + Length;
+ if (Value == 0)
+ break;
+ IndexList.push_back(Value);
+ }
+}
+
+void ARMAttributeParser::ParseAttributeList(const uint8_t *Data,
+ uint32_t &Offset, uint32_t Length) {
+ while (Offset < Length) {
+ unsigned Length;
+ uint64_t Tag = decodeULEB128(Data + Offset, &Length);
+ Offset += Length;
+
+ bool Handled = false;
+ for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines);
+ AHI != AHE && !Handled; ++AHI) {
+ if (DisplayRoutines[AHI].Attribute == Tag) {
+ (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag),
+ Data, Offset);
+ Handled = true;
+ break;
+ }
+ }
+ if (!Handled) {
+ if (Tag < 32) {
+ errs() << "unhandled AEABI Tag " << Tag
+ << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n";
+ continue;
+ }
+
+ if (Tag % 2 == 0)
+ IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
+ else
+ StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
+ }
+ }
+}
+
+void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) {
+ uint32_t Offset = sizeof(uint32_t); /* SectionLength */
+
+ SW.printNumber("SectionLength", Length);
+
+ const char *VendorName = reinterpret_cast<const char*>(Data + Offset);
+ size_t VendorNameLength = std::strlen(VendorName);
+ SW.printString("Vendor", StringRef(VendorName, VendorNameLength));
+ Offset = Offset + VendorNameLength + 1;
+
+ if (StringRef(VendorName, VendorNameLength).lower() != "aeabi")
+ return;
+
+ while (Offset < Length) {
+ /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
+ uint8_t Tag = Data[Offset];
+ SW.printEnum("Tag", Tag, makeArrayRef(TagNames));
+ Offset = Offset + sizeof(Tag);
+
+ uint32_t Size =
+ *reinterpret_cast<const support::ulittle32_t*>(Data + Offset);
+ SW.printNumber("Size", Size);
+ Offset = Offset + sizeof(Size);
+
+ if (Size > Length) {
+ errs() << "subsection length greater than section length\n";
+ return;
+ }
+
+ StringRef ScopeName, IndexName;
+ SmallVector<uint8_t, 8> Indicies;
+ switch (Tag) {
+ case ARMBuildAttrs::File:
+ ScopeName = "FileAttributes";
+ break;
+ case ARMBuildAttrs::Section:
+ ScopeName = "SectionAttributes";
+ IndexName = "Sections";
+ ParseIndexList(Data, Offset, Indicies);
+ break;
+ case ARMBuildAttrs::Symbol:
+ ScopeName = "SymbolAttributes";
+ IndexName = "Symbols";
+ ParseIndexList(Data, Offset, Indicies);
+ break;
+ default:
+ errs() << "unrecognised tag: 0x" << utohexstr(Tag) << '\n';
+ return;
+ }
+
+ DictScope ASS(SW, ScopeName);
+
+ if (!Indicies.empty())
+ SW.printList(IndexName, Indicies);
+
+ ParseAttributeList(Data, Offset, Length);
+ }
+}
+
+void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section) {
+ size_t Offset = 1;
+ unsigned SectionNumber = 0;
+
+ while (Offset < Section.size()) {
+ uint32_t SectionLength =
+ *reinterpret_cast<const support::ulittle32_t*>(Section.data() + Offset);
+
+ SW.startLine() << "Section " << ++SectionNumber << " {\n";
+ SW.indent();
+
+ ParseSubsection(Section.data() + Offset, SectionLength);
+ Offset = Offset + SectionLength;
+
+ SW.unindent();
+ SW.startLine() << "}\n";
+ }
+}
+}
+
diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h
new file mode 100644
index 0000000..f924c83
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h
@@ -0,0 +1,124 @@
+//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
+#define LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
+
+#include "StreamWriter.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+
+namespace llvm {
+class StringRef;
+
+class ARMAttributeParser {
+ StreamWriter &SW;
+
+ struct DisplayHandler {
+ ARMBuildAttrs::AttrType Attribute;
+ void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType,
+ const uint8_t *, uint32_t &);
+ };
+ static const DisplayHandler DisplayRoutines[];
+
+ uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset);
+ StringRef ParseString(const uint8_t *Data, uint32_t &Offset);
+
+ void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+
+ void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc);
+
+ void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag,
+ const uint8_t *Data, uint32_t &Offset);
+ void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+ void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+ uint32_t &Offset);
+
+ void ParseAttributeList(const uint8_t *Data, uint32_t &Offset,
+ uint32_t Length);
+ void ParseIndexList(const uint8_t *Data, uint32_t &Offset,
+ SmallVectorImpl<uint8_t> &IndexList);
+ void ParseSubsection(const uint8_t *Data, uint32_t Length);
+public:
+ ARMAttributeParser(StreamWriter &SW) : SW(SW) {}
+
+ void Parse(ArrayRef<uint8_t> Section);
+};
+
+}
+
+#endif
+
diff --git a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
new file mode 100644
index 0000000..b15421d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
@@ -0,0 +1,552 @@
+//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
+#define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
+
+#include "Error.h"
+#include "StreamWriter.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Support/ARMEHABI.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/type_traits.h"
+
+namespace llvm {
+namespace ARM {
+namespace EHABI {
+
+class OpcodeDecoder {
+ StreamWriter &SW;
+ raw_ostream &OS;
+
+ struct RingEntry {
+ uint8_t Mask;
+ uint8_t Value;
+ void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI);
+ };
+ static const RingEntry Ring[];
+
+ void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10011101(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10011111(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10110000(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10110001_0000iiii(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10110010_uleb128(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10110011_sssscccc(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_101101nn(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11000110_sssscccc(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11000111_0000iiii(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11001000_sssscccc(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11001001_sssscccc(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI);
+ void Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI);
+
+ void PrintGPR(uint16_t GPRMask);
+ void PrintRegisters(uint32_t Mask, StringRef Prefix);
+
+public:
+ OpcodeDecoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {}
+ void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length);
+};
+
+const OpcodeDecoder::RingEntry OpcodeDecoder::Ring[] = {
+ { 0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx },
+ { 0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx },
+ { 0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii },
+ { 0xff, 0x9d, &OpcodeDecoder::Decode_10011101 },
+ { 0xff, 0x9f, &OpcodeDecoder::Decode_10011111 },
+ { 0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn },
+ { 0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn },
+ { 0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn },
+ { 0xff, 0xb0, &OpcodeDecoder::Decode_10110000 },
+ { 0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii },
+ { 0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128 },
+ { 0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc },
+ { 0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn },
+ { 0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn },
+ { 0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc },
+ { 0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii },
+ { 0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc },
+ { 0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc },
+ { 0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy },
+ { 0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn },
+ { 0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn },
+ { 0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy },
+};
+
+void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode,
+ ((Opcode & 0x3f) << 2) + 4);
+}
+void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode,
+ ((Opcode & 0x3f) << 2) + 4);
+}
+void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode0 = Opcodes[OI++ ^ 3];
+ uint8_t Opcode1 = Opcodes[OI++ ^ 3];
+
+ uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12);
+ SW.startLine()
+ << format("0x%02X 0x%02X ; %s",
+ Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind");
+ if (GPRMask)
+ PrintGPR(GPRMask);
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; reserved (ARM MOVrr)\n", Opcode);
+}
+void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; reserved (WiMMX MOVrr)\n", Opcode);
+}
+void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; vsp = r%u\n", Opcode, (Opcode & 0x0f));
+}
+void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; pop ", Opcode);
+ PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4));
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; pop ", Opcode);
+ PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14));
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; finish\n", Opcode);
+}
+void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode0 = Opcodes[OI++ ^ 3];
+ uint8_t Opcode1 = Opcodes[OI++ ^ 3];
+
+ SW.startLine()
+ << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
+ ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
+ if (((Opcode1 & 0xf0) == 0x00) && Opcode1)
+ PrintGPR((Opcode1 & 0x0f));
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ", Opcode);
+
+ SmallVector<uint8_t, 4> ULEB;
+ do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80);
+
+ for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)
+ OS << format("0x%02X ", ULEB[BI]);
+
+ uint64_t Value = 0;
+ for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)
+ Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI));
+
+ OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2));
+}
+void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode0 = Opcodes[OI++ ^ 3];
+ uint8_t Opcode1 = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
+ uint8_t Start = ((Opcode1 & 0xf0) >> 4);
+ uint8_t Count = ((Opcode1 & 0x0f) >> 0);
+ PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; spare\n", Opcode);
+}
+void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; pop ", Opcode);
+ PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode0 = Opcodes[OI++ ^ 3];
+ uint8_t Opcode1 = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
+ uint8_t Start = ((Opcode1 & 0xf0) >> 4);
+ uint8_t Count = ((Opcode1 & 0x0f) >> 0);
+ PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode0 = Opcodes[OI++ ^ 3];
+ uint8_t Opcode1 = Opcodes[OI++ ^ 3];
+ SW.startLine()
+ << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,
+ ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");
+ if ((Opcode1 & 0xf0) == 0x00 && Opcode1)
+ PrintRegisters(Opcode1 & 0x0f, "wCGR");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode0 = Opcodes[OI++ ^ 3];
+ uint8_t Opcode1 = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
+ uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4);
+ uint8_t Count = ((Opcode1 & 0x0f) >> 0);
+ PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes,
+ unsigned &OI) {
+ uint8_t Opcode0 = Opcodes[OI++ ^ 3];
+ uint8_t Opcode1 = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);
+ uint8_t Start = ((Opcode1 & 0xf0) >> 4);
+ uint8_t Count = ((Opcode1 & 0x0f) >> 0);
+ PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; spare\n", Opcode);
+}
+void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; pop ", Opcode);
+ PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; pop ", Opcode);
+ PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");
+ OS << '\n';
+}
+void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; spare\n", Opcode);
+}
+
+void OpcodeDecoder::PrintGPR(uint16_t GPRMask) {
+ static const char *GPRRegisterNames[16] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "fp", "ip", "sp", "lr", "pc"
+ };
+
+ OS << '{';
+ bool Comma = false;
+ for (unsigned RI = 0, RE = 17; RI < RE; ++RI) {
+ if (GPRMask & (1 << RI)) {
+ if (Comma)
+ OS << ", ";
+ OS << GPRRegisterNames[RI];
+ Comma = true;
+ }
+ }
+ OS << '}';
+}
+
+void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) {
+ OS << '{';
+ bool Comma = false;
+ for (unsigned RI = 0, RE = 32; RI < RE; ++RI) {
+ if (VFPMask & (1 << RI)) {
+ if (Comma)
+ OS << ", ";
+ OS << Prefix << RI;
+ Comma = true;
+ }
+ }
+ OS << '}';
+}
+
+void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) {
+ for (unsigned OCI = Offset; OCI < Length + Offset; ) {
+ bool Decoded = false;
+ for (unsigned REI = 0, REE = array_lengthof(Ring);
+ REI != REE && !Decoded; ++REI) {
+ if ((Opcodes[OCI ^ 3] & Ring[REI].Mask) == Ring[REI].Value) {
+ (this->*Ring[REI].Routine)(Opcodes, OCI);
+ Decoded = true;
+ break;
+ }
+ }
+ if (!Decoded)
+ SW.startLine() << format("0x%02X ; reserved\n", Opcodes[OCI++ ^ 3]);
+ }
+}
+
+template <typename ET>
+class PrinterContext {
+ StreamWriter &SW;
+ const object::ELFFile<ET> *ELF;
+
+ typedef typename object::ELFFile<ET>::Elf_Sym Elf_Sym;
+ typedef typename object::ELFFile<ET>::Elf_Shdr Elf_Shdr;
+
+ typedef typename object::ELFFile<ET>::Elf_Rel_Iter Elf_Rel_iterator;
+ typedef typename object::ELFFile<ET>::Elf_Sym_Iter Elf_Sym_iterator;
+ typedef typename object::ELFFile<ET>::Elf_Shdr_Iter Elf_Shdr_iterator;
+
+ static const size_t IndexTableEntrySize;
+
+ static uint64_t PREL31(uint32_t Address, uint32_t Place) {
+ uint64_t Location = Address & 0x7fffffff;
+ if (Location & 0x04000000)
+ Location |= (uint64_t) ~0x7fffffff;
+ return Location + Place;
+ }
+
+ ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const;
+ const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex,
+ off_t IndexTableOffset) const;
+
+ void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const;
+ void PrintExceptionTable(const Elf_Shdr *IT, const Elf_Shdr *EHT,
+ uint64_t TableEntryOffset) const;
+ void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const;
+
+public:
+ PrinterContext(StreamWriter &Writer, const object::ELFFile<ET> *File)
+ : SW(Writer), ELF(File) {}
+
+ void PrintUnwindInformation() const;
+};
+
+template <typename ET>
+const size_t PrinterContext<ET>::IndexTableEntrySize = 8;
+
+template <typename ET>
+ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(unsigned Section,
+ uint64_t Address) const {
+ for (Elf_Sym_iterator SI = ELF->begin_symbols(), SE = ELF->end_symbols();
+ SI != SE; ++SI)
+ if (SI->st_shndx == Section && SI->st_value == Address &&
+ SI->getType() == ELF::STT_FUNC)
+ return ELF->getSymbolName(SI);
+ return readobj_error::unknown_symbol;
+}
+
+template <typename ET>
+const typename object::ELFFile<ET>::Elf_Shdr *
+PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex,
+ off_t IndexTableOffset) const {
+ /// Iterate through the sections, searching for the relocation section
+ /// associated with the unwind index table section specified by
+ /// IndexSectionIndex. Iterate the associated section searching for the
+ /// relocation associated with the index table entry specified by
+ /// IndexTableOffset. The symbol is the section symbol for the exception
+ /// handling table. Use this symbol to recover the actual exception handling
+ /// table.
+
+ for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections();
+ SI != SE; ++SI) {
+ if (SI->sh_type == ELF::SHT_REL && SI->sh_info == IndexSectionIndex) {
+ for (Elf_Rel_iterator RI = ELF->begin_rel(&*SI), RE = ELF->end_rel(&*SI);
+ RI != RE; ++RI) {
+ if (RI->r_offset == static_cast<unsigned>(IndexTableOffset)) {
+ typename object::ELFFile<ET>::Elf_Rela RelA;
+ RelA.r_offset = RI->r_offset;
+ RelA.r_info = RI->r_info;
+ RelA.r_addend = 0;
+
+ std::pair<const Elf_Shdr *, const Elf_Sym *> Symbol =
+ ELF->getRelocationSymbol(&(*SI), &RelA);
+
+ return ELF->getSection(Symbol.second);
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+template <typename ET>
+void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT,
+ const Elf_Shdr *EHT,
+ uint64_t TableEntryOffset) const {
+ ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(EHT);
+ if (!Contents)
+ return;
+
+ /// ARM EHABI Section 6.2 - The generic model
+ ///
+ /// An exception-handling table entry for the generic model is laid out as:
+ ///
+ /// 3 3
+ /// 1 0 0
+ /// +-+------------------------------+
+ /// |0| personality routine offset |
+ /// +-+------------------------------+
+ /// | personality routine data ... |
+ ///
+ ///
+ /// ARM EHABI Section 6.3 - The ARM-defined compact model
+ ///
+ /// An exception-handling table entry for the compact model looks like:
+ ///
+ /// 3 3 2 2 2 2
+ /// 1 0 8 7 4 3 0
+ /// +-+---+----+-----------------------+
+ /// |1| 0 | Ix | data for pers routine |
+ /// +-+---+----+-----------------------+
+ /// | more personality routine data |
+
+ const support::ulittle32_t Word =
+ *reinterpret_cast<const support::ulittle32_t *>(Contents->data() + TableEntryOffset);
+
+ if (Word & 0x80000000) {
+ SW.printString("Model", StringRef("Compact"));
+
+ unsigned PersonalityIndex = (Word & 0x0f000000) >> 24;
+ SW.printNumber("PersonalityIndex", PersonalityIndex);
+
+ switch (PersonalityIndex) {
+ case AEABI_UNWIND_CPP_PR0:
+ PrintOpcodes(Contents->data() + TableEntryOffset, 3, 1);
+ break;
+ case AEABI_UNWIND_CPP_PR1:
+ case AEABI_UNWIND_CPP_PR2:
+ unsigned AdditionalWords = (Word & 0x00ff0000) >> 16;
+ PrintOpcodes(Contents->data() + TableEntryOffset, 2 + 4 * AdditionalWords,
+ 2);
+ break;
+ }
+ } else {
+ SW.printString("Model", StringRef("Generic"));
+
+ uint64_t Address = PREL31(Word, EHT->sh_addr);
+ SW.printHex("PersonalityRoutineAddress", Address);
+ if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address))
+ SW.printString("PersonalityRoutineName", *Name);
+ }
+}
+
+template <typename ET>
+void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry,
+ size_t Length, off_t Offset) const {
+ ListScope OCC(SW, "Opcodes");
+ OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length);
+}
+
+template <typename ET>
+void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
+ const Elf_Shdr *IT) const {
+ ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(IT);
+ if (!Contents)
+ return;
+
+ /// ARM EHABI Section 5 - Index Table Entries
+ /// * The first word contains a PREL31 offset to the start of a function with
+ /// bit 31 clear
+ /// * The second word contains one of:
+ /// - The PREL31 offset of the start of the table entry for the function,
+ /// with bit 31 clear
+ /// - The exception-handling table entry itself with bit 31 set
+ /// - The special bit pattern EXIDX_CANTUNWIND, indicating that associated
+ /// frames cannot be unwound
+
+ const support::ulittle32_t *Data =
+ reinterpret_cast<const support::ulittle32_t *>(Contents->data());
+ const unsigned Entries = IT->sh_size / IndexTableEntrySize;
+
+ ListScope E(SW, "Entries");
+ for (unsigned Entry = 0; Entry < Entries; ++Entry) {
+ DictScope E(SW, "Entry");
+
+ const support::ulittle32_t Word0 =
+ Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 0];
+ const support::ulittle32_t Word1 =
+ Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 1];
+
+ if (Word0 & 0x80000000) {
+ errs() << "corrupt unwind data in section " << SectionIndex << "\n";
+ continue;
+ }
+
+ const uint64_t Offset = PREL31(Word0, IT->sh_addr);
+ SW.printHex("FunctionAddress", Offset);
+ if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset))
+ SW.printString("FunctionName", *Name);
+
+ if (Word1 == EXIDX_CANTUNWIND) {
+ SW.printString("Model", StringRef("CantUnwind"));
+ continue;
+ }
+
+ if (Word1 & 0x80000000) {
+ SW.printString("Model", StringRef("Compact (Inline)"));
+
+ unsigned PersonalityIndex = (Word1 & 0x0f000000) >> 24;
+ SW.printNumber("PersonalityIndex", PersonalityIndex);
+
+ PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1);
+ } else {
+ const Elf_Shdr *EHT =
+ FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4);
+
+ if (ErrorOr<StringRef> Name = ELF->getSectionName(EHT))
+ SW.printString("ExceptionHandlingTable", *Name);
+
+ uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr);
+ SW.printHex("TableEntryOffset", TableEntryOffset);
+
+ PrintExceptionTable(IT, EHT, TableEntryOffset);
+ }
+ }
+}
+
+template <typename ET>
+void PrinterContext<ET>::PrintUnwindInformation() const {
+ DictScope UI(SW, "UnwindInformation");
+
+ int SectionIndex = 0;
+ for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections();
+ SI != SE; ++SI, ++SectionIndex) {
+ if (SI->sh_type == ELF::SHT_ARM_EXIDX) {
+ const Elf_Shdr *IT = &(*SI);
+
+ DictScope UIT(SW, "UnwindIndexTable");
+
+ SW.printNumber("SectionIndex", SectionIndex);
+ if (ErrorOr<StringRef> SectionName = ELF->getSectionName(IT))
+ SW.printString("SectionName", *SectionName);
+ SW.printHex("SectionOffset", IT->sh_offset);
+
+ PrintIndexTable(SectionIndex, IT);
+ }
+ }
+}
+}
+}
+}
+
+#endif
+
diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
new file mode 100644
index 0000000..62252fc
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -0,0 +1,735 @@
+//===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Windows on ARM uses a series of serialised data structures (RuntimeFunction)
+// to create a table of information for unwinding. In order to conserve space,
+// there are two different ways that this data is represented.
+//
+// For functions with canonical forms for the prologue and epilogue, the data
+// can be stored in a "packed" form. In this case, the data is packed into the
+// RuntimeFunction's remaining 30-bits and can fully describe the entire frame.
+//
+// +---------------------------------------+
+// | Function Entry Address |
+// +---------------------------------------+
+// | Packed Form Data |
+// +---------------------------------------+
+//
+// This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is
+// associated with such a frame as they can be derived from the provided data.
+// The decoder does not synthesize this data as it is unnecessary for the
+// purposes of validation, with the synthesis being required only by a proper
+// unwinder.
+//
+// For functions that are large or do not match canonical forms, the data is
+// split up into two portions, with the actual data residing in the "exception
+// data" table (.xdata) with a reference to the entry from the "procedure data"
+// (.pdata) entry.
+//
+// The exception data contains information about the frame setup, all of the
+// epilouge scopes (for functions for which there are multiple exit points) and
+// the associated exception handler. Additionally, the entry contains byte-code
+// describing how to unwind the function (c.f. Decoder::decodeOpcodes).
+//
+// +---------------------------------------+
+// | Function Entry Address |
+// +---------------------------------------+
+// | Exception Data Entry Address |
+// +---------------------------------------+
+//
+// This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must
+// first resolve the exception data entry address. This structure
+// (ExceptionDataRecord) has a variable sized header
+// (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as
+// the packed form. However, because this information is insufficient to
+// synthesize the unwinding, there are associated unwinding bytecode which make
+// up the bulk of the Decoder.
+//
+// The decoder itself is table-driven, using the first byte to determine the
+// opcode and dispatching to the associated printing routine. The bytecode
+// itself is a variable length instruction encoding that can fully describe the
+// state of the stack and the necessary operations for unwinding to the
+// beginning of the frame.
+//
+// The byte-code maintains a 1-1 instruction mapping, indicating both the width
+// of the instruction (Thumb2 instructions are variable length, 16 or 32 bits
+// wide) allowing the program to unwind from any point in the prologue, body, or
+// epilogue of the function.
+
+#include "ARMWinEHPrinter.h"
+#include "Error.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ARMWinEH.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support;
+
+namespace llvm {
+raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) {
+ switch (RT) {
+ case ARM::WinEH::ReturnType::RT_POP:
+ OS << "pop {pc}";
+ break;
+ case ARM::WinEH::ReturnType::RT_B:
+ OS << "b target";
+ break;
+ case ARM::WinEH::ReturnType::RT_BW:
+ OS << "b.w target";
+ break;
+ case ARM::WinEH::ReturnType::RT_NoEpilogue:
+ OS << "(no epilogue)";
+ break;
+ }
+ return OS;
+}
+}
+
+static std::string formatSymbol(StringRef Name, uint64_t Address,
+ uint64_t Offset = 0) {
+ std::string Buffer;
+ raw_string_ostream OS(Buffer);
+
+ if (!Name.empty())
+ OS << Name << " ";
+
+ if (Offset)
+ OS << format("+0x%X (0x%" PRIX64 ")", Offset, Address);
+ else if (!Name.empty())
+ OS << format("(0x%" PRIX64 ")", Address);
+ else
+ OS << format("0x%" PRIX64, Address);
+
+ return OS.str();
+}
+
+namespace llvm {
+namespace ARM {
+namespace WinEH {
+const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction);
+
+// TODO name the uops more appropriately
+const Decoder::RingEntry Decoder::Ring[] = {
+ { 0x80, 0x00, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit)
+ { 0xc0, 0x80, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit)
+ { 0xf0, 0xc0, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit)
+ { 0xf8, 0xd0, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit)
+ { 0xf8, 0xd8, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit)
+ { 0xf8, 0xe0, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit)
+ { 0xfc, 0xe8, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit)
+ { 0xfe, 0xec, &Decoder::opcode_1110110L }, // UOP_POP (16-bit)
+ { 0xff, 0xee, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit)
+ // UOP_PUSH_MACHINE_FRAME
+ // UOP_PUSH_CONTEXT
+ // UOP_PUSH_TRAP_FRAME
+ // UOP_REDZONE_RESTORE_LR
+ { 0xff, 0xef, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit)
+ { 0xff, 0xf5, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit)
+ { 0xff, 0xf6, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit)
+ { 0xff, 0xf7, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit)
+ { 0xff, 0xf8, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit)
+ { 0xff, 0xf9, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit)
+ { 0xff, 0xfa, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit)
+ { 0xff, 0xfb, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit)
+ { 0xff, 0xfc, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit)
+ { 0xff, 0xfd, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END
+ { 0xff, 0xfe, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END
+ { 0xff, 0xff, &Decoder::opcode_11111111 }, // UOP_END
+};
+
+void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask) {
+ static const char * const GPRRegisterNames[16] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "ip", "sp", "lr", "pc",
+ };
+
+ const uint16_t GPRMask = std::get<0>(RegisterMask);
+ const uint16_t VFPMask = std::get<1>(RegisterMask);
+
+ OS << '{';
+ bool Comma = false;
+ for (unsigned RI = 0, RE = 11; RI < RE; ++RI) {
+ if (GPRMask & (1 << RI)) {
+ if (Comma)
+ OS << ", ";
+ OS << GPRRegisterNames[RI];
+ Comma = true;
+ }
+ }
+ for (unsigned RI = 0, RE = 32; RI < RE; ++RI) {
+ if (VFPMask & (1 << RI)) {
+ if (Comma)
+ OS << ", ";
+ OS << "d" << unsigned(RI);
+ Comma = true;
+ }
+ }
+ for (unsigned RI = 11, RE = 16; RI < RE; ++RI) {
+ if (GPRMask & (1 << RI)) {
+ if (Comma)
+ OS << ", ";
+ OS << GPRRegisterNames[RI];
+ Comma = true;
+ }
+ }
+ OS << '}';
+}
+
+ErrorOr<object::SectionRef>
+Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) {
+ for (const auto &Section : COFF.sections()) {
+ uint64_t Address = Section.getAddress();
+ uint64_t Size = Section.getSize();
+
+ if (VA >= Address && (VA - Address) <= Size)
+ return Section;
+ }
+ return readobj_error::unknown_symbol;
+}
+
+ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF,
+ uint64_t VA, bool FunctionOnly) {
+ for (const auto &Symbol : COFF.symbols()) {
+ if (FunctionOnly) {
+ SymbolRef::Type Type;
+ if (std::error_code EC = Symbol.getType(Type))
+ return EC;
+ if (Type != SymbolRef::ST_Function)
+ continue;
+ }
+
+ uint64_t Address;
+ if (std::error_code EC = Symbol.getAddress(Address))
+ return EC;
+ if (Address == VA)
+ return Symbol;
+ }
+ return readobj_error::unknown_symbol;
+}
+
+ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &,
+ const SectionRef &Section,
+ uint64_t Offset) {
+ for (const auto &Relocation : Section.relocations()) {
+ uint64_t RelocationOffset;
+ if (auto Error = Relocation.getOffset(RelocationOffset))
+ return Error;
+ if (RelocationOffset == Offset)
+ return *Relocation.getSymbol();
+ }
+ return readobj_error::unknown_symbol;
+}
+
+bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint8_t Imm = OC[Offset] & 0x7f;
+ SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n",
+ OC[Offset],
+ static_cast<const char *>(Prologue ? "sub" : "add"),
+ Imm);
+ ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ unsigned Link = (OC[Offset] & 0x20) >> 5;
+ uint16_t RegisterMask = (Link << (Prologue ? 14 : 15))
+ | ((OC[Offset + 0] & 0x1f) << 8)
+ | ((OC[Offset + 1] & 0xff) << 0);
+ assert((~RegisterMask & (1 << 13)) && "sp must not be set");
+ assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set");
+
+ SW.startLine() << format("0x%02x 0x%02x ; %s.w ",
+ OC[Offset + 0], OC[Offset + 1],
+ Prologue ? "push" : "pop");
+ printRegisters(std::make_pair(RegisterMask, 0));
+ OS << '\n';
+
+ ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ if (Prologue)
+ SW.startLine() << format("0x%02x ; mov r%u, sp\n",
+ OC[Offset], OC[Offset] & 0xf);
+ else
+ SW.startLine() << format("0x%02x ; mov sp, r%u\n",
+ OC[Offset], OC[Offset] & 0xf);
+ ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ unsigned Link = (OC[Offset] & 0x4) >> 3;
+ unsigned Count = (OC[Offset] & 0x3);
+
+ uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
+ | (((1 << (Count + 1)) - 1) << 4);
+
+ SW.startLine() << format("0x%02x ; %s ", OC[Offset],
+ Prologue ? "push" : "pop");
+ printRegisters(std::make_pair(GPRMask, 0));
+ OS << '\n';
+
+ ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ unsigned Link = (OC[Offset] & 0x4) >> 2;
+ unsigned Count = (OC[Offset] & 0x3) + 4;
+
+ uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
+ | (((1 << (Count + 1)) - 1) << 4);
+
+ SW.startLine() << format("0x%02x ; %s.w ", OC[Offset],
+ Prologue ? "push" : "pop");
+ printRegisters(std::make_pair(GPRMask, 0));
+ OS << '\n';
+
+ ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ unsigned High = (OC[Offset] & 0x7);
+ uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8);
+
+ SW.startLine() << format("0x%02x ; %s ", OC[Offset],
+ Prologue ? "vpush" : "vpop");
+ printRegisters(std::make_pair(0, VFPMask));
+ OS << '\n';
+
+ ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0);
+
+ SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n",
+ OC[Offset + 0], OC[Offset + 1],
+ static_cast<const char *>(Prologue ? "sub" : "add"),
+ Imm);
+
+ ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15))
+ | ((OC[Offset + 1] & 0xff) << 0);
+
+ SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],
+ OC[Offset + 1], Prologue ? "push" : "pop");
+ printRegisters(std::make_pair(GPRMask, 0));
+ OS << '\n';
+
+ ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ assert(!Prologue && "may not be used in prologue");
+
+ if (OC[Offset + 1] & 0xf0)
+ SW.startLine() << format("0x%02x 0x%02x ; reserved\n",
+ OC[Offset + 0], OC[Offset + 1]);
+ else
+ SW.startLine()
+ << format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n",
+ OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f);
+
+ ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ assert(!Prologue && "may not be used in prologue");
+
+ if (OC[Offset + 1] & 0xf0)
+ SW.startLine() << format("0x%02x 0x%02x ; reserved\n",
+ OC[Offset + 0], OC[Offset + 1]);
+ else
+ SW.startLine()
+ << format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n",
+ OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);
+
+ ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
+ unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
+ uint32_t VFPMask = ((1 << (End - Start)) - 1) << Start;
+
+ SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],
+ OC[Offset + 1], Prologue ? "vpush" : "vpop");
+ printRegisters(std::make_pair(0, VFPMask));
+ OS << '\n';
+
+ ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
+ unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
+ uint32_t VFPMask = ((1 << (End - Start)) - 1) << 16;
+
+ SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],
+ OC[Offset + 1], Prologue ? "vpush" : "vpop");
+ printRegisters(std::make_pair(0, VFPMask));
+ OS << '\n';
+
+ ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
+
+ SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",
+ OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
+ static_cast<const char *>(Prologue ? "sub" : "add"),
+ Imm);
+
+ ++Offset, ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint32_t Imm = (OC[Offset + 1] << 16)
+ | (OC[Offset + 2] << 8)
+ | (OC[Offset + 3] << 0);
+
+ SW.startLine()
+ << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",
+ OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
+ static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
+
+ ++Offset, ++Offset, ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
+
+ SW.startLine()
+ << format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",
+ OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
+ static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
+
+ ++Offset, ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint32_t Imm = (OC[Offset + 1] << 16)
+ | (OC[Offset + 2] << 8)
+ | (OC[Offset + 3] << 0);
+
+ SW.startLine()
+ << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",
+ OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
+ static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
+
+ ++Offset, ++Offset, ++Offset, ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ SW.startLine() << format("0x%02x ; nop\n", OC[Offset]);
+ ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]);
+ ++Offset;
+ return false;
+}
+
+bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ SW.startLine() << format("0x%02x ; b\n", OC[Offset]);
+ ++Offset;
+ return true;
+}
+
+bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ SW.startLine() << format("0x%02x ; b.w\n", OC[Offset]);
+ ++Offset;
+ return true;
+}
+
+bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ ++Offset;
+ return true;
+}
+
+void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
+ bool Prologue) {
+ assert((!Prologue || Offset == 0) && "prologue should always use offset 0");
+
+ bool Terminated = false;
+ for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) {
+ for (unsigned DI = 0;; ++DI) {
+ if ((Opcodes[OI] & Ring[DI].Mask) == Ring[DI].Value) {
+ Terminated = (this->*Ring[DI].Routine)(Opcodes.data(), OI, 0, Prologue);
+ break;
+ }
+ assert(DI < array_lengthof(Ring) && "unhandled opcode");
+ }
+ }
+}
+
+bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,
+ const SectionRef &Section,
+ uint64_t FunctionAddress, uint64_t VA) {
+ ArrayRef<uint8_t> Contents;
+ if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
+ return false;
+
+ uint64_t SectionVA = Section.getAddress();
+ uint64_t Offset = VA - SectionVA;
+ const ulittle32_t *Data =
+ reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
+ const ExceptionDataRecord XData(Data);
+
+ DictScope XRS(SW, "ExceptionData");
+ SW.printNumber("FunctionLength", XData.FunctionLength() << 1);
+ SW.printNumber("Version", XData.Vers());
+ SW.printBoolean("ExceptionData", XData.X());
+ SW.printBoolean("EpiloguePacked", XData.E());
+ SW.printBoolean("Fragment", XData.F());
+ SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes",
+ XData.EpilogueCount());
+ SW.printNumber("ByteCodeLength",
+ static_cast<uint64_t>(XData.CodeWords() * sizeof(uint32_t)));
+
+ if (XData.E()) {
+ ArrayRef<uint8_t> UC = XData.UnwindByteCode();
+ if (!XData.F()) {
+ ListScope PS(SW, "Prologue");
+ decodeOpcodes(UC, 0, /*Prologue=*/true);
+ }
+ if (XData.EpilogueCount()) {
+ ListScope ES(SW, "Epilogue");
+ decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false);
+ }
+ } else {
+ ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes();
+ ListScope ESS(SW, "EpilogueScopes");
+ for (const EpilogueScope ES : EpilogueScopes) {
+ DictScope ESES(SW, "EpilogueScope");
+ SW.printNumber("StartOffset", ES.EpilogueStartOffset());
+ SW.printNumber("Condition", ES.Condition());
+ SW.printNumber("EpilogueStartIndex", ES.EpilogueStartIndex());
+
+ ListScope Opcodes(SW, "Opcodes");
+ decodeOpcodes(XData.UnwindByteCode(), ES.EpilogueStartIndex(),
+ /*Prologue=*/false);
+ }
+ }
+
+ if (XData.X()) {
+ const uint32_t Address = XData.ExceptionHandlerRVA();
+ const uint32_t Parameter = XData.ExceptionHandlerParameter();
+ const size_t HandlerOffset = HeaderWords(XData)
+ + (XData.E() ? 0 : XData.EpilogueCount())
+ + XData.CodeWords();
+
+ ErrorOr<SymbolRef> Symbol =
+ getRelocatedSymbol(COFF, Section, HandlerOffset * sizeof(uint32_t));
+ if (!Symbol)
+ Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true);
+
+ StringRef Name;
+ if (Symbol)
+ Symbol->getName(Name);
+
+ ListScope EHS(SW, "ExceptionHandler");
+ SW.printString("Routine", formatSymbol(Name, Address));
+ SW.printHex("Parameter", Parameter);
+ }
+
+ return true;
+}
+
+bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,
+ const SectionRef Section, uint64_t Offset,
+ unsigned Index, const RuntimeFunction &RF) {
+ assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
+ "packed entry cannot be treated as an unpacked entry");
+
+ ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);
+ if (!Function)
+ Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true);
+
+ ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4);
+ if (!XDataRecord)
+ XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA());
+
+ if (!RF.BeginAddress && !Function)
+ return false;
+ if (!RF.UnwindData && !XDataRecord)
+ return false;
+
+ StringRef FunctionName;
+ uint64_t FunctionAddress;
+ if (Function) {
+ Function->getName(FunctionName);
+ Function->getAddress(FunctionAddress);
+ } else {
+ const pe32_header *PEHeader;
+ if (COFF.getPE32Header(PEHeader))
+ return false;
+ FunctionAddress = PEHeader->ImageBase + RF.BeginAddress;
+ }
+
+ SW.printString("Function", formatSymbol(FunctionName, FunctionAddress));
+
+ if (XDataRecord) {
+ StringRef Name;
+ uint64_t Address;
+
+ XDataRecord->getName(Name);
+ XDataRecord->getAddress(Address);
+
+ SW.printString("ExceptionRecord", formatSymbol(Name, Address));
+
+ section_iterator SI = COFF.section_end();
+ if (XDataRecord->getSection(SI))
+ return false;
+
+ return dumpXDataRecord(COFF, *SI, FunctionAddress, Address);
+ } else {
+ const pe32_header *PEHeader;
+ if (COFF.getPE32Header(PEHeader))
+ return false;
+
+ uint64_t Address = PEHeader->ImageBase + RF.ExceptionInformationRVA();
+ SW.printString("ExceptionRecord", formatSymbol("", Address));
+
+ ErrorOr<SectionRef> Section =
+ getSectionContaining(COFF, RF.ExceptionInformationRVA());
+ if (!Section)
+ return false;
+
+ return dumpXDataRecord(COFF, *Section, FunctionAddress,
+ RF.ExceptionInformationRVA());
+ }
+}
+
+bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,
+ const SectionRef Section, uint64_t Offset,
+ unsigned Index, const RuntimeFunction &RF) {
+ assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "unpacked entry cannot be treated as a packed entry");
+
+ ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);
+ if (!Function)
+ Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true);
+
+ StringRef FunctionName;
+ uint64_t FunctionAddress;
+ if (Function) {
+ Function->getName(FunctionName);
+ Function->getAddress(FunctionAddress);
+ } else {
+ const pe32_header *PEHeader;
+ if (COFF.getPE32Header(PEHeader))
+ return false;
+ FunctionAddress = PEHeader->ImageBase + RF.BeginAddress;
+ }
+
+ SW.printString("Function", formatSymbol(FunctionName, FunctionAddress));
+ SW.printBoolean("Fragment",
+ RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
+ SW.printNumber("FunctionLength", RF.FunctionLength());
+ SW.startLine() << "ReturnType: " << RF.Ret() << '\n';
+ SW.printBoolean("HomedParameters", RF.H());
+ SW.startLine() << "SavedRegisters: ";
+ printRegisters(SavedRegisterMask(RF));
+ OS << '\n';
+ SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2);
+
+ return true;
+}
+
+bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,
+ const SectionRef Section, unsigned Index,
+ ArrayRef<uint8_t> Contents) {
+ uint64_t Offset = PDataEntrySize * Index;
+ const ulittle32_t *Data =
+ reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
+
+ const RuntimeFunction Entry(Data);
+ DictScope RFS(SW, "RuntimeFunction");
+ if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked)
+ return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry);
+ return dumpPackedEntry(COFF, Section, Offset, Index, Entry);
+}
+
+void Decoder::dumpProcedureData(const COFFObjectFile &COFF,
+ const SectionRef Section) {
+ ArrayRef<uint8_t> Contents;
+ if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
+ return;
+
+ if (Contents.size() % PDataEntrySize) {
+ errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n";
+ return;
+ }
+
+ for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI)
+ if (!dumpProcedureDataEntry(COFF, Section, EI, Contents))
+ break;
+}
+
+std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
+ for (const auto &Section : COFF.sections()) {
+ StringRef SectionName;
+ if (std::error_code EC =
+ COFF.getSectionName(COFF.getCOFFSection(Section), SectionName))
+ return EC;
+
+ if (SectionName.startswith(".pdata"))
+ dumpProcedureData(COFF, Section);
+ }
+ return std::error_code();
+}
+}
+}
+}
diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
new file mode 100644
index 0000000..274ef11
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
@@ -0,0 +1,117 @@
+//===--- ARMWinEHPrinter.h - Windows on ARM Unwind Information Printer ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMWINEHPRINTER_H
+#define LLVM_TOOLS_LLVM_READOBJ_ARMWINEHPRINTER_H
+
+#include "StreamWriter.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/ErrorOr.h"
+
+namespace llvm {
+namespace ARM {
+namespace WinEH {
+class RuntimeFunction;
+
+class Decoder {
+ static const size_t PDataEntrySize;
+
+ StreamWriter &SW;
+ raw_ostream &OS;
+
+ struct RingEntry {
+ uint8_t Mask;
+ uint8_t Value;
+ bool (Decoder::*Routine)(const uint8_t *, unsigned &, unsigned, bool);
+ };
+ static const RingEntry Ring[];
+
+ bool opcode_0xxxxxxx(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_10Lxxxxx(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_1100xxxx(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11010Lxx(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11011Lxx(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11100xxx(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_111010xx(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_1110110L(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11101110(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11101111(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11110101(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11110110(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11110111(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111000(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111001(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111010(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111011(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111100(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111101(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111110(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_11111111(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+
+ void decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
+ bool Prologue);
+
+ void printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask);
+
+ ErrorOr<object::SectionRef>
+ getSectionContaining(const object::COFFObjectFile &COFF, uint64_t Address);
+
+ ErrorOr<object::SymbolRef>
+ getSymbol(const object::COFFObjectFile &COFF, uint64_t Address,
+ bool FunctionOnly = false);
+
+ ErrorOr<object::SymbolRef>
+ getRelocatedSymbol(const object::COFFObjectFile &COFF,
+ const object::SectionRef &Section, uint64_t Offset);
+
+ bool dumpXDataRecord(const object::COFFObjectFile &COFF,
+ const object::SectionRef &Section,
+ uint64_t FunctionAddress, uint64_t VA);
+ bool dumpUnpackedEntry(const object::COFFObjectFile &COFF,
+ const object::SectionRef Section, uint64_t Offset,
+ unsigned Index, const RuntimeFunction &Entry);
+ bool dumpPackedEntry(const object::COFFObjectFile &COFF,
+ const object::SectionRef Section, uint64_t Offset,
+ unsigned Index, const RuntimeFunction &Entry);
+ bool dumpProcedureDataEntry(const object::COFFObjectFile &COFF,
+ const object::SectionRef Section, unsigned Entry,
+ ArrayRef<uint8_t> Contents);
+ void dumpProcedureData(const object::COFFObjectFile &COFF,
+ const object::SectionRef Section);
+
+public:
+ Decoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {}
+ std::error_code dumpProcedureData(const object::COFFObjectFile &COFF);
+};
+}
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
new file mode 100644
index 0000000..1412111
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -0,0 +1,1142 @@
+//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements the COFF-specific dumper for llvm-readobj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "ARMWinEHPrinter.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+#include "Win64EHDumper.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Win64EH.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstring>
+#include <system_error>
+#include <time.h>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::Win64EH;
+
+namespace {
+
+class COFFDumper : public ObjDumper {
+public:
+ COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) {
+ cacheRelocations();
+ }
+
+ void printFileHeaders() override;
+ void printSections() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override;
+ void printUnwindInfo() override;
+ void printCOFFImports() override;
+ void printCOFFExports() override;
+ void printCOFFDirectives() override;
+ void printCOFFBaseReloc() override;
+
+private:
+ void printSymbol(const SymbolRef &Sym);
+ void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
+ void printDataDirectory(uint32_t Index, const std::string &FieldName);
+
+ void printDOSHeader(const dos_header *DH);
+ template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
+ void printBaseOfDataField(const pe32_header *Hdr);
+ void printBaseOfDataField(const pe32plus_header *Hdr);
+
+ void printCodeViewDebugInfo(const SectionRef &Section);
+
+ void printCodeViewSymbolsSubsection(StringRef Subsection,
+ const SectionRef &Section,
+ uint32_t Offset);
+
+ void cacheRelocations();
+
+ std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset,
+ SymbolRef &Sym);
+ std::error_code resolveSymbolName(const coff_section *Section,
+ uint64_t Offset, StringRef &Name);
+ void printImportedSymbols(iterator_range<imported_symbol_iterator> Range);
+ void printDelayImportedSymbols(
+ const DelayImportDirectoryEntryRef &I,
+ iterator_range<imported_symbol_iterator> Range);
+
+ typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
+
+ const llvm::object::COFFObjectFile *Obj;
+ RelocMapTy RelocMap;
+ StringRef CVFileIndexToStringOffsetTable;
+ StringRef CVStringTable;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+std::error_code createCOFFDumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj);
+ if (!COFFObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new COFFDumper(COFFObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
+
+// Given a a section and an offset into this section the function returns the
+// symbol used for the relocation at the offset.
+std::error_code COFFDumper::resolveSymbol(const coff_section *Section,
+ uint64_t Offset, SymbolRef &Sym) {
+ const auto &Relocations = RelocMap[Section];
+ for (const auto &Relocation : Relocations) {
+ uint64_t RelocationOffset;
+ if (std::error_code EC = Relocation.getOffset(RelocationOffset))
+ return EC;
+
+ if (RelocationOffset == Offset) {
+ Sym = *Relocation.getSymbol();
+ return readobj_error::success;
+ }
+ }
+ return readobj_error::unknown_symbol;
+}
+
+// Given a section and an offset into this section the function returns the name
+// of the symbol used for the relocation at the offset.
+std::error_code COFFDumper::resolveSymbolName(const coff_section *Section,
+ uint64_t Offset,
+ StringRef &Name) {
+ SymbolRef Symbol;
+ if (std::error_code EC = resolveSymbol(Section, Offset, Symbol))
+ return EC;
+ if (std::error_code EC = Symbol.getName(Name))
+ return EC;
+ return object_error::success;
+}
+
+static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2)
+};
+
+static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI )
+};
+
+static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX ),
+};
+
+static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
+};
+
+static const EnumEntry<COFF::SectionCharacteristics>
+ImageSectionCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE )
+};
+
+static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = {
+ { "Null" , COFF::IMAGE_SYM_TYPE_NULL },
+ { "Void" , COFF::IMAGE_SYM_TYPE_VOID },
+ { "Char" , COFF::IMAGE_SYM_TYPE_CHAR },
+ { "Short" , COFF::IMAGE_SYM_TYPE_SHORT },
+ { "Int" , COFF::IMAGE_SYM_TYPE_INT },
+ { "Long" , COFF::IMAGE_SYM_TYPE_LONG },
+ { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT },
+ { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE },
+ { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT },
+ { "Union" , COFF::IMAGE_SYM_TYPE_UNION },
+ { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM },
+ { "MOE" , COFF::IMAGE_SYM_TYPE_MOE },
+ { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE },
+ { "Word" , COFF::IMAGE_SYM_TYPE_WORD },
+ { "UInt" , COFF::IMAGE_SYM_TYPE_UINT },
+ { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD }
+};
+
+static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = {
+ { "Null" , COFF::IMAGE_SYM_DTYPE_NULL },
+ { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER },
+ { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION },
+ { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY }
+};
+
+static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = {
+ { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION },
+ { "Null" , COFF::IMAGE_SYM_CLASS_NULL },
+ { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC },
+ { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL },
+ { "Static" , COFF::IMAGE_SYM_CLASS_STATIC },
+ { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER },
+ { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF },
+ { "Label" , COFF::IMAGE_SYM_CLASS_LABEL },
+ { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL },
+ { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT },
+ { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT },
+ { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG },
+ { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION },
+ { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG },
+ { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION },
+ { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC },
+ { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG },
+ { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM },
+ { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM },
+ { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD },
+ { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK },
+ { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION },
+ { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT },
+ { "File" , COFF::IMAGE_SYM_CLASS_FILE },
+ { "Section" , COFF::IMAGE_SYM_CLASS_SECTION },
+ { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL },
+ { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN }
+};
+
+static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = {
+ { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES },
+ { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY },
+ { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE },
+ { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH },
+ { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE },
+ { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST },
+ { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST }
+};
+
+static const EnumEntry<COFF::WeakExternalCharacteristics>
+WeakExternalCharacteristics[] = {
+ { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
+ { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY },
+ { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }
+};
+
+template <typename T>
+static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
+ COFFSymbolRef Symbol,
+ uint8_t AuxSymbolIdx, const T *&Aux) {
+ ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol);
+ AuxData = AuxData.slice(AuxSymbolIdx * Obj->getSymbolTableEntrySize());
+ Aux = reinterpret_cast<const T*>(AuxData.data());
+ return readobj_error::success;
+}
+
+void COFFDumper::cacheRelocations() {
+ for (const SectionRef &S : Obj->sections()) {
+ const coff_section *Section = Obj->getCOFFSection(S);
+
+ for (const RelocationRef &Reloc : S.relocations())
+ RelocMap[Section].push_back(Reloc);
+
+ // Sort relocations by address.
+ std::sort(RelocMap[Section].begin(), RelocMap[Section].end(),
+ relocAddressLess);
+ }
+}
+
+void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) {
+ const data_directory *Data;
+ if (Obj->getDataDirectory(Index, Data))
+ return;
+ W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress);
+ W.printHex(FieldName + "Size", Data->Size);
+}
+
+void COFFDumper::printFileHeaders() {
+ time_t TDS = Obj->getTimeDateStamp();
+ char FormattedTime[20] = { };
+ strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+
+ {
+ DictScope D(W, "ImageFileHeader");
+ W.printEnum ("Machine", Obj->getMachine(),
+ makeArrayRef(ImageFileMachineType));
+ W.printNumber("SectionCount", Obj->getNumberOfSections());
+ W.printHex ("TimeDateStamp", FormattedTime, Obj->getTimeDateStamp());
+ W.printHex ("PointerToSymbolTable", Obj->getPointerToSymbolTable());
+ W.printNumber("SymbolCount", Obj->getNumberOfSymbols());
+ W.printNumber("OptionalHeaderSize", Obj->getSizeOfOptionalHeader());
+ W.printFlags ("Characteristics", Obj->getCharacteristics(),
+ makeArrayRef(ImageFileCharacteristics));
+ }
+
+ // Print PE header. This header does not exist if this is an object file and
+ // not an executable.
+ const pe32_header *PEHeader = nullptr;
+ if (error(Obj->getPE32Header(PEHeader)))
+ return;
+ if (PEHeader)
+ printPEHeader<pe32_header>(PEHeader);
+
+ const pe32plus_header *PEPlusHeader = nullptr;
+ if (error(Obj->getPE32PlusHeader(PEPlusHeader)))
+ return;
+ if (PEPlusHeader)
+ printPEHeader<pe32plus_header>(PEPlusHeader);
+
+ if (const dos_header *DH = Obj->getDOSHeader())
+ printDOSHeader(DH);
+}
+
+void COFFDumper::printDOSHeader(const dos_header *DH) {
+ DictScope D(W, "DOSHeader");
+ W.printString("Magic", StringRef(DH->Magic, sizeof(DH->Magic)));
+ W.printNumber("UsedBytesInTheLastPage", DH->UsedBytesInTheLastPage);
+ W.printNumber("FileSizeInPages", DH->FileSizeInPages);
+ W.printNumber("NumberOfRelocationItems", DH->NumberOfRelocationItems);
+ W.printNumber("HeaderSizeInParagraphs", DH->HeaderSizeInParagraphs);
+ W.printNumber("MinimumExtraParagraphs", DH->MinimumExtraParagraphs);
+ W.printNumber("MaximumExtraParagraphs", DH->MaximumExtraParagraphs);
+ W.printNumber("InitialRelativeSS", DH->InitialRelativeSS);
+ W.printNumber("InitialSP", DH->InitialSP);
+ W.printNumber("Checksum", DH->Checksum);
+ W.printNumber("InitialIP", DH->InitialIP);
+ W.printNumber("InitialRelativeCS", DH->InitialRelativeCS);
+ W.printNumber("AddressOfRelocationTable", DH->AddressOfRelocationTable);
+ W.printNumber("OverlayNumber", DH->OverlayNumber);
+ W.printNumber("OEMid", DH->OEMid);
+ W.printNumber("OEMinfo", DH->OEMinfo);
+ W.printNumber("AddressOfNewExeHeader", DH->AddressOfNewExeHeader);
+}
+
+template <class PEHeader>
+void COFFDumper::printPEHeader(const PEHeader *Hdr) {
+ DictScope D(W, "ImageOptionalHeader");
+ W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion);
+ W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion);
+ W.printNumber("SizeOfCode", Hdr->SizeOfCode);
+ W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData);
+ W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData);
+ W.printHex ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint);
+ W.printHex ("BaseOfCode", Hdr->BaseOfCode);
+ printBaseOfDataField(Hdr);
+ W.printHex ("ImageBase", Hdr->ImageBase);
+ W.printNumber("SectionAlignment", Hdr->SectionAlignment);
+ W.printNumber("FileAlignment", Hdr->FileAlignment);
+ W.printNumber("MajorOperatingSystemVersion",
+ Hdr->MajorOperatingSystemVersion);
+ W.printNumber("MinorOperatingSystemVersion",
+ Hdr->MinorOperatingSystemVersion);
+ W.printNumber("MajorImageVersion", Hdr->MajorImageVersion);
+ W.printNumber("MinorImageVersion", Hdr->MinorImageVersion);
+ W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion);
+ W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion);
+ W.printNumber("SizeOfImage", Hdr->SizeOfImage);
+ W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
+ W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem));
+ W.printFlags ("Characteristics", Hdr->DLLCharacteristics,
+ makeArrayRef(PEDLLCharacteristics));
+ W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
+ W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
+ W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve);
+ W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit);
+ W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize);
+
+ if (Hdr->NumberOfRvaAndSize > 0) {
+ DictScope D(W, "DataDirectory");
+ static const char * const directory[] = {
+ "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
+ "CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
+ "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
+ "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
+ };
+
+ for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) {
+ printDataDirectory(i, directory[i]);
+ }
+ }
+}
+
+void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
+ W.printHex("BaseOfData", Hdr->BaseOfData);
+}
+
+void COFFDumper::printBaseOfDataField(const pe32plus_header *) {}
+
+void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) {
+ StringRef Data;
+ if (error(Section.getContents(Data)))
+ return;
+
+ SmallVector<StringRef, 10> FunctionNames;
+ StringMap<StringRef> FunctionLineTables;
+
+ ListScope D(W, "CodeViewDebugInfo");
+ {
+ // FIXME: Add more offset correctness checks.
+ DataExtractor DE(Data, true, 4);
+ uint32_t Offset = 0,
+ Magic = DE.getU32(&Offset);
+ W.printHex("Magic", Magic);
+ if (Magic != COFF::DEBUG_SECTION_MAGIC) {
+ error(object_error::parse_failed);
+ return;
+ }
+
+ bool Finished = false;
+ while (DE.isValidOffset(Offset) && !Finished) {
+ // The section consists of a number of subsection in the following format:
+ // |Type|PayloadSize|Payload...|
+ uint32_t SubSectionType = DE.getU32(&Offset),
+ PayloadSize = DE.getU32(&Offset);
+ ListScope S(W, "Subsection");
+ W.printHex("Type", SubSectionType);
+ W.printHex("PayloadSize", PayloadSize);
+ if (PayloadSize > Data.size() - Offset) {
+ error(object_error::parse_failed);
+ return;
+ }
+
+ StringRef Contents = Data.substr(Offset, PayloadSize);
+ if (opts::CodeViewSubsectionBytes) {
+ // Print the raw contents to simplify debugging if anything goes wrong
+ // afterwards.
+ W.printBinaryBlock("Contents", Contents);
+ }
+
+ switch (SubSectionType) {
+ case COFF::DEBUG_SYMBOL_SUBSECTION:
+ if (opts::SectionSymbols)
+ printCodeViewSymbolsSubsection(Contents, Section, Offset);
+ break;
+ case COFF::DEBUG_LINE_TABLE_SUBSECTION: {
+ // Holds a PC to file:line table. Some data to parse this subsection is
+ // stored in the other subsections, so just check sanity and store the
+ // pointers for deferred processing.
+
+ if (PayloadSize < 12) {
+ // There should be at least three words to store two function
+ // relocations and size of the code.
+ error(object_error::parse_failed);
+ return;
+ }
+
+ StringRef FunctionName;
+ if (error(resolveSymbolName(Obj->getCOFFSection(Section), Offset,
+ FunctionName)))
+ return;
+ W.printString("FunctionName", FunctionName);
+ if (FunctionLineTables.count(FunctionName) != 0) {
+ // Saw debug info for this function already?
+ error(object_error::parse_failed);
+ return;
+ }
+
+ FunctionLineTables[FunctionName] = Contents;
+ FunctionNames.push_back(FunctionName);
+ break;
+ }
+ case COFF::DEBUG_STRING_TABLE_SUBSECTION:
+ if (PayloadSize == 0 || CVStringTable.data() != nullptr ||
+ Contents.back() != '\0') {
+ // Empty or duplicate or non-null-terminated subsection.
+ error(object_error::parse_failed);
+ return;
+ }
+ CVStringTable = Contents;
+ break;
+ case COFF::DEBUG_INDEX_SUBSECTION:
+ // Holds the translation table from file indices
+ // to offsets in the string table.
+
+ if (PayloadSize == 0 ||
+ CVFileIndexToStringOffsetTable.data() != nullptr) {
+ // Empty or duplicate subsection.
+ error(object_error::parse_failed);
+ return;
+ }
+ CVFileIndexToStringOffsetTable = Contents;
+ break;
+ }
+ Offset += PayloadSize;
+
+ // Align the reading pointer by 4.
+ Offset += (-Offset) % 4;
+ }
+ }
+
+ // Dump the line tables now that we've read all the subsections and know all
+ // the required information.
+ for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) {
+ StringRef Name = FunctionNames[I];
+ ListScope S(W, "FunctionLineTable");
+ W.printString("FunctionName", Name);
+
+ DataExtractor DE(FunctionLineTables[Name], true, 4);
+ uint32_t Offset = 8; // Skip relocations.
+ uint32_t FunctionSize = DE.getU32(&Offset);
+ W.printHex("CodeSize", FunctionSize);
+ while (DE.isValidOffset(Offset)) {
+ // For each range of lines with the same filename, we have a segment
+ // in the line table. The filename string is accessed using double
+ // indirection to the string table subsection using the index subsection.
+ uint32_t OffsetInIndex = DE.getU32(&Offset),
+ SegmentLength = DE.getU32(&Offset),
+ FullSegmentSize = DE.getU32(&Offset);
+ if (FullSegmentSize != 12 + 8 * SegmentLength) {
+ error(object_error::parse_failed);
+ return;
+ }
+
+ uint32_t FilenameOffset;
+ {
+ DataExtractor SDE(CVFileIndexToStringOffsetTable, true, 4);
+ uint32_t OffsetInSDE = OffsetInIndex;
+ if (!SDE.isValidOffset(OffsetInSDE)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ FilenameOffset = SDE.getU32(&OffsetInSDE);
+ }
+
+ if (FilenameOffset == 0 || FilenameOffset + 1 >= CVStringTable.size() ||
+ CVStringTable.data()[FilenameOffset - 1] != '\0') {
+ // Each string in an F3 subsection should be preceded by a null
+ // character.
+ error(object_error::parse_failed);
+ return;
+ }
+
+ StringRef Filename(CVStringTable.data() + FilenameOffset);
+ ListScope S(W, "FilenameSegment");
+ W.printString("Filename", Filename);
+ for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset);
+ ++J) {
+ // Then go the (PC, LineNumber) pairs. The line number is stored in the
+ // least significant 31 bits of the respective word in the table.
+ uint32_t PC = DE.getU32(&Offset),
+ LineNumber = DE.getU32(&Offset) & 0x7fffffff;
+ if (PC >= FunctionSize) {
+ error(object_error::parse_failed);
+ return;
+ }
+ char Buffer[32];
+ format("+0x%X", PC).snprint(Buffer, 32);
+ W.printNumber(Buffer, LineNumber);
+ }
+ }
+ }
+}
+
+void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
+ const SectionRef &Section,
+ uint32_t OffsetInSection) {
+ if (Subsection.size() == 0) {
+ error(object_error::parse_failed);
+ return;
+ }
+ DataExtractor DE(Subsection, true, 4);
+ uint32_t Offset = 0;
+
+ // Function-level subsections have "procedure start" and "procedure end"
+ // commands that should come in pairs and surround relevant info.
+ bool InFunctionScope = false;
+ while (DE.isValidOffset(Offset)) {
+ // Read subsection segments one by one.
+ uint16_t Size = DE.getU16(&Offset);
+ // The section size includes the size of the type identifier.
+ if (Size < 2 || !DE.isValidOffsetForDataOfSize(Offset, Size)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ Size -= 2;
+ uint16_t Type = DE.getU16(&Offset);
+ switch (Type) {
+ case COFF::DEBUG_SYMBOL_TYPE_PROC_START: {
+ DictScope S(W, "ProcStart");
+ if (InFunctionScope || Size < 36) {
+ error(object_error::parse_failed);
+ return;
+ }
+ InFunctionScope = true;
+
+ // We're currently interested in a limited subset of fields in this
+ // segment, just ignore the rest of the fields for now.
+ uint8_t Unused[12];
+ DE.getU8(&Offset, Unused, 12);
+ uint32_t CodeSize = DE.getU32(&Offset);
+ DE.getU8(&Offset, Unused, 12);
+ StringRef SectionName;
+ if (error(resolveSymbolName(Obj->getCOFFSection(Section),
+ OffsetInSection + Offset, SectionName)))
+ return;
+ Offset += 4;
+ DE.getU8(&Offset, Unused, 3);
+ StringRef DisplayName = DE.getCStr(&Offset);
+ if (!DE.isValidOffset(Offset)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ W.printString("DisplayName", DisplayName);
+ W.printString("Section", SectionName);
+ W.printHex("CodeSize", CodeSize);
+
+ break;
+ }
+ case COFF::DEBUG_SYMBOL_TYPE_PROC_END: {
+ W.startLine() << "ProcEnd\n";
+ if (!InFunctionScope || Size > 0) {
+ error(object_error::parse_failed);
+ return;
+ }
+ InFunctionScope = false;
+ break;
+ }
+ default: {
+ if (opts::CodeViewSubsectionBytes) {
+ ListScope S(W, "Record");
+ W.printHex("Size", Size);
+ W.printHex("Type", Type);
+
+ StringRef Contents = DE.getData().substr(Offset, Size);
+ W.printBinaryBlock("Contents", Contents);
+ }
+
+ Offset += Size;
+ break;
+ }
+ }
+ }
+
+ if (InFunctionScope)
+ error(object_error::parse_failed);
+}
+
+void COFFDumper::printSections() {
+ ListScope SectionsD(W, "Sections");
+ int SectionNumber = 0;
+ for (const SectionRef &Sec : Obj->sections()) {
+ ++SectionNumber;
+ const coff_section *Section = Obj->getCOFFSection(Sec);
+
+ StringRef Name;
+ if (error(Sec.getName(Name)))
+ Name = "";
+
+ DictScope D(W, "Section");
+ W.printNumber("Number", SectionNumber);
+ W.printBinary("Name", Name, Section->Name);
+ W.printHex ("VirtualSize", Section->VirtualSize);
+ W.printHex ("VirtualAddress", Section->VirtualAddress);
+ W.printNumber("RawDataSize", Section->SizeOfRawData);
+ W.printHex ("PointerToRawData", Section->PointerToRawData);
+ W.printHex ("PointerToRelocations", Section->PointerToRelocations);
+ W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers);
+ W.printNumber("RelocationCount", Section->NumberOfRelocations);
+ W.printNumber("LineNumberCount", Section->NumberOfLinenumbers);
+ W.printFlags ("Characteristics", Section->Characteristics,
+ makeArrayRef(ImageSectionCharacteristics),
+ COFF::SectionCharacteristics(0x00F00000));
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (const RelocationRef &Reloc : Sec.relocations())
+ printRelocation(Sec, Reloc);
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (const SymbolRef &Symbol : Obj->symbols()) {
+ if (!Sec.containsSymbol(Symbol))
+ continue;
+
+ printSymbol(Symbol);
+ }
+ }
+
+ if (Name == ".debug$S" && opts::CodeView)
+ printCodeViewDebugInfo(Sec);
+
+ if (opts::SectionData &&
+ !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
+ StringRef Data;
+ if (error(Sec.getContents(Data)))
+ break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+}
+
+void COFFDumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ int SectionNumber = 0;
+ for (const SectionRef &Section : Obj->sections()) {
+ ++SectionNumber;
+ StringRef Name;
+ if (error(Section.getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ if (!PrintedGroup) {
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(Section, Reloc);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void COFFDumper::printRelocation(const SectionRef &Section,
+ const RelocationRef &Reloc) {
+ uint64_t Offset;
+ uint64_t RelocType;
+ SmallString<32> RelocName;
+ StringRef SymbolName;
+ if (error(Reloc.getOffset(Offset)))
+ return;
+ if (error(Reloc.getType(RelocType)))
+ return;
+ if (error(Reloc.getTypeName(RelocName)))
+ return;
+ symbol_iterator Symbol = Reloc.getSymbol();
+ if (Symbol != Obj->symbol_end() && error(Symbol->getName(SymbolName)))
+ return;
+
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printHex("Offset", Offset);
+ W.printNumber("Type", RelocName, RelocType);
+ W.printString("Symbol", SymbolName.empty() ? "-" : SymbolName);
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << RelocName
+ << " " << (SymbolName.empty() ? "-" : SymbolName)
+ << "\n";
+ }
+}
+
+void COFFDumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ for (const SymbolRef &Symbol : Obj->symbols())
+ printSymbol(Symbol);
+}
+
+void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }
+
+static ErrorOr<StringRef>
+getSectionName(const llvm::object::COFFObjectFile *Obj, int32_t SectionNumber,
+ const coff_section *Section) {
+ if (Section) {
+ StringRef SectionName;
+ if (std::error_code EC = Obj->getSectionName(Section, SectionName))
+ return EC;
+ return SectionName;
+ }
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
+ return StringRef("IMAGE_SYM_DEBUG");
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE)
+ return StringRef("IMAGE_SYM_ABSOLUTE");
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
+ return StringRef("IMAGE_SYM_UNDEFINED");
+ return StringRef("");
+}
+
+void COFFDumper::printSymbol(const SymbolRef &Sym) {
+ DictScope D(W, "Symbol");
+
+ COFFSymbolRef Symbol = Obj->getCOFFSymbol(Sym);
+ const coff_section *Section;
+ if (std::error_code EC = Obj->getSection(Symbol.getSectionNumber(), Section)) {
+ W.startLine() << "Invalid section number: " << EC.message() << "\n";
+ W.flush();
+ return;
+ }
+
+ StringRef SymbolName;
+ if (Obj->getSymbolName(Symbol, SymbolName))
+ SymbolName = "";
+
+ StringRef SectionName = "";
+ ErrorOr<StringRef> Res =
+ getSectionName(Obj, Symbol.getSectionNumber(), Section);
+ if (Res)
+ SectionName = *Res;
+
+ W.printString("Name", SymbolName);
+ W.printNumber("Value", Symbol.getValue());
+ W.printNumber("Section", SectionName, Symbol.getSectionNumber());
+ W.printEnum ("BaseType", Symbol.getBaseType(), makeArrayRef(ImageSymType));
+ W.printEnum ("ComplexType", Symbol.getComplexType(),
+ makeArrayRef(ImageSymDType));
+ W.printEnum ("StorageClass", Symbol.getStorageClass(),
+ makeArrayRef(ImageSymClass));
+ W.printNumber("AuxSymbolCount", Symbol.getNumberOfAuxSymbols());
+
+ for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) {
+ if (Symbol.isFunctionDefinition()) {
+ const coff_aux_function_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxFunctionDef");
+ W.printNumber("TagIndex", Aux->TagIndex);
+ W.printNumber("TotalSize", Aux->TotalSize);
+ W.printHex("PointerToLineNumber", Aux->PointerToLinenumber);
+ W.printHex("PointerToNextFunction", Aux->PointerToNextFunction);
+
+ } else if (Symbol.isAnyUndefined()) {
+ const coff_aux_weak_external *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
+ break;
+
+ ErrorOr<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex);
+ StringRef LinkedName;
+ std::error_code EC = Linked.getError();
+ if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) {
+ LinkedName = "";
+ error(EC);
+ }
+
+ DictScope AS(W, "AuxWeakExternal");
+ W.printNumber("Linked", LinkedName, Aux->TagIndex);
+ W.printEnum ("Search", Aux->Characteristics,
+ makeArrayRef(WeakExternalCharacteristics));
+
+ } else if (Symbol.isFileRecord()) {
+ const char *FileName;
+ if (error(getSymbolAuxData(Obj, Symbol, I, FileName)))
+ break;
+
+ DictScope AS(W, "AuxFileRecord");
+
+ StringRef Name(FileName, Symbol.getNumberOfAuxSymbols() *
+ Obj->getSymbolTableEntrySize());
+ W.printString("FileName", Name.rtrim(StringRef("\0", 1)));
+ break;
+ } else if (Symbol.isSectionDefinition()) {
+ const coff_aux_section_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
+ break;
+
+ int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj());
+
+ DictScope AS(W, "AuxSectionDef");
+ W.printNumber("Length", Aux->Length);
+ W.printNumber("RelocationCount", Aux->NumberOfRelocations);
+ W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
+ W.printHex("Checksum", Aux->CheckSum);
+ W.printNumber("Number", AuxNumber);
+ W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect));
+
+ if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
+ && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ const coff_section *Assoc;
+ StringRef AssocName = "";
+ std::error_code EC = Obj->getSection(AuxNumber, Assoc);
+ ErrorOr<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
+ if (Res)
+ AssocName = *Res;
+ if (!EC)
+ EC = Res.getError();
+ if (EC) {
+ AssocName = "";
+ error(EC);
+ }
+
+ W.printNumber("AssocSection", AssocName, AuxNumber);
+ }
+ } else if (Symbol.isCLRToken()) {
+ const coff_aux_clr_token *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
+ break;
+
+ ErrorOr<COFFSymbolRef> ReferredSym =
+ Obj->getSymbol(Aux->SymbolTableIndex);
+ StringRef ReferredName;
+ std::error_code EC = ReferredSym.getError();
+ if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) {
+ ReferredName = "";
+ error(EC);
+ }
+
+ DictScope AS(W, "AuxCLRToken");
+ W.printNumber("AuxType", Aux->AuxType);
+ W.printNumber("Reserved", Aux->Reserved);
+ W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex);
+
+ } else {
+ W.startLine() << "<unhandled auxiliary record>\n";
+ }
+ }
+}
+
+void COFFDumper::printUnwindInfo() {
+ ListScope D(W, "UnwindInformation");
+ switch (Obj->getMachine()) {
+ case COFF::IMAGE_FILE_MACHINE_AMD64: {
+ Win64EH::Dumper Dumper(W);
+ Win64EH::Dumper::SymbolResolver
+ Resolver = [](const object::coff_section *Section, uint64_t Offset,
+ SymbolRef &Symbol, void *user_data) -> std::error_code {
+ COFFDumper *Dumper = reinterpret_cast<COFFDumper *>(user_data);
+ return Dumper->resolveSymbol(Section, Offset, Symbol);
+ };
+ Win64EH::Dumper::Context Ctx(*Obj, Resolver, this);
+ Dumper.printData(Ctx);
+ break;
+ }
+ case COFF::IMAGE_FILE_MACHINE_ARMNT: {
+ ARM::WinEH::Decoder Decoder(W);
+ Decoder.dumpProcedureData(*Obj);
+ break;
+ }
+ default:
+ W.printEnum("unsupported Image Machine", Obj->getMachine(),
+ makeArrayRef(ImageFileMachineType));
+ break;
+ }
+}
+
+void COFFDumper::printImportedSymbols(
+ iterator_range<imported_symbol_iterator> Range) {
+ for (const ImportedSymbolRef &I : Range) {
+ StringRef Sym;
+ if (error(I.getSymbolName(Sym))) return;
+ uint16_t Ordinal;
+ if (error(I.getOrdinal(Ordinal))) return;
+ W.printNumber("Symbol", Sym, Ordinal);
+ }
+}
+
+void COFFDumper::printDelayImportedSymbols(
+ const DelayImportDirectoryEntryRef &I,
+ iterator_range<imported_symbol_iterator> Range) {
+ int Index = 0;
+ for (const ImportedSymbolRef &S : Range) {
+ DictScope Import(W, "Import");
+ StringRef Sym;
+ if (error(S.getSymbolName(Sym))) return;
+ uint16_t Ordinal;
+ if (error(S.getOrdinal(Ordinal))) return;
+ W.printNumber("Symbol", Sym, Ordinal);
+ uint64_t Addr;
+ if (error(I.getImportAddress(Index++, Addr))) return;
+ W.printHex("Address", Addr);
+ }
+}
+
+void COFFDumper::printCOFFImports() {
+ // Regular imports
+ for (const ImportDirectoryEntryRef &I : Obj->import_directories()) {
+ DictScope Import(W, "Import");
+ StringRef Name;
+ if (error(I.getName(Name))) return;
+ W.printString("Name", Name);
+ uint32_t Addr;
+ if (error(I.getImportLookupTableRVA(Addr))) return;
+ W.printHex("ImportLookupTableRVA", Addr);
+ if (error(I.getImportAddressTableRVA(Addr))) return;
+ W.printHex("ImportAddressTableRVA", Addr);
+ printImportedSymbols(I.imported_symbols());
+ }
+
+ // Delay imports
+ for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) {
+ DictScope Import(W, "DelayImport");
+ StringRef Name;
+ if (error(I.getName(Name))) return;
+ W.printString("Name", Name);
+ const delay_import_directory_table_entry *Table;
+ if (error(I.getDelayImportTable(Table))) return;
+ W.printHex("Attributes", Table->Attributes);
+ W.printHex("ModuleHandle", Table->ModuleHandle);
+ W.printHex("ImportAddressTable", Table->DelayImportAddressTable);
+ W.printHex("ImportNameTable", Table->DelayImportNameTable);
+ W.printHex("BoundDelayImportTable", Table->BoundDelayImportTable);
+ W.printHex("UnloadDelayImportTable", Table->UnloadDelayImportTable);
+ printDelayImportedSymbols(I, I.imported_symbols());
+ }
+}
+
+void COFFDumper::printCOFFExports() {
+ for (const ExportDirectoryEntryRef &E : Obj->export_directories()) {
+ DictScope Export(W, "Export");
+
+ StringRef Name;
+ uint32_t Ordinal, RVA;
+
+ if (error(E.getSymbolName(Name)))
+ continue;
+ if (error(E.getOrdinal(Ordinal)))
+ continue;
+ if (error(E.getExportRVA(RVA)))
+ continue;
+
+ W.printNumber("Ordinal", Ordinal);
+ W.printString("Name", Name);
+ W.printHex("RVA", RVA);
+ }
+}
+
+void COFFDumper::printCOFFDirectives() {
+ for (const SectionRef &Section : Obj->sections()) {
+ StringRef Contents;
+ StringRef Name;
+
+ if (error(Section.getName(Name)))
+ continue;
+ if (Name != ".drectve")
+ continue;
+
+ if (error(Section.getContents(Contents)))
+ return;
+
+ W.printString("Directive(s)", Contents);
+ }
+}
+
+static StringRef getBaseRelocTypeName(uint8_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_BASED_ABSOLUTE: return "ABSOLUTE";
+ case COFF::IMAGE_REL_BASED_HIGH: return "HIGH";
+ case COFF::IMAGE_REL_BASED_LOW: return "LOW";
+ case COFF::IMAGE_REL_BASED_HIGHLOW: return "HIGHLOW";
+ case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ";
+ case COFF::IMAGE_REL_BASED_ARM_MOV32T: return "ARM_MOV32(T)";
+ case COFF::IMAGE_REL_BASED_DIR64: return "DIR64";
+ default: return "unknown (" + llvm::utostr(Type) + ")";
+ }
+}
+
+void COFFDumper::printCOFFBaseReloc() {
+ ListScope D(W, "BaseReloc");
+ for (const BaseRelocRef &I : Obj->base_relocs()) {
+ uint8_t Type;
+ uint32_t RVA;
+ if (error(I.getRVA(RVA)))
+ continue;
+ if (error(I.getType(Type)))
+ continue;
+ DictScope Import(W, "Entry");
+ W.printString("Type", getBaseRelocTypeName(Type));
+ W.printHex("Address", RVA);
+ }
+}
diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
new file mode 100644
index 0000000..a20512f
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -0,0 +1,1424 @@
+//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements the ELF-specific dumper for llvm-readobj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "ARMAttributeParser.h"
+#include "ARMEHABIPrinter.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MipsABIFlags.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace ELF;
+
+#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
+ case ns::enum: return #enum;
+
+namespace {
+
+template<typename ELFT>
+class ELFDumper : public ObjDumper {
+public:
+ ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
+ : ObjDumper(Writer), Obj(Obj) {}
+
+ void printFileHeaders() override;
+ void printSections() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override;
+ void printUnwindInfo() override;
+
+ void printDynamicTable() override;
+ void printNeededLibraries() override;
+ void printProgramHeaders() override;
+
+ void printAttributes() override;
+ void printMipsPLTGOT() override;
+ void printMipsABIFlags() override;
+
+private:
+ typedef ELFFile<ELFT> ELFO;
+ typedef typename ELFO::Elf_Shdr Elf_Shdr;
+ typedef typename ELFO::Elf_Sym Elf_Sym;
+
+ void printSymbol(typename ELFO::Elf_Sym_Iter Symbol);
+
+ void printRelocations(const Elf_Shdr *Sec);
+ void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel);
+
+ const ELFO *Obj;
+};
+
+template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) {
+ if (!Val) {
+ error(Val.getError());
+ return Default;
+ }
+
+ return *Val;
+}
+} // namespace
+
+namespace llvm {
+
+template <class ELFT>
+static std::error_code createELFDumper(const ELFFile<ELFT> *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ Result.reset(new ELFDumper<ELFT>(Obj, Writer));
+ return readobj_error::success;
+}
+
+std::error_code createELFDumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ // Little-endian 32-bit
+ if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
+ return createELFDumper(ELFObj->getELFFile(), Writer, Result);
+
+ // Big-endian 32-bit
+ if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
+ return createELFDumper(ELFObj->getELFFile(), Writer, Result);
+
+ // Little-endian 64-bit
+ if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
+ return createELFDumper(ELFObj->getELFFile(), Writer, Result);
+
+ // Big-endian 64-bit
+ if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
+ return createELFDumper(ELFObj->getELFFile(), Writer, Result);
+
+ return readobj_error::unsupported_obj_file_format;
+}
+
+} // namespace llvm
+
+template <typename ELFO>
+static std::string getFullSymbolName(const ELFO &Obj,
+ typename ELFO::Elf_Sym_Iter Symbol) {
+ StringRef SymbolName = errorOrDefault(Obj.getSymbolName(Symbol));
+ if (!Symbol.isDynamic())
+ return SymbolName;
+
+ std::string FullSymbolName(SymbolName);
+
+ bool IsDefault;
+ ErrorOr<StringRef> Version =
+ Obj.getSymbolVersion(nullptr, &*Symbol, IsDefault);
+ if (Version) {
+ FullSymbolName += (IsDefault ? "@@" : "@");
+ FullSymbolName += *Version;
+ } else
+ error(Version.getError());
+ return FullSymbolName;
+}
+
+template <typename ELFO>
+static void
+getSectionNameIndex(const ELFO &Obj, typename ELFO::Elf_Sym_Iter Symbol,
+ StringRef &SectionName, unsigned &SectionIndex) {
+ SectionIndex = Symbol->st_shndx;
+ if (SectionIndex == SHN_UNDEF) {
+ SectionName = "Undefined";
+ } else if (SectionIndex >= SHN_LOPROC && SectionIndex <= SHN_HIPROC) {
+ SectionName = "Processor Specific";
+ } else if (SectionIndex >= SHN_LOOS && SectionIndex <= SHN_HIOS) {
+ SectionName = "Operating System Specific";
+ } else if (SectionIndex > SHN_HIOS && SectionIndex < SHN_ABS) {
+ SectionName = "Reserved";
+ } else if (SectionIndex == SHN_ABS) {
+ SectionName = "Absolute";
+ } else if (SectionIndex == SHN_COMMON) {
+ SectionName = "Common";
+ } else {
+ if (SectionIndex == SHN_XINDEX)
+ SectionIndex = Obj.getSymbolTableIndex(&*Symbol);
+ assert(SectionIndex != SHN_XINDEX &&
+ "getSymbolTableIndex should handle this");
+ const typename ELFO::Elf_Shdr *Sec = Obj.getSection(SectionIndex);
+ SectionName = errorOrDefault(Obj.getSectionName(Sec));
+ }
+}
+
+template <class ELFT>
+static const typename ELFFile<ELFT>::Elf_Shdr *
+findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) {
+ for (const auto &Shdr : Obj->sections())
+ if (Shdr.sh_addr == Addr)
+ return &Shdr;
+ return nullptr;
+}
+
+template <class ELFT>
+static const typename ELFFile<ELFT>::Elf_Shdr *
+findSectionByName(const ELFFile<ELFT> &Obj, StringRef Name) {
+ for (const auto &Shdr : Obj.sections()) {
+ if (Name == errorOrDefault(Obj.getSectionName(&Shdr)))
+ return &Shdr;
+ }
+ return nullptr;
+}
+
+static const EnumEntry<unsigned> ElfClass[] = {
+ { "None", ELF::ELFCLASSNONE },
+ { "32-bit", ELF::ELFCLASS32 },
+ { "64-bit", ELF::ELFCLASS64 },
+};
+
+static const EnumEntry<unsigned> ElfDataEncoding[] = {
+ { "None", ELF::ELFDATANONE },
+ { "LittleEndian", ELF::ELFDATA2LSB },
+ { "BigEndian", ELF::ELFDATA2MSB },
+};
+
+static const EnumEntry<unsigned> ElfObjectFileType[] = {
+ { "None", ELF::ET_NONE },
+ { "Relocatable", ELF::ET_REL },
+ { "Executable", ELF::ET_EXEC },
+ { "SharedObject", ELF::ET_DYN },
+ { "Core", ELF::ET_CORE },
+};
+
+static const EnumEntry<unsigned> ElfOSABI[] = {
+ { "SystemV", ELF::ELFOSABI_NONE },
+ { "HPUX", ELF::ELFOSABI_HPUX },
+ { "NetBSD", ELF::ELFOSABI_NETBSD },
+ { "GNU/Linux", ELF::ELFOSABI_LINUX },
+ { "GNU/Hurd", ELF::ELFOSABI_HURD },
+ { "Solaris", ELF::ELFOSABI_SOLARIS },
+ { "AIX", ELF::ELFOSABI_AIX },
+ { "IRIX", ELF::ELFOSABI_IRIX },
+ { "FreeBSD", ELF::ELFOSABI_FREEBSD },
+ { "TRU64", ELF::ELFOSABI_TRU64 },
+ { "Modesto", ELF::ELFOSABI_MODESTO },
+ { "OpenBSD", ELF::ELFOSABI_OPENBSD },
+ { "OpenVMS", ELF::ELFOSABI_OPENVMS },
+ { "NSK", ELF::ELFOSABI_NSK },
+ { "AROS", ELF::ELFOSABI_AROS },
+ { "FenixOS", ELF::ELFOSABI_FENIXOS },
+ { "CloudABI", ELF::ELFOSABI_CLOUDABI },
+ { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI },
+ { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX },
+ { "ARM", ELF::ELFOSABI_ARM },
+ { "Standalone" , ELF::ELFOSABI_STANDALONE }
+};
+
+static const EnumEntry<unsigned> ElfMachineType[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NONE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_RS3_LE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PARISC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VPP500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC32PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_960 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_S390 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_V800 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FR20 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RH32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RCE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARM ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ALPHA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SH ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARCV9 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TRICORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300H ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8S ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_IA_64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COLDFIRE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC12 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PCP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NCPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NDR1 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STARCORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ME16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST100 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TINYJ ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_X86_64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDSP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP10 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP11 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FX66 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST9PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST7 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC11 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC08 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC05 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SVX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST19 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VAX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRIS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_JAVELIN ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FIREPATH ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ZSP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMIX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_HUANY ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PRISM ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FR30 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_D10V ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_D30V ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_V850 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32R ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10300 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10200 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PJ ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_OPENRISC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XTENSA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TMM_GPP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NS32K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TPC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SNP1K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST200 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_IP2K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MAX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_F2MC16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MSP430 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_BLACKFIN ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C33 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SEP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARCA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_UNICORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_EXCESS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DXP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ALTERA_NIOS2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XGATE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_C166 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M16C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DSPIC30F ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TSK3000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RS08 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SHARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SCORE7 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DSP24 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE3 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_LATTICEMICO32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C17 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C6000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C2000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C5500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMDSP_PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MAXQ30 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XIMO16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MANIK ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRAYNV2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_METAG ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MCST_ELBRUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CR16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ETPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SLE9X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_L10M ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_K10M ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AARCH64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_1ST ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_2ND ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_OPEN8 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX )
+};
+
+static const EnumEntry<unsigned> ElfSymbolBindings[] = {
+ { "Local", ELF::STB_LOCAL },
+ { "Global", ELF::STB_GLOBAL },
+ { "Weak", ELF::STB_WEAK },
+ { "Unique", ELF::STB_GNU_UNIQUE }
+};
+
+static const EnumEntry<unsigned> ElfSymbolTypes[] = {
+ { "None", ELF::STT_NOTYPE },
+ { "Object", ELF::STT_OBJECT },
+ { "Function", ELF::STT_FUNC },
+ { "Section", ELF::STT_SECTION },
+ { "File", ELF::STT_FILE },
+ { "Common", ELF::STT_COMMON },
+ { "TLS", ELF::STT_TLS },
+ { "GNU_IFunc", ELF::STT_GNU_IFUNC }
+};
+
+static const char *getElfSectionType(unsigned Arch, unsigned Type) {
+ switch (Arch) {
+ case ELF::EM_ARM:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION);
+ }
+ case ELF::EM_HEXAGON:
+ switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); }
+ case ELF::EM_X86_64:
+ switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); }
+ case ELF::EM_MIPS:
+ case ELF::EM_MIPS_RS3_LE:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
+ }
+ }
+
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym );
+ default: return "";
+ }
+}
+
+static const EnumEntry<unsigned> ElfSectionFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXCLUDE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_INFO_LINK ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_LINK_ORDER ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_OS_NONCONFORMING),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_GROUP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION),
+ LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP )
+};
+
+static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
+ // Check potentially overlapped processor-specific
+ // program header type.
+ switch (Arch) {
+ case ELF::EM_ARM:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX);
+ }
+ case ELF::EM_MIPS:
+ case ELF::EM_MIPS_RS3_LE:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_ABIFLAGS);
+ }
+ }
+
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_NULL );
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_LOAD );
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_DYNAMIC);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_INTERP );
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_NOTE );
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_SHLIB );
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_PHDR );
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_TLS );
+
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_EH_FRAME);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_SUNW_UNWIND);
+
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO);
+ default: return "";
+ }
+}
+
+static const EnumEntry<unsigned> ElfSegmentFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, PF_X),
+ LLVM_READOBJ_ENUM_ENT(ELF, PF_W),
+ LLVM_READOBJ_ENUM_ENT(ELF, PF_R)
+};
+
+static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_NOREORDER),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_PIC),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_CPIC),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI2),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_32BITMODE),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_FP64),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_NAN2008),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_O32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_O64),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_EABI32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_EABI64),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_3900),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4010),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4100),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4650),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4120),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4111),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_SB1),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_XLR),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON2),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON3),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5400),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5900),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5500),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_9000),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS2E),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS2F),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS3A),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MICROMIPS),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_ASE_M16),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_ASE_MDMX),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_1),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_2),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_3),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_4),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_5),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32R2),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R2),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32R6),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6)
+};
+
+template<class ELFT>
+void ELFDumper<ELFT>::printFileHeaders() {
+ const typename ELFO::Elf_Ehdr *Header = Obj->getHeader();
+
+ {
+ DictScope D(W, "ElfHeader");
+ {
+ DictScope D(W, "Ident");
+ W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0,
+ 4));
+ W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS],
+ makeArrayRef(ElfClass));
+ W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA],
+ makeArrayRef(ElfDataEncoding));
+ W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]);
+ W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI],
+ makeArrayRef(ElfOSABI));
+ W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]);
+ W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD));
+ }
+
+ W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType));
+ W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType));
+ W.printNumber("Version", Header->e_version);
+ W.printHex ("Entry", Header->e_entry);
+ W.printHex ("ProgramHeaderOffset", Header->e_phoff);
+ W.printHex ("SectionHeaderOffset", Header->e_shoff);
+ if (Header->e_machine == EM_MIPS)
+ W.printFlags("Flags", Header->e_flags, makeArrayRef(ElfHeaderMipsFlags),
+ unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI),
+ unsigned(ELF::EF_MIPS_MACH));
+ else
+ W.printFlags("Flags", Header->e_flags);
+ W.printNumber("HeaderSize", Header->e_ehsize);
+ W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize);
+ W.printNumber("ProgramHeaderCount", Header->e_phnum);
+ W.printNumber("SectionHeaderEntrySize", Header->e_shentsize);
+ W.printNumber("SectionHeaderCount", Header->e_shnum);
+ W.printNumber("StringTableSectionIndex", Header->e_shstrndx);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSections() {
+ ListScope SectionsD(W, "Sections");
+
+ int SectionIndex = -1;
+ for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; ++SecI) {
+ ++SectionIndex;
+
+ const Elf_Shdr *Section = &*SecI;
+ StringRef Name = errorOrDefault(Obj->getSectionName(Section));
+
+ DictScope SectionD(W, "Section");
+ W.printNumber("Index", SectionIndex);
+ W.printNumber("Name", Name, Section->sh_name);
+ W.printHex("Type",
+ getElfSectionType(Obj->getHeader()->e_machine, Section->sh_type),
+ Section->sh_type);
+ W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags));
+ W.printHex ("Address", Section->sh_addr);
+ W.printHex ("Offset", Section->sh_offset);
+ W.printNumber("Size", Section->sh_size);
+ W.printNumber("Link", Section->sh_link);
+ W.printNumber("Info", Section->sh_info);
+ W.printNumber("AddressAlignment", Section->sh_addralign);
+ W.printNumber("EntrySize", Section->sh_entsize);
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ printRelocations(Section);
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; ++SymI) {
+ if (Obj->getSection(&*SymI) == Section)
+ printSymbol(SymI);
+ }
+ }
+
+ if (opts::SectionData && Section->sh_type != ELF::SHT_NOBITS) {
+ ArrayRef<uint8_t> Data = errorOrDefault(Obj->getSectionContents(Section));
+ W.printBinaryBlock("SectionData",
+ StringRef((const char *)Data.data(), Data.size()));
+ }
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ int SectionNumber = -1;
+ for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; ++SecI) {
+ ++SectionNumber;
+
+ if (SecI->sh_type != ELF::SHT_REL && SecI->sh_type != ELF::SHT_RELA)
+ continue;
+
+ StringRef Name = errorOrDefault(Obj->getSectionName(&*SecI));
+
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+
+ printRelocations(&*SecI);
+
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+}
+
+template <class ELFT>
+void ELFDumper<ELFT>::printRelocations(const Elf_Shdr *Sec) {
+ switch (Sec->sh_type) {
+ case ELF::SHT_REL:
+ for (typename ELFO::Elf_Rel_Iter RI = Obj->begin_rel(Sec),
+ RE = Obj->end_rel(Sec);
+ RI != RE; ++RI) {
+ typename ELFO::Elf_Rela Rela;
+ Rela.r_offset = RI->r_offset;
+ Rela.r_info = RI->r_info;
+ Rela.r_addend = 0;
+ printRelocation(Sec, Rela);
+ }
+ break;
+ case ELF::SHT_RELA:
+ for (typename ELFO::Elf_Rela_Iter RI = Obj->begin_rela(Sec),
+ RE = Obj->end_rela(Sec);
+ RI != RE; ++RI) {
+ printRelocation(Sec, *RI);
+ }
+ break;
+ }
+}
+
+template <class ELFT>
+void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec,
+ typename ELFO::Elf_Rela Rel) {
+ SmallString<32> RelocName;
+ Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
+ StringRef SymbolName;
+ std::pair<const Elf_Shdr *, const Elf_Sym *> Sym =
+ Obj->getRelocationSymbol(Sec, &Rel);
+ if (Sym.first)
+ SymbolName = errorOrDefault(Obj->getSymbolName(Sym.first, Sym.second));
+
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printHex("Offset", Rel.r_offset);
+ W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
+ W.printNumber("Symbol", SymbolName.size() > 0 ? SymbolName : "-",
+ Rel.getSymbol(Obj->isMips64EL()));
+ W.printHex("Addend", Rel.r_addend);
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Rel.r_offset)
+ << " " << RelocName
+ << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << " " << W.hex(Rel.r_addend)
+ << "\n";
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSymbols() {
+ ListScope Group(W, "Symbols");
+ for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; ++SymI) {
+ printSymbol(SymI);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+
+ for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_dynamic_symbols(),
+ SymE = Obj->end_dynamic_symbols();
+ SymI != SymE; ++SymI) {
+ printSymbol(SymI);
+ }
+}
+
+template <class ELFT>
+void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) {
+ unsigned SectionIndex = 0;
+ StringRef SectionName;
+ getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex);
+ std::string FullSymbolName = getFullSymbolName(*Obj, Symbol);
+
+ DictScope D(W, "Symbol");
+ W.printNumber("Name", FullSymbolName, Symbol->st_name);
+ W.printHex ("Value", Symbol->st_value);
+ W.printNumber("Size", Symbol->st_size);
+ W.printEnum ("Binding", Symbol->getBinding(),
+ makeArrayRef(ElfSymbolBindings));
+ W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes));
+ W.printNumber("Other", Symbol->st_other);
+ W.printHex("Section", SectionName, SectionIndex);
+}
+
+#define LLVM_READOBJ_TYPE_CASE(name) \
+ case DT_##name: return #name
+
+static const char *getTypeString(uint64_t Type) {
+ switch (Type) {
+ LLVM_READOBJ_TYPE_CASE(BIND_NOW);
+ LLVM_READOBJ_TYPE_CASE(DEBUG);
+ LLVM_READOBJ_TYPE_CASE(FINI);
+ LLVM_READOBJ_TYPE_CASE(FINI_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(FLAGS);
+ LLVM_READOBJ_TYPE_CASE(FLAGS_1);
+ LLVM_READOBJ_TYPE_CASE(HASH);
+ LLVM_READOBJ_TYPE_CASE(INIT);
+ LLVM_READOBJ_TYPE_CASE(INIT_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(JMPREL);
+ LLVM_READOBJ_TYPE_CASE(NEEDED);
+ LLVM_READOBJ_TYPE_CASE(NULL);
+ LLVM_READOBJ_TYPE_CASE(PLTGOT);
+ LLVM_READOBJ_TYPE_CASE(PLTREL);
+ LLVM_READOBJ_TYPE_CASE(PLTRELSZ);
+ LLVM_READOBJ_TYPE_CASE(REL);
+ LLVM_READOBJ_TYPE_CASE(RELA);
+ LLVM_READOBJ_TYPE_CASE(RELENT);
+ LLVM_READOBJ_TYPE_CASE(RELSZ);
+ LLVM_READOBJ_TYPE_CASE(RELAENT);
+ LLVM_READOBJ_TYPE_CASE(RELASZ);
+ LLVM_READOBJ_TYPE_CASE(RPATH);
+ LLVM_READOBJ_TYPE_CASE(RUNPATH);
+ LLVM_READOBJ_TYPE_CASE(SONAME);
+ LLVM_READOBJ_TYPE_CASE(STRSZ);
+ LLVM_READOBJ_TYPE_CASE(STRTAB);
+ LLVM_READOBJ_TYPE_CASE(SYMBOLIC);
+ LLVM_READOBJ_TYPE_CASE(SYMENT);
+ LLVM_READOBJ_TYPE_CASE(SYMTAB);
+ LLVM_READOBJ_TYPE_CASE(TEXTREL);
+ LLVM_READOBJ_TYPE_CASE(VERNEED);
+ LLVM_READOBJ_TYPE_CASE(VERNEEDNUM);
+ LLVM_READOBJ_TYPE_CASE(VERSYM);
+ LLVM_READOBJ_TYPE_CASE(RELCOUNT);
+ LLVM_READOBJ_TYPE_CASE(GNU_HASH);
+ LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION);
+ LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS);
+ LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS);
+ LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO);
+ LLVM_READOBJ_TYPE_CASE(MIPS_SYMTABNO);
+ LLVM_READOBJ_TYPE_CASE(MIPS_UNREFEXTNO);
+ LLVM_READOBJ_TYPE_CASE(MIPS_GOTSYM);
+ LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP);
+ LLVM_READOBJ_TYPE_CASE(MIPS_PLTGOT);
+ LLVM_READOBJ_TYPE_CASE(MIPS_OPTIONS);
+ default: return "unknown";
+ }
+}
+
+#undef LLVM_READOBJ_TYPE_CASE
+
+#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \
+ { #enum, prefix##_##enum }
+
+static const EnumEntry<unsigned> ElfDynamicDTFlags[] = {
+ LLVM_READOBJ_DT_FLAG_ENT(DF, ORIGIN),
+ LLVM_READOBJ_DT_FLAG_ENT(DF, SYMBOLIC),
+ LLVM_READOBJ_DT_FLAG_ENT(DF, TEXTREL),
+ LLVM_READOBJ_DT_FLAG_ENT(DF, BIND_NOW),
+ LLVM_READOBJ_DT_FLAG_ENT(DF, STATIC_TLS)
+};
+
+static const EnumEntry<unsigned> ElfDynamicDTFlags1[] = {
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOW),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAL),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, GROUP),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODELETE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, LOADFLTR),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, INITFIRST),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOOPEN),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, ORIGIN),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, DIRECT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, TRANS),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, INTERPOSE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODEFLIB),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODUMP),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, CONFALT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, ENDFILTEE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELDNE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODIRECT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, IGNMULDEF),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOKSYMS),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOHDR),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, EDITED),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NORELOC),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, SYMINTPOSE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAUDIT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON)
+};
+
+static const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = {
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, NONE),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, QUICKSTART),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, NOTPOT),
+ LLVM_READOBJ_DT_FLAG_ENT(RHS, NO_LIBRARY_REPLACEMENT),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_MOVE),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, SGI_ONLY),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_INIT),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, DELTA_C_PLUS_PLUS),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_START_INIT),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, PIXIE),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, DEFAULT_DELAY_LOAD),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTART),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTARTED),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, CORD),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_UNRES_UNDEF),
+ LLVM_READOBJ_DT_FLAG_ENT(RHF, RLD_ORDER_SAFE)
+};
+
+#undef LLVM_READOBJ_DT_FLAG_ENT
+
+template <typename T, typename TFlag>
+void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) {
+ typedef EnumEntry<TFlag> FlagEntry;
+ typedef SmallVector<FlagEntry, 10> FlagVector;
+ FlagVector SetFlags;
+
+ for (const auto &Flag : Flags) {
+ if (Flag.Value == 0)
+ continue;
+
+ if ((Value & Flag.Value) == Flag.Value)
+ SetFlags.push_back(Flag);
+ }
+
+ for (const auto &Flag : SetFlags) {
+ OS << Flag.Name << " ";
+ }
+}
+
+template <class ELFT>
+static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value,
+ bool Is64, raw_ostream &OS) {
+ switch (Type) {
+ case DT_PLTREL:
+ if (Value == DT_REL) {
+ OS << "REL";
+ break;
+ } else if (Value == DT_RELA) {
+ OS << "RELA";
+ break;
+ }
+ // Fallthrough.
+ case DT_PLTGOT:
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_SYMTAB:
+ case DT_RELA:
+ case DT_INIT:
+ case DT_FINI:
+ case DT_REL:
+ case DT_JMPREL:
+ case DT_INIT_ARRAY:
+ case DT_FINI_ARRAY:
+ case DT_PREINIT_ARRAY:
+ case DT_DEBUG:
+ case DT_VERNEED:
+ case DT_VERSYM:
+ case DT_GNU_HASH:
+ case DT_NULL:
+ case DT_MIPS_BASE_ADDRESS:
+ case DT_MIPS_GOTSYM:
+ case DT_MIPS_RLD_MAP:
+ case DT_MIPS_PLTGOT:
+ case DT_MIPS_OPTIONS:
+ OS << format("0x%" PRIX64, Value);
+ break;
+ case DT_RELCOUNT:
+ case DT_VERNEEDNUM:
+ case DT_MIPS_RLD_VERSION:
+ case DT_MIPS_LOCAL_GOTNO:
+ case DT_MIPS_SYMTABNO:
+ case DT_MIPS_UNREFEXTNO:
+ OS << Value;
+ break;
+ case DT_PLTRELSZ:
+ case DT_RELASZ:
+ case DT_RELAENT:
+ case DT_STRSZ:
+ case DT_SYMENT:
+ case DT_RELSZ:
+ case DT_RELENT:
+ case DT_INIT_ARRAYSZ:
+ case DT_FINI_ARRAYSZ:
+ case DT_PREINIT_ARRAYSZ:
+ OS << Value << " (bytes)";
+ break;
+ case DT_NEEDED:
+ OS << "SharedLibrary (" << O->getDynamicString(Value) << ")";
+ break;
+ case DT_SONAME:
+ OS << "LibrarySoname (" << O->getDynamicString(Value) << ")";
+ break;
+ case DT_RPATH:
+ case DT_RUNPATH:
+ OS << O->getDynamicString(Value);
+ break;
+ case DT_MIPS_FLAGS:
+ printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS);
+ break;
+ case DT_FLAGS:
+ printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS);
+ break;
+ case DT_FLAGS_1:
+ printFlags(Value, makeArrayRef(ElfDynamicDTFlags1), OS);
+ break;
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printUnwindInfo() {
+ W.startLine() << "UnwindInfo not implemented.\n";
+}
+
+namespace {
+template <>
+void ELFDumper<ELFType<support::little, 2, false> >::printUnwindInfo() {
+ const unsigned Machine = Obj->getHeader()->e_machine;
+ if (Machine == EM_ARM) {
+ ARM::EHABI::PrinterContext<ELFType<support::little, 2, false> > Ctx(W, Obj);
+ return Ctx.PrintUnwindInformation();
+ }
+ W.startLine() << "UnwindInfo not implemented.\n";
+}
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printDynamicTable() {
+ auto DynTable = Obj->dynamic_table(true);
+
+ ptrdiff_t Total = std::distance(DynTable.begin(), DynTable.end());
+ if (Total == 0)
+ return;
+
+ raw_ostream &OS = W.getOStream();
+ W.startLine() << "DynamicSection [ (" << Total << " entries)\n";
+
+ bool Is64 = ELFT::Is64Bits;
+
+ W.startLine()
+ << " Tag" << (Is64 ? " " : " ") << "Type"
+ << " " << "Name/Value\n";
+ for (const auto &Entry : DynTable) {
+ W.startLine()
+ << " "
+ << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag())
+ << " " << format("%-21s", getTypeString(Entry.getTag()));
+ printValue(Obj, Entry.getTag(), Entry.getVal(), Is64, OS);
+ OS << "\n";
+ }
+
+ W.startLine() << "]\n";
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printNeededLibraries() {
+ ListScope D(W, "NeededLibraries");
+
+ typedef std::vector<StringRef> LibsTy;
+ LibsTy Libs;
+
+ for (const auto &Entry : Obj->dynamic_table())
+ if (Entry.d_tag == ELF::DT_NEEDED)
+ Libs.push_back(Obj->getDynamicString(Entry.d_un.d_val));
+
+ std::stable_sort(Libs.begin(), Libs.end());
+
+ for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); I != E; ++I) {
+ outs() << " " << *I << "\n";
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printProgramHeaders() {
+ ListScope L(W, "ProgramHeaders");
+
+ for (typename ELFO::Elf_Phdr_Iter PI = Obj->begin_program_headers(),
+ PE = Obj->end_program_headers();
+ PI != PE; ++PI) {
+ DictScope P(W, "ProgramHeader");
+ W.printHex ("Type",
+ getElfSegmentType(Obj->getHeader()->e_machine, PI->p_type),
+ PI->p_type);
+ W.printHex ("Offset", PI->p_offset);
+ W.printHex ("VirtualAddress", PI->p_vaddr);
+ W.printHex ("PhysicalAddress", PI->p_paddr);
+ W.printNumber("FileSize", PI->p_filesz);
+ W.printNumber("MemSize", PI->p_memsz);
+ W.printFlags ("Flags", PI->p_flags, makeArrayRef(ElfSegmentFlags));
+ W.printNumber("Alignment", PI->p_align);
+ }
+}
+
+template <class ELFT>
+void ELFDumper<ELFT>::printAttributes() {
+ W.startLine() << "Attributes not implemented.\n";
+}
+
+namespace {
+template <>
+void ELFDumper<ELFType<support::little, 2, false> >::printAttributes() {
+ if (Obj->getHeader()->e_machine != EM_ARM) {
+ W.startLine() << "Attributes not implemented.\n";
+ return;
+ }
+
+ DictScope BA(W, "BuildAttributes");
+ for (ELFO::Elf_Shdr_Iter SI = Obj->begin_sections(), SE = Obj->end_sections();
+ SI != SE; ++SI) {
+ if (SI->sh_type != ELF::SHT_ARM_ATTRIBUTES)
+ continue;
+
+ ErrorOr<ArrayRef<uint8_t> > Contents = Obj->getSectionContents(&(*SI));
+ if (!Contents)
+ continue;
+
+ if ((*Contents)[0] != ARMBuildAttrs::Format_Version) {
+ errs() << "unrecognised FormatVersion: 0x" << utohexstr((*Contents)[0])
+ << '\n';
+ continue;
+ }
+
+ W.printHex("FormatVersion", (*Contents)[0]);
+ if (Contents->size() == 1)
+ continue;
+
+ ARMAttributeParser(W).Parse(*Contents);
+ }
+}
+}
+
+namespace {
+template <class ELFT> class MipsGOTParser {
+public:
+ typedef object::ELFFile<ELFT> ObjectFile;
+ typedef typename ObjectFile::Elf_Shdr Elf_Shdr;
+
+ MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) : Obj(Obj), W(W) {}
+
+ void parseGOT(const Elf_Shdr &GOTShdr);
+
+private:
+ typedef typename ObjectFile::Elf_Sym_Iter Elf_Sym_Iter;
+ typedef typename ObjectFile::Elf_Addr GOTEntry;
+ typedef typename ObjectFile::template ELFEntityIterator<const GOTEntry>
+ GOTIter;
+
+ const ObjectFile *Obj;
+ StreamWriter &W;
+
+ std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const;
+ GOTIter makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum);
+
+ bool getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym);
+ void printGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It);
+ void printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It,
+ Elf_Sym_Iter Sym);
+};
+}
+
+template <class ELFT>
+void MipsGOTParser<ELFT>::parseGOT(const Elf_Shdr &GOTShdr) {
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed GOT description.
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+
+ ErrorOr<ArrayRef<uint8_t>> GOT = Obj->getSectionContents(&GOTShdr);
+ if (!GOT) {
+ W.startLine() << "The .got section is empty.\n";
+ return;
+ }
+
+ uint64_t DtLocalGotNum;
+ uint64_t DtGotSym;
+ if (!getGOTTags(DtLocalGotNum, DtGotSym))
+ return;
+
+ if (DtLocalGotNum > getGOTTotal(*GOT)) {
+ W.startLine() << "MIPS_LOCAL_GOTNO exceeds a number of GOT entries.\n";
+ return;
+ }
+
+ Elf_Sym_Iter DynSymBegin = Obj->begin_dynamic_symbols();
+ Elf_Sym_Iter DynSymEnd = Obj->end_dynamic_symbols();
+ std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd));
+
+ if (DtGotSym > DynSymTotal) {
+ W.startLine() << "MIPS_GOTSYM exceeds a number of dynamic symbols.\n";
+ return;
+ }
+
+ std::size_t GlobalGotNum = DynSymTotal - DtGotSym;
+
+ if (DtLocalGotNum + GlobalGotNum > getGOTTotal(*GOT)) {
+ W.startLine() << "Number of global GOT entries exceeds the size of GOT.\n";
+ return;
+ }
+
+ GOTIter GotBegin = makeGOTIter(*GOT, 0);
+ GOTIter GotLocalEnd = makeGOTIter(*GOT, DtLocalGotNum);
+ GOTIter It = GotBegin;
+
+ DictScope GS(W, "Primary GOT");
+
+ W.printHex("Canonical gp value", GOTShdr.sh_addr + 0x7ff0);
+ {
+ ListScope RS(W, "Reserved entries");
+
+ {
+ DictScope D(W, "Entry");
+ printGotEntry(GOTShdr.sh_addr, GotBegin, It++);
+ W.printString("Purpose", StringRef("Lazy resolver"));
+ }
+
+ if (It != GotLocalEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) {
+ DictScope D(W, "Entry");
+ printGotEntry(GOTShdr.sh_addr, GotBegin, It++);
+ W.printString("Purpose", StringRef("Module pointer (GNU extension)"));
+ }
+ }
+ {
+ ListScope LS(W, "Local entries");
+ for (; It != GotLocalEnd; ++It) {
+ DictScope D(W, "Entry");
+ printGotEntry(GOTShdr.sh_addr, GotBegin, It);
+ }
+ }
+ {
+ ListScope GS(W, "Global entries");
+
+ GOTIter GotGlobalEnd = makeGOTIter(*GOT, DtLocalGotNum + GlobalGotNum);
+ Elf_Sym_Iter GotDynSym = DynSymBegin + DtGotSym;
+ for (; It != GotGlobalEnd; ++It) {
+ DictScope D(W, "Entry");
+ printGlobalGotEntry(GOTShdr.sh_addr, GotBegin, It, GotDynSym++);
+ }
+ }
+
+ std::size_t SpecGotNum = getGOTTotal(*GOT) - DtLocalGotNum - GlobalGotNum;
+ W.printNumber("Number of TLS and multi-GOT entries", uint64_t(SpecGotNum));
+}
+
+template <class ELFT>
+std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const {
+ return GOT.size() / sizeof(GOTEntry);
+}
+
+template <class ELFT>
+typename MipsGOTParser<ELFT>::GOTIter
+MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) {
+ const char *Data = reinterpret_cast<const char *>(GOT.data());
+ return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry));
+}
+
+template <class ELFT>
+bool MipsGOTParser<ELFT>::getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym) {
+ bool FoundLocalGotNum = false;
+ bool FoundGotSym = false;
+ for (const auto &Entry : Obj->dynamic_table()) {
+ switch (Entry.getTag()) {
+ case ELF::DT_MIPS_LOCAL_GOTNO:
+ LocalGotNum = Entry.getVal();
+ FoundLocalGotNum = true;
+ break;
+ case ELF::DT_MIPS_GOTSYM:
+ GotSym = Entry.getVal();
+ FoundGotSym = true;
+ break;
+ }
+ }
+
+ if (!FoundLocalGotNum) {
+ W.startLine() << "Cannot find MIPS_LOCAL_GOTNO dynamic table tag.\n";
+ return false;
+ }
+
+ if (!FoundGotSym) {
+ W.startLine() << "Cannot find MIPS_GOTSYM dynamic table tag.\n";
+ return false;
+ }
+
+ return true;
+}
+
+template <class ELFT>
+void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt,
+ GOTIter It) {
+ int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry);
+ W.printHex("Address", GotAddr + Offset);
+ W.printNumber("Access", Offset - 0x7ff0);
+ W.printHex("Initial", *It);
+}
+
+template <class ELFT>
+void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt,
+ GOTIter It, Elf_Sym_Iter Sym) {
+ printGotEntry(GotAddr, BeginIt, It);
+
+ W.printHex("Value", Sym->st_value);
+ W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes));
+
+ unsigned SectionIndex = 0;
+ StringRef SectionName;
+ getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex);
+ W.printHex("Section", SectionName, SectionIndex);
+
+ std::string FullSymbolName = getFullSymbolName(*Obj, Sym);
+ W.printNumber("Name", FullSymbolName, Sym->st_name);
+}
+
+template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() {
+ if (Obj->getHeader()->e_machine != EM_MIPS) {
+ W.startLine() << "MIPS PLT GOT is available for MIPS targets only.\n";
+ return;
+ }
+
+ llvm::Optional<uint64_t> DtPltGot;
+ for (const auto &Entry : Obj->dynamic_table()) {
+ if (Entry.getTag() == ELF::DT_PLTGOT) {
+ DtPltGot = Entry.getVal();
+ break;
+ }
+ }
+
+ if (!DtPltGot) {
+ W.startLine() << "Cannot find PLTGOT dynamic table tag.\n";
+ return;
+ }
+
+ const Elf_Shdr *GotShdr = findSectionByAddress(Obj, *DtPltGot);
+ if (!GotShdr) {
+ W.startLine() << "There is no .got section in the file.\n";
+ return;
+ }
+
+ MipsGOTParser<ELFT>(Obj, W).parseGOT(*GotShdr);
+}
+
+static const EnumEntry<unsigned> ElfMipsISAExtType[] = {
+ {"None", Mips::AFL_EXT_NONE},
+ {"Broadcom SB-1", Mips::AFL_EXT_SB1},
+ {"Cavium Networks Octeon", Mips::AFL_EXT_OCTEON},
+ {"Cavium Networks Octeon2", Mips::AFL_EXT_OCTEON2},
+ {"Cavium Networks OcteonP", Mips::AFL_EXT_OCTEONP},
+ {"Cavium Networks Octeon3", Mips::AFL_EXT_OCTEON3},
+ {"LSI R4010", Mips::AFL_EXT_4010},
+ {"Loongson 2E", Mips::AFL_EXT_LOONGSON_2E},
+ {"Loongson 2F", Mips::AFL_EXT_LOONGSON_2F},
+ {"Loongson 3A", Mips::AFL_EXT_LOONGSON_3A},
+ {"MIPS R4650", Mips::AFL_EXT_4650},
+ {"MIPS R5900", Mips::AFL_EXT_5900},
+ {"MIPS R10000", Mips::AFL_EXT_10000},
+ {"NEC VR4100", Mips::AFL_EXT_4100},
+ {"NEC VR4111/VR4181", Mips::AFL_EXT_4111},
+ {"NEC VR4120", Mips::AFL_EXT_4120},
+ {"NEC VR5400", Mips::AFL_EXT_5400},
+ {"NEC VR5500", Mips::AFL_EXT_5500},
+ {"RMI Xlr", Mips::AFL_EXT_XLR},
+ {"Toshiba R3900", Mips::AFL_EXT_3900}
+};
+
+static const EnumEntry<unsigned> ElfMipsASEFlags[] = {
+ {"DSP", Mips::AFL_ASE_DSP},
+ {"DSPR2", Mips::AFL_ASE_DSPR2},
+ {"Enhanced VA Scheme", Mips::AFL_ASE_EVA},
+ {"MCU", Mips::AFL_ASE_MCU},
+ {"MDMX", Mips::AFL_ASE_MDMX},
+ {"MIPS-3D", Mips::AFL_ASE_MIPS3D},
+ {"MT", Mips::AFL_ASE_MT},
+ {"SmartMIPS", Mips::AFL_ASE_SMARTMIPS},
+ {"VZ", Mips::AFL_ASE_VIRT},
+ {"MSA", Mips::AFL_ASE_MSA},
+ {"MIPS16", Mips::AFL_ASE_MIPS16},
+ {"microMIPS", Mips::AFL_ASE_MICROMIPS},
+ {"XPA", Mips::AFL_ASE_XPA}
+};
+
+static const EnumEntry<unsigned> ElfMipsFpABIType[] = {
+ {"Hard or soft float", Mips::Val_GNU_MIPS_ABI_FP_ANY},
+ {"Hard float (double precision)", Mips::Val_GNU_MIPS_ABI_FP_DOUBLE},
+ {"Hard float (single precision)", Mips::Val_GNU_MIPS_ABI_FP_SINGLE},
+ {"Soft float", Mips::Val_GNU_MIPS_ABI_FP_SOFT},
+ {"Hard float (MIPS32r2 64-bit FPU 12 callee-saved)",
+ Mips::Val_GNU_MIPS_ABI_FP_OLD_64},
+ {"Hard float (32-bit CPU, Any FPU)", Mips::Val_GNU_MIPS_ABI_FP_XX},
+ {"Hard float (32-bit CPU, 64-bit FPU)", Mips::Val_GNU_MIPS_ABI_FP_64},
+ {"Hard float compat (32-bit CPU, 64-bit FPU)",
+ Mips::Val_GNU_MIPS_ABI_FP_64A}
+};
+
+static const EnumEntry<unsigned> ElfMipsFlags1[] {
+ {"ODDSPREG", Mips::AFL_FLAGS1_ODDSPREG},
+};
+
+static int getMipsRegisterSize(uint8_t Flag) {
+ switch (Flag) {
+ case Mips::AFL_REG_NONE:
+ return 0;
+ case Mips::AFL_REG_32:
+ return 32;
+ case Mips::AFL_REG_64:
+ return 64;
+ case Mips::AFL_REG_128:
+ return 128;
+ default:
+ return -1;
+ }
+}
+
+template <class ELFT> void ELFDumper<ELFT>::printMipsABIFlags() {
+ const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.abiflags");
+ if (!Shdr) {
+ W.startLine() << "There is no .MIPS.abiflags section in the file.\n";
+ return;
+ }
+ ErrorOr<ArrayRef<uint8_t>> Sec = Obj->getSectionContents(Shdr);
+ if (!Sec) {
+ W.startLine() << "The .MIPS.abiflags section is empty.\n";
+ return;
+ }
+ if (Sec->size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) {
+ W.startLine() << "The .MIPS.abiflags section has a wrong size.\n";
+ return;
+ }
+
+ auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec->data());
+
+ raw_ostream &OS = W.getOStream();
+ DictScope GS(W, "MIPS ABI Flags");
+
+ W.printNumber("Version", Flags->version);
+ W.startLine() << "ISA: ";
+ if (Flags->isa_rev <= 1)
+ OS << format("MIPS%u", Flags->isa_level);
+ else
+ OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev);
+ OS << "\n";
+ W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType));
+ W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags));
+ W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType));
+ W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size));
+ W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size));
+ W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size));
+ W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1));
+ W.printHex("Flags 2", Flags->flags2);
+}
diff --git a/contrib/llvm/tools/llvm-readobj/Error.cpp b/contrib/llvm/tools/llvm-readobj/Error.cpp
new file mode 100644
index 0000000..7e6f780
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/Error.cpp
@@ -0,0 +1,54 @@
+//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines a new error_category for the llvm-readobj tool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+class _readobj_error_category : public std::error_category {
+public:
+ const char* name() const LLVM_NOEXCEPT override;
+ std::string message(int ev) const override;
+};
+} // namespace
+
+const char *_readobj_error_category::name() const LLVM_NOEXCEPT {
+ return "llvm.readobj";
+}
+
+std::string _readobj_error_category::message(int EV) const {
+ switch (static_cast<readobj_error>(EV)) {
+ case readobj_error::success: return "Success";
+ case readobj_error::file_not_found:
+ return "No such file.";
+ case readobj_error::unsupported_file_format:
+ return "The file was not recognized as a valid object file.";
+ case readobj_error::unrecognized_file_format:
+ return "Unrecognized file type.";
+ case readobj_error::unsupported_obj_file_format:
+ return "Unsupported object file format.";
+ case readobj_error::unknown_symbol:
+ return "Unknown symbol.";
+ }
+ llvm_unreachable("An enumerator of readobj_error does not have a message "
+ "defined.");
+}
+
+namespace llvm {
+const std::error_category &readobj_category() {
+ static _readobj_error_category o;
+ return o;
+}
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-readobj/Error.h b/contrib/llvm/tools/llvm-readobj/Error.h
new file mode 100644
index 0000000..f3e24bb
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/Error.h
@@ -0,0 +1,41 @@
+//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares a new error_category for the llvm-readobj tool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ERROR_H
+#define LLVM_TOOLS_LLVM_READOBJ_ERROR_H
+
+#include <system_error>
+
+namespace llvm {
+const std::error_category &readobj_category();
+
+enum class readobj_error {
+ success = 0,
+ file_not_found,
+ unsupported_file_format,
+ unrecognized_file_format,
+ unsupported_obj_file_format,
+ unknown_symbol
+};
+
+inline std::error_code make_error_code(readobj_error e) {
+ return std::error_code(static_cast<int>(e), readobj_category());
+}
+
+} // namespace llvm
+
+namespace std {
+template <> struct is_error_code_enum<llvm::readobj_error> : std::true_type {};
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
new file mode 100644
index 0000000..40691a2
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -0,0 +1,563 @@
+//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MachO-specific dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Casting.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+class MachODumper : public ObjDumper {
+public:
+ MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) { }
+
+ void printFileHeaders() override;
+ void printSections() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override;
+ void printUnwindInfo() override;
+
+private:
+ template<class MachHeader>
+ void printFileHeaders(const MachHeader &Header);
+
+ void printSymbol(const SymbolRef &Symbol);
+
+ void printRelocation(const RelocationRef &Reloc);
+
+ void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc);
+
+ void printSections(const MachOObjectFile *Obj);
+
+ const MachOObjectFile *Obj;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+std::error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
+ if (!MachOObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new MachODumper(MachOObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
+
+static const EnumEntry<uint32_t> MachOMagics[] = {
+ { "Magic", MachO::MH_MAGIC },
+ { "Cigam", MachO::MH_CIGAM },
+ { "Magic64", MachO::MH_MAGIC_64 },
+ { "Cigam64", MachO::MH_CIGAM_64 },
+ { "FatMagic", MachO::FAT_MAGIC },
+ { "FatCigam", MachO::FAT_CIGAM },
+};
+
+static const EnumEntry<uint32_t> MachOHeaderFileTypes[] = {
+ { "Relocatable", MachO::MH_OBJECT },
+ { "Executable", MachO::MH_EXECUTE },
+ { "FixedVMLibrary", MachO::MH_FVMLIB },
+ { "Core", MachO::MH_CORE },
+ { "PreloadedExecutable", MachO::MH_PRELOAD },
+ { "DynamicLibrary", MachO::MH_DYLIB },
+ { "DynamicLinker", MachO::MH_DYLINKER },
+ { "Bundle", MachO::MH_BUNDLE },
+ { "DynamicLibraryStub", MachO::MH_DYLIB_STUB },
+ { "DWARFSymbol", MachO::MH_DSYM },
+ { "KextBundle", MachO::MH_KEXT_BUNDLE },
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuTypes[] = {
+ { "Any" , static_cast<uint32_t>(MachO::CPU_TYPE_ANY) },
+ { "X86" , MachO::CPU_TYPE_X86 },
+ { "X86-64" , MachO::CPU_TYPE_X86_64 },
+ { "Mc98000" , MachO::CPU_TYPE_MC98000 },
+ { "Arm" , MachO::CPU_TYPE_ARM },
+ { "Arm64" , MachO::CPU_TYPE_ARM64 },
+ { "Sparc" , MachO::CPU_TYPE_SPARC },
+ { "PowerPC" , MachO::CPU_TYPE_POWERPC },
+ { "PowerPC64" , MachO::CPU_TYPE_POWERPC64 },
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX86[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX64[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V4T),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5TEJ),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_XSCALE),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7S),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7K),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7EM),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM64[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesSPARC[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesPPC[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE),
+};
+
+static const EnumEntry<unsigned> MachOSectionAttributes[] = {
+ { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ },
+ { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ },
+ { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ },
+ { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ },
+ { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
+ { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ },
+ { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ },
+ { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ },
+ { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ },
+ { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ },
+};
+
+static const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
+ { "UndefinedNonLazy", 0 },
+ { "ReferenceFlagUndefinedLazy", 1 },
+ { "ReferenceFlagDefined", 2 },
+ { "ReferenceFlagPrivateDefined", 3 },
+ { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
+ { "ReferenceFlagPrivateUndefinedLazy", 5 }
+};
+
+static const EnumEntry<unsigned> MachOSymbolFlags[] = {
+ { "ReferencedDynamically", 0x10 },
+ { "NoDeadStrip", 0x20 },
+ { "WeakRef", 0x40 },
+ { "WeakDef", 0x80 }
+};
+
+static const EnumEntry<unsigned> MachOSymbolTypes[] = {
+ { "Undef", 0x0 },
+ { "Abs", 0x2 },
+ { "Indirect", 0xA },
+ { "PreboundUndef", 0xC },
+ { "Section", 0xE }
+};
+
+namespace {
+ struct MachOSection {
+ ArrayRef<char> Name;
+ ArrayRef<char> SegmentName;
+ uint64_t Address;
+ uint64_t Size;
+ uint32_t Offset;
+ uint32_t Alignment;
+ uint32_t RelocationTableOffset;
+ uint32_t NumRelocationTableEntries;
+ uint32_t Flags;
+ uint32_t Reserved1;
+ uint32_t Reserved2;
+ };
+
+ struct MachOSymbol {
+ uint32_t StringIndex;
+ uint8_t Type;
+ uint8_t SectionIndex;
+ uint16_t Flags;
+ uint64_t Value;
+ };
+}
+
+static void getSection(const MachOObjectFile *Obj,
+ DataRefImpl Sec,
+ MachOSection &Section) {
+ if (!Obj->is64Bit()) {
+ MachO::section Sect = Obj->getSection(Sec);
+ Section.Address = Sect.addr;
+ Section.Size = Sect.size;
+ Section.Offset = Sect.offset;
+ Section.Alignment = Sect.align;
+ Section.RelocationTableOffset = Sect.reloff;
+ Section.NumRelocationTableEntries = Sect.nreloc;
+ Section.Flags = Sect.flags;
+ Section.Reserved1 = Sect.reserved1;
+ Section.Reserved2 = Sect.reserved2;
+ return;
+ }
+ MachO::section_64 Sect = Obj->getSection64(Sec);
+ Section.Address = Sect.addr;
+ Section.Size = Sect.size;
+ Section.Offset = Sect.offset;
+ Section.Alignment = Sect.align;
+ Section.RelocationTableOffset = Sect.reloff;
+ Section.NumRelocationTableEntries = Sect.nreloc;
+ Section.Flags = Sect.flags;
+ Section.Reserved1 = Sect.reserved1;
+ Section.Reserved2 = Sect.reserved2;
+}
+
+
+static void getSymbol(const MachOObjectFile *Obj,
+ DataRefImpl DRI,
+ MachOSymbol &Symbol) {
+ if (!Obj->is64Bit()) {
+ MachO::nlist Entry = Obj->getSymbolTableEntry(DRI);
+ Symbol.StringIndex = Entry.n_strx;
+ Symbol.Type = Entry.n_type;
+ Symbol.SectionIndex = Entry.n_sect;
+ Symbol.Flags = Entry.n_desc;
+ Symbol.Value = Entry.n_value;
+ return;
+ }
+ MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI);
+ Symbol.StringIndex = Entry.n_strx;
+ Symbol.Type = Entry.n_type;
+ Symbol.SectionIndex = Entry.n_sect;
+ Symbol.Flags = Entry.n_desc;
+ Symbol.Value = Entry.n_value;
+}
+
+void MachODumper::printFileHeaders() {
+ DictScope H(W, "MachHeader");
+ if (!Obj->is64Bit()) {
+ printFileHeaders(Obj->getHeader());
+ } else {
+ printFileHeaders(Obj->getHeader64());
+ W.printHex("Reserved", Obj->getHeader64().reserved);
+ }
+}
+
+template<class MachHeader>
+void MachODumper::printFileHeaders(const MachHeader &Header) {
+ W.printEnum("Magic", Header.magic, makeArrayRef(MachOMagics));
+ W.printEnum("CpuType", Header.cputype, makeArrayRef(MachOHeaderCpuTypes));
+ uint32_t subtype = Header.cpusubtype & ~MachO::CPU_SUBTYPE_MASK;
+ switch (Header.cputype) {
+ case MachO::CPU_TYPE_X86:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX86));
+ break;
+ case MachO::CPU_TYPE_X86_64:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX64));
+ break;
+ case MachO::CPU_TYPE_ARM:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM));
+ break;
+ case MachO::CPU_TYPE_POWERPC:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesPPC));
+ break;
+ case MachO::CPU_TYPE_SPARC:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesSPARC));
+ break;
+ case MachO::CPU_TYPE_ARM64:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM64));
+ break;
+ case MachO::CPU_TYPE_POWERPC64:
+ default:
+ W.printHex("CpuSubtype", subtype);
+ }
+ W.printEnum("FileType", Header.filetype, makeArrayRef(MachOHeaderFileTypes));
+ W.printNumber("NumOfLoadCommands", Header.ncmds);
+ W.printNumber("SizeOfLoadCommands", Header.sizeofcmds);
+ W.printFlags("Flags", Header.flags, makeArrayRef(MachOHeaderFlags));
+}
+
+void MachODumper::printSections() {
+ return printSections(Obj);
+}
+
+void MachODumper::printSections(const MachOObjectFile *Obj) {
+ ListScope Group(W, "Sections");
+
+ int SectionIndex = -1;
+ for (const SectionRef &Section : Obj->sections()) {
+ ++SectionIndex;
+
+ MachOSection MOSection;
+ getSection(Obj, Section.getRawDataRefImpl(), MOSection);
+ DataRefImpl DR = Section.getRawDataRefImpl();
+
+ StringRef Name;
+ if (error(Section.getName(Name)))
+ Name = "";
+
+ ArrayRef<char> RawName = Obj->getSectionRawName(DR);
+ StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);
+ ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR);
+
+ DictScope SectionD(W, "Section");
+ W.printNumber("Index", SectionIndex);
+ W.printBinary("Name", Name, RawName);
+ W.printBinary("Segment", SegmentName, RawSegmentName);
+ W.printHex("Address", MOSection.Address);
+ W.printHex("Size", MOSection.Size);
+ W.printNumber("Offset", MOSection.Offset);
+ W.printNumber("Alignment", MOSection.Alignment);
+ W.printHex("RelocationOffset", MOSection.RelocationTableOffset);
+ W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries);
+ W.printEnum("Type", MOSection.Flags & 0xFF,
+ makeArrayRef(MachOSectionAttributes));
+ W.printFlags("Attributes", MOSection.Flags >> 8,
+ makeArrayRef(MachOSectionAttributes));
+ W.printHex("Reserved1", MOSection.Reserved1);
+ W.printHex("Reserved2", MOSection.Reserved2);
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (const RelocationRef &Reloc : Section.relocations())
+ printRelocation(Reloc);
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (const SymbolRef &Symbol : Obj->symbols()) {
+ if (!Section.containsSymbol(Symbol))
+ continue;
+
+ printSymbol(Symbol);
+ }
+ }
+
+ if (opts::SectionData) {
+ bool IsBSS = Section.isBSS();
+ if (!IsBSS) {
+ StringRef Data;
+ if (error(Section.getContents(Data)))
+ break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+ }
+}
+
+void MachODumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ std::error_code EC;
+ for (const SectionRef &Section : Obj->sections()) {
+ StringRef Name;
+ if (error(Section.getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ if (!PrintedGroup) {
+ W.startLine() << "Section " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(Reloc);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void MachODumper::printRelocation(const RelocationRef &Reloc) {
+ return printRelocation(Obj, Reloc);
+}
+
+void MachODumper::printRelocation(const MachOObjectFile *Obj,
+ const RelocationRef &Reloc) {
+ uint64_t Offset;
+ SmallString<32> RelocName;
+ if (error(Reloc.getOffset(Offset)))
+ return;
+ if (error(Reloc.getTypeName(RelocName)))
+ return;
+
+ DataRefImpl DR = Reloc.getRawDataRefImpl();
+ MachO::any_relocation_info RE = Obj->getRelocation(DR);
+ bool IsScattered = Obj->isRelocationScattered(RE);
+ SmallString<32> SymbolNameOrOffset("0x");
+ if (IsScattered) {
+ // Scattered relocations don't really have an associated symbol
+ // for some reason, even if one exists in the symtab at the correct address.
+ SymbolNameOrOffset += utohexstr(Obj->getScatteredRelocationValue(RE));
+ } else {
+ symbol_iterator Symbol = Reloc.getSymbol();
+ if (Symbol != Obj->symbol_end()) {
+ StringRef SymbolName;
+ if (error(Symbol->getName(SymbolName)))
+ return;
+ SymbolNameOrOffset = SymbolName;
+ } else
+ SymbolNameOrOffset += utohexstr(Obj->getPlainRelocationSymbolNum(RE));
+ }
+
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printHex("Offset", Offset);
+ W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE));
+ W.printNumber("Length", Obj->getAnyRelocationLength(RE));
+ if (IsScattered)
+ W.printString("Extern", StringRef("N/A"));
+ else
+ W.printNumber("Extern", Obj->getPlainRelocationExternal(RE));
+ W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE));
+ W.printString("Symbol", SymbolNameOrOffset);
+ W.printNumber("Scattered", IsScattered);
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << Obj->getAnyRelocationPCRel(RE)
+ << " " << Obj->getAnyRelocationLength(RE);
+ if (IsScattered)
+ OS << " n/a";
+ else
+ OS << " " << Obj->getPlainRelocationExternal(RE);
+ OS << " " << RelocName
+ << " " << IsScattered
+ << " " << SymbolNameOrOffset
+ << "\n";
+ }
+}
+
+void MachODumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ for (const SymbolRef &Symbol : Obj->symbols()) {
+ printSymbol(Symbol);
+ }
+}
+
+void MachODumper::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+}
+
+void MachODumper::printSymbol(const SymbolRef &Symbol) {
+ StringRef SymbolName;
+ if (Symbol.getName(SymbolName))
+ SymbolName = "";
+
+ MachOSymbol MOSymbol;
+ getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol);
+
+ StringRef SectionName = "";
+ section_iterator SecI(Obj->section_begin());
+ if (!error(Symbol.getSection(SecI)) && SecI != Obj->section_end())
+ error(SecI->getName(SectionName));
+
+ DictScope D(W, "Symbol");
+ W.printNumber("Name", SymbolName, MOSymbol.StringIndex);
+ if (MOSymbol.Type & MachO::N_STAB) {
+ W.printHex("Type", "SymDebugTable", MOSymbol.Type);
+ } else {
+ if (MOSymbol.Type & MachO::N_PEXT)
+ W.startLine() << "PrivateExtern\n";
+ if (MOSymbol.Type & MachO::N_EXT)
+ W.startLine() << "Extern\n";
+ W.printEnum("Type", uint8_t(MOSymbol.Type & MachO::N_TYPE),
+ makeArrayRef(MachOSymbolTypes));
+ }
+ W.printHex("Section", SectionName, MOSymbol.SectionIndex);
+ W.printEnum("RefType", static_cast<uint16_t>(MOSymbol.Flags & 0xF),
+ makeArrayRef(MachOSymbolRefTypes));
+ W.printFlags("Flags", static_cast<uint16_t>(MOSymbol.Flags & ~0xF),
+ makeArrayRef(MachOSymbolFlags));
+ W.printHex("Value", MOSymbol.Value);
+}
+
+void MachODumper::printUnwindInfo() {
+ W.startLine() << "UnwindInfo not implemented.\n";
+}
diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp
new file mode 100644
index 0000000..f500a05
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -0,0 +1,31 @@
+//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements ObjDumper.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ObjDumper.h"
+#include "Error.h"
+#include "StreamWriter.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+ObjDumper::ObjDumper(StreamWriter& Writer)
+ : W(Writer) {
+}
+
+ObjDumper::~ObjDumper() {
+}
+
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h
new file mode 100644
index 0000000..5750d6f
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h
@@ -0,0 +1,71 @@
+//===-- ObjDumper.h -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_OBJDUMPER_H
+#define LLVM_TOOLS_LLVM_READOBJ_OBJDUMPER_H
+
+#include <memory>
+#include <system_error>
+
+namespace llvm {
+namespace object {
+ class ObjectFile;
+}
+
+class StreamWriter;
+
+class ObjDumper {
+public:
+ ObjDumper(StreamWriter& Writer);
+ virtual ~ObjDumper();
+
+ virtual void printFileHeaders() = 0;
+ virtual void printSections() = 0;
+ virtual void printRelocations() = 0;
+ virtual void printSymbols() = 0;
+ virtual void printDynamicSymbols() = 0;
+ virtual void printUnwindInfo() = 0;
+
+ // Only implemented for ELF at this time.
+ virtual void printDynamicTable() { }
+ virtual void printNeededLibraries() { }
+ virtual void printProgramHeaders() { }
+
+ // Only implemented for ARM ELF at this time.
+ virtual void printAttributes() { }
+
+ // Only implemented for MIPS ELF at this time.
+ virtual void printMipsPLTGOT() { }
+ virtual void printMipsABIFlags() { }
+
+ // Only implemented for PE/COFF.
+ virtual void printCOFFImports() { }
+ virtual void printCOFFExports() { }
+ virtual void printCOFFDirectives() { }
+ virtual void printCOFFBaseReloc() { }
+
+protected:
+ StreamWriter& W;
+};
+
+std::error_code createCOFFDumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
+
+std::error_code createELFDumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
+
+std::error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-readobj/StreamWriter.cpp b/contrib/llvm/tools/llvm-readobj/StreamWriter.cpp
new file mode 100644
index 0000000..8718112
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/StreamWriter.cpp
@@ -0,0 +1,79 @@
+#include "StreamWriter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
+#include <cctype>
+
+using namespace llvm::support;
+
+namespace llvm {
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) {
+ uint64_t N = Value.Value;
+ // Zero is a special case.
+ if (N == 0)
+ return OS << "0x0";
+
+ char NumberBuffer[20];
+ char *EndPtr = NumberBuffer + sizeof(NumberBuffer);
+ char *CurPtr = EndPtr;
+
+ while (N) {
+ uintptr_t X = N % 16;
+ *--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10);
+ N /= 16;
+ }
+
+ OS << "0x";
+ return OS.write(CurPtr, EndPtr - CurPtr);
+}
+
+void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str,
+ ArrayRef<uint8_t> Data, bool Block) {
+ if (Data.size() > 16)
+ Block = true;
+
+ if (Block) {
+ startLine() << Label;
+ if (Str.size() > 0)
+ OS << ": " << Str;
+ OS << " (\n";
+ for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) {
+ startLine() << format(" %04" PRIX64 ": ", uint64_t(addr));
+ // Dump line of hex.
+ for (size_t i = 0; i < 16; ++i) {
+ if (i != 0 && i % 4 == 0)
+ OS << ' ';
+ if (addr + i < end)
+ OS << hexdigit((Data[addr + i] >> 4) & 0xF, false)
+ << hexdigit(Data[addr + i] & 0xF, false);
+ else
+ OS << " ";
+ }
+ // Print ascii.
+ OS << " |";
+ for (std::size_t i = 0; i < 16 && addr + i < end; ++i) {
+ if (std::isprint(Data[addr + i] & 0xFF))
+ OS << Data[addr + i];
+ else
+ OS << ".";
+ }
+ OS << "|\n";
+ }
+
+ startLine() << ")\n";
+ } else {
+ startLine() << Label << ":";
+ if (Str.size() > 0)
+ OS << " " << Str;
+ OS << " (";
+ for (size_t i = 0; i < Data.size(); ++i) {
+ if (i > 0)
+ OS << " ";
+
+ OS << format("%02X", static_cast<int>(Data[i]));
+ }
+ OS << ")\n";
+ }
+}
+
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-readobj/StreamWriter.h b/contrib/llvm/tools/llvm-readobj/StreamWriter.h
new file mode 100644
index 0000000..245588b
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/StreamWriter.h
@@ -0,0 +1,304 @@
+//===-- StreamWriter.h ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H
+#define LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::support;
+
+namespace llvm {
+
+template<typename T>
+struct EnumEntry {
+ StringRef Name;
+ T Value;
+};
+
+struct HexNumber {
+ // To avoid sign-extension we have to explicitly cast to the appropriate
+ // unsigned type. The overloads are here so that every type that is implicitly
+ // convertible to an integer (including enums and endian helpers) can be used
+ // without requiring type traits or call-site changes.
+ HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { }
+ HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { }
+ HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { }
+ HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { }
+ HexNumber(uint8_t Value) : Value(Value) { }
+ HexNumber(uint16_t Value) : Value(Value) { }
+ HexNumber(uint32_t Value) : Value(Value) { }
+ HexNumber(uint64_t Value) : Value(Value) { }
+ uint64_t Value;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value);
+
+class StreamWriter {
+public:
+ StreamWriter(raw_ostream &OS)
+ : OS(OS)
+ , IndentLevel(0) {
+ }
+
+ void flush() {
+ OS.flush();
+ }
+
+ void indent(int Levels = 1) {
+ IndentLevel += Levels;
+ }
+
+ void unindent(int Levels = 1) {
+ IndentLevel = std::max(0, IndentLevel - Levels);
+ }
+
+ void printIndent() {
+ for (int i = 0; i < IndentLevel; ++i)
+ OS << " ";
+ }
+
+ template<typename T>
+ HexNumber hex(T Value) {
+ return HexNumber(Value);
+ }
+
+ template<typename T, typename TEnum>
+ void printEnum(StringRef Label, T Value,
+ ArrayRef<EnumEntry<TEnum> > EnumValues) {
+ StringRef Name;
+ bool Found = false;
+ for (const auto &EnumItem : EnumValues) {
+ if (EnumItem.Value == Value) {
+ Name = EnumItem.Name;
+ Found = true;
+ break;
+ }
+ }
+
+ if (Found) {
+ startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
+ } else {
+ startLine() << Label << ": " << hex(Value) << "\n";
+ }
+ }
+
+ template <typename T, typename TFlag>
+ void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
+ TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
+ TFlag EnumMask3 = {}) {
+ typedef EnumEntry<TFlag> FlagEntry;
+ typedef SmallVector<FlagEntry, 10> FlagVector;
+ FlagVector SetFlags;
+
+ for (const auto &Flag : Flags) {
+ if (Flag.Value == 0)
+ continue;
+
+ TFlag EnumMask{};
+ if (Flag.Value & EnumMask1)
+ EnumMask = EnumMask1;
+ else if (Flag.Value & EnumMask2)
+ EnumMask = EnumMask2;
+ else if (Flag.Value & EnumMask3)
+ EnumMask = EnumMask3;
+ bool IsEnum = (Flag.Value & EnumMask) != 0;
+ if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
+ (IsEnum && (Value & EnumMask) == Flag.Value)) {
+ SetFlags.push_back(Flag);
+ }
+ }
+
+ std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
+
+ startLine() << Label << " [ (" << hex(Value) << ")\n";
+ for (const auto &Flag : SetFlags) {
+ startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
+ }
+ startLine() << "]\n";
+ }
+
+ template<typename T>
+ void printFlags(StringRef Label, T Value) {
+ startLine() << Label << " [ (" << hex(Value) << ")\n";
+ uint64_t Flag = 1;
+ uint64_t Curr = Value;
+ while (Curr > 0) {
+ if (Curr & 1)
+ startLine() << " " << hex(Flag) << "\n";
+ Curr >>= 1;
+ Flag <<= 1;
+ }
+ startLine() << "]\n";
+ }
+
+ void printNumber(StringRef Label, uint64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint8_t Value) {
+ startLine() << Label << ": " << unsigned(Value) << "\n";
+ }
+
+ void printNumber(StringRef Label, int64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int8_t Value) {
+ startLine() << Label << ": " << int(Value) << "\n";
+ }
+
+ void printBoolean(StringRef Label, bool Value) {
+ startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
+ }
+
+ template <typename T_>
+ void printList(StringRef Label, const SmallVectorImpl<T_> &List) {
+ startLine() << Label << ": [";
+ bool Comma = false;
+ for (const auto &Item : List) {
+ if (Comma)
+ OS << ", ";
+ OS << Item;
+ Comma = true;
+ }
+ OS << "]\n";
+ }
+
+ template<typename T>
+ void printHex(StringRef Label, T Value) {
+ startLine() << Label << ": " << hex(Value) << "\n";
+ }
+
+ template<typename T>
+ void printHex(StringRef Label, StringRef Str, T Value) {
+ startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
+ }
+
+ void printString(StringRef Label, StringRef Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printString(StringRef Label, const std::string &Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ template<typename T>
+ void printNumber(StringRef Label, StringRef Str, T Value) {
+ startLine() << Label << ": " << Str << " (" << Value << ")\n";
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, Str, Value, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, Str, V, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, StringRef(), Value, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<char> Value) {
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Value) {
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinaryBlock(StringRef Label, StringRef Value) {
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, true);
+ }
+
+ raw_ostream& startLine() {
+ printIndent();
+ return OS;
+ }
+
+ raw_ostream& getOStream() {
+ return OS;
+ }
+
+private:
+ template<typename T>
+ static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) {
+ return lhs.Name < rhs.Name;
+ }
+
+ void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
+ bool Block);
+
+ raw_ostream &OS;
+ int IndentLevel;
+};
+
+struct DictScope {
+ DictScope(StreamWriter& W, StringRef N) : W(W) {
+ W.startLine() << N << " {\n";
+ W.indent();
+ }
+
+ ~DictScope() {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+
+ StreamWriter& W;
+};
+
+struct ListScope {
+ ListScope(StreamWriter& W, StringRef N) : W(W) {
+ W.startLine() << N << " [\n";
+ W.indent();
+ }
+
+ ~ListScope() {
+ W.unindent();
+ W.startLine() << "]\n";
+ }
+
+ StreamWriter& W;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp
new file mode 100644
index 0000000..f058632
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp
@@ -0,0 +1,329 @@
+//===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Win64EHDumper.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::Win64EH;
+
+static const EnumEntry<unsigned> UnwindFlags[] = {
+ { "ExceptionHandler", UNW_ExceptionHandler },
+ { "TerminateHandler", UNW_TerminateHandler },
+ { "ChainInfo" , UNW_ChainInfo }
+};
+
+static const EnumEntry<unsigned> UnwindOpInfo[] = {
+ { "RAX", 0 },
+ { "RCX", 1 },
+ { "RDX", 2 },
+ { "RBX", 3 },
+ { "RSP", 4 },
+ { "RBP", 5 },
+ { "RSI", 6 },
+ { "RDI", 7 },
+ { "R8", 8 },
+ { "R9", 9 },
+ { "R10", 10 },
+ { "R11", 11 },
+ { "R12", 12 },
+ { "R13", 13 },
+ { "R14", 14 },
+ { "R15", 15 }
+};
+
+static uint64_t getOffsetOfLSDA(const UnwindInfo& UI) {
+ return static_cast<const char*>(UI.getLanguageSpecificData())
+ - reinterpret_cast<const char*>(&UI);
+}
+
+static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UC) {
+ if (UC.size() < 3)
+ return 0;
+ return UC[1].FrameOffset + (static_cast<uint32_t>(UC[2].FrameOffset) << 16);
+}
+
+// Returns the name of the unwind code.
+static StringRef getUnwindCodeTypeName(uint8_t Code) {
+ switch (Code) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol: return "PUSH_NONVOL";
+ case UOP_AllocLarge: return "ALLOC_LARGE";
+ case UOP_AllocSmall: return "ALLOC_SMALL";
+ case UOP_SetFPReg: return "SET_FPREG";
+ case UOP_SaveNonVol: return "SAVE_NONVOL";
+ case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR";
+ case UOP_SaveXMM128: return "SAVE_XMM128";
+ case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
+ case UOP_PushMachFrame: return "PUSH_MACHFRAME";
+ }
+}
+
+// Returns the name of a referenced register.
+static StringRef getUnwindRegisterName(uint8_t Reg) {
+ switch (Reg) {
+ default: llvm_unreachable("Invalid register");
+ case 0: return "RAX";
+ case 1: return "RCX";
+ case 2: return "RDX";
+ case 3: return "RBX";
+ case 4: return "RSP";
+ case 5: return "RBP";
+ case 6: return "RSI";
+ case 7: return "RDI";
+ case 8: return "R8";
+ case 9: return "R9";
+ case 10: return "R10";
+ case 11: return "R11";
+ case 12: return "R12";
+ case 13: return "R13";
+ case 14: return "R14";
+ case 15: return "R15";
+ }
+}
+
+// Calculates the number of array slots required for the unwind code.
+static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
+ switch (UnwindCode.getUnwindOp()) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol:
+ case UOP_AllocSmall:
+ case UOP_SetFPReg:
+ case UOP_PushMachFrame:
+ return 1;
+ case UOP_SaveNonVol:
+ case UOP_SaveXMM128:
+ return 2;
+ case UOP_SaveNonVolBig:
+ case UOP_SaveXMM128Big:
+ return 3;
+ case UOP_AllocLarge:
+ return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
+ }
+}
+
+static std::string formatSymbol(const Dumper::Context &Ctx,
+ const coff_section *Section, uint64_t Offset,
+ uint32_t Displacement) {
+ std::string Buffer;
+ raw_string_ostream OS(Buffer);
+
+ StringRef Name;
+ SymbolRef Symbol;
+ if (Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData) ||
+ Symbol.getName(Name)) {
+ OS << format(" (0x%" PRIX64 ")", Offset);
+ return OS.str();
+ }
+
+ OS << Name;
+ if (Displacement > 0)
+ OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset);
+ else
+ OS << format(" (0x%" PRIX64 ")", Offset);
+ return OS.str();
+}
+
+static std::error_code resolveRelocation(const Dumper::Context &Ctx,
+ const coff_section *Section,
+ uint64_t Offset,
+ const coff_section *&ResolvedSection,
+ uint64_t &ResolvedAddress) {
+ SymbolRef Symbol;
+ if (std::error_code EC =
+ Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData))
+ return EC;
+
+ if (std::error_code EC = Symbol.getAddress(ResolvedAddress))
+ return EC;
+
+ section_iterator SI = Ctx.COFF.section_begin();
+ if (std::error_code EC = Symbol.getSection(SI))
+ return EC;
+
+ ResolvedSection = Ctx.COFF.getCOFFSection(*SI);
+ return object_error::success;
+}
+
+namespace llvm {
+namespace Win64EH {
+void Dumper::printRuntimeFunctionEntry(const Context &Ctx,
+ const coff_section *Section,
+ uint64_t Offset,
+ const RuntimeFunction &RF) {
+ SW.printString("StartAddress",
+ formatSymbol(Ctx, Section, Offset + 0, RF.StartAddress));
+ SW.printString("EndAddress",
+ formatSymbol(Ctx, Section, Offset + 4, RF.EndAddress));
+ SW.printString("UnwindInfoAddress",
+ formatSymbol(Ctx, Section, Offset + 8, RF.UnwindInfoOffset));
+}
+
+// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
+// the unwind codes array, this function requires that the correct number of
+// slots is provided.
+void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) {
+ assert(UC.size() >= getNumUsedSlots(UC[0]));
+
+ SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset))
+ << getUnwindCodeTypeName(UC[0].getUnwindOp());
+
+ switch (UC[0].getUnwindOp()) {
+ case UOP_PushNonVol:
+ OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo());
+ break;
+
+ case UOP_AllocLarge:
+ OS << " size="
+ << ((UC[0].getOpInfo() == 0) ? UC[1].FrameOffset * 8
+ : getLargeSlotValue(UC));
+ break;
+
+ case UOP_AllocSmall:
+ OS << " size=" << (UC[0].getOpInfo() + 1) * 8;
+ break;
+
+ case UOP_SetFPReg:
+ if (UI.getFrameRegister() == 0)
+ OS << " reg=<invalid>";
+ else
+ OS << " reg=" << getUnwindRegisterName(UI.getFrameRegister())
+ << format(", offset=0x%X", UI.getFrameOffset() * 16);
+ break;
+
+ case UOP_SaveNonVol:
+ OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo())
+ << format(", offset=0x%X", UC[1].FrameOffset * 8);
+ break;
+
+ case UOP_SaveNonVolBig:
+ OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UC));
+ break;
+
+ case UOP_SaveXMM128:
+ OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo())
+ << format(", offset=0x%X", UC[1].FrameOffset * 16);
+ break;
+
+ case UOP_SaveXMM128Big:
+ OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UC));
+ break;
+
+ case UOP_PushMachFrame:
+ OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes");
+ break;
+ }
+
+ OS << "\n";
+}
+
+void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section,
+ off_t Offset, const UnwindInfo &UI) {
+ DictScope UIS(SW, "UnwindInfo");
+ SW.printNumber("Version", UI.getVersion());
+ SW.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags));
+ SW.printNumber("PrologSize", UI.PrologSize);
+ if (UI.getFrameRegister()) {
+ SW.printEnum("FrameRegister", UI.getFrameRegister(),
+ makeArrayRef(UnwindOpInfo));
+ SW.printHex("FrameOffset", UI.getFrameOffset());
+ } else {
+ SW.printString("FrameRegister", StringRef("-"));
+ SW.printString("FrameOffset", StringRef("-"));
+ }
+
+ SW.printNumber("UnwindCodeCount", UI.NumCodes);
+ {
+ ListScope UCS(SW, "UnwindCodes");
+ ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes);
+ for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) {
+ unsigned UsedSlots = getNumUsedSlots(*UCI);
+ if (UsedSlots > UC.size()) {
+ errs() << "corrupt unwind data";
+ return;
+ }
+
+ printUnwindCode(UI, ArrayRef<UnwindCode>(UCI, UCE));
+ UCI = UCI + UsedSlots - 1;
+ }
+ }
+
+ uint64_t LSDAOffset = Offset + getOffsetOfLSDA(UI);
+ if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
+ SW.printString("Handler",
+ formatSymbol(Ctx, Section, LSDAOffset,
+ UI.getLanguageSpecificHandlerOffset()));
+ } else if (UI.getFlags() & UNW_ChainInfo) {
+ if (const RuntimeFunction *Chained = UI.getChainedFunctionEntry()) {
+ DictScope CS(SW, "Chained");
+ printRuntimeFunctionEntry(Ctx, Section, LSDAOffset, *Chained);
+ }
+ }
+}
+
+void Dumper::printRuntimeFunction(const Context &Ctx,
+ const coff_section *Section,
+ uint64_t SectionOffset,
+ const RuntimeFunction &RF) {
+ DictScope RFS(SW, "RuntimeFunction");
+ printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF);
+
+ const coff_section *XData;
+ uint64_t Offset;
+ if (error(resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset)))
+ return;
+
+ ArrayRef<uint8_t> Contents;
+ if (error(Ctx.COFF.getSectionContents(XData, Contents)) || Contents.empty())
+ return;
+
+ Offset = Offset + RF.UnwindInfoOffset;
+ if (Offset > Contents.size())
+ return;
+
+ const auto UI = reinterpret_cast<const UnwindInfo*>(Contents.data() + Offset);
+ printUnwindInfo(Ctx, XData, Offset, *UI);
+}
+
+void Dumper::printData(const Context &Ctx) {
+ for (const auto &Section : Ctx.COFF.sections()) {
+ StringRef Name;
+ if (error(Section.getName(Name)))
+ continue;
+
+ if (Name != ".pdata" && !Name.startswith(".pdata$"))
+ continue;
+
+ const coff_section *PData = Ctx.COFF.getCOFFSection(Section);
+ ArrayRef<uint8_t> Contents;
+ if (error(Ctx.COFF.getSectionContents(PData, Contents)) || Contents.empty())
+ continue;
+
+ const RuntimeFunction *Entries =
+ reinterpret_cast<const RuntimeFunction *>(Contents.data());
+ const size_t Count = Contents.size() / sizeof(RuntimeFunction);
+ ArrayRef<RuntimeFunction> RuntimeFunctions(Entries, Count);
+
+ size_t Index = 0;
+ for (const auto &RF : RuntimeFunctions) {
+ printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section),
+ Index * sizeof(RuntimeFunction), RF);
+ ++Index;
+ }
+ }
+}
+}
+}
+
diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h
new file mode 100644
index 0000000..a80df9c
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h
@@ -0,0 +1,63 @@
+//===- Win64EHDumper.h - Win64 EH Printing ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_WIN64EHDUMPER_H
+#define LLVM_TOOLS_LLVM_READOBJ_WIN64EHDUMPER_H
+
+#include "StreamWriter.h"
+#include "llvm/Support/Win64EH.h"
+
+namespace llvm {
+namespace object {
+class COFFObjectFile;
+class SymbolRef;
+struct coff_section;
+}
+
+namespace Win64EH {
+class Dumper {
+ StreamWriter &SW;
+ raw_ostream &OS;
+
+public:
+ typedef std::error_code (*SymbolResolver)(const object::coff_section *,
+ uint64_t, object::SymbolRef &,
+ void *);
+
+ struct Context {
+ const object::COFFObjectFile &COFF;
+ SymbolResolver ResolveSymbol;
+ void *UserData;
+
+ Context(const object::COFFObjectFile &COFF, SymbolResolver Resolver,
+ void *UserData)
+ : COFF(COFF), ResolveSymbol(Resolver), UserData(UserData) {}
+ };
+
+private:
+ void printRuntimeFunctionEntry(const Context &Ctx,
+ const object::coff_section *Section,
+ uint64_t SectionOffset,
+ const RuntimeFunction &RF);
+ void printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC);
+ void printUnwindInfo(const Context &Ctx, const object::coff_section *Section,
+ off_t Offset, const UnwindInfo &UI);
+ void printRuntimeFunction(const Context &Ctx,
+ const object::coff_section *Section,
+ uint64_t SectionOffset, const RuntimeFunction &RF);
+
+public:
+ Dumper(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {}
+
+ void printData(const Context &Ctx);
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
new file mode 100644
index 0000000..be7bbe9
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -0,0 +1,393 @@
+//===- llvm-readobj.cpp - Dump contents of an Object File -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a tool similar to readelf, except it works on multiple object file
+// formats. The main purpose of this tool is to provide detailed output suitable
+// for FileCheck.
+//
+// Flags should be similar to readelf where supported, but the output format
+// does not need to be identical. The point is to not make users learn yet
+// another set of flags.
+//
+// Output should be specialized for each format where appropriate.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include <string>
+#include <system_error>
+
+
+using namespace llvm;
+using namespace llvm::object;
+
+namespace opts {
+ cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input object files>"),
+ cl::ZeroOrMore);
+
+ // -file-headers, -h
+ cl::opt<bool> FileHeaders("file-headers",
+ cl::desc("Display file headers "));
+ cl::alias FileHeadersShort("h",
+ cl::desc("Alias for --file-headers"),
+ cl::aliasopt(FileHeaders));
+
+ // -sections, -s
+ cl::opt<bool> Sections("sections",
+ cl::desc("Display all sections."));
+ cl::alias SectionsShort("s",
+ cl::desc("Alias for --sections"),
+ cl::aliasopt(Sections));
+
+ // -section-relocations, -sr
+ cl::opt<bool> SectionRelocations("section-relocations",
+ cl::desc("Display relocations for each section shown."));
+ cl::alias SectionRelocationsShort("sr",
+ cl::desc("Alias for --section-relocations"),
+ cl::aliasopt(SectionRelocations));
+
+ // -section-symbols, -st
+ cl::opt<bool> SectionSymbols("section-symbols",
+ cl::desc("Display symbols for each section shown."));
+ cl::alias SectionSymbolsShort("st",
+ cl::desc("Alias for --section-symbols"),
+ cl::aliasopt(SectionSymbols));
+
+ // -section-data, -sd
+ cl::opt<bool> SectionData("section-data",
+ cl::desc("Display section data for each section shown."));
+ cl::alias SectionDataShort("sd",
+ cl::desc("Alias for --section-data"),
+ cl::aliasopt(SectionData));
+
+ // -relocations, -r
+ cl::opt<bool> Relocations("relocations",
+ cl::desc("Display the relocation entries in the file"));
+ cl::alias RelocationsShort("r",
+ cl::desc("Alias for --relocations"),
+ cl::aliasopt(Relocations));
+
+ // -symbols, -t
+ cl::opt<bool> Symbols("symbols",
+ cl::desc("Display the symbol table"));
+ cl::alias SymbolsShort("t",
+ cl::desc("Alias for --symbols"),
+ cl::aliasopt(Symbols));
+
+ // -dyn-symbols, -dt
+ cl::opt<bool> DynamicSymbols("dyn-symbols",
+ cl::desc("Display the dynamic symbol table"));
+ cl::alias DynamicSymbolsShort("dt",
+ cl::desc("Alias for --dyn-symbols"),
+ cl::aliasopt(DynamicSymbols));
+
+ // -unwind, -u
+ cl::opt<bool> UnwindInfo("unwind",
+ cl::desc("Display unwind information"));
+ cl::alias UnwindInfoShort("u",
+ cl::desc("Alias for --unwind"),
+ cl::aliasopt(UnwindInfo));
+
+ // -dynamic-table
+ cl::opt<bool> DynamicTable("dynamic-table",
+ cl::desc("Display the ELF .dynamic section table"));
+
+ // -needed-libs
+ cl::opt<bool> NeededLibraries("needed-libs",
+ cl::desc("Display the needed libraries"));
+
+ // -program-headers
+ cl::opt<bool> ProgramHeaders("program-headers",
+ cl::desc("Display ELF program headers"));
+
+ // -expand-relocs
+ cl::opt<bool> ExpandRelocs("expand-relocs",
+ cl::desc("Expand each shown relocation to multiple lines"));
+
+ // -codeview
+ cl::opt<bool> CodeView("codeview",
+ cl::desc("Display CodeView debug information"));
+
+ // -codeview-subsection-bytes
+ cl::opt<bool> CodeViewSubsectionBytes(
+ "codeview-subsection-bytes",
+ cl::desc("Dump raw contents of codeview debug sections and records"));
+
+ // -arm-attributes, -a
+ cl::opt<bool> ARMAttributes("arm-attributes",
+ cl::desc("Display the ARM attributes section"));
+ cl::alias ARMAttributesShort("-a", cl::desc("Alias for --arm-attributes"),
+ cl::aliasopt(ARMAttributes));
+
+ // -mips-plt-got
+ cl::opt<bool>
+ MipsPLTGOT("mips-plt-got",
+ cl::desc("Display the MIPS GOT and PLT GOT sections"));
+
+ // -mips-abi-flags
+ cl::opt<bool> MipsABIFlags("mips-abi-flags",
+ cl::desc("Display the MIPS.abiflags section"));
+
+ // -coff-imports
+ cl::opt<bool>
+ COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
+
+ // -coff-exports
+ cl::opt<bool>
+ COFFExports("coff-exports", cl::desc("Display the PE/COFF export table"));
+
+ // -coff-directives
+ cl::opt<bool>
+ COFFDirectives("coff-directives",
+ cl::desc("Display the PE/COFF .drectve section"));
+
+ // -coff-basereloc
+ cl::opt<bool>
+ COFFBaseRelocs("coff-basereloc",
+ cl::desc("Display the PE/COFF .reloc section"));
+} // namespace opts
+
+static int ReturnValue = EXIT_SUCCESS;
+
+namespace llvm {
+
+bool error(std::error_code EC) {
+ if (!EC)
+ return false;
+
+ ReturnValue = EXIT_FAILURE;
+ outs() << "\nError reading file: " << EC.message() << ".\n";
+ outs().flush();
+ return true;
+}
+
+bool relocAddressLess(RelocationRef a, RelocationRef b) {
+ uint64_t a_addr, b_addr;
+ if (error(a.getOffset(a_addr))) exit(ReturnValue);
+ if (error(b.getOffset(b_addr))) exit(ReturnValue);
+ return a_addr < b_addr;
+}
+
+} // namespace llvm
+
+static void reportError(StringRef Input, std::error_code EC) {
+ if (Input == "-")
+ Input = "<stdin>";
+
+ errs() << Input << ": " << EC.message() << "\n";
+ errs().flush();
+ ReturnValue = EXIT_FAILURE;
+}
+
+static void reportError(StringRef Input, StringRef Message) {
+ if (Input == "-")
+ Input = "<stdin>";
+
+ errs() << Input << ": " << Message << "\n";
+ ReturnValue = EXIT_FAILURE;
+}
+
+static bool isMipsArch(unsigned Arch) {
+ switch (Arch) {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// @brief Creates an format-specific object file dumper.
+static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ if (!Obj)
+ return readobj_error::unsupported_file_format;
+
+ if (Obj->isCOFF())
+ return createCOFFDumper(Obj, Writer, Result);
+ if (Obj->isELF())
+ return createELFDumper(Obj, Writer, Result);
+ if (Obj->isMachO())
+ return createMachODumper(Obj, Writer, Result);
+
+ return readobj_error::unsupported_obj_file_format;
+}
+
+static StringRef getLoadName(const ObjectFile *Obj) {
+ if (auto *ELF = dyn_cast<ELF32LEObjectFile>(Obj))
+ return ELF->getLoadName();
+ if (auto *ELF = dyn_cast<ELF64LEObjectFile>(Obj))
+ return ELF->getLoadName();
+ if (auto *ELF = dyn_cast<ELF32BEObjectFile>(Obj))
+ return ELF->getLoadName();
+ if (auto *ELF = dyn_cast<ELF64BEObjectFile>(Obj))
+ return ELF->getLoadName();
+ llvm_unreachable("Not ELF");
+}
+
+/// @brief Dumps the specified object file.
+static void dumpObject(const ObjectFile *Obj) {
+ StreamWriter Writer(outs());
+ std::unique_ptr<ObjDumper> Dumper;
+ if (std::error_code EC = createDumper(Obj, Writer, Dumper)) {
+ reportError(Obj->getFileName(), EC);
+ return;
+ }
+
+ outs() << '\n';
+ outs() << "File: " << Obj->getFileName() << "\n";
+ outs() << "Format: " << Obj->getFileFormatName() << "\n";
+ outs() << "Arch: "
+ << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch())
+ << "\n";
+ outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n";
+ if (Obj->isELF())
+ outs() << "LoadName: " << getLoadName(Obj) << "\n";
+
+ if (opts::FileHeaders)
+ Dumper->printFileHeaders();
+ if (opts::Sections)
+ Dumper->printSections();
+ if (opts::Relocations)
+ Dumper->printRelocations();
+ if (opts::Symbols)
+ Dumper->printSymbols();
+ if (opts::DynamicSymbols)
+ Dumper->printDynamicSymbols();
+ if (opts::UnwindInfo)
+ Dumper->printUnwindInfo();
+ if (opts::DynamicTable)
+ Dumper->printDynamicTable();
+ if (opts::NeededLibraries)
+ Dumper->printNeededLibraries();
+ if (opts::ProgramHeaders)
+ Dumper->printProgramHeaders();
+ if (Obj->getArch() == llvm::Triple::arm && Obj->isELF())
+ if (opts::ARMAttributes)
+ Dumper->printAttributes();
+ if (isMipsArch(Obj->getArch()) && Obj->isELF()) {
+ if (opts::MipsPLTGOT)
+ Dumper->printMipsPLTGOT();
+ if (opts::MipsABIFlags)
+ Dumper->printMipsABIFlags();
+ }
+ if (opts::COFFImports)
+ Dumper->printCOFFImports();
+ if (opts::COFFExports)
+ Dumper->printCOFFExports();
+ if (opts::COFFDirectives)
+ Dumper->printCOFFDirectives();
+ if (opts::COFFBaseRelocs)
+ Dumper->printCOFFBaseReloc();
+}
+
+
+/// @brief Dumps each object file in \a Arc;
+static void dumpArchive(const Archive *Arc) {
+ for (Archive::child_iterator ArcI = Arc->child_begin(),
+ ArcE = Arc->child_end();
+ ArcI != ArcE; ++ArcI) {
+ ErrorOr<std::unique_ptr<Binary>> ChildOrErr = ArcI->getAsBinary();
+ if (std::error_code EC = ChildOrErr.getError()) {
+ // Ignore non-object files.
+ if (EC != object_error::invalid_file_type)
+ reportError(Arc->getFileName(), EC.message());
+ continue;
+ }
+
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
+ dumpObject(Obj);
+ else
+ reportError(Arc->getFileName(), readobj_error::unrecognized_file_format);
+ }
+}
+
+/// @brief Dumps each object file in \a MachO Universal Binary;
+static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) {
+ for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
+ ErrorOr<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
+ if (ObjOrErr)
+ dumpObject(&*ObjOrErr.get());
+ else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
+ dumpArchive(&*AOrErr.get());
+ else
+ reportError(UBinary->getFileName(), ObjOrErr.getError().message());
+ }
+}
+
+/// @brief Opens \a File and dumps it.
+static void dumpInput(StringRef File) {
+ // If file isn't stdin, check that it exists.
+ if (File != "-" && !sys::fs::exists(File)) {
+ reportError(File, readobj_error::file_not_found);
+ return;
+ }
+
+ // Attempt to open the binary.
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
+ if (std::error_code EC = BinaryOrErr.getError()) {
+ reportError(File, EC);
+ return;
+ }
+ Binary &Binary = *BinaryOrErr.get().getBinary();
+
+ if (Archive *Arc = dyn_cast<Archive>(&Binary))
+ dumpArchive(Arc);
+ else if (MachOUniversalBinary *UBinary =
+ dyn_cast<MachOUniversalBinary>(&Binary))
+ dumpMachOUniversalBinary(UBinary);
+ else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
+ dumpObject(Obj);
+ else
+ reportError(File, readobj_error::unrecognized_file_format);
+}
+
+
+int main(int argc, const char *argv[]) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y;
+
+ // Initialize targets.
+ llvm::InitializeAllTargetInfos();
+
+ // Register the target printer for --version.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
+
+ // Default to stdin if no filename is specified.
+ if (opts::InputFilenames.size() == 0)
+ opts::InputFilenames.push_back("-");
+
+ std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
+ dumpInput);
+
+ return ReturnValue;
+}
diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
new file mode 100644
index 0000000..74b9a60
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
@@ -0,0 +1,48 @@
+//===-- llvm-readobj.h ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H
+#define LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H
+
+#include "llvm/Support/CommandLine.h"
+#include <string>
+
+namespace llvm {
+ namespace object {
+ class RelocationRef;
+ }
+
+ // Various helper functions.
+ bool error(std::error_code ec);
+ bool relocAddressLess(object::RelocationRef A,
+ object::RelocationRef B);
+} // namespace llvm
+
+namespace opts {
+ extern llvm::cl::list<std::string> InputFilenames;
+ extern llvm::cl::opt<bool> FileHeaders;
+ extern llvm::cl::opt<bool> Sections;
+ extern llvm::cl::opt<bool> SectionRelocations;
+ extern llvm::cl::opt<bool> SectionSymbols;
+ extern llvm::cl::opt<bool> SectionData;
+ extern llvm::cl::opt<bool> Relocations;
+ extern llvm::cl::opt<bool> Symbols;
+ extern llvm::cl::opt<bool> DynamicSymbols;
+ extern llvm::cl::opt<bool> UnwindInfo;
+ extern llvm::cl::opt<bool> ExpandRelocs;
+ extern llvm::cl::opt<bool> CodeView;
+ extern llvm::cl::opt<bool> CodeViewSubsectionBytes;
+ extern llvm::cl::opt<bool> ARMAttributes;
+ extern llvm::cl::opt<bool> MipsPLTGOT;
+} // namespace opts
+
+#define LLVM_READOBJ_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+#endif
OpenPOWER on IntegriCloud