Split symbol support for ELF and Linux.

llvm-svn: 185366
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 9e1febb..5215b08 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -262,13 +262,27 @@
                 if (spec.GetArchitecture().IsValid())
                 {
                     // We could parse the ABI tag information (in .note, .notes, or .note.ABI-tag) to get the
-                    // machine information. However, we'd have to read a good bit of the rest of the file,
-                    // and this info isn't guaranteed to exist or be correct. More details here:
+                    // machine information. However, this info isn't guaranteed to exist or be correct. Details:
                     //  http://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
                     // Instead of passing potentially incorrect information down the pipeline, grab
                     // the host information and use it.
                     spec.GetArchitecture().GetTriple().setOSName (Host::GetOSString().GetCString());
                     spec.GetArchitecture().GetTriple().setVendorName(Host::GetVendorString().GetCString());
+
+                    // Try to get the UUID from the section list. Usually that's at the end, so
+                    // map the file in if we don't have it already.
+                    size_t section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize;
+                    if (section_header_end > data_sp->GetByteSize())
+                    {
+                        data_sp = file.MemoryMapFileContents (file_offset, section_header_end);
+                        data.SetData(data_sp);
+                    }
+
+                    uint32_t gnu_debuglink_crc;
+                    std::string gnu_debuglink_file;
+                    SectionHeaderColl section_headers;
+                    GetSectionHeaderInfo(section_headers, data, header, spec.GetUUID(), gnu_debuglink_file, gnu_debuglink_crc);
+
                     specs.Append(spec);
                 }
             }
@@ -306,12 +320,13 @@
     m_header(),
     m_program_headers(),
     m_section_headers(),
-    m_filespec_ap(),
-    m_shstr_data()
+    m_filespec_ap()
 {
     if (file)
         m_file = *file;
     ::memset(&m_header, 0, sizeof(m_header));
+    m_gnu_debuglink_crc = 0;
+    m_gnu_debuglink_file.clear();
 }
 
 ObjectFileELF::~ObjectFileELF()
@@ -359,18 +374,111 @@
     return m_header.Parse(m_data, &offset);
 }
 
+/*
+ * crc function from http://svnweb.freebsd.org/base/head/sys/libkern/crc32.c
+ *
+ *   COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ *   code or tables extracted from it, as desired without restriction.
+ */
+static uint32_t
+calc_gnu_debuglink_crc32(const void *buf, size_t size)
+{
+    static const uint32_t g_crc32_tab[] =
+    {
+        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+        0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+        0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+        0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+        0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+        0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+        0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+        0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+        0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+        0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+        0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+        0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+        0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+        0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+        0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+        0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+        0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+        0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+        0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+        0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+        0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+        0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+        0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+        0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+        0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+        0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+        0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+        0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+        0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+        0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+        0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+        0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+    };    
+    const uint8_t *p = (const uint8_t *)buf;
+    uint32_t crc;
+
+    crc = ~0U;
+    while (size--)
+        crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+    return crc ^ ~0U;
+}
+
 bool
 ObjectFileELF::GetUUID(lldb_private::UUID* uuid)
 {
+    // Need to parse the section list to get the UUIDs, so make sure that's been done.
+    if (!ParseSectionHeaders())
+        return false;
+
     if (m_uuid.IsValid())
     {
+        // We have the full build id uuid.
         *uuid = m_uuid;
         return true;
     }
-    // FIXME: Return MD5 sum here. See comment in ObjectFile.h.
+    else 
+    {
+        m_gnu_debuglink_crc = calc_gnu_debuglink_crc32 (m_data.GetDataStart(), m_data.GetByteSize());
+        if (m_gnu_debuglink_crc)
+        {
+            // Use 4 bytes of crc from the .gnu_debuglink section.
+            uint32_t uuidt[4] = { m_gnu_debuglink_crc, 0, 0, 0 };
+            uuid->SetBytes (uuidt, sizeof(uuidt));
+            return true;
+        }
+    }
+
     return false;
 }
 
