[llvm] f97019a - [llvm-readobj/elf] - Add a testing for --stackmap and refine the implementation.
Georgii Rymar via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 03:09:34 PDT 2020
Author: Georgii Rymar
Date: 2020-08-05T13:09:04+03:00
New Revision: f97019ad6e3a96995dda3f759ee692eb81abcc4c
URL: https://github.com/llvm/llvm-project/commit/f97019ad6e3a96995dda3f759ee692eb81abcc4c
DIFF: https://github.com/llvm/llvm-project/commit/f97019ad6e3a96995dda3f759ee692eb81abcc4c.diff
LOG: [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
Added:
llvm/test/tools/llvm-readobj/ELF/stackmap.test
Modified:
llvm/include/llvm/Object/StackMapParser.h
llvm/lib/CodeGen/StackMaps.cpp
llvm/tools/llvm-readobj/COFFDumper.cpp
llvm/tools/llvm-readobj/ELFDumper.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Object/StackMapParser.h b/llvm/include/llvm/Object/StackMapParser.h
index b408f4041034..83926c6471c0 100644
--- a/llvm/include/llvm/Object/StackMapParser.h
+++ b/llvm/include/llvm/Object/StackMapParser.h
@@ -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 @@ class StackMapParser {
}
}
+ /// 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>;
diff --git a/llvm/lib/CodeGen/StackMaps.cpp b/llvm/lib/CodeGen/StackMaps.cpp
index 1e060ecbeb43..113d477ec80a 100644
--- a/llvm/lib/CodeGen/StackMaps.cpp
+++ b/llvm/lib/CodeGen/StackMaps.cpp
@@ -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)
/// }
diff --git a/llvm/test/tools/llvm-readobj/ELF/stackmap.test b/llvm/test/tools/llvm-readobj/ELF/stackmap.test
new file mode 100644
index 000000000000..22a1bd1bef8d
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/stackmap.test
@@ -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)
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 89a904f53ae7..39549efc040c 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -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 {
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 53ebfd5663c9..78d47b540ab6 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -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))));
+ };
+
+ 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>(StackMapContentsArray));
+ prettyPrintStackMap(W, StackMapParser<ELFT::TargetEndianness>(*ContentOrErr));
}
template <class ELFT> void ELFDumper<ELFT>::printGroupSections() {
More information about the llvm-commits
mailing list