Re-introduces ELF core file support for Linux x86-64
authorAshok Thirumurthi <ashok.thirumurthi@intel.com>
Wed, 17 Jul 2013 16:06:12 +0000 (16:06 +0000)
committerAshok Thirumurthi <ashok.thirumurthi@intel.com>
Wed, 17 Jul 2013 16:06:12 +0000 (16:06 +0000)
  Usage: 'lldb a.out -c core'.
  TODO: FreeBSD support.
  TODO: Support for AVX registers.
  TODO: Refactor so that RegisterContextCore* don't inherit from classes that use ProcessMonitor
  to fix the build on OS/X.

llvm-svn: 186516

19 files changed:
lldb/lib/Makefile
lldb/source/CMakeLists.txt
lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
lldb/source/Plugins/Makefile
lldb/source/Plugins/Process/CMakeLists.txt
lldb/source/Plugins/Process/Linux/ProcessLinux.cpp
lldb/source/Plugins/Process/Linux/ProcessLinux.h
lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
lldb/source/Plugins/Process/elf-core/CMakeLists.txt
lldb/source/Plugins/Process/elf-core/Makefile
lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp
lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h
lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp
lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h
lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
lldb/source/lldb.cpp

index ea028ce..eb52768 100644 (file)
@@ -98,13 +98,15 @@ ifeq ($(HOST_OS),Linux)
   USEDLIBS += lldbHostLinux.a \
               lldbPluginProcessLinux.a \
               lldbPluginProcessPOSIX.a \
-              lldbPluginDynamicLoaderMacOSX.a
+              lldbPluginDynamicLoaderMacOSX.a \
+              lldbPluginProcessElfCore.a
 endif
 
 ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD))
   USEDLIBS += lldbHostFreeBSD.a \
               lldbPluginProcessPOSIX.a \
-              lldbPluginProcessFreeBSD.a
+              lldbPluginProcessFreeBSD.a \
+              lldbPluginProcessElfCore.a
 endif
 
 include $(LEVEL)/Makefile.common
index 8b7d34f..57543e0 100644 (file)
@@ -90,6 +90,7 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Linux" )
     lldbHostLinux\r
     lldbPluginProcessLinux\r
     lldbPluginProcessPOSIX\r
+    lldbPluginProcessElfCore\r
     )\r
 endif ()\r
 \r
@@ -99,6 +100,7 @@ if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" )
     lldbHostFreeBSD\r
     lldbPluginProcessFreeBSD\r
     lldbPluginProcessPOSIX\r
+    lldbPluginProcessElfCore\r
     )\r
 endif ()\r
 \r
index 7123786..2604ae6 100644 (file)
 #include "lldb/Core/Log.h"
 #include "lldb/Target/Process.h"
 
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#endif
+
 #include "AuxVector.h"
 
 using namespace lldb;
@@ -53,7 +57,10 @@ ParseAuxvEntry(DataExtractor &data,
 DataBufferSP
 AuxVector::GetAuxvData()
 {
-
+#if defined(__linux__) or defined(__FreeBSD__)
+    if (m_process->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+        return static_cast<ProcessElfCore *>(m_process)->GetAuxvData();
+#endif
     return lldb_private::Host::GetAuxvData(m_process);
 }
 
index f420a03..3694f31 100644 (file)
@@ -35,11 +35,13 @@ ifeq ($(HOST_OS),Linux)
 DIRS += DynamicLoader/MacOSX-DYLD
 DIRS += Process/Linux Process/POSIX
 DIRS += SymbolVendor/ELF
+DIRS += Process/elf-core
 endif
 
 ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD))
 DIRS += Process/FreeBSD Process/POSIX
 DIRS += SymbolVendor/ELF
+DIRS += Process/elf-core
 endif
 
 include $(LLDB_LEVEL)/Makefile
index cf12bcd..5d8986e 100644 (file)
@@ -1,13 +1,14 @@
 if (CMAKE_SYSTEM_NAME MATCHES "Linux")\r
   add_subdirectory(Linux)\r
   add_subdirectory(POSIX)\r
+  add_subdirectory(elf-core)\r
 elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")\r
   add_subdirectory(FreeBSD)\r
   add_subdirectory(POSIX)\r
+  add_subdirectory(elf-core)\r
 elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")\r
   add_subdirectory(MacOSX-Kernel)\r
 endif()\r
-\r
 add_subdirectory(gdb-remote)\r
 add_subdirectory(Utility)\r
 add_subdirectory(mach-core)\r
index 8c0a2a2..c53a2eb 100644 (file)
@@ -32,9 +32,9 @@ using namespace lldb_private;
 // Static functions.
 
 ProcessSP
-ProcessLinux::CreateInstance(Target &target, Listener &listener, const FileSpec *)
+ProcessLinux::CreateInstance(Target &target, Listener &listener, const FileSpec *core_file)
 {
-    return ProcessSP(new ProcessLinux(target, listener));
+    return ProcessSP(new ProcessLinux(target, listener, (FileSpec *)core_file));
 }
 
 void
@@ -63,8 +63,8 @@ ProcessLinux::Initialize()
 //------------------------------------------------------------------------------
 // Constructors and destructors.
 
-ProcessLinux::ProcessLinux(Target& target, Listener &listener)
-    : ProcessPOSIX(target, listener), m_stopping_threads(false)
+ProcessLinux::ProcessLinux(Target& target, Listener &listener, FileSpec *core_file)
+    : ProcessPOSIX(target, listener), m_stopping_threads(false), m_core_file(core_file)
 {
 #if 0
     // FIXME: Putting this code in the ctor and saving the byte order in a
@@ -170,3 +170,17 @@ ProcessLinux::StopAllThreads(lldb::tid_t stop_tid)
     if (log)
         log->Printf ("ProcessLinux::%s() finished", __FUNCTION__);
 }
