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
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
lldbHostLinux\r
lldbPluginProcessLinux\r
lldbPluginProcessPOSIX\r
+ lldbPluginProcessElfCore\r
)\r
endif ()\r
\r
lldbHostFreeBSD\r
lldbPluginProcessFreeBSD\r
lldbPluginProcessPOSIX\r
+ lldbPluginProcessElfCore\r
)\r
endif ()\r
\r
#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;
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);
}
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
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
// 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
//------------------------------------------------------------------------------
// 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
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);
+}
+
// 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);
return m_linux_signals;
}
+ virtual bool
+ CanDebug(lldb_private::Target &target, bool plugin_specified_by_name);
+
//------------------------------------------------------------------
// ProcessPOSIX overrides
//------------------------------------------------------------------
/// 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;
};
#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;
::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())
{
}
-ProcessMonitor &
-RegisterContext_x86_64::GetMonitor()
-{
- ProcessSP base = CalculateProcess();
- ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
- return process->GetMonitor();
-}
-
void
RegisterContext_x86_64::Invalidate()
{
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)
{
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)) {
}
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.
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()
{
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
+include_directories(../Utility)
+
+set(LLVM_NO_RTTI 1)
+
+add_lldb_library(lldbPluginProcessElfCore
+ ProcessElfCore.cpp
+ ThreadElfCore.cpp
+ RegisterContextCoreLinux_x86_64.cpp
+ RegisterContextCoreFreeBSD_x86_64.cpp
+ )
+##===- 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
+//===-- 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;
+}
+
+//===-- 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_
+//===-- 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;
+}
+
+//===-- 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_
+//===-- 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;
+}
+//===-- 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_
+//===-- 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;
+ }
+}
+
+//===-- 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_
#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
#if defined (__FreeBSD__)
ProcessFreeBSD::Initialize();
#endif
+
+#if defined(__linux__) or defined(__FreeBSD__)
+ ProcessElfCore::Initialize();
+#endif
//----------------------------------------------------------------------
// Platform agnostic plugins
//----------------------------------------------------------------------
#if defined (__FreeBSD__)
ProcessFreeBSD::Terminate();
#endif
-
+
+#if defined(__linux__) or defined(__FreeBSD__)
+ ProcessElfCore::Terminate();
+#endif
ProcessGDBRemote::Terminate();
DynamicLoaderStatic::Terminate();