aboutsummaryrefslogtreecommitdiffstats
path: root/tools/llvm-readobj
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-readobj')
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.cpp744
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.h119
-rw-r--r--tools/llvm-readobj/Android.mk3
-rw-r--r--tools/llvm-readobj/CMakeLists.txt1
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp65
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp336
-rw-r--r--tools/llvm-readobj/Error.cpp22
-rw-r--r--tools/llvm-readobj/Error.h39
-rw-r--r--tools/llvm-readobj/MachODumper.cpp32
-rw-r--r--tools/llvm-readobj/ObjDumper.h23
-rw-r--r--tools/llvm-readobj/StreamWriter.h4
-rw-r--r--tools/llvm-readobj/Win64EHDumper.cpp17
-rw-r--r--tools/llvm-readobj/Win64EHDumper.h5
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp41
-rw-r--r--tools/llvm-readobj/llvm-readobj.h5
15 files changed, 1294 insertions, 162 deletions
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp
new file mode 100644
index 0000000..b486e4a
--- /dev/null
+++ b/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/tools/llvm-readobj/ARMWinEHPrinter.h b/tools/llvm-readobj/ARMWinEHPrinter.h
new file mode 100644
index 0000000..740c8b5
--- /dev/null
+++ b/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/tools/llvm-readobj/Android.mk b/tools/llvm-readobj/Android.mk
index 10c99db..219e6a9 100644
--- a/tools/llvm-readobj/Android.mk
+++ b/tools/llvm-readobj/Android.mk
@@ -9,6 +9,7 @@ LLVM_ROOT_PATH := $(LOCAL_PATH)/../..
llvm_readobj_SRC_FILES := \
ARMAttributeParser.cpp \
+ ARMWinEHPrinter.cpp \
COFFDumper.cpp \
ELFDumper.cpp \
Error.cpp \
@@ -25,6 +26,8 @@ llvm_readobj_STATIC_LIBRARIES := \
libLLVMX86Info \
libLLVMObject \
libLLVMBitReader \
+ libLLVMMC \
+ libLLVMMCParser \
libLLVMCore \
libLLVMSupport \
diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt
index b057dcd..30f336f 100644
--- a/tools/llvm-readobj/CMakeLists.txt
+++ b/tools/llvm-readobj/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_tool(llvm-readobj
ARMAttributeParser.cpp
+ ARMWinEHPrinter.cpp
COFFDumper.cpp
ELFDumper.cpp
Error.cpp
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index 91f2a57..7842cd4 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm-readobj.h"
+#include "ARMWinEHPrinter.h"
#include "Error.h"
#include "ObjDumper.h"
#include "StreamWriter.h"
@@ -29,9 +30,9 @@
#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;
@@ -68,10 +69,10 @@ private:
void cacheRelocations();
- error_code resolveSymbol(const coff_section *Section, uint64_t Offset,
- SymbolRef &Sym);
- error_code resolveSymbolName(const coff_section *Section, uint64_t Offset,
- StringRef &Name);
+ 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;
@@ -84,8 +85,9 @@ private:
namespace llvm {
-error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer,
- std::unique_ptr<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;
@@ -98,12 +100,12 @@ error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer,
// Given a a section and an offset into this section the function returns the
// symbol used for the relocation at the offset.
-error_code COFFDumper::resolveSymbol(const coff_section *Section,
- uint64_t Offset, SymbolRef &Sym) {
+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 (error_code EC = Relocation.getOffset(RelocationOffset))
+ if (std::error_code EC = Relocation.getOffset(RelocationOffset))
return EC;
if (RelocationOffset == Offset) {
@@ -116,12 +118,13 @@ error_code COFFDumper::resolveSymbol(const coff_section *Section,
// Given a section and an offset into this section the function returns the name
// of the symbol used for the relocation at the offset.
-error_code COFFDumper::resolveSymbolName(const coff_section *Section,
- uint64_t Offset, StringRef &Name) {
+std::error_code COFFDumper::resolveSymbolName(const coff_section *Section,
+ uint64_t Offset,
+ StringRef &Name) {
SymbolRef Symbol;
- if (error_code EC = resolveSymbol(Section, Offset, Symbol))
+ if (std::error_code EC = resolveSymbol(Section, Offset, Symbol))
return EC;
- if (error_code EC = Symbol.getName(Name))
+ if (std::error_code EC = Symbol.getName(Name))
return EC;
return object_error::success;
}
@@ -190,7 +193,9 @@ static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
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),
};
@@ -306,9 +311,10 @@ WeakExternalCharacteristics[] = {
{ "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }
};
-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;
@@ -718,7 +724,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
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;
@@ -762,7 +768,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
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 = "";
@@ -804,7 +810,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
&& 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 = "";
@@ -820,7 +826,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
const coff_symbol *ReferredSym;
StringRef ReferredName;
- error_code EC;
+ std::error_code EC;
if ((EC = Obj->getSymbol(Aux->SymbolTableIndex, ReferredSym)) ||
(EC = Obj->getSymbolName(ReferredSym, ReferredName))) {
ReferredName = "";
@@ -848,16 +854,21 @@ void COFFDumper::printUnwindInfo() {
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) -> error_code {
- COFFDumper *Dumper = reinterpret_cast<COFFDumper*>(user_data);
- return Dumper->resolveSymbol(Section, Offset, Symbol);
- };
+ Win64EH::Dumper::SymbolResolver
+ Resolver = [](const object::coff_section *Section, uint64_t Offset,
+ SymbolRef &Symbol, void *user_data) -> std::error_code {
+ COFFDumper *Dumper = reinterpret_cast<COFFDumper *>(user_data);
+ return Dumper->resolveSymbol(Section, Offset, Symbol);
+ };
Win64EH::Dumper::Context Ctx(*Obj, Resolver, this);
Dumper.printData(Ctx);
break;
}
+ case COFF::IMAGE_FILE_MACHINE_ARMNT: {
+ ARM::WinEH::Decoder Decoder(W);
+ Decoder.dumpProcedureData(*Obj);
+ break;
+ }
default:
W.printEnum("unsupported Image Machine", Header->Machine,
makeArrayRef(ImageFileMachineType));
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index de4c207..5df51e2 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -18,6 +18,7 @@
#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"
@@ -54,6 +55,7 @@ public:
void printProgramHeaders() override;
void printAttributes() override;
+ void printMipsPLTGOT() override;
private:
typedef ELFFile<ELFT> ELFO;
@@ -81,15 +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,
- std::unique_ptr<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,
- std::unique_ptr<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);
@@ -111,6 +114,62 @@ error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer,
} // 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 },
@@ -651,42 +710,10 @@ void ELFDumper<ELFT>::printDynamicSymbols() {
template <class ELFT>
void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) {
- StringRef SymbolName = errorOrDefault(Obj->getSymbolName(Symbol));
-
- unsigned SectionIndex = Symbol->st_shndx;
+ unsigned SectionIndex = 0;
StringRef SectionName;
- if (SectionIndex == SHN_UNDEF) {
- SectionName = "Undefined";
- } else if (SectionIndex >= SHN_LOPROC && SectionIndex <= SHN_HIPROC) {
- SectionName = "Processor Specific";
- } else if (SectionIndex >= SHN_LOOS && SectionIndex <= SHN_HIOS) {
- SectionName = "Operating System Specific";
- } else if (SectionIndex > SHN_HIOS && SectionIndex < SHN_ABS) {
- SectionName = "Reserved";
- } else if (SectionIndex == SHN_ABS) {
- SectionName = "Absolute";
- } else if (SectionIndex == SHN_COMMON) {
- SectionName = "Common";
- } else {
- if (SectionIndex == SHN_XINDEX)
- SectionIndex = Obj->getSymbolTableIndex(&*Symbol);
- assert(SectionIndex != SHN_XINDEX &&
- "getSymbolTableIndex should handle this");
- const Elf_Shdr *Sec = Obj->getSection(SectionIndex);
- SectionName = errorOrDefault(Obj->getSectionName(Sec));
- }
-
- std::string FullSymbolName(SymbolName);
- if (Symbol.isDynamic()) {
- bool IsDefault;
- ErrorOr<StringRef> Version = Obj->getSymbolVersion(nullptr, &*Symbol,
- IsDefault);
- if (Version) {
- FullSymbolName += (IsDefault ? "@@" : "@");
- FullSymbolName += *Version;
- } else
- error(Version.getError());
- }
+ getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex);
+ std::string FullSymbolName = getFullSymbolName(*Obj, Symbol);
DictScope D(W, "Symbol");
W.printNumber("Name", FullSymbolName, Symbol->st_name);
@@ -902,13 +929,12 @@ void ELFDumper<ELFType<support::little, 2, false> >::printUnwindInfo() {
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";
@@ -917,12 +943,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";
}
@@ -936,11 +962,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());
@@ -1008,3 +1032,209 @@ void ELFDumper<ELFType<support::little, 2, false> >::printAttributes() {
}
}
+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/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp
index 83ed6a7..a078f5c 100644
--- a/tools/llvm-readobj/Error.cpp
+++ b/tools/llvm-readobj/Error.cpp
@@ -17,11 +17,10 @@
using namespace llvm;
namespace {
-class _readobj_error_category : public error_category {
+class _readobj_error_category : public std::error_category {
public:
- const char* name() const override;
+ const char* name() const LLVM_NOEXCEPT override;
std::string message(int ev) const override;
- error_condition default_error_condition(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/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h
index 5129b4e..81ce408 100644
--- a/tools/llvm-readobj/Error.h
+++ b/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> : std::true_type { };
-template <> struct is_error_code_enum<readobj_error::_> : std::true_type { };
-
} // namespace llvm
+namespace std {
+template <> struct is_error_code_enum<llvm::readobj_error> : std::true_type {};
+}
+
#endif
diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp
index 2fd5d4a..a5e5cf8 100644
--- a/tools/llvm-readobj/MachODumper.cpp
+++ b/tools/llvm-readobj/MachODumper.cpp
@@ -16,6 +16,7 @@
#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"
@@ -54,9 +55,9 @@ private:
namespace llvm {
-error_code createMachODumper(const object::ObjectFile *Obj,
- StreamWriter &Writer,
- std::unique_ptr<ObjDumper> &Result) {
+std::error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
if (!MachOObj)
return readobj_error::unsupported_obj_file_format;
@@ -277,7 +278,7 @@ void MachODumper::printSections(const MachOObjectFile *Obj) {
void MachODumper::printRelocations() {
ListScope D(W, "Relocations");
- error_code EC;
+ std::error_code EC;
for (const SectionRef &Section : Obj->sections()) {
StringRef Name;
if (error(Section.getName(Name)))
@@ -309,18 +310,29 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj,
const RelocationRef &Reloc) {
uint64_t Offset;
SmallString<32> RelocName;
- StringRef SymbolName;
if (error(Reloc.getOffset(Offset)))
return;
if (error(Reloc.getTypeName(RelocName)))
return;
- symbol_iterator Symbol = Reloc.getSymbol();
- if (Symbol != Obj->symbol_end() && error(Symbol->getName(SymbolName)))
- return;
DataRefImpl DR = 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");
@@ -332,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();
@@ -345,7 +357,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj,
OS << " " << Obj->getPlainRelocationExternal(RE);
OS << " " << RelocName
<< " " << IsScattered
- << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << " " << SymbolNameOrOffset
<< "\n";
}
}
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
index 9e0fd2f..f80a28b 100644
--- a/tools/llvm-readobj/ObjDumper.h
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -11,15 +11,13 @@
#define LLVM_READOBJ_OBJDUMPER_H
#include <memory>
+#include <system_error>
namespace llvm {
-
namespace object {
class ObjectFile;
}
-class error_code;
-
class StreamWriter;
class ObjDumper {
@@ -42,19 +40,24 @@ public:
// 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,
- std::unique_ptr<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,
- std::unique_ptr<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,
- std::unique_ptr<ObjDumper> &Result);
+std::error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
} // namespace llvm
diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h
index 9282dcc..04b38fb 100644
--- a/tools/llvm-readobj/StreamWriter.h
+++ b/tools/llvm-readobj/StreamWriter.h
@@ -169,6 +169,10 @@ 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 << ": [";
diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp
index c64d362..f058632 100644
--- a/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/tools/llvm-readobj/Win64EHDumper.cpp
@@ -134,20 +134,21 @@ static std::string formatSymbol(const Dumper::Context &Ctx,
return OS.str();
}
-static error_code resolveRelocation(const Dumper::Context &Ctx,
- const coff_section *Section,
- uint64_t Offset,
- const coff_section *&ResolvedSection,
- uint64_t &ResolvedAddress) {
+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 (error_code EC = Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData))
+ if (std::error_code EC =
+ Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData))
return EC;
- if (error_code EC = Symbol.getAddress(ResolvedAddress))
+ if (std::error_code EC = Symbol.getAddress(ResolvedAddress))
return EC;
section_iterator SI = Ctx.COFF.section_begin();
- if (error_code EC = Symbol.getSection(SI))
+ if (std::error_code EC = Symbol.getSection(SI))
return EC;
ResolvedSection = Ctx.COFF.getCOFFSection(*SI);
diff --git a/tools/llvm-readobj/Win64EHDumper.h b/tools/llvm-readobj/Win64EHDumper.h
index 2eac810..9ce4d39 100644
--- a/tools/llvm-readobj/Win64EHDumper.h
+++ b/tools/llvm-readobj/Win64EHDumper.h
@@ -26,8 +26,9 @@ class Dumper {
raw_ostream &OS;
public:
- typedef error_code (*SymbolResolver)(const object::coff_section *, uint64_t,
- object::SymbolRef &, void *);
+ typedef std::error_code (*SymbolResolver)(const object::coff_section *,
+ uint64_t, object::SymbolRef &,
+ void *);
struct Context {
const object::COFFObjectFile &COFF;
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 5be959f..8d2a997 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -35,8 +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;
@@ -135,13 +135,18 @@ namespace opts {
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;
@@ -160,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>";
@@ -178,9 +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,
- std::unique_ptr<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;
@@ -199,7 +215,7 @@ static error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer,
static void dumpObject(const ObjectFile *Obj) {
StreamWriter Writer(outs());
std::unique_ptr<ObjDumper> Dumper;
- if (error_code EC = createDumper(Obj, Writer, Dumper)) {
+ if (std::error_code EC = createDumper(Obj, Writer, Dumper)) {
reportError(Obj->getFileName(), EC);
return;
}
@@ -235,6 +251,9 @@ static void dumpObject(const ObjectFile *Obj) {
if (Obj->getArch() == llvm::Triple::arm && Obj->isELF())
if (opts::ARMAttributes)
Dumper->printAttributes();
+ if (isMipsArch(Obj->getArch()) && Obj->isELF())
+ if (opts::MipsPLTGOT)
+ Dumper->printMipsPLTGOT();
}
@@ -243,15 +262,15 @@ static void dumpArchive(const Archive *Arc) {
for (Archive::child_iterator ArcI = Arc->child_begin(),
ArcE = Arc->child_end();
ArcI != ArcE; ++ArcI) {
- std::unique_ptr<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);
@@ -269,7 +288,7 @@ static void dumpInput(StringRef File) {
// Attempt to open the binary.
ErrorOr<Binary *> BinaryOrErr = createBinary(File);
- if (error_code EC = BinaryOrErr.getError()) {
+ if (std::error_code EC = BinaryOrErr.getError()) {
reportError(File, EC);
return;
}
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
index cc5c85d..0413948 100644
--- a/tools/llvm-readobj/llvm-readobj.h
+++ b/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
@@ -40,6 +38,7 @@ namespace opts {
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) \