+lldb_private::FileSpecList
+ObjectFileELF::GetDebugSymbolFilePaths()
+{
+    FileSpecList file_spec_list;
+
+    if (!m_gnu_debuglink_file.empty())
+    {
+        FileSpec file_spec (m_gnu_debuglink_file.c_str(), false);
+        file_spec_list.Append (file_spec);
+    }
+    return file_spec_list;
+}
+
 uint32_t
 ObjectFileELF::GetDependentModules(FileSpecList &files)
 {
@@ -416,7 +524,7 @@
     if (!dynsym_id)
         return Address();
 
-    const ELFSectionHeader *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id);
+    const ELFSectionHeaderInfo *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id);
     if (!dynsym_hdr)
         return Address();
 
@@ -477,7 +585,7 @@
 
     m_filespec_ap.reset(new FileSpecList());
 
-    if (!(ParseSectionHeaders() && GetSectionHeaderStringTable()))
+    if (!ParseSectionHeaders())
         return 0;
 
     // Locate the dynamic table.
@@ -574,102 +682,8 @@
     return m_program_headers.size();
 }
 
-//----------------------------------------------------------------------
-// ParseSectionHeaders
-//----------------------------------------------------------------------
-size_t
-ObjectFileELF::ParseSectionHeaders()
-{
-    // We have already parsed the section headers
-    if (!m_section_headers.empty())
-        return m_section_headers.size();
-
-    // If there are no section headers we are done.
-    if (m_header.e_shnum == 0)
-        return 0;
-
-    m_section_headers.resize(m_header.e_shnum);
-    if (m_section_headers.size() != m_header.e_shnum)
-        return 0;
-
-    const size_t sh_size = m_header.e_shnum * m_header.e_shentsize;
-    const elf_off sh_offset = m_header.e_shoff;
-    DataExtractor data;
-    if (GetData (sh_offset, sh_size, data) != sh_size)
-        return 0;
-
-    uint32_t idx;
-    lldb::offset_t offset;
-    for (idx = 0, offset = 0; idx < m_header.e_shnum; ++idx)
-    {
-        if (m_section_headers[idx].Parse(data, &offset) == false)
-            break;
-    }
-    if (idx < m_section_headers.size())
-        m_section_headers.resize(idx);
-
-    return m_section_headers.size();
-}
-
-size_t
-ObjectFileELF::GetSectionHeaderStringTable()
-{
-    if (m_shstr_data.GetByteSize() == 0)
-    {
-        const unsigned strtab_idx = m_header.e_shstrndx;
-
-        if (strtab_idx && strtab_idx < m_section_headers.size())
-        {
-            const ELFSectionHeader &sheader = m_section_headers[strtab_idx];
-            const size_t byte_size = sheader.sh_size;
-            const Elf64_Off offset = sheader.sh_offset;
-            m_shstr_data.SetData (m_data, offset, byte_size);
-
-            if (m_shstr_data.GetByteSize() != byte_size)
-                return 0;
-        }
-    }
-    return m_shstr_data.GetByteSize();
-}
-
-lldb::user_id_t
-ObjectFileELF::GetSectionIndexByName(const char *name)
-{
-    if (!(ParseSectionHeaders() && GetSectionHeaderStringTable()))
-        return 0;
-
-    // Search the collection of section headers for one with a matching name.
-    for (SectionHeaderCollIter I = m_section_headers.begin();
-         I != m_section_headers.end(); ++I)
-    {
-        const char *sectionName = m_shstr_data.PeekCStr(I->sh_name);
-
-        if (!sectionName)
-            return 0;
-
-        if (strcmp(name, sectionName) != 0)
-            continue;
-
-        return SectionIndex(I);
-    }
-
-    return 0;
-}
-
-const elf::ELFSectionHeader *
-ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id)
-{
-    if (!ParseSectionHeaders() || !id)
-        return NULL;
-
-    if (--id < m_section_headers.size())
-        return &m_section_headers[id];
-
-    return NULL;
-}
-
 static bool
