[llvm] f855a55 - [llvm-readelf] - Implement --section-details option.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 27 03:30:07 PDT 2020


Author: Georgii Rymar
Date: 2020-10-27T13:29:39+03:00
New Revision: f855a553339aa78225a309a6f9b5fcae767de8da

URL: https://github.com/llvm/llvm-project/commit/f855a553339aa78225a309a6f9b5fcae767de8da
DIFF: https://github.com/llvm/llvm-project/commit/f855a553339aa78225a309a6f9b5fcae767de8da.diff

LOG: [llvm-readelf] - Implement --section-details option.

--section-details/-t is a GNU readelf option that produce
an output that is an alternative to --sections.

Differential revision: https://reviews.llvm.org/D89304

Added: 
    llvm/test/tools/llvm-readobj/ELF/section-details.test

Modified: 
    llvm/docs/CommandGuide/llvm-readelf.rst
    llvm/test/tools/llvm-readobj/ELF/symbols.test
    llvm/test/tools/llvm-readobj/basic.test
    llvm/tools/llvm-readobj/ELFDumper.cpp
    llvm/tools/llvm-readobj/ObjDumper.h
    llvm/tools/llvm-readobj/llvm-readobj.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-readelf.rst b/llvm/docs/CommandGuide/llvm-readelf.rst
index fa54c1dc84dc..b566ad2ff5bc 100644
--- a/llvm/docs/CommandGuide/llvm-readelf.rst
+++ b/llvm/docs/CommandGuide/llvm-readelf.rst
@@ -142,6 +142,10 @@ OPTIONS
  When used with :option:`--sections`, display section data for each section
  shown. This option has no effect for GNU style output.
 
+.. option:: --section-details, -t
+
+ Display all section details. Used as an alternative to :option:`--sections`.
+
 .. option:: --section-mapping
 
  Display the section to segment mapping.

