[llvm] 541daa5 - [llvm-readelf][llvm-readobj] - Reimplement the logic of section flags dumping.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 17 23:53:32 PST 2019


Author: Georgii Rymar
Date: 2019-12-18T10:44:40+03:00
New Revision: 541daa5e6b9bc38986e09612a9bd6f0f148fdfcf

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

LOG: [llvm-readelf][llvm-readobj] - Reimplement the logic of section flags dumping.

Our logic that dumped the flags was buggy.

For LLVM style it dumped SHF_MASKPROC/SHF_MASKOS named constants, though
they are not flags, but masks.

For GNU style it was just very inconsistent with GNU which has logic
that is not straightforward. Imagine we have sh_flags == 0x90000000.
SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000.
GNU readelf will not print "E" or "Ep" in this case, but will print just
"p". It only will print "E" when no other processor flag is set.
I had to investigate the GNU source to find the algorithm and now our logic should
match it.

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

Added: 
    llvm/test/tools/llvm-readobj/ELF/section-flags-os-proc.test

Modified: 
    llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
    llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
    llvm/test/tools/llvm-readobj/ELF/section-flags.test
    llvm/tools/llvm-readobj/ELFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
index a76929051060..0d3224a41d31 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
@@ -77,7 +77,6 @@ Sections:
 # MIPS-NEXT:   Flags [
 # MIPS-NEXT:     SHF_ALLOC (0x2)
 # MIPS-NEXT:     SHF_EXCLUDE (0x80000000)
-# MIPS-NEXT:     SHF_MASKPROC (0xF0000000)
 # MIPS-NEXT:     SHF_MIPS_ADDR (0x40000000)
 # MIPS-NEXT:     SHF_MIPS_GPREL (0x10000000)
 # MIPS-NEXT:     SHF_MIPS_LOCAL (0x4000000)

diff  --git a/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test b/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
index 7b023e1c321c..e70b3b2bce73 100644
--- a/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
+++ b/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
@@ -27,12 +27,10 @@ Sections:
 # RUN: llvm-readelf -S %t-mips.o | FileCheck --check-prefix=MIPS-GNU %s
 
 # MIPS-GNU: [Nr] Name  Type     Address  Off    Size   ES Flg Lk Inf Al
-# MIPS-GNU: [ 1] .mips PROGBITS 00000000 000034 000000 00 Eop  0   0  0
+# MIPS-GNU: [ 1] .mips PROGBITS 00000000 000034 000000 00  op  0   0  0
 
 # MIPS-LLVM:      Flags [ (0xFF000000)
 # MIPS-LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
-## FIXME: we should not print SHF_MASKPROC, because it is a mask value.
-# MIPS-LLVM-NEXT:   SHF_MASKPROC (0xF0000000)
 # MIPS-LLVM-NEXT:   SHF_MIPS_ADDR (0x40000000)
 # MIPS-LLVM-NEXT:   SHF_MIPS_GPREL (0x10000000)
 # MIPS-LLVM-NEXT:   SHF_MIPS_LOCAL (0x4000000)
@@ -55,7 +53,35 @@ Sections:
     Flags: [ SHF_MIPS_NODUPES, SHF_MIPS_NAMES, SHF_MIPS_LOCAL, SHF_MIPS_NOSTRIP,
               SHF_MIPS_GPREL, SHF_MIPS_MERGE, SHF_MIPS_ADDR, SHF_MIPS_STRING ]
 
-# RUN: yaml2obj --docnum 3 %s -o %t-x86_64.o
+## Test what we print when a MIPS object has the SHF_MIPS_STRING flag.
+## SHF_MIPS_STRING has a value of 0x80000000, which matches the value of SHF_EXCLUDE.
+
+# RUN: yaml2obj --docnum 3 %s -o %t-mips-exclude.o
+# RUN: llvm-readobj -S %t-mips-exclude.o | FileCheck --check-prefix=MIPS-EXCLUDE-LLVM %s
+# RUN: llvm-readelf -S %t-mips-exclude.o | FileCheck --check-prefix=MIPS-EXCLUDE-GNU %s
+
+# MIPS-EXCLUDE-LLVM:      Name: .mips
+# MIPS-EXCLUDE-LLVM-NEXT: Type: SHT_PROGBITS
+# MIPS-EXCLUDE-LLVM-NEXT: Flags [ (0x80000000)
+# MIPS-EXCLUDE-LLVM-NEXT:  SHF_EXCLUDE (0x80000000)
+# MIPS-EXCLUDE-LLVM-NEXT:  SHF_MIPS_STRING (0x80000000)
+# MIPS-EXCLUDE-LLVM-NEXT: ]
+
+# MIPS-EXCLUDE-GNU: [Nr] Name  Type     Address  Off    Size   ES Flg Lk Inf Al
+# MIPS-EXCLUDE-GNU: [ 1] .mips PROGBITS 00000000 000034 000000 00   E  0   0  0
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_MIPS
+Sections:
+  - Name:  .mips
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_MIPS_STRING ]
+
+# RUN: yaml2obj --docnum 4 %s -o %t-x86_64.o
 # RUN: llvm-readobj -S %t-x86_64.o | FileCheck --check-prefix=X86_64-LLVM %s
 # RUN: llvm-readelf -S %t-x86_64.o | FileCheck --check-prefix=X86_64-GNU %s
 
