[llvm] r321253 - [llvm-readobj] Support 'GNU' style for MIPS GOT/PLT dumping

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 21 02:26:02 PST 2017


Author: atanasyan
Date: Thu Dec 21 02:26:02 2017
New Revision: 321253

URL: http://llvm.org/viewvc/llvm-project?rev=321253&view=rev
Log:
[llvm-readobj] Support 'GNU' style for MIPS GOT/PLT dumping

This change adds `printMipsGOT` and `printMipsPLT` methods to the
`DumpStyle` class and overrides them in the `GNUStyle` and `LLVMStyle`
descendants. To pass information about GOT/PLT layout into these
methods, the `MipsGOTParser` class has been extended to hold all
necessary data.

Modified:
    llvm/trunk/test/tools/llvm-readobj/mips-got.test
    llvm/trunk/test/tools/llvm-readobj/mips-plt.test
    llvm/trunk/tools/llvm-readobj/ELFDumper.cpp

Modified: llvm/trunk/test/tools/llvm-readobj/mips-got.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/mips-got.test?rev=321253&r1=321252&r2=321253&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/mips-got.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/mips-got.test Thu Dec 21 02:26:02 2017
@@ -1,4 +1,4 @@
-RUN: llvm-readobj -mips-plt-got %p/Inputs/relocs.obj.elf-mips | \
+RUN: not llvm-readobj -mips-plt-got %p/Inputs/relocs.obj.elf-mips 2>&1 | \
 RUN:   FileCheck %s -check-prefix GOT-OBJ
 RUN: llvm-readobj -mips-plt-got %p/Inputs/dynamic-table-exe.mips | \
 RUN:   FileCheck %s -check-prefix GOT-EXE
@@ -11,7 +11,26 @@ RUN:   FileCheck %s -check-prefix GOT-EM
 RUN: llvm-readobj -mips-plt-got %p/Inputs/got-static.exe.mips | \
 RUN:   FileCheck %s -check-prefix GOT-STATIC
 
-GOT-OBJ: Cannot find .got section
+RUN: not llvm-readobj -mips-plt-got %p/Inputs/relocs.obj.elf-mips \
+RUN:                  --elf-output-style=GNU 2>&1 | \
+RUN:   FileCheck %s -check-prefix GNU-GOT-OBJ
+RUN: llvm-readobj -mips-plt-got %p/Inputs/dynamic-table-exe.mips \
+RUN:                  --elf-output-style=GNU | \
+RUN:   FileCheck %s -check-prefix GNU-GOT-EXE
+RUN: llvm-readobj -mips-plt-got %p/Inputs/dynamic-table-so.mips \
+RUN:                  --elf-output-style=GNU | \
+RUN:   FileCheck %s -check-prefix GNU-GOT-SO
+RUN: llvm-readobj -mips-plt-got %p/Inputs/got-tls.so.elf-mips64el \
+RUN:                  --elf-output-style=GNU | \
+RUN:   FileCheck %s -check-prefix GNU-GOT-TLS
+RUN: llvm-readobj -mips-plt-got %p/Inputs/got-empty.exe.mipsel \
+RUN:                  --elf-output-style=GNU | \
+RUN:   FileCheck %s -check-prefix GNU-GOT-EMPTY
+RUN: llvm-readobj -mips-plt-got %p/Inputs/got-static.exe.mips \
+RUN:                  --elf-output-style=GNU | \
+RUN:   FileCheck %s -check-prefix GNU-GOT-STATIC
+
+GOT-OBJ: Error reading file: Cannot find .got section.
 
 GOT-EXE:      Primary GOT {
 GOT-EXE-NEXT:   Canonical gp value: 0x418880
@@ -366,3 +385,116 @@ GOT-STATIC-NEXT:       Initial: 0x400104
 GOT-STATIC-NEXT:     }
 GOT-STATIC-NEXT:   ]
 GOT-STATIC-NEXT: }