-ParseNoteGNUBuildID(DataExtractor& data, lldb_private::UUID& uuid)
+ParseNoteGNUBuildID(DataExtractor &data, lldb_private::UUID &uuid)
 {
     // Try to parse the note section (ie .note.gnu.build-id|.notes|.note|...) and get the build id.
     // BuildID documentation: https://fedoraproject.org/wiki/Releases/FeatureBuildId
@@ -712,23 +726,158 @@
     }
     return false;
 }
- 
+
+//----------------------------------------------------------------------
+// GetSectionHeaderInfo
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
+                                    lldb_private::DataExtractor &object_data,
+                                    const elf::ELFHeader &header,
+                                    lldb_private::UUID &uuid,
+                                    std::string &gnu_debuglink_file,
+                                    uint32_t &gnu_debuglink_crc)
+{
+    // We have already parsed the section headers
+    if (!section_headers.empty())
+        return section_headers.size();
+
+    // If there are no section headers we are done.
+    if (header.e_shnum == 0)
+        return 0;
+
+    section_headers.resize(header.e_shnum);
+    if (section_headers.size() != header.e_shnum)
+        return 0;
+
+    const size_t sh_size = header.e_shnum * header.e_shentsize;
+    const elf_off sh_offset = header.e_shoff;
+    DataExtractor sh_data;
+    if (sh_data.SetData (object_data, sh_offset, sh_size) != sh_size)
+        return 0;
+
+    uint32_t idx;
+    lldb::offset_t offset;
+    for (idx = 0, offset = 0; idx < header.e_shnum; ++idx)
+    {
+        if (section_headers[idx].Parse(sh_data, &offset) == false)
+            break;
+    }
+    if (idx < section_headers.size())
+        section_headers.resize(idx);
+
+    const unsigned strtab_idx = header.e_shstrndx;
+    if (strtab_idx && strtab_idx < section_headers.size())
+    {
+        const ELFSectionHeaderInfo &sheader = section_headers[strtab_idx];
+        const size_t byte_size = sheader.sh_size;
+        const Elf64_Off offset = sheader.sh_offset;
+        lldb_private::DataExtractor shstr_data;
+
+        if (shstr_data.SetData (object_data, offset, byte_size) == byte_size)
+        {
+            for (SectionHeaderCollIter I = section_headers.begin();
+                 I != section_headers.end(); ++I)
+            {
+                static ConstString g_sect_name_gnu_debuglink (".gnu_debuglink");
+                const ELFSectionHeaderInfo &header = *I;
+                const uint64_t section_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
+                ConstString name(shstr_data.PeekCStr(I->sh_name));
+
+                I->section_name = name;
+
+                if (name == g_sect_name_gnu_debuglink)
+                {
+                    DataExtractor data;
+                    if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
+                    {
+                        lldb::offset_t gnu_debuglink_offset = 0;
+                        gnu_debuglink_file = data.GetCStr (&gnu_debuglink_offset);
+                        gnu_debuglink_offset = llvm::RoundUpToAlignment (gnu_debuglink_offset, 4);
+                        data.GetU32 (&gnu_debuglink_offset, &gnu_debuglink_crc, 1);
+                    }
+                }
+
+                if (header.sh_type == SHT_NOTE && !uuid.IsValid())
+                {
+                    DataExtractor data;
+                    if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
+                    {
+                        ParseNoteGNUBuildID (data, uuid);
+                    }
+                }
+            }
+
+            return section_headers.size();
+        }
+    }
+
+    section_headers.clear();
+    return 0;
+}
+
+//----------------------------------------------------------------------
+// ParseSectionHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseSectionHeaders()
+{
+    return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc);
+}
+
+lldb::user_id_t
+ObjectFileELF::GetSectionIndexByName(const char *name)
+{
+    if (!ParseSectionHeaders())
+        return 0;
+
+    // Search the collection of section headers for one with a matching name.
+    for (SectionHeaderCollIter I = m_section_headers.begin();
+         I != m_section_headers.end(); ++I)
+    {
+        const char *sectionName = I->section_name.AsCString();
+
+        if (!sectionName)
+            return 0;
+
+        if (strcmp(name, sectionName) != 0)
+            continue;
+
+        return SectionIndex(I);
+    }
+
+    return 0;
+}
+
+const ObjectFileELF::ELFSectionHeaderInfo *
+ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id)
+{
+    if (!ParseSectionHeaders() || !id)
+        return NULL;
+
+    if (--id < m_section_headers.size())
+        return &m_section_headers[id];
+
+    return NULL;
+}
+
+
 SectionList *
 ObjectFileELF::GetSectionList()
 {
     if (m_sections_ap.get())
         return m_sections_ap.get();
 
-    if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+    if (ParseSectionHeaders())
     {
         m_sections_ap.reset(new SectionList());
 
         for (SectionHeaderCollIter I = m_section_headers.begin();
              I != m_section_headers.end(); ++I)
         {
-            const ELFSectionHeader &header = *I;
+            const ELFSectionHeaderInfo &header = *I;
 
-            ConstString name(m_shstr_data.PeekCStr(header.sh_name));
+            ConstString& name = I->section_name;
             const uint64_t file_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
             const uint64_t vm_size = header.sh_flags & SHF_ALLOC ? header.sh_size : 0;
 
@@ -753,7 +902,7 @@
             SectionType sect_type = eSectionTypeOther;
 
             bool is_thread_specific = false;
-            
+
             if      (name == g_sect_name_text)                  sect_type = eSectionTypeCode;
             else if (name == g_sect_name_data)                  sect_type = eSectionTypeData;
             else if (name == g_sect_name_bss)                   sect_type = eSectionTypeZeroFill;
@@ -767,6 +916,19 @@
                 sect_type = eSectionTypeZeroFill;   
                 is_thread_specific = true;   
             }
+            // .debug_abbrev – Abbreviations used in the .debug_info section
+            // .debug_aranges – Lookup table for mapping addresses to compilation units
+            // .debug_frame – Call frame information
+            // .debug_info – The core DWARF information section
+            // .debug_line – Line number information
+            // .debug_loc – Location lists used in DW_AT_location attributes
+            // .debug_macinfo – Macro information
+            // .debug_pubnames – Lookup table for mapping object and function names to compilation units
+            // .debug_pubtypes – Lookup table for mapping type names to compilation units
+            // .debug_ranges – Address ranges used in DW_AT_ranges attributes
+            // .debug_str – String table used in .debug_info
+            // MISSING? .debug-index http://src.chromium.org/viewvc/chrome/trunk/src/build/gdb-add-index?pathrev=144644
+            // MISSING? .debug_types - Type descriptions from DWARF 4? See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo
             else if (name == g_sect_name_dwarf_debug_abbrev)    sect_type = eSectionTypeDWARFDebugAbbrev;
             else if (name == g_sect_name_dwarf_debug_aranges)   sect_type = eSectionTypeDWARFDebugAranges;
             else if (name == g_sect_name_dwarf_debug_frame)     sect_type = eSectionTypeDWARFDebugFrame;
@@ -779,20 +941,31 @@
             else if (name == g_sect_name_dwarf_debug_ranges)    sect_type = eSectionTypeDWARFDebugRanges;
             else if (name == g_sect_name_dwarf_debug_str)       sect_type = eSectionTypeDWARFDebugStr;
             else if (name == g_sect_name_eh_frame)              sect_type = eSectionTypeEHFrame;
-            else if (header.sh_type == SHT_NOTE)
+
+            switch (header.sh_type)
             {
-                if (!m_uuid.IsValid())
-                {
-                    DataExtractor data;
-                    if (vm_size && (GetData (header.sh_offset, vm_size, data) == vm_size))
-                    {
-                        ParseNoteGNUBuildID (data, m_uuid);
-                    }
-                }
+                case SHT_SYMTAB:
+                    assert (sect_type == eSectionTypeOther);
+                    sect_type = eSectionTypeELFSymbolTable;
+                    break;
+                case SHT_DYNSYM:
+                    assert (sect_type == eSectionTypeOther);
+                    sect_type = eSectionTypeELFDynamicSymbols;
+                    break;
+                case SHT_RELA:
+                case SHT_REL:
+                    assert (sect_type == eSectionTypeOther);
+                    sect_type = eSectionTypeELFRelocationEntries;
+                    break;
+                case SHT_DYNAMIC:
+                    assert (sect_type == eSectionTypeOther);
+                    sect_type = eSectionTypeELFDynamicLinkInfo;
+                    break;
             }
-            
+
             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.
@@ -806,18 +979,18 @@
                 section_sp->SetIsThreadSpecific (is_thread_specific);
             m_sections_ap->AddSection(section_sp);
         }
-        
+
         m_sections_ap->Finalize(); // Now that we're done adding sections, finalize to build fast-lookup caches
     }
 
     return m_sections_ap.get();
 }
 