diff  --git a/llvm/test/tools/llvm-readobj/ELF/section-details.test b/llvm/test/tools/llvm-readobj/ELF/section-details.test
new file mode 100644
index 000000000000..fe1f1840c157
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/section-details.test
@@ -0,0 +1,256 @@
+## Check how llvm-readelf prints section details with --section-details.
+
+## Check the output for the 64-bit case.
+# RUN: yaml2obj %s -DBITS=64 -o %t64.o
+# RUN: llvm-readelf %t64.o --section-details | \
+# RUN:   FileCheck %s --strict-whitespace --match-full-lines --check-prefix=GNU64
+
+#       GNU64:There are 19 section headers, starting at offset 0xf8:
+# GNU64-EMPTY:
+#  GNU64-NEXT:Section Headers:
+#  GNU64-NEXT:  [Nr] Name
+#  GNU64-NEXT:       Type            Address          Off    Size   ES   Lk Inf Al
+#  GNU64-NEXT:       Flags
+#  GNU64-NEXT:  [ 0] {{$}}
+#  GNU64-NEXT:       NULL            0000000000000000 000000 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000000]: {{$}}
+#  GNU64-NEXT:  [ 1] allflags_and_long_fields
+#  GNU64-NEXT:       PROGBITS        1111111111111111 2222222222222222 4444444444444444 5555555555555555 858993459 1717986918 8608480567731124087
+#  GNU64-NEXT:       [ffffffffffffffff]: WRITE, ALLOC, EXEC, MERGE, STRINGS, INFO LINK, LINK ORDER, OS NONCONF, GROUP, TLS, COMPRESSED, EXCLUDE, OS (000000000ff00000), PROC (0000000070000000), UNKNOWN (ffffffff000ff008)
+#  GNU64-NEXT:  [ 2] noflags
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000000]: {{$}}
+#  GNU64-NEXT:  [ 3] write
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000001]: WRITE
+#  GNU64-NEXT:  [ 4] alloc
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000002]: ALLOC
+#  GNU64-NEXT:  [ 5] exec
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000004]: EXEC
+#  GNU64-NEXT:  [ 6] merge
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000010]: MERGE
+#  GNU64-NEXT:  [ 7] strings
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000020]: STRINGS
+#  GNU64-NEXT:  [ 8] infolink
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000040]: INFO LINK
+#  GNU64-NEXT:  [ 9] linkorder
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000080]: LINK ORDER
+#  GNU64-NEXT:  [10] nonconforming
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000100]: OS NONCONF
+#  GNU64-NEXT:  [11] group
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000200]: GROUP
+#  GNU64-NEXT:  [12] tls
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000400]: TLS
+#  GNU64-NEXT:  [13] compressed
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000000000800]: COMPRESSED
+#  GNU64-NEXT:  [14] exclude
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [0000000080000000]: EXCLUDE
+#  GNU64-NEXT:  [15] known_and_unknown
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [00000000000f0003]: WRITE, ALLOC, UNKNOWN (00000000000f0000)
+#  GNU64-NEXT:  [16] only_unknown
+#  GNU64-NEXT:       PROGBITS        0000000000000000 000040 000000 00   0   0  0
+#  GNU64-NEXT:       [00000000000f0000]: UNKNOWN (00000000000f0000)
+#  GNU64-NEXT:  [17] .strtab
+#  GNU64-NEXT:       STRTAB          0000000000000000 000040 000001 00   0   0  1
+#  GNU64-NEXT:       [0000000000000000]: {{$}}
+#  GNU64-NEXT:  [18] .shstrtab
+#  GNU64-NEXT:       STRTAB          0000000000000000 000041 0000b0 00   0   0  1
+#  GNU64-NEXT:       [0000000000000000]: {{$}}
+#  GNU64-NOT:{{.}}
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS[[BITS]]
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+  Flags: []
+Sections:
+  - Name:        allflags_and_long_fields
+    Type:        SHT_PROGBITS
+    ShFlags:     0xffffffffffffffff
+    Address:     0x1111111111111111
+    ShOffset:    0x2222222222222222
+    Link:        0x33333333
+    ShSize:      0x4444444444444444
+    EntSize:     0x5555555555555555
+    Info:        0x66666666
+    ShAddrAlign: 0x7777777777777777
+  - Name:  noflags
+    Type:  SHT_PROGBITS
+    Flags: [ ]
+  - Name:  write
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_WRITE ]
+  - Name:  alloc
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_ALLOC ]
+  - Name:  exec
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_EXECINSTR ]
+  - Name:  merge
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_MERGE ]
+  - Name:  strings
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_STRINGS ]
+  - Name:  infolink
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_INFO_LINK ]
+  - Name:  linkorder
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_LINK_ORDER ]
+  - Name:  nonconforming
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_OS_NONCONFORMING ]
+  - Name:  group
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_GROUP ]
+  - Name:  tls
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_TLS ]
+  - Name:  compressed
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_COMPRESSED ]
+  - Name:  exclude
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_EXCLUDE ]
+  - Name:  known_and_unknown
+    Type:  SHT_PROGBITS
+    ShFlags: 0x000f0003
+  - Name:  only_unknown
+    Type:  SHT_PROGBITS
+    ShFlags: 0x000f0000
+
+## Check the output for the 32-bit case.
+# RUN: yaml2obj %s -DBITS=32 -o %t32.o
+# RUN: llvm-readelf %t32.o --section-details | \
+# RUN:   FileCheck %s --strict-whitespace --match-full-lines --check-prefix=GNU32
+
+#       GNU32:There are 19 section headers, starting at offset 0xe8:
+# GNU32-EMPTY:
+#  GNU32-NEXT:Section Headers:
+#  GNU32-NEXT:  [Nr] Name
+#  GNU32-NEXT:       Type            Addr     Off    Size   ES   Lk Inf Al
+#  GNU32-NEXT:       Flags
+#  GNU32-NEXT:  [ 0] {{$}}
+#  GNU32-NEXT:       NULL            00000000 000000 000000 00   0   0  0
+#  GNU32-NEXT:       [00000000]: {{$}}
+#  GNU32-NEXT:  [ 1] allflags_and_long_fields
+#  GNU32-NEXT:       PROGBITS        11111111 22222222 44444444 55555555 858993459 1717986918 2004318071
+#  GNU32-NEXT:       [ffffffff]: WRITE, ALLOC, EXEC, MERGE, STRINGS, INFO LINK, LINK ORDER, OS NONCONF, GROUP, TLS, COMPRESSED, EXCLUDE, OS (0ff00000), PROC (70000000), UNKNOWN (000ff008)
+#  GNU32-NEXT:  [ 2] noflags
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000000]: {{$}}
+#  GNU32-NEXT:  [ 3] write
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000001]: WRITE
+#  GNU32-NEXT:  [ 4] alloc
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000002]: ALLOC
+#  GNU32-NEXT:  [ 5] exec
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000004]: EXEC
+#  GNU32-NEXT:  [ 6] merge
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000010]: MERGE
+#  GNU32-NEXT:  [ 7] strings
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000020]: STRINGS
+#  GNU32-NEXT:  [ 8] infolink
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000040]: INFO LINK
+#  GNU32-NEXT:  [ 9] linkorder
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000080]: LINK ORDER
+#  GNU32-NEXT:  [10] nonconforming
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000100]: OS NONCONF
+#  GNU32-NEXT:  [11] group
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000200]: GROUP
+#  GNU32-NEXT:  [12] tls
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000400]: TLS
+#  GNU32-NEXT:  [13] compressed
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [00000800]: COMPRESSED
+#  GNU32-NEXT:  [14] exclude
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [80000000]: EXCLUDE
+#  GNU32-NEXT:  [15] known_and_unknown
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [000f0003]: WRITE, ALLOC, UNKNOWN (000f0000)
+#  GNU32-NEXT:  [16] only_unknown
+#  GNU32-NEXT:       PROGBITS        00000000 000034 000000 00   0   0  0
+#  GNU32-NEXT:       [000f0000]: UNKNOWN (000f0000)
+#  GNU32-NEXT:  [17] .strtab
+#  GNU32-NEXT:       STRTAB          00000000 000034 000001 00   0   0  1
+#  GNU32-NEXT:       [00000000]: {{$}}
+#  GNU32-NEXT:  [18] .shstrtab
+#  GNU32-NEXT:       STRTAB          00000000 000035 0000b0 00   0   0  1
+#  GNU32-NEXT:       [00000000]: {{$}}
+#  GNU32-NOT:{{.}}
+
+## When --section-details and --sections are both specified, --sections is ignored.
+# RUN: llvm-readelf %t64.o --section-details --sections | FileCheck %s --check-prefix=GNU64
+# RUN: llvm-readelf %t64.o --sections --section-details | FileCheck %s --check-prefix=GNU64
+
+## Check that we produce the same output with -t (alias).
+# RUN: llvm-readelf --section-details %t64.o > %t.readelf.full
+# RUN: llvm-readelf -t %t64.o > %t.readelf.alias
+# RUN: cmp %t.readelf.full %t.readelf.alias
+
+## Check how we dump sections when the section header string table can't be read.
+
+# RUN: yaml2obj --docnum=2 %s -o %tshstrndx.o
+# RUN: llvm-readelf %tshstrndx.o --section-details 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%tshstrndx.o --check-prefix=SHSTRNDX
+
+# SHSTRNDX:      Section Headers:
+# SHSTRNDX-NEXT:   [Nr] Name
+# SHSTRNDX-NEXT:        Type            Address          Off    Size   ES   Lk Inf Al
+# SHSTRNDX-NEXT:        Flags
+# SHSTRNDX-NEXT: warning: '[[FILE]]': section header string table index 65279 does not exist
+# SHSTRNDX-NEXT:   [ 0]
+# SHSTRNDX-NEXT:        NULL            0000000000000000 000000 000000 00   0   0  0
+# SHSTRNDX-NEXT:        [0000000000000000]:
+# SHSTRNDX-NEXT: warning: '[[FILE]]': a section [index 1] has an invalid sh_name (0x5) offset which goes past the end of the section name string table
+# SHSTRNDX-NEXT:   [ 1] <?>
+# SHSTRNDX-NEXT:        PROGBITS        0000000000000000 000040 000000 00   0   0  0
+# SHSTRNDX-NEXT:        [0000000000000000]:
+# SHSTRNDX-NEXT: warning: '[[FILE]]': a section [index 2] has an invalid sh_name (0x1) offset which goes past the end of the section name string table
+# SHSTRNDX-NEXT:   [ 2] <?>
+# SHSTRNDX-NEXT:        PROGBITS        0000000000000000 000040 000000 00   0   0  0
+# SHSTRNDX-NEXT:        [0000000000000000]:
+# SHSTRNDX-NEXT: warning: '[[FILE]]': a section [index 3] has an invalid sh_name (0x13) offset which goes past the end of the section name string table
+# SHSTRNDX-NEXT:   [ 3] <?>
+# SHSTRNDX-NEXT:        STRTAB          0000000000000000 000040 000001 00   0   0  1
+# SHSTRNDX-NEXT:        [0000000000000000]:
+# SHSTRNDX-NEXT: warning: '[[FILE]]': a section [index 4] has an invalid sh_name (0x9) offset which goes past the end of the section name string table
+# SHSTRNDX-NEXT:   [ 4] <?>
+# SHSTRNDX-NEXT:        STRTAB          0000000000000000 000041 00001b 00   0   0  1
+# SHSTRNDX-NEXT:        [0000000000000000]:
+
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_REL
+  EShStrNdx: 0xfeff
+Sections:
+  - Name: foo
+    Type: SHT_PROGBITS
+  - Name: bar
+    Type: SHT_PROGBITS

