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 §ion_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 §_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 §ion_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();
};