+
+GNU-GOT-OBJ: Error reading file: Cannot find .got section.
+
+GNU-GOT-EXE:      Primary GOT:
+GNU-GOT-EXE-NEXT:  Canonical gp value: 00418880
+
+GNU-GOT-EXE:       Reserved entries:
+GNU-GOT-EXE-NEXT:    Address     Access  Initial Purpose
+GNU-GOT-EXE-NEXT:   00410890 -32752(gp) 00000000 Lazy resolver
+GNU-GOT-EXE-NEXT:   00410894 -32748(gp) 80000000 Module pointer (GNU extension)
+
+GNU-GOT-EXE:       Local entries:
+GNU-GOT-EXE-NEXT:    Address     Access  Initial
+GNU-GOT-EXE-NEXT:   00410898 -32744(gp) 00400418
+GNU-GOT-EXE-NEXT:   0041089c -32740(gp) 00410840
+GNU-GOT-EXE-NEXT:   004108a0 -32736(gp) 00000000
+
+GNU-GOT-EXE:       Global entries:
+GNU-GOT-EXE-NEXT:    Address     Access  Initial Sym.Val. Type    Ndx Name
+GNU-GOT-EXE-NEXT:   004108a4 -32732(gp) 00000000 00000000 FUNC    UND __gmon_start__
+
+GNU-GOT-EXE:      PLT GOT:
+
+GNU-GOT-EXE:       Reserved entries:
+GNU-GOT-EXE-NEXT:    Address  Initial Purpose
+GNU-GOT-EXE-NEXT:   00410854 00000000 PLT lazy resolver
+GNU-GOT-EXE-NEXT:   00410894 80000000 Module pointer
+
+GNU-GOT-EXE:       Entries:
+GNU-GOT-EXE-NEXT:    Address  Initial Sym.Val. Type    Ndx Name
+GNU-GOT-EXE-NEXT:   0041085c 00400800 00000000 FUNC    UND puts
+GNU-GOT-EXE-NEXT:   00410860 00400800 00000000 FUNC    UND __libc_start_main
+
+GNU-GOT-SO:      Primary GOT:
+GNU-GOT-SO-NEXT:  Canonical gp value: 000188d0
+
+GNU-GOT-SO:       Reserved entries:
+GNU-GOT-SO-NEXT:    Address     Access  Initial Purpose
+GNU-GOT-SO-NEXT:   000108e0 -32752(gp) 00000000 Lazy resolver
+GNU-GOT-SO-NEXT:   000108e4 -32748(gp) 80000000 Module pointer (GNU extension)
+
+GNU-GOT-SO:       Local entries:
+GNU-GOT-SO-NEXT:    Address     Access  Initial
+GNU-GOT-SO-NEXT:   000108e8 -32744(gp) 000108e0
+GNU-GOT-SO-NEXT:   000108ec -32740(gp) 00010000
+GNU-GOT-SO-NEXT:   000108f0 -32736(gp) 00010920
+GNU-GOT-SO-NEXT:   000108f4 -32732(gp) 000108cc
+GNU-GOT-SO-NEXT:   000108f8 -32728(gp) 00000000
+GNU-GOT-SO-NEXT:   000108fc -32724(gp) 00000000
+GNU-GOT-SO-NEXT:   00010900 -32720(gp) 00000000
+GNU-GOT-SO-NEXT:   00010904 -32716(gp) 00000000
+
+GNU-GOT-SO:       Global entries:
+GNU-GOT-SO-NEXT:    Address     Access  Initial Sym.Val. Type    Ndx Name
+GNU-GOT-SO-NEXT:   00010908 -32712(gp) 00000000 00000000 NOTYPE  UND _ITM_registerTMCloneTable
+GNU-GOT-SO-NEXT:   0001090c -32708(gp) 00000000 00000000 NOTYPE  UND _Jv_RegisterClasses
+GNU-GOT-SO-NEXT:   00010910 -32704(gp) 00000000 00000000 FUNC    UND __gmon_start__
+GNU-GOT-SO-NEXT:   00010914 -32700(gp) 00000840 00000840 FUNC    UND puts
+GNU-GOT-SO-NEXT:   00010918 -32696(gp) 00000000 00000000 NOTYPE  UND _ITM_deregisterTMCloneTable
+GNU-GOT-SO-NEXT:   0001091c -32692(gp) 00000000 00000000 FUNC    UND __cxa_finalize
+
+GNU-GOT-TLS:      Primary GOT:
+GNU-GOT-TLS-NEXT:  Canonical gp value: 0000000000018bf0
+
+GNU-GOT-TLS:       Reserved entries:
+GNU-GOT-TLS-NEXT:            Address     Access          Initial Purpose
+GNU-GOT-TLS-NEXT:   0000000000010c00 -32752(gp) 0000000000000000 Lazy resolver
+GNU-GOT-TLS-NEXT:   0000000000010c08 -32744(gp) 8000000000000000 Module pointer (GNU extension)
+
+GNU-GOT-TLS:       Local entries:
+GNU-GOT-TLS-NEXT:            Address     Access          Initial
+GNU-GOT-TLS-NEXT:   0000000000010c10 -32736(gp) 0000000000010000
+GNU-GOT-TLS-NEXT:   0000000000010c18 -32728(gp) 0000000000010c00
+GNU-GOT-TLS-NEXT:   0000000000010c20 -32720(gp) 0000000000010cb8
+GNU-GOT-TLS-NEXT:   0000000000010c28 -32712(gp) 0000000000010bf0
+GNU-GOT-TLS-NEXT:   0000000000010c30 -32704(gp) 0000000000000000
+GNU-GOT-TLS-NEXT:   0000000000010c38 -32696(gp) 0000000000000948
+GNU-GOT-TLS-NEXT:   0000000000010c40 -32688(gp) 0000000000000a20
+GNU-GOT-TLS-NEXT:   0000000000010c48 -32680(gp) 0000000000000af0
+GNU-GOT-TLS-NEXT:   0000000000010c50 -32672(gp) 0000000000000000
+GNU-GOT-TLS-NEXT:   0000000000010c58 -32664(gp) 0000000000000000
+GNU-GOT-TLS-NEXT:   0000000000010c60 -32656(gp) 0000000000000000
+
+GNU-GOT-TLS:       Global entries:
+GNU-GOT-TLS-NEXT:            Address     Access          Initial         Sym.Val. Type    Ndx Name
+GNU-GOT-TLS-NEXT:   0000000000010c68 -32648(gp) 0000000000000000 0000000000000000 NOTYPE  UND _ITM_registerTMCloneTable
+GNU-GOT-TLS-NEXT:   0000000000010c70 -32640(gp) 0000000000000000 0000000000000000 NOTYPE  UND _Jv_RegisterClasses
+GNU-GOT-TLS-NEXT:   0000000000010c78 -32632(gp) 0000000000000000 0000000000000000 FUNC    UND __gmon_start__
+GNU-GOT-TLS-NEXT:   0000000000010c80 -32624(gp) 0000000000000b60 0000000000000b60 FUNC    UND __tls_get_addr
+GNU-GOT-TLS-NEXT:   0000000000010c88 -32616(gp) 0000000000000000 0000000000000000 NOTYPE  UND _ITM_deregisterTMCloneTable
+GNU-GOT-TLS-NEXT:   0000000000010c90 -32608(gp) 0000000000000000 0000000000000000 FUNC    UND __cxa_finalize
+
+GNU-GOTY     : Primary GOT:
+GNU-GOT-EMPTY:  Canonical gp value: 00409ff0
+
+GNU-GOTY     :  Reserved entries:
+GNU-GOT-EMPTY:    Address     Access  Initial Purpose
+GNU-GOT-EMPTY:   00402000 -32752(gp) 00000000 Lazy resolver
+GNU-GOT-EMPTY:   00402004 -32748(gp) 80000000 Module pointer (GNU extension)
+
+GNU-GOT-STATIC:      Static GOT:
+GNU-GOT-STATIC-NEXT:  Canonical gp value: 00418100
+
+GNU-GOT-STATIC:       Reserved entries:
+GNU-GOT-STATIC-NEXT:    Address     Access  Initial Purpose
+GNU-GOT-STATIC-NEXT:   00410110 -32752(gp) 00000000 Lazy resolver
+GNU-GOT-STATIC-NEXT:   00410114 -32748(gp) 80000000 Module pointer (GNU extension)
+
+GNU-GOT-STATIC:       Local entries:
+GNU-GOT-STATIC-NEXT:    Address     Access  Initial
+GNU-GOT-STATIC-NEXT:   00410118 -32744(gp) 00400000
+GNU-GOT-STATIC-NEXT:   0041011c -32740(gp) 00400100
+GNU-GOT-STATIC-NEXT:   00410120 -32736(gp) 00400104

