Author: labath Date: Tue Jan 31 17:09:46 2017 New Revision: 293714 URL: http://llvm.org/viewvc/llvm-project?rev=293714&view=rev Log: Open ELF core dumps with more than 64K sections
Summary: Problem: There are three filelds in the ELF header - e_phnum, e_shnum, and e_shstrndx - that could be bigger than 64K and therefore do not fit in 16 bits reserved for them in the header. If this happens, pretty often there is a special section at index 0 which contains their real values for these fields in the section header in the fields sh_info, sh_size, and sh_link respectively. Fix: - Rename original fields in the header declaration. We want to have them around just in case. - Reintroduce these fields as 32-bit members at the end of the header. By default they are initialized from the header in Parse() method. - In Parse(), detect the situation when the header might have been extended into section info #0 and try to read it from the same data source. - ObjectFileELF::GetModuleSpecifications accesses some of these fields but the original parse uses too small data source. Re-parse the header if necessary using bigger data source. - ProcessElfCore::CreateInstance uses header with potentially sentinel values, but it does not access these fields, so a comment here is enough. Reviewers: labath Reviewed By: labath Subscribers: davidb, lldb-commits, mgorny Differential Revision: https://reviews.llvm.org/D29095 Author: Eugene Birukov <eugen...@hotmail.com> Added: lldb/trunk/unittests/ObjectFile/ lldb/trunk/unittests/ObjectFile/CMakeLists.txt lldb/trunk/unittests/ObjectFile/ELF/ lldb/trunk/unittests/ObjectFile/ELF/CMakeLists.txt lldb/trunk/unittests/ObjectFile/ELF/TestELFHeader.cpp Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.h lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp lldb/trunk/unittests/CMakeLists.txt Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp?rev=293714&r1=293713&r2=293714&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.cpp Tue Jan 31 17:09:46 2017 @@ -81,6 +81,39 @@ ByteOrder ELFHeader::GetByteOrder() cons 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::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; } Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.h?rev=293714&r1=293713&r2=293714&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.h (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ELFHeader.h Tue Jan 31 17:09:46 2017 @@ -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); }; //------------------------------------------------------------------------------ Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp?rev=293714&r1=293713&r2=293714&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Tue Jan 31 17:09:46 2017 @@ -610,7 +610,8 @@ size_t ObjectFileELF::GetModuleSpecifica 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::GetModuleSpecifica __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->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); } //---------------------------------------------------------------------- Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp?rev=293714&r1=293713&r2=293714&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp (original) +++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp Tue Jan 31 17:09:46 2017 @@ -56,6 +56,8 @@ lldb::ProcessSP ProcessElfCore::CreateIn lldb::ProcessSP process_sp; if (crash_file) { // Read enough data for a ELF32 header or ELF64 header + // Note: Here we care about e_type field only, so it is safe + // to ignore possible presence of the header extension. const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr); lldb::DataBufferSP data_sp(crash_file->ReadFileContents(0, header_size)); Modified: lldb/trunk/unittests/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/CMakeLists.txt?rev=293714&r1=293713&r2=293714&view=diff ============================================================================== --- lldb/trunk/unittests/CMakeLists.txt (original) +++ lldb/trunk/unittests/CMakeLists.txt Tue Jan 31 17:09:46 2017 @@ -53,6 +53,7 @@ add_subdirectory(Expression) add_subdirectory(Host) add_subdirectory(Interpreter) add_subdirectory(Language) +add_subdirectory(ObjectFile) add_subdirectory(Platform) add_subdirectory(Process) add_subdirectory(ScriptInterpreter) Added: lldb/trunk/unittests/ObjectFile/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/ObjectFile/CMakeLists.txt?rev=293714&view=auto ============================================================================== --- lldb/trunk/unittests/ObjectFile/CMakeLists.txt (added) +++ lldb/trunk/unittests/ObjectFile/CMakeLists.txt Tue Jan 31 17:09:46 2017 @@ -0,0 +1 @@ +add_subdirectory(ELF) Added: lldb/trunk/unittests/ObjectFile/ELF/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/ObjectFile/ELF/CMakeLists.txt?rev=293714&view=auto ============================================================================== --- lldb/trunk/unittests/ObjectFile/ELF/CMakeLists.txt (added) +++ lldb/trunk/unittests/ObjectFile/ELF/CMakeLists.txt Tue Jan 31 17:09:46 2017 @@ -0,0 +1,3 @@ +add_lldb_unittest(ObjectFileELFTests + TestELFHeader.cpp + ) Added: lldb/trunk/unittests/ObjectFile/ELF/TestELFHeader.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/ObjectFile/ELF/TestELFHeader.cpp?rev=293714&view=auto ============================================================================== --- lldb/trunk/unittests/ObjectFile/ELF/TestELFHeader.cpp (added) +++ lldb/trunk/unittests/ObjectFile/ELF/TestELFHeader.cpp Tue Jan 31 17:09:46 2017 @@ -0,0 +1,62 @@ +//===-- TestELFHeader.cpp ---------------------------------------*- C++ -*-===// +// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/ObjectFile/ELF/ELFHeader.h" +#include "lldb/Core/DataExtractor.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; + + +TEST(ELFHeader, ParseHeaderExtension) { + uint8_t data[] = { + // e_ident + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // e_type, e_machine, e_version, e_entry + 0x03, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x90, 0x48, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // e_phoff, e_shoff + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // e_flags, e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, + // e_shstrndx + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0xff, 0xff, 0x40, 0x00, + 0x00, 0x00, 0xff, 0xff, + + // sh_name, sh_type, sh_flags + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // sh_addr, sh_offset + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + // sh_size, sh_link, sh_info + 0x23, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x56, 0x78, 0x00, + 0x12, 0x34, 0x56, 0x00, + + // sh_addralign, sh_entsize + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + + DataExtractor extractor(data, sizeof data, eByteOrderLittle, 8); + elf::ELFHeader header; + offset_t offset = 0; + ASSERT_TRUE(header.Parse(extractor, &offset)); + EXPECT_EQ(0x563412u, header.e_phnum); + EXPECT_EQ(0x785634u, header.e_shstrndx); + EXPECT_EQ(0x674523u, header.e_shnum); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits