Author: dvlahovski
Date: Fri Jul 29 08:18:09 2016
New Revision: 277140

URL: http://llvm.org/viewvc/llvm-project?rev=277140&view=rev
Log:
Add/fix support for i386 elf core files

Summary:
There were places in the code, assuming(hardcoding) offsets
and types that were only valid for the x86_64 elf core file format.

The NT_PRSTATUS and NT_PRPSINFO structures are with the 64 bit layout.
I have reused them and parse i386 files manually, and fill them in the
same struct.

Also added some error handling during parsing that checks if the
available bytes in the buffer are enough to fill the structures.

The i386 core file test case now passes.

For reference on the structures layout, I generally used the
source of binutils (bfd, readelf)

Bug: https://llvm.org/bugs/show_bug.cgi?id=26947

Reviewers: labath

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D22917

Modified:
    
lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
    lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
    lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp
    lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h
    lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp
    lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h

Modified: 
lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py?rev=277140&r1=277139&r2=277140&view=diff
==============================================================================
--- 
lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
 (original)
+++ 
lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
 Fri Jul 29 08:18:09 2016
@@ -25,7 +25,6 @@ class LinuxCoreTestCase(TestBase):
     _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)

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=277140&r1=277139&r2=277140&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Fri Jul 29 
08:18:09 2016
@@ -1479,7 +1479,7 @@ ObjectFileELF::RefineModuleDetailsFromNo
         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 @@ ObjectFileELF::RefineModuleDetailsFromNo
             // [  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;

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=277140&r1=277139&r2=277140&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp Fri Jul 29 
08:18:09 2016
@@ -223,8 +223,11 @@ ProcessElfCore::DoLoadCore ()
 
         // 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 @@ ParseFreeBSDThrMisc(ThreadData &thread_d
 ///        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 @@ ProcessElfCore::ParseThreadContextsFromN
     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 @@ ProcessElfCore::ParseThreadContextsFromN
             {
                 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 @@ ProcessElfCore::ParseThreadContextsFromN
                     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 @@ ProcessElfCore::ParseThreadContextsFromN
     {
         m_thread_data.push_back(*thread_data);
     }
+
+    return error;
 }
 
 uint32_t

Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h?rev=277140&r1=277139&r2=277140&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h Fri Jul 29 
08:18:09 2016
@@ -166,9 +166,9 @@ private:
     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

Modified: lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp?rev=277140&r1=277139&r2=277140&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.cpp Fri Jul 29 
08:18:09 2016
@@ -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 @@ ThreadElfCore::CreateRegisterContextForF
                     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 @@ ELFLinuxPrStatus::ELFLinuxPrStatus()
     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 @@ ELFLinuxPrPsInfo::ELFLinuxPrPsInfo()
     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;
 }
 

Modified: lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h?rev=277140&r1=277139&r2=277140&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ThreadElfCore.h Fri Jul 29 
08:18:09 2016
@@ -26,8 +26,10 @@ struct compat_timeval
 };
 
 // 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 @@ struct ELFLinuxPrStatus
 
     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 @@ struct ELFLinuxPrStatus
             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 @@ struct ELFLinuxPrStatus
 
 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 @@ struct ELFLinuxPrPsInfo
 
     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 @@ struct ELFLinuxPrPsInfo
             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;
         }


_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to