Modified: llvm/trunk/test/tools/llvm-readobj/mips-plt.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/mips-plt.test?rev=321253&r1=321252&r2=321253&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/mips-plt.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/mips-plt.test Thu Dec 21 02:26:02 2017
@@ -1,4 +1,7 @@
 RUN: llvm-readobj -mips-plt-got %p/Inputs/got-plt.exe.elf-mipsel | FileCheck %s
+RUN: llvm-readobj -mips-plt-got --elf-output-style=GNU \
+RUN:              %p/Inputs/got-plt.exe.elf-mipsel \
+RUN:   | FileCheck --check-prefix=GNU %s
 
 CHECK:      PLT GOT {
 CHECK-NEXT:   Reserved entries [
@@ -32,3 +35,32 @@ CHECK-NEXT:       Name: __libc_start_mai
 CHECK-NEXT:     }
 CHECK-NEXT:   ]
 CHECK-NEXT: }
+
+GNU:      Primary GOT:
+GNU-NEXT:  Canonical gp value: 00418840
+
+GNU:       Reserved entries:
+GNU-NEXT:    Address     Access  Initial Purpose
+GNU-NEXT:   00410850 -32752(gp) 00000000 Lazy resolver
+GNU-NEXT:   00410854 -32748(gp) 80000000 Module pointer (GNU extension)
+
+GNU:       Local entries:
+GNU-NEXT:    Address     Access  Initial
+GNU-NEXT:   00410858 -32744(gp) 004003d4
+GNU-NEXT:   0041085c -32740(gp) 00410800
+GNU-NEXT:   00410860 -32736(gp) 00000000
+
+GNU:       Global entries:
+GNU-NEXT:    Address     Access  Initial Sym.Val. Type    Ndx Name
+GNU-NEXT:   00410864 -32732(gp) 00000000 00000000 FUNC    UND __gmon_start__
+GNU-NEXT: PLT GOT:
+
+GNU:       Reserved entries:
+GNU-NEXT:    Address  Initial Purpose
+GNU-NEXT:   00410814 00000000 PLT lazy resolver
+GNU-NEXT:   00410854 80000000 Module pointer
+
+GNU:       Entries:
+GNU-NEXT:    Address  Initial Sym.Val. Type    Ndx Name
+GNU-NEXT:   0041081c 004007c0 00000000 FUNC    UND puts
+GNU-NEXT:   00410820 004007c0 00000000 FUNC    UND __libc_start_main

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=321253&r1=321252&r2=321253&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Thu Dec 21 02:26:02 2017
@@ -77,6 +77,7 @@ using namespace ELF;
 
 #define TYPEDEF_ELF_TYPES(ELFT)                                                \
   using ELFO = ELFFile<ELFT>;                                                  \
+  using Elf_Addr = typename ELFO::Elf_Addr;                                    \
   using Elf_Shdr = typename ELFO::Elf_Shdr;                                    \
   using Elf_Sym = typename ELFO::Elf_Sym;                                      \
   using Elf_Dyn = typename ELFO::Elf_Dyn;                                      \
@@ -249,6 +250,9 @@ public:
   Elf_Rela_Range dyn_relas() const;
   std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
                                 bool IsDynamic) const;
+  void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
+                           StringRef &SectionName,
+                           unsigned &SectionIndex) const;
 
   void printSymbolsHelper(bool IsDynamic) const;
   const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
@@ -287,6 +291,8 @@ void ELFDumper<ELFT>::printSymbolsHelper
     ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic);
 }
 
+template <class ELFT> class MipsGOTParser;
+
 template <typename ELFT> class DumpStyle {
 public:
   using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr;
@@ -310,6 +316,8 @@ public:
   virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
   virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
   virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
+  virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
+  virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
   const ELFDumper<ELFT> *dumper() const { return Dumper; }
 
 private:
@@ -337,6 +345,8 @@ public:
   void printProgramHeaders(const ELFO *Obj) override;
   void printHashHistogram(const ELFFile<ELFT> *Obj) override;
   void printNotes(const ELFFile<ELFT> *Obj) override;
+  void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
+  void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
 
 private:
   struct Field {
@@ -395,6 +405,8 @@ public:
   void printProgramHeaders(const ELFO *Obj) override;
   void printHashHistogram(const ELFFile<ELFT> *Obj) override;
   void printNotes(const ELFFile<ELFT> *Obj) override;
+  void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
+  void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
 
 private:
   void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
@@ -735,11 +747,10 @@ std::string ELFDumper<ELFT>::getFullSymb
 }
 
 template <typename ELFT>
-static void
-getSectionNameIndex(const ELFFile<ELFT> &Obj, const typename ELFT::Sym *Symbol,
-                    const typename ELFT::Sym *FirstSym,
-                    ArrayRef<typename ELFT::Word> ShndxTable,
-                    StringRef &SectionName, unsigned &SectionIndex) {
+void ELFDumper<ELFT>::getSectionNameIndex(const Elf_Sym *Symbol,
+                                          const Elf_Sym *FirstSym,
+                                          StringRef &SectionName,
+                                          unsigned &SectionIndex) const {
   SectionIndex = Symbol->st_shndx;
   if (Symbol->isUndefined())
     SectionName = "Undefined";
@@ -758,8 +769,8 @@ getSectionNameIndex(const ELFFile<ELFT>
       SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>(
           Symbol, FirstSym, ShndxTable));
     const typename ELFT::Shdr *Sec =
-        unwrapOrError(Obj.getSection(SectionIndex));
-    SectionName = unwrapOrError(Obj.getSectionName(Sec));
+        unwrapOrError(Obj->getSection(SectionIndex));
+    SectionName = unwrapOrError(Obj->getSectionName(Sec));
   }
 }
 
@@ -1905,47 +1916,83 @@ template <> void ELFDumper<ELFType<suppo
 template <class ELFT> class MipsGOTParser {
 public:
   TYPEDEF_ELF_TYPES(ELFT)
-  using GOTEntry = typename ELFO::Elf_Addr;
+  using Entry = typename ELFO::Elf_Addr;
+  using Entries = ArrayRef<Entry>;
 
-  MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj,
-                Elf_Dyn_Range DynTable, ScopedPrinter &W);
+  const bool IsStatic;
+  const ELFO * const Obj;
 
-  void parseStaticGOT();
-  void parseGOT();
-  void parsePLT();
+  MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms);
 
