[llvm-readobj] Print .MIPS.abiflags section content
authorSimon Atanasyan <simon@atanasyan.com>
Thu, 7 May 2015 15:40:35 +0000 (15:40 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Thu, 7 May 2015 15:40:35 +0000 (15:40 +0000)
This change adds new flag -mips-abi-flags to the llvm-readobj. This flag
forces printing of .MIPS.abiflags section content.

https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking#10.2.1._.MIPS.abiflags

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236737 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/ELFTypes.h
test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mips [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mipsel [new file with mode: 0644]
test/tools/llvm-readobj/mips-abiflags.test [new file with mode: 0644]
tools/llvm-readobj/ELFDumper.cpp
tools/llvm-readobj/ObjDumper.h
tools/llvm-readobj/llvm-readobj.cpp

index 5a4e03e7bbed817439ed07372c5124c1ff244ce6..1952b9480d0199c9017e0d12624b881983727065 100644 (file)
@@ -489,6 +489,22 @@ struct Elf_Phdr_Impl<ELFType<TargetEndianness, MaxAlign, true> > {
   Elf_Xword p_align;  // Segment alignment constraint
 };
 
+// .MIPS.abiflags section content
+template <class ELFT> struct Elf_Mips_ABIFlags {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Half version;  // Version of the structure
+  uint8_t isa_level; // ISA level: 1-5, 32, and 64
+  uint8_t isa_rev;   // ISA revision (0 for MIPS I - MIPS V)
+  uint8_t gpr_size;  // General purpose registers size
+  uint8_t cpr1_size; // Co-processor 1 registers size
+  uint8_t cpr2_size; // Co-processor 2 registers size
+  uint8_t fp_abi;    // Floating-point ABI flag
+  Elf_Word isa_ext;  // Processor-specific extension
+  Elf_Word ases;     // ASEs flags
+  Elf_Word flags1;   // General flags
+  Elf_Word flags2;   // General flags
+};
+
 } // end namespace object.
 } // end namespace llvm.
 
diff --git a/test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mips b/test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mips
new file mode 100644 (file)
index 0000000..edcd50b
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mips differ
diff --git a/test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mipsel b/test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mipsel
new file mode 100644 (file)
index 0000000..bb5f43d
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/abiflags.obj.elf-mipsel differ
diff --git a/test/tools/llvm-readobj/mips-abiflags.test b/test/tools/llvm-readobj/mips-abiflags.test
new file mode 100644 (file)
index 0000000..b4c769b
--- /dev/null
@@ -0,0 +1,42 @@
+RUN: llvm-readobj -mips-abi-flags %p/Inputs/abiflags.obj.elf-mipsel | \
+RUN:   FileCheck -check-prefix=EL64 %s
+RUN: llvm-readobj -mips-abi-flags %p/Inputs/abiflags.obj.elf-mips | \
+RUN:   FileCheck -check-prefix=BE32 %s
+
+EL64:      MIPS ABI Flags {
+EL64-NEXT:   Version: 0
+EL64-NEXT:   ISA: MIPS64r5
+EL64-NEXT:   ISA Extension: Cavium Networks Octeon3 (0x13)
+EL64-NEXT:   ASEs [ (0x103)
+EL64-NEXT:     DSP (0x1)
+EL64-NEXT:     DSPR2 (0x2)
+EL64-NEXT:     VZ (0x100)
+EL64-NEXT:   ]
+EL64-NEXT:   FP ABI: Hard float (double precision) (0x1)
+EL64-NEXT:   GPR size: 64
+EL64-NEXT:   CPR1 size: 64
+EL64-NEXT:   CPR2 size: 0
+EL64-NEXT:   Flags 1 [ (0x1)
+EL64-NEXT:     ODDSPREG (0x1)
+EL64-NEXT:   ]
+EL64-NEXT:   Flags 2: 0x0
+EL64-NEXT: }
+
+BE32:      MIPS ABI Flags {
+BE32-NEXT:   Version: 0
+BE32-NEXT:   ISA: MIPS32r2
+BE32-NEXT:   ISA Extension: None (0x0)
+BE32-NEXT:   ASEs [ (0x803)
+BE32-NEXT:     DSP (0x1)
+BE32-NEXT:     DSPR2 (0x2)
+BE32-NEXT:     microMIPS (0x800)
+BE32-NEXT:   ]
+BE32-NEXT:   FP ABI: Soft float (0x3)
+BE32-NEXT:   GPR size: 32
+BE32-NEXT:   CPR1 size: 0
+BE32-NEXT:   CPR2 size: 0
+BE32-NEXT:   Flags 1 [ (0x1)
+BE32-NEXT:     ODDSPREG (0x1)
+BE32-NEXT:   ]
+BE32-NEXT:   Flags 2: 0x0
+BE32-NEXT: }
index ed4dd2c5a704499245d61e95d1c7da717fa58447..8fa40c3c8caec6d9afcb22b97bf0a3a47e0e713a 100644 (file)
@@ -26,6 +26,7 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MipsABIFlags.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
@@ -56,6 +57,7 @@ public:
 
   void printAttributes() override;
   void printMipsPLTGOT() override;