diff  --git a/llvm/test/tools/llvm-readobj/ELF/symbols.test b/llvm/test/tools/llvm-readobj/ELF/symbols.test
index ba8c8989ddda..486718edfb88 100644
--- a/llvm/test/tools/llvm-readobj/ELF/symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/symbols.test
@@ -78,9 +78,7 @@
 # RUN: llvm-readelf --symbols %t64 > %t.symbols.gnu
 # RUN: llvm-readelf --syms %t64 > %t.syms.gnu
 # RUN: cmp %t.symbols.gnu %t.syms.gnu
-## There is no -t option in llvm-readelf.
-# RUN: not llvm-readelf -t %t64 2>&1 | FileCheck %s --check-prefix=NO-T-ERR
-# NO-T-ERR: Unknown command line argument '-t'
+
 ## -s is an llvm-readobj option to dump sections.
 # RUN: llvm-readobj -s --elf-output-style=GNU %t64 | FileCheck %s --implicit-check-not="Symbol table"
 

diff  --git a/llvm/test/tools/llvm-readobj/basic.test b/llvm/test/tools/llvm-readobj/basic.test
index 5b317951493b..ddf6acb5c44d 100644
--- a/llvm/test/tools/llvm-readobj/basic.test
+++ b/llvm/test/tools/llvm-readobj/basic.test
@@ -41,5 +41,5 @@ HELP: OPTIONS:
 OBJ: -s - Alias for --section-headers
 OBJ: -t - Alias for --symbols
 ELF: -s - Alias for --symbols
