1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02: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:
Georgii Rymar 2020-08-04 15:19:36 +03:00
parent eacb852738
commit af54a4ae5b
5 changed files with 125 additions and 19 deletions

View File

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

View File

@ -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)
/// }

View 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)

View File

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

View File

@ -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() {