[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