@@ -77,7 +103,7 @@ Sections:
     Type:  SHT_PROGBITS
     Flags: [ SHF_X86_64_LARGE ]
 
-# RUN: yaml2obj --docnum 4 %s -o %t-arm.o
+# RUN: yaml2obj --docnum 5 %s -o %t-arm.o
 # RUN: llvm-readobj -S %t-arm.o | FileCheck --check-prefix=ARM-LLVM %s
 # RUN: llvm-readelf -S %t-arm.o | FileCheck --check-prefix=ARM-GNU %s
 

diff  --git a/llvm/test/tools/llvm-readobj/ELF/section-flags-os-proc.test b/llvm/test/tools/llvm-readobj/ELF/section-flags-os-proc.test
new file mode 100644
index 000000000000..b5ba3ef45a4c
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/section-flags-os-proc.test
@@ -0,0 +1,132 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: llvm-readobj -S %t.o | FileCheck --check-prefix=OS-PROC-LLVM %s
+# RUN: llvm-readelf -S %t.o | FileCheck --check-prefix=OS-PROC-GNU %s
+
+## Here we test how OS and processor specific flags are dumped.
+
+# OS-PROC-LLVM:      Name: .os.flags.low
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0x100000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .os.flags.high
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0xFE00000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .os.flags.mask
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0xFF00000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .proc.flags.low
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0x10000000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .proc.flags.high
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0xE0000000)
+# OS-PROC-LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .proc.flags.mask
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0xF0000000)
+# OS-PROC-LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .both.flags.low
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0x10100000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .both.flags.high
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0xEFE00000)
+# OS-PROC-LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .both.flags.mask
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0xFFF00000)
+# OS-PROC-LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .exclude
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0x80000000)
+# OS-PROC-LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
+# OS-PROC-LLVM-NEXT: ]
+# OS-PROC-LLVM:      Name: .all.possible
+# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS
+# OS-PROC-LLVM-NEXT: Flags [ (0xFFFFFFFF)
+# OS-PROC-LLVM-NEXT:   SHF_ALLOC (0x2)
+# OS-PROC-LLVM-NEXT:   SHF_COMPRESSED (0x800)
+# OS-PROC-LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
+# OS-PROC-LLVM-NEXT:   SHF_EXECINSTR (0x4)
+# OS-PROC-LLVM-NEXT:   SHF_GROUP (0x200)
+# OS-PROC-LLVM-NEXT:   SHF_INFO_LINK (0x40)
+# OS-PROC-LLVM-NEXT:   SHF_LINK_ORDER (0x80)
+# OS-PROC-LLVM-NEXT:   SHF_MERGE (0x10)
+# OS-PROC-LLVM-NEXT:   SHF_OS_NONCONFORMING (0x100)
+# OS-PROC-LLVM-NEXT:   SHF_STRINGS (0x20)
+# OS-PROC-LLVM-NEXT:   SHF_TLS (0x400)
+# OS-PROC-LLVM-NEXT:   SHF_WRITE (0x1)
+# OS-PROC-LLVM-NEXT: ]
+
+# OS-PROC-GNU:      Section Headers:
+# OS-PROC-GNU-NEXT:  [Nr] Name                   Type     Address          Off    Size   ES Flg            Lk Inf Al
+# OS-PROC-GNU-NEXT:  [ 0]                        NULL     0000000000000000 000000 000000 00                0   0  0
+# OS-PROC-GNU-NEXT:  [ 1] .os.flags.low          PROGBITS 0000000000000000 000040 000000 00   o            0   0  0
+# OS-PROC-GNU-NEXT:  [ 2] .os.flags.high         PROGBITS 0000000000000000 000040 000000 00   o            0   0  0
+# OS-PROC-GNU-NEXT:  [ 3] .os.flags.mask         PROGBITS 0000000000000000 000040 000000 00   o            0   0  0
+# OS-PROC-GNU-NEXT:  [ 4] .proc.flags.low        PROGBITS 0000000000000000 000040 000000 00   p            0   0  0
+# OS-PROC-GNU-NEXT:  [ 5] .proc.flags.high       PROGBITS 0000000000000000 000040 000000 00   p            0   0  0
+# OS-PROC-GNU-NEXT:  [ 6] .proc.flags.mask       PROGBITS 0000000000000000 000040 000000 00   p            0   0  0
+# OS-PROC-GNU-NEXT:  [ 7] .both.flags.low        PROGBITS 0000000000000000 000040 000000 00  op            0   0  0
+# OS-PROC-GNU-NEXT:  [ 8] .both.flags.high       PROGBITS 0000000000000000 000040 000000 00  op            0   0  0
+# OS-PROC-GNU-NEXT:  [ 9] .both.flags.mask       PROGBITS 0000000000000000 000040 000000 00  op            0   0  0
+# OS-PROC-GNU-NEXT:  [10] .exclude               PROGBITS 0000000000000000 000040 000000 00   E            0   0  0
+# OS-PROC-GNU-NEXT:  [11] .all.possible          PROGBITS 0000000000000000 000040 000000 00 WAXMSILOGTCopx 0   0  0
+
+## Use an arbitrary EM_* machine type that does not have specific SHF_* OS/Processor
+## flags to test what we dump when bits in the OS and processor specific ranges are set.
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_NONE
+Sections:
+  - Name:  .os.flags.low
+    Type:  SHT_PROGBITS
+    ShFlags: 0x00100000
+  - Name:  .os.flags.high
+    Type:  SHT_PROGBITS
+    ShFlags: 0x0FE00000
+  - Name:  .os.flags.mask
+    Type:  SHT_PROGBITS
+    ShFlags: 0x0FF00000
+  - Name:  .proc.flags.low
+    Type:  SHT_PROGBITS
+    ShFlags: 0x10000000
+  - Name:  .proc.flags.high
+    Type:  SHT_PROGBITS
+    ShFlags: 0xE0000000
+  - Name:  .proc.flags.mask
+    Type:  SHT_PROGBITS
+    ShFlags: 0xF0000000
+  - Name:  .both.flags.low
+    Type:  SHT_PROGBITS
+    ShFlags: 0x10100000
+  - Name:  .both.flags.high
+    Type:  SHT_PROGBITS
+    ShFlags: 0xEFE00000
+  - Name:  .both.flags.mask
+    Type:  SHT_PROGBITS
+    ShFlags: 0xFFF00000
+## SHF_MASKPROC has a value of 0xf0000000, SHF_EXCLUDE has a value of
+## 0x80000000. When SHF_EXCLUDE is mixed with other processor specific
+## flags, GNU readelf does not necessarily print "E", because it handles
+## the SHF_MASKPROC mask first. It only prints "E" when there are no other
+## processor flags set. Check llvm-readelf output matches GNU.
+  - Name:  .exclude
+    Type:  SHT_PROGBITS
+    ShFlags: 0x80000000
+## Set all possible flags to test where we print 'o' and 'p' letters.
+  - Name:  .all.possible
+    Type:  SHT_PROGBITS
+    ShFlags: 0xFFFFFFFF

