diff options
Diffstat (limited to 'lldb/source/Plugins/ObjectFile/ELF')
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp | 43 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h | 32 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 25 |
3 files changed, 92 insertions, 8 deletions
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index a3e82390d26..34b32a10b67 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -81,6 +81,39 @@ ByteOrder ELFHeader::GetByteOrder() const { return eByteOrderInvalid; } +bool ELFHeader::HasHeaderExtension() const { + bool result = false; + + // Check if any of these values looks like sentinel. + result |= e_phnum_hdr == 0xFFFF; // PN_XNUM + result |= e_shnum_hdr == SHN_UNDEF; + result |= e_shstrndx_hdr == SHN_XINDEX; + + // If header extension is present, the section offset cannot be null. + result &= e_shoff != 0; + + // Done. + return result; +} + +void ELFHeader::ParseHeaderExtension(lldb_private::DataExtractor &data) { + // Extract section #0 header. + ELFSectionHeader section_zero; + lldb::offset_t offset = 0; + lldb_private::DataExtractor sh_data(data, e_shoff, e_shentsize); + bool ok = section_zero.Parse(sh_data, &offset); + + // If we succeeded, fix the header. + if (ok) { + if (e_phnum_hdr == 0xFFFF) // PN_XNUM + e_phnum = section_zero.sh_info; + if (e_shnum_hdr == SHN_UNDEF) + e_shnum = section_zero.sh_size; + if (e_shstrndx_hdr == SHN_XINDEX) + e_shstrndx = section_zero.sh_link; + } +} + bool ELFHeader::Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset) { // Read e_ident. This provides byte order and address size info. @@ -112,6 +145,16 @@ bool ELFHeader::Parse(lldb_private::DataExtractor &data, if (data.GetU16(offset, &e_ehsize, 6) == NULL) return false; + // Initialize e_phnum, e_shnum, and e_shstrndx with the values + // read from the header. + e_phnum = e_phnum_hdr; + e_shnum = e_shnum_hdr; + e_shstrndx = e_shstrndx_hdr; + + // See if we have extended header in section #0. + if (HasHeaderExtension()) + ParseHeaderExtension(data); + return true; } diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h index 71b200f1c16..e6738a1ecb2 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -24,6 +24,7 @@ #include "llvm/Support/ELF.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-types.h" namespace lldb_private { class DataExtractor; @@ -65,10 +66,17 @@ struct ELFHeader { elf_half e_machine; ///< Target architecture. elf_half e_ehsize; ///< Byte size of the ELF header. elf_half e_phentsize; ///< Size of a program header table entry. - elf_half e_phnum; ///< Number of program header entries. + elf_half e_phnum_hdr; ///< Number of program header entries. elf_half e_shentsize; ///< Size of a section header table entry. - elf_half e_shnum; ///< Number of section header entries. - elf_half e_shstrndx; ///< String table section index. + elf_half e_shnum_hdr; ///< Number of section header entries. + elf_half e_shstrndx_hdr; ///< String table section index. + + // In some cases these numbers do not fit in 16 bits and they are + // stored outside of the header in section #0. Here are the actual + // values. + elf_word e_phnum; ///< Number of program header entries. + elf_word e_shnum; ///< Number of section header entries. + elf_word e_shstrndx; ///< String table section index. ELFHeader(); @@ -102,6 +110,14 @@ struct ELFHeader { unsigned GetRelocationJumpSlotType() const; //-------------------------------------------------------------------------- + /// Check if there should be header extension in section header #0 + /// + /// @return + /// True if parsing the ELFHeader requires reading header extension + /// and false otherwise. + bool HasHeaderExtension() const; + + //-------------------------------------------------------------------------- /// Parse an ELFHeader entry starting at position \p offset and /// update the data extractor with the address size and byte order /// attributes as defined by the header. @@ -137,6 +153,16 @@ struct ELFHeader { /// The number of bytes forming an address in the ELF file (either 4 or /// 8), else zero if the address size could not be determined. static unsigned AddressSizeInBytes(const uint8_t *magic); + +private: + + //-------------------------------------------------------------------------- + /// Parse an ELFHeader header extension entry. This method is called + /// by Parse(). + /// + /// @param[in] data + /// The DataExtractor to read from. + void ParseHeaderExtension(lldb_private::DataExtractor &data); }; //------------------------------------------------------------------------------ diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index fa79b24c481..44ea01dbe16 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -610,7 +610,8 @@ size_t ObjectFileELF::GetModuleSpecifications( DataExtractor data; data.SetData(data_sp); elf::ELFHeader header; - if (header.Parse(data, &data_offset)) { + lldb::offset_t header_offset = data_offset; + if (header.Parse(data, &header_offset)) { if (data_sp) { ModuleSpec spec(file); @@ -645,10 +646,24 @@ size_t ObjectFileELF::GetModuleSpecifications( __FUNCTION__, file.GetPath().c_str()); } + // In case there is header extension in the section #0, the header + // we parsed above could have sentinel values for e_phnum, e_shnum, + // and e_shstrndx. In this case we need to reparse the header + // with a bigger data source to get the actual values. + size_t section_header_end = header.e_shoff + header.e_shentsize; + if (header.HasHeaderExtension() && + section_header_end > data_sp->GetByteSize()) { + data_sp = file.MemoryMapFileContentsIfLocal (file_offset, + section_header_end); + data.SetData(data_sp); + lldb::offset_t header_offset = data_offset; + header.Parse(data, &header_offset); + } + // 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 = + section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize; if (section_header_end > data_sp->GetByteSize()) { data_sp = file.MemoryMapFileContentsIfLocal(file_offset, @@ -3067,10 +3082,10 @@ void ObjectFileELF::DumpELFHeader(Stream *s, const ELFHeader &header) { s->Printf("e_flags = 0x%8.8x\n", header.e_flags); s->Printf("e_ehsize = 0x%4.4x\n", header.e_ehsize); s->Printf("e_phentsize = 0x%4.4x\n", header.e_phentsize); - s->Printf("e_phnum = 0x%4.4x\n", header.e_phnum); + s->Printf("e_phnum = 0x%8.8x\n", header.e_phnum); s->Printf("e_shentsize = 0x%4.4x\n", header.e_shentsize); - s->Printf("e_shnum = 0x%4.4x\n", header.e_shnum); - s->Printf("e_shstrndx = 0x%4.4x\n", header.e_shstrndx); + s->Printf("e_shnum = 0x%8.8x\n", header.e_shnum); + s->Printf("e_shstrndx = 0x%8.8x\n", header.e_shstrndx); } //---------------------------------------------------------------------- |