-private:
-  ELFDumper<ELFT> *Dumper;
-  const ELFO *Obj;
-  ScopedPrinter &W;
-  Optional<uint64_t> DtPltGot;
-  Optional<uint64_t> DtLocalGotNum;
-  Optional<uint64_t> DtGotSym;
-  Optional<uint64_t> DtMipsPltGot;
-  Optional<uint64_t> DtJmpRel;
+  bool hasGot() const { return !GotEntries.empty(); }
+  bool hasPlt() const { return !PltEntries.empty(); }
+
+  uint64_t getGp() const;
+
+  const Entry *getGotLazyResolver() const;
+  const Entry *getGotModulePointer() const;
+  const Entry *getPltLazyResolver() const;
+  const Entry *getPltModulePointer() const;
+
+  Entries getLocalEntries() const;
+  Entries getGlobalEntries() const;
+  Entries getOtherEntries() const;
+  Entries getPltEntries() const;
+
+  uint64_t getGotAddress(const Entry * E) const;
+  int64_t getGotOffset(const Entry * E) const;
+  const Elf_Sym *getGotSym(const Entry *E) const;
 
-  std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const;
-  const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum);
+  uint64_t getPltAddress(const Entry * E) const;
+  const Elf_Sym *getPltSym(const Entry *E) const;
 
-  void printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num);
-  void printGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt,
-                     const GOTEntry *It);
-  void printGlobalGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt,
-                           const GOTEntry *It, const Elf_Sym *Sym,
-                           StringRef StrTable);
-  void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt,
-                     const GOTEntry *It, StringRef Purpose);
-  void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt,
-                     const GOTEntry *It, StringRef StrTable,
-                     const Elf_Sym *Sym);
+  StringRef getPltStrTable() const { return PltStrTable; }
+
+private:
+  const Elf_Shdr *GotSec;
+  size_t LocalNum;
+  size_t GlobalNum;
+
+  const Elf_Shdr *PltSec;
+  const Elf_Shdr *PltRelSec;
+  const Elf_Shdr *PltSymTable;
+  Elf_Sym_Range GotDynSyms;
+  StringRef PltStrTable;
+
+  Entries GotEntries;
+  Entries PltEntries;
 };
 
 } // end anonymous namespace
 
 template <class ELFT>
-MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj,
-                                   Elf_Dyn_Range DynTable, ScopedPrinter &W)
-    : Dumper(Dumper), Obj(Obj), W(W) {
+MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable,
+                                   Elf_Sym_Range DynSyms)
+    : IsStatic(DynTable.empty()), Obj(Obj), GotSec(nullptr), LocalNum(0),
+      GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr) {
+  // 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
+
+  // Find static GOT secton.
+  if (IsStatic) {
+    GotSec = findSectionByName(*Obj, ".got");
+    if (!GotSec)
+      reportError("Cannot find .got section");
+
+    ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec));
+    GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
+                         Content.size() / sizeof(Entry));
+    LocalNum = GotEntries.size();
+    return;
+  }
+
+  // Lookup dynamic table tags which define GOT/PLT layouts.
+  Optional<uint64_t> DtPltGot;
+  Optional<uint64_t> DtLocalGotNum;
+  Optional<uint64_t> DtGotSym;
+  Optional<uint64_t> DtMipsPltGot;
+  Optional<uint64_t> DtJmpRel;
   for (const auto &Entry : DynTable) {
     switch (Entry.getTag()) {
     case ELF::DT_PLTGOT:
@@ -1965,261 +2012,175 @@ MipsGOTParser<ELFT>::MipsGOTParser(ELFDu
       break;
     }
   }
-}
 
-template <class ELFT>
-void MipsGOTParser<ELFT>::printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num) {
-  ArrayRef<uint8_t> GOT = unwrapOrError(Obj->getSectionContents(GOTShdr));
+  // Find dynamic GOT section.
+  if (DtPltGot || DtLocalGotNum || DtGotSym) {
+    if (!DtPltGot)
+      report_fatal_error("Cannot find PLTGOT dynamic table tag.");
+    if (!DtLocalGotNum)
+      report_fatal_error("Cannot find MIPS_LOCAL_GOTNO dynamic table tag.");
+    if (!DtGotSym)
+      report_fatal_error("Cannot find MIPS_GOTSYM dynamic table tag.");
 
-  const GOTEntry *GotBegin = makeGOTIter(GOT, 0);
-  const GOTEntry *GotEnd = makeGOTIter(GOT, Num);
-  const GOTEntry *It = GotBegin;
+    size_t DynSymTotal = DynSyms.size();
+    if (*DtGotSym > DynSymTotal)
+      reportError("MIPS_GOTSYM exceeds a number of dynamic symbols");
 
-  W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0);
-  {
-    ListScope RS(W, "Reserved entries");
+    GotSec = findNotEmptySectionByAddress(Obj, *DtPltGot);
+    if (!GotSec)
+      reportError("There is no not empty GOT section at 0x" +
+                  Twine::utohexstr(*DtPltGot));
 
-    {
-      DictScope D(W, "Entry");
-      printGotEntry(GOTShdr->sh_addr, GotBegin, It++);
-      W.printString("Purpose", StringRef("Lazy resolver"));
-    }
+    LocalNum = *DtLocalGotNum;
+    GlobalNum = DynSymTotal - *DtGotSym;
 
-    if (It != GotEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) {
-      DictScope D(W, "Entry");
-      printGotEntry(GOTShdr->sh_addr, GotBegin, It++);
-      W.printString("Purpose", StringRef("Module pointer (GNU extension)"));
-    }
+    ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec));
+    GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
+                         Content.size() / sizeof(Entry));
+    GotDynSyms = DynSyms.drop_front(*DtGotSym);
   }
