diff options
author | Stephen Hines <srhines@google.com> | 2014-04-23 16:57:46 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-04-24 15:53:16 -0700 |
commit | 36b56886974eae4f9c5ebc96befd3e7bfe5de338 (patch) | |
tree | e6cfb69fbbd937f450eeb83bfb83b9da3b01275a /tools/llvm-readobj | |
parent | 69a8640022b04415ae9fac62f8ab090601d8f889 (diff) | |
download | external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.zip external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.gz external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.bz2 |
Update to LLVM 3.5a.
Change-Id: Ifadecab779f128e62e430c2b4f6ddd84953ed617
Diffstat (limited to 'tools/llvm-readobj')
-rw-r--r-- | tools/llvm-readobj/ARMAttributeParser.cpp | 639 | ||||
-rw-r--r-- | tools/llvm-readobj/ARMAttributeParser.h | 124 | ||||
-rw-r--r-- | tools/llvm-readobj/ARMEHABIPrinter.h | 557 | ||||
-rw-r--r-- | tools/llvm-readobj/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tools/llvm-readobj/COFFDumper.cpp | 497 | ||||
-rw-r--r-- | tools/llvm-readobj/ELFDumper.cpp | 119 | ||||
-rw-r--r-- | tools/llvm-readobj/Error.cpp | 8 | ||||
-rw-r--r-- | tools/llvm-readobj/Error.h | 4 | ||||
-rw-r--r-- | tools/llvm-readobj/MachODumper.cpp | 181 | ||||
-rw-r--r-- | tools/llvm-readobj/ObjDumper.cpp | 2 | ||||
-rw-r--r-- | tools/llvm-readobj/ObjDumper.h | 22 | ||||
-rw-r--r-- | tools/llvm-readobj/StreamWriter.h | 15 | ||||
-rw-r--r-- | tools/llvm-readobj/llvm-readobj.cpp | 34 | ||||
-rw-r--r-- | tools/llvm-readobj/llvm-readobj.h | 2 |
14 files changed, 1858 insertions, 352 deletions
diff --git a/tools/llvm-readobj/ARMAttributeParser.cpp b/tools/llvm-readobj/ARMAttributeParser.cpp new file mode 100644 index 0000000..5857547 --- /dev/null +++ b/tools/llvm-readobj/ARMAttributeParser.cpp @@ -0,0 +1,639 @@ +//===--- 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/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 }, +}; + +template <typename type_, size_t size_> +size_t countof(const type_ (&)[size_]) { + return size_; +} + +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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(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 < countof(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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 < countof(Strings)) ? Strings[Value] : NULL; + 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 = countof(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/tools/llvm-readobj/ARMAttributeParser.h b/tools/llvm-readobj/ARMAttributeParser.h new file mode 100644 index 0000000..c286251 --- /dev/null +++ b/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_READOBJ_ARMATTRIBUTE_PARSER_H +#define LLVM_READOBJ_ARMATTRIBUTE_PARSER_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/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h new file mode 100644 index 0000000..75e2bee --- /dev/null +++ b/tools/llvm-readobj/ARMEHABIPrinter.h @@ -0,0 +1,557 @@ +//===--- 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_READOBJ_ARMEHABI_PRINTER_H +#define LLVM_READOBJ_ARMEHABI_PRINTER_H + +#include "Error.h" +#include "StreamWriter.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 { +template <typename type_, size_t N> +size_t countof(const type_ (&)[N]) { + return N; +} +} + +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 = countof(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 NULL; +} + +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/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index 90997a8..036185d 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,7 +1,8 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - bitreader - object) + Object + Support + ) add_llvm_tool(llvm-readobj llvm-readobj.cpp @@ -11,4 +12,5 @@ add_llvm_tool(llvm-readobj MachODumper.cpp Error.cpp StreamWriter.cpp + ARMAttributeParser.cpp ) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 2f309e3..cd40da7 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -13,23 +13,22 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" -#include "ObjDumper.h" - #include "Error.h" +#include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.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 "llvm/Support/system_error.h" - #include <algorithm> #include <cstring> #include <time.h> @@ -48,22 +47,23 @@ public: cacheRelocations(); } - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; + virtual void printFileHeaders() override; + virtual void printSections() override; + virtual void printRelocations() override; + virtual void printSymbols() override; + virtual void printDynamicSymbols() override; + virtual void printUnwindInfo() override; private: - void printSymbol(symbol_iterator SymI); - - void printRelocation(section_iterator SecI, relocation_iterator RelI); - + void printSymbol(const SymbolRef &Sym); + void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); void printDataDirectory(uint32_t Index, const std::string &FieldName); - void printX64UnwindInfo(); + template <class PEHeader> void printPEHeader(const PEHeader *Hdr); + void printBaseOfDataField(const pe32_header *Hdr); + void printBaseOfDataField(const pe32plus_header *Hdr); + void printRuntimeFunction( const RuntimeFunction& RTF, uint64_t OffsetInSection, @@ -74,7 +74,9 @@ private: uint64_t OffsetInSection, const std::vector<RelocationRef> &Rels); - void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs); + void printUnwindCode(const Win64EH::UnwindInfo &UI, ArrayRef<UnwindCode> UCs); + + void printCodeViewLineTables(const SectionRef &Section); void cacheRelocations(); @@ -102,9 +104,8 @@ private: namespace llvm { -error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { +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; @@ -183,11 +184,11 @@ static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, if (error_code EC = Sym.getAddress(ResolvedAddr)) return EC; - section_iterator iter(Obj->begin_sections()); + section_iterator iter(Obj->section_begin()); if (error_code EC = Sym.getSection(iter)) return EC; - ResolvedSection = Obj->getCOFFSection(iter); + ResolvedSection = Obj->getCOFFSection(*iter); return object_error::success; } @@ -227,7 +228,7 @@ static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = { 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_ARMV7 ), + 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 ), @@ -279,6 +280,7 @@ static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = { }; 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 ), @@ -428,30 +430,9 @@ static const EnumEntry<unsigned> UnwindOpInfo[] = { // Some additional COFF structures not defined by llvm::object. namespace { - struct coff_aux_function_definition { - support::ulittle32_t TagIndex; - support::ulittle32_t TotalSize; - support::ulittle32_t PointerToLineNumber; - support::ulittle32_t PointerToNextFunction; - uint8_t Unused[2]; - }; - - struct coff_aux_weak_external_definition { - support::ulittle32_t TagIndex; - support::ulittle32_t Characteristics; - uint8_t Unused[10]; - }; - struct coff_aux_file_record { char FileName[18]; }; - - struct coff_aux_clr_token { - support::ulittle8_t AuxType; - support::ulittle8_t Reserved; - support::ulittle32_t SymbolTableIndex; - uint8_t Unused[12]; - }; } // namespace static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) { @@ -538,23 +519,11 @@ error_code COFFDumper::getSection( } void COFFDumper::cacheRelocations() { - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) - break; - - const coff_section *Section = Obj->getCOFFSection(SecI); - - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) - break; + for (const SectionRef &S : Obj->sections()) { + const coff_section *Section = Obj->getCOFFSection(S); - RelocMap[Section].push_back(*RelI); - } + for (const RelocationRef &Reloc : S.relocations()) + RelocMap[Section].push_back(Reloc); // Sort relocations by address. std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), @@ -598,73 +567,239 @@ void COFFDumper::printFileHeaders() { const pe32_header *PEHeader = 0; if (error(Obj->getPE32Header(PEHeader))) return; + if (PEHeader) + printPEHeader<pe32_header>(PEHeader); + + const pe32plus_header *PEPlusHeader = 0; + if (error(Obj->getPE32PlusHeader(PEPlusHeader))) + return; + if (PEPlusHeader) + printPEHeader<pe32plus_header>(PEPlusHeader); +} + +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 ("Subsystem", 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::printCodeViewLineTables(const SectionRef &Section) { + StringRef Data; + if (error(Section.getContents(Data))) + return; + + SmallVector<StringRef, 10> FunctionNames; + StringMap<StringRef> FunctionLineTables; + StringRef FileIndexToStringOffsetTable; + StringRef StringTable; + + ListScope D(W, "CodeViewLineTables"); + { + 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; + } + + // Print the raw contents to simplify debugging if anything goes wrong + // afterwards. + StringRef Contents = Data.substr(Offset, PayloadSize); + W.printBinaryBlock("Contents", Contents); + + switch (SubSectionType) { + 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(RelocMap[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 || StringTable.data() != 0 || + Contents.back() != '\0') { + // Empty or duplicate or non-null-terminated subsection. + error(object_error::parse_failed); + return; + } + StringTable = Contents; + break; + case COFF::DEBUG_INDEX_SUBSECTION: + // Holds the translation table from file indices + // to offsets in the string table. + + if (PayloadSize == 0 || FileIndexToStringOffsetTable.data() != 0) { + // Empty or duplicate subsection. + error(object_error::parse_failed); + return; + } + FileIndexToStringOffsetTable = 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(FileIndexToStringOffsetTable, true, 4); + uint32_t OffsetInSDE = OffsetInIndex; + if (!SDE.isValidOffset(OffsetInSDE)) { + error(object_error::parse_failed); + return; + } + FilenameOffset = SDE.getU32(&OffsetInSDE); + } - if (PEHeader) { - DictScope D(W, "ImageOptionalHeader"); - W.printNumber("MajorLinkerVersion", PEHeader->MajorLinkerVersion); - W.printNumber("MinorLinkerVersion", PEHeader->MinorLinkerVersion); - W.printNumber("SizeOfCode", PEHeader->SizeOfCode); - W.printNumber("SizeOfInitializedData", PEHeader->SizeOfInitializedData); - W.printNumber("SizeOfUninitializedData", PEHeader->SizeOfUninitializedData); - W.printHex ("AddressOfEntryPoint", PEHeader->AddressOfEntryPoint); - W.printHex ("BaseOfCode", PEHeader->BaseOfCode); - W.printHex ("BaseOfData", PEHeader->BaseOfData); - W.printHex ("ImageBase", PEHeader->ImageBase); - W.printNumber("SectionAlignment", PEHeader->SectionAlignment); - W.printNumber("FileAlignment", PEHeader->FileAlignment); - W.printNumber("MajorOperatingSystemVersion", - PEHeader->MajorOperatingSystemVersion); - W.printNumber("MinorOperatingSystemVersion", - PEHeader->MinorOperatingSystemVersion); - W.printNumber("MajorImageVersion", PEHeader->MajorImageVersion); - W.printNumber("MinorImageVersion", PEHeader->MinorImageVersion); - W.printNumber("MajorSubsystemVersion", PEHeader->MajorSubsystemVersion); - W.printNumber("MinorSubsystemVersion", PEHeader->MinorSubsystemVersion); - W.printNumber("SizeOfImage", PEHeader->SizeOfImage); - W.printNumber("SizeOfHeaders", PEHeader->SizeOfHeaders); - W.printEnum ("Subsystem", PEHeader->Subsystem, - makeArrayRef(PEWindowsSubsystem)); - W.printFlags ("Subsystem", PEHeader->DLLCharacteristics, - makeArrayRef(PEDLLCharacteristics)); - W.printNumber("SizeOfStackReserve", PEHeader->SizeOfStackReserve); - W.printNumber("SizeOfStackCommit", PEHeader->SizeOfStackCommit); - W.printNumber("SizeOfHeapReserve", PEHeader->SizeOfHeapReserve); - W.printNumber("SizeOfHeapCommit", PEHeader->SizeOfHeapCommit); - W.printNumber("NumberOfRvaAndSize", PEHeader->NumberOfRvaAndSize); - - if (PEHeader->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 < PEHeader->NumberOfRvaAndSize; ++i) { - printDataDirectory(i, directory[i]); + if (FilenameOffset == 0 || FilenameOffset + 1 >= StringTable.size() || + StringTable.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(StringTable.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::printSections() { - error_code EC; - ListScope SectionsD(W, "Sections"); int SectionNumber = 0; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) - break; - + for (const SectionRef &Sec : Obj->sections()) { ++SectionNumber; - const coff_section *Section = Obj->getCOFFSection(SecI); + const coff_section *Section = Obj->getCOFFSection(Sec); StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + if (error(Sec.getName(Name))) + Name = ""; DictScope D(W, "Section"); W.printNumber("Number", SectionNumber); @@ -683,33 +818,28 @@ void COFFDumper::printSections() { if (opts::SectionRelocations) { ListScope D(W, "Relocations"); - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - - printRelocation(SecI, RelI); - } + for (const RelocationRef &Reloc : Sec.relocations()) + printRelocation(Sec, Reloc); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - + for (const SymbolRef &Symbol : Obj->symbols()) { bool Contained = false; - if (SecI->containsSymbol(*SymI, Contained) || !Contained) + if (Sec.containsSymbol(Symbol, Contained) || !Contained) continue; - printSymbol(SymI); + printSymbol(Symbol); } } + if (Name == ".debug$S" && opts::CodeViewLineTables) + printCodeViewLineTables(Sec); + if (opts::SectionData) { StringRef Data; - if (error(SecI->getContents(Data))) break; + if (error(Sec.getContents(Data))) + break; W.printBinaryBlock("SectionData", Data); } @@ -719,32 +849,22 @@ void COFFDumper::printSections() { void COFFDumper::printRelocations() { ListScope D(W, "Relocations"); - error_code EC; int SectionNumber = 0; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { + for (const SectionRef &Section : Obj->sections()) { ++SectionNumber; - if (error(EC)) - break; - StringRef Name; - if (error(SecI->getName(Name))) + if (error(Section.getName(Name))) continue; bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - + for (const RelocationRef &Reloc : Section.relocations()) { if (!PrintedGroup) { W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; W.indent(); PrintedGroup = true; } - printRelocation(SecI, RelI); + printRelocation(Section, Reloc); } if (PrintedGroup) { @@ -754,19 +874,24 @@ void COFFDumper::printRelocations() { } } -void COFFDumper::printRelocation(section_iterator SecI, - relocation_iterator RelI) { +void COFFDumper::printRelocation(const SectionRef &Section, + const RelocationRef &Reloc) { uint64_t Offset; uint64_t RelocType; SmallString<32> RelocName; StringRef SymbolName; StringRef Contents; - if (error(RelI->getOffset(Offset))) return; - if (error(RelI->getType(RelocType))) return; - if (error(RelI->getTypeName(RelocName))) return; - symbol_iterator Symbol = RelI->getSymbol(); - if (error(Symbol->getName(SymbolName))) return; - if (error(SecI->getContents(Contents))) return; + if (error(Reloc.getOffset(Offset))) + return; + if (error(Reloc.getType(RelocType))) + return; + if (error(Reloc.getTypeName(RelocName))) + return; + symbol_iterator Symbol = Reloc.getSymbol(); + if (error(Symbol->getName(SymbolName))) + return; + if (error(Section.getContents(Contents))) + return; if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); @@ -785,24 +910,16 @@ void COFFDumper::printRelocation(section_iterator SecI, void COFFDumper::printSymbols() { ListScope Group(W, "Symbols"); - error_code EC; - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - printSymbol(SymI); - } + for (const SymbolRef &Symbol : Obj->symbols()) + printSymbol(Symbol); } -void COFFDumper::printDynamicSymbols() { - ListScope Group(W, "DynamicSymbols"); -} +void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); } -void COFFDumper::printSymbol(symbol_iterator SymI) { +void COFFDumper::printSymbol(const SymbolRef &Sym) { DictScope D(W, "Symbol"); - const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI); + const coff_symbol *Symbol = Obj->getCOFFSymbol(Sym); const coff_section *Section; if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { W.startLine() << "Invalid section number: " << EC.message() << "\n"; @@ -829,10 +946,7 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols); for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) { - if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && - Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION && - Symbol->SectionNumber > 0) { + if (Symbol->isFunctionDefinition()) { const coff_aux_function_definition *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -840,16 +954,12 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { DictScope AS(W, "AuxFunctionDef"); W.printNumber("TagIndex", Aux->TagIndex); W.printNumber("TotalSize", Aux->TotalSize); - W.printHex("PointerToLineNumber", Aux->PointerToLineNumber); + W.printHex("PointerToLineNumber", Aux->PointerToLinenumber); W.printHex("PointerToNextFunction", Aux->PointerToNextFunction); W.printBinary("Unused", makeArrayRef(Aux->Unused)); - } else if ( - Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL || - (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->SectionNumber == 0 && - Symbol->Value == 0)) { - const coff_aux_weak_external_definition *Aux; + } else if (Symbol->isWeakExternal()) { + const coff_aux_weak_external *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -866,9 +976,9 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { W.printNumber("Linked", LinkedName, Aux->TagIndex); W.printEnum ("Search", Aux->Characteristics, makeArrayRef(WeakExternalCharacteristics)); - W.printBinary("Unused", Aux->Unused); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) { + } else if (Symbol->isFileRecord()) { const coff_aux_file_record *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -876,9 +986,7 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { DictScope AS(W, "AuxFileRecord"); W.printString("FileName", StringRef(Aux->FileName)); - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC || - (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->SectionNumber != COFF::IMAGE_SYM_UNDEFINED)) { + } else if (Symbol->isSectionDefinition()) { const coff_aux_section_definition *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -905,16 +1013,25 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { W.printNumber("AssocSection", AssocName, Aux->Number); } - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) { + } else if (Symbol->isCLRToken()) { const coff_aux_clr_token *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; + const coff_symbol *ReferredSym; + StringRef ReferredName; + error_code EC; + if ((EC = Obj->getSymbol(Aux->SymbolTableIndex, ReferredSym)) || + (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", Aux->SymbolTableIndex); - W.printBinary("Unused", Aux->Unused); + W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); } else { W.startLine() << "<unhandled auxiliary record>\n"; @@ -938,23 +1055,17 @@ void COFFDumper::printUnwindInfo() { } void COFFDumper::printX64UnwindInfo() { - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(SecI->getName(Name))) + if (error(Section.getName(Name))) continue; if (Name != ".pdata" && !Name.startswith(".pdata$")) continue; - const coff_section *PData = Obj->getCOFFSection(SecI); + const coff_section *PData = Obj->getCOFFSection(Section); ArrayRef<uint8_t> Contents; - if (error(Obj->getSectionContents(PData, Contents)) || - Contents.empty()) + if (error(Obj->getSectionContents(PData, Contents)) || Contents.empty()) continue; ArrayRef<RuntimeFunction> RFs( diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 07a9083..4cd3393 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -13,12 +13,15 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" +#include "ARMAttributeParser.h" +#include "ARMEHABIPrinter.h" #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.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" @@ -39,16 +42,18 @@ public: ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) : ObjDumper(Writer), Obj(Obj) {} - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; + 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; - virtual void printDynamicTable() LLVM_OVERRIDE; - virtual void printNeededLibraries() LLVM_OVERRIDE; - virtual void printProgramHeaders() LLVM_OVERRIDE; + void printAttributes() override; private: typedef ELFFile<ELFT> ELFO; @@ -65,7 +70,7 @@ private: template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { if (!Val) { - error(Val); + error(Val.getError()); return Default; } @@ -78,14 +83,13 @@ namespace llvm { template <class ELFT> static error_code createELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer, - OwningPtr<ObjDumper> &Result) { + std::unique_ptr<ObjDumper> &Result) { Result.reset(new ELFDumper<ELFT>(Obj, Writer)); return readobj_error::success; } -error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { +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); @@ -621,8 +625,30 @@ void ELFDumper<ELFT>::printDynamicSymbols() { template <class ELFT> void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { StringRef SymbolName = errorOrDefault(Obj->getSymbolName(Symbol)); - const Elf_Shdr *Sec = Obj->getSection(&*Symbol); - StringRef SectionName = Sec ? errorOrDefault(Obj->getSectionName(Sec)) : ""; + + unsigned SectionIndex = Symbol->st_shndx; + StringRef SectionName; + 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 Elf_Shdr *Sec = Obj->getSection(SectionIndex); + SectionName = errorOrDefault(Obj->getSectionName(Sec)); + } + std::string FullSymbolName(SymbolName); if (Symbol.isDynamic()) { bool IsDefault; @@ -631,7 +657,7 @@ void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { FullSymbolName += (IsDefault ? "@@" : "@"); FullSymbolName += *Version; } else - error(Version); + error(Version.getError()); } DictScope D(W, "Symbol"); @@ -642,7 +668,7 @@ void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { makeArrayRef(ElfSymbolBindings)); W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); W.printNumber("Other", Symbol->st_other); - W.printHex ("Section", SectionName, Symbol->st_shndx); + W.printHex("Section", SectionName, SectionIndex); } #define LLVM_READOBJ_TYPE_CASE(name) \ @@ -693,6 +719,8 @@ static const char *getTypeString(uint64_t Type) { 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); default: return "unknown"; } } @@ -731,6 +759,8 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_MIPS_FLAGS: case DT_MIPS_BASE_ADDRESS: case DT_MIPS_GOTSYM: + case DT_MIPS_RLD_MAP: + case DT_MIPS_PLTGOT: OS << format("0x%" PRIX64, Value); break; case DT_VERNEEDNUM: @@ -770,6 +800,18 @@ 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() { typedef typename ELFO::Elf_Dyn_Iter EDI; @@ -839,3 +881,42 @@ void ELFDumper<ELFT>::printProgramHeaders() { 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); + } +} +} + diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp index a6c6132..83ed6a7 100644 --- a/tools/llvm-readobj/Error.cpp +++ b/tools/llvm-readobj/Error.cpp @@ -17,11 +17,11 @@ using namespace llvm; namespace { -class _readobj_error_category : public _do_message { +class _readobj_error_category : public error_category { public: - virtual const char* name() const; - virtual std::string message(int ev) const; - virtual error_condition default_error_condition(int ev) const; + const char* name() const override; + std::string message(int ev) const override; + error_condition default_error_condition(int ev) const override; }; } // namespace diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h index cf68da8..5129b4e 100644 --- a/tools/llvm-readobj/Error.h +++ b/tools/llvm-readobj/Error.h @@ -40,8 +40,8 @@ inline error_code make_error_code(readobj_error e) { return error_code(static_cast<int>(e), readobj_category()); } -template <> struct is_error_code_enum<readobj_error> : true_type { }; -template <> struct is_error_code_enum<readobj_error::_> : true_type { }; +template <> struct is_error_code_enum<readobj_error> : std::true_type { }; +template <> struct is_error_code_enum<readobj_error::_> : std::true_type { }; } // namespace llvm diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index b97166b..2fd5d4a 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -15,7 +15,6 @@ #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/ADT/SmallString.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" @@ -31,20 +30,19 @@ public: : ObjDumper(Writer) , Obj(Obj) { } - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; + virtual void printFileHeaders() override; + virtual void printSections() override; + virtual void printRelocations() override; + virtual void printSymbols() override; + virtual void printDynamicSymbols() override; + virtual void printUnwindInfo() override; private: - void printSymbol(symbol_iterator SymI); + void printSymbol(const SymbolRef &Symbol); - void printRelocation(section_iterator SecI, relocation_iterator RelI); + void printRelocation(const RelocationRef &Reloc); - void printRelocation(const MachOObjectFile *Obj, - section_iterator SecI, relocation_iterator RelI); + void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc); void printSections(const MachOObjectFile *Obj); @@ -57,8 +55,8 @@ private: namespace llvm { error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); if (!MachOObj) return readobj_error::unsupported_obj_file_format; @@ -126,19 +124,13 @@ static const EnumEntry<unsigned> MachOSymbolFlags[] = { static const EnumEntry<unsigned> MachOSymbolTypes[] = { { "Undef", 0x0 }, - { "External", 0x1 }, { "Abs", 0x2 }, { "Indirect", 0xA }, { "PreboundUndef", 0xC }, - { "Section", 0xE }, - { "PrivateExternal", 0x10 } + { "Section", 0xE } }; namespace { - enum { - N_STAB = 0xE0 - }; - struct MachOSection { ArrayRef<char> Name; ArrayRef<char> SegmentName; @@ -223,21 +215,16 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { ListScope Group(W, "Sections"); int SectionIndex = -1; - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const SectionRef &Section : Obj->sections()) { ++SectionIndex; - MachOSection Section; - getSection(Obj, SecI->getRawDataRefImpl(), Section); - DataRefImpl DR = SecI->getRawDataRefImpl(); + MachOSection MOSection; + getSection(Obj, Section.getRawDataRefImpl(), MOSection); + DataRefImpl DR = Section.getRawDataRefImpl(); StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + if (error(Section.getName(Name))) + Name = ""; ArrayRef<char> RawName = Obj->getSectionRawName(DR); StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); @@ -247,48 +234,40 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { W.printNumber("Index", SectionIndex); W.printBinary("Name", Name, RawName); W.printBinary("Segment", SegmentName, RawSegmentName); - W.printHex ("Address", Section.Address); - W.printHex ("Size", Section.Size); - W.printNumber("Offset", Section.Offset); - W.printNumber("Alignment", Section.Alignment); - W.printHex ("RelocationOffset", Section.RelocationTableOffset); - W.printNumber("RelocationCount", Section.NumRelocationTableEntries); - W.printEnum ("Type", Section.Flags & 0xFF, - makeArrayRef(MachOSectionAttributes)); - W.printFlags ("Attributes", Section.Flags >> 8, - makeArrayRef(MachOSectionAttributes)); - W.printHex ("Reserved1", Section.Reserved1); - W.printHex ("Reserved2", Section.Reserved2); + 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 (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - - printRelocation(SecI, RelI); - } + for (const RelocationRef &Reloc : Section.relocations()) + printRelocation(Reloc); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - + for (const SymbolRef &Symbol : Obj->symbols()) { bool Contained = false; - if (SecI->containsSymbol(*SymI, Contained) || !Contained) + if (Section.containsSymbol(Symbol, Contained) || !Contained) continue; - printSymbol(SymI); + printSymbol(Symbol); } } if (opts::SectionData) { StringRef Data; - if (error(SecI->getContents(Data))) break; + if (error(Section.getContents(Data))) + break; W.printBinaryBlock("SectionData", Data); } @@ -299,28 +278,20 @@ void MachODumper::printRelocations() { ListScope D(W, "Relocations"); error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(SecI->getName(Name))) + if (error(Section.getName(Name))) continue; bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - + for (const RelocationRef &Reloc : Section.relocations()) { if (!PrintedGroup) { W.startLine() << "Section " << Name << " {\n"; W.indent(); PrintedGroup = true; } - printRelocation(SecI, RelI); + printRelocation(Reloc); } if (PrintedGroup) { @@ -330,25 +301,24 @@ void MachODumper::printRelocations() { } } -void MachODumper::printRelocation(section_iterator SecI, - relocation_iterator RelI) { - return printRelocation(Obj, SecI, RelI); +void MachODumper::printRelocation(const RelocationRef &Reloc) { + return printRelocation(Obj, Reloc); } void MachODumper::printRelocation(const MachOObjectFile *Obj, - section_iterator SecI, - relocation_iterator RelI) { + const RelocationRef &Reloc) { uint64_t Offset; SmallString<32> RelocName; StringRef SymbolName; - if (error(RelI->getOffset(Offset))) return; - if (error(RelI->getTypeName(RelocName))) return; - symbol_iterator Symbol = RelI->getSymbol(); - if (Symbol != Obj->end_symbols() && - error(Symbol->getName(SymbolName))) + if (error(Reloc.getOffset(Offset))) + return; + if (error(Reloc.getTypeName(RelocName))) + return; + symbol_iterator Symbol = Reloc.getSymbol(); + if (Symbol != Obj->symbol_end() && error(Symbol->getName(SymbolName))) return; - DataRefImpl DR = RelI->getRawDataRefImpl(); + DataRefImpl DR = Reloc.getRawDataRefImpl(); MachO::any_relocation_info RE = Obj->getRelocation(DR); bool IsScattered = Obj->isRelocationScattered(RE); @@ -383,13 +353,8 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, void MachODumper::printSymbols() { ListScope Group(W, "Symbols"); - error_code EC; - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - printSymbol(SymI); + for (const SymbolRef &Symbol : Obj->symbols()) { + printSymbol(Symbol); } } @@ -397,33 +362,37 @@ void MachODumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); } -void MachODumper::printSymbol(symbol_iterator SymI) { +void MachODumper::printSymbol(const SymbolRef &Symbol) { StringRef SymbolName; - if (SymI->getName(SymbolName)) + if (Symbol.getName(SymbolName)) SymbolName = ""; - MachOSymbol Symbol; - getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol); + MachOSymbol MOSymbol; + getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); StringRef SectionName = ""; - section_iterator SecI(Obj->end_sections()); - if (!error(SymI->getSection(SecI)) && - SecI != Obj->end_sections()) - error(SecI->getName(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, Symbol.StringIndex); - if (Symbol.Type & N_STAB) { - W.printHex ("Type", "SymDebugTable", Symbol.Type); + W.printNumber("Name", SymbolName, MOSymbol.StringIndex); + if (MOSymbol.Type & MachO::N_STAB) { + W.printHex("Type", "SymDebugTable", MOSymbol.Type); } else { - W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes)); + 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, Symbol.SectionIndex); - W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF), - makeArrayRef(MachOSymbolRefTypes)); - W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF), - makeArrayRef(MachOSymbolFlags)); - W.printHex ("Value", Symbol.Value); + 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() { diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp index 61f5117..f500a05 100644 --- a/tools/llvm-readobj/ObjDumper.cpp +++ b/tools/llvm-readobj/ObjDumper.cpp @@ -13,10 +13,8 @@ //===----------------------------------------------------------------------===// #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" diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 6918e28..9e0fd2f 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -10,6 +10,8 @@ #ifndef LLVM_READOBJ_OBJDUMPER_H #define LLVM_READOBJ_OBJDUMPER_H +#include <memory> + namespace llvm { namespace object { @@ -18,9 +20,6 @@ namespace object { class error_code; -template<typename T> -class OwningPtr; - class StreamWriter; class ObjDumper { @@ -40,21 +39,22 @@ public: virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } + // Only implemented for ARM ELF at this time. + virtual void printAttributes() { } + protected: StreamWriter& W; }; -error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result); +error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); -error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result); +error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result); + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); } // namespace llvm diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h index 129f6e7..c40077a 100644 --- a/tools/llvm-readobj/StreamWriter.h +++ b/tools/llvm-readobj/StreamWriter.h @@ -11,8 +11,8 @@ #define LLVM_READOBJ_STREAMWRITER_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.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" @@ -172,6 +172,19 @@ public: startLine() << Label << ": " << int(Value) << "\n"; } + template <typename T_> + void printList(StringRef Label, const SmallVectorImpl<T_> &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (unsigned LI = 0, LE = List.size(); LI != LE; ++LI) { + if (Comma) + OS << ", "; + OS << List[LI]; + Comma = true; + } + OS << "]\n"; + } + template<typename T> void printHex(StringRef Label, T Value) { startLine() << Label << ": " << hex(Value) << "\n"; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index f84a72f..5be959f 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -20,11 +20,9 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" - #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" @@ -38,7 +36,6 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/system_error.h" - #include <string> @@ -128,6 +125,16 @@ namespace opts { // -expand-relocs cl::opt<bool> ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); + + // -codeview-linetables + cl::opt<bool> CodeViewLineTables("codeview-linetables", + cl::desc("Display CodeView line table information")); + + // -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)); } // namespace opts static int ReturnValue = EXIT_SUCCESS; @@ -172,9 +179,8 @@ static void reportError(StringRef Input, StringRef Message) { } /// @brief Creates an format-specific object file dumper. -static error_code createDumper(const ObjectFile *Obj, - StreamWriter &Writer, - OwningPtr<ObjDumper> &Result) { +static error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { if (!Obj) return readobj_error::unsupported_file_format; @@ -192,7 +198,7 @@ static error_code createDumper(const ObjectFile *Obj, /// @brief Dumps the specified object file. static void dumpObject(const ObjectFile *Obj) { StreamWriter Writer(outs()); - OwningPtr<ObjDumper> Dumper; + std::unique_ptr<ObjDumper> Dumper; if (error_code EC = createDumper(Obj, Writer, Dumper)) { reportError(Obj->getFileName(), EC); return; @@ -226,15 +232,18 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printNeededLibraries(); if (opts::ProgramHeaders) Dumper->printProgramHeaders(); + if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) + if (opts::ARMAttributes) + Dumper->printAttributes(); } /// @brief Dumps each object file in \a Arc; static void dumpArchive(const Archive *Arc) { - for (Archive::child_iterator ArcI = Arc->begin_children(), - ArcE = Arc->end_children(); + for (Archive::child_iterator ArcI = Arc->child_begin(), + ArcE = Arc->child_end(); ArcI != ArcE; ++ArcI) { - OwningPtr<Binary> child; + std::unique_ptr<Binary> child; if (error_code EC = ArcI->getAsBinary(child)) { // Ignore non-object files. if (EC != object_error::invalid_file_type) @@ -259,11 +268,12 @@ static void dumpInput(StringRef File) { } // Attempt to open the binary. - OwningPtr<Binary> Binary; - if (error_code EC = createBinary(File, Binary)) { + ErrorOr<Binary *> BinaryOrErr = createBinary(File); + if (error_code EC = BinaryOrErr.getError()) { reportError(File, EC); return; } + std::unique_ptr<Binary> Binary(BinaryOrErr.get()); if (Archive *Arc = dyn_cast<Archive>(Binary.get())) dumpArchive(Arc); diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index 3f75610..cc5c85d 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -38,6 +38,8 @@ namespace opts { extern llvm::cl::opt<bool> DynamicSymbols; extern llvm::cl::opt<bool> UnwindInfo; extern llvm::cl::opt<bool> ExpandRelocs; + extern llvm::cl::opt<bool> CodeViewLineTables; + extern llvm::cl::opt<bool> ARMAttributes; } // namespace opts #define LLVM_READOBJ_ENUM_ENT(ns, enum) \ |