-static unsigned
-ParseSymbols(Symtab *symtab, 
+unsigned
+ObjectFileELF::ParseSymbols(Symtab *symtab, 
              user_id_t start_id,
              SectionList *section_list,
-             const ELFSectionHeader *symtab_shdr,
+             const ELFSectionHeaderInfo *symtab_shdr,
              const DataExtractor &symtab_data,
              const DataExtractor &strtab_data)
 {
@@ -936,6 +1109,29 @@
             }
         }
 
+        // If the symbol section we've found has no data (SHT_NOBITS), then check the module
+        // for the main object file and use the section there if it has data. This can happen
+        // if we're parsing the debug file and the it has no .text section, for example.
+        if (symbol_section_sp && (symbol_section_sp->GetFileSize() == 0))
+        {
+            ModuleSP module_sp(GetModule());
+            if (module_sp)
+            {
+                ObjectFile *obj_file = module_sp->GetObjectFile();
+                // Check if we've got a different object file than ourselves.
+                if (obj_file && (obj_file != this))
+                {
+                    const ConstString &sect_name = symbol_section_sp->GetName();
+                    SectionList *obj_file_section_list = obj_file->GetSectionList();
+                    lldb::SectionSP section_sp (obj_file_section_list->FindSectionByName (sect_name));
+                    if (section_sp && section_sp->GetFileSize())
+                    {
+                        symbol_section_sp = section_sp;
+                    }
+                }
+            }
+        }
+
         uint64_t symbol_value = symbol.st_value;
         if (symbol_section_sp)
             symbol_value -= symbol_section_sp->GetFileAddress();