-  {
-    ListScope LS(W, "Local entries");
-    for (; It != GotEnd; ++It) {
-      DictScope D(W, "Entry");
-      printGotEntry(GOTShdr->sh_addr, GotBegin, It);
-    }
-  }
-}
 
-template <class ELFT> void MipsGOTParser<ELFT>::parseStaticGOT() {
-  const Elf_Shdr *GOTShdr = findSectionByName(*Obj, ".got");
-  if (!GOTShdr) {
-    W.startLine() << "Cannot find .got section.\n";
-    return;
-  }
+  // Find PLT section.
+  if (DtMipsPltGot || DtJmpRel) {
+    if (!DtMipsPltGot)
+      report_fatal_error("Cannot find MIPS_PLTGOT dynamic table tag.");
+    if (!DtJmpRel)
+      report_fatal_error("Cannot find JMPREL dynamic table tag.");
 
-  DictScope GS(W, "Static GOT");
-  printLocalGOT(GOTShdr, GOTShdr->sh_size / sizeof(GOTEntry));
-}
+    PltSec = findNotEmptySectionByAddress(Obj, *DtMipsPltGot);
+    if (!PltSec)
+      report_fatal_error("There is no not empty PLTGOT section at 0x " +
+                         Twine::utohexstr(*DtMipsPltGot));
 
-template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() {
-  // 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
-  if (!DtPltGot) {
-    W.startLine() << "Cannot find PLTGOT dynamic table tag.\n";
-    return;
-  }
-  if (!DtLocalGotNum) {
-    W.startLine() << "Cannot find MIPS_LOCAL_GOTNO dynamic table tag.\n";
-    return;
-  }
-  if (!DtGotSym) {
-    W.startLine() << "Cannot find MIPS_GOTSYM dynamic table tag.\n";
-    return;
-  }
-
-  std::size_t DynSymTotal = Dumper->dynamic_symbols().size();
+    PltRelSec = findNotEmptySectionByAddress(Obj, *DtJmpRel);
+    if (!PltRelSec)
+      report_fatal_error("There is no not empty RELPLT section at 0x" +
+                         Twine::utohexstr(*DtJmpRel));
 
-  if (*DtGotSym > DynSymTotal)
-    report_fatal_error("MIPS_GOTSYM exceeds a number of dynamic symbols");
+    ArrayRef<uint8_t> PltContent =
+        unwrapOrError(Obj->getSectionContents(PltSec));
+    PltEntries = Entries(reinterpret_cast<const Entry *>(PltContent.data()),
+                         PltContent.size() / sizeof(Entry));
 
-  std::size_t GlobalGotNum = DynSymTotal - *DtGotSym;
-
-  if (*DtLocalGotNum + GlobalGotNum == 0) {
-    W.startLine() << "GOT is empty.\n";
-    return;
+    PltSymTable = unwrapOrError(Obj->getSection(PltRelSec->sh_link));
+    PltStrTable = unwrapOrError(Obj->getStringTableForSymtab(*PltSymTable));
   }
-
-  const Elf_Shdr *GOTShdr = findNotEmptySectionByAddress(Obj, *DtPltGot);
-  if (!GOTShdr)
-    report_fatal_error("There is no not empty GOT section at 0x" +
-                       Twine::utohexstr(*DtPltGot));
-
-  ArrayRef<uint8_t> GOT = unwrapOrError(Obj->getSectionContents(GOTShdr));
-
-  if (*DtLocalGotNum + GlobalGotNum > getGOTTotal(GOT))
-    report_fatal_error("Number of GOT entries exceeds the size of GOT section");
-
-  DictScope GS(W, "Primary GOT");
-  printLocalGOT(GOTShdr, *DtLocalGotNum);
-
-  {
-    ListScope GS(W, "Global entries");
-
-    const GOTEntry *GotBegin = makeGOTIter(GOT, 0);
-    const GOTEntry *GotEnd = makeGOTIter(GOT, *DtLocalGotNum + GlobalGotNum);
-    const Elf_Sym *GotDynSym = Dumper->dynamic_symbols().begin() + *DtGotSym;
-    for (auto It = makeGOTIter(GOT, *DtLocalGotNum); It != GotEnd; ++It) {
-      DictScope D(W, "Entry");
-      printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++,
-                          Dumper->getDynamicStringTable());
-    }
-  }
-
-  std::size_t SpecGotNum = getGOTTotal(GOT) - *DtLocalGotNum - GlobalGotNum;
-  W.printNumber("Number of TLS and multi-GOT entries", uint64_t(SpecGotNum));
 }
 
-template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() {
-  if (!DtMipsPltGot) {
-    W.startLine() << "Cannot find MIPS_PLTGOT dynamic table tag.\n";
-    return;
-  }
-  if (!DtJmpRel) {
-    W.startLine() << "Cannot find JMPREL dynamic table tag.\n";
-    return;
-  }
-
-  const Elf_Shdr *PLTShdr = findNotEmptySectionByAddress(Obj, *DtMipsPltGot);
-  if (!PLTShdr)
-    report_fatal_error("There is no not empty PLTGOT section at 0x " +
-                       Twine::utohexstr(*DtMipsPltGot));
-  ArrayRef<uint8_t> PLT = unwrapOrError(Obj->getSectionContents(PLTShdr));
-
-  const Elf_Shdr *PLTRelShdr = findNotEmptySectionByAddress(Obj, *DtJmpRel);
-  if (!PLTRelShdr)
-    report_fatal_error("There is no not empty RELPLT section at 0x" +
-                       Twine::utohexstr(*DtJmpRel));
-  const Elf_Shdr *SymTable =
-      unwrapOrError(Obj->getSection(PLTRelShdr->sh_link));
-  StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTable));
-
-  const GOTEntry *PLTBegin = makeGOTIter(PLT, 0);
-  const GOTEntry *PLTEnd = makeGOTIter(PLT, getGOTTotal(PLT));
-  const GOTEntry *It = PLTBegin;
+template <class ELFT> uint64_t MipsGOTParser<ELFT>::getGp() const {
+  return GotSec->sh_addr + 0x7ff0;
+}
 