-ELF-NOT: {{ }}-t{{ }}
+ELF: -t - Alias for --section-details
 HELP: @FILE

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index b1efd49fbd88..6bf08585c873 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -239,6 +239,7 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   void printDynamicRelocations() override;
   void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
   void printHashSymbols() override;
+  void printSectionDetails() override;
   void printUnwindInfo() override;
 
   void printDynamicTable() override;
@@ -736,6 +737,7 @@ template <typename ELFT> class DumpStyle {
   virtual void printSectionHeaders() = 0;
   virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) = 0;
   virtual void printHashSymbols() {}
+  virtual void printSectionDetails() {}
   virtual void printDependentLibs() = 0;
   virtual void printDynamic() {}
   virtual void printDynamicRelocations() = 0;
@@ -814,6 +816,7 @@ template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> {
   void printSectionHeaders() override;
   void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
   void printHashSymbols() override;
+  void printSectionDetails() override;
   void printDependentLibs() override;
   void printDynamic() override;
   void printDynamicRelocations() override;
@@ -2305,6 +2308,10 @@ template <class ELFT> void ELFDumper<ELFT>::printHashSymbols() {
   ELFDumperStyle->printHashSymbols();
 }
 
+template <class ELFT> void ELFDumper<ELFT>::printSectionDetails() {
+  ELFDumperStyle->printSectionDetails();
+}
+
 template <class ELFT> void ELFDumper<ELFT>::printHashHistograms() {
   ELFDumperStyle->printHashHistograms();
 }
@@ -4159,6 +4166,115 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols() {
   }
 }
 