@@ -963,18 +1159,17 @@
 }
 
 unsigned
-ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id,
-                                const ELFSectionHeader *symtab_hdr,
-                                user_id_t symtab_id)
+ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, user_id_t symtab_id)
 {
-    assert(symtab_hdr->sh_type == SHT_SYMTAB || 
-           symtab_hdr->sh_type == SHT_DYNSYM);
-
     // Parse in the section list if needed.
     SectionList *section_list = GetSectionList();
     if (!section_list)
         return 0;
 
+    const ELFSectionHeaderInfo *symtab_hdr = &m_section_headers[symtab_id - 1];
+    assert(symtab_hdr->sh_type == SHT_SYMTAB || 
+           symtab_hdr->sh_type == SHT_DYNSYM);
+
     // Section ID's are ones based.
     user_id_t strtab_id = symtab_hdr->sh_link + 1;
 
@@ -1040,10 +1235,6 @@
     if (!ParseDynamicSymbols())
         return NULL;
 
-    SectionList *section_list = GetSectionList();
-    if (!section_list)
-        return 0;
-
     DynamicSymbolCollIter I = m_dynamic_symbols.begin();
     DynamicSymbolCollIter E = m_dynamic_symbols.end();
     for ( ; I != E; ++I)
@@ -1057,21 +1248,6 @@
     return NULL;
 }
 
-Section *
-ObjectFileELF::PLTSection()
-{
-    const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL);
-    SectionList *section_list = GetSectionList();
-
-    if (symbol && section_list)
-    {
-        addr_t addr = symbol->d_ptr;
-        return section_list->FindSectionContainingFileAddress(addr).get();
-    }
-
-    return NULL;
-}
-
 unsigned
 ObjectFileELF::PLTRelocationType()
 {
@@ -1160,12 +1336,12 @@
 unsigned
 ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table,
                                       user_id_t start_id,
-                                      const ELFSectionHeader *rel_hdr,
+                                      const ELFSectionHeaderInfo *rel_hdr,
                                       user_id_t rel_id)
 {
     assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL);
 