+  void printMipsABIFlags() override;
 
 private:
   typedef ELFFile<ELFT> ELFO;
@@ -170,6 +172,16 @@ findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) {
   return nullptr;
 }
 
+template <class ELFT>
+static const typename ELFFile<ELFT>::Elf_Shdr *
+findSectionByName(const ELFFile<ELFT> &Obj, StringRef Name) {
+  for (const auto &Shdr : Obj.sections()) {
+    if (Name == errorOrDefault(Obj.getSectionName(&Shdr)))
+      return &Shdr;
+  }
+  return nullptr;
+}
+
 static const EnumEntry<unsigned> ElfClass[] = {
   { "None",   ELF::ELFCLASSNONE },
   { "32-bit", ELF::ELFCLASS32   },
@@ -1249,3 +1261,112 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() {
 
   MipsGOTParser<ELFT>(Obj, W).parseGOT(*GotShdr);
 }
+
+static const EnumEntry<unsigned> ElfMipsISAExtType[] = {
+  {"None",                    Mips::AFL_EXT_NONE},
+  {"Broadcom SB-1",           Mips::AFL_EXT_SB1},
+  {"Cavium Networks Octeon",  Mips::AFL_EXT_OCTEON},
+  {"Cavium Networks Octeon2", Mips::AFL_EXT_OCTEON2},
+  {"Cavium Networks OcteonP", Mips::AFL_EXT_OCTEONP},
+  {"Cavium Networks Octeon3", Mips::AFL_EXT_OCTEON3},
+  {"LSI R4010",               Mips::AFL_EXT_4010},
+  {"Loongson 2E",             Mips::AFL_EXT_LOONGSON_2E},
+  {"Loongson 2F",             Mips::AFL_EXT_LOONGSON_2F},
+  {"Loongson 3A",             Mips::AFL_EXT_LOONGSON_3A},
+  {"MIPS R4650",              Mips::AFL_EXT_4650},
+  {"MIPS R5900",              Mips::AFL_EXT_5900},
+  {"MIPS R10000",             Mips::AFL_EXT_10000},
+  {"NEC VR4100",              Mips::AFL_EXT_4100},
+  {"NEC VR4111/VR4181",       Mips::AFL_EXT_4111},
+  {"NEC VR4120",              Mips::AFL_EXT_4120},
+  {"NEC VR5400",              Mips::AFL_EXT_5400},
+  {"NEC VR5500",              Mips::AFL_EXT_5500},
+  {"RMI Xlr",                 Mips::AFL_EXT_XLR},
+  {"Toshiba R3900",           Mips::AFL_EXT_3900}
+};
+
+static const EnumEntry<unsigned> ElfMipsASEFlags[] = {
+  {"DSP",                Mips::AFL_ASE_DSP},
+  {"DSPR2",              Mips::AFL_ASE_DSPR2},
+  {"Enhanced VA Scheme", Mips::AFL_ASE_EVA},
+  {"MCU",                Mips::AFL_ASE_MCU},
+  {"MDMX",               Mips::AFL_ASE_MDMX},
+  {"MIPS-3D",            Mips::AFL_ASE_MIPS3D},
+  {"MT",                 Mips::AFL_ASE_MT},
+  {"SmartMIPS",          Mips::AFL_ASE_SMARTMIPS},
+  {"VZ",                 Mips::AFL_ASE_VIRT},
+  {"MSA",                Mips::AFL_ASE_MSA},
+  {"MIPS16",             Mips::AFL_ASE_MIPS16},
+  {"microMIPS",          Mips::AFL_ASE_MICROMIPS},
+  {"XPA",                Mips::AFL_ASE_XPA}
+};
+
+static const EnumEntry<unsigned> ElfMipsFpABIType[] = {
+  {"Hard or soft float",                  Mips::Val_GNU_MIPS_ABI_FP_ANY},
+  {"Hard float (double precision)",       Mips::Val_GNU_MIPS_ABI_FP_DOUBLE},
+  {"Hard float (single precision)",       Mips::Val_GNU_MIPS_ABI_FP_SINGLE},
+  {"Soft float",                          Mips::Val_GNU_MIPS_ABI_FP_SOFT},
+  {"Hard float (MIPS32r2 64-bit FPU 12 callee-saved)",
+   Mips::Val_GNU_MIPS_ABI_FP_OLD_64},
+  {"Hard float (32-bit CPU, Any FPU)",    Mips::Val_GNU_MIPS_ABI_FP_XX},
+  {"Hard float (32-bit CPU, 64-bit FPU)", Mips::Val_GNU_MIPS_ABI_FP_64},
+  {"Hard float compat (32-bit CPU, 64-bit FPU)",
+   Mips::Val_GNU_MIPS_ABI_FP_64A}
+};
+
+static const EnumEntry<unsigned> ElfMipsFlags1[] {
+  {"ODDSPREG", Mips::AFL_FLAGS1_ODDSPREG},
+};
+
+static int getMipsRegisterSize(uint8_t Flag) {
+  switch (Flag) {
+  case Mips::AFL_REG_NONE:
+    return 0;
+  case Mips::AFL_REG_32:
+    return 32;
+  case Mips::AFL_REG_64:
+    return 64;
+  case Mips::AFL_REG_128:
+    return 128;
+  default:
+    return -1;
+  }
+}
+
+template <class ELFT> void ELFDumper<ELFT>::printMipsABIFlags() {
+  const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.abiflags");
+  if (!Shdr) {
+    W.startLine() << "There is no .MIPS.abiflags section in the file.\n";
+    return;
+  }
+  ErrorOr<ArrayRef<uint8_t>> Sec = Obj->getSectionContents(Shdr);
+  if (!Sec) {
+    W.startLine() << "The .MIPS.abiflags section is empty.\n";
+    return;
+  }
+  if (Sec->size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) {
+    W.startLine() << "The .MIPS.abiflags section has a wrong size.\n";
+    return;
+  }
+
+  auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec->data());
+
+  raw_ostream &OS = W.getOStream();
+  DictScope GS(W, "MIPS ABI Flags");
+
+  W.printNumber("Version", Flags->version);
+  W.startLine() << "ISA: ";
+  if (Flags->isa_rev <= 1)
+    OS << format("MIPS%u", Flags->isa_level);
+  else
+    OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev);
+  OS << "\n";
+  W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType));
+  W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags));
+  W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType));
+  W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size));
+  W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size));
+  W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size));
+  W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1));
+  W.printHex("Flags 2", Flags->flags2);
+}
index 27e658fc731a51aeecbbb5318e970308fd2251f6..5750d6ffd28670b0986a18b2aec29c4067130b0f 100644 (file)
@@ -42,6 +42,7 @@ public:
 
   // Only implemented for MIPS ELF at this time.
   virtual void printMipsPLTGOT() { }
+  virtual void printMipsABIFlags() { }
 
   // Only implemented for PE/COFF.
   virtual void printCOFFImports() { }
index 7e6ce49672313b7d25bf6e1db3732f93c6553af1..be7bbe94d9eaad92627ddcaef591e94ce4291fde 100644 (file)
@@ -148,6 +148,10 @@ namespace opts {
   MipsPLTGOT("mips-plt-got",
              cl::desc("Display the MIPS GOT and PLT GOT sections"));
 
+  // -mips-abi-flags
+  cl::opt<bool> MipsABIFlags("mips-abi-flags",
+                             cl::desc("Display the MIPS.abiflags section"));
+
   // -coff-imports
   cl::opt<bool>
   COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
@@ -287,9 +291,12 @@ 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 (isMipsArch(Obj->getArch()) && Obj->isELF()) {
     if (opts::MipsPLTGOT)
       Dumper->printMipsPLTGOT();
+    if (opts::MipsABIFlags)
+      Dumper->printMipsABIFlags();
+  }
   if (opts::COFFImports)
     Dumper->printCOFFImports();
   if (opts::COFFExports)