+
+bool
+ProcessLinux::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+    if (plugin_specified_by_name)
+        return true;
+
+    /* If core file is specified then let elf-core plugin handle it */
+    if (m_core_file)
+        return false;
+
+    return ProcessPOSIX::CanDebug(target, plugin_specified_by_name);
+}
+
index d7f338f..c651351 100644 (file)
@@ -51,7 +51,8 @@ public:
     // Constructors and destructors
     //------------------------------------------------------------------
     ProcessLinux(lldb_private::Target& target,
-                 lldb_private::Listener &listener);
+                 lldb_private::Listener &listener,
+                 lldb_private::FileSpec *core_file);
 
     virtual bool
     UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list);
@@ -84,6 +85,9 @@ public:
         return m_linux_signals;
     }
 
+    virtual bool
+    CanDebug(lldb_private::Target &target, bool plugin_specified_by_name);
+
     //------------------------------------------------------------------
     // ProcessPOSIX overrides
     //------------------------------------------------------------------
@@ -95,6 +99,8 @@ private:
     /// Linux-specific signal set.
     LinuxSignals m_linux_signals;
 
+    lldb_private::FileSpec *m_core_file;
+
     // Flag to avoid recursion when stopping all threads.
     bool m_stopping_threads;
 };
index 73eb7b9..617b184 100644 (file)
 #include "llvm/Support/Compiler.h"
 
 #include "ProcessPOSIX.h"
+#if defined(__linux__) or defined(__FreeBSD__)
 #include "ProcessMonitor.h"
+#endif
 #include "RegisterContext_i386.h"
 #include "RegisterContext_x86.h"
 #include "RegisterContext_x86_64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
 
 using namespace lldb_private;
 using namespace lldb;
@@ -497,6 +500,11 @@ RegisterContext_x86_64::RegisterContext_x86_64(Thread &thread,
 
     ::memset(&m_fpr, 0, sizeof(RegisterContext_x86_64::FPR));
 
+    // elf-core yet to support ReadFPR()
+    ProcessSP base = CalculateProcess();
+    if (base.get()->GetPluginName() ==  ProcessElfCore::GetPluginNameStatic())
+        return;
+    
     // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx
     m_fpr_type = eXSAVE; // extended floating-point registers, if available
     if (false == ReadFPR())
@@ -507,14 +515,6 @@ RegisterContext_x86_64::~RegisterContext_x86_64()
 {
 }
 
-ProcessMonitor &
-RegisterContext_x86_64::GetMonitor()
-{
-    ProcessSP base = CalculateProcess();
-    ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
-    return process->GetMonitor();
-}
-
 void
 RegisterContext_x86_64::Invalidate()
 {
@@ -696,9 +696,7 @@ RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue
             return false;
     }
     else {
-        ProcessMonitor &monitor = GetMonitor();
-        bool success = monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg),
-                                                 GetRegisterName(reg), GetRegisterSize(reg), value);
+        bool success = ReadRegister(reg, value);
 
         // If an i386 register should be parsed from an x86_64 register...
         if (success && reg >= k_first_i386 && reg <= k_last_i386)
@@ -801,8 +799,7 @@ RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info
 {
     const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
     if (IsGPR(reg)) {
-        ProcessMonitor &monitor = GetMonitor();
-        return monitor.WriteRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), GetRegisterName(reg), value);
+        return WriteRegister(reg, value);
     }
 
     if (IsFPR(reg, m_fpr_type)) {
@@ -898,29 +895,6 @@ RegisterContext_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp)
 }
 
 bool
-RegisterContext_x86_64::ReadRegister(const unsigned reg,
-                                     RegisterValue &value)
-{
-    ProcessMonitor &monitor = GetMonitor();
-    return monitor.ReadRegisterValue(m_thread.GetID(),
-                                     GetRegisterOffset(reg),
-                                     GetRegisterName(reg),
-                                     GetRegisterSize(reg),
-                                     value);
-}
-
-bool
-RegisterContext_x86_64::WriteRegister(const unsigned reg,
-                                      const RegisterValue &value)
-{
-    ProcessMonitor &monitor = GetMonitor();
-    return monitor.WriteRegisterValue(m_thread.GetID(),
-                                      GetRegisterOffset(reg),
-                                      GetRegisterName(reg),
-                                      value);
-}
-
-bool
 RegisterContext_x86_64::UpdateAfterBreakpoint()
 {
     // PC points one byte past the int3 responsible for the breakpoint.
@@ -1469,6 +1443,16 @@ RegisterContext_x86_64::HardwareSingleStep(bool enable)
     return WriteRegisterFromUnsigned(gpr_rflags, rflags);
 }
 
