diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-readobj')
17 files changed, 3617 insertions, 846 deletions
diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp new file mode 100644 index 000000000000..d35cd14265fb --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp @@ -0,0 +1,665 @@ +//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARMAttributeParser.h" +#include "StreamWriter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/LEB128.h" + +using namespace llvm; +using namespace llvm::ARMBuildAttrs; + + +static const EnumEntry<unsigned> TagNames[] = { + { "Tag_File", ARMBuildAttrs::File }, + { "Tag_Section", ARMBuildAttrs::Section }, + { "Tag_Symbol", ARMBuildAttrs::Symbol }, +}; + +namespace llvm { +#define ATTRIBUTE_HANDLER(Attr_) \ + { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ } + +const ARMAttributeParser::DisplayHandler +ARMAttributeParser::DisplayRoutines[] = { + { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, }, + { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute }, + ATTRIBUTE_HANDLER(CPU_arch), + ATTRIBUTE_HANDLER(CPU_arch_profile), + ATTRIBUTE_HANDLER(ARM_ISA_use), + ATTRIBUTE_HANDLER(THUMB_ISA_use), + ATTRIBUTE_HANDLER(FP_arch), + ATTRIBUTE_HANDLER(WMMX_arch), + ATTRIBUTE_HANDLER(Advanced_SIMD_arch), + ATTRIBUTE_HANDLER(PCS_config), + ATTRIBUTE_HANDLER(ABI_PCS_R9_use), + ATTRIBUTE_HANDLER(ABI_PCS_RW_data), + ATTRIBUTE_HANDLER(ABI_PCS_RO_data), + ATTRIBUTE_HANDLER(ABI_PCS_GOT_use), + ATTRIBUTE_HANDLER(ABI_PCS_wchar_t), + ATTRIBUTE_HANDLER(ABI_FP_rounding), + ATTRIBUTE_HANDLER(ABI_FP_denormal), + ATTRIBUTE_HANDLER(ABI_FP_exceptions), + ATTRIBUTE_HANDLER(ABI_FP_user_exceptions), + ATTRIBUTE_HANDLER(ABI_FP_number_model), + ATTRIBUTE_HANDLER(ABI_align_needed), + ATTRIBUTE_HANDLER(ABI_align_preserved), + ATTRIBUTE_HANDLER(ABI_enum_size), + ATTRIBUTE_HANDLER(ABI_HardFP_use), + ATTRIBUTE_HANDLER(ABI_VFP_args), + ATTRIBUTE_HANDLER(ABI_WMMX_args), + ATTRIBUTE_HANDLER(ABI_optimization_goals), + ATTRIBUTE_HANDLER(ABI_FP_optimization_goals), + ATTRIBUTE_HANDLER(compatibility), + ATTRIBUTE_HANDLER(CPU_unaligned_access), + ATTRIBUTE_HANDLER(FP_HP_extension), + ATTRIBUTE_HANDLER(ABI_FP_16bit_format), + ATTRIBUTE_HANDLER(MPextension_use), + ATTRIBUTE_HANDLER(DIV_use), + ATTRIBUTE_HANDLER(T2EE_use), + ATTRIBUTE_HANDLER(Virtualization_use), + ATTRIBUTE_HANDLER(nodefaults) +}; + +#undef ATTRIBUTE_HANDLER + +uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data, + uint32_t &Offset) { + unsigned Length; + uint64_t Value = decodeULEB128(Data + Offset, &Length); + Offset = Offset + Length; + return Value; +} + +StringRef ARMAttributeParser::ParseString(const uint8_t *Data, + uint32_t &Offset) { + const char *String = reinterpret_cast<const char*>(Data + Offset); + size_t Length = std::strlen(String); + Offset = Offset + Length + 1; + return StringRef(String, Length); +} + +void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + SW.printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), + ParseInteger(Data, Offset)); +} + +void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false); + + DictScope AS(SW, "Attribute"); + SW.printNumber("Tag", Tag); + if (!TagName.empty()) + SW.printString("TagName", TagName); + SW.printString("Value", ParseString(Data, Offset)); +} + +void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value, + StringRef ValueDesc) { + StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false); + + DictScope AS(SW, "Attribute"); + SW.printNumber("Tag", Tag); + SW.printNumber("Value", Value); + if (!TagName.empty()) + SW.printString("TagName", TagName); + if (!ValueDesc.empty()) + SW.printString("Description", ValueDesc); +} + +void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6", + "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M", + "ARM v7E-M", "ARM v8" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Encoded = ParseInteger(Data, Offset); + + StringRef Profile; + switch (Encoded) { + default: Profile = "Unknown"; break; + case 'A': Profile = "Application"; break; + case 'R': Profile = "Real-time"; break; + case 'M': Profile = "Microcontroller"; break; + case 'S': Profile = "Classic"; break; + case '0': Profile = "None"; break; + } + + PrintAttribute(Tag, Encoded, Profile); +} + +void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", + "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004", + "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "v6", "Static Base", "TLS", "Unused" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Absolute", "PC-relative", "SB-relative", "Not Permitted" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Absolute", "PC-relative", "Not Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Direct", "GOT-Indirect" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "IEEE-754", "Runtime" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Unsupported", "IEEE-754", "Sign Only" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag, + const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "Finite Only", "RTABI", "IEEE-754" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved" + }; + + uint64_t Value = ParseInteger(Data, Offset); + + std::string Description; + if (Value < array_lengthof(Strings)) + Description = std::string(Strings[Value]); + else if (Value <= 12) + Description = std::string("8-byte alignment, ") + utostr(1 << Value) + + std::string("-byte extended alignment"); + else + Description = "Invalid"; + + PrintAttribute(Tag, Value, Description); +} + +void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Required", "8-byte data alignment", "8-byte data and code alignment", + "Reserved" + }; + + uint64_t Value = ParseInteger(Data, Offset); + + std::string Description; + if (Value < array_lengthof(Strings)) + Description = std::string(Strings[Value]); + else if (Value <= 12) + Description = std::string("8-byte stack alignment, ") + utostr(1 << Value) + + std::string("-byte data alignment"); + else + Description = "Invalid"; + + PrintAttribute(Tag, Value, Description); +} + +void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "Packed", "Int32", "External Int32" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "AAPCS", "AAPCS VFP", "Custom", "Not Permitted" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "AAPCS", "iWMMX", "Custom" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, + const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging", + "Best Debugging" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag, + const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy", + "Best Accuracy" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Integer = ParseInteger(Data, Offset); + StringRef String = ParseString(Data, Offset); + + DictScope AS(SW, "Attribute"); + SW.printNumber("Tag", Tag); + SW.startLine() << "Value: " << Integer << ", " << String << '\n'; + SW.printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false)); + switch (Integer) { + case 0: + SW.printString("Description", StringRef("No Specific Requirements")); + break; + case 1: + SW.printString("Description", StringRef("AEABI Conformant")); + break; + default: + SW.printString("Description", StringRef("AEABI Non-Conformant")); + break; + } +} + +void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "v6-style" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "If Available", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "If Available", "Not Permitted", "Permitted" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "TrustZone", "Virtualization Extensions", + "TrustZone + Virtualization Extensions" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Value = ParseInteger(Data, Offset); + PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED"); +} + +void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset, + SmallVectorImpl<uint8_t> &IndexList) { + for (;;) { + unsigned Length; + uint64_t Value = decodeULEB128(Data + Offset, &Length); + Offset = Offset + Length; + if (Value == 0) + break; + IndexList.push_back(Value); + } +} + +void ARMAttributeParser::ParseAttributeList(const uint8_t *Data, + uint32_t &Offset, uint32_t Length) { + while (Offset < Length) { + unsigned Length; + uint64_t Tag = decodeULEB128(Data + Offset, &Length); + Offset += Length; + + bool Handled = false; + for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines); + AHI != AHE && !Handled; ++AHI) { + if (DisplayRoutines[AHI].Attribute == Tag) { + (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag), + Data, Offset); + Handled = true; + break; + } + } + if (!Handled) { + if (Tag < 32) { + errs() << "unhandled AEABI Tag " << Tag + << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n"; + continue; + } + + if (Tag % 2 == 0) + IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset); + else + StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset); + } + } +} + +void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { + uint32_t Offset = sizeof(uint32_t); /* SectionLength */ + + SW.printNumber("SectionLength", Length); + + const char *VendorName = reinterpret_cast<const char*>(Data + Offset); + size_t VendorNameLength = std::strlen(VendorName); + SW.printString("Vendor", StringRef(VendorName, VendorNameLength)); + Offset = Offset + VendorNameLength + 1; + + if (StringRef(VendorName, VendorNameLength).lower() != "aeabi") + return; + + while (Offset < Length) { + /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size + uint8_t Tag = Data[Offset]; + SW.printEnum("Tag", Tag, makeArrayRef(TagNames)); + Offset = Offset + sizeof(Tag); + + uint32_t Size = + *reinterpret_cast<const support::ulittle32_t*>(Data + Offset); + SW.printNumber("Size", Size); + Offset = Offset + sizeof(Size); + + if (Size > Length) { + errs() << "subsection length greater than section length\n"; + return; + } + + StringRef ScopeName, IndexName; + SmallVector<uint8_t, 8> Indicies; + switch (Tag) { + case ARMBuildAttrs::File: + ScopeName = "FileAttributes"; + break; + case ARMBuildAttrs::Section: + ScopeName = "SectionAttributes"; + IndexName = "Sections"; + ParseIndexList(Data, Offset, Indicies); + break; + case ARMBuildAttrs::Symbol: + ScopeName = "SymbolAttributes"; + IndexName = "Symbols"; + ParseIndexList(Data, Offset, Indicies); + break; + default: + errs() << "unrecognised tag: 0x" << utohexstr(Tag) << '\n'; + return; + } + + DictScope ASS(SW, ScopeName); + + if (!Indicies.empty()) + SW.printList(IndexName, Indicies); + + ParseAttributeList(Data, Offset, Length); + } +} + +void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section) { + size_t Offset = 1; + unsigned SectionNumber = 0; + + while (Offset < Section.size()) { + uint32_t SectionLength = + *reinterpret_cast<const support::ulittle32_t*>(Section.data() + Offset); + + SW.startLine() << "Section " << ++SectionNumber << " {\n"; + SW.indent(); + + ParseSubsection(Section.data() + Offset, SectionLength); + Offset = Offset + SectionLength; + + SW.unindent(); + SW.startLine() << "}\n"; + } +} +} + diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h new file mode 100644 index 000000000000..c2862513b751 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h @@ -0,0 +1,124 @@ +//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_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/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h new file mode 100644 index 000000000000..7608cfbbd8d1 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -0,0 +1,552 @@ +//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ARMEHABI_PRINTER_H +#define LLVM_READOBJ_ARMEHABI_PRINTER_H + +#include "Error.h" +#include "StreamWriter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Support/ARMEHABI.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/type_traits.h" + +namespace llvm { +namespace ARM { +namespace EHABI { + +class OpcodeDecoder { + StreamWriter &SW; + raw_ostream &OS; + + struct RingEntry { + uint8_t Mask; + uint8_t Value; + void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI); + }; + static const RingEntry Ring[]; + + void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI); + void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI); + void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_10011101(const uint8_t *Opcodes, unsigned &OI); + void Decode_10011111(const uint8_t *Opcodes, unsigned &OI); + void Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110000(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110001_0000iiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110010_uleb128(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110011_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_101101nn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000110_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000111_0000iiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001000_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001001_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI); + + void PrintGPR(uint16_t GPRMask); + void PrintRegisters(uint32_t Mask, StringRef Prefix); + +public: + OpcodeDecoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length); +}; + +const OpcodeDecoder::RingEntry OpcodeDecoder::Ring[] = { + { 0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx }, + { 0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx }, + { 0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii }, + { 0xff, 0x9d, &OpcodeDecoder::Decode_10011101 }, + { 0xff, 0x9f, &OpcodeDecoder::Decode_10011111 }, + { 0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn }, + { 0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn }, + { 0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn }, + { 0xff, 0xb0, &OpcodeDecoder::Decode_10110000 }, + { 0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii }, + { 0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128 }, + { 0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc }, + { 0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn }, + { 0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn }, + { 0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc }, + { 0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii }, + { 0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc }, + { 0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc }, + { 0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy }, + { 0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn }, + { 0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn }, + { 0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy }, +}; + +void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode, + ((Opcode & 0x3f) << 2) + 4); +} +void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode, + ((Opcode & 0x3f) << 2) + 4); +} +void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + + uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12); + SW.startLine() + << format("0x%02X 0x%02X ; %s", + Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind"); + if (GPRMask) + PrintGPR(GPRMask); + OS << '\n'; +} +void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; reserved (ARM MOVrr)\n", Opcode); +} +void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; reserved (WiMMX MOVrr)\n", Opcode); +} +void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = r%u\n", Opcode, (Opcode & 0x0f)); +} +void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; finish\n", Opcode); +} +void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + + SW.startLine() + << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1, + ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop "); + if (((Opcode1 & 0xf0) == 0x00) && Opcode1) + PrintGPR((Opcode1 & 0x0f)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ", Opcode); + + SmallVector<uint8_t, 4> ULEB; + do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80); + + for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI) + OS << format("0x%02X ", ULEB[BI]); + + uint64_t Value = 0; + for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI) + Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI)); + + OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2)); +} +void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} +void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() + << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1, + ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop "); + if ((Opcode1 & 0xf0) == 0x00 && Opcode1) + PrintRegisters(Opcode1 & 0x0f, "wCGR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} +void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} + +void OpcodeDecoder::PrintGPR(uint16_t GPRMask) { + static const char *GPRRegisterNames[16] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "fp", "ip", "sp", "lr", "pc" + }; + + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 17; RI < RE; ++RI) { + if (GPRMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << GPRRegisterNames[RI]; + Comma = true; + } + } + OS << '}'; +} + +void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) { + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { + if (VFPMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << Prefix << RI; + Comma = true; + } + } + OS << '}'; +} + +void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) { + for (unsigned OCI = Offset; OCI < Length + Offset; ) { + bool Decoded = false; + for (unsigned REI = 0, REE = array_lengthof(Ring); + REI != REE && !Decoded; ++REI) { + if ((Opcodes[OCI ^ 3] & Ring[REI].Mask) == Ring[REI].Value) { + (this->*Ring[REI].Routine)(Opcodes, OCI); + Decoded = true; + break; + } + } + if (!Decoded) + SW.startLine() << format("0x%02X ; reserved\n", Opcodes[OCI++ ^ 3]); + } +} + +template <typename ET> +class PrinterContext { + StreamWriter &SW; + const object::ELFFile<ET> *ELF; + + typedef typename object::ELFFile<ET>::Elf_Sym Elf_Sym; + typedef typename object::ELFFile<ET>::Elf_Shdr Elf_Shdr; + + typedef typename object::ELFFile<ET>::Elf_Rel_Iter Elf_Rel_iterator; + typedef typename object::ELFFile<ET>::Elf_Sym_Iter Elf_Sym_iterator; + typedef typename object::ELFFile<ET>::Elf_Shdr_Iter Elf_Shdr_iterator; + + static const size_t IndexTableEntrySize; + + static uint64_t PREL31(uint32_t Address, uint32_t Place) { + uint64_t Location = Address & 0x7fffffff; + if (Location & 0x04000000) + Location |= (uint64_t) ~0x7fffffff; + return Location + Place; + } + + ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const; + const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex, + off_t IndexTableOffset) const; + + void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const; + void PrintExceptionTable(const Elf_Shdr *IT, const Elf_Shdr *EHT, + uint64_t TableEntryOffset) const; + void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const; + +public: + PrinterContext(StreamWriter &Writer, const object::ELFFile<ET> *File) + : SW(Writer), ELF(File) {} + + void PrintUnwindInformation() const; +}; + +template <typename ET> +const size_t PrinterContext<ET>::IndexTableEntrySize = 8; + +template <typename ET> +ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(unsigned Section, + uint64_t Address) const { + for (Elf_Sym_iterator SI = ELF->begin_symbols(), SE = ELF->end_symbols(); + SI != SE; ++SI) + if (SI->st_shndx == Section && SI->st_value == Address && + SI->getType() == ELF::STT_FUNC) + return ELF->getSymbolName(SI); + return readobj_error::unknown_symbol; +} + +template <typename ET> +const typename object::ELFFile<ET>::Elf_Shdr * +PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, + off_t IndexTableOffset) const { + /// Iterate through the sections, searching for the relocation section + /// associated with the unwind index table section specified by + /// IndexSectionIndex. Iterate the associated section searching for the + /// relocation associated with the index table entry specified by + /// IndexTableOffset. The symbol is the section symbol for the exception + /// handling table. Use this symbol to recover the actual exception handling + /// table. + + for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections(); + SI != SE; ++SI) { + if (SI->sh_type == ELF::SHT_REL && SI->sh_info == IndexSectionIndex) { + for (Elf_Rel_iterator RI = ELF->begin_rel(&*SI), RE = ELF->end_rel(&*SI); + RI != RE; ++RI) { + if (RI->r_offset == static_cast<unsigned>(IndexTableOffset)) { + typename object::ELFFile<ET>::Elf_Rela RelA; + RelA.r_offset = RI->r_offset; + RelA.r_info = RI->r_info; + RelA.r_addend = 0; + + std::pair<const Elf_Shdr *, const Elf_Sym *> Symbol = + ELF->getRelocationSymbol(&(*SI), &RelA); + + return ELF->getSection(Symbol.second); + } + } + } + } + return nullptr; +} + +template <typename ET> +void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT, + const Elf_Shdr *EHT, + uint64_t TableEntryOffset) const { + ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(EHT); + if (!Contents) + return; + + /// ARM EHABI Section 6.2 - The generic model + /// + /// An exception-handling table entry for the generic model is laid out as: + /// + /// 3 3 + /// 1 0 0 + /// +-+------------------------------+ + /// |0| personality routine offset | + /// +-+------------------------------+ + /// | personality routine data ... | + /// + /// + /// ARM EHABI Section 6.3 - The ARM-defined compact model + /// + /// An exception-handling table entry for the compact model looks like: + /// + /// 3 3 2 2 2 2 + /// 1 0 8 7 4 3 0 + /// +-+---+----+-----------------------+ + /// |1| 0 | Ix | data for pers routine | + /// +-+---+----+-----------------------+ + /// | more personality routine data | + + const support::ulittle32_t Word = + *reinterpret_cast<const support::ulittle32_t *>(Contents->data() + TableEntryOffset); + + if (Word & 0x80000000) { + SW.printString("Model", StringRef("Compact")); + + unsigned PersonalityIndex = (Word & 0x0f000000) >> 24; + SW.printNumber("PersonalityIndex", PersonalityIndex); + + switch (PersonalityIndex) { + case AEABI_UNWIND_CPP_PR0: + PrintOpcodes(Contents->data() + TableEntryOffset, 3, 1); + break; + case AEABI_UNWIND_CPP_PR1: + case AEABI_UNWIND_CPP_PR2: + unsigned AdditionalWords = (Word & 0x00ff0000) >> 16; + PrintOpcodes(Contents->data() + TableEntryOffset, 2 + 4 * AdditionalWords, + 2); + break; + } + } else { + SW.printString("Model", StringRef("Generic")); + + uint64_t Address = PREL31(Word, EHT->sh_addr); + SW.printHex("PersonalityRoutineAddress", Address); + if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address)) + SW.printString("PersonalityRoutineName", *Name); + } +} + +template <typename ET> +void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry, + size_t Length, off_t Offset) const { + ListScope OCC(SW, "Opcodes"); + OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length); +} + +template <typename ET> +void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex, + const Elf_Shdr *IT) const { + ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(IT); + if (!Contents) + return; + + /// ARM EHABI Section 5 - Index Table Entries + /// * The first word contains a PREL31 offset to the start of a function with + /// bit 31 clear + /// * The second word contains one of: + /// - The PREL31 offset of the start of the table entry for the function, + /// with bit 31 clear + /// - The exception-handling table entry itself with bit 31 set + /// - The special bit pattern EXIDX_CANTUNWIND, indicating that associated + /// frames cannot be unwound + + const support::ulittle32_t *Data = + reinterpret_cast<const support::ulittle32_t *>(Contents->data()); + const unsigned Entries = IT->sh_size / IndexTableEntrySize; + + ListScope E(SW, "Entries"); + for (unsigned Entry = 0; Entry < Entries; ++Entry) { + DictScope E(SW, "Entry"); + + const support::ulittle32_t Word0 = + Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 0]; + const support::ulittle32_t Word1 = + Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 1]; + + if (Word0 & 0x80000000) { + errs() << "corrupt unwind data in section " << SectionIndex << "\n"; + continue; + } + + const uint64_t Offset = PREL31(Word0, IT->sh_addr); + SW.printHex("FunctionAddress", Offset); + if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset)) + SW.printString("FunctionName", *Name); + + if (Word1 == EXIDX_CANTUNWIND) { + SW.printString("Model", StringRef("CantUnwind")); + continue; + } + + if (Word1 & 0x80000000) { + SW.printString("Model", StringRef("Compact (Inline)")); + + unsigned PersonalityIndex = (Word1 & 0x0f000000) >> 24; + SW.printNumber("PersonalityIndex", PersonalityIndex); + + PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1); + } else { + const Elf_Shdr *EHT = + FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4); + + if (ErrorOr<StringRef> Name = ELF->getSectionName(EHT)) + SW.printString("ExceptionHandlingTable", *Name); + + uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr); + SW.printHex("TableEntryOffset", TableEntryOffset); + + PrintExceptionTable(IT, EHT, TableEntryOffset); + } + } +} + +template <typename ET> +void PrinterContext<ET>::PrintUnwindInformation() const { + DictScope UI(SW, "UnwindInformation"); + + int SectionIndex = 0; + for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections(); + SI != SE; ++SI, ++SectionIndex) { + if (SI->sh_type == ELF::SHT_ARM_EXIDX) { + const Elf_Shdr *IT = &(*SI); + + DictScope UIT(SW, "UnwindIndexTable"); + + SW.printNumber("SectionIndex", SectionIndex); + if (ErrorOr<StringRef> SectionName = ELF->getSectionName(IT)) + SW.printString("SectionName", *SectionName); + SW.printHex("SectionOffset", IT->sh_offset); + + PrintIndexTable(SectionIndex, IT); + } + } +} +} +} +} + +#endif + diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp new file mode 100644 index 000000000000..b486e4ad0e51 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -0,0 +1,744 @@ +//===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Windows on ARM uses a series of serialised data structures (RuntimeFunction) +// to create a table of information for unwinding. In order to conserve space, +// there are two different ways that this data is represented. +// +// For functions with canonical forms for the prologue and epilogue, the data +// can be stored in a "packed" form. In this case, the data is packed into the +// RuntimeFunction's remaining 30-bits and can fully describe the entire frame. +// +// +---------------------------------------+ +// | Function Entry Address | +// +---------------------------------------+ +// | Packed Form Data | +// +---------------------------------------+ +// +// This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is +// associated with such a frame as they can be derived from the provided data. +// The decoder does not synthesize this data as it is unnecessary for the +// purposes of validation, with the synthesis being required only by a proper +// unwinder. +// +// For functions that are large or do not match canonical forms, the data is +// split up into two portions, with the actual data residing in the "exception +// data" table (.xdata) with a reference to the entry from the "procedure data" +// (.pdata) entry. +// +// The exception data contains information about the frame setup, all of the +// epilouge scopes (for functions for which there are multiple exit points) and +// the associated exception handler. Additionally, the entry contains byte-code +// describing how to unwind the function (c.f. Decoder::decodeOpcodes). +// +// +---------------------------------------+ +// | Function Entry Address | +// +---------------------------------------+ +// | Exception Data Entry Address | +// +---------------------------------------+ +// +// This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must +// first resolve the exception data entry address. This structure +// (ExceptionDataRecord) has a variable sized header +// (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as +// the packed form. However, because this information is insufficient to +// synthesize the unwinding, there are associated unwinding bytecode which make +// up the bulk of the Decoder. +// +// The decoder itself is table-driven, using the first byte to determine the +// opcode and dispatching to the associated printing routine. The bytecode +// itself is a variable length instruction encoding that can fully describe the +// state of the stack and the necessary operations for unwinding to the +// beginning of the frame. +// +// The byte-code maintains a 1-1 instruction mapping, indicating both the width +// of the instruction (Thumb2 instructions are variable length, 16 or 32 bits +// wide) allowing the program to unwind from any point in the prologue, body, or +// epilogue of the function. + +#include "ARMWinEHPrinter.h" +#include "Error.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ARMWinEH.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support; + +namespace llvm { +raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) { + switch (RT) { + case ARM::WinEH::ReturnType::RT_POP: + OS << "pop {pc}"; + break; + case ARM::WinEH::ReturnType::RT_B: + OS << "b target"; + break; + case ARM::WinEH::ReturnType::RT_BW: + OS << "b.w target"; + break; + case ARM::WinEH::ReturnType::RT_NoEpilogue: + OS << "(no epilogue)"; + break; + } + return OS; +} +} + +static std::string formatSymbol(StringRef Name, uint64_t Address, + uint64_t Offset = 0) { + std::string Buffer; + raw_string_ostream OS(Buffer); + + if (!Name.empty()) + OS << Name << " "; + + if (Offset) + OS << format("+0x%X (0x%" PRIX64 ")", Offset, Address); + else if (!Name.empty()) + OS << format("(0x%" PRIX64 ")", Address); + else + OS << format("0x%" PRIX64, Address); + + return OS.str(); +} + +namespace llvm { +namespace ARM { +namespace WinEH { +const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); + +// TODO name the uops more appropriately +const Decoder::RingEntry Decoder::Ring[] = { + { 0x80, 0x00, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit) + { 0xc0, 0x80, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit) + { 0xf0, 0xc0, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit) + { 0xf8, 0xd0, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit) + { 0xf8, 0xd8, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit) + { 0xf8, 0xe0, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit) + { 0xfc, 0xe8, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit) + { 0xfe, 0xec, &Decoder::opcode_1110110L }, // UOP_POP (16-bit) + { 0xff, 0xee, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit) + // UOP_PUSH_MACHINE_FRAME + // UOP_PUSH_CONTEXT + // UOP_PUSH_TRAP_FRAME + // UOP_REDZONE_RESTORE_LR + { 0xff, 0xef, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit) + { 0xff, 0xf5, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit) + { 0xff, 0xf6, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit) + { 0xff, 0xf7, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit) + { 0xff, 0xf8, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit) + { 0xff, 0xf9, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit) + { 0xff, 0xfa, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit) + { 0xff, 0xfb, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit) + { 0xff, 0xfc, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit) + { 0xff, 0xfd, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END + { 0xff, 0xfe, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END + { 0xff, 0xff, &Decoder::opcode_11111111 }, // UOP_END +}; + +void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask) { + static const char * const GPRRegisterNames[16] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "ip", "sp", "lr", "pc", + }; + + const uint16_t GPRMask = std::get<0>(RegisterMask); + const uint16_t VFPMask = std::get<1>(RegisterMask); + + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 11; RI < RE; ++RI) { + if (GPRMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << GPRRegisterNames[RI]; + Comma = true; + } + } + for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { + if (VFPMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << "d" << unsigned(RI); + Comma = true; + } + } + for (unsigned RI = 11, RE = 16; RI < RE; ++RI) { + if (GPRMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << GPRRegisterNames[RI]; + Comma = true; + } + } + OS << '}'; +} + +ErrorOr<object::SectionRef> +Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { + for (const auto &Section : COFF.sections()) { + uint64_t Address; + uint64_t Size; + + if (std::error_code EC = Section.getAddress(Address)) + return EC; + if (std::error_code EC = Section.getSize(Size)) + return EC; + + if (VA >= Address && (VA - Address) <= Size) + return Section; + } + return readobj_error::unknown_symbol; +} + +ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, + uint64_t VA, bool FunctionOnly) { + for (const auto &Symbol : COFF.symbols()) { + if (FunctionOnly) { + SymbolRef::Type Type; + if (std::error_code EC = Symbol.getType(Type)) + return EC; + if (Type != SymbolRef::ST_Function) + continue; + } + + uint64_t Address; + if (std::error_code EC = Symbol.getAddress(Address)) + return EC; + if (Address == VA) + return Symbol; + } + return readobj_error::unknown_symbol; +} + +ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, + const SectionRef &Section, + uint64_t Offset) { + for (const auto &Relocation : Section.relocations()) { + uint64_t RelocationOffset; + if (auto Error = Relocation.getOffset(RelocationOffset)) + return Error; + if (RelocationOffset == Offset) + return *Relocation.getSymbol(); + } + return readobj_error::unknown_symbol; +} + +bool Decoder::opcode_0xxxxxxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint8_t Imm = OC[Offset] & 0x7f; + SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n", + OC[Offset], + static_cast<const char *>(Prologue ? "sub" : "add"), + Imm); + ++Offset; + return false; +} + +bool Decoder::opcode_10Lxxxxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Link = (OC[Offset] & 0x20) >> 5; + uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) + | ((OC[Offset + 0] & 0x1f) << 8) + | ((OC[Offset + 1] & 0xff) << 0); + assert((~RegisterMask & (1 << 13)) && "sp must not be set"); + assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set"); + + SW.startLine() << format("0x%02x 0x%02x ; %s.w ", + OC[Offset + 0], OC[Offset + 1], + Prologue ? "push" : "pop"); + printRegisters(std::make_pair(RegisterMask, 0)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_1100xxxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + if (Prologue) + SW.startLine() << format("0x%02x ; mov r%u, sp\n", + OC[Offset], OC[Offset] & 0xf); + else + SW.startLine() << format("0x%02x ; mov sp, r%u\n", + OC[Offset], OC[Offset] & 0xf); + ++Offset; + return false; +} + +bool Decoder::opcode_11010Lxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Link = (OC[Offset] & 0x4) >> 3; + unsigned Count = (OC[Offset] & 0x3); + + uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) + | (((1 << (Count + 1)) - 1) << 4); + + SW.startLine() << format("0x%02x ; %s ", OC[Offset], + Prologue ? "push" : "pop"); + printRegisters(std::make_pair(GPRMask, 0)); + OS << '\n'; + + ++Offset; + return false; +} + +bool Decoder::opcode_11011Lxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Link = (OC[Offset] & 0x4) >> 2; + unsigned Count = (OC[Offset] & 0x3) + 4; + + uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) + | (((1 << (Count + 1)) - 1) << 4); + + SW.startLine() << format("0x%02x ; %s.w ", OC[Offset], + Prologue ? "push" : "pop"); + printRegisters(std::make_pair(GPRMask, 0)); + OS << '\n'; + + ++Offset; + return false; +} + +bool Decoder::opcode_11100xxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned High = (OC[Offset] & 0x7); + uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); + + SW.startLine() << format("0x%02x ; %s ", OC[Offset], + Prologue ? "vpush" : "vpop"); + printRegisters(std::make_pair(0, VFPMask)); + OS << '\n'; + + ++Offset; + return false; +} + +bool Decoder::opcode_111010xx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); + + SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], + static_cast<const char *>(Prologue ? "sub" : "add"), + Imm); + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_1110110L(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) + | ((OC[Offset + 1] & 0xff) << 0); + + SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], + OC[Offset + 1], Prologue ? "push" : "pop"); + printRegisters(std::make_pair(GPRMask, 0)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11101110(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + assert(!Prologue && "may not be used in prologue"); + + if (OC[Offset + 1] & 0xf0) + SW.startLine() << format("0x%02x 0x%02x ; reserved\n", + OC[Offset + 0], OC[Offset + 1]); + else + SW.startLine() + << format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f); + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11101111(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + assert(!Prologue && "may not be used in prologue"); + + if (OC[Offset + 1] & 0xf0) + SW.startLine() << format("0x%02x 0x%02x ; reserved\n", + OC[Offset + 0], OC[Offset + 1]); + else + SW.startLine() + << format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11110101(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; + unsigned End = (OC[Offset + 1] & 0x0f) >> 0; + uint32_t VFPMask = ((1 << (End - Start)) - 1) << Start; + + SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], + OC[Offset + 1], Prologue ? "vpush" : "vpop"); + printRegisters(std::make_pair(0, VFPMask)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11110110(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; + unsigned End = (OC[Offset + 1] & 0x0f) >> 0; + uint32_t VFPMask = ((1 << (End - Start)) - 1) << 16; + + SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], + OC[Offset + 1], Prologue ? "vpush" : "vpop"); + printRegisters(std::make_pair(0, VFPMask)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11110111(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); + + SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], + static_cast<const char *>(Prologue ? "sub" : "add"), + Imm); + + ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111000(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 16) + | (OC[Offset + 2] << 8) + | (OC[Offset + 3] << 0); + + SW.startLine() + << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], + static_cast<const char *>(Prologue ? "sub" : "add"), Imm); + + ++Offset, ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111001(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); + + SW.startLine() + << format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], + static_cast<const char *>(Prologue ? "sub" : "add"), Imm); + + ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111010(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 16) + | (OC[Offset + 2] << 8) + | (OC[Offset + 3] << 0); + + SW.startLine() + << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], + static_cast<const char *>(Prologue ? "sub" : "add"), Imm); + + ++Offset, ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111011(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_11111100(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_11111101(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; b\n", OC[Offset]); + ++Offset; + return true; +} + +bool Decoder::opcode_11111110(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; b.w\n", OC[Offset]); + ++Offset; + return true; +} + +bool Decoder::opcode_11111111(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + ++Offset; + return true; +} + +void Decoder::decodeOpcodes(ArrayRef<ulittle8_t> Opcodes, unsigned Offset, + bool Prologue) { + assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); + + bool Terminated = false; + for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { + for (unsigned DI = 0;; ++DI) { + if ((Opcodes[OI] & Ring[DI].Mask) == Ring[DI].Value) { + Terminated = (this->*Ring[DI].Routine)(Opcodes.data(), OI, 0, Prologue); + break; + } + assert(DI < array_lengthof(Ring) && "unhandled opcode"); + } + } +} + +bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, + const SectionRef &Section, + uint64_t FunctionAddress, uint64_t VA) { + ArrayRef<uint8_t> Contents; + if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) + return false; + + uint64_t SectionVA; + if (Section.getAddress(SectionVA)) + return false; + + uint64_t Offset = VA - SectionVA; + const ulittle32_t *Data = + reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); + const ExceptionDataRecord XData(Data); + + DictScope XRS(SW, "ExceptionData"); + SW.printNumber("FunctionLength", XData.FunctionLength() << 1); + SW.printNumber("Version", XData.Vers()); + SW.printBoolean("ExceptionData", XData.X()); + SW.printBoolean("EpiloguePacked", XData.E()); + SW.printBoolean("Fragment", XData.F()); + SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes", + XData.EpilogueCount()); + SW.printNumber("ByteCodeLength", + static_cast<uint64_t>(XData.CodeWords() * sizeof(uint32_t))); + + if (XData.E()) { + ArrayRef<ulittle8_t> UC = XData.UnwindByteCode(); + if (!XData.F()) { + ListScope PS(SW, "Prologue"); + decodeOpcodes(UC, 0, /*Prologue=*/true); + } + if (XData.EpilogueCount()) { + ListScope ES(SW, "Epilogue"); + decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false); + } + } else { + ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes(); + ListScope ESS(SW, "EpilogueScopes"); + for (const EpilogueScope ES : EpilogueScopes) { + DictScope ESES(SW, "EpilogueScope"); + SW.printNumber("StartOffset", ES.EpilogueStartOffset()); + SW.printNumber("Condition", ES.Condition()); + SW.printNumber("EpilogueStartIndex", ES.EpilogueStartIndex()); + + ListScope Opcodes(SW, "Opcodes"); + decodeOpcodes(XData.UnwindByteCode(), ES.EpilogueStartIndex(), + /*Prologue=*/false); + } + } + + if (XData.X()) { + const uint32_t Address = XData.ExceptionHandlerRVA(); + const uint32_t Parameter = XData.ExceptionHandlerParameter(); + const size_t HandlerOffset = HeaderWords(XData) + + (XData.E() ? 0 : XData.EpilogueCount()) + + XData.CodeWords(); + + ErrorOr<SymbolRef> Symbol = + getRelocatedSymbol(COFF, Section, HandlerOffset * sizeof(uint32_t)); + if (!Symbol) + Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); + + StringRef Name; + if (Symbol) + Symbol->getName(Name); + + ListScope EHS(SW, "ExceptionHandler"); + SW.printString("Routine", formatSymbol(Name, Address)); + SW.printHex("Parameter", Parameter); + } + + return true; +} + +bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, + const SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &RF) { + assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && + "packed entry cannot be treated as an unpacked entry"); + + ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); + if (!Function) + Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + + ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4); + if (!XDataRecord) + XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA()); + + if (!RF.BeginAddress && !Function) + return false; + if (!RF.UnwindData && !XDataRecord) + return false; + + StringRef FunctionName; + uint64_t FunctionAddress; + if (Function) { + Function->getName(FunctionName); + Function->getAddress(FunctionAddress); + } else { + const pe32_header *PEHeader; + if (COFF.getPE32Header(PEHeader)) + return false; + FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; + } + + SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + + if (XDataRecord) { + StringRef Name; + uint64_t Address; + + XDataRecord->getName(Name); + XDataRecord->getAddress(Address); + + SW.printString("ExceptionRecord", formatSymbol(Name, Address)); + + section_iterator SI = COFF.section_end(); + if (XDataRecord->getSection(SI)) + return false; + + return dumpXDataRecord(COFF, *SI, FunctionAddress, Address); + } else { + const pe32_header *PEHeader; + if (COFF.getPE32Header(PEHeader)) + return false; + + uint64_t Address = PEHeader->ImageBase + RF.ExceptionInformationRVA(); + SW.printString("ExceptionRecord", formatSymbol("", Address)); + + ErrorOr<SectionRef> Section = + getSectionContaining(COFF, RF.ExceptionInformationRVA()); + if (!Section) + return false; + + return dumpXDataRecord(COFF, *Section, FunctionAddress, + RF.ExceptionInformationRVA()); + } +} + +bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, + const SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &RF) { + assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || + RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && + "unpacked entry cannot be treated as a packed entry"); + + ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); + if (!Function) + Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + + StringRef FunctionName; + uint64_t FunctionAddress; + if (Function) { + Function->getName(FunctionName); + Function->getAddress(FunctionAddress); + } else { + const pe32_header *PEHeader; + if (COFF.getPE32Header(PEHeader)) + return false; + FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; + } + + SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + SW.printBoolean("Fragment", + RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); + SW.printNumber("FunctionLength", RF.FunctionLength()); + SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; + SW.printBoolean("HomedParameters", RF.H()); + SW.startLine() << "SavedRegisters: "; + printRegisters(SavedRegisterMask(RF)); + OS << '\n'; + SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2); + + return true; +} + +bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, + const SectionRef Section, unsigned Index, + ArrayRef<uint8_t> Contents) { + uint64_t Offset = PDataEntrySize * Index; + const ulittle32_t *Data = + reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); + + const RuntimeFunction Entry(Data); + DictScope RFS(SW, "RuntimeFunction"); + if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) + return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry); + return dumpPackedEntry(COFF, Section, Offset, Index, Entry); +} + +void Decoder::dumpProcedureData(const COFFObjectFile &COFF, + const SectionRef Section) { + ArrayRef<uint8_t> Contents; + if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) + return; + + if (Contents.size() % PDataEntrySize) { + errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n"; + return; + } + + for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI) + if (!dumpProcedureDataEntry(COFF, Section, EI, Contents)) + break; +} + +std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) { + for (const auto &Section : COFF.sections()) { + StringRef SectionName; + if (std::error_code EC = + COFF.getSectionName(COFF.getCOFFSection(Section), SectionName)) + return EC; + + if (SectionName.startswith(".pdata")) + dumpProcedureData(COFF, Section); + } + return std::error_code(); +} +} +} +} + diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h new file mode 100644 index 000000000000..740c8b5841b5 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h @@ -0,0 +1,119 @@ +//===--- ARMWinEHPrinter.h - Windows on ARM Unwind Information Printer ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ARMWINEHPRINTER_H +#define LLVM_READOBJ_ARMWINEHPRINTER_H + +#include "StreamWriter.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/ErrorOr.h" + +namespace llvm { +namespace ARM { +namespace WinEH { +class RuntimeFunction; + +class Decoder { + static const size_t PDataEntrySize; + + StreamWriter &SW; + raw_ostream &OS; + + struct RingEntry { + uint8_t Mask; + uint8_t Value; + bool (Decoder::*Routine)(const support::ulittle8_t *, unsigned &, unsigned, + bool); + }; + static const RingEntry Ring[]; + + bool opcode_0xxxxxxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_10Lxxxxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_1100xxxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11010Lxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11011Lxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11100xxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_111010xx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_1110110L(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11101110(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11101111(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11110101(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11110110(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11110111(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111000(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111001(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111010(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111011(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111100(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111101(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111110(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111111(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + + void decodeOpcodes(ArrayRef<support::ulittle8_t> Opcodes, unsigned Offset, + bool Prologue); + + void printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask); + + ErrorOr<object::SectionRef> + getSectionContaining(const object::COFFObjectFile &COFF, uint64_t Address); + + ErrorOr<object::SymbolRef> + getSymbol(const object::COFFObjectFile &COFF, uint64_t Address, + bool FunctionOnly = false); + + ErrorOr<object::SymbolRef> + getRelocatedSymbol(const object::COFFObjectFile &COFF, + const object::SectionRef &Section, uint64_t Offset); + + bool dumpXDataRecord(const object::COFFObjectFile &COFF, + const object::SectionRef &Section, + uint64_t FunctionAddress, uint64_t VA); + bool dumpUnpackedEntry(const object::COFFObjectFile &COFF, + const object::SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &Entry); + bool dumpPackedEntry(const object::COFFObjectFile &COFF, + const object::SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &Entry); + bool dumpProcedureDataEntry(const object::COFFObjectFile &COFF, + const object::SectionRef Section, unsigned Entry, + ArrayRef<uint8_t> Contents); + void dumpProcedureData(const object::COFFObjectFile &COFF, + const object::SectionRef Section); + +public: + Decoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + std::error_code dumpProcedureData(const object::COFFObjectFile &COFF); +}; +} +} +} + +#endif + diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp index 2f309e30ec22..7842cd4d44fe 100644 --- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -13,25 +13,26 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" -#include "ObjDumper.h" - +#include "ARMWinEHPrinter.h" #include "Error.h" +#include "ObjDumper.h" #include "StreamWriter.h" - +#include "Win64EHDumper.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/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 <system_error> #include <time.h> using namespace llvm; @@ -48,53 +49,35 @@ 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, - const std::vector<RelocationRef> &Rels); - - void printUnwindInfo( - const Win64EH::UnwindInfo& UI, - uint64_t OffsetInSection, - const std::vector<RelocationRef> &Rels); - - void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs); + void printCodeViewLineTables(const SectionRef &Section); void cacheRelocations(); - error_code getSectionContents( - const std::vector<RelocationRef> &Rels, - uint64_t Offset, - ArrayRef<uint8_t> &Contents, - uint64_t &Addr); - - error_code getSection( - const std::vector<RelocationRef> &Rels, - uint64_t Offset, - const coff_section **Section, - uint64_t *AddrPtr); + std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset, + SymbolRef &Sym); + std::error_code resolveSymbolName(const coff_section *Section, + uint64_t Offset, StringRef &Name); typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; const llvm::object::COFFObjectFile *Obj; RelocMapTy RelocMap; - std::vector<RelocationRef> EmptyRelocs; }; } // namespace @@ -102,9 +85,9 @@ private: namespace llvm { -error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { +std::error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); if (!COFFObj) return readobj_error::unsupported_obj_file_format; @@ -115,110 +98,34 @@ error_code createCOFFDumper(const object::ObjectFile *Obj, } // namespace llvm - -// Returns the name of the unwind code. -static StringRef getUnwindCodeTypeName(uint8_t Code) { - switch(Code) { - default: llvm_unreachable("Invalid unwind code"); - case UOP_PushNonVol: return "PUSH_NONVOL"; - case UOP_AllocLarge: return "ALLOC_LARGE"; - case UOP_AllocSmall: return "ALLOC_SMALL"; - case UOP_SetFPReg: return "SET_FPREG"; - case UOP_SaveNonVol: return "SAVE_NONVOL"; - case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; - case UOP_SaveXMM128: return "SAVE_XMM128"; - case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; - case UOP_PushMachFrame: return "PUSH_MACHFRAME"; - } -} - -// Returns the name of a referenced register. -static StringRef getUnwindRegisterName(uint8_t Reg) { - switch(Reg) { - default: llvm_unreachable("Invalid register"); - case 0: return "RAX"; - case 1: return "RCX"; - case 2: return "RDX"; - case 3: return "RBX"; - case 4: return "RSP"; - case 5: return "RBP"; - case 6: return "RSI"; - case 7: return "RDI"; - case 8: return "R8"; - case 9: return "R9"; - case 10: return "R10"; - case 11: return "R11"; - case 12: return "R12"; - case 13: return "R13"; - case 14: return "R14"; - case 15: return "R15"; - } -} - -// Calculates the number of array slots required for the unwind code. -static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { - switch (UnwindCode.getUnwindOp()) { - default: llvm_unreachable("Invalid unwind code"); - case UOP_PushNonVol: - case UOP_AllocSmall: - case UOP_SetFPReg: - case UOP_PushMachFrame: - return 1; - case UOP_SaveNonVol: - case UOP_SaveXMM128: - return 2; - case UOP_SaveNonVolBig: - case UOP_SaveXMM128Big: - return 3; - case UOP_AllocLarge: - return (UnwindCode.getOpInfo() == 0) ? 2 : 3; - } -} - -// Given a symbol sym this functions returns the address and section of it. -static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, - const SymbolRef &Sym, - const coff_section *&ResolvedSection, - uint64_t &ResolvedAddr) { - if (error_code EC = Sym.getAddress(ResolvedAddr)) - return EC; - - section_iterator iter(Obj->begin_sections()); - if (error_code EC = Sym.getSection(iter)) - return EC; - - ResolvedSection = Obj->getCOFFSection(iter); - return object_error::success; -} - -// Given a vector of relocations for a section and an offset into this section -// the function returns the symbol used for the relocation at the offset. -static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, - uint64_t Offset, SymbolRef &Sym) { - for (std::vector<RelocationRef>::const_iterator RelI = Rels.begin(), - RelE = Rels.end(); - RelI != RelE; ++RelI) { - uint64_t Ofs; - if (error_code EC = RelI->getOffset(Ofs)) +// Given a a section and an offset into this section the function returns the +// symbol used for the relocation at the offset. +std::error_code COFFDumper::resolveSymbol(const coff_section *Section, + uint64_t Offset, SymbolRef &Sym) { + const auto &Relocations = RelocMap[Section]; + for (const auto &Relocation : Relocations) { + uint64_t RelocationOffset; + if (std::error_code EC = Relocation.getOffset(RelocationOffset)) return EC; - if (Ofs == Offset) { - Sym = *RelI->getSymbol(); + if (RelocationOffset == Offset) { + Sym = *Relocation.getSymbol(); return readobj_error::success; } } - return readobj_error::unknown_symbol; } -// Given a vector of relocations for a section and an offset into this section -// the function returns the name of the symbol used for the relocation at the -// offset. -static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, - uint64_t Offset, StringRef &Name) { - SymbolRef Sym; - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; - if (error_code EC = Sym.getName(Name)) return EC; +// Given a section and an offset into this section the function returns the name +// of the symbol used for the relocation at the offset. +std::error_code COFFDumper::resolveSymbolName(const coff_section *Section, + uint64_t Offset, + StringRef &Name) { + SymbolRef Symbol; + if (std::error_code EC = resolveSymbol(Section, Offset, Symbol)) + return EC; + if (std::error_code EC = Symbol.getName(Name)) + return EC; return object_error::success; } @@ -227,7 +134,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,13 +186,16 @@ 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 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE), }; @@ -401,160 +311,21 @@ WeakExternalCharacteristics[] = { { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } }; -static const EnumEntry<unsigned> UnwindFlags[] = { - { "ExceptionHandler", Win64EH::UNW_ExceptionHandler }, - { "TerminateHandler", Win64EH::UNW_TerminateHandler }, - { "ChainInfo" , Win64EH::UNW_ChainInfo } -}; - -static const EnumEntry<unsigned> UnwindOpInfo[] = { - { "RAX", 0 }, - { "RCX", 1 }, - { "RDX", 2 }, - { "RBX", 3 }, - { "RSP", 4 }, - { "RBP", 5 }, - { "RSI", 6 }, - { "RDI", 7 }, - { "R8", 8 }, - { "R9", 9 }, - { "R10", 10 }, - { "R11", 11 }, - { "R12", 12 }, - { "R13", 13 }, - { "R14", 14 }, - { "R15", 15 } -}; - -// 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) { - return static_cast<const char*>(UI.getLanguageSpecificData()) - - reinterpret_cast<const char*>(&UI); -} - -static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) { - if (UCs.size() < 3) - return 0; - - return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); -} - -template<typename T> -static error_code getSymbolAuxData(const COFFObjectFile *Obj, - const coff_symbol *Symbol, const T* &Aux) { +template <typename T> +static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, + const coff_symbol *Symbol, + const T *&Aux) { ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); Aux = reinterpret_cast<const T*>(AuxData.data()); return readobj_error::success; } -static std::string formatSymbol(const std::vector<RelocationRef> &Rels, - uint64_t Offset, uint32_t Disp) { - std::string Buffer; - raw_string_ostream Str(Buffer); - - StringRef Sym; - if (resolveSymbolName(Rels, Offset, Sym)) { - Str << format(" (0x%" PRIX64 ")", Offset); - return Str.str(); - } - - Str << Sym; - if (Disp > 0) { - Str << format(" +0x%X (0x%" PRIX64 ")", Disp, Offset); - } else { - Str << format(" (0x%" PRIX64 ")", Offset); - } - - return Str.str(); -} - -// Given a vector of relocations for a section and an offset into this section -// the function resolves the symbol used for the relocation at the offset and -// returns the section content and the address inside the content pointed to -// by the symbol. -error_code COFFDumper::getSectionContents( - const std::vector<RelocationRef> &Rels, uint64_t Offset, - ArrayRef<uint8_t> &Contents, uint64_t &Addr) { - - SymbolRef Sym; - const coff_section *Section; - - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) - return EC; - if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) - return EC; - if (error_code EC = Obj->getSectionContents(Section, Contents)) - return EC; - - return object_error::success; -} - -error_code COFFDumper::getSection( - const std::vector<RelocationRef> &Rels, uint64_t Offset, - const coff_section **SectionPtr, uint64_t *AddrPtr) { - - SymbolRef Sym; - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) - return EC; - - const coff_section *Section; - uint64_t Addr; - if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) - return EC; - - if (SectionPtr) - *SectionPtr = Section; - if (AddrPtr) - *AddrPtr = Addr; - - return object_error::success; -} - 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; + for (const SectionRef &S : Obj->sections()) { + const coff_section *Section = Obj->getCOFFSection(S); - 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; - - 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(), @@ -572,7 +343,7 @@ void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName void COFFDumper::printFileHeaders() { // Print COFF header - const coff_file_header *COFFHeader = 0; + const coff_file_header *COFFHeader = nullptr; if (error(Obj->getCOFFHeader(COFFHeader))) return; @@ -595,76 +366,243 @@ void COFFDumper::printFileHeaders() { // Print PE header. This header does not exist if this is an object file and // not an executable. - const pe32_header *PEHeader = 0; + const pe32_header *PEHeader = nullptr; if (error(Obj->getPE32Header(PEHeader))) return; + if (PEHeader) + printPEHeader<pe32_header>(PEHeader); - 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]); + const pe32plus_header *PEPlusHeader = nullptr; + 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(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() != nullptr || + 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() != nullptr) { + // 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 (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 +621,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 +652,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 +677,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,26 +713,18 @@ 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)) { + if (std::error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { W.startLine() << "Invalid section number: " << EC.message() << "\n"; W.flush(); return; @@ -829,10 +749,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,22 +757,18 @@ 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; const coff_symbol *Linked; StringRef LinkedName; - error_code EC; + std::error_code EC; if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) || (EC = Obj->getSymbolName(Linked, LinkedName))) { LinkedName = ""; @@ -866,19 +779,20 @@ 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) { - const coff_aux_file_record *Aux; + } else if (Symbol->isFileRecord()) { + const coff_aux_file *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; 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)) { + StringRef Name(Aux->FileName, + Symbol->NumberOfAuxSymbols * COFF::SymbolSize); + W.printString("FileName", Name.rtrim(StringRef("\0", 1))); + break; + } else if (Symbol->isSectionDefinition()) { const coff_aux_section_definition *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -896,7 +810,7 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { const coff_section *Assoc; StringRef AssocName; - error_code EC; + std::error_code EC; if ((EC = Obj->getSection(Aux->Number, Assoc)) || (EC = Obj->getSectionName(Assoc, AssocName))) { AssocName = ""; @@ -905,16 +819,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; + std::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"; @@ -928,187 +851,28 @@ void COFFDumper::printUnwindInfo() { return; ListScope D(W, "UnwindInformation"); - if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { - W.startLine() << "Unsupported image machine type " - "(currently only AMD64 is supported).\n"; - return; - } - - printX64UnwindInfo(); -} - -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; - - StringRef Name; - if (error(SecI->getName(Name))) - continue; - if (Name != ".pdata" && !Name.startswith(".pdata$")) - continue; - - const coff_section *PData = Obj->getCOFFSection(SecI); - - ArrayRef<uint8_t> Contents; - if (error(Obj->getSectionContents(PData, Contents)) || - Contents.empty()) - continue; - - ArrayRef<RuntimeFunction> RFs( - reinterpret_cast<const RuntimeFunction *>(Contents.data()), - Contents.size() / sizeof(RuntimeFunction)); - - for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { - const uint64_t OffsetInSection = std::distance(RFs.begin(), I) - * sizeof(RuntimeFunction); - - printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]); - } - } -} - -void COFFDumper::printRuntimeFunction( - const RuntimeFunction& RTF, - uint64_t OffsetInSection, - const std::vector<RelocationRef> &Rels) { - - DictScope D(W, "RuntimeFunction"); - W.printString("StartAddress", - formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress)); - W.printString("EndAddress", - formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress)); - W.printString("UnwindInfoAddress", - formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset)); - - const coff_section* XData = 0; - uint64_t UnwindInfoOffset = 0; - if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset))) - return; - - ArrayRef<uint8_t> XContents; - if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty()) - return; - - UnwindInfoOffset += RTF.UnwindInfoOffset; - if (UnwindInfoOffset > XContents.size()) - return; - - const Win64EH::UnwindInfo *UI = - reinterpret_cast<const Win64EH::UnwindInfo *>( - XContents.data() + UnwindInfoOffset); - - printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]); -} - -void COFFDumper::printUnwindInfo( - const Win64EH::UnwindInfo& UI, - uint64_t OffsetInSection, - const std::vector<RelocationRef> &Rels) { - DictScope D(W, "UnwindInfo"); - W.printNumber("Version", UI.getVersion()); - W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); - W.printNumber("PrologSize", UI.PrologSize); - if (UI.getFrameRegister() != 0) { - W.printEnum("FrameRegister", UI.getFrameRegister(), - makeArrayRef(UnwindOpInfo)); - W.printHex("FrameOffset", UI.getFrameOffset()); - } else { - W.printString("FrameRegister", StringRef("-")); - W.printString("FrameOffset", StringRef("-")); - } - - W.printNumber("UnwindCodeCount", UI.NumCodes); - { - ListScope CodesD(W, "UnwindCodes"); - ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes); - for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) { - unsigned UsedSlots = getNumUsedSlots(*I); - if (UsedSlots > UCs.size()) { - errs() << "Corrupt unwind data"; - return; - } - printUnwindCode(UI, ArrayRef<UnwindCode>(I, E)); - I += UsedSlots - 1; - } - } - - uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI); - if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { - W.printString("Handler", formatSymbol(Rels, LSDAOffset, - UI.getLanguageSpecificHandlerOffset())); - } else if (UI.getFlags() & UNW_ChainInfo) { - const RuntimeFunction *Chained = UI.getChainedFunctionEntry(); - if (Chained) { - DictScope D(W, "Chained"); - W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0, - Chained->StartAddress)); - W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4, - Chained->EndAddress)); - W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8, - Chained->UnwindInfoOffset)); - } - } -} - -// Prints one unwind code. Because an unwind code can occupy up to 3 slots in -// the unwind codes array, this function requires that the correct number of -// slots is provided. -void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI, - ArrayRef<UnwindCode> UCs) { - assert(UCs.size() >= getNumUsedSlots(UCs[0])); - - W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset)) - << getUnwindCodeTypeName(UCs[0].getUnwindOp()); - - uint32_t AllocSize = 0; - - switch (UCs[0].getUnwindOp()) { - case UOP_PushNonVol: - outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()); + switch (Header->Machine) { + case COFF::IMAGE_FILE_MACHINE_AMD64: { + Win64EH::Dumper Dumper(W); + Win64EH::Dumper::SymbolResolver + Resolver = [](const object::coff_section *Section, uint64_t Offset, + SymbolRef &Symbol, void *user_data) -> std::error_code { + COFFDumper *Dumper = reinterpret_cast<COFFDumper *>(user_data); + return Dumper->resolveSymbol(Section, Offset, Symbol); + }; + Win64EH::Dumper::Context Ctx(*Obj, Resolver, this); + Dumper.printData(Ctx); break; - - case UOP_AllocLarge: - if (UCs[0].getOpInfo() == 0) { - AllocSize = UCs[1].FrameOffset * 8; - } else { - AllocSize = getLargeSlotValue(UCs); - } - outs() << " size=" << AllocSize; - break; - case UOP_AllocSmall: - outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8); - break; - case UOP_SetFPReg: - if (UI.getFrameRegister() == 0) { - outs() << " reg=<invalid>"; - } else { - outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) - << format(", offset=0x%X", UI.getFrameOffset() * 16); - } - break; - case UOP_SaveNonVol: - outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) - << format(", offset=0x%X", UCs[1].FrameOffset * 8); - break; - case UOP_SaveNonVolBig: - outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) - << format(", offset=0x%X", getLargeSlotValue(UCs)); - break; - case UOP_SaveXMM128: - outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) - << format(", offset=0x%X", UCs[1].FrameOffset * 16); - break; - case UOP_SaveXMM128Big: - outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) - << format(", offset=0x%X", getLargeSlotValue(UCs)); + } + case COFF::IMAGE_FILE_MACHINE_ARMNT: { + ARM::WinEH::Decoder Decoder(W); + Decoder.dumpProcedureData(*Obj); break; - case UOP_PushMachFrame: - outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes"); + } + default: + W.printEnum("unsupported Image Machine", Header->Machine, + makeArrayRef(ImageFileMachineType)); break; } - - outs() << "\n"; } + diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp index 07a9083f3c8e..1791f5a32471 100644 --- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -13,12 +13,16 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" +#include "ARMAttributeParser.h" +#include "ARMEHABIPrinter.h" #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" - +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" @@ -39,16 +43,19 @@ 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; + void printMipsPLTGOT() override; private: typedef ELFFile<ELFT> ELFO; @@ -65,7 +72,7 @@ private: template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { if (!Val) { - error(Val); + error(Val.getError()); return Default; } @@ -76,16 +83,16 @@ template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { namespace llvm { template <class ELFT> -static error_code createELFDumper(const ELFFile<ELFT> *Obj, - StreamWriter &Writer, - OwningPtr<ObjDumper> &Result) { +static std::error_code createELFDumper(const ELFFile<ELFT> *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { Result.reset(new ELFDumper<ELFT>(Obj, Writer)); return readobj_error::success; } -error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { +std::error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) return createELFDumper(ELFObj->getELFFile(), Writer, Result); @@ -107,6 +114,62 @@ error_code createELFDumper(const object::ObjectFile *Obj, } // namespace llvm +template <typename ELFO> +static std::string getFullSymbolName(const ELFO &Obj, + typename ELFO::Elf_Sym_Iter Symbol) { + StringRef SymbolName = errorOrDefault(Obj.getSymbolName(Symbol)); + if (!Symbol.isDynamic()) + return SymbolName; + + std::string FullSymbolName(SymbolName); + + bool IsDefault; + ErrorOr<StringRef> Version = + Obj.getSymbolVersion(nullptr, &*Symbol, IsDefault); + if (Version) { + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += *Version; + } else + error(Version.getError()); + return FullSymbolName; +} + +template <typename ELFO> +static void +getSectionNameIndex(const ELFO &Obj, typename ELFO::Elf_Sym_Iter Symbol, + StringRef &SectionName, unsigned &SectionIndex) { + SectionIndex = Symbol->st_shndx; + if (SectionIndex == SHN_UNDEF) { + SectionName = "Undefined"; + } else if (SectionIndex >= SHN_LOPROC && SectionIndex <= SHN_HIPROC) { + SectionName = "Processor Specific"; + } else if (SectionIndex >= SHN_LOOS && SectionIndex <= SHN_HIOS) { + SectionName = "Operating System Specific"; + } else if (SectionIndex > SHN_HIOS && SectionIndex < SHN_ABS) { + SectionName = "Reserved"; + } else if (SectionIndex == SHN_ABS) { + SectionName = "Absolute"; + } else if (SectionIndex == SHN_COMMON) { + SectionName = "Common"; + } else { + if (SectionIndex == SHN_XINDEX) + SectionIndex = Obj.getSymbolTableIndex(&*Symbol); + assert(SectionIndex != SHN_XINDEX && + "getSymbolTableIndex should handle this"); + const typename ELFO::Elf_Shdr *Sec = Obj.getSection(SectionIndex); + SectionName = errorOrDefault(Obj.getSectionName(Sec)); + } +} + +template <class ELFT> +static const typename ELFFile<ELFT>::Elf_Shdr * +findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) { + for (const auto &Shdr : Obj->sections()) + if (Shdr.sh_addr == Addr) + return &Shdr; + return nullptr; +} + static const EnumEntry<unsigned> ElfClass[] = { { "None", ELF::ELFCLASSNONE }, { "32-bit", ELF::ELFCLASS32 }, @@ -344,6 +407,7 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); } } @@ -433,6 +497,29 @@ static const EnumEntry<unsigned> ElfSegmentFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, PF_R) }; +static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_NOREORDER), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_PIC), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_CPIC), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_32BITMODE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_NAN2008), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_O32), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MICROMIPS), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_ASE_M16), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_1), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_3), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_4), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_5), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32R2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32R6), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) +}; + template<class ELFT> void ELFDumper<ELFT>::printFileHeaders() { const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); @@ -460,7 +547,11 @@ void ELFDumper<ELFT>::printFileHeaders() { W.printHex ("Entry", Header->e_entry); W.printHex ("ProgramHeaderOffset", Header->e_phoff); W.printHex ("SectionHeaderOffset", Header->e_shoff); - W.printFlags ("Flags", Header->e_flags); + if (Header->e_machine == EM_MIPS) + W.printFlags("Flags", Header->e_flags, makeArrayRef(ElfHeaderMipsFlags), + unsigned(ELF::EF_MIPS_ARCH)); + else + W.printFlags("Flags", Header->e_flags); W.printNumber("HeaderSize", Header->e_ehsize); W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize); W.printNumber("ProgramHeaderCount", Header->e_phnum); @@ -620,19 +711,10 @@ 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)) : ""; - std::string FullSymbolName(SymbolName); - if (Symbol.isDynamic()) { - bool IsDefault; - ErrorOr<StringRef> Version = Obj->getSymbolVersion(0, &*Symbol, IsDefault); - if (Version) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += *Version; - } else - error(Version); - } + unsigned SectionIndex = 0; + StringRef SectionName; + getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex); + std::string FullSymbolName = getFullSymbolName(*Obj, Symbol); DictScope D(W, "Symbol"); W.printNumber("Name", FullSymbolName, Symbol->st_name); @@ -642,7 +724,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) \ @@ -686,6 +768,8 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(VERNEED); LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); LLVM_READOBJ_TYPE_CASE(VERSYM); + LLVM_READOBJ_TYPE_CASE(RELCOUNT); + LLVM_READOBJ_TYPE_CASE(GNU_HASH); LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); @@ -693,12 +777,65 @@ 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"; } } #undef LLVM_READOBJ_TYPE_CASE +#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ + { #enum, prefix##_##enum } + +static const EnumEntry<unsigned> ElfDynamicDTFlags[] = { + LLVM_READOBJ_DT_FLAG_ENT(DF, ORIGIN), + LLVM_READOBJ_DT_FLAG_ENT(DF, SYMBOLIC), + LLVM_READOBJ_DT_FLAG_ENT(DF, TEXTREL), + LLVM_READOBJ_DT_FLAG_ENT(DF, BIND_NOW), + LLVM_READOBJ_DT_FLAG_ENT(DF, STATIC_TLS) +}; + +static const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = { + LLVM_READOBJ_DT_FLAG_ENT(RHF, NONE), + LLVM_READOBJ_DT_FLAG_ENT(RHF, QUICKSTART), + LLVM_READOBJ_DT_FLAG_ENT(RHF, NOTPOT), + LLVM_READOBJ_DT_FLAG_ENT(RHS, NO_LIBRARY_REPLACEMENT), + LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_MOVE), + LLVM_READOBJ_DT_FLAG_ENT(RHF, SGI_ONLY), + LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_INIT), + LLVM_READOBJ_DT_FLAG_ENT(RHF, DELTA_C_PLUS_PLUS), + LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_START_INIT), + LLVM_READOBJ_DT_FLAG_ENT(RHF, PIXIE), + LLVM_READOBJ_DT_FLAG_ENT(RHF, DEFAULT_DELAY_LOAD), + LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTART), + LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTARTED), + LLVM_READOBJ_DT_FLAG_ENT(RHF, CORD), + LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_UNRES_UNDEF), + LLVM_READOBJ_DT_FLAG_ENT(RHF, RLD_ORDER_SAFE) +}; + +#undef LLVM_READOBJ_DT_FLAG_ENT + +template <typename T, typename TFlag> +void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) { + typedef EnumEntry<TFlag> FlagEntry; + typedef SmallVector<FlagEntry, 10> FlagVector; + FlagVector SetFlags; + + for (const auto &Flag : Flags) { + if (Flag.Value == 0) + continue; + + if ((Value & Flag.Value) == Flag.Value) + SetFlags.push_back(Flag); + } + + for (const auto &Flag : SetFlags) { + OS << Flag.Name << " "; + } +} + template <class ELFT> static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, bool Is64, raw_ostream &OS) { @@ -727,12 +864,15 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_DEBUG: case DT_VERNEED: case DT_VERSYM: + case DT_GNU_HASH: case DT_NULL: - 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_RELCOUNT: case DT_VERNEEDNUM: case DT_MIPS_RLD_VERSION: case DT_MIPS_LOCAL_GOTNO: @@ -762,6 +902,12 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_RUNPATH: OS << O->getDynamicString(Value); break; + case DT_MIPS_FLAGS: + printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); + break; + case DT_FLAGS: + printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS); + break; } } @@ -770,15 +916,26 @@ 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; - EDI Start = Obj->begin_dynamic_table(), End = Obj->end_dynamic_table(true); + auto DynTable = Obj->dynamic_table(true); - if (Start == End) + ptrdiff_t Total = std::distance(DynTable.begin(), DynTable.end()); + if (Total == 0) return; - ptrdiff_t Total = std::distance(Start, End); raw_ostream &OS = W.getOStream(); W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; @@ -787,12 +944,12 @@ void ELFDumper<ELFT>::printDynamicTable() { W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" << " " << "Name/Value\n"; - for (; Start != End; ++Start) { + for (const auto &Entry : DynTable) { W.startLine() << " " - << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag()) - << " " << format("%-21s", getTypeString(Start->getTag())); - printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS); + << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag()) + << " " << format("%-21s", getTypeString(Entry.getTag())); + printValue(Obj, Entry.getTag(), Entry.getVal(), Is64, OS); OS << "\n"; } @@ -806,11 +963,9 @@ void ELFDumper<ELFT>::printNeededLibraries() { typedef std::vector<StringRef> LibsTy; LibsTy Libs; - for (typename ELFO::Elf_Dyn_Iter DynI = Obj->begin_dynamic_table(), - DynE = Obj->end_dynamic_table(); - DynI != DynE; ++DynI) - if (DynI->d_tag == ELF::DT_NEEDED) - Libs.push_back(Obj->getDynamicString(DynI->d_un.d_val)); + for (const auto &Entry : Obj->dynamic_table()) + if (Entry.d_tag == ELF::DT_NEEDED) + Libs.push_back(Obj->getDynamicString(Entry.d_un.d_val)); std::stable_sort(Libs.begin(), Libs.end()); @@ -839,3 +994,248 @@ 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); + } +} +} + +namespace { +template <class ELFT> class MipsGOTParser { +public: + typedef object::ELFFile<ELFT> ObjectFile; + typedef typename ObjectFile::Elf_Shdr Elf_Shdr; + + MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) : Obj(Obj), W(W) {} + + void parseGOT(const Elf_Shdr &GOTShdr); + +private: + typedef typename ObjectFile::Elf_Sym_Iter Elf_Sym_Iter; + typedef typename ObjectFile::Elf_Addr GOTEntry; + typedef typename ObjectFile::template ELFEntityIterator<const GOTEntry> + GOTIter; + + const ObjectFile *Obj; + StreamWriter &W; + + std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; + GOTIter makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); + + bool getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym); + void printGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It); + void printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It, + Elf_Sym_Iter Sym); +}; +} + +template <class ELFT> +void MipsGOTParser<ELFT>::parseGOT(const Elf_Shdr &GOTShdr) { + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed GOT description. + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + + ErrorOr<ArrayRef<uint8_t>> GOT = Obj->getSectionContents(&GOTShdr); + if (!GOT) { + W.startLine() << "The .got section is empty.\n"; + return; + } + + uint64_t DtLocalGotNum; + uint64_t DtGotSym; + if (!getGOTTags(DtLocalGotNum, DtGotSym)) + return; + + if (DtLocalGotNum > getGOTTotal(*GOT)) { + W.startLine() << "MIPS_LOCAL_GOTNO exceeds a number of GOT entries.\n"; + return; + } + + Elf_Sym_Iter DynSymBegin = Obj->begin_dynamic_symbols(); + Elf_Sym_Iter DynSymEnd = Obj->end_dynamic_symbols(); + std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); + + if (DtGotSym > DynSymTotal) { + W.startLine() << "MIPS_GOTSYM exceeds a number of dynamic symbols.\n"; + return; + } + + std::size_t GlobalGotNum = DynSymTotal - DtGotSym; + + if (DtLocalGotNum + GlobalGotNum > getGOTTotal(*GOT)) { + W.startLine() << "Number of global GOT entries exceeds the size of GOT.\n"; + return; + } + + GOTIter GotBegin = makeGOTIter(*GOT, 0); + GOTIter GotLocalEnd = makeGOTIter(*GOT, DtLocalGotNum); + GOTIter It = GotBegin; + + DictScope GS(W, "Primary GOT"); + + W.printHex("Canonical gp value", GOTShdr.sh_addr + 0x7ff0); + { + ListScope RS(W, "Reserved entries"); + + { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr.sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Lazy resolver")); + } + + if (It != GotLocalEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr.sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Module pointer (GNU extension)")); + } + } + { + ListScope LS(W, "Local entries"); + for (; It != GotLocalEnd; ++It) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr.sh_addr, GotBegin, It); + } + } + { + ListScope GS(W, "Global entries"); + + GOTIter GotGlobalEnd = makeGOTIter(*GOT, DtLocalGotNum + GlobalGotNum); + Elf_Sym_Iter GotDynSym = DynSymBegin + DtGotSym; + for (; It != GotGlobalEnd; ++It) { + DictScope D(W, "Entry"); + printGlobalGotEntry(GOTShdr.sh_addr, GotBegin, It, GotDynSym++); + } + } + + std::size_t SpecGotNum = getGOTTotal(*GOT) - DtLocalGotNum - GlobalGotNum; + W.printNumber("Number of TLS and multi-GOT entries", uint64_t(SpecGotNum)); +} + +template <class ELFT> +std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const { + return GOT.size() / sizeof(GOTEntry); +} + +template <class ELFT> +typename MipsGOTParser<ELFT>::GOTIter +MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) { + const char *Data = reinterpret_cast<const char *>(GOT.data()); + return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry)); +} + +template <class ELFT> +bool MipsGOTParser<ELFT>::getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym) { + bool FoundLocalGotNum = false; + bool FoundGotSym = false; + for (const auto &Entry : Obj->dynamic_table()) { + switch (Entry.getTag()) { + case ELF::DT_MIPS_LOCAL_GOTNO: + LocalGotNum = Entry.getVal(); + FoundLocalGotNum = true; + break; + case ELF::DT_MIPS_GOTSYM: + GotSym = Entry.getVal(); + FoundGotSym = true; + break; + } + } + + if (!FoundLocalGotNum) { + W.startLine() << "Cannot find MIPS_LOCAL_GOTNO dynamic table tag.\n"; + return false; + } + + if (!FoundGotSym) { + W.startLine() << "Cannot find MIPS_GOTSYM dynamic table tag.\n"; + return false; + } + + return true; +} + +template <class ELFT> +void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, + GOTIter It) { + int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); + W.printHex("Address", GotAddr + Offset); + W.printNumber("Access", Offset - 0x7ff0); + W.printHex("Initial", *It); +} + +template <class ELFT> +void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, + GOTIter It, Elf_Sym_Iter Sym) { + printGotEntry(GotAddr, BeginIt, It); + + W.printHex("Value", Sym->st_value); + W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); + + unsigned SectionIndex = 0; + StringRef SectionName; + getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + W.printHex("Section", SectionName, SectionIndex); + + std::string FullSymbolName = getFullSymbolName(*Obj, Sym); + W.printNumber("Name", FullSymbolName, Sym->st_name); +} + +template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { + if (Obj->getHeader()->e_machine != EM_MIPS) { + W.startLine() << "MIPS PLT GOT is available for MIPS targets only.\n"; + return; + } + + llvm::Optional<uint64_t> DtPltGot; + for (const auto &Entry : Obj->dynamic_table()) { + if (Entry.getTag() == ELF::DT_PLTGOT) { + DtPltGot = Entry.getVal(); + break; + } + } + + if (!DtPltGot) { + W.startLine() << "Cannot find PLTGOT dynamic table tag.\n"; + return; + } + + const Elf_Shdr *GotShdr = findSectionByAddress(Obj, *DtPltGot); + if (!GotShdr) { + W.startLine() << "There is no .got section in the file.\n"; + return; + } + + MipsGOTParser<ELFT>(Obj, W).parseGOT(*GotShdr); +} diff --git a/contrib/llvm/tools/llvm-readobj/Error.cpp b/contrib/llvm/tools/llvm-readobj/Error.cpp index a6c61321c6dc..a078f5c095c7 100644 --- a/contrib/llvm/tools/llvm-readobj/Error.cpp +++ b/contrib/llvm/tools/llvm-readobj/Error.cpp @@ -17,11 +17,10 @@ using namespace llvm; namespace { -class _readobj_error_category : public _do_message { +class _readobj_error_category : public std::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 LLVM_NOEXCEPT override; + std::string message(int ev) const override; }; } // namespace @@ -29,8 +28,8 @@ const char *_readobj_error_category::name() const { return "llvm.readobj"; } -std::string _readobj_error_category::message(int ev) const { - switch (ev) { +std::string _readobj_error_category::message(int EV) const { + switch (static_cast<readobj_error>(EV)) { case readobj_error::success: return "Success"; case readobj_error::file_not_found: return "No such file."; @@ -42,20 +41,13 @@ std::string _readobj_error_category::message(int ev) const { return "Unsupported object file format."; case readobj_error::unknown_symbol: return "Unknown symbol."; - default: - llvm_unreachable("An enumerator of readobj_error does not have a message " - "defined."); } -} - -error_condition _readobj_error_category::default_error_condition(int ev) const { - if (ev == readobj_error::success) - return errc::success; - return errc::invalid_argument; + llvm_unreachable("An enumerator of readobj_error does not have a message " + "defined."); } namespace llvm { -const error_category &readobj_category() { +const std::error_category &readobj_category() { static _readobj_error_category o; return o; } diff --git a/contrib/llvm/tools/llvm-readobj/Error.h b/contrib/llvm/tools/llvm-readobj/Error.h index cf68da89c1d3..81ce4082aab9 100644 --- a/contrib/llvm/tools/llvm-readobj/Error.h +++ b/contrib/llvm/tools/llvm-readobj/Error.h @@ -14,35 +14,28 @@ #ifndef LLVM_READOBJ_ERROR_H #define LLVM_READOBJ_ERROR_H -#include "llvm/Support/system_error.h" +#include <system_error> namespace llvm { - -const error_category &readobj_category(); - -struct readobj_error { - enum _ { - success = 0, - file_not_found, - unsupported_file_format, - unrecognized_file_format, - unsupported_obj_file_format, - unknown_symbol - }; - _ v_; - - readobj_error(_ v) : v_(v) {} - explicit readobj_error(int v) : v_(_(v)) {} - operator int() const {return v_;} +const std::error_category &readobj_category(); + +enum class readobj_error { + success = 0, + file_not_found, + unsupported_file_format, + unrecognized_file_format, + unsupported_obj_file_format, + unknown_symbol }; -inline error_code make_error_code(readobj_error e) { - return error_code(static_cast<int>(e), readobj_category()); +inline std::error_code make_error_code(readobj_error e) { + return std::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 { }; - } // namespace llvm +namespace std { +template <> struct is_error_code_enum<llvm::readobj_error> : std::true_type {}; +} + #endif diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp index b97166b4c1bb..a5e5cf850a3b 100644 --- a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp @@ -15,8 +15,8 @@ #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" @@ -31,20 +31,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); @@ -56,9 +55,9 @@ private: namespace llvm { -error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { +std::error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); if (!MachOObj) return readobj_error::unsupported_obj_file_format; @@ -126,19 +125,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 +216,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 +235,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); } @@ -298,29 +278,21 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { 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; - + std::error_code EC; + 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,27 +302,37 @@ 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; - DataRefImpl DR = RelI->getRawDataRefImpl(); + DataRefImpl DR = Reloc.getRawDataRefImpl(); MachO::any_relocation_info RE = Obj->getRelocation(DR); bool IsScattered = Obj->isRelocationScattered(RE); + SmallString<32> SymbolNameOrOffset("0x"); + if (IsScattered) { + // Scattered relocations don't really have an associated symbol + // for some reason, even if one exists in the symtab at the correct address. + SymbolNameOrOffset += utohexstr(Obj->getScatteredRelocationValue(RE)); + } else { + symbol_iterator Symbol = Reloc.getSymbol(); + if (Symbol != Obj->symbol_end()) { + StringRef SymbolName; + if (error(Symbol->getName(SymbolName))) + return; + SymbolNameOrOffset = SymbolName; + } else + SymbolNameOrOffset += utohexstr(Obj->getPlainRelocationSymbolNum(RE)); + } if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); @@ -362,7 +344,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, else W.printNumber("Extern", Obj->getPlainRelocationExternal(RE)); W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE)); - W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + W.printString("Symbol", SymbolNameOrOffset); W.printNumber("Scattered", IsScattered); } else { raw_ostream& OS = W.startLine(); @@ -375,7 +357,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, OS << " " << Obj->getPlainRelocationExternal(RE); OS << " " << RelocName << " " << IsScattered - << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << SymbolNameOrOffset << "\n"; } } @@ -383,13 +365,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 +374,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/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp index 61f511740a23..f500a0581553 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp +++ b/contrib/llvm/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/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h index 6918e28cb93a..f80a28b25cfc 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h @@ -10,17 +10,14 @@ #ifndef LLVM_READOBJ_OBJDUMPER_H #define LLVM_READOBJ_OBJDUMPER_H -namespace llvm { +#include <memory> +#include <system_error> +namespace llvm { namespace object { class ObjectFile; } -class error_code; - -template<typename T> -class OwningPtr; - class StreamWriter; class ObjDumper { @@ -40,21 +37,27 @@ public: virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } + // Only implemented for ARM ELF at this time. + virtual void printAttributes() { } + + // Only implemented for MIPS ELF at this time. + virtual void printMipsPLTGOT() { } + protected: StreamWriter& W; }; -error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result); +std::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); +std::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); +std::error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); } // namespace llvm diff --git a/contrib/llvm/tools/llvm-readobj/StreamWriter.h b/contrib/llvm/tools/llvm-readobj/StreamWriter.h index 129f6e79336e..04b38fbe25ea 100644 --- a/contrib/llvm/tools/llvm-readobj/StreamWriter.h +++ b/contrib/llvm/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" @@ -81,9 +81,9 @@ public: ArrayRef<EnumEntry<TEnum> > EnumValues) { StringRef Name; bool Found = false; - for (size_t i = 0; i < EnumValues.size(); ++i) { - if (EnumValues[i].Value == Value) { - Name = EnumValues[i].Name; + for (const auto &EnumItem : EnumValues) { + if (EnumItem.Value == Value) { + Name = EnumItem.Name; Found = true; break; } @@ -103,25 +103,22 @@ public: typedef SmallVector<FlagEntry, 10> FlagVector; FlagVector SetFlags; - for (typename ArrayRef<FlagEntry>::const_iterator I = Flags.begin(), - E = Flags.end(); I != E; ++I) { - if (I->Value == 0) + for (const auto &Flag : Flags) { + if (Flag.Value == 0) continue; - bool IsEnum = (I->Value & EnumMask) != 0; - if ((!IsEnum && (Value & I->Value) == I->Value) || - (IsEnum && (Value & EnumMask) == I->Value)) { - SetFlags.push_back(*I); + bool IsEnum = (Flag.Value & EnumMask) != 0; + if ((!IsEnum && (Value & Flag.Value) == Flag.Value) || + (IsEnum && (Value & EnumMask) == Flag.Value)) { + SetFlags.push_back(Flag); } } std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>); startLine() << Label << " [ (" << hex(Value) << ")\n"; - for (typename FlagVector::const_iterator I = SetFlags.begin(), - E = SetFlags.end(); - I != E; ++I) { - startLine() << " " << I->Name << " (" << hex(I->Value) << ")\n"; + for (const auto &Flag : SetFlags) { + startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n"; } startLine() << "]\n"; } @@ -172,6 +169,23 @@ public: startLine() << Label << ": " << int(Value) << "\n"; } + void printBoolean(StringRef Label, bool Value) { + startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; + } + + template <typename T_> + void printList(StringRef Label, const SmallVectorImpl<T_> &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << Item; + Comma = true; + } + OS << "]\n"; + } + template<typename T> void printHex(StringRef Label, T Value) { startLine() << Label << ": " << hex(Value) << "\n"; diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp new file mode 100644 index 000000000000..f058632a8ce8 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -0,0 +1,329 @@ +//===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Win64EHDumper.h" +#include "llvm-readobj.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::Win64EH; + +static const EnumEntry<unsigned> UnwindFlags[] = { + { "ExceptionHandler", UNW_ExceptionHandler }, + { "TerminateHandler", UNW_TerminateHandler }, + { "ChainInfo" , UNW_ChainInfo } +}; + +static const EnumEntry<unsigned> UnwindOpInfo[] = { + { "RAX", 0 }, + { "RCX", 1 }, + { "RDX", 2 }, + { "RBX", 3 }, + { "RSP", 4 }, + { "RBP", 5 }, + { "RSI", 6 }, + { "RDI", 7 }, + { "R8", 8 }, + { "R9", 9 }, + { "R10", 10 }, + { "R11", 11 }, + { "R12", 12 }, + { "R13", 13 }, + { "R14", 14 }, + { "R15", 15 } +}; + +static uint64_t getOffsetOfLSDA(const UnwindInfo& UI) { + return static_cast<const char*>(UI.getLanguageSpecificData()) + - reinterpret_cast<const char*>(&UI); +} + +static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UC) { + if (UC.size() < 3) + return 0; + return UC[1].FrameOffset + (static_cast<uint32_t>(UC[2].FrameOffset) << 16); +} + +// Returns the name of the unwind code. +static StringRef getUnwindCodeTypeName(uint8_t Code) { + switch (Code) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: return "PUSH_NONVOL"; + case UOP_AllocLarge: return "ALLOC_LARGE"; + case UOP_AllocSmall: return "ALLOC_SMALL"; + case UOP_SetFPReg: return "SET_FPREG"; + case UOP_SaveNonVol: return "SAVE_NONVOL"; + case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; + case UOP_SaveXMM128: return "SAVE_XMM128"; + case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; + case UOP_PushMachFrame: return "PUSH_MACHFRAME"; + } +} + +// Returns the name of a referenced register. +static StringRef getUnwindRegisterName(uint8_t Reg) { + switch (Reg) { + default: llvm_unreachable("Invalid register"); + case 0: return "RAX"; + case 1: return "RCX"; + case 2: return "RDX"; + case 3: return "RBX"; + case 4: return "RSP"; + case 5: return "RBP"; + case 6: return "RSI"; + case 7: return "RDI"; + case 8: return "R8"; + case 9: return "R9"; + case 10: return "R10"; + case 11: return "R11"; + case 12: return "R12"; + case 13: return "R13"; + case 14: return "R14"; + case 15: return "R15"; + } +} + +// Calculates the number of array slots required for the unwind code. +static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { + switch (UnwindCode.getUnwindOp()) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: + case UOP_AllocSmall: + case UOP_SetFPReg: + case UOP_PushMachFrame: + return 1; + case UOP_SaveNonVol: + case UOP_SaveXMM128: + return 2; + case UOP_SaveNonVolBig: + case UOP_SaveXMM128Big: + return 3; + case UOP_AllocLarge: + return (UnwindCode.getOpInfo() == 0) ? 2 : 3; + } +} + +static std::string formatSymbol(const Dumper::Context &Ctx, + const coff_section *Section, uint64_t Offset, + uint32_t Displacement) { + std::string Buffer; + raw_string_ostream OS(Buffer); + + StringRef Name; + SymbolRef Symbol; + if (Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData) || + Symbol.getName(Name)) { + OS << format(" (0x%" PRIX64 ")", Offset); + return OS.str(); + } + + OS << Name; + if (Displacement > 0) + OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset); + else + OS << format(" (0x%" PRIX64 ")", Offset); + return OS.str(); +} + +static std::error_code resolveRelocation(const Dumper::Context &Ctx, + const coff_section *Section, + uint64_t Offset, + const coff_section *&ResolvedSection, + uint64_t &ResolvedAddress) { + SymbolRef Symbol; + if (std::error_code EC = + Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) + return EC; + + if (std::error_code EC = Symbol.getAddress(ResolvedAddress)) + return EC; + + section_iterator SI = Ctx.COFF.section_begin(); + if (std::error_code EC = Symbol.getSection(SI)) + return EC; + + ResolvedSection = Ctx.COFF.getCOFFSection(*SI); + return object_error::success; +} + +namespace llvm { +namespace Win64EH { +void Dumper::printRuntimeFunctionEntry(const Context &Ctx, + const coff_section *Section, + uint64_t Offset, + const RuntimeFunction &RF) { + SW.printString("StartAddress", + formatSymbol(Ctx, Section, Offset + 0, RF.StartAddress)); + SW.printString("EndAddress", + formatSymbol(Ctx, Section, Offset + 4, RF.EndAddress)); + SW.printString("UnwindInfoAddress", + formatSymbol(Ctx, Section, Offset + 8, RF.UnwindInfoOffset)); +} + +// Prints one unwind code. Because an unwind code can occupy up to 3 slots in +// the unwind codes array, this function requires that the correct number of +// slots is provided. +void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) { + assert(UC.size() >= getNumUsedSlots(UC[0])); + + SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset)) + << getUnwindCodeTypeName(UC[0].getUnwindOp()); + + switch (UC[0].getUnwindOp()) { + case UOP_PushNonVol: + OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()); + break; + + case UOP_AllocLarge: + OS << " size=" + << ((UC[0].getOpInfo() == 0) ? UC[1].FrameOffset * 8 + : getLargeSlotValue(UC)); + break; + + case UOP_AllocSmall: + OS << " size=" << (UC[0].getOpInfo() + 1) * 8; + break; + + case UOP_SetFPReg: + if (UI.getFrameRegister() == 0) + OS << " reg=<invalid>"; + else + OS << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) + << format(", offset=0x%X", UI.getFrameOffset() * 16); + break; + + case UOP_SaveNonVol: + OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) + << format(", offset=0x%X", UC[1].FrameOffset * 8); + break; + + case UOP_SaveNonVolBig: + OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UC)); + break; + + case UOP_SaveXMM128: + OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) + << format(", offset=0x%X", UC[1].FrameOffset * 16); + break; + + case UOP_SaveXMM128Big: + OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UC)); + break; + + case UOP_PushMachFrame: + OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes"); + break; + } + + OS << "\n"; +} + +void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, + off_t Offset, const UnwindInfo &UI) { + DictScope UIS(SW, "UnwindInfo"); + SW.printNumber("Version", UI.getVersion()); + SW.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); + SW.printNumber("PrologSize", UI.PrologSize); + if (UI.getFrameRegister()) { + SW.printEnum("FrameRegister", UI.getFrameRegister(), + makeArrayRef(UnwindOpInfo)); + SW.printHex("FrameOffset", UI.getFrameOffset()); + } else { + SW.printString("FrameRegister", StringRef("-")); + SW.printString("FrameOffset", StringRef("-")); + } + + SW.printNumber("UnwindCodeCount", UI.NumCodes); + { + ListScope UCS(SW, "UnwindCodes"); + ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes); + for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) { + unsigned UsedSlots = getNumUsedSlots(*UCI); + if (UsedSlots > UC.size()) { + errs() << "corrupt unwind data"; + return; + } + + printUnwindCode(UI, ArrayRef<UnwindCode>(UCI, UCE)); + UCI = UCI + UsedSlots - 1; + } + } + + uint64_t LSDAOffset = Offset + getOffsetOfLSDA(UI); + if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { + SW.printString("Handler", + formatSymbol(Ctx, Section, LSDAOffset, + UI.getLanguageSpecificHandlerOffset())); + } else if (UI.getFlags() & UNW_ChainInfo) { + if (const RuntimeFunction *Chained = UI.getChainedFunctionEntry()) { + DictScope CS(SW, "Chained"); + printRuntimeFunctionEntry(Ctx, Section, LSDAOffset, *Chained); + } + } +} + +void Dumper::printRuntimeFunction(const Context &Ctx, + const coff_section *Section, + uint64_t SectionOffset, + const RuntimeFunction &RF) { + DictScope RFS(SW, "RuntimeFunction"); + printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF); + + const coff_section *XData; + uint64_t Offset; + if (error(resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset))) + return; + + ArrayRef<uint8_t> Contents; + if (error(Ctx.COFF.getSectionContents(XData, Contents)) || Contents.empty()) + return; + + Offset = Offset + RF.UnwindInfoOffset; + if (Offset > Contents.size()) + return; + + const auto UI = reinterpret_cast<const UnwindInfo*>(Contents.data() + Offset); + printUnwindInfo(Ctx, XData, Offset, *UI); +} + +void Dumper::printData(const Context &Ctx) { + for (const auto &Section : Ctx.COFF.sections()) { + StringRef Name; + if (error(Section.getName(Name))) + continue; + + if (Name != ".pdata" && !Name.startswith(".pdata$")) + continue; + + const coff_section *PData = Ctx.COFF.getCOFFSection(Section); + ArrayRef<uint8_t> Contents; + if (error(Ctx.COFF.getSectionContents(PData, Contents)) || Contents.empty()) + continue; + + const RuntimeFunction *Entries = + reinterpret_cast<const RuntimeFunction *>(Contents.data()); + const size_t Count = Contents.size() / sizeof(RuntimeFunction); + ArrayRef<RuntimeFunction> RuntimeFunctions(Entries, Count); + + size_t Index = 0; + for (const auto &RF : RuntimeFunctions) { + printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section), + Index * sizeof(RuntimeFunction), RF); + ++Index; + } + } +} +} +} + diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h new file mode 100644 index 000000000000..9ce4d39a6912 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h @@ -0,0 +1,63 @@ +//===- Win64EHDumper.h - Win64 EH Printing ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_READOBJ_WIN64EHPRINTER_H +#define LLVM_TOOLS_READOBJ_WIN64EHPRINTER_H + +#include "StreamWriter.h" +#include "llvm/Support/Win64EH.h" + +namespace llvm { +namespace object { +class COFFObjectFile; +class SymbolRef; +struct coff_section; +} + +namespace Win64EH { +class Dumper { + StreamWriter &SW; + raw_ostream &OS; + +public: + typedef std::error_code (*SymbolResolver)(const object::coff_section *, + uint64_t, object::SymbolRef &, + void *); + + struct Context { + const object::COFFObjectFile &COFF; + SymbolResolver ResolveSymbol; + void *UserData; + + Context(const object::COFFObjectFile &COFF, SymbolResolver Resolver, + void *UserData) + : COFF(COFF), ResolveSymbol(Resolver), UserData(UserData) {} + }; + +private: + void printRuntimeFunctionEntry(const Context &Ctx, + const object::coff_section *Section, + uint64_t SectionOffset, + const RuntimeFunction &RF); + void printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC); + void printUnwindInfo(const Context &Ctx, const object::coff_section *Section, + off_t Offset, const UnwindInfo &UI); + void printRuntimeFunction(const Context &Ctx, + const object::coff_section *Section, + uint64_t SectionOffset, const RuntimeFunction &RF); + +public: + Dumper(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + + void printData(const Context &Ctx); +}; +} +} + +#endif diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp index f84a72f46140..8d2a997a2312 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm/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" @@ -37,9 +35,8 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/Support/system_error.h" - #include <string> +#include <system_error> using namespace llvm; @@ -128,13 +125,28 @@ 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)); + + // -mips-plt-got + cl::opt<bool> + MipsPLTGOT("mips-plt-got", + cl::desc("Display the MIPS GOT and PLT GOT sections")); } // namespace opts static int ReturnValue = EXIT_SUCCESS; namespace llvm { -bool error(error_code EC) { +bool error(std::error_code EC) { if (!EC) return false; @@ -153,8 +165,7 @@ bool relocAddressLess(RelocationRef a, RelocationRef b) { } // namespace llvm - -static void reportError(StringRef Input, error_code EC) { +static void reportError(StringRef Input, std::error_code EC) { if (Input == "-") Input = "<stdin>"; @@ -171,10 +182,21 @@ static void reportError(StringRef Input, StringRef Message) { ReturnValue = EXIT_FAILURE; } +static bool isMipsArch(unsigned Arch) { + switch (Arch) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return true; + default: + return false; + } +} + /// @brief Creates an format-specific object file dumper. -static error_code createDumper(const ObjectFile *Obj, - StreamWriter &Writer, - OwningPtr<ObjDumper> &Result) { +static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { if (!Obj) return readobj_error::unsupported_file_format; @@ -192,8 +214,8 @@ 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; - if (error_code EC = createDumper(Obj, Writer, Dumper)) { + std::unique_ptr<ObjDumper> Dumper; + if (std::error_code EC = createDumper(Obj, Writer, Dumper)) { reportError(Obj->getFileName(), EC); return; } @@ -226,23 +248,29 @@ 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(); + if (isMipsArch(Obj->getArch()) && Obj->isELF()) + if (opts::MipsPLTGOT) + Dumper->printMipsPLTGOT(); } /// @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; - if (error_code EC = ArcI->getAsBinary(child)) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = ArcI->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { // Ignore non-object files. if (EC != object_error::invalid_file_type) reportError(Arc->getFileName(), EC.message()); continue; } - if (ObjectFile *Obj = dyn_cast<ObjectFile>(child.get())) + if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) dumpObject(Obj); else reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); @@ -259,11 +287,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 (std::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/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h index 3f756106c978..04139480a6d8 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h @@ -18,10 +18,8 @@ namespace llvm { class RelocationRef; } - class error_code; - // Various helper functions. - bool error(error_code ec); + bool error(std::error_code ec); bool relocAddressLess(object::RelocationRef A, object::RelocationRef B); } // namespace llvm @@ -38,6 +36,9 @@ 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; + extern llvm::cl::opt<bool> MipsPLTGOT; } // namespace opts #define LLVM_READOBJ_ENUM_ENT(ns, enum) \ |