diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index 5a4e03e7bbe..1952b9480d0 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -489,6 +489,22 @@ struct Elf_Phdr_Impl > { Elf_Xword p_align; // Segment alignment constraint }; +// .MIPS.abiflags section content +template 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 index 00000000000..edcd50becec 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 index 00000000000..bb5f43d2862 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 index 00000000000..b4c769be207 --- /dev/null +++ b/test/tools/llvm-readobj/mips-abiflags.test @@ -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: } diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index ed4dd2c5a70..8fa40c3c8ca 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -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 ELFO; @@ -170,6 +172,16 @@ findSectionByAddress(const ELFFile *Obj, uint64_t Addr) { return nullptr; } +template +static const typename ELFFile::Elf_Shdr * +findSectionByName(const ELFFile &Obj, StringRef Name) { + for (const auto &Shdr : Obj.sections()) { + if (Name == errorOrDefault(Obj.getSectionName(&Shdr))) + return &Shdr; + } + return nullptr; +} + static const EnumEntry ElfClass[] = { { "None", ELF::ELFCLASSNONE }, { "32-bit", ELF::ELFCLASS32 }, @@ -1249,3 +1261,112 @@ template void ELFDumper::printMipsPLTGOT() { MipsGOTParser(Obj, W).parseGOT(*GotShdr); } + +static const EnumEntry 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 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 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 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 void ELFDumper::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> Sec = Obj->getSectionContents(Shdr); + if (!Sec) { + W.startLine() << "The .MIPS.abiflags section is empty.\n"; + return; + } + if (Sec->size() != sizeof(Elf_Mips_ABIFlags)) { + W.startLine() << "The .MIPS.abiflags section has a wrong size.\n"; + return; + } + + auto *Flags = reinterpret_cast *>(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); +} diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 27e658fc731..5750d6ffd28 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -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() { } diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 7e6ce496723..be7bbe94d9e 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -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 MipsABIFlags("mips-abi-flags", + cl::desc("Display the MIPS.abiflags section")); + // -coff-imports cl::opt 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)