-    // The link field points to the asscoiated symbol table.  The info field
+    // The link field points to the associated symbol table.  The info field
     // points to the section holding the plt.
     user_id_t symtab_id = rel_hdr->sh_link;
     user_id_t plt_id = rel_hdr->sh_info;
@@ -1177,11 +1353,11 @@
     symtab_id++;
     plt_id++;
 
-    const ELFSectionHeader *plt_hdr = GetSectionHeaderByIndex(plt_id);
+    const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id);
     if (!plt_hdr)
         return 0;
 
-    const ELFSectionHeader *sym_hdr = GetSectionHeaderByIndex(symtab_id);
+    const ELFSectionHeaderInfo *sym_hdr = GetSectionHeaderByIndex(symtab_id);
     if (!sym_hdr)
         return 0;
 
@@ -1235,45 +1411,82 @@
 }
 
 Symtab *
-ObjectFileELF::GetSymtab()
+ObjectFileELF::GetSymtab(uint32_t flags)
 {
-    if (m_symtab_ap.get())
-        return m_symtab_ap.get();
-
-    Symtab *symbol_table = new Symtab(this);
-    m_symtab_ap.reset(symbol_table);
-
-    Mutex::Locker locker(symbol_table->GetMutex());
-    
-    if (!(ParseSectionHeaders() && GetSectionHeaderStringTable()))
-        return symbol_table;
-
-    // Locate and parse all linker symbol tables.
-    uint64_t symbol_id = 0;
-    for (SectionHeaderCollIter I = m_section_headers.begin();
-         I != m_section_headers.end(); ++I)
+    ModuleSP module_sp(GetModule());
+    if (module_sp)
     {
-        if (I->sh_type == SHT_SYMTAB || I->sh_type == SHT_DYNSYM)
+        lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+
+        bool from_unified_section_list = !!(flags & eSymtabFromUnifiedSectionList);
+        SectionList *section_list = from_unified_section_list ? module_sp->GetUnifiedSectionList() : GetSectionList();
+        if (!section_list)
+            return NULL;
+
+        // If we're doing the unified section list and it has been modified, then clear our
+        // cache and reload the symbols. If needed, we could check on only the sections that
+        // we use to create the symbol table...
+        std::unique_ptr<lldb_private::Symtab> &symtab_ap = from_unified_section_list ? m_symtab_unified_ap : m_symtab_ap;
+        if (from_unified_section_list && (m_symtab_unified_revisionid != section_list->GetRevisionID()))
         {
-            const ELFSectionHeader &symtab_header = *I;
-            user_id_t section_id = SectionIndex(I);
-            symbol_id += ParseSymbolTable(symbol_table, symbol_id,
-                                          &symtab_header, section_id);
+            symtab_ap.reset();
+            m_symtab_unified_revisionid = section_list->GetRevisionID();
         }
-    }
-    
-    // Synthesize trampoline symbols to help navigate the PLT.
-    Section *reloc_section = PLTSection();
-    if (reloc_section) 
-    {
-        user_id_t reloc_id = reloc_section->GetID();
-        const ELFSectionHeader *reloc_header = GetSectionHeaderByIndex(reloc_id);
-        assert(reloc_header);
+        else if (symtab_ap.get())
+        {
+            return symtab_ap.get();
+        }
 
-        ParseTrampolineSymbols(symbol_table, symbol_id, reloc_header, reloc_id);
-    }
+        Symtab *symbol_table = new Symtab(this);
+        symtab_ap.reset(symbol_table);
 
-    return symbol_table;
+        // Sharable objects and dynamic executables usually have 2 distinct symbol
+        // tables, one named ".symtab", and the other ".dynsym". The dynsym is a smaller
+        // version of the symtab that only contains global symbols. The information found
+        // in the dynsym is therefore also found in the symtab, while the reverse is not
+        // necessarily true.
+        Section *section_sym = section_list->FindSectionByType (eSectionTypeELFSymbolTable, true).get();
+        if (!section_sym)
+        {
+            // The symtab section is non-allocable and can be stripped, so if it doesn't exist
+            // then use the dynsym section which should always be there.
+            section_sym = section_list->FindSectionByType (eSectionTypeELFDynamicSymbols, true).get();
+        }
+
+        uint64_t symbol_id = 0;
+        if (section_sym)
+        {
+            user_id_t section_id = section_sym->GetID();
+            ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(section_sym->GetObjectFile());
+
+            symbol_id += obj_file_elf->ParseSymbolTable (symbol_table, symbol_id, section_id);
+        }
+
+        Section *section = section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true).get();
+        if (section)
+        {
+            ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(section->GetObjectFile());
+
+            // Synthesize trampoline symbols to help navigate the PLT.
+            const ELFDynamic *symbol = obj_file_elf->FindDynamicSymbol(DT_JMPREL);
+            if (symbol)
+            {
+                addr_t addr = symbol->d_ptr;
+                Section *reloc_section = section_list->FindSectionContainingFileAddress(addr).get();
+                if (reloc_section) 
+                {
+                    user_id_t reloc_id = reloc_section->GetID();
+                    const ELFSectionHeaderInfo *reloc_header = obj_file_elf->GetSectionHeaderByIndex(reloc_id);
+                    assert(reloc_header);
+
+                    obj_file_elf->ParseTrampolineSymbols(symbol_table, symbol_id, reloc_header, reloc_id);
+                }
+            }
+        }
+
+        return symbol_table;
+    }
+    return NULL;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1472,7 +1685,7 @@
 // Dump a single ELF section header to the specified output stream
 //----------------------------------------------------------------------
 void
