diff options
Diffstat (limited to 'lldb/source/Plugins/ObjectFile')
6 files changed, 428 insertions, 190 deletions
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 9e1febb7e75..5215b081ee9 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -262,13 +262,27 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, 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 @@ ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp, 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 @@ ObjectFileELF::ParseHeader() 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 @@ ObjectFileELF::GetImageInfoAddress() 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 @@ ObjectFileELF::ParseDependentModules() m_filespec_ap.reset(new FileSpecList()); - if (!(ParseSectionHeaders() && GetSectionHeaderStringTable())) + if (!ParseSectionHeaders()) return 0; // Locate the dynamic table. @@ -574,75 +682,160 @@ ObjectFileELF::ParseProgramHeaders() return m_program_headers.size(); } +static bool +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 + struct + { + uint32_t name_len; // Length of note name + uint32_t desc_len; // Length of note descriptor + uint32_t type; // Type of note (1 is ABI_TAG, 3 is BUILD_ID) + } notehdr; + lldb::offset_t offset = 0; + static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h + + while (true) + { + if (data.GetU32 (&offset, ¬ehdr, 3) == NULL) + return false; + + notehdr.name_len = llvm::RoundUpToAlignment (notehdr.name_len, 4); + notehdr.desc_len = llvm::RoundUpToAlignment (notehdr.desc_len, 4); + + lldb::offset_t offset_next_note = offset + notehdr.name_len + notehdr.desc_len; + + // 16 bytes is UUID|MD5, 20 bytes is SHA1 + if ((notehdr.type == g_gnu_build_id) && (notehdr.name_len == 4) && + (notehdr.desc_len == 16 || notehdr.desc_len == 20)) + { + char name[4]; + if (data.GetU8 (&offset, name, 4) == NULL) + return false; + if (!strcmp(name, "GNU")) + { + uint8_t uuidbuf[20]; + if (data.GetU8 (&offset, &uuidbuf, notehdr.desc_len) == NULL) + return false; + uuid.SetBytes (uuidbuf, notehdr.desc_len); + return true; + } + } + offset = offset_next_note; + } + return false; +} + //---------------------------------------------------------------------- -// ParseSectionHeaders +// GetSectionHeaderInfo //---------------------------------------------------------------------- size_t -ObjectFileELF::ParseSectionHeaders() +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 (!m_section_headers.empty()) - return m_section_headers.size(); + if (!section_headers.empty()) + return section_headers.size(); // If there are no section headers we are done. - if (m_header.e_shnum == 0) + if (header.e_shnum == 0) return 0; - m_section_headers.resize(m_header.e_shnum); - if (m_section_headers.size() != m_header.e_shnum) + section_headers.resize(header.e_shnum); + if (section_headers.size() != 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) + 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 < m_header.e_shnum; ++idx) + for (idx = 0, offset = 0; idx < header.e_shnum; ++idx) { - if (m_section_headers[idx].Parse(data, &offset) == false) + if (section_headers[idx].Parse(sh_data, &offset) == false) break; } - if (idx < m_section_headers.size()) - m_section_headers.resize(idx); + if (idx < section_headers.size()) + section_headers.resize(idx); - return m_section_headers.size(); -} - -size_t -ObjectFileELF::GetSectionHeaderStringTable() -{ - if (m_shstr_data.GetByteSize() == 0) + const unsigned strtab_idx = header.e_shstrndx; + if (strtab_idx && strtab_idx < section_headers.size()) { - const unsigned strtab_idx = m_header.e_shstrndx; + 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 (strtab_idx && strtab_idx < m_section_headers.size()) + if (shstr_data.SetData (object_data, offset, byte_size) == byte_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); + 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 (m_shstr_data.GetByteSize() != byte_size) - return 0; + 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(); } } - return m_shstr_data.GetByteSize(); + + 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() && GetSectionHeaderStringTable())) + 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 = m_shstr_data.PeekCStr(I->sh_name); + const char *sectionName = I->section_name.AsCString(); if (!sectionName) return 0; @@ -656,7 +849,7 @@ ObjectFileELF::GetSectionIndexByName(const char *name) return 0; } -const elf::ELFSectionHeader * +const ObjectFileELF::ELFSectionHeaderInfo * ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) { if (!ParseSectionHeaders() || !id) @@ -668,67 +861,23 @@ ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) return NULL; } -static bool -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 - struct - { - uint32_t name_len; // Length of note name - uint32_t desc_len; // Length of note descriptor - uint32_t type; // Type of note (1 is ABI_TAG, 3 is BUILD_ID) - } notehdr; - lldb::offset_t offset = 0; - static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h - while (true) - { - if (data.GetU32 (&offset, ¬ehdr, 3) == NULL) - return false; - - notehdr.name_len = llvm::RoundUpToAlignment (notehdr.name_len, 4); - notehdr.desc_len = llvm::RoundUpToAlignment (notehdr.desc_len, 4); - - lldb::offset_t offset_next_note = offset + notehdr.name_len + notehdr.desc_len; - - // 16 bytes is UUID|MD5, 20 bytes is SHA1 - if ((notehdr.type == g_gnu_build_id) && (notehdr.name_len == 4) && - (notehdr.desc_len == 16 || notehdr.desc_len == 20)) - { - char name[4]; - if (data.GetU8 (&offset, name, 4) == NULL) - return false; - if (!strcmp(name, "GNU")) - { - uint8_t uuidbuf[20]; - if (data.GetU8 (&offset, &uuidbuf, notehdr.desc_len) == NULL) - return false; - uuid.SetBytes (uuidbuf, notehdr.desc_len); - return true; - } - } - offset = offset_next_note; - } - return false; -} - 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 @@ ObjectFileELF::GetSectionList() 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 @@ ObjectFileELF::GetSectionList() 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 @@ ObjectFileELF::GetSectionList() 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 @@ ObjectFileELF::GetSectionList() 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 @@ ParseSymbols(Symtab *symtab, } } + // 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 @@ ParseSymbols(Symtab *symtab, } 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 @@ ObjectFileELF::FindDynamicSymbol(unsigned tag) 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 @@ ObjectFileELF::FindDynamicSymbol(unsigned tag) 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 @@ ParsePLTRelocations(Symtab *symbol_table, 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 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, 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 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, } Symtab * -ObjectFileELF::GetSymtab() +ObjectFileELF::GetSymtab(uint32_t flags) { - if (m_symtab_ap.get()) - return m_symtab_ap.get(); + ModuleSP module_sp(GetModule()); + if (module_sp) + { + 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())) + { + symtab_ap.reset(); + m_symtab_unified_revisionid = section_list->GetRevisionID(); + } + else if (symtab_ap.get()) + { + return symtab_ap.get(); + } - Symtab *symbol_table = new Symtab(this); - m_symtab_ap.reset(symbol_table); + Symtab *symbol_table = new Symtab(this); + symtab_ap.reset(symbol_table); - Mutex::Locker locker(symbol_table->GetMutex()); - - if (!(ParseSectionHeaders() && GetSectionHeaderStringTable())) - 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(); + } - // 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) - { - if (I->sh_type == SHT_SYMTAB || I->sh_type == SHT_DYNSYM) + uint64_t symbol_id = 0; + if (section_sym) { - const ELFSectionHeader &symtab_header = *I; - user_id_t section_id = SectionIndex(I); - symbol_id += ParseSymbolTable(symbol_table, symbol_id, - &symtab_header, section_id); + 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); } - } - - // 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); - ParseTrampolineSymbols(symbol_table, symbol_id, reloc_header, reloc_id); - } + Section *section = section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true).get(); + if (section) + { + ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(section->GetObjectFile()); - return symbol_table; + // 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 @@ ObjectFileELF::DumpELFProgramHeaders(Stream *s) // 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 @@ ObjectFileELF::DumpELFSectionHeader_sh_flags(Stream *s, elf_xword sh_flags) void ObjectFileELF::DumpELFSectionHeaders(Stream *s) { - if (!(ParseSectionHeaders() && GetSectionHeaderStringTable())) + if (!ParseSectionHeaders()) return; s->PutCString("Section Headers\n"); @@ -1557,7 +1770,7 @@ ObjectFileELF::DumpELFSectionHeaders(Stream *s) { 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 f1fea3c666d..a6e3cbb3fd9 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -100,7 +100,7 @@ public: GetAddressByteSize() const; virtual lldb_private::Symtab * - GetSymtab(); + GetSymtab(uint32_t flags = 0); virtual lldb_private::SectionList * GetSectionList(); @@ -114,6 +114,9 @@ public: virtual bool GetUUID(lldb_private::UUID* uuid); + virtual lldb_private::FileSpecList + GetDebugSymbolFilePaths(); + virtual uint32_t GetDependentModules(lldb_private::FileSpecList& files); @@ -141,7 +144,11 @@ private: 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 @@ private: /// 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 @@ private: /// 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: const elf::ELFDynamic * FindDynamicSymbol(unsigned tag); - lldb_private::Section * - PLTSection(); - unsigned PLTRelocationType(); }; diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 9f27c1c5107..c59da7b16a1 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -838,6 +838,10 @@ ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr) case eSectionTypeDWARFAppleObjC: return eAddressClassDebug; case eSectionTypeEHFrame: return eAddressClassRuntime; + case eSectionTypeELFSymbolTable: + case eSectionTypeELFDynamicSymbols: + case eSectionTypeELFRelocationEntries: + case eSectionTypeELFDynamicLinkInfo: case eSectionTypeOther: return eAddressClassUnknown; } } @@ -891,7 +895,7 @@ ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr) } Symtab * -ObjectFileMachO::GetSymtab() +ObjectFileMachO::GetSymtab(uint32_t flags) { ModuleSP module_sp(GetModule()); if (module_sp) @@ -1033,6 +1037,7 @@ ObjectFileMachO::ParseSections () if (segment_name || is_core) { segment_sp.reset(new Section (module_sp, // Module to which this section belongs + this, // Object file to which this sections belongs ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible segment_name, // Name of this section eSectionTypeContainer, // This section is a container of other sections. @@ -1129,7 +1134,8 @@ ObjectFileMachO::ParseSections () { // Create a fake section for the section's named segment segment_sp.reset(new Section (segment_sp, // Parent section - module_sp, // Module to which this section belongs + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible segment_name, // Name of this section eSectionTypeContainer, // This section is a container of other sections. @@ -1258,6 +1264,7 @@ ObjectFileMachO::ParseSections () SectionSP section_sp(new Section (segment_sp, module_sp, + this, ++sectID, section_name, sect_type, diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 349928e9538..65874533ed3 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -102,7 +102,7 @@ public: GetAddressClass (lldb::addr_t file_addr); virtual lldb_private::Symtab * - GetSymtab(); + GetSymtab(uint32_t flags = 0); virtual lldb_private::SectionList * GetSectionList(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 4da254ca9a0..ec1aef784c2 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -511,7 +511,7 @@ ObjectFilePECOFF::GetSectionName(std::string& sect_name, const section_header_t& // GetNListSymtab //---------------------------------------------------------------------- Symtab * -ObjectFilePECOFF::GetSymtab() +ObjectFilePECOFF::GetSymtab(uint32_t flags) { ModuleSP module_sp(GetModule()); if (module_sp) @@ -698,9 +698,10 @@ ObjectFilePECOFF::GetSectionList() // Use a segment ID of the segment index shifted left by 8 so they // never conflict with any of the sections. SectionSP section_sp (new Section (module_sp, // Module to which this section belongs + this, // Object file to which this section belongs idx + 1, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible const_sect_name, // Name of this section - section_type, // This section is a container of other sections. + section_type, // This section is a container of other sections. m_coff_header_opt.image_base + m_sect_headers[idx].vmaddr, // File VM address == addresses as they are found in the object file m_sect_headers[idx].vmsize, // VM size in bytes of this section m_sect_headers[idx].offset, // Offset to the data for this section in the file diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index d980006eab6..c12c7b9c5e2 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -86,7 +86,7 @@ public: // GetAddressClass (lldb::addr_t file_addr); // virtual lldb_private::Symtab * - GetSymtab(); + GetSymtab(uint32_t flags = 0); virtual lldb_private::SectionList * GetSectionList(); |