+template <class ELFT> void GNUStyle<ELFT>::printSectionDetails() {
+  ArrayRef<Elf_Shdr> Sections = cantFail(this->Obj.sections());
+  OS << "There are " << to_string(Sections.size())
+     << " section headers, starting at offset "
+     << "0x" << to_hexString(this->Obj.getHeader().e_shoff, false) << ":\n\n";
+
+  OS << "Section Headers:\n";
+
+  auto PrintFields = [&](ArrayRef<Field> V) {
+    for (const Field &F : V)
+      printField(F);
+    OS << "\n";
+  };
+
+  PrintFields({{"[Nr]", 2}, {"Name", 7}});
+
+  constexpr bool Is64 = ELFT::Is64Bits;
+  PrintFields({{"Type", 7},
+               {Is64 ? "Address" : "Addr", 23},
+               {"Off", Is64 ? 40 : 32},
+               {"Size", Is64 ? 47 : 39},
+               {"ES", Is64 ? 54 : 46},
+               {"Lk", Is64 ? 59 : 51},
+               {"Inf", Is64 ? 62 : 54},
+               {"Al", Is64 ? 66 : 57}});
+  PrintFields({{"Flags", 7}});
+
+  StringRef SecStrTable;
+  if (Expected<StringRef> SecStrTableOrErr = this->Obj.getSectionStringTable(
+          Sections, this->dumper().WarningHandler))
+    SecStrTable = *SecStrTableOrErr;
+  else
+    this->reportUniqueWarning(SecStrTableOrErr.takeError());
+
+  size_t SectionIndex = 0;
+  const unsigned AddrSize = Is64 ? 16 : 8;
+  for (const Elf_Shdr &S : Sections) {
+    StringRef Name = "<?>";
+    if (Expected<StringRef> NameOrErr =
+            this->Obj.getSectionName(S, SecStrTable))
+      Name = *NameOrErr;
+    else
+      this->reportUniqueWarning(NameOrErr.takeError());
+
+    OS.PadToColumn(2);
+    OS << "[" << right_justify(to_string(SectionIndex), 2) << "]";
+    PrintFields({{Name, 7}});
+    PrintFields(
+        {{getSectionTypeString(this->Obj.getHeader().e_machine, S.sh_type), 7},
+         {to_string(format_hex_no_prefix(S.sh_addr, AddrSize)), 23},
+         {to_string(format_hex_no_prefix(S.sh_offset, 6)), Is64 ? 39 : 32},
+         {to_string(format_hex_no_prefix(S.sh_size, 6)), Is64 ? 47 : 39},
+         {to_string(format_hex_no_prefix(S.sh_entsize, 2)), Is64 ? 54 : 46},
+         {to_string(S.sh_link), Is64 ? 59 : 51},
+         {to_string(S.sh_info), Is64 ? 63 : 55},
+         {to_string(S.sh_addralign), Is64 ? 66 : 58}});
+
+    OS.PadToColumn(7);
+    OS << "[" << to_string(format_hex_no_prefix(S.sh_flags, AddrSize)) << "]: ";
+
+    DenseMap<unsigned, StringRef> FlagToName = {
+        {SHF_WRITE, "WRITE"},           {SHF_ALLOC, "ALLOC"},
+        {SHF_EXECINSTR, "EXEC"},        {SHF_MERGE, "MERGE"},
+        {SHF_STRINGS, "STRINGS"},       {SHF_INFO_LINK, "INFO LINK"},
+        {SHF_LINK_ORDER, "LINK ORDER"}, {SHF_OS_NONCONFORMING, "OS NONCONF"},
+        {SHF_GROUP, "GROUP"},           {SHF_TLS, "TLS"},
+        {SHF_COMPRESSED, "COMPRESSED"}, {SHF_EXCLUDE, "EXCLUDE"}};
+
+    uint64_t Flags = S.sh_flags;
+    uint64_t UnknownFlags = 0;
+    bool NeedsComma = false;
+    while (Flags) {
+      // Take the least significant bit as a flag.
+      uint64_t Flag = Flags & -Flags;
+      Flags -= Flag;
+
+      auto It = FlagToName.find(Flag);
+      if (It != FlagToName.end()) {
+        if (NeedsComma)
+          OS << ", ";
+        NeedsComma = true;
+        OS << It->second;
+      } else {
+        UnknownFlags |= Flag;
+      }
+    }
+
+    auto PrintUnknownFlags = [&](uint64_t Mask, StringRef Name) {
+      uint64_t FlagsToPrint = UnknownFlags & Mask;
+      if (!FlagsToPrint)
+        return;
+
+      if (NeedsComma)
+        OS << ", ";
+      OS << Name << " ("
+         << to_string(format_hex_no_prefix(FlagsToPrint, AddrSize)) << ")";
+      UnknownFlags &= ~Mask;
+      NeedsComma = true;
+    };
+
+    PrintUnknownFlags(SHF_MASKOS, "OS");
+    PrintUnknownFlags(SHF_MASKPROC, "PROC");
+    PrintUnknownFlags(uint64_t(-1), "UNKNOWN");
+
+    OS << "\n";
+    ++SectionIndex;
+  }
+}
+
 static inline std::string printPhdrFlags(unsigned Flag) {
   std::string Str;
   Str = (Flag & PF_R) ? "R" : " ";

diff  --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 943299a121fc..ea549dcca219 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -72,7 +72,8 @@ class ObjDumper {
   virtual void printNotes() {}
   virtual void printELFLinkerOptions() {}
   virtual void printStackSizes() {}
-  virtual void printArchSpecificInfo() { }
+  virtual void printSectionDetails() {}
+  virtual void printArchSpecificInfo() {}
 
   // Only implemented for PE/COFF.
   virtual void printCOFFImports() { }

diff  --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 1546ce7926a4..a30773525c1c 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -137,6 +137,11 @@ namespace opts {
   cl::opt<bool> DynRelocs("dyn-relocations",
     cl::desc("Display the dynamic relocation entries in the file"));
 
+  // --section-details
+  // Also -t in llvm-readelf mode.
+  cl::opt<bool> SectionDetails("section-details",
+                               cl::desc("Display the section details"));
+
   // --symbols
   // Also -s in llvm-readelf mode, or -t in llvm-readobj mode.
   cl::opt<bool>
@@ -480,8 +485,14 @@ static void dumpObject(const ObjectFile &Obj, ScopedPrinter &Writer,
 
   if (opts::FileHeaders)
     Dumper->printFileHeaders();
-  if (opts::SectionHeaders)
-    Dumper->printSectionHeaders();
+
+  if (opts::SectionDetails || opts::SectionHeaders) {
+    if (opts::Output == opts::GNU && opts::SectionDetails)
+      Dumper->printSectionDetails();
+    else
+      Dumper->printSectionHeaders();
+  }
+
   if (opts::HashSymbols)
     Dumper->printHashSymbols();
   if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
@@ -656,8 +667,7 @@ static void registerReadobjAliases() {
                                  cl::aliasopt(opts::SectionHeaders),
                                  cl::NotHidden);
 
-  // Only register -t in llvm-readobj, as readelf reserves it for
-  // --section-details (not implemented yet).
+  // llvm-readelf reserves it for --section-details.
   static cl::alias SymbolsShort("t", cl::desc("Alias for --symbols"),
                                 cl::aliasopt(opts::Symbols), cl::NotHidden);
 
@@ -683,6 +693,11 @@ static void registerReadelfAliases() {
                                 cl::aliasopt(opts::Symbols), cl::NotHidden,
                                 cl::Grouping);
 
+  // -t is here because for readobj it is an alias for --symbols.
+  static cl::alias SectionDetailsShort(
+      "t", cl::desc("Alias for --section-details"),
+      cl::aliasopt(opts::SectionDetails), cl::NotHidden);
+
   // Allow all single letter flags to be grouped together.
   for (auto &OptEntry : cl::getRegisteredOptions()) {
     StringRef ArgName = OptEntry.getKey();


        


More information about the llvm-commits mailing list