-  DictScope GS(W, "PLT GOT");
-  {
-    ListScope RS(W, "Reserved entries");
-    printPLTEntry(PLTShdr->sh_addr, PLTBegin, It++, "PLT lazy resolver");
-    if (It != PLTEnd)
-      printPLTEntry(PLTShdr->sh_addr, PLTBegin, It++, "Module pointer");
-  }
-  {
-    ListScope GS(W, "Entries");
+template <class ELFT>
+const typename MipsGOTParser<ELFT>::Entry *
+MipsGOTParser<ELFT>::getGotLazyResolver() const {
+  return LocalNum > 0 ? &GotEntries[0] : nullptr;
+}
 
-    switch (PLTRelShdr->sh_type) {
-    case ELF::SHT_REL:
-      for (const Elf_Rel &Rel : unwrapOrError(Obj->rels(PLTRelShdr))) {
-        const Elf_Sym *Sym =
-            unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTable));
-        printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, StrTable, Sym);
-        if (++It == PLTEnd)
-          break;
-      }
-      break;
-    case ELF::SHT_RELA:
-      for (const Elf_Rela &Rel : unwrapOrError(Obj->relas(PLTRelShdr))) {
-        const Elf_Sym *Sym =
-            unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTable));
-        printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, StrTable, Sym);
-        if (++It == PLTEnd)
-          break;
-      }
-      break;
-    }
-  }
+template <class ELFT>
+const typename MipsGOTParser<ELFT>::Entry *
+MipsGOTParser<ELFT>::getGotModulePointer() const {
+  if (LocalNum < 2)
+    return nullptr;
+  const Entry &E = GotEntries[1];
+  if ((E >> (sizeof(Entry) * 8 - 1)) == 0)
+    return nullptr;
+  return &E;
 }
 
 template <class ELFT>
-std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const {
-  return GOT.size() / sizeof(GOTEntry);
+typename MipsGOTParser<ELFT>::Entries
+MipsGOTParser<ELFT>::getLocalEntries() const {
+  size_t Skip = getGotModulePointer() ? 2 : 1;
+  if (LocalNum - Skip <= 0)
+    return Entries();
+  return GotEntries.slice(Skip, LocalNum - Skip);
 }
 
 template <class ELFT>
-const typename MipsGOTParser<ELFT>::GOTEntry *
-MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) {
-  const char *Data = reinterpret_cast<const char *>(GOT.data());
-  return reinterpret_cast<const GOTEntry *>(Data + EntryNum * sizeof(GOTEntry));
+typename MipsGOTParser<ELFT>::Entries
+MipsGOTParser<ELFT>::getGlobalEntries() const {
+  if (GlobalNum == 0)
+    return Entries();
+  return GotEntries.slice(LocalNum, GlobalNum);
 }
 
 template <class ELFT>
-void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr,
-                                        const GOTEntry *BeginIt,
-                                        const GOTEntry *It) {
-  int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry);
-  W.printHex("Address", GotAddr + Offset);
-  W.printNumber("Access", Offset - 0x7ff0);
-  W.printHex("Initial", *It);
+typename MipsGOTParser<ELFT>::Entries
+MipsGOTParser<ELFT>::getOtherEntries() const {
+  size_t OtherNum = GotEntries.size() - LocalNum - GlobalNum;
+  if (OtherNum == 0)
+    return Entries();
+  return GotEntries.slice(LocalNum + GlobalNum, OtherNum);
 }
 
 template <class ELFT>
-void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr,
-                                              const GOTEntry *BeginIt,
-                                              const GOTEntry *It,
-                                              const Elf_Sym *Sym,
-                                              StringRef StrTable) {
-  printGotEntry(GotAddr, BeginIt, It);
+uint64_t MipsGOTParser<ELFT>::getGotAddress(const Entry *E) const {
+  int64_t Offset = std::distance(GotEntries.data(), E) * sizeof(Entry);
+  return GotSec->sh_addr + Offset;
+}
 
-  W.printHex("Value", Sym->st_value);
-  W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes));
+template <class ELFT>
+int64_t MipsGOTParser<ELFT>::getGotOffset(const Entry *E) const {
+  int64_t Offset = std::distance(GotEntries.data(), E) * sizeof(Entry);
+  return Offset - 0x7ff0;
+}
 
-  unsigned SectionIndex = 0;
-  StringRef SectionName;
-  getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(),
-                      Dumper->getShndxTable(), SectionName, SectionIndex);
-  W.printHex("Section", SectionName, SectionIndex);
+template <class ELFT>
+const typename MipsGOTParser<ELFT>::Elf_Sym *
+MipsGOTParser<ELFT>::getGotSym(const Entry *E) const {
+  int64_t Offset = std::distance(GotEntries.data(), E);
+  return &GotDynSyms[Offset - LocalNum];
+}
 
-  std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true);
-  W.printNumber("Name", FullSymbolName, Sym->st_name);
+template <class ELFT>
+const typename MipsGOTParser<ELFT>::Entry *
+MipsGOTParser<ELFT>::getPltLazyResolver() const {
+  return PltEntries.empty() ? nullptr : &PltEntries[0];
 }
 
 template <class ELFT>
-void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr,
-                                        const GOTEntry *BeginIt,
-                                        const GOTEntry *It, StringRef Purpose) {
-  DictScope D(W, "Entry");
-  int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry);
-  W.printHex("Address", PLTAddr + Offset);
-  W.printHex("Initial", *It);
-  W.printString("Purpose", Purpose);
+const typename MipsGOTParser<ELFT>::Entry *
+MipsGOTParser<ELFT>::getPltModulePointer() const {
+  return PltEntries.size() < 2 ? nullptr : &PltEntries[1];
 }
 
 template <class ELFT>