+#if defined(__linux__) or defined(__FreeBSD__)
+
+ProcessMonitor &
+RegisterContext_x86_64::GetMonitor()
+{
+    ProcessSP base = CalculateProcess();
+    ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+    return process->GetMonitor();
+}
+
 bool
 RegisterContext_x86_64::ReadGPR()
 {
@@ -1507,3 +1491,73 @@ RegisterContext_x86_64::WriteFPR()
     return false;
 }
 
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+                                     RegisterValue &value)
+{
+    ProcessMonitor &monitor = GetMonitor();
+    return monitor.ReadRegisterValue(m_thread.GetID(),
+                                     GetRegisterOffset(reg),
+                                     GetRegisterName(reg),
+                                     GetRegisterSize(reg),
+                                     value);
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+                                      const RegisterValue &value)
+{
+    ProcessMonitor &monitor = GetMonitor();
+    return monitor.WriteRegisterValue(m_thread.GetID(),
+                                      GetRegisterOffset(reg),
+                                      GetRegisterName(reg),
+                                      value);
+}
+
+#else
+
+bool
+RegisterContext_x86_64::ReadGPR()
+{
+    llvm_unreachable("not implemented");
+    return false;
+}
+
+bool
+RegisterContext_x86_64::ReadFPR()
+{
+    llvm_unreachable("not implemented");
+    return false;
+}
+
+bool
+RegisterContext_x86_64::WriteGPR()
+{
+    llvm_unreachable("not implemented");
+    return false;
+}
+
+bool
+RegisterContext_x86_64::WriteFPR()
+{
+    llvm_unreachable("not implemented");
+    return false;
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+                                     RegisterValue &value)
+{
+    llvm_unreachable("not implemented");
+    return false;
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+                                      const RegisterValue &value)
+{
+    llvm_unreachable("not implemented");
+    return false;
+}
+
+#endif
index e69de29..cf454b9 100644 (file)
@@ -0,0 +1,10 @@
+include_directories(../Utility)
+
+set(LLVM_NO_RTTI 1)
+
+add_lldb_library(lldbPluginProcessElfCore
+  ProcessElfCore.cpp
+  ThreadElfCore.cpp
+  RegisterContextCoreLinux_x86_64.cpp
+  RegisterContextCoreFreeBSD_x86_64.cpp
+  )
index e69de29..51a0aae 100644 (file)
@@ -0,0 +1,14 @@
+##===- source/Plugins/Process/elf-core/Makefile -----------*- Makefile -*-===##
+# 
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+# 
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessElfCore
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
index e69de29..8b52740 100644 (file)
@@ -0,0 +1,518 @@
+//===-- ProcessElfCore.cpp --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdlib.h>
+
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+
+// Project includes
+#include "ProcessElfCore.h"
+#include "ThreadElfCore.h"
+
+using namespace lldb_private;
+
+ConstString
+ProcessElfCore::GetPluginNameStatic()
+{
+    static ConstString g_name("elf-core");
+    return g_name;
+}
+
+const char *
+ProcessElfCore::GetPluginDescriptionStatic()
+{
+    return "ELF core dump plug-in.";
+}
+
+void
+ProcessElfCore::Terminate()
+{
+    PluginManager::UnregisterPlugin (ProcessElfCore::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessElfCore::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file)
+{
+    lldb::ProcessSP process_sp;
+    if (crash_file) 
+        process_sp.reset(new ProcessElfCore (target, listener, *crash_file));
+    return process_sp;
+}
+
+bool
+ProcessElfCore::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+    // For now we are just making sure the file exists for a given module
+    if (!m_core_module_sp && m_core_file.Exists())
+    {
+        ModuleSpec core_module_spec(m_core_file, target.GetArchitecture());
+        Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp, 
+                                                  NULL, NULL, NULL));
+        if (m_core_module_sp)
+        {
+            ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+            if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
+                return true;
+        }
+    }
+    return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessElfCore constructor
+//----------------------------------------------------------------------
+ProcessElfCore::ProcessElfCore(Target& target, Listener &listener,
+                               const FileSpec &core_file) :
+    Process (target, listener),
+    m_core_module_sp (),
+    m_core_file (core_file),
+    m_dyld_plugin_name (),
+    m_thread_data_valid(false),
+    m_thread_data(),
+    m_core_aranges ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessElfCore::~ProcessElfCore()
+{
+    Clear();
+    // We need to call finalize on the process before destroying ourselves
+    // to make sure all of the broadcaster cleanup goes as planned. If we
+    // destruct this class, then Process::~Process() might have problems
+    // trying to fully destroy the broadcaster.
+    Finalize();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessElfCore::GetPluginName()
+{
+    return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessElfCore::GetPluginVersion()
+{
+    return 1;
+}
+
+lldb::addr_t
+ProcessElfCore::AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header)
+{
+    lldb::addr_t addr = header->p_vaddr;
+    FileRange file_range (header->p_offset, header->p_filesz);
+    VMRangeToFileOffset::Entry range_entry(addr, header->p_memsz, file_range);
+
+    VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
+    if (last_entry &&
+        last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
+        last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase())
+    {
+        last_entry->SetRangeEnd (range_entry.GetRangeEnd());
+        last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd());
+    }
+    else
+    {
+        m_core_aranges.Append(range_entry);
+    }
+
+    return addr;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessElfCore::DoLoadCore ()
+{
+    Error error;
+    if (!m_core_module_sp)
+    {
+        error.SetErrorString ("invalid core module");   
+        return error;
+    }
+
+    ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+    if (core == NULL)
+    {
+        error.SetErrorString ("invalid core object file");   
+        return error;
+    }
+
+    const uint32_t num_segments = core->GetProgramHeaderCount();
+    if (num_segments == 0)
+    {
+        error.SetErrorString ("core file has no sections");   
+        return error;
+    }
+
+    SetCanJIT(false);
+
+    m_thread_data_valid = true;
+
+    bool ranges_are_sorted = true;
+    lldb::addr_t vm_addr = 0;
+    /// Walk through segments and Thread and Address Map information.
+    /// PT_NOTE - Contains Thread and Register information
+    /// PT_LOAD - Contains a contiguous range of Process Address Space
+    for(uint32_t i = 1; i <= num_segments; i++)
+    {
+        const elf::ELFProgramHeader *header = core->GetProgramHeaderByIndex(i);
+        assert(header != NULL);
+
+        DataExtractor data = core->GetSegmentDataByIndex(i);
+
+        // Parse thread contexts and auxv structure
+        if (header->p_type == llvm::ELF::PT_NOTE)
+            ParseThreadContextsFromNoteSegment(header, data);
+
+        // PT_LOAD segments contains address map
+        if (header->p_type == llvm::ELF::PT_LOAD)
+        {
+            lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(header);
+            if (vm_addr > last_addr)
+                ranges_are_sorted = false;
+            vm_addr = last_addr;
+        }
+    }
+
+    if (!ranges_are_sorted)
+        m_core_aranges.Sort();
+
+    // Even if the architecture is set in the target, we need to override
+    // it to match the core file which is always single arch.
+    ArchSpec arch (m_core_module_sp->GetArchitecture());
+    switch (arch.GetCore())
+    {
+        case ArchSpec::eCore_x86_32_i486:
+            arch.SetTriple ("i386", m_target.GetPlatform().get());
+            break;
+        case ArchSpec::eCore_x86_64_x86_64:
+            arch.SetTriple ("x86_64-linux-gnu", m_target.GetPlatform().get());
+            break;
+        default:
+            assert(false && "Unhandled core type");
+    }
+    if (arch.IsValid())
+        m_target.SetArchitecture(arch);            
+
+    return error;
+}
+
+lldb_private::DynamicLoader *
+ProcessElfCore::GetDynamicLoader ()
+{
+    if (m_dyld_ap.get() == NULL)
+        m_dyld_ap.reset (DynamicLoader::FindPlugin(this, DynamicLoaderPOSIXDYLD::GetPluginNameStatic().GetCString()));
+    return m_dyld_ap.get();
+}
+
+bool
+ProcessElfCore::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+    const uint32_t num_threads = GetNumThreadContexts ();
+    if (!m_thread_data_valid)
+        return false;
+
+    for (lldb::tid_t tid = 0; tid < num_threads; ++tid)
+    {
+        const ThreadData &td = m_thread_data[tid];
+        lldb::ThreadSP thread_sp(new ThreadElfCore (*this, tid, td.prstatus,
+                                                    td.prpsinfo, td.fpregset));
+        new_thread_list.AddThread (thread_sp);
+    }
+    return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessElfCore::RefreshStateAfterStop ()
+{
+}
+
+Error
+ProcessElfCore::DoDestroy ()
+{
+    return Error();
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessElfCore::IsAlive ()
+{
+    return true;
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessElfCore::ReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+    // Don't allow the caching that lldb_private::Process::ReadMemory does
+    // since in core files we have it all cached our our core file anyway.
+    return DoReadMemory (addr, buf, size, error);
+}
+
+size_t
+ProcessElfCore::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+    ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+
+    if (core_objfile == NULL)
+        return 0;
+
+    // Get the address range
+    const VMRangeToFileOffset::Entry *address_range = m_core_aranges.FindEntryThatContains (addr);
+    if (address_range == NULL || address_range->GetRangeEnd() < addr)
+    {
+        error.SetErrorStringWithFormat ("core file does not contain 0x%" PRIx64, addr);
+        return 0;
+    }
+
+    // Convert the address into core file offset
+    const lldb::addr_t offset = addr - address_range->GetRangeBase();
+    const lldb::addr_t file_start = address_range->data.GetRangeBase();
+    const lldb::addr_t file_end = address_range->data.GetRangeEnd();
+    size_t bytes_to_read = size; // Number of bytes to read from the core file
+    size_t bytes_copied = 0;     // Number of bytes actually read from the core file
+    size_t zero_fill_size = 0;   // Padding
+    lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address
+
+    if (file_end > offset)
+        bytes_left = file_end - offset;
+
+    if (bytes_to_read > bytes_left)
+    {
+        zero_fill_size = bytes_to_read - bytes_left;
+        bytes_to_read = bytes_left;
+    }
+
+    // If there is data available on the core file read it
+    if (bytes_to_read)
+        bytes_copied = core_objfile->CopyData(offset + file_start, bytes_to_read, buf);
+
+    assert(zero_fill_size <= size);
+    // Pad remaining bytes
+    if (zero_fill_size)
+        memset(((char *)buf) + bytes_copied, 0, zero_fill_size);
+
+    return bytes_copied + zero_fill_size;
+}
+
+void
+ProcessElfCore::Clear()
+{
+    m_thread_list.Clear();
+}
+
+void
+ProcessElfCore::Initialize()
+{
+    static bool g_initialized = false;
+    
+    if (g_initialized == false)
+    {
+        g_initialized = true;
+        PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance);
+    }
+}
+
+lldb::addr_t
+ProcessElfCore::GetImageInfoAddress()
+{
+    Target *target = &GetTarget();
+    ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+    Address addr = obj_file->GetImageInfoAddress();
+
+    if (addr.IsValid()) 
+        return addr.GetLoadAddress(target);
+    return LLDB_INVALID_ADDRESS;
+}
+
+/// Core files PT_NOTE segment descriptor types
+enum {
+    NT_PRSTATUS     = 1,
+    NT_FPREGSET,
+    NT_PRPSINFO,
+    NT_TASKSTRUCT,
+    NT_PLATFORM,
+    NT_AUXV
+};
+
+/// Note Structure found in ELF core dumps.
+/// This is PT_NOTE type program/segments in the core file.
+struct ELFNote
+{
+    elf::elf_word n_namesz;
+    elf::elf_word n_descsz;
+    elf::elf_word n_type;
+
+    ELFNote()
+    {
+        memset(this, 0, sizeof(ELFNote));
+    }
+
+    /// Parse an ELFNote entry from the given DataExtractor starting at position
+    /// \p offset.
+    ///
+    /// @param[in] data
+    ///    The DataExtractor to read from.
+    ///
+    /// @param[in,out] offset
+    ///    Pointer to an offset in the data.  On return the offset will be
+    ///    advanced by the number of bytes read.
+    ///
+    /// @return
+    ///    True if the ELFRel entry was successfully read and false otherwise.
+    bool
+    Parse(const DataExtractor &data, lldb::offset_t *offset)
+    {
+        // Read all fields.
+        if (data.GetU32(offset, &n_namesz, 3) == NULL)
+            return false;
+
+        return true;
+    }
+};
+
+/// Align the given value to next boundary specified by the alignment bytes
+static uint32_t
+AlignToNext(uint32_t value, int alignment_bytes)
+{
+    return (value + alignment_bytes - 1) & ~(alignment_bytes - 1);
+}
+
+/// Parse Thread context from PT_NOTE segment and store it in the thread list
+/// Notes:
+/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
+/// 2) NOTE Entry contains a standard header followed by variable size data.
+///   (see ELFNote structure)
+/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
+///    a) NT_PRSTATUS - Register context
+///    b) NT_PRPSINFO - Process info(pid..)
+///    c) NT_FPREGSET - Floating point registers
+/// 4) The NOTE entries can be in any order
+/// 5) If a core file contains multiple thread contexts then there is two data forms
+///    a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE)
+///    b) All thread context is stored in a single segment(PT_NOTE).
+///        This case is little tricker since while parsing we have to find where the
+///        new thread starts. The current implementation marks begining of 
+///        new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
+void
+ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, 
+                                                   DataExtractor segment_data)
+{
+    assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
+
+    lldb::offset_t offset = 0;
+    ThreadData *thread_data = NULL;
+
+    // Loop through the NOTE entires in the segment
+    while (offset < segment_header->p_filesz)
+    {
+        static unsigned lead_n_type = -1;
+        ELFNote note = ELFNote();
+        note.Parse(segment_data, &offset);
+
+        if ((lead_n_type == (unsigned)-1) &&
+           ((note.n_type == NT_PRSTATUS) || (note.n_type == NT_PRPSINFO)))
+            lead_n_type = note.n_type;
+
+        // Begining of new thread
+        if (note.n_type == lead_n_type)
+        {
+            if (thread_data)
+            {
+                assert(thread_data->prstatus.GetByteSize() > 0);
+                // Add the new thread to thread list
+                m_thread_data.push_back(*thread_data);
+            }
+            thread_data = new ThreadData();
+        }
+
+        size_t note_start, note_size;
+        note_start = offset + AlignToNext(note.n_namesz, 4);
+        note_size = AlignToNext(note.n_descsz, 4);
+
+        // Store the NOTE information in the current thread
+        DataExtractor note_data (segment_data, note_start, note_size);
+        switch (note.n_type)
+        {
+            case NT_PRSTATUS:
+                thread_data->prstatus = note_data;
+                break;
+            case NT_FPREGSET:
+                thread_data->fpregset = note_data;
+                break;
+            case NT_PRPSINFO:
+                thread_data->prpsinfo = note_data;
+                break;
+            case NT_AUXV:
+                m_auxv = DataExtractor(note_data);
+                break;
+            default:
+                break;
+        }
+
+        offset += AlignToNext(note.n_namesz, 4) + note_size;
+    }
+    // Add last entry in the note section
+    if (thread_data && thread_data->prstatus.GetByteSize() > 0)
+    {
+        m_thread_data.push_back(*thread_data);
+    }
+}
+
+uint32_t
+ProcessElfCore::GetNumThreadContexts ()
+{
+    if (!m_thread_data_valid)
+        DoLoadCore();
+    return m_thread_data.size();
+}
+
+ArchSpec
+ProcessElfCore::GetArchitecture()
+{
+    ObjectFileELF *core_file = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+    ArchSpec arch;
+    core_file->GetArchitecture(arch);
+    return arch;
+}
+
+const lldb::DataBufferSP
+ProcessElfCore::GetAuxvData()
+{
+    const uint8_t *start = m_auxv.GetDataStart();
+    size_t len = m_auxv.GetByteSize();
+    lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
+    return buffer;
+}
+
index e69de29..34ac05c 100644 (file)
@@ -0,0 +1,178 @@
+//===-- ProcessElfCore.h ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// Notes about Linux Process core dumps:
+//  1) Linux core dump is stored as ELF file.
+//  2) The ELF file's PT_NOTE and PT_LOAD segments describes the program's
+//     address space and thread contexts.
+//  3) PT_NOTE segment contains note entries which describes a thread context.
+//  4) PT_LOAD segment describes a valid contigous range of process address
+//     space.
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessElfCore_h_
+#define liblldb_ProcessElfCore_h_
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+
+#include "Plugins/ObjectFile/ELF/ELFHeader.h"
+
+class ProcessElfCore : public lldb_private::Process
+{
+public:
+    //------------------------------------------------------------------
+    // Constructors and Destructors
+    //------------------------------------------------------------------
+    static lldb::ProcessSP
+    CreateInstance (lldb_private::Target& target, 
+                    lldb_private::Listener &listener, 
+                    const lldb_private::FileSpec *crash_file_path);
+    
+    static void
+    Initialize();
+    
+    static void
+    Terminate();
+    
+    static lldb_private::ConstString
+    GetPluginNameStatic();
+    
+    static const char *
+    GetPluginDescriptionStatic();
+    
+    //------------------------------------------------------------------
+    // Constructors and Destructors
+    //------------------------------------------------------------------
+    ProcessElfCore(lldb_private::Target& target, 
+                    lldb_private::Listener &listener,
+                    const lldb_private::FileSpec &core_file);
+    
+    virtual
+    ~ProcessElfCore();
+    
+    //------------------------------------------------------------------
+    // Check if a given Process
+    //------------------------------------------------------------------
+    virtual bool
+    CanDebug (lldb_private::Target &target,
+              bool plugin_specified_by_name);
+    
+    //------------------------------------------------------------------
+    // Creating a new process, or attaching to an existing one
+    //------------------------------------------------------------------
+    virtual lldb_private::Error
+    DoLoadCore ();
+    
+    virtual lldb_private::DynamicLoader *
+    GetDynamicLoader ();
+
+    //------------------------------------------------------------------
+    // PluginInterface protocol
+    //------------------------------------------------------------------
+    virtual lldb_private::ConstString
+    GetPluginName();
+    
+    virtual uint32_t
+    GetPluginVersion();
+    
+    //------------------------------------------------------------------
+    // Process Control
+    //------------------------------------------------------------------    
+    virtual lldb_private::Error
+    DoDestroy ();
+    
+    virtual void
+    RefreshStateAfterStop();
+    
+    //------------------------------------------------------------------
+    // Process Queries
+    //------------------------------------------------------------------
+    virtual bool
+    IsAlive ();
+
+    //------------------------------------------------------------------
+    // Process Memory
+    //------------------------------------------------------------------
+    virtual size_t
+    ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+    
+    virtual size_t
+    DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+    
+    virtual lldb::addr_t
+    GetImageInfoAddress ();
+
+    lldb_private::ArchSpec
+    GetArchitecture();
+
+    // Returns AUXV structure found in the core file
+    const lldb::DataBufferSP
+    GetAuxvData();
+
+protected:
+    void
+    Clear ( );
+    
+    virtual bool
+    UpdateThreadList (lldb_private::ThreadList &old_thread_list, 
+                      lldb_private::ThreadList &new_thread_list);
+   
+private:
+    //------------------------------------------------------------------
+    // For ProcessElfCore only
+    //------------------------------------------------------------------
+    typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
+    typedef lldb_private::RangeDataArray<lldb::addr_t, lldb::addr_t, FileRange, 1> VMRangeToFileOffset;
+
+    // In ELF core file thread context is described mainly by 3 Note entries
+    // The following structure holds pointers to those note entries.
+    struct ThreadData
+    {
+        lldb_private::DataExtractor prstatus;
+        lldb_private::DataExtractor fpregset;
+        lldb_private::DataExtractor prpsinfo;
+    };
+
+    lldb::ModuleSP m_core_module_sp;
+    lldb_private::FileSpec m_core_file;
+    std::string  m_dyld_plugin_name;
+    DISALLOW_COPY_AND_ASSIGN (ProcessElfCore);
+
+    // True if m_thread_contexts contains valid entries
+    bool m_thread_data_valid;
+
+    // Contain thread data read from NOTE segments
+    std::vector<ThreadData> m_thread_data;
+
+    // AUXV structure found from the NOTE segment
+    lldb_private::DataExtractor m_auxv;
+
+    // Address ranges found in the core
+    VMRangeToFileOffset m_core_aranges;
+
+    // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
+    void
+    ParseThreadContextsFromNoteSegment (const elf::ELFProgramHeader *segment_header,
+                                        lldb_private::DataExtractor segment_data);
+
+    // Returns number of thread contexts stored in the core file
+    uint32_t
+    GetNumThreadContexts();
+
+    // Parse a contiguous address range of the process from LOAD segment
+    lldb::addr_t
+    AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header);
+};
+
+#endif  // liblldb_ProcessElffCore_h_
index e69de29..6210175 100644 (file)
@@ -0,0 +1,68 @@
+//===-- RegisterContextCoreFreeBSD_x86_64.cpp -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "RegisterContextCoreFreeBSD_x86_64.h"
+
+RegisterContextCoreFreeBSD_x86_64::RegisterContextCoreFreeBSD_x86_64(Thread &thread,
+                        const DataExtractor &gpregset, const DataExtractor &fpregset)
+    : RegisterContextFreeBSD_x86_64(thread, 0)
+{
+    size_t size, len;
+
+    size = GetGPRSize();
+    m_gpregset = new uint8_t[size];
+    len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset);
+    assert(len == size);
+}
+
+RegisterContextCoreFreeBSD_x86_64::~RegisterContextCoreFreeBSD_x86_64()
+{
+    delete [] m_gpregset;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+    value = *(uint64_t *)(m_gpregset + reg_info->byte_offset);
+    return true;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+    return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+    return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+    return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::UpdateAfterBreakpoint()
+{
+    return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::HardwareSingleStep(bool enable)
+{
+    return false;
+}
+
index e69de29..acd594a 100644 (file)
@@ -0,0 +1,47 @@
+//===-- RegisterContextCoreFreeBSD_x86_64.h ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCoreFreeBSD_x86_64_H_
+#define liblldb_RegisterContextCoreFreeBSD_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h"
+
+using namespace lldb_private;
+
+class RegisterContextCoreFreeBSD_x86_64: public RegisterContextFreeBSD_x86_64
+{
+public:
+    RegisterContextCoreFreeBSD_x86_64 (Thread &thread, const DataExtractor &gpregset,
+                                       const DataExtractor &fpregset);
+
+    ~RegisterContextCoreFreeBSD_x86_64();
+
+    virtual bool
+    ReadRegister(const RegisterInfo *reg_info, RegisterValue &value);
+
+    bool
+    ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+    virtual bool
+    WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value);
+
+    bool
+    WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+    bool
+    HardwareSingleStep(bool enable);
+
+    bool
+    UpdateAfterBreakpoint();
+
+private:
+    uint8_t *m_gpregset;
+};
+
+#endif // #ifndef liblldb_RegisterContextCoreFreeBSD_x86_64_H_
index e69de29..d9e3f6d 100644 (file)
@@ -0,0 +1,68 @@
+//===-- RegisterContextCoreLinux_x86_64.cpp -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "RegisterContextCoreLinux_x86_64.h"
+
+RegisterContextCoreLinux_x86_64::RegisterContextCoreLinux_x86_64(Thread &thread,
+                                                const DataExtractor &gpregset,
+                                                const DataExtractor &fpregset)
+    : RegisterContextLinux_x86_64(thread, 0)
+{
+    size_t size, len;
+
+    size = GetGPRSize();
+    m_gpregset = new uint8_t[size];
+    len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset);
+    assert(len == size);
+}
+
+RegisterContextCoreLinux_x86_64::~RegisterContextCoreLinux_x86_64()
+{
+    delete [] m_gpregset;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+    value = *(uint64_t *)(m_gpregset + reg_info->byte_offset);
+    return true;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+    return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+    return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+    return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::UpdateAfterBreakpoint()
+{
+    return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::HardwareSingleStep(bool enable)
+{
+    return false;
+}
index e69de29..9cf545a 100644 (file)
@@ -0,0 +1,54 @@
+//===-- RegisterContextCoreLinux_x86_64.h ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCoreLinux_x86_64_H_
+#define liblldb_RegisterContextCoreLinux_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContextLinux_x86_64.h"
+
+using namespace lldb_private;
+
+class RegisterContextCoreLinux_x86_64: public RegisterContextLinux_x86_64
+{
+public:
+    RegisterContextCoreLinux_x86_64 (Thread &thread, const DataExtractor &gpregset,
+                                     const DataExtractor &fpregset);
+
+    ~RegisterContextCoreLinux_x86_64();
+
+    virtual bool
+    ReadRegister(const RegisterInfo *reg_info, RegisterValue &value);
+
+    bool
+    ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+    virtual bool
+    WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value);
+
+    bool
+    WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+    bool
+    HardwareSingleStep(bool enable);
+
+    bool
+    UpdateAfterBreakpoint();
+
+protected:
+    bool
+    ReadFPR()
+    {
+        assert(0);
+    }
+
+private:
+    uint8_t *m_gpregset;
+};
+
+#endif // #ifndef liblldb_RegisterContextCoreLinux_x86_64_H_
index e69de29..de57d25 100644 (file)
@@ -0,0 +1,170 @@
+//===-- ThreadElfCore.cpp --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "ProcessPOSIXLog.h"
+
+#include "ThreadElfCore.h"
+#include "ProcessElfCore.h"
+#include "RegisterContextCoreLinux_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Construct a Thread object with given PRSTATUS, PRPSINFO and FPREGSET
+//----------------------------------------------------------------------
+ThreadElfCore::ThreadElfCore (Process &process, tid_t tid, DataExtractor prstatus,
+                              DataExtractor prpsinfo, DataExtractor fpregset) :
+    Thread(process, tid),
+    m_thread_reg_ctx_sp ()
+{
+    ProcessElfCore *pr = static_cast<ProcessElfCore *>(GetProcess().get());
+    ArchSpec arch = pr->GetArchitecture();
+
+    /* Parse the datastructures from the file */
+    m_prstatus.Parse(prstatus, arch);
+    m_prpsinfo.Parse(prpsinfo, arch);
+
+    m_prstatus_data = prstatus;
+    m_fpregset_data = fpregset;
+
+    m_thread_name = std::string(m_prpsinfo.pr_fname);
+}
+
+ThreadElfCore::~ThreadElfCore ()
+{
+    DestroyThread();
+}
+
+void
+ThreadElfCore::RefreshStateAfterStop()
+{
+    GetRegisterContext()->InvalidateIfNeeded (false);
+}
+
+void
+ThreadElfCore::ClearStackFrames ()
+{
+    Unwind *unwinder = GetUnwinder ();
+    if (unwinder)
+        unwinder->Clear();
+    Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadElfCore::GetRegisterContext ()
+{
+    if (m_reg_context_sp.get() == NULL) {
+        m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+    }
+    return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
+{
+    RegisterContextSP reg_ctx_sp;
+    uint32_t concrete_frame_idx = 0;
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+    if (frame)
+        concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+    if (concrete_frame_idx == 0)
+    {
+        if (m_thread_reg_ctx_sp)
+            return m_thread_reg_ctx_sp;
+
+        ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());
+        ArchSpec arch = process->GetArchitecture();
+        size_t header_size = ELFPrStatus::GetSize(arch);
+        size_t len = m_prstatus_data.GetByteSize() - header_size;
+        DataExtractor gpregset_data = DataExtractor(m_prstatus_data, header_size, len);
+        switch (arch.GetMachine())
+        {
+            case llvm::Triple::x86_64:
+                m_thread_reg_ctx_sp.reset(new RegisterContextCoreLinux_x86_64 (*this, gpregset_data, m_fpregset_data));
+                break;
+            default:
+                if (log)
+                    log->Printf ("elf-core::%s:: Architecture(%d) not supported",
+                                 __FUNCTION__, arch.GetMachine());
+        }
+        reg_ctx_sp = m_thread_reg_ctx_sp;
+    }
+    else if (m_unwinder_ap.get())
+    {
+        reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame (frame);
+    }
+    return reg_ctx_sp;
+}
+
+bool
+ThreadElfCore::CalculateStopInfo ()
+{
+    ProcessSP process_sp (GetProcess());
+    if (process_sp)
+    {
+        SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, m_prstatus.pr_cursig));
+        return true;
+    }
+    return false;
+}
+
+//----------------------------------------------------------------
+// Parse PRSTATUS from NOTE entry
+//----------------------------------------------------------------
+ELFPrStatus::ELFPrStatus()
+{
+    memset(this, 0, sizeof(ELFPrStatus));
+}
+
+bool
+ELFPrStatus::Parse(DataExtractor &data, ArchSpec &arch)
+{
+    ByteOrder byteorder = data.GetByteOrder();
+    size_t len;
+    switch(arch.GetCore())
+    {
+        case ArchSpec::eCore_x86_64_x86_64:
+            len = data.ExtractBytes(0, ELFPRSTATUS64_SIZE, byteorder, this);
+            return len == ELFPRSTATUS64_SIZE;
+        default:
+            return false;
+    }
+}
+
+//----------------------------------------------------------------
+// Parse PRPSINFO from NOTE entry
+//----------------------------------------------------------------
+ELFPrPsInfo::ELFPrPsInfo()
+{
+    memset(this, 0, sizeof(ELFPrPsInfo));
+}
+
+bool
+ELFPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch)
+{
+    ByteOrder byteorder = data.GetByteOrder();
+    size_t len;
+    switch(arch.GetCore())
+    {
+        case ArchSpec::eCore_x86_64_x86_64:
+            len = data.ExtractBytes(0, ELFPRPSINFO64_SIZE, byteorder, this);
+            return len == ELFPRPSINFO64_SIZE;
+        default:
+            return false;
+    }
+}
+
index e69de29..34598a4 100644 (file)
@@ -0,0 +1,168 @@
+//===-- ThreadElfCore.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadElfCore_h_
+#define liblldb_ThreadElfCore_h_
+
+#include <string>
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataExtractor.h"
+
+struct compat_timeval
+{
+    int64_t tv_sec;
+    int32_t tv_usec;
+};
+
+// PRSTATUS structure's size differs based on architecture.
+// Currently parsing done only for x86-64 architecture by
+// simply reading data from the buffer.
+// The following macros are used to specify the size.
+// Calculating size using sizeof() wont work because of padding.
+#define ELFPRSTATUS64_SIZE (112)
+#define ELFPRPSINFO64_SIZE (132)
+
+struct ELFPrStatus
+{
+    int32_t         si_signo;
+    int32_t         si_code;
+    int32_t         si_errno;
+
+    int16_t         pr_cursig;
+    
+    uint64_t        pr_sigpend;
+    uint64_t        pr_sighold;
+
+    uint32_t        pr_pid;
+    uint32_t        pr_ppid;
+    uint32_t        pr_pgrp;
+    uint32_t        pr_sid;
+
+    compat_timeval  pr_utime;
+    compat_timeval  pr_stime;
+    compat_timeval  pr_cutime;
+    compat_timeval  pr_cstime;
+
+    ELFPrStatus();
+
+    bool
+    Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+    static size_t
+    GetSize(lldb_private::ArchSpec &arch)
+    {
+        switch(arch.GetCore())
+        {
+            case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+                return ELFPRSTATUS64_SIZE;
+            default:
+                return 0;
+        }
+    }
+};
+
+struct ELFPrPsInfo
+{
+    char        pr_state;
+    char        pr_sname;
+    char        pr_zomb;
+    char        pr_nice;
+    uint64_t    pr_flag;
+    uint32_t    pr_uid;
+    uint32_t    pr_gid;
+    int32_t     pr_pid;
+    int32_t     pr_ppid;
+    int32_t     pr_pgrp;
+    int32_t     pr_sid;
+    char        pr_fname[16];
+    char        pr_psargs[80];
+
+    ELFPrPsInfo();
+
+    bool
+    Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+    static size_t
+    GetSize(lldb_private::ArchSpec &arch)
+    {
+        switch(arch.GetCore())
+        {
+            case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+                return ELFPRPSINFO64_SIZE;
+            default:
+                return 0;
+        }
+    }
+
+};
+
+class ThreadElfCore : public lldb_private::Thread
+{
+public:
+    ThreadElfCore (lldb_private::Process &process, lldb::tid_t tid,
+                   lldb_private::DataExtractor prstatus,
+                   lldb_private::DataExtractor prpsinfo,
+                   lldb_private::DataExtractor fpregset);
+
+    virtual
+    ~ThreadElfCore ();
+
+    virtual void
+    RefreshStateAfterStop();
+
+    virtual lldb::RegisterContextSP
+    GetRegisterContext ();
+
+    virtual lldb::RegisterContextSP
+    CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+    virtual void
+    ClearStackFrames ();
+
+    static bool
+    ThreadIDIsValid (lldb::tid_t thread)
+    {
+        return thread != 0;
+    }
+
+    virtual const char *
+    GetName ()
+    {
+        if (m_thread_name.empty())
+            return NULL;
+        return m_thread_name.c_str();
+    }
+
+    void
+    SetName (const char *name)
+    {
+        if (name && name[0])
+            m_thread_name.assign (name);
+        else
+            m_thread_name.clear();
+    }
+
+protected:
+    //------------------------------------------------------------------
+    // Member variables.
+    //------------------------------------------------------------------
+    std::string m_thread_name;
+    lldb::RegisterContextSP m_thread_reg_ctx_sp;
+
+    ELFPrStatus m_prstatus;
+    ELFPrPsInfo m_prpsinfo;
+    lldb_private::DataExtractor m_prstatus_data;
+    lldb_private::DataExtractor m_fpregset_data;
+
+    virtual bool CalculateStopInfo();
+
+};
+
+#endif  // liblldb_ThreadElfCore_h_
index f2dfdee..1ac03f4 100644 (file)
 
 #include "Plugins/Process/mach-core/ProcessMachCore.h"
 
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#endif
+
 #if defined (__linux__)
 #include "Plugins/Process/Linux/ProcessLinux.h"
 #endif
@@ -142,6 +146,10 @@ lldb_private::Initialize ()
 #if defined (__FreeBSD__)
         ProcessFreeBSD::Initialize();
 #endif
+
+#if defined(__linux__) or defined(__FreeBSD__)
+        ProcessElfCore::Initialize();
+#endif
         //----------------------------------------------------------------------
         // Platform agnostic plugins
         //----------------------------------------------------------------------
@@ -220,7 +228,10 @@ lldb_private::Terminate ()
 #if defined (__FreeBSD__)
     ProcessFreeBSD::Terminate();
 #endif
-    
+
+#if defined(__linux__) or defined(__FreeBSD__)
+    ProcessElfCore::Terminate();
+#endif
     ProcessGDBRemote::Terminate();
     DynamicLoaderStatic::Terminate();