Open ELF core dumps with more than 64K sections

Summary:
Problem:

There are three filelds in the ELF header - e_phnum, e_shnum, and e_shstrndx -
that could be bigger than 64K and therefore do not fit in 16 bits reserved for
them in the header. If this happens, pretty often there is a special section at
index 0 which contains their real values for these fields in the section header
in the fields sh_info, sh_size, and sh_link respectively.

Fix:

- Rename original fields in the header declaration. We want to have them around
just in case.

- Reintroduce these fields as 32-bit members at the end of the header. By default
they are initialized from the header in Parse() method.

- In Parse(), detect the situation when the header might have been extended into
section info #0 and try to read it from the same data source.

- ObjectFileELF::GetModuleSpecifications accesses some of these fields but the
original parse uses too small data source. Re-parse the header if necessary
using bigger data source.

- ProcessElfCore::CreateInstance uses header with potentially sentinel values,
but it does not access these fields, so a comment here is enough.

Reviewers: labath

Reviewed By: labath

Subscribers: davidb, lldb-commits, mgorny

Differential Revision: https://reviews.llvm.org/D29095
Author: Eugene Birukov <eugenebi@hotmail.com>

llvm-svn: 293714
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
index a3e8239..34b32a1 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
@@ -81,6 +81,39 @@
   return eByteOrderInvalid;
 }
 
+bool ELFHeader::HasHeaderExtension() const {
+  bool result = false;
+
+  // Check if any of these values looks like sentinel.
+  result |= e_phnum_hdr == 0xFFFF; // PN_XNUM
+  result |= e_shnum_hdr == SHN_UNDEF;
+  result |= e_shstrndx_hdr == SHN_XINDEX;
+
+  // If header extension is present, the section offset cannot be null.
+  result &= e_shoff != 0;
+
+  // Done.
+  return result;
+}
+
+void ELFHeader::ParseHeaderExtension(lldb_private::DataExtractor &data) {
+  // Extract section #0 header.
+  ELFSectionHeader section_zero;
+  lldb::offset_t offset = 0;
+  lldb_private::DataExtractor sh_data(data, e_shoff, e_shentsize);
+  bool ok = section_zero.Parse(sh_data, &offset);
+
+  // If we succeeded, fix the header.
+  if (ok) {
+    if (e_phnum_hdr == 0xFFFF) // PN_XNUM
+      e_phnum = section_zero.sh_info;
+    if (e_shnum_hdr == SHN_UNDEF)
+      e_shnum = section_zero.sh_size;
+    if (e_shstrndx_hdr == SHN_XINDEX)
+      e_shstrndx = section_zero.sh_link;
+  }
+}
+
 bool ELFHeader::Parse(lldb_private::DataExtractor &data,
                       lldb::offset_t *offset) {
   // Read e_ident.  This provides byte order and address size info.
@@ -112,6 +145,16 @@
   if (data.GetU16(offset, &e_ehsize, 6) == NULL)
     return false;
 
+  // Initialize e_phnum, e_shnum, and e_shstrndx with the values
+  // read from the header.
+  e_phnum = e_phnum_hdr;
+  e_shnum = e_shnum_hdr;
+  e_shstrndx = e_shstrndx_hdr;
+
+  // See if we have extended header in section #0.
+  if (HasHeaderExtension())
+    ParseHeaderExtension(data);
+
   return true;
 }