diff  --git a/llvm/test/tools/llvm-readobj/ELF/section-flags.test b/llvm/test/tools/llvm-readobj/ELF/section-flags.test
index 9b27b5c065d3..2485b50b8e35 100644
--- a/llvm/test/tools/llvm-readobj/ELF/section-flags.test
+++ b/llvm/test/tools/llvm-readobj/ELF/section-flags.test
@@ -98,6 +98,11 @@
 # LLVM-NEXT:   SHF_EXCLUDE (0x80000000)
 # LLVM-NEXT: ]
 
+# LLVM:      Name: unknown
+# LLVM-NEXT: Type: SHT_PROGBITS
+# LLVM-NEXT: Flags [ (0xF0000)
+# LLVM-NEXT: ]
+
 # GNU: [Nr] Name          Type     Address          Off    Size   ES Flg          Lk Inf Al
 # GNU: [ 1] allflags      PROGBITS 0000000000000000 000040 000000 00 WAXMSILOGTCE 0   0  0
 # GNU: [ 2] noflags       PROGBITS 0000000000000000 000040 000000 00              0   0  0
@@ -113,6 +118,7 @@
 # GNU: [12] tls           PROGBITS 0000000000000000 000040 000000 00 T            0   0  0
 # GNU: [13] compressed    PROGBITS 0000000000000000 000040 000000 00 C            0   0  0
 # GNU: [14] exclude       PROGBITS 0000000000000000 000040 000000 00 E            0   0  0
+# GNU: [15] unknown       PROGBITS 0000000000000000 000040 000000 00 x            0   0  0
 
 --- !ELF
 FileHeader:
@@ -166,3 +172,6 @@ Sections:
   - Name:  exclude
     Type:  SHT_PROGBITS
     Flags: [ SHF_EXCLUDE ]
+  - Name:  unknown
+    Type:  SHT_PROGBITS
+    ShFlags: 0x000f0000

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 531ca351e212..7d648da41ea1 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1444,8 +1444,6 @@ static const EnumEntry<unsigned> ElfSectionFlags[] = {
   ENUM_ENT(SHF_TLS,              "T"),
   ENUM_ENT(SHF_COMPRESSED,       "C"),
   ENUM_ENT(SHF_EXCLUDE,          "E"),
-  ENUM_ENT(SHF_MASKOS,           "o"),
-  ENUM_ENT(SHF_MASKPROC,         "p"),
 };
 
 static const EnumEntry<unsigned> ElfXCoreSectionFlags[] = {
@@ -1477,34 +1475,51 @@ static const EnumEntry<unsigned> ElfX86_64SectionFlags[] = {
 };
 
 static std::string getGNUFlags(uint64_t Flags) {
+  // Here we are trying to build the flags string in the same way as GNU does.
+  // It is not that straightforward. Imagine we have sh_flags == 0x90000000.
+  // SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000.
+  // GNU readelf will not print "E" or "Ep" in this case, but will print just
+  // "p". It only will print "E" when no other processor flag is set.
   std::string Str;
-  for (auto Entry : ElfSectionFlags) {
-    uint64_t Flag = Entry.Value & Flags;
-    Flags &= ~Entry.Value;
-    switch (Flag) {
-    case ELF::SHF_WRITE:
-    case ELF::SHF_ALLOC:
-    case ELF::SHF_EXECINSTR:
-    case ELF::SHF_MERGE:
-    case ELF::SHF_STRINGS:
-    case ELF::SHF_INFO_LINK:
-    case ELF::SHF_LINK_ORDER:
-    case ELF::SHF_OS_NONCONFORMING:
-    case ELF::SHF_GROUP:
-    case ELF::SHF_TLS:
-    case ELF::SHF_COMPRESSED:
-    case ELF::SHF_EXCLUDE:
-      Str += Entry.AltName;
-      break;
-    default:
-      if (Flag & ELF::SHF_MASKOS)
-        Str += "o";
-      else if (Flag & ELF::SHF_MASKPROC)
-        Str += "p";
-      else if (Flag)
-        Str += "x";
+  bool HasUnknownFlag = false;
+  bool HasOSFlag = false;
+  bool HasProcFlag = false;
+  while (Flags) {
+    // Take the least significant bit as a flag.
+    uint64_t Flag = Flags & -Flags;
+    Flags -= Flag;
+
+    // Find the flag in the known flags list.
+    auto I = llvm::find_if(ElfSectionFlags, [=](const EnumEntry<unsigned> &E) {
+      return E.Value == Flag;
+    });
+    if (I != std::end(ElfSectionFlags)) {
+      Str += I->AltName;
+      continue;
+    }
+
+    // If we did not find a matching regular flag, then we deal with an OS
+    // specific flag, processor specific flag or an unknown flag.
+    if (Flag & ELF::SHF_MASKOS) {
+      HasOSFlag = true;
+      Flags &= ~ELF::SHF_MASKOS;
+    } else if (Flag & ELF::SHF_MASKPROC) {
+      HasProcFlag = true;
+      // Mask off all the processor-specific bits. This removes the SHF_EXCLUDE
+      // bit if set so that it doesn't also get printed.
+      Flags &= ~ELF::SHF_MASKPROC;
+    } else {
+      HasUnknownFlag = true;
     }
   }
+
+  // "o", "p" and "x" are printed last.
+  if (HasOSFlag)
+    Str += "o";
+  if (HasProcFlag)
+    Str += "p";
+  if (HasUnknownFlag)
+    Str += "x";
   return Str;
 }
 


        


More information about the llvm-commits mailing list