-ObjectFileELF::DumpELFSectionHeader(Stream *s, const ELFSectionHeader &sh)
+ObjectFileELF::DumpELFSectionHeader(Stream *s, const ELFSectionHeaderInfo &sh)
 {
     s->Printf("%8.8x ", sh.sh_name);
     DumpELFSectionHeader_sh_type(s, sh.sh_type);
@@ -1540,7 +1753,7 @@
 void
 ObjectFileELF::DumpELFSectionHeaders(Stream *s)
 {
-    if (!(ParseSectionHeaders() && GetSectionHeaderStringTable()))
+    if (!ParseSectionHeaders())
         return;
 
     s->PutCString("Section Headers\n");
@@ -1557,7 +1770,7 @@
     {
         s->Printf("[%2u] ", idx);
         ObjectFileELF::DumpELFSectionHeader(s, *I);
-        const char* section_name = m_shstr_data.PeekCStr(I->sh_name);
+        const char* section_name = I->section_name.AsCString("");
         if (section_name)
             *s << ' ' << section_name << "\n";
     }
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index f1fea3c..a6e3cbb 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -100,7 +100,7 @@
     GetAddressByteSize() const;
 
     virtual lldb_private::Symtab *
-    GetSymtab();
+    GetSymtab(uint32_t flags = 0);
 
     virtual lldb_private::SectionList *
     GetSectionList();
@@ -114,6 +114,9 @@
     virtual bool
     GetUUID(lldb_private::UUID* uuid);
 
+    virtual lldb_private::FileSpecList
+    GetDebugSymbolFilePaths();
+
     virtual uint32_t
     GetDependentModules(lldb_private::FileSpecList& files);
 
@@ -141,7 +144,11 @@
     typedef ProgramHeaderColl::iterator         ProgramHeaderCollIter;
     typedef ProgramHeaderColl::const_iterator   ProgramHeaderCollConstIter;
 
-    typedef std::vector<elf::ELFSectionHeader>  SectionHeaderColl;
+    struct ELFSectionHeaderInfo : public elf::ELFSectionHeader
+    {
+        lldb_private::ConstString section_name;
+    };
+    typedef std::vector<ELFSectionHeaderInfo>   SectionHeaderColl;
     typedef SectionHeaderColl::iterator         SectionHeaderCollIter;
     typedef SectionHeaderColl::const_iterator   SectionHeaderCollConstIter;
 
@@ -155,9 +162,13 @@
     /// ELF file header.
     elf::ELFHeader m_header;
 
-    /// ELF build ID
+    /// ELF build ID.
     lldb_private::UUID m_uuid;
 
+    /// ELF .gnu_debuglink file and crc data if available.
+    std::string m_gnu_debuglink_file;
+    uint32_t m_gnu_debuglink_crc;
+
     /// Collection of program headers.
     ProgramHeaderColl m_program_headers;
 
@@ -171,9 +182,6 @@
     /// libraries) on which this object file depends.
     mutable std::unique_ptr<lldb_private::FileSpecList> m_filespec_ap;
 
-    /// Data extractor holding the string table used to resolve section names.
-    lldb_private::DataExtractor m_shstr_data;
-
     /// Cached value of the entry point for this module.
     lldb_private::Address  m_entry_point_address;
 
@@ -197,6 +205,15 @@
     size_t
     ParseSectionHeaders();
 
+    /// Parses the elf section headers and returns the uuid, debug link name, crc.
+    static size_t
+    GetSectionHeaderInfo(SectionHeaderColl &section_headers,
+                         lldb_private::DataExtractor &data,
+                         const elf::ELFHeader &header,
+                         lldb_private::UUID &uuid,
+                         std::string &gnu_debuglink_file,
+                         uint32_t &gnu_debuglink_crc);
+
     /// Scans the dynamic section and locates all dependent modules (shared
     /// libraries) populating m_filespec_ap.  This method will compute the
     /// dependent module list only once.  Returns the number of dependent
@@ -215,23 +232,26 @@
     unsigned
     ParseSymbolTable(lldb_private::Symtab *symbol_table,
                      lldb::user_id_t start_id,
-                     const elf::ELFSectionHeader *symtab_section,
                      lldb::user_id_t symtab_id);
 
+    /// Helper routine for ParseSymbolTable().
+    unsigned
+    ParseSymbols(lldb_private::Symtab *symbol_table, 
+                 lldb::user_id_t start_id,
+                 lldb_private::SectionList *section_list,
+                 const ELFSectionHeaderInfo *symtab_shdr,
+                 const lldb_private::DataExtractor &symtab_data,
+                 const lldb_private::DataExtractor &strtab_data);
+
     /// Scans the relocation entries and adds a set of artificial symbols to the
     /// given symbol table for each PLT slot.  Returns the number of symbols
     /// added.
     unsigned
     ParseTrampolineSymbols(lldb_private::Symtab *symbol_table, 
                            lldb::user_id_t start_id,
-                           const elf::ELFSectionHeader *rela_hdr,
+                           const ELFSectionHeaderInfo *rela_hdr,
                            lldb::user_id_t section_id);
 
-    /// Loads the section name string table into m_shstr_data.  Returns the
-    /// number of bytes constituting the table.
-    size_t
-    GetSectionHeaderStringTable();
-
     /// Utility method for looking up a section given its name.  Returns the
     /// index of the corresponding section or zero if no section with the given
     /// name can be found (note that section indices are always 1 based, and so
@@ -244,7 +264,7 @@
     GetSectionIndexByType(unsigned type);
 
     /// Returns the section header with the given id or NULL.
-    const elf::ELFSectionHeader *
+    const ELFSectionHeaderInfo *
     GetSectionHeaderByIndex(lldb::user_id_t id);
 
     /// @name  ELF header dump routines
@@ -284,7 +304,7 @@
 
     static void
     DumpELFSectionHeader(lldb_private::Stream *s, 
-                         const elf::ELFSectionHeader& sh);
+                         const ELFSectionHeaderInfo& sh);
 
     static void
     DumpELFSectionHeader_sh_type(lldb_private::Stream *s, 
@@ -302,9 +322,6 @@
     const elf::ELFDynamic *
     FindDynamicSymbol(unsigned tag);
         
-    lldb_private::Section *
-    PLTSection();
-
     unsigned
     PLTRelocationType();
 };