-void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr,
-                                        const GOTEntry *BeginIt,
-                                        const GOTEntry *It, StringRef StrTable,
-                                        const Elf_Sym *Sym) {
-  DictScope D(W, "Entry");
-  int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry);
-  W.printHex("Address", PLTAddr + Offset);
-  W.printHex("Initial", *It);
-  W.printHex("Value", Sym->st_value);
-  W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes));
+typename MipsGOTParser<ELFT>::Entries
+MipsGOTParser<ELFT>::getPltEntries() const {
+  if (PltEntries.size() <= 2)
+    return Entries();
+  return PltEntries.slice(2, PltEntries.size() - 2);
+}
 
-  unsigned SectionIndex = 0;
-  StringRef SectionName;
-  getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(),
-                      Dumper->getShndxTable(), SectionName, SectionIndex);
-  W.printHex("Section", SectionName, SectionIndex);
+template <class ELFT>
+uint64_t MipsGOTParser<ELFT>::getPltAddress(const Entry *E) const {
+  int64_t Offset = std::distance(PltEntries.data(), E) * sizeof(Entry);
+  return PltSec->sh_addr + Offset;
+}
 
-  std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true);
-  W.printNumber("Name", FullSymbolName, Sym->st_name);
+template <class ELFT>
+const typename MipsGOTParser<ELFT>::Elf_Sym *
+MipsGOTParser<ELFT>::getPltSym(const Entry *E) const {
+  int64_t Offset = std::distance(getPltEntries().data(), E);
+  if (PltRelSec->sh_type == ELF::SHT_REL) {
+    Elf_Rel_Range Rels = unwrapOrError(Obj->rels(PltRelSec));
+    return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable));
+  } else {
+    Elf_Rela_Range Rels = unwrapOrError(Obj->relas(PltRelSec));
+    return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable));
+  }
 }
 
 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;
-  }
+  if (Obj->getHeader()->e_machine != EM_MIPS)
+    reportError("MIPS PLT GOT is available for MIPS targets only");
 
-  MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W);
-  if (dynamic_table().empty())
-    GOTParser.parseStaticGOT();
-  else {
-    GOTParser.parseGOT();
-    GOTParser.parsePLT();
-  }
+  MipsGOTParser<ELFT> Parser(Obj, dynamic_table(), dynamic_symbols());
+  if (Parser.hasGot())
+    ELFDumperStyle->printMipsGOT(Parser);
+  if (Parser.hasPlt())
+    ELFDumperStyle->printMipsPLT(Parser);
 }
 
 static const EnumEntry<unsigned> ElfMipsISAExtType[] = {
@@ -3597,6 +3558,119 @@ void GNUStyle<ELFT>::printNotes(const EL
   }
 }
 
