_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)
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
// [ 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<count; ++i)
{
- llvm::StringRef path(data.GetCStr(&offset));
- if (path.startswith("/lib/x86_64-linux-gnu"))
+ cstr = data.GetCStr(&offset);
+ if(cstr == nullptr)
+ {
+ error.SetErrorStringWithFormat("ObjectFileELF::%s trying to read at an offset after the end (GetCStr returned nullptr)", __FUNCTION__);
+ return error;
+ }
+ llvm::StringRef path(cstr);
+ if (path.startswith("/lib/x86_64-linux-gnu") || path.startswith("/lib/i386-linux-gnu"))
{
arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux);
break;
// 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)
{
/// 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)
{
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)
{
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);
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;
{
m_thread_data.push_back(*thread_data);
}
+
+ return error;
}
uint32_t
std::vector<NT_FILE_Entry> 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
#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"
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;
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;
}
//----------------------------------------------------------------
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;
}
};
// 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
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)
{
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;
}
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;
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)
{
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;
}