diff --git a/llvm/lib/Support/ELFAttributeParser.cpp b/llvm/lib/Support/ELFAttributeParser.cpp --- a/llvm/lib/Support/ELFAttributeParser.cpp +++ b/llvm/lib/Support/ELFAttributeParser.cpp @@ -129,10 +129,10 @@ sw->printString("Vendor", vendorName); } - // Ignore unrecognized vendor-name. + // Ignore unrecognized vendor name. if (vendorName.lower() != vendor) return createStringError(errc::invalid_argument, - "unrecognized vendor-name: " + vendorName); + "unrecognized vendor name: " + vendorName); while (cursor.tell() < end) { /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size @@ -147,7 +147,7 @@ } if (size < 5) return createStringError(errc::invalid_argument, - "invalid attribute size " + Twine(size) + + "invalid subsection size " + Twine(size) + " at offset 0x" + Twine::utohexstr(cursor.tell() - 5)); @@ -217,7 +217,7 @@ if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size()) return createStringError(errc::invalid_argument, - "invalid subsection length " + + "invalid section size " + Twine(sectionLength) + " at offset 0x" + utohexstr(cursor.tell() - 4)); diff --git a/llvm/test/MC/RISCV/attribute-with-option.s b/llvm/test/MC/RISCV/attribute-with-option.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/attribute-with-option.s @@ -0,0 +1,21 @@ +## When a user specifies an architecture extension which conflicts with an +## architecture attribute, we use the architecture attribute instead of the +## command line option. +## +## This test uses option '-mattr=+e' to specify the "e" extension. However, +## there is an architecture attribute in the file to specify rv32i. We will +## use rv32i to assemble the file instead of rv32e. + +# RUN: llvm-mc %s -triple=riscv32 -mattr=+e -filetype=obj -o - \ +# RUN: | llvm-readobj -A - | FileCheck %s + +.attribute arch, "rv32i2p0" +## Invalid operand for RV32E, because x16 is an invalid register for RV32E. +## Use RV32I to assemble, since it will not trigger an assembly error. +lui x16, 1 + +## Check that the architecture attribute is not overridden by the command line +## option. +# CHECK: Tag: 5 +# CHECK-NEXT: TagName: arch +# CHECK-NEXT: Value: rv32i2p0 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.s b/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/attribute.s @@ -0,0 +1,44 @@ +## Test llvm-readobj & llvm-readelf can decode RISC-V attributes correctly. + +# RUN: llvm-mc -triple riscv32 -filetype obj -o %t.rv32.o %s +# RUN: llvm-mc -triple riscv64 -filetype obj -o %t.rv64.o %s +# RUN: llvm-readobj --arch-specific %t.rv32.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ +# RUN: llvm-readelf -A %t.rv32.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ +# RUN: llvm-readobj --arch-specific %t.rv64.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ +# RUN: llvm-readelf -A %t.rv64.o \ +# RUN: | FileCheck %s --check-prefix=CHECK-OBJ + +.attribute Tag_stack_align, 16 +# CHECK-OBJ: Tag: 4 +# CHECK-OBJ-NEXT: Value: 16 +# CHECK-OBJ-NEXT: TagName: stack_align +# CHECK-OBJ-NEXT: Description: Stack alignment is 16-bytes + +.attribute Tag_arch, "rv32i2p0_m2p0_a2p0_c2p0" +# CHECK-OBJ: Tag: 5 +# CHECK-OBJ-NEXT: TagName: arch +# CHECK-OBJ-NEXT: Value: rv32i2p0_m2p0_a2p0_c2p0 + +.attribute Tag_unaligned_access, 0 +# CHECK-OBJ: Tag: 6 +# CHECK-OBJ-NEXT: Value: 0 +# CHECK-OBJ-NEXT: TagName: unaligned_access +# CHECK-OBJ-NEXT: Description: No unaligned access + +.attribute Tag_priv_spec, 2 +# CHECK-OBJ: Tag: 8 +# CHECK-OBJ-NEXT: TagName: priv_spec +# CHECK-OBJ-NEXT: Value: 2 + +.attribute Tag_priv_spec_minor, 0 +# CHECK-OBJ: Tag: 10 +# CHECK-OBJ-NEXT: TagName: priv_spec_minor +# CHECK-OBJ-NEXT: Value: 0 + +.attribute Tag_priv_spec_revision, 0 +# CHECK-OBJ: Tag: 12 +# CHECK-OBJ-NEXT: TagName: priv_spec_revision +# CHECK-OBJ-NEXT: Value: 0 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-section-size.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-section-size.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-section-size.test @@ -0,0 +1,18 @@ +# RUN: yaml2obj %s -D BITS=32 -o %t.32.o +# RUN: not llvm-readobj -A %t.32.o 2>&1 | FileCheck %s +# RUN: yaml2obj %s -D BITS=64 -o %t.64.o +# RUN: not llvm-readobj -A %t.64.o 2>&1 | FileCheck %s + +# CHECK: error: '{{.*}}.o': invalid section size 0 at offset 0x1 + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES +## Version: 'A'(0x41), section size: 0 + Content: 4100000000 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-subsection-size.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-subsection-size.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-subsection-size.test @@ -0,0 +1,20 @@ +# RUN: yaml2obj %s -D BITS=32 -o %t.32.o +# RUN: not llvm-readobj -A %t.32.o 2>&1 | FileCheck %s +# RUN: yaml2obj %s -D BITS=64 -o %t.64.o +# RUN: not llvm-readobj -A %t.64.o 2>&1 | FileCheck %s + +# CHECK: error: '{{.*}}.o': invalid subsection size 0 at offset 0xb + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES +## Version: 'A'(0x41), section size: 15(0f000000) +## vendor name: 'riscv'(726973637600), tag: Tag_File(0x1) +## attribute subsection size: 0 + Content: 410f0000007269736376000100000000 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-tag.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-tag.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-tag.test @@ -0,0 +1,20 @@ +# RUN: yaml2obj %s -D BITS=32 -o %t.32.o +# RUN: not llvm-readobj -A %t.32.o 2>&1 | FileCheck %s +# RUN: yaml2obj %s -D BITS=64 -o %t.64.o +# RUN: not llvm-readobj -A %t.64.o 2>&1 | FileCheck %s + +# CHECK: error: '{{.*}}.o': unrecognized tag 0x4 at offset 0xb + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES +## Version: 'A'(0x41), section size: 15(0f000000) +## vendor name: 'riscv'(726973637600), tag: unknown(0x4) +## attribute subsection size: 5 + Content: 410f0000007269736376000405000000 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-vendor.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-vendor.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-vendor.test @@ -0,0 +1,19 @@ +# RUN: yaml2obj %s -D BITS=32 -o %t.32.o +# RUN: not llvm-readobj -A %t.32.o 2>&1 | FileCheck %s +# RUN: yaml2obj %s -D BITS=64 -o %t.64.o +# RUN: not llvm-readobj -A %t.64.o 2>&1 | FileCheck %s + +# CHECK: error: '{{.*}}.o': unrecognized vendor name: qiscv + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES +## Version: 'A'(0x41), section size: 10(0a000000) +## vendor name: 'qiscv'(716973637600) + Content: 410a000000716973637600 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-version.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-version.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/invalid-attr-version.test @@ -0,0 +1,18 @@ +# RUN: yaml2obj %s -D BITS=32 -o %t.32.o +# RUN: llvm-readobj -A %t.32.o 2>&1 | FileCheck %s +# RUN: yaml2obj %s -D BITS=64 -o %t.64.o +# RUN: llvm-readobj -A %t.64.o 2>&1 | FileCheck %s + +# CHECK: unrecognised FormatVersion: 0x42 + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES +## Version: 'B' + Content: 42 diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/lit.local.cfg b/llvm/test/tools/llvm-readobj/ELF/RISCV/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/section-types.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/section-types.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/section-types.test @@ -0,0 +1,21 @@ +## Show that all RISCV specific section types are properly printed for both +## LLVM and GNU styles. + +# RUN: yaml2obj %s -o %t-riscv.o +# RUN: llvm-readobj --section-headers %t-riscv.o | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readelf --section-headers %t-riscv.o | FileCheck %s --check-prefix=GNU + +# LLVM: Name: .riscv.attributes (1) +# LLVM-NEXT: Type: SHT_RISCV_ATTRIBUTES (0x70000003) + +# GNU: [ 1] .riscv.attributes RISCV_ATTRIBUTES + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/validate-attr-section.test b/llvm/test/tools/llvm-readobj/ELF/RISCV/validate-attr-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/validate-attr-section.test @@ -0,0 +1,17 @@ +## We only implement attribute section printing for little-endian encoding. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-readobj -A %t.o | FileCheck %s + +# CHECK: Attributes not implemented. + +--- !ELF +FileHeader: + Class: ELFCLASS64 +## Test big-endian encoding. + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .riscv.attributes + Type: SHT_RISCV_ATTRIBUTES diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -52,6 +52,8 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" +#include "llvm/Support/RISCVAttributeParser.h" +#include "llvm/Support/RISCVAttributes.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include @@ -2639,6 +2641,7 @@ const ELFFile *Obj = ObjF->getELFFile(); switch (Obj->getHeader()->e_machine) { case EM_ARM: + case EM_RISCV: printAttributes(); break; case EM_MIPS: { @@ -2659,23 +2662,23 @@ } } -template void ELFDumper::printAttributes() { - W.startLine() << "Attributes not implemented.\n"; -} - namespace { -template <> void ELFDumper::printAttributes() { - const ELFFile *Obj = ObjF->getELFFile(); - if (Obj->getHeader()->e_machine != EM_ARM) { +template void ELFDumper::printAttributes() { + const ELFFile *Obj = ObjF->getELFFile(); + if (!Obj->isLE()) { W.startLine() << "Attributes not implemented.\n"; return; } + const unsigned Machine = Obj->getHeader()->e_machine; + assert((Machine == EM_ARM || Machine == EM_RISCV) && + "Attributes not implemented."); + DictScope BA(W, "BuildAttributes"); - for (const ELFO::Elf_Shdr &Sec : - unwrapOrError(ObjF->getFileName(), Obj->sections())) { - if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES) + for (const auto &Sec : unwrapOrError(ObjF->getFileName(), Obj->sections())) { + if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES && + Sec.sh_type != ELF::SHT_RISCV_ATTRIBUTES) continue; ArrayRef Contents = @@ -2685,14 +2688,18 @@ << Twine::utohexstr(Contents[0]) << '\n'; continue; } - W.printHex("FormatVersion", Contents[0]); if (Contents.size() == 1) continue; - // TODO: Print error and delete the redundant FormatVersion check above. - if (Error E = ARMAttributeParser(&W).parse(Contents, support::little)) - consumeError(std::move(E)); + // TODO: Delete the redundant FormatVersion check above. + if (Machine == EM_ARM) { + if (Error E = ARMAttributeParser(&W).parse(Contents, support::little)) + reportError(std::move(E), ObjF->getFileName()); + } else if (Machine == EM_RISCV) { + if (Error E = RISCVAttributeParser(&W).parse(Contents, support::little)) + reportError(std::move(E), ObjF->getFileName()); + } } } @@ -3530,6 +3537,11 @@ return "MIPS_ABIFLAGS"; } break; + case EM_RISCV: + switch (Type) { + case SHT_RISCV_ATTRIBUTES: + return "RISCV_ATTRIBUTES"; + } } switch (Type) { case SHT_NULL: diff --git a/llvm/unittests/Support/ELFAttributeParserTest.cpp b/llvm/unittests/Support/ELFAttributeParserTest.cpp --- a/llvm/unittests/Support/ELFAttributeParserTest.cpp +++ b/llvm/unittests/Support/ELFAttributeParserTest.cpp @@ -42,12 +42,12 @@ TEST(AttributeHeaderParser, InvalidSubsectionLength) { static const uint8_t bytes[] = {'A', 3, 0, 0, 0}; - testParseError(bytes, "invalid subsection length 3 at offset 0x1"); + testParseError(bytes, "invalid section size 3 at offset 0x1"); } TEST(AttributeHeaderParser, UnrecognizedVendorName) { static const uint8_t bytes[] = {'A', 7, 0, 0, 0, 'x', 'y', 0}; - testParseError(bytes, "unrecognized vendor-name: xy"); + testParseError(bytes, "unrecognized vendor name: xy"); } TEST(AttributeHeaderParser, UnrecognizedTag) { @@ -59,5 +59,5 @@ TEST(AttributeHeaderParser, InvalidAttributeSize) { static const uint8_t bytes[] = {'A', 14, 0, 0, 0, 't', 'e', 's', 't', 0, 1, 4, 0, 0, 0}; - testParseError(bytes, "invalid attribute size 4 at offset 0xa"); + testParseError(bytes, "invalid subsection size 4 at offset 0xa"); }