Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py @@ -25,7 +25,6 @@ _x86_64_regions = 5 _s390x_regions = 2 - @skipIf(bugnumber="llvm.org/pr26947") def test_i386(self): """Test that lldb can read the process information from an i386 linux core file.""" self.do_test("i386", self._i386_pid, self._i386_regions) Index: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1479,7 +1479,7 @@ else if (note.n_name == LLDB_NT_OWNER_CORE) { // Parse the NT_FILE to look for stuff in paths to shared libraries - // As the contents look like: + // As the contents look like this in a 64 bit ELF core file: // count = 0x000000000000000a (10) // page_size = 0x0000000000001000 (4096) // Index start end file_ofs path @@ -1494,14 +1494,24 @@ // [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000 0x0000000000000000 /lib/x86_64-linux-gnu/ld-2.19.so // [ 8] 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 /lib/x86_64-linux-gnu/ld-2.19.so // [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000 0x0000000000000023 /lib/x86_64-linux-gnu/ld-2.19.so + // In the 32 bit ELFs the count, page_size, start, end, file_ofs are uint32_t + // For reference: see readelf source code (in binutils). if (note.n_type == NT_FILE) { - uint64_t count = data.GetU64(&offset); - offset += 8 + 3*8*count; // Skip page size and all start/end/file_ofs + uint64_t count = data.GetAddress(&offset); + const char *cstr; + data.GetAddress(&offset); // Skip page size + offset += count * 3 * data.GetAddressByteSize(); // Skip all start/end/file_ofs for (size_t i=0; i m_nt_file_entries; // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment - void - ParseThreadContextsFromNoteSegment (const elf::ELFProgramHeader *segment_header, - lldb_private::DataExtractor segment_data); + lldb_private::Error + ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, + lldb_private::DataExtractor segment_data); // Returns number of thread contexts stored in the core file uint32_t Index: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -223,8 +223,11 @@ // Parse thread contexts and auxv structure if (header->p_type == llvm::ELF::PT_NOTE) - ParseThreadContextsFromNoteSegment(header, data); - + { + error = ParseThreadContextsFromNoteSegment(header, data); + if (error.Fail()) + return error; + } // PT_LOAD segments contains address map if (header->p_type == llvm::ELF::PT_LOAD) { @@ -533,7 +536,7 @@ /// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry. /// For case (b) there may be either one NT_PRPSINFO per thread, or a single /// one that applies to all threads (depending on the platform type). -void +Error ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) { @@ -549,6 +552,7 @@ ELFLinuxPrStatus prstatus; size_t header_size; size_t len; + Error error; // Loop through the NOTE entires in the segment while (offset < segment_header->p_filesz) @@ -610,7 +614,9 @@ { case NT_PRSTATUS: have_prstatus = true; - prstatus.Parse(note_data, arch); + error = prstatus.Parse(note_data, arch); + if (error.Fail()) + return error; thread_data->signo = prstatus.pr_cursig; thread_data->tid = prstatus.pr_pid; header_size = ELFLinuxPrStatus::GetSize(arch); @@ -622,7 +628,9 @@ break; case NT_PRPSINFO: have_prpsinfo = true; - prpsinfo.Parse(note_data, arch); + error = prpsinfo.Parse(note_data, arch); + if (error.Fail()) + return error; thread_data->name = prpsinfo.pr_fname; SetID(prpsinfo.pr_pid); break; @@ -663,6 +671,8 @@ { m_thread_data.push_back(*thread_data); } + + return error; } uint32_t Index: lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h =================================================================== --- lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h +++ lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -26,8 +26,10 @@ }; // PRSTATUS structure's size differs based on architecture. -// Currently parsing done only for x86-64 architecture by -// simply reading data from the buffer. +// This is the layout in the x86-64 arch. +// In the i386 case we parse it manually and fill it again +// in the same structure +// The gp registers are also a part of this struct, but they are handled separately #undef si_signo #undef si_code @@ -56,9 +58,13 @@ ELFLinuxPrStatus(); - bool + lldb_private::Error Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch); + // Return the bytesize of the structure + // 64 bit - just sizeof + // 32 bit - hardcoded because we are reusing the struct, but some of the members are smaller - + // so the layout is not the same static size_t GetSize(lldb_private::ArchSpec &arch) { @@ -67,6 +73,9 @@ case lldb_private::ArchSpec::eCore_s390x_generic: case lldb_private::ArchSpec::eCore_x86_64_x86_64: return sizeof(ELFLinuxPrStatus); + case lldb_private::ArchSpec::eCore_x86_32_i386: + case lldb_private::ArchSpec::eCore_x86_32_i486: + return 72; default: return 0; } @@ -75,6 +84,10 @@ static_assert(sizeof(ELFLinuxPrStatus) == 112, "sizeof ELFLinuxPrStatus is not correct!"); +// PRPSINFO structure's size differs based on architecture. +// This is the layout in the x86-64 arch case. +// In the i386 case we parse it manually and fill it again +// in the same structure struct ELFLinuxPrPsInfo { char pr_state; @@ -93,9 +106,13 @@ ELFLinuxPrPsInfo(); - bool + lldb_private::Error Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch); + // Return the bytesize of the structure + // 64 bit - just sizeof + // 32 bit - hardcoded because we are reusing the struct, but some of the members are smaller - + // so the layout is not the same static size_t GetSize(lldb_private::ArchSpec &arch) { @@ -104,6 +121,9 @@ case lldb_private::ArchSpec::eCore_s390x_generic: case lldb_private::ArchSpec::eCore_x86_64_x86_64: return sizeof(ELFLinuxPrPsInfo); + case lldb_private::ArchSpec::eCore_x86_32_i386: + case lldb_private::ArchSpec::eCore_x86_32_i486: + return 124; default: return 0; } Index: lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -19,6 +19,7 @@ #include "Plugins/Process/Utility/RegisterContextLinux_arm.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" +#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h" @@ -144,6 +145,9 @@ case llvm::Triple::systemz: reg_interface = new RegisterContextLinux_s390x(arch); break; + case llvm::Triple::x86: + reg_interface = new RegisterContextLinux_i386(arch); + break; case llvm::Triple::x86_64: reg_interface = new RegisterContextLinux_x86_64(arch); break; @@ -219,20 +223,65 @@ memset(this, 0, sizeof(ELFLinuxPrStatus)); } -bool +Error ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch) { + Error error; ByteOrder byteorder = data.GetByteOrder(); - size_t len; + if (GetSize(arch) > data.GetByteSize()) + { + error.SetErrorStringWithFormat("NT_PRSTATUS size should be %lu, but the remaining bytes are: %lu", + GetSize(arch), data.GetByteSize()); + return error; + } + switch(arch.GetCore()) { case ArchSpec::eCore_s390x_generic: case ArchSpec::eCore_x86_64_x86_64: - len = data.ExtractBytes(0, sizeof(ELFLinuxPrStatus), byteorder, this); - return len == sizeof(ELFLinuxPrStatus); + data.ExtractBytes(0, sizeof(ELFLinuxPrStatus), byteorder, this); + break; + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + { + // Parsing from a 32 bit ELF core file, and populating/reusing the structure + // properly, because the struct is for the 64 bit version + offset_t offset = 0; + si_signo = data.GetU32(&offset); + si_code = data.GetU32(&offset); + si_errno = data.GetU32(&offset); + + pr_cursig = data.GetU16(&offset); + offset += 2; // pad + + pr_sigpend = data.GetU32(&offset); + pr_sighold = data.GetU32(&offset); + + pr_pid = data.GetU32(&offset); + pr_ppid = data.GetU32(&offset); + pr_pgrp = data.GetU32(&offset); + pr_sid = data.GetU32(&offset); + + pr_utime.tv_sec = data.GetU32(&offset); + pr_utime.tv_usec = data.GetU32(&offset); + + pr_stime.tv_sec = data.GetU32(&offset); + pr_stime.tv_usec = data.GetU32(&offset); + + pr_cutime.tv_sec = data.GetU32(&offset); + pr_cutime.tv_usec = data.GetU32(&offset); + + pr_cstime.tv_sec = data.GetU32(&offset); + pr_cstime.tv_usec = data.GetU32(&offset); + + break; + } default: - return false; + error.SetErrorStringWithFormat("ELFLinuxPrStatus::%s Unknown architecture", __FUNCTION__); + break; } + + return error; } //---------------------------------------------------------------- @@ -243,19 +292,61 @@ memset(this, 0, sizeof(ELFLinuxPrPsInfo)); } -bool +Error ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) { + Error error; ByteOrder byteorder = data.GetByteOrder(); - size_t len; + if (GetSize(arch) > data.GetByteSize()) + { + error.SetErrorStringWithFormat("NT_PRPSINFO size should be %lu, but the remaining bytes are: %lu", + GetSize(arch), data.GetByteSize()); + return error; + } + switch(arch.GetCore()) { case ArchSpec::eCore_s390x_generic: case ArchSpec::eCore_x86_64_x86_64: - len = data.ExtractBytes(0, sizeof(ELFLinuxPrPsInfo), byteorder, this); - return len == sizeof(ELFLinuxPrPsInfo); + data.ExtractBytes(0, sizeof(ELFLinuxPrPsInfo), byteorder, this); + break; + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + { + // Parsing from a 32 bit ELF core file, and populating/reusing the structure + // properly, because the struct is for the 64 bit version + size_t size = 0; + offset_t offset = 0; + + pr_state = data.GetU8(&offset); + pr_sname = data.GetU8(&offset); + pr_zomb = data.GetU8(&offset); + pr_nice = data.GetU8(&offset); + + pr_flag = data.GetU32(&offset); + pr_uid = data.GetU16(&offset); + pr_gid = data.GetU16(&offset); + + pr_pid = data.GetU32(&offset); + pr_ppid = data.GetU32(&offset); + pr_pgrp = data.GetU32(&offset); + pr_sid = data.GetU32(&offset); + + size = 16; + data.ExtractBytes(offset, size, byteorder, pr_fname); + offset += size; + + size = 80; + data.ExtractBytes(offset, size, byteorder, pr_psargs); + offset += size; + + break; + } default: - return false; + error.SetErrorStringWithFormat("ELFLinuxPrPsInfo::%s Unknown architecture", __FUNCTION__); + break; } + + return error; }