diff options
author | Tamas Berghammer <tberghammer@google.com> | 2015-05-08 09:40:05 +0000 |
---|---|---|
committer | Tamas Berghammer <tberghammer@google.com> | 2015-05-08 09:40:05 +0000 |
commit | 85fadd9fe88a3852b92bd0098e6ad10330132c68 (patch) | |
tree | 0acad58e2fef1741059a3a7f0cae4021ffa8657d /lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | |
parent | c0c838516d9d89330c6498c983b770a7e4ea1e1b (diff) | |
download | bcm5719-llvm-85fadd9fe88a3852b92bd0098e6ad10330132c68.tar.gz bcm5719-llvm-85fadd9fe88a3852b92bd0098e6ad10330132c68.zip |
Fix parsing of the plt section for android-arm
The ELF data contains two different errors in some ELF files on android.
* The link field of the symbol table don't point to the plt section or
to the dynsym section even when it is present in the ELF files.
* The size of the plt entries aren't specified in the section header of
the plt section.
This CL adds some workarounds for these two issue with finding the
sections by name if the link field is empty and by using a heuristic to
calculate the size and offset of the plt entries.
Differential revision: http://reviews.llvm.org/D9560
llvm-svn: 236818
Diffstat (limited to 'lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp')
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 7bab472ffa7..c043628b666 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1537,6 +1537,17 @@ ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) return NULL; } +lldb::user_id_t +ObjectFileELF::GetSectionIndexByName(const char* name) +{ + if (!name || !name[0] || !ParseSectionHeaders()) + return 0; + for (size_t i = 1; i < m_section_headers.size(); ++i) + if (m_section_headers[i].section_name == ConstString(name)) + return i; + return 0; +} + void ObjectFileELF::CreateSections(SectionList &unified_section_list) { @@ -2108,6 +2119,36 @@ ObjectFileELF::PLTRelocationType() return 0; } +// Returns the size of the normal plt entries and the offset of the first normal plt entry. The +// 0th entry in the plt table is ususally a resolution entry which have different size in some +// architectures then the rest of the plt entries. +static std::pair<uint64_t, uint64_t> +GetPltEntrySizeAndOffset(const ELFSectionHeader* rel_hdr, const ELFSectionHeader* plt_hdr) +{ + const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; + + // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are 16 bytes. + // So round the entsize up by the alignment if addralign is set. + elf_xword plt_entsize = plt_hdr->sh_addralign ? + llvm::RoundUpToAlignment (plt_hdr->sh_entsize, plt_hdr->sh_addralign) : plt_hdr->sh_entsize; + + if (plt_entsize == 0) + { + // The linker haven't set the plt_hdr->sh_entsize field. Try to guess the size of the plt + // entries based on the number of entries and the size of the plt section with the + // asumption that the size of the 0th entry is at least as big as the size of the normal + // entries and it isn't mutch bigger then that. + if (plt_hdr->sh_addralign) + plt_entsize = plt_hdr->sh_size / plt_hdr->sh_addralign / (num_relocations + 1) * plt_hdr->sh_addralign; + else + plt_entsize = plt_hdr->sh_size / (num_relocations + 1); + } + + elf_xword plt_offset = plt_hdr->sh_size - num_relocations * plt_entsize; + + return std::make_pair(plt_entsize, plt_offset); +} + static unsigned ParsePLTRelocations(Symtab *symbol_table, user_id_t start_id, @@ -2124,10 +2165,9 @@ ParsePLTRelocations(Symtab *symbol_table, ELFRelocation rel(rel_type); ELFSymbol symbol; lldb::offset_t offset = 0; - // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are 16 bytes. - // So round the entsize up by the alignment if addralign is set. - const elf_xword plt_entsize = plt_hdr->sh_addralign ? - llvm::RoundUpToAlignment (plt_hdr->sh_entsize, plt_hdr->sh_addralign) : plt_hdr->sh_entsize; + + uint64_t plt_offset, plt_entsize; + std::tie(plt_entsize, plt_offset) = GetPltEntrySizeAndOffset(rel_hdr, plt_hdr); const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel); @@ -2156,13 +2196,12 @@ ParsePLTRelocations(Symtab *symbol_table, continue; lldb::offset_t symbol_offset = reloc_symbol(rel) * sym_hdr->sh_entsize; - uint64_t plt_index = (i + 1) * plt_entsize; - if (!symbol.Parse(symtab_data, &symbol_offset)) break; const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false; + uint64_t plt_index = plt_offset + i * plt_entsize; Symbol jump_symbol( i + start_id, // Symbol table index @@ -2199,6 +2238,13 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t symtab_id = rel_hdr->sh_link; user_id_t plt_id = rel_hdr->sh_info; + // If the link field doesn't point to the appropriate symbol name table then + // try to find it by name as some compiler don't fill in the link fields. + if (!symtab_id) + symtab_id = GetSectionIndexByName(".dynsym"); + if (!plt_id) + plt_id = GetSectionIndexByName(".plt"); + if (!symtab_id || !plt_id) return 0; |