[llvm] r367942 - [llvm-readelf] Support dumping of stack sizes sections with readelf --stack-sizes
Wolfgang Pieb via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 5 15:47:07 PDT 2019
Author: wolfgangp
Date: Mon Aug 5 15:47:07 2019
New Revision: 367942
URL: http://llvm.org/viewvc/llvm-project?rev=367942&view=rev
Log:
[llvm-readelf] Support dumping of stack sizes sections with readelf --stack-sizes
Reviewers: jhenderson, grimar, rupprecht
Differential Revision: https://reviews.llvm.org/D65313
Added:
llvm/trunk/test/tools/llvm-readobj/stack-sizes.test
Modified:
llvm/trunk/docs/CommandGuide/llvm-readelf.rst
llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
llvm/trunk/tools/llvm-readobj/ObjDumper.h
llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
Modified: llvm/trunk/docs/CommandGuide/llvm-readelf.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-readelf.rst?rev=367942&r1=367941&r2=367942&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/llvm-readelf.rst (original)
+++ llvm/trunk/docs/CommandGuide/llvm-readelf.rst Mon Aug 5 15:47:07 2019
@@ -160,6 +160,11 @@ OPTIONS
Display contents of the stackmap section.
+.. option:: --stack-sizes
+
+ Display the contents of the stack sizes section(s), i.e. pairs of function
+ names and the size of their stack frames.
+
.. option:: --string-dump=<section[,section,...]>, -p
Display the specified section(s) as a list of strings. ``section`` may be a
Added: llvm/trunk/test/tools/llvm-readobj/stack-sizes.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/stack-sizes.test?rev=367942&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/stack-sizes.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/stack-sizes.test Mon Aug 5 15:47:07 2019
@@ -0,0 +1,473 @@
+## Check that we correctly display the contents of the .stack_sizes section
+## in a relocatable object file.
+
+# RUN: yaml2obj --docnum=1 %s > %t01
+# RUN: llvm-readelf --stack-sizes %t01 \
+# RUN: | FileCheck %s --check-prefix=RELOC --strict-whitespace --match-full-lines
+
+# RELOC: Size Function
+# RELOC-NEXT: 16 referenced_by_symbol_foo
+# RELOC-NEXT: 32 referenced_via_section_bar
+# RELOC-NEXT: 8 separate_text_section_baz
+# RELOC-NOT:{{.}}
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Size: 16
+ - Name: .text.baz
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Size: 16
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+## 2 stack size entries. Each consists of an address (subject to relocation)
+## followed by a ULEB for the size.
+ Content: "000000000000000010000000000000000020"
+ Link: .text
+ - Name: .stack_sizes.baz
+ Type: SHT_PROGBITS
+## One stack size entry.
+ Content: "200000000000000008"
+ Link: .text.baz
+ - Name: .rela.stack_sizes
+ Type: SHT_RELA
+ Info: .stack_sizes
+ Relocations:
+## A symbol relative reference.
+ - Offset: 0
+ Symbol: referenced_by_symbol_foo
+ Type: R_X86_64_64
+## A section relative reference.
+ - Offset: 9
+ Addend: 16
+ Symbol: .text
+ Type: R_X86_64_64
+ - Name: .rela.stack_sizes.baz
+ Type: SHT_RELA
+ Info: .stack_sizes.baz
+ Relocations:
+ - Offset: 0
+ Symbol: separate_text_section_baz
+ Type: R_X86_64_64
+Symbols:
+ - Name: separate_text_section_baz
+ Section: .text.baz
+ Type: STT_FUNC
+ - Name: .text
+ Section: .text
+ Type: STT_SECTION
+ - Name: referenced_by_symbol_foo
+ Section: .text
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+ - Name: referenced_via_section_bar
+ Section: .text
+ Value: 0x10
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we correctly report the stack sizes in an executable (non-relocatable)
+## object file.
+
+# RUN: yaml2obj --docnum=2 %s > %t02
+# RUN: llvm-readelf --stack-sizes %t02 \
+# RUN: | FileCheck %s --check-prefix=EXEC --strict-whitespace --match-full-lines
+
+# EXEC: Size Function
+# EXEC-NEXT: 16 foo
+# EXEC-NEXT: 32 bar
+# EXEC-NOT:{{.}}
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Size: 16
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Content: "100000000000000010200000000000000020"
+ Link: .text
+Symbols:
+ - Name: foo
+ Section: .text
+ Value: 0x10
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+ - Name: bar
+ Section: .text
+ Value: 0x20
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we report an error when we find relocations whose offsets point outside
+## of the .stack_sizes section.
+
+# RUN: yaml2obj --docnum=3 %s > %t03
+# RUN: not llvm-readelf --stack-sizes %t03 2>&1 | FileCheck %s --check-prefix=SHORT -DFILE=%t03
+
+# SHORT: error: '[[FILE]]': found invalid relocation offset into section .stack_sizes while trying to extract a stack size entry
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Size: 16
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Size: 1
+ Link: .text
+ - Name: .rela.stack_sizes
+ Type: SHT_RELA
+ Info: .stack_sizes
+ Relocations:
+ - Offset: 1
+ Symbol: foo
+ Type: R_X86_64_64
+Symbols:
+ - Name: foo
+ Section: .text
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we warn about a function symbol that is not in the section
+## that is referenced by the stack sizes section's sh_link.
+
+# RUN: yaml2obj --docnum=4 %s > %t04
+# RUN: llvm-readelf --stack-sizes %t04 2> %t04.err | FileCheck %s --check-prefix=WRONGSECTION
+# RUN: FileCheck %s < %t04.err --check-prefix=WRONGSECTION-ERR -DFILE=%t04
+
+# WRONGSECTION: Size Function
+# WRONGSECTION-NEXT: 8 foo
+# WRONGSECTION-ERR: warning: '[[FILE]]': relocation symbol foo is not in the expected section
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ - Name: .text2
+ Type: SHT_PROGBITS
+ Size: 8
+ Flags: [SHF_ALLOC]
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Content: "000000000000000008"
+ Link: .text2
+ - Name: .rela.stack_sizes
+ Type: SHT_RELA
+ Info: .stack_sizes
+ Relocations:
+ - Offset: 0
+ Symbol: foo
+ Type: R_X86_64_64
+Symbols:
+ - Name: foo
+ Section: .text
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we report an error when a stack sizes section ends with an incomplete stack size entry.
+
+# RUN: yaml2obj --docnum=5 %s > %t05
+# RUN: not llvm-readelf --stack-sizes %t05 2>&1 %t05.err | \
+# RUN: FileCheck %s --check-prefix=SUDDENEND -DFILE=%t05
+
+# SUDDENEND: error: '[[FILE]]': section .stack_sizes ended while trying to extract a stack size entry
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Size: 16
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Content: "10000000"
+ Link: .text
+Symbols:
+ - Name: foo
+ Section: .text
+ Value: 0x10
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we report an invalid stack size, which is represented by a ULEB that
+## ends in a byte with the high bit set.
+
+# RUN: yaml2obj --docnum=6 %s > %t06
+# RUN: not llvm-readelf --stack-sizes %t06 2>&1 | FileCheck %s --check-prefix=BADSIZE -DFILE=%t06
+
+# BADSIZE: error: '[[FILE]]': could not extract a valid stack size in section .stack_sizes
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Size: 16
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Content: "100000000000000080"
+ Link: .text
+Symbols:
+ - Name: foo
+ Section: .text
+ Value: 0x10
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we report a warning when a relocation symbol does not belong to a
+## valid section. We expect a stack size entry with an unknown symbol in the
+## output.
+
+# RUN: yaml2obj --docnum=7 %s > %t07
+# RUN: llvm-readelf --stack-sizes %t07 2> %t07.err | FileCheck %s --check-prefix=BADSECTION-OUT
+# RUN: FileCheck %s < %t07.err --check-prefix=BADSECTION-ERR -DFILE=%t07
+
+# BADSECTION-OUT: Size Function
+# BADSECTION-OUT: 8 ?
+# BADSECTION-ERR: warning: '[[FILE]]': cannot identify the section for relocation symbol foo
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Link: .text
+ Content: "000000000000000008"
+ - Name: .rela.stack_sizes
+ Type: SHT_RELA
+ Info: .stack_sizes
+ Relocations:
+ - Offset: 0
+ Symbol: foo
+ Type: R_X86_64_64
+Symbols:
+ - Name: foo
+## An invalid section index.
+ Index: 10
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we report a warning when a stack sizes section does not come with
+## a corresponding relocation section.
+
+# RUN: yaml2obj --docnum=8 %s > %t08
+# RUN: llvm-readelf --stack-sizes %t08 2> %t08.err | FileCheck %s --check-prefix=NORELOCSECTION-OUT
+# RUN: FileCheck %s < %t08.err --check-prefix=NORELOCSECTION-ERR -DFILE=%t08
+
+# NORELOCSECTION-OUT: Size Function
+# NORELOCSECTION-OUT-NOT: {{.}}
+# NORELOCSECTION-ERR: warning: '[[FILE]]': section .stack_sizes does not have a corresponding relocation section
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Link: .text
+ Content: "000000000000000008"
+
+## Check that we handle multiple object files, separately and when they
+## are in an archive. This also checks whether we have blank lines between the
+## tables.
+
+# RUN: llvm-ar rc %t1.a %t01 %t02
+# RUN: llvm-readelf --stack-sizes %t01 %t02 | FileCheck %s --check-prefix=MULTIPLE
+# RUN: llvm-readelf --stack-sizes %t1.a \
+# RUN: | FileCheck %s --check-prefix=MULTIPLE --check-prefix=ARCHIVE --strict-whitespace\
+# RUN: --match-full-lines -DFILE=%t1.a
+
+# ARCHIVE:File: [[FILE]]({{.*01}})
+# MULTIPLE:Stack Sizes:
+# MULTIPLE-NEXT: Size Function
+# MULTIPLE-NEXT: 16 referenced_by_symbol_foo
+# MULTIPLE-NEXT: 32 referenced_via_section_bar
+# MULTIPLE-NEXT: 8 separate_text_section_baz
+# MULTIPLE-EMPTY:
+# ARCHIVE:File: [[FILE]]({{.*02}})
+# MULTIPLE-EMPTY:
+# MULTIPLE-NEXT:Stack Sizes:
+# MULTIPLE-NEXT: Size Function
+# MULTIPLE-NEXT: 16 foo
+# MULTIPLE-NEXT: 32 bar
+
+## Check that we do not consider symbols that are not function symbols, even though
+## a relocation references them.
+
+# RUN: yaml2obj --docnum=9 %s > %t14
+# RUN: llvm-readelf --stack-sizes %t14 2> %t14.err | FileCheck %s --check-prefix=NONFUNCTIONSYM
+# RUN: FileCheck %s < %t14.err --check-prefix=NONFUNCTIONSYM-ERR -DFILE=%t14
+
+# NONFUNCTIONSYM: Stack Sizes:
+# NONFUNCTIONSYM: 0 ?
+# NONFUNCTIONSYM-ERR: warning: '[[FILE]]': could not identify function symbol for stack size entry
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 16
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Size: 9
+ Link: .text
+ - Name: .rela.stack_sizes
+ Type: SHT_RELA
+ Info: .stack_sizes
+ Relocations:
+ - Offset: 0
+ Symbol: foo
+ Type: R_X86_64_64
+Symbols:
+ - Name: foo
+ Section: .text
+ Type: STT_OBJECT
+ Binding: STB_GLOBAL
+
+## Check that we report an error when we find an unsupported relocation
+## in the section that contains the stack size entries' relocations.
+
+# RUN: yaml2obj --docnum=10 %s > %t15
+# RUN: not llvm-readelf --stack-sizes %t15 2>&1 | FileCheck %s --check-prefix=UNSUPPRELOC -DFILE=%t15
+
+# UNSUPPRELOC: error: '[[FILE]]': unsupported relocation type in section .rela.stack_sizes: R_X86_64_RELATIVE
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Size: 16
+ Link: .text
+ - Name: .rela.stack_sizes
+ Type: SHT_RELA
+ Info: .stack_sizes
+ Relocations:
+ - Offset: 0
+ Symbol: foo
+ Type: R_X86_64_RELATIVE
+Symbols:
+ - Name: foo
+ Section: .text
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that warning messages in archives do not impact other members. In the following
+## test, the first archive member generates a warning and we make sure all the information
+## is still dumped.
+
+# RUN: llvm-ar rc %t2.a %t04 %t01
+# RUN: llvm-readelf --stack-sizes %t2.a 2>&1 | FileCheck %s --check-prefix=ARCHIVEWARN \
+# RUN: -DFILE=%t2.a --strict-whitespace --match-full-lines
+
+# ARCHIVEWARN:File: [[FILE]]({{.*04}})
+# ARCHIVEWARN:Stack Sizes:
+# ARCHIVEWARN-NEXT: Size Function
+# ARCHIVEWARN: 8 foo
+# ARCHIVEWARN:File: [[FILE]]({{.*01}})
+# ARCHIVEWARN:Stack Sizes:
+# ARCHIVEWARN-NEXT: Size Function
+# ARCHIVEWARN-NEXT: 16 referenced_by_symbol_foo
+# ARCHIVEWARN-NEXT: 32 referenced_via_section_bar
+# ARCHIVEWARN-NEXT: 8 separate_text_section_baz
+# ARCHIVEWARN-NOT:{{.}}
+# ARCHIVEWARN-ERR:warning: '[[FILE]]': relocation symbol foo is not in the expected section
+
+## Check that we demangle function names when requested.
+
+# RUN: yaml2obj --docnum=11 %s > %t16
+# RUN: llvm-readelf --stack-sizes --demangle %t16 | FileCheck %s --check-prefix=DEMANGLE
+
+# DEMANGLE: 16 foo(float)
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Size: 16
+ - Name: .stack_sizes
+ Type: SHT_PROGBITS
+ Content: "100000000000000010"
+ Link: .text
+Symbols:
+ - Name: _Z3foof
+ Section: .text
+ Value: 0x10
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+
+## Check that we emit a 'not implemented' message for an attempt to dump stack-sizes
+## sections LLVM-style, i.e. when invoking llvm-readobj.
+## FIXME: Replace this test with something functional when the feature is implemented.
+
+# RUN: llvm-readobj --stack-sizes %t01 | FileCheck %s --check-prefix=NOTIMPLEMENTED
+
+# NOTIMPLEMENTED: Dumping of stack sizes in LLVM style is not implemented yet
Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=367942&r1=367941&r2=367942&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Mon Aug 5 15:47:07 2019
@@ -20,6 +20,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
@@ -36,6 +37,7 @@
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/RelocationResolver.h"
#include "llvm/Object/StackMapParser.h"
#include "llvm/Support/AMDGPUMetadata.h"
#include "llvm/Support/ARMAttributeParser.h"
@@ -182,6 +184,7 @@ public:
void printNotes() override;
void printELFLinkerOptions() override;
+ void printStackSizes() override;
const object::ELFObjectFile<ELFT> *getElfObject() const { return ObjF; };
@@ -347,6 +350,7 @@ template <typename ELFT> class DumpStyle
public:
using Elf_Shdr = typename ELFT::Shdr;
using Elf_Sym = typename ELFT::Sym;
+ using Elf_Addr = typename ELFT::Addr;
DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {}
virtual ~DumpStyle() = default;
@@ -379,6 +383,20 @@ public:
virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printStackSizes(const ELFObjectFile<ELFT> *Obj) = 0;
+ void printNonRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj,
+ std::function<void()> PrintHeader);
+ void printRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj,
+ std::function<void()> PrintHeader);
+ void printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, uint64_t SymValue,
+ SectionRef FunctionSec,
+ const StringRef SectionName, DataExtractor Data,
+ uint64_t *Offset);
+ void printStackSize(const ELFObjectFile<ELFT> *Obj, RelocationRef Rel,
+ SectionRef FunctionSec,
+ const StringRef &StackSizeSectionName,
+ const RelocationResolver &Resolver, DataExtractor Data);
+ virtual void printStackSizeEntry(uint64_t Size, StringRef FuncName) = 0;
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
@@ -423,6 +441,8 @@ public:
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
+ void printStackSizes(const ELFObjectFile<ELFT> *Obj) override;
+ void printStackSizeEntry(uint64_t Size, StringRef FuncName) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -526,6 +546,8 @@ public:
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
+ void printStackSizes(const ELFObjectFile<ELFT> *Obj) override;
+ void printStackSizeEntry(uint64_t Size, StringRef FuncName) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -1715,6 +1737,10 @@ template <class ELFT> void ELFDumper<ELF
ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile());
}
+template <class ELFT> void ELFDumper<ELFT>::printStackSizes() {
+ ELFDumperStyle->printStackSizes(ObjF);
+}
+
#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \
{ #enum, prefix##_##enum }
@@ -4357,6 +4383,296 @@ void GNUStyle<ELFT>::printELFLinkerOptio
OS << "printELFLinkerOptions not implemented!\n";
}
+// FIXME: As soon as the DataExtractor interface handles uint64_t *, this
+// should be eliminated. See upstream review https://reviews.llvm.org/D64006.
+inline uint32_t *AdjustPtr(uint64_t *Offset) {
+ uint32_t *Ptr = reinterpret_cast<uint32_t *>(Offset);
+ if (sys::IsBigEndianHost)
+ Ptr++;
+ return Ptr;
+}
+
+template <class ELFT>
+void DumpStyle<ELFT>::printFunctionStackSize(
+ const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, SectionRef FunctionSec,
+ const StringRef SectionName, DataExtractor Data, uint64_t *Offset) {
+ // This function ignores potentially erroneous input, unless it is directly
+ // related to stack size reporting.
+ SymbolRef FuncSym;
+ for (const ELFSymbolRef &Symbol : Obj->symbols()) {
+ Expected<uint64_t> SymAddrOrErr = Symbol.getAddress();
+ if (!SymAddrOrErr) {
+ consumeError(SymAddrOrErr.takeError());
+ continue;
+ }
+ if (Symbol.getELFType() == ELF::STT_FUNC && *SymAddrOrErr == SymValue) {
+ // Check if the symbol is in the right section.
+ if (FunctionSec.containsSymbol(Symbol)) {
+ FuncSym = Symbol;
+ break;
+ }
+ }
+ }
+
+ StringRef FileStr = Obj->getFileName();
+ std::string FuncName = "?";
+ // A valid SymbolRef has a non-null object file pointer.
+ if (FuncSym.BasicSymbolRef::getObject()) {
+ // Extract the symbol name.
+ Expected<StringRef> FuncNameOrErr = FuncSym.getName();
+ if (FuncNameOrErr)
+ FuncName = maybeDemangle(*FuncNameOrErr);
+ else
+ consumeError(FuncNameOrErr.takeError());
+ } else
+ reportWarning(" '" + FileStr +
+ "': could not identify function symbol for stack size entry");
+
+ // Extract the size. The expectation is that Offset is pointing to the right
+ // place, i.e. past the function address.
+ uint64_t PrevOffset = *Offset;
+ uint64_t StackSize = Data.getULEB128(AdjustPtr(Offset));
+ // getULEB128() does not advance Offset if it is not able to extract a valid
+ // integer.
+ if (*Offset == PrevOffset)
+ reportError(
+ FileStr,
+ createStringError(object_error::parse_failed,
+ "could not extract a valid stack size in section %s",
+ SectionName.data()));
+
+ printStackSizeEntry(StackSize, FuncName);
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) {
+ OS.PadToColumn(2);
+ OS << format_decimal(Size, 11);
+ OS.PadToColumn(18);
+ OS << FuncName << "\n";
+}
+
+template <class ELFT>
+void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj,
+ RelocationRef Reloc,
+ SectionRef FunctionSec,
+ const StringRef &StackSizeSectionName,
+ const RelocationResolver &Resolver,
+ DataExtractor Data) {
+ // This function ignores potentially erroneous input, unless it is directly
+ // related to stack size reporting.
+ object::symbol_iterator RelocSym = Reloc.getSymbol();
+ uint64_t RelocSymValue = 0;
+ StringRef FileStr = Obj->getFileName();
+ if (RelocSym != Obj->symbol_end()) {
+ // Ensure that the relocation symbol is in the function section, i.e. the
+ // section where the functions whose stack sizes we are reporting are
+ // located.
+ StringRef SymName = "?";
+ Expected<StringRef> NameOrErr = RelocSym->getName();
+ if (NameOrErr)
+ SymName = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
+ auto SectionOrErr = RelocSym->getSection();
+ if (!SectionOrErr) {
+ reportWarning(" '" + FileStr +
+ "': cannot identify the section for relocation symbol " +
+ SymName);
+ consumeError(SectionOrErr.takeError());
+ } else if (*SectionOrErr != FunctionSec) {
+ reportWarning(" '" + FileStr + "': relocation symbol " + SymName +
+ " is not in the expected section");
+ // Pretend that the symbol is in the correct section and report its
+ // stack size anyway.
+ FunctionSec = **SectionOrErr;
+ }
+
+ Expected<uint64_t> RelocSymValueOrErr = RelocSym->getValue();
+ if (RelocSymValueOrErr)
+ RelocSymValue = *RelocSymValueOrErr;
+ else
+ consumeError(RelocSymValueOrErr.takeError());
+ }
+
+ uint64_t Offset = Reloc.getOffset();
+ if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1))
+ reportError(FileStr, createStringError(
+ object_error::parse_failed,
+ "found invalid relocation offset into section %s "
+ "while trying to extract a stack size entry",
+ StackSizeSectionName.data()));
+
+ uint64_t Addend = Data.getAddress(AdjustPtr(&Offset));
+ uint64_t SymValue = Resolver(Reloc, RelocSymValue, Addend);
+ this->printFunctionStackSize(Obj, SymValue, FunctionSec, StackSizeSectionName,
+ Data, &Offset);
+}
+
+template <class ELFT>
+SectionRef toSectionRef(const ObjectFile *Obj, const typename ELFT::Shdr *Sec) {
+ DataRefImpl DRI;
+ DRI.p = reinterpret_cast<uintptr_t>(Sec);
+ return SectionRef(DRI, Obj);
+}
+
+template <class ELFT>
+void DumpStyle<ELFT>::printNonRelocatableStackSizes(
+ const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) {
+ // This function ignores potentially erroneous input, unless it is directly
+ // related to stack size reporting.
+ const ELFFile<ELFT> *EF = Obj->getELFFile();
+ StringRef FileStr = Obj->getFileName();
+ for (const SectionRef &Sec : Obj->sections()) {
+ StringRef SectionName;
+ Sec.getName(SectionName);
+ const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl());
+ if (!SectionName.startswith(".stack_sizes"))
+ continue;
+ PrintHeader();
+ ArrayRef<uint8_t> Contents = unwrapOrError(EF->getSectionContents(ElfSec));
+ DataExtractor Data(
+ StringRef(reinterpret_cast<const char *>(Contents.data()),
+ Contents.size()),
+ Obj->isLittleEndian(), sizeof(Elf_Addr));
+ // A .stack_sizes section header's sh_link field is supposed to point
+ // to the section that contains the functions whose stack sizes are
+ // described in it.
+ const Elf_Shdr *FunctionELFSec =
+ unwrapOrError(EF->getSection(ElfSec->sh_link));
+ uint64_t Offset = 0;
+ while (Offset < Contents.size()) {
+ // The function address is followed by a ULEB representing the stack
+ // size. Check for an extra byte before we try to process the entry.
+ if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) {
+ reportError(
+ FileStr,
+ createStringError(
+ object_error::parse_failed,
+ "section %s ended while trying to extract a stack size entry",
+ SectionName.data()));
+ }
+ uint64_t SymValue = Data.getAddress(AdjustPtr(&Offset));
+ printFunctionStackSize(Obj, SymValue,
+ toSectionRef<ELFT>(Obj, FunctionELFSec),
+ SectionName, Data, &Offset);
+ }
+ }
+}
+
+template <class ELFT>
+void DumpStyle<ELFT>::printRelocatableStackSizes(
+ const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) {
+ const ELFFile<ELFT> *EF = Obj->getELFFile();
+ StringRef FileStr = Obj->getFileName();
+ // Build a map between stack size sections and their corresponding relocation
+ // sections.
+ llvm::MapVector<SectionRef, SectionRef> StackSizeRelocMap;
+ const SectionRef NullSection;
+
+ for (const SectionRef &Sec : Obj->sections()) {
+ StringRef SectionName;
+ Sec.getName(SectionName);
+ // A stack size section that we haven't encountered yet is mapped to the
+ // null section until we find its corresponding relocation section.
+ if (SectionName.startswith(".stack_sizes"))
+ if (StackSizeRelocMap.count(Sec) == 0) {
+ StackSizeRelocMap[Sec] = NullSection;
+ continue;
+ }
+
+ // Check relocation sections if they are relocating contents of a
+ // stack sizes section.
+ const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl());
+ uint32_t SectionType = ElfSec->sh_type;
+ if (SectionType != ELF::SHT_RELA && SectionType != ELF::SHT_REL)
+ continue;
+
+ SectionRef Contents = *Sec.getRelocatedSection();
+ const Elf_Shdr *ContentsSec = Obj->getSection(Contents.getRawDataRefImpl());
+ Expected<StringRef> ContentsSectionNameOrErr =
+ EF->getSectionName(ContentsSec);
+ if (!ContentsSectionNameOrErr) {
+ consumeError(ContentsSectionNameOrErr.takeError());
+ continue;
+ }
+ if (!ContentsSectionNameOrErr->startswith(".stack_sizes"))
+ continue;
+ // Insert a mapping from the stack sizes section to its relocation section.
+ StackSizeRelocMap[toSectionRef<ELFT>(Obj, ContentsSec)] = Sec;
+ }
+
+ for (const auto &StackSizeMapEntry : StackSizeRelocMap) {
+ PrintHeader();
+ const SectionRef &StackSizesSec = StackSizeMapEntry.first;
+ const SectionRef &RelocSec = StackSizeMapEntry.second;
+
+ // Warn about stack size sections without a relocation section.
+ StringRef StackSizeSectionName;
+ StackSizesSec.getName(StackSizeSectionName);
+ if (RelocSec == NullSection) {
+ reportWarning(" '" + FileStr + "': section " + StackSizeSectionName +
+ " does not have a corresponding "
+ "relocation section");
+ continue;
+ }
+
+ // A .stack_sizes section header's sh_link field is supposed to point
+ // to the section that contains the functions whose stack sizes are
+ // described in it.
+ const Elf_Shdr *StackSizesELFSec =
+ Obj->getSection(StackSizesSec.getRawDataRefImpl());
+ const SectionRef FunctionSec = toSectionRef<ELFT>(
+ Obj, unwrapOrError(EF->getSection(StackSizesELFSec->sh_link)));
+
+ bool (*IsSupportedFn)(uint64_t);
+ RelocationResolver Resolver;
+ std::tie(IsSupportedFn, Resolver) = getRelocationResolver(*Obj);
+ auto Contents = unwrapOrError(StackSizesSec.getContents());
+ DataExtractor Data(
+ StringRef(reinterpret_cast<const char *>(Contents.data()),
+ Contents.size()),
+ Obj->isLittleEndian(), sizeof(Elf_Addr));
+ for (const RelocationRef &Reloc : RelocSec.relocations()) {
+ if (!IsSupportedFn(Reloc.getType())) {
+ StringRef RelocSectionName;
+ RelocSec.getName(RelocSectionName);
+ StringRef RelocName = EF->getRelocationTypeName(Reloc.getType());
+ reportError(
+ FileStr,
+ createStringError(object_error::parse_failed,
+ "unsupported relocation type in section %s: %s",
+ RelocSectionName.data(), RelocName.data()));
+ }
+ this->printStackSize(Obj, Reloc, FunctionSec, StackSizeSectionName,
+ Resolver, Data);
+ }
+ }
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) {
+ bool HeaderHasBeenPrinted = false;
+ auto PrintHeader = [&]() {
+ if (HeaderHasBeenPrinted)
+ return;
+ OS << "\nStack Sizes:\n";
+ OS.PadToColumn(9);
+ OS << "Size";
+ OS.PadToColumn(18);
+ OS << "Function\n";
+ HeaderHasBeenPrinted = true;
+ };
+
+ // For non-relocatable objects, look directly for sections whose name starts
+ // with .stack_sizes and process the contents.
+ if (Obj->isRelocatableObject())
+ this->printRelocatableStackSizes(Obj, PrintHeader);
+ else
+ this->printNonRelocatableStackSizes(Obj, PrintHeader);
+}
+
template <class ELFT>
void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
size_t Bias = ELFT::Is64Bits ? 8 : 0;
@@ -5223,6 +5539,17 @@ void LLVMStyle<ELFT>::printELFLinkerOpti
}
template <class ELFT>
+void LLVMStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) {
+ W.printString(
+ "Dumping of stack sizes in LLVM style is not implemented yet\n");
+}
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) {
+ // FIXME: Implement this function for LLVM-style dumping.
+}
+
+template <class ELFT>
void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
auto PrintEntry = [&](const Elf_Addr *E) {
W.printHex("Address", Parser.getGotAddress(E));
Modified: llvm/trunk/tools/llvm-readobj/ObjDumper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ObjDumper.h?rev=367942&r1=367941&r2=367942&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ObjDumper.h (original)
+++ llvm/trunk/tools/llvm-readobj/ObjDumper.h Mon Aug 5 15:47:07 2019
@@ -68,6 +68,7 @@ public:
virtual void printAddrsig() {}
virtual void printNotes() {}
virtual void printELFLinkerOptions() {}
+ virtual void printStackSizes() {}
// Only implemented for ARM ELF at this time.
virtual void printAttributes() { }
Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=367942&r1=367941&r2=367942&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Mon Aug 5 15:47:07 2019
@@ -324,6 +324,11 @@ namespace opts {
PrintStackMap("stackmap",
cl::desc("Display contents of stackmap section"));
+ // --stack-sizes
+ cl::opt<bool>
+ PrintStackSizes("stack-sizes",
+ cl::desc("Display contents of all stack sizes sections"));
+
// --version-info, -V
cl::opt<bool>
VersionInfo("version-info",
@@ -583,6 +588,8 @@ static void dumpObject(const ObjectFile
}
if (opts::PrintStackMap)
Dumper->printStackMap();
+ if (opts::PrintStackSizes)
+ Dumper->printStackSizes();
}
/// Dumps each object file in \a Arc;
@@ -727,6 +734,10 @@ int main(int argc, const char *argv[]) {
opts::UnwindInfo = true;
opts::SectionGroups = true;
opts::HashHistogram = true;
+ // FIXME: As soon as we implement LLVM-style printing of the .stack_size
+ // section, we will enable it with --all (only for LLVM-style).
+ if (opts::Output == opts::LLVM)
+ opts::PrintStackSizes = false;
}
if (opts::Headers) {
More information about the llvm-commits
mailing list