+template <class ELFT>
+void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
+  size_t Bias = ELFT::Is64Bits ? 8 : 0;
+  auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) {
+    OS.PadToColumn(2);
+    OS << format_hex_no_prefix(Parser.getGotAddress(E), 8 + Bias);
+    OS.PadToColumn(11 + Bias);
+    OS << format_decimal(Parser.getGotOffset(E), 6) << "(gp)";
+    OS.PadToColumn(22 + Bias);
+    OS << format_hex_no_prefix(*E, 8 + Bias);
+    OS.PadToColumn(31 + 2 * Bias);
+    OS << Purpose << "\n";
+  };
+
+  OS << (Parser.IsStatic ? "Static GOT:\n" : "Primary GOT:\n");
+  OS << " Canonical gp value: "
+     << format_hex_no_prefix(Parser.getGp(), 8 + Bias) << "\n\n";
+
+  OS << " Reserved entries:\n";
+  OS << "   Address     Access  Initial Purpose\n";
+  PrintEntry(Parser.getGotLazyResolver(), "Lazy resolver");
+  if (Parser.getGotModulePointer())
+    PrintEntry(Parser.getGotModulePointer(), "Module pointer (GNU extension)");
+
+  if (!Parser.getLocalEntries().empty()) {
+    OS << "\n";
+    OS << " Local entries:\n";
+    OS << "   Address     Access  Initial\n";
+    for (auto &E : Parser.getLocalEntries())
+      PrintEntry(&E, "");
+  }
+
+  if (Parser.IsStatic)
+    return;
+
+  if (!Parser.getGlobalEntries().empty()) {
+    OS << "\n";
+    OS << " Global entries:\n";
+    OS << "   Address     Access  Initial Sym.Val. Type    Ndx Name\n";
+    for (auto &E : Parser.getGlobalEntries()) {
+      const Elf_Sym *Sym = Parser.getGotSym(&E);
+      std::string SymName = this->dumper()->getFullSymbolName(
+          Sym, this->dumper()->getDynamicStringTable(), false);
+
+      OS.PadToColumn(2);
+      OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias));
+      OS.PadToColumn(11 + Bias);
+      OS << to_string(format_decimal(Parser.getGotOffset(&E), 6)) + "(gp)";
+      OS.PadToColumn(22 + Bias);
+      OS << to_string(format_hex_no_prefix(E, 8 + Bias));
+      OS.PadToColumn(31 + 2 * Bias);
+      OS << to_string(format_hex_no_prefix(Sym->st_value, 8 + Bias));
+      OS.PadToColumn(40 + 3 * Bias);
+      OS << printEnum(Sym->getType(), makeArrayRef(ElfSymbolTypes));
+      OS.PadToColumn(48 + 3 * Bias);
+      OS << getSymbolSectionNdx(Parser.Obj, Sym,
+                                this->dumper()->dynamic_symbols().begin());
+      OS.PadToColumn(52 + 3 * Bias);
+      OS << SymName << "\n";
+    }
+  }
+
+  if (!Parser.getOtherEntries().empty())
+    OS << "\n Number of TLS and multi-GOT entries "
+       << Parser.getOtherEntries().size() << "\n";
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
+  size_t Bias = ELFT::Is64Bits ? 8 : 0;
+  auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) {
+    OS.PadToColumn(2);
+    OS << format_hex_no_prefix(Parser.getGotAddress(E), 8 + Bias);
+    OS.PadToColumn(11 + Bias);
+    OS << format_hex_no_prefix(*E, 8 + Bias);
+    OS.PadToColumn(20 + 2 * Bias);
+    OS << Purpose << "\n";
+  };
+
+  OS << "PLT GOT:\n\n";
+
+  OS << " Reserved entries:\n";
+  OS << "   Address  Initial Purpose\n";
+  PrintEntry(Parser.getPltLazyResolver(), "PLT lazy resolver");
+  if (Parser.getPltModulePointer())
+    PrintEntry(Parser.getGotModulePointer(), "Module pointer");
+
+  if (!Parser.getPltEntries().empty()) {
+    OS << "\n";
+    OS << " Entries:\n";
+    OS << "   Address  Initial Sym.Val. Type    Ndx Name\n";
+    for (auto &E : Parser.getPltEntries()) {
+      const Elf_Sym *Sym = Parser.getPltSym(&E);
+      std::string SymName = this->dumper()->getFullSymbolName(
+          Sym, this->dumper()->getDynamicStringTable(), false);
+
+      OS.PadToColumn(2);
+      OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias));
+      OS.PadToColumn(11 + Bias);
+      OS << to_string(format_hex_no_prefix(E, 8 + Bias));
+      OS.PadToColumn(20 + 2 * Bias);
+      OS << to_string(format_hex_no_prefix(Sym->st_value, 8 + Bias));
+      OS.PadToColumn(29 + 3 * Bias);
+      OS << printEnum(Sym->getType(), makeArrayRef(ElfSymbolTypes));
+      OS.PadToColumn(37 + 3 * Bias);
+      OS << getSymbolSectionNdx(Parser.Obj, Sym,
+                                this->dumper()->dynamic_symbols().begin());
+      OS.PadToColumn(41 + 3 * Bias);
+      OS << SymName << "\n";
+    }
+  }
+}
+
 template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
   const Elf_Ehdr *e = Obj->getHeader();
   {
@@ -3854,8 +3928,7 @@ void LLVMStyle<ELFT>::printSymbol(const
                                   bool IsDynamic) {
   unsigned SectionIndex = 0;
   StringRef SectionName;
-  getSectionNameIndex(*Obj, Symbol, First, this->dumper()->getShndxTable(),
-                      SectionName, SectionIndex);
+  this->dumper()->getSectionNameIndex(Symbol, First, SectionName, SectionIndex);
   std::string FullSymbolName =
       this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
   unsigned char SymbolType = Symbol->getType();
@@ -3992,3 +4065,114 @@ template <class ELFT>
 void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
   W.startLine() << "printNotes not implemented!\n";
 }
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
+  auto PrintEntry = [&](const Elf_Addr *E) {
+    W.printHex("Address", Parser.getGotAddress(E));
+    W.printNumber("Access", Parser.getGotOffset(E));
+    W.printHex("Initial", *E);
+  };
+
+  DictScope GS(W, Parser.IsStatic ? "Static GOT" : "Primary GOT");
+
+  W.printHex("Canonical gp value", Parser.getGp());
+  {
+    ListScope RS(W, "Reserved entries");
+    {
+      DictScope D(W, "Entry");
+      PrintEntry(Parser.getGotLazyResolver());
+      W.printString("Purpose", StringRef("Lazy resolver"));
+    }
+
+    if (Parser.getGotModulePointer()) {
+      DictScope D(W, "Entry");
+      PrintEntry(Parser.getGotModulePointer());
+      W.printString("Purpose", StringRef("Module pointer (GNU extension)"));
+    }
+  }
+  {
+    ListScope LS(W, "Local entries");
+    for (auto &E : Parser.getLocalEntries()) {
+      DictScope D(W, "Entry");
+      PrintEntry(&E);
+    }
+  }
+
+  if (Parser.IsStatic)
+    return;
+
+  {
+    ListScope GS(W, "Global entries");
+    for (auto &E : Parser.getGlobalEntries()) {
+      DictScope D(W, "Entry");
+
+      PrintEntry(&E);
+
+      const Elf_Sym *Sym = Parser.getGotSym(&E);
+      W.printHex("Value", Sym->st_value);
+      W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes));
+
+      unsigned SectionIndex = 0;
+      StringRef SectionName;
+      this->dumper()->getSectionNameIndex(
+          Sym, this->dumper()->dynamic_symbols().begin(), SectionName,
+          SectionIndex);
+      W.printHex("Section", SectionName, SectionIndex);
+
+      std::string SymName = this->dumper()->getFullSymbolName(
+          Sym, this->dumper()->getDynamicStringTable(), true);
+      W.printNumber("Name", SymName, Sym->st_name);
+    }
+  }
+
+  W.printNumber("Number of TLS and multi-GOT entries",
+                Parser.getOtherEntries().size());
+}
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
+  auto PrintEntry = [&](const Elf_Addr *E) {
+    W.printHex("Address", Parser.getPltAddress(E));
+    W.printHex("Initial", *E);
+  };
+
+  DictScope GS(W, "PLT GOT");
+
+  {
+    ListScope RS(W, "Reserved entries");
+    {
+      DictScope D(W, "Entry");
+      PrintEntry(Parser.getPltLazyResolver());
+      W.printString("Purpose", StringRef("PLT lazy resolver"));
+    }
+
+    if (auto E = Parser.getPltModulePointer()) {
+      DictScope D(W, "Entry");
+      PrintEntry(E);
+      W.printString("Purpose", StringRef("Module pointer"));
+    }
+  }
+  {
+    ListScope LS(W, "Entries");
+    for (auto &E : Parser.getPltEntries()) {
+      DictScope D(W, "Entry");
+      PrintEntry(&E);
+
+      const Elf_Sym *Sym = Parser.getPltSym(&E);
+      W.printHex("Value", Sym->st_value);
+      W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes));
+
+      unsigned SectionIndex = 0;
+      StringRef SectionName;
+      this->dumper()->getSectionNameIndex(
+          Sym, this->dumper()->dynamic_symbols().begin(), SectionName,
+          SectionIndex);
+      W.printHex("Section", SectionName, SectionIndex);
+
+      std::string SymName =
+          this->dumper()->getFullSymbolName(Sym, Parser.getPltStrTable(), true);
+      W.printNumber("Name", SymName, Sym->st_name);
+    }
+  }
+}




More information about the llvm-commits mailing list