mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-26 23:38:31 +00:00
[llvm-readobj/elf] - Add a testing for --stackmap and refine the implementation.
Currently, we only test the `--stackmap` option here: https://github.com/llvm/llvm-project/blob/master/llvm/test/Object/stackmap-dump.test it uses a precompiled MachO binary currently and I've found no tests for this option for ELF. The implementation also has issues. For example, it might assert on a wrong version of the .llvm-stackmaps section. Or it might crash on an empty or truncated section. This patch introduces a new tools/llvm-readobj/ELF test file as well as implements a few basic checks to catch simple crashes/issues It also eliminates `unwrapOrError` calls in `printStackMap()`. Differential revision: https://reviews.llvm.org/D85208
This commit is contained in:
parent
eacb852738
commit
af54a4ae5b
@ -11,6 +11,7 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
@ -318,6 +319,23 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates the header of the specified stack map section.
|
||||
static Error validateHeader(ArrayRef<uint8_t> StackMapSection) {
|
||||
// See the comment for StackMaps::emitStackmapHeader().
|
||||
if (StackMapSection.size() < 16)
|
||||
return object::createError(
|
||||
"the stack map section size (" + Twine(StackMapSection.size()) +
|
||||
") is less than the minimum possible size of its header (16)");
|
||||
|
||||
unsigned Version = StackMapSection[0];
|
||||
if (Version != 3)
|
||||
return object::createError(
|
||||
"the version (" + Twine(Version) +
|
||||
") of the stack map section is unsupported, the "
|
||||
"supported version is 3");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
using function_iterator = AccessorIterator<FunctionAccessor>;
|
||||
using constant_iterator = AccessorIterator<ConstantAccessor>;
|
||||
using record_iterator = AccessorIterator<RecordAccessor>;
|
||||
|
@ -404,7 +404,7 @@ void StackMaps::recordStatepoint(const MCSymbol &L, const MachineInstr &MI) {
|
||||
/// Emit the stackmap header.
|
||||
///
|
||||
/// Header {
|
||||
/// uint8 : Stack Map Version (currently 2)
|
||||
/// uint8 : Stack Map Version (currently 3)
|
||||
/// uint8 : Reserved (expected to be 0)
|
||||
/// uint16 : Reserved (expected to be 0)
|
||||
/// }
|
||||
|
86
test/tools/llvm-readobj/ELF/stackmap.test
Normal file
86
test/tools/llvm-readobj/ELF/stackmap.test
Normal file
@ -0,0 +1,86 @@
|
||||
## Here we test how the --stackmap option can be used to dump .llvm_stackmaps sections.
|
||||
|
||||
## Check we are able to dump an empty .llvm_stackmaps section. Document that
|
||||
## we are only trying to dump the first stack map section and ignore others if any.
|
||||
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: llvm-readobj %t --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf %t --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=warning:
|
||||
|
||||
# EMPTY: LLVM StackMap Version: 3
|
||||
# EMPTY-NEXT: Num Functions: 0
|
||||
# EMPTY-NEXT: Num Constants: 0
|
||||
# EMPTY-NEXT: Num Records: 0
|
||||
# EMPTY-NOT: {{.}}
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: [[NAME=.llvm_stackmaps]]
|
||||
Type: SHT_PROGBITS
|
||||
ContentArray: [ [[VERSION=0x3]] ]
|
||||
Size: [[SIZE=16]]
|
||||
ShSize: [[SHSIZE=<none>]]
|
||||
ShOffset: [[SHOFFSET=<none>]]
|
||||
## An arbitrary second broken .llvm_stackmaps section.
|
||||
- Name: .llvm_stackmaps (1)
|
||||
Type: SHT_PROGBITS
|
||||
ContentArray: [ 0xFF ]
|
||||
Size: 0x1
|
||||
|
||||
## Hide the first stack map section to allow dumpers to locate and validate the second one, which is broken.
|
||||
## Check we are able to find it and report a warning properly.
|
||||
|
||||
# RUN: yaml2obj %s -DNAME=.foo -o %t.second
|
||||
# RUN: llvm-readobj %t.second --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=SECOND -DFILE=%t.second --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf %t.second --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=SECOND -DFILE=%t.second --implicit-check-not=warning:
|
||||
|
||||
# SECOND: warning: '[[FILE]]': unable to read the stack map from SHT_PROGBITS section with index 2: the stack map section size (1) is less than the minimum possible size of its header (16)
|
||||
|
||||
## Check we report a warning when the size of the .llvm_stackmaps section is less
|
||||
## than the minimum possible size of its header.
|
||||
|
||||
# RUN: yaml2obj %s -DSHSIZE=0 -o %t.trunc0
|
||||
# RUN: llvm-readobj %t.trunc0 --stackmap 2>&1 | FileCheck %s -DFILE=%t.trunc0 --check-prefix=TRUNC -DVAL=0
|
||||
# RUN: llvm-readelf %t.trunc0 --stackmap 2>&1 | FileCheck %s -DFILE=%t.trunc0 --check-prefix=TRUNC -DVAL=0
|
||||
|
||||
# RUN: yaml2obj %s -DSIZE=1 -o %t.trunc1
|
||||
# RUN: llvm-readobj %t.trunc1 --stackmap 2>&1 | FileCheck %s -DFILE=%t.trunc1 --check-prefix=TRUNC -DVAL=1
|
||||
# RUN: llvm-readelf %t.trunc1 --stackmap 2>&1 | FileCheck %s -DFILE=%t.trunc1 --check-prefix=TRUNC -DVAL=1
|
||||
|
||||
# RUN: yaml2obj %s -DSIZE=15 -o %t.trunc15
|
||||
# RUN: llvm-readobj %t.trunc15 --stackmap 2>&1 | FileCheck %s -DFILE=%t.trunc15 --check-prefix=TRUNC -DVAL=15
|
||||
# RUN: llvm-readelf %t.trunc15 --stackmap 2>&1 | FileCheck %s -DFILE=%t.trunc15 --check-prefix=TRUNC -DVAL=15
|
||||
|
||||
# TRUNC: warning: '[[FILE]]': unable to read the stack map from SHT_PROGBITS section with index 1: the stack map section size ([[VAL]]) is less than the minimum possible size of its header (16)
|
||||
|
||||
## Check that we report a warning when the version of the stack map section is not supported.
|
||||
|
||||
# RUN: yaml2obj %s -DVERSION=2 -o %t.ver2
|
||||
# RUN: llvm-readobj %t.ver2 --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=VERSION -DFILE=%t.ver2 --implicit-check-not=warning: -DVERSION=2
|
||||
# RUN: llvm-readelf %t.ver2 --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=VERSION -DFILE=%t.ver2 --implicit-check-not=warning: -DVERSION=2
|
||||
|
||||
# RUN: yaml2obj %s -DVERSION=4 -o %t.ver4
|
||||
# RUN: llvm-readobj %t.ver4 --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=VERSION -DFILE=%t.ver4 --implicit-check-not=warning: -DVERSION=4
|
||||
# RUN: llvm-readelf %t.ver4 --stackmap 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=VERSION -DFILE=%t.ver4 --implicit-check-not=warning: -DVERSION=4
|
||||
|
||||
# VERSION: warning: '[[FILE]]': unable to read the stack map from SHT_PROGBITS section with index 1: the version ([[VERSION]]) of the stack map section is unsupported, the supported version is 3
|
||||
|
||||
## Check that we report a warning when we are unable to read the content of the stack map section.
|
||||
# RUN: yaml2obj %s -DSHOFFSET=0xffff -o %t.offset
|
||||
# RUN: llvm-readobj %t.offset --stackmap 2>&1 | FileCheck %s -DFILE=%t.offset --check-prefix=OFFSET
|
||||
# RUN: llvm-readelf %t.offset --stackmap 2>&1 | FileCheck %s -DFILE=%t.offset --check-prefix=OFFSET
|
||||
|
||||
# OFFSET: warning: '[[FILE]]': unable to read the stack map from SHT_PROGBITS section with index 1: section [index 1] has a sh_offset (0xffff) + sh_size (0x10) that is greater than the file size (0x1b8)
|
@ -60,10 +60,6 @@ using namespace llvm::codeview;
|
||||
using namespace llvm::support;
|
||||
using namespace llvm::Win64EH;
|
||||
|
||||
static inline Error createError(const Twine &Err) {
|
||||
return make_error<StringError>(Err, object_error::parse_failed);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct LoadConfigTables {
|
||||
|
@ -3423,24 +3423,30 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {
|
||||
|
||||
template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
|
||||
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
|
||||
const Elf_Shdr *StackMapSection = nullptr;
|
||||
for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
|
||||
StringRef Name =
|
||||
unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec));
|
||||
if (Name == ".llvm_stackmaps") {
|
||||
StackMapSection = &Sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const Elf_Shdr *StackMapSection = findSectionByName(".llvm_stackmaps");
|
||||
if (!StackMapSection)
|
||||
return;
|
||||
|
||||
ArrayRef<uint8_t> StackMapContentsArray = unwrapOrError(
|
||||
ObjF->getFileName(), Obj->getSectionContents(StackMapSection));
|
||||
auto Warn = [&](Error &&E) {
|
||||
this->reportUniqueWarning(createError("unable to read the stack map from " +
|
||||
describe(*StackMapSection) + ": " +
|
||||
toString(std::move(E))));
|
||||
};
|
||||
|
||||
prettyPrintStackMap(
|
||||
W, StackMapParser<ELFT::TargetEndianness>(StackMapContentsArray));
|
||||
Expected<ArrayRef<uint8_t>> ContentOrErr =
|
||||
Obj->getSectionContents(StackMapSection);
|
||||
if (!ContentOrErr) {
|
||||
Warn(ContentOrErr.takeError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (Error E = StackMapParser<ELFT::TargetEndianness>::validateHeader(
|
||||
*ContentOrErr)) {
|
||||
Warn(std::move(E));
|
||||
return;
|
||||
}
|
||||
|
||||
prettyPrintStackMap(W, StackMapParser<ELFT::TargetEndianness>(*ContentOrErr));
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFDumper<ELFT>::printGroupSections() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user