[RISCV] Support RISC-V ELF attributes sections in llvm-readobj.

Enable llvm-readobj to handle RISC-V ELF attribute sections.

Differential Revision: https://reviews.llvm.org/D75833
This commit is contained in:
Kai Wang 2020-03-09 10:05:15 +08:00
parent be7a233e93
commit 501522b5b2
10 changed files with 178 additions and 19 deletions

View File

@ -217,7 +217,7 @@ Error ELFAttributeParser::parse(ArrayRef<uint8_t> section,
if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())
return createStringError(errc::invalid_argument,
"invalid subsection length " +
"invalid section length " +
Twine(sectionLength) + " at offset 0x" +
utohexstr(cursor.tell() - 4));

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,20 @@
## This test case is used to ensure the error code is caught by llvm-readobj.
# RUN: yaml2obj %s -D BITS=32 -o %t.32.o
# RUN: llvm-readobj -A %t.32.o 2>&1 | FileCheck -DFILE=%t %s
# RUN: yaml2obj %s -D BITS=64 -o %t.64.o
# RUN: llvm-readobj -A %t.64.o 2>&1 | FileCheck -DFILE=%t %s
# CHECK: warning: '[[FILE]].{{32|64}}.o': invalid section length 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 length: 0
Content: 4100000000

View File

@ -0,0 +1,21 @@
## This test case is used to ensure llvm-readobj checks the version of
## attribute sections correctly.
# RUN: yaml2obj %s -D BITS=32 -o %t.32.o
# RUN: llvm-readobj -A %t.32.o 2>&1 | FileCheck -DFILE=%t %s
# RUN: yaml2obj %s -D BITS=64 -o %t.64.o
# RUN: llvm-readobj -A %t.64.o 2>&1 | FileCheck -DFILE=%t %s
# CHECK: warning: '[[FILE]].{{32|64}}.o': 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

View File

@ -0,0 +1,2 @@
if not 'RISCV' in config.root.targets:
config.unsupported = True

View File

@ -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

View File

@ -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

View File

@ -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 <algorithm>
@ -2678,6 +2680,7 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
switch (Obj->getHeader()->e_machine) {
case EM_ARM:
case EM_RISCV:
printAttributes();
break;
case EM_MIPS: {
@ -2698,40 +2701,45 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
}
}
template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
W.startLine() << "Attributes not implemented.\n";
}
namespace {
template <> void ELFDumper<ELF32LE>::printAttributes() {
const ELFFile<ELF32LE> *Obj = ObjF->getELFFile();
if (Obj->getHeader()->e_machine != EM_ARM) {
template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
const ELFFile<ELFT> *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<uint8_t> Contents =
unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec));
if (Contents[0] != ELFAttrs::Format_Version) {
errs() << "unrecognised FormatVersion: 0x"
<< Twine::utohexstr(Contents[0]) << '\n';
reportWarning(createError(Twine("unrecognised FormatVersion: 0x") +
Twine::utohexstr(Contents[0])),
ObjF->getFileName());
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))
reportWarning(std::move(E), ObjF->getFileName());
} else if (Machine == EM_RISCV) {
if (Error E = RISCVAttributeParser(&W).parse(Contents, support::little))
reportWarning(std::move(E), ObjF->getFileName());
}
}
}
@ -3569,6 +3577,11 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "MIPS_ABIFLAGS";
}
break;
case EM_RISCV:
switch (Type) {
case SHT_RISCV_ATTRIBUTES:
return "RISCV_ATTRIBUTES";
}
}
switch (Type) {
case SHT_NULL:

View File

@ -40,9 +40,9 @@ TEST(AttributeHeaderParser, UnrecognizedFormatVersion) {
testParseError(bytes, "unrecognized format-version: 0x1");
}
TEST(AttributeHeaderParser, InvalidSubsectionLength) {
TEST(AttributeHeaderParser, InvalidSectionLength) {
static const uint8_t bytes[] = {'A', 3, 0, 0, 0};
testParseError(bytes, "invalid subsection length 3 at offset 0x1");
testParseError(bytes, "invalid section length 3 at offset 0x1");
}
TEST(AttributeHeaderParser, UnrecognizedVendorName) {