[Lldb-commits] [lldb] r350742 - ELF: create "container" sections from PT_LOAD segments

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Wed Jan 9 08:50:46 PST 2019


Author: labath
Date: Wed Jan  9 08:50:45 2019
New Revision: 350742

URL: http://llvm.org/viewvc/llvm-project?rev=350742&view=rev
Log:
ELF: create "container" sections from PT_LOAD segments

Summary:
This is the result of the discussion in D55356, where it was suggested
as a solution to representing the addresses that logically belong to a
module in memory, but are not a part of any of its sections.

The ELF PT_LOAD segments are similar to the MachO "load commands",
except that the relationship between them and the object file sections
is a bit weaker. While in the MachO case, the sections belonging to a
specific segment are placed directly inside it in the object file
logical structur, in the ELF case, the sections and segments form two
separate hierarchies. This means that it is in theory possible to create
an elf file where only a part of a section would belong to some segment
(and another part to a different one). However, I am not aware of any
tool which would produce such a file (and most tools will have problems
ingesting them), so this means it is still possible to follow the MachO
model and make sections children of the PT_LOAD segments.

In case we run into (corrupt?) files with overlapping sections, I have
added code (and tests) which adjusts the sizes and/or drops the offending
sections in order to present a reasonable image to the upper layers of
LLDB. This is mostly done for completeness, as I don't anticipate
running into this situation in the real world. However, if we do run
into it, and the current behavior is not suitable for some reason, we
can implement this logic differently.

Reviewers: clayborg, jankratochvil, krytarowski, joerg, espindola

Subscribers: emaste, arichardson, lldb-commits

Differential Revision: https://reviews.llvm.org/D55998

Added:
    lldb/trunk/lit/Modules/ELF/Inputs/
    lldb/trunk/lit/Modules/ELF/Inputs/PT_LOAD-overlap-section.elf
    lldb/trunk/lit/Modules/ELF/PT_LOAD-empty.yaml
    lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-PT_INTERP.yaml
    lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-section.yaml
    lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap.yaml
    lldb/trunk/lit/Modules/ELF/PT_LOAD.yaml
    lldb/trunk/lit/Modules/ELF/section-overlap.yaml
Modified:
    lldb/trunk/lit/Modules/ELF/section-permissions.yaml
    lldb/trunk/lit/Modules/ELF/section-types.yaml
    lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp

Added: lldb/trunk/lit/Modules/ELF/Inputs/PT_LOAD-overlap-section.elf
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/Inputs/PT_LOAD-overlap-section.elf?rev=350742&view=auto
==============================================================================
Binary files lldb/trunk/lit/Modules/ELF/Inputs/PT_LOAD-overlap-section.elf (added) and lldb/trunk/lit/Modules/ELF/Inputs/PT_LOAD-overlap-section.elf Wed Jan  9 08:50:45 2019 differ

Added: lldb/trunk/lit/Modules/ELF/PT_LOAD-empty.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/PT_LOAD-empty.yaml?rev=350742&view=auto
==============================================================================
--- lldb/trunk/lit/Modules/ELF/PT_LOAD-empty.yaml (added)
+++ lldb/trunk/lit/Modules/ELF/PT_LOAD-empty.yaml Wed Jan  9 08:50:45 2019
@@ -0,0 +1,26 @@
+# Test behavior on unusual (and probably corrupt) files. Test that we drop an
+# empty PT_LOAD segment.
+
+# RUN: yaml2obj %s > %t
+# RUN: lldb-test object-file %t | FileCheck %s
+#
+# CHECK-NOT: container
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_ARM
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+ProgramHeaders:
+  - Type: PT_LOAD
+    Flags: [ PF_X, PF_R ]
+    VAddr: 0x1000
+    Align: 0x4

Added: lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-PT_INTERP.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-PT_INTERP.yaml?rev=350742&view=auto
==============================================================================
--- lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-PT_INTERP.yaml (added)
+++ lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-PT_INTERP.yaml Wed Jan  9 08:50:45 2019
@@ -0,0 +1,50 @@
+# Test that an overlapping PT_INTERP segment does not cause us to drop the
+# subsequent PT_LOAD segment.
+
+# RUN: yaml2obj %s > %t
+# RUN: lldb-test object-file %t | FileCheck %s
+
+# CHECK:        Index: 0
+# CHECK-NEXT:   ID: 0xfffffffffffffffe
+# CHECK-NEXT:   Name: PT_LOAD[0]
+# CHECK-NEXT:   Type: container
+# CHECK-NEXT:   Permissions: rwx
+# CHECK-NEXT:   Thread specific: no
+# CHECK-NEXT:   VM address: 0x1000
+# CHECK-NEXT:   VM size: 12
+# CHECK-NEXT:   File size: 12
+# CHECK-NEXT:   Showing 2 subsections
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_ARM
+Sections:
+  - Name:            .interp
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1000
+    AddressAlign:    0x4
+    Content:         3232
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1004
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+ProgramHeaders:
+  - Type: PT_INTERP
+    Flags: [ PF_R ]
+    VAddr: 0x1000
+    Align: 0x4
+    Sections:
+      - Section: .interp
+  - Type: PT_LOAD
+    Flags: [ PF_X, PF_W, PF_R ]
+    VAddr: 0x1000
+    Align: 0x4
+    Sections:
+      - Section: .interp
+      - Section: .text

Added: lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-section.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-section.yaml?rev=350742&view=auto
==============================================================================
--- lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-section.yaml (added)
+++ lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap-section.yaml Wed Jan  9 08:50:45 2019
@@ -0,0 +1,66 @@
+# Test behavior on strange (invalid?) elf files where the sections cross segment
+# boundary. The test input was generated from this yaml file, but the program
+# header was modified by hand, so this input is here for reference only.
+#
+# Right now lldb shortens sections to make sure every section is fully contained
+# within a segment, but other behaviors are possible too (including outright
+# rejecting such files).
+
+# RUN: lldb-test object-file %S/Inputs/PT_LOAD-overlap-section.elf | FileCheck %s
+
+# CHECK:      Index: 0
+# CHECK-NEXT: ID: 0xffffffffffffffff
+# CHECK-NEXT: Name: PT_LOAD[0]
+# CHECK-NEXT: Type: container
+# CHECK-NEXT: Permissions: rwx
+# CHECK-NEXT: Thread specific: no
+# CHECK-NEXT: VM address: 0x1006
+# CHECK-NEXT: VM size: 8
+# CHECK-NEXT: File size: 8
+# CHECK-NEXT: Showing 1 subsections
+# CHECK-NEXT:   Index: 0
+# CHECK-NEXT:   ID: 0x2
+# CHECK-NEXT:   Name: .text
+# CHECK-NEXT:   Type: code
+# CHECK-NEXT:   Permissions: r-x
+# CHECK-NEXT:   Thread specific: no
+# CHECK-NEXT:   VM address: 0x1008
+# CHECK-NEXT:   VM size: 6
+# CHECK-NEXT:   File size: 8
+
+# CHECK:      Index: 1
+# CHECK-NEXT: ID: 0x1
+# CHECK-NEXT: Name: .interp
+# CHECK-NEXT: Type: regular
+# CHECK-NEXT: Permissions: r--
+# CHECK-NEXT: Thread specific: no
+# CHECK-NEXT: VM address: 0x1000
+# CHECK-NEXT: VM size: 6
+# CHECK-NEXT: File size: 8
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_ARM
+Sections:
+  - Name:            .interp
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1000
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1008
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+ProgramHeaders:
+  - Type: PT_LOAD
+    Flags: [ PF_X, PF_W, PF_R ]
+    VAddr: 0x1008 # Modified by hand to start at 0x1006
+    Align: 0x4
+    Sections:
+      - Section: .text

Added: lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap.yaml?rev=350742&view=auto
==============================================================================
--- lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap.yaml (added)
+++ lldb/trunk/lit/Modules/ELF/PT_LOAD-overlap.yaml Wed Jan  9 08:50:45 2019
@@ -0,0 +1,42 @@
+# Test behavior on unusual (and probably corrupt) object files. Check that we
+# drop the second PT_LOAD segment which overlaps with the first one.
+
+# RUN: yaml2obj %s > %t
+# RUN: lldb-test object-file %t | FileCheck %s
+
+# CHECK: Type: container
+# CHECK-NOT: Type: container
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_ARM
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1008
+    AddressAlign:    0x4
+    Content:         3232
+ProgramHeaders:
+  - Type: PT_LOAD
+    Flags: [ PF_X, PF_W, PF_R ]
+    VAddr: 0x1000
+    Align: 0x4
+    Sections:
+      - Section: .text
+      - Section: .data
+  - Type: PT_LOAD
+    Flags: [ PF_R, PF_W ]
+    VAddr: 0x1008
+    Align: 0x4
+    Sections:
+      - Section: .data

Added: lldb/trunk/lit/Modules/ELF/PT_LOAD.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/PT_LOAD.yaml?rev=350742&view=auto
==============================================================================
--- lldb/trunk/lit/Modules/ELF/PT_LOAD.yaml (added)
+++ lldb/trunk/lit/Modules/ELF/PT_LOAD.yaml Wed Jan  9 08:50:45 2019
@@ -0,0 +1,79 @@
+# Test that sections are made child-sections of the PT_LOAD segments/sections.
+
+# RUN: yaml2obj %s > %t
+# RUN: lldb-test object-file %t | FileCheck %s
+
+# CHECK:      Index: 0
+# CHECK-NEXT: ID: 0xffffffffffffffff
+# CHECK-NEXT: Name: PT_LOAD[0]
+# CHECK-NEXT: Type: container
+# CHECK-NEXT: Permissions: rwx
+# CHECK-NEXT: Thread specific: no
+# CHECK-NEXT: VM address: 0x1000
+# CHECK-NEXT: VM size: 10
+# CHECK-NEXT: File size: 10
+# CHECK-NEXT: Showing 2 subsections
+# CHECK-NEXT:   Index: 0
+# CHECK-NEXT:   ID: 0x1
+# CHECK-NEXT:   Name: .text
+# CHECK-NEXT:   Type: code
+# CHECK-NEXT:   Permissions: r-x
+# CHECK-NEXT:   Thread specific: no
+# CHECK-NEXT:   VM address: 0x1000
+# CHECK-NEXT:   VM size: 8
+# CHECK-NEXT:   File size: 8
+# CHECK-EMPTY:
+# CHECK-NEXT:   Index: 1
+# CHECK-NEXT:   ID: 0x2
+# CHECK-NEXT:   Name: .data
+# CHECK-NEXT:   Type: data
+# CHECK-NEXT:   Permissions: r--
+# CHECK-NEXT:   Thread specific: no
+# CHECK-NEXT:   VM address: 0x1008
+# CHECK-NEXT:   VM size: 2
+# CHECK-NEXT:   File size: 2
+# CHECK-EMPTY:
+# CHECK-EMPTY:
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: ID: 0x3
+# CHECK-NEXT: Name: .data_outside
+# CHECK-NEXT: Type: regular
+# CHECK-NEXT: Permissions: r--
+# CHECK-NEXT: Thread specific: no
+# CHECK-NEXT: VM address: 0x2000
+# CHECK-NEXT: VM size: 2
+# CHECK-NEXT: File size: 2
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_ARM
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1008
+    AddressAlign:    0x4
+    Content:         3232
+  - Name:            .data_outside
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2000
+    AddressAlign:    0x4
+    Content:         3232
+ProgramHeaders:
+  - Type: PT_LOAD
+    Flags: [ PF_X, PF_W, PF_R ]
+    VAddr: 0x1000
+    Align: 0x4
+    Sections:
+      - Section: .text
+      - Section: .data

Added: lldb/trunk/lit/Modules/ELF/section-overlap.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/section-overlap.yaml?rev=350742&view=auto
==============================================================================
--- lldb/trunk/lit/Modules/ELF/section-overlap.yaml (added)
+++ lldb/trunk/lit/Modules/ELF/section-overlap.yaml Wed Jan  9 08:50:45 2019
@@ -0,0 +1,51 @@
+# Test handling of (corrupt?) object files, which have sections with overlapping
+# virtual addresses.
+#
+# Right now the overlapping sections get dropped, but other behaviors
+# (including outright rejecting such files) are possible too.
+
+# RUN: yaml2obj %s > %t
+# RUN: lldb-test object-file %t | FileCheck %s
+
+# CHECK-NOT: .overlap1
+# CHECK-NOT: .overlap2
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_ARM
+Sections:
+  - Name:            .sect1
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1000
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+  - Name:            .overlap1
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1004
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+  - Name:            .sect2
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2000
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+  - Name:            .overlap2
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2004
+    AddressAlign:    0x4
+    Content:         DEADBEEFBAADF00D
+ProgramHeaders:
+  - Type: PT_LOAD
+    Flags: [ PF_X, PF_W, PF_R ]
+    VAddr: 0x1000
+    Align: 0x4
+    Sections:
+      - Section: .sect1
+      - Section: .overlap1

Modified: lldb/trunk/lit/Modules/ELF/section-permissions.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/section-permissions.yaml?rev=350742&r1=350741&r2=350742&view=diff
==============================================================================
--- lldb/trunk/lit/Modules/ELF/section-permissions.yaml (original)
+++ lldb/trunk/lit/Modules/ELF/section-permissions.yaml Wed Jan  9 08:50:45 2019
@@ -14,7 +14,7 @@
 FileHeader:
   Class:           ELFCLASS64
   Data:            ELFDATA2LSB
-  Type:            ET_DYN
+  Type:            ET_REL
   Machine:         EM_X86_64
   Entry:           0x00000000000007A0
 Sections:

Modified: lldb/trunk/lit/Modules/ELF/section-types.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Modules/ELF/section-types.yaml?rev=350742&r1=350741&r2=350742&view=diff
==============================================================================
--- lldb/trunk/lit/Modules/ELF/section-types.yaml (original)
+++ lldb/trunk/lit/Modules/ELF/section-types.yaml Wed Jan  9 08:50:45 2019
@@ -35,7 +35,7 @@
 FileHeader:
   Class:           ELFCLASS64
   Data:            ELFDATA2LSB
-  Type:            ET_DYN
+  Type:            ET_REL
   Machine:         EM_X86_64
   Entry:           0x00000000000007A0
 Sections:

Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp?rev=350742&r1=350741&r2=350742&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Wed Jan  9 08:50:45 2019
@@ -17,6 +17,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RangeMap.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Symbol/DWARFCallFrameInfo.h"
@@ -30,6 +31,7 @@
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
 
+#include "llvm/ADT/IntervalMap.h"
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Object/Decompressor.h"
@@ -236,6 +238,8 @@ unsigned ELFRelocation::RelocAddend64(co
 
 } // end anonymous namespace
 
+static user_id_t SegmentID(size_t PHdrIndex) { return ~PHdrIndex; }
+
 bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) {
   // Read all fields.
   if (data.GetU32(offset, &n_namesz, 3) == NULL)
@@ -822,7 +826,8 @@ bool ObjectFileELF::SetLoadAddress(Targe
         // Iterate through the object file sections to find all of the sections
         // that have SHF_ALLOC in their flag bits.
         SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
-        if (section_sp && section_sp->Test(SHF_ALLOC)) {
+        if (section_sp->Test(SHF_ALLOC) ||
+            section_sp->GetType() == eSectionTypeContainer) {
           lldb::addr_t load_addr = section_sp->GetFileAddress();
           // We don't want to update the load address of a section with type
           // eSectionTypeAbsoluteAddress as they already have the absolute load
@@ -1821,74 +1826,185 @@ static Permissions GetPermissions(const
   return Perm;
 }
 
+static Permissions GetPermissions(const ELFProgramHeader &H) {
+  Permissions Perm = Permissions(0);
+  if (H.p_flags & PF_R)
+    Perm |= ePermissionsReadable;
+  if (H.p_flags & PF_W)
+    Perm |= ePermissionsWritable;
+  if (H.p_flags & PF_X)
+    Perm |= ePermissionsExecutable;
+  return Perm;
+}
+
 namespace {
+
+using VMRange = lldb_private::Range<addr_t, addr_t>;
+
+struct SectionAddressInfo {
+  SectionSP Segment;
+  VMRange Range;
+};
+
 // (Unlinked) ELF object files usually have 0 for every section address, meaning
 // we need to compute synthetic addresses in order for "file addresses" from
 // different sections to not overlap. This class handles that logic.
 class VMAddressProvider {
-  bool m_synthesizing;
-  addr_t m_next;
+  using VMMap = llvm::IntervalMap<addr_t, SectionSP, 4,
+                                       llvm::IntervalMapHalfOpenInfo<addr_t>>;
+
+  ObjectFile::Type ObjectType;
+  addr_t NextVMAddress = 0;
+  VMMap::Allocator Alloc;
+  VMMap Segments = VMMap(Alloc);
+  VMMap Sections = VMMap(Alloc);
+  lldb_private::Log *Log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES);
+
+  VMRange GetVMRange(const ELFSectionHeader &H) {
+    addr_t Address = H.sh_addr;
+    addr_t Size = H.sh_flags & SHF_ALLOC ? H.sh_size : 0;
+    if (ObjectType == ObjectFile::Type::eTypeObjectFile && Segments.empty() && (H.sh_flags & SHF_ALLOC)) {
+      NextVMAddress =
+          llvm::alignTo(NextVMAddress, std::max<addr_t>(H.sh_addralign, 1));
+      Address = NextVMAddress;
+      NextVMAddress += Size;
+    }
+    return VMRange(Address, Size);
+  }
 
 public:
-  VMAddressProvider(ObjectFile::Type Type)
-      : m_synthesizing(Type == ObjectFile::Type::eTypeObjectFile), m_next(0) {}
+  VMAddressProvider(ObjectFile::Type Type) : ObjectType(Type) {}
 
-  std::pair<addr_t, addr_t> GetAddressAndSize(const ELFSectionHeader &H) {
-    addr_t address = H.sh_addr;
-    addr_t size = H.sh_flags & SHF_ALLOC ? H.sh_size : 0;
-    if (m_synthesizing && (H.sh_flags & SHF_ALLOC)) {
-      m_next = llvm::alignTo(m_next, std::max<addr_t>(H.sh_addralign, 1));
-      address = m_next;
-      m_next += size;
+  llvm::Optional<VMRange> GetAddressInfo(const ELFProgramHeader &H) {
+    if (H.p_memsz == 0) {
+      LLDB_LOG(Log,
+               "Ignoring zero-sized PT_LOAD segment. Corrupt object file?");
+      return llvm::None;
+    }
+
+    if (Segments.overlaps(H.p_vaddr, H.p_vaddr + H.p_memsz)) {
+      LLDB_LOG(Log,
+               "Ignoring overlapping PT_LOAD segment. Corrupt object file?");
+      return llvm::None;
+    }
+    return VMRange(H.p_vaddr, H.p_memsz);
+  }
+
+  llvm::Optional<SectionAddressInfo> GetAddressInfo(const ELFSectionHeader &H) {
+    VMRange Range = GetVMRange(H);
+    SectionSP Segment;
+    auto It = Segments.find(Range.GetRangeBase());
+    if ((H.sh_flags & SHF_ALLOC) && It.valid()) {
+      addr_t MaxSize;
+      if (It.start() <= Range.GetRangeBase()) {
+        MaxSize = It.stop() - Range.GetRangeBase();
+        Segment = *It;
+      } else
+        MaxSize = It.start() - Range.GetRangeBase();
+      if (Range.GetByteSize() > MaxSize) {
+        LLDB_LOG(Log, "Shortening section crossing segment boundaries. "
+                      "Corrupt object file?");
+        Range.SetByteSize(MaxSize);
+      }
     }
-    return {address, size};
+    if (Range.GetByteSize() > 0 &&
+        Sections.overlaps(Range.GetRangeBase(), Range.GetRangeEnd())) {
+      LLDB_LOG(Log, "Ignoring overlapping section. Corrupt object file?");
+      return llvm::None;
+    }
+    if (Segment)
+      Range.Slide(-Segment->GetFileAddress());
+    return SectionAddressInfo{Segment, Range};
+  }
+
+  void AddSegment(const VMRange &Range, SectionSP Seg) {
+    Segments.insert(Range.GetRangeBase(), Range.GetRangeEnd(), std::move(Seg));
+  }
+
+  void AddSection(SectionAddressInfo Info, SectionSP Sect) {
+    if (Info.Range.GetByteSize() == 0)
+      return;
+    if (Info.Segment)
+      Info.Range.Slide(Info.Segment->GetFileAddress());
+    Sections.insert(Info.Range.GetRangeBase(), Info.Range.GetRangeEnd(),
+                    std::move(Sect));
   }
 };
 }
 
 void ObjectFileELF::CreateSections(SectionList &unified_section_list) {
-  if (!m_sections_ap.get() && ParseSectionHeaders()) {
-    m_sections_ap.reset(new SectionList());
+  if (m_sections_ap)
+    return;
 
-    VMAddressProvider address_provider(CalculateType());
-    for (SectionHeaderCollIter I = std::next(m_section_headers.begin());
-         I != m_section_headers.end(); ++I) {
-      const ELFSectionHeaderInfo &header = *I;
-
-      ConstString &name = I->section_name;
-      const uint64_t file_size =
-          header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
-
-      addr_t vm_addr, vm_size;
-      std::tie(vm_addr, vm_size) = address_provider.GetAddressAndSize(header);
-
-      SectionType sect_type = GetSectionType(header);
-
-      const uint32_t target_bytes_size =
-          GetTargetByteSize(sect_type, m_arch_spec);
-
-      elf::elf_xword log2align =
-          (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign);
-
-      SectionSP section_sp(new Section(
-          GetModule(), // Module to which this section belongs.
-          this, // ObjectFile to which this section belongs and should read
-                // section data from.
-          SectionIndex(I),     // Section ID.
-          name,                // Section name.
-          sect_type,           // Section type.
-          vm_addr,             // VM address.
-          vm_size,             // VM size in bytes of this section.
-          header.sh_offset,    // Offset of this section in the file.
-          file_size,           // Size of the section as found in the file.
-          log2align,           // Alignment of the section
-          header.sh_flags,     // Flags for this section.
-          target_bytes_size)); // Number of host bytes per target byte
-
-      section_sp->SetPermissions(GetPermissions(header));
-      section_sp->SetIsThreadSpecific(header.sh_flags & SHF_TLS);
-      m_sections_ap->AddSection(section_sp);
-    }
+  m_sections_ap = llvm::make_unique<SectionList>();
+  VMAddressProvider address_provider(CalculateType());
+
+  size_t LoadID = 0;
+  for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) {
+    const ELFProgramHeader &PHdr = EnumPHdr.value();
+    if (PHdr.p_type != PT_LOAD)
+      continue;
+
+    auto InfoOr = address_provider.GetAddressInfo(PHdr);
+    if (!InfoOr)
+      continue;
+
+    ConstString Name(("PT_LOAD[" + llvm::Twine(LoadID++) + "]").str());
+    uint32_t Log2Align = llvm::Log2_64(std::max<elf_xword>(PHdr.p_align, 1));
+    SectionSP Segment = std::make_shared<Section>(
+        GetModule(), this, SegmentID(EnumPHdr.index()), Name,
+        eSectionTypeContainer, InfoOr->GetRangeBase(), InfoOr->GetByteSize(),
+        PHdr.p_offset, PHdr.p_filesz, Log2Align, /*flags*/ 0);
+    Segment->SetPermissions(GetPermissions(PHdr));
+    m_sections_ap->AddSection(Segment);
+
+    address_provider.AddSegment(*InfoOr, std::move(Segment));
+  }
+
+  ParseSectionHeaders();
+  if (m_section_headers.empty())
+    return;
+
+  for (SectionHeaderCollIter I = std::next(m_section_headers.begin());
+       I != m_section_headers.end(); ++I) {
+    const ELFSectionHeaderInfo &header = *I;
+
+    ConstString &name = I->section_name;
+    const uint64_t file_size =
+        header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
+
+    auto InfoOr = address_provider.GetAddressInfo(header);
+    if (!InfoOr)
+      continue;
+
+    SectionType sect_type = GetSectionType(header);
+
+    const uint32_t target_bytes_size =
+        GetTargetByteSize(sect_type, m_arch_spec);
+
+    elf::elf_xword log2align =
+        (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign);
+
+    SectionSP section_sp(new Section(
+        InfoOr->Segment, GetModule(), // Module to which this section belongs.
+        this,            // ObjectFile to which this section belongs and should
+                         // read section data from.
+        SectionIndex(I), // Section ID.
+        name,            // Section name.
+        sect_type,       // Section type.
+        InfoOr->Range.GetRangeBase(), // VM address.
+        InfoOr->Range.GetByteSize(),  // VM size in bytes of this section.
+        header.sh_offset,             // Offset of this section in the file.
+        file_size,           // Size of the section as found in the file.
+        log2align,           // Alignment of the section
+        header.sh_flags,     // Flags for this section.
+        target_bytes_size)); // Number of host bytes per target byte
+
+    section_sp->SetPermissions(GetPermissions(header));
+    section_sp->SetIsThreadSpecific(header.sh_flags & SHF_TLS);
+    (InfoOr->Segment ? InfoOr->Segment->GetChildren() : *m_sections_ap)
+        .AddSection(section_sp);
+    address_provider.AddSection(std::move(*InfoOr), std::move(section_sp));
   }
 
   // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the




More information about the lldb-commits mailing list