diff options
author | Ashok Thirumurthi <ashok.thirumurthi@intel.com> | 2013-07-17 16:06:12 +0000 |
---|---|---|
committer | Ashok Thirumurthi <ashok.thirumurthi@intel.com> | 2013-07-17 16:06:12 +0000 |
commit | 4f01ff8bfe4961e3ce6f1b9b6520f5a5588e5590 (patch) | |
tree | 51ea1f17531035d8c53eccc2718bc4eddcb0e90b /lldb | |
parent | c834c70986b01f5086d72bc5c5e564d7d0ebbc74 (diff) | |
download | bcm5719-llvm-4f01ff8bfe4961e3ce6f1b9b6520f5a5588e5590.tar.gz bcm5719-llvm-4f01ff8bfe4961e3ce6f1b9b6520f5a5588e5590.zip |
Re-introduces ELF core file support for Linux x86-64
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
Diffstat (limited to 'lldb')
19 files changed, 1440 insertions, 46 deletions
diff --git a/lldb/lib/Makefile b/lldb/lib/Makefile index ea028ce3735..eb527682392 100644 --- a/lldb/lib/Makefile +++ b/lldb/lib/Makefile @@ -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 diff --git a/lldb/source/CMakeLists.txt b/lldb/source/CMakeLists.txt index 8b7d34f73ed..57543e06c0f 100644 --- a/lldb/source/CMakeLists.txt +++ b/lldb/source/CMakeLists.txt @@ -90,6 +90,7 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Linux" ) lldbHostLinux
lldbPluginProcessLinux
lldbPluginProcessPOSIX
+ lldbPluginProcessElfCore
)
endif ()
@@ -99,6 +100,7 @@ if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" ) lldbHostFreeBSD
lldbPluginProcessFreeBSD
lldbPluginProcessPOSIX
+ lldbPluginProcessElfCore
)
endif ()
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp index 7123786b601..2604ae67016 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp @@ -19,6 +19,10 @@ #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); } diff --git a/lldb/source/Plugins/Makefile b/lldb/source/Plugins/Makefile index f420a03deee..3694f319b69 100644 --- a/lldb/source/Plugins/Makefile +++ b/lldb/source/Plugins/Makefile @@ -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 diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index cf12bcdf34b..5d8986ec5d4 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -1,13 +1,14 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
add_subdirectory(Linux)
add_subdirectory(POSIX)
+ add_subdirectory(elf-core)
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
add_subdirectory(FreeBSD)
add_subdirectory(POSIX)
+ add_subdirectory(elf-core)
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
add_subdirectory(MacOSX-Kernel)
endif()
-
add_subdirectory(gdb-remote)
add_subdirectory(Utility)
add_subdirectory(mach-core)
diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp index 8c0a2a240f2..c53a2eb2e33 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp @@ -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); +} + diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinux.h b/lldb/source/Plugins/Process/Linux/ProcessLinux.h index d7f338fe984..c651351599a 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/ProcessLinux.h @@ -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; }; diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp index 73eb7b95135..617b18484e5 100644 --- a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp +++ b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp @@ -21,10 +21,13 @@ #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 diff --git a/lldb/source/Plugins/Process/elf-core/CMakeLists.txt b/lldb/source/Plugins/Process/elf-core/CMakeLists.txt index e69de29bb2d..cf454b9f95e 100644 --- a/lldb/source/Plugins/Process/elf-core/CMakeLists.txt +++ b/lldb/source/Plugins/Process/elf-core/CMakeLists.txt @@ -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 + ) diff --git a/lldb/source/Plugins/Process/elf-core/Makefile b/lldb/source/Plugins/Process/elf-core/Makefile index e69de29bb2d..51a0aaea624 100644 --- a/lldb/source/Plugins/Process/elf-core/Makefile +++ b/lldb/source/Plugins/Process/elf-core/Makefile @@ -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 diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index e69de29bb2d..8b527402316 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -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; +} + diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index e69de29bb2d..34ac05cbfba 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -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_ diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp index e69de29bb2d..6210175f9a7 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp @@ -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; +} + diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h index e69de29bb2d..acd594a6e66 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h @@ -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_ diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp index e69de29bb2d..d9e3f6d5f90 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp @@ -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; +} diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h index e69de29bb2d..9cf545afd56 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h @@ -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_ diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index e69de29bb2d..de57d25316d 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -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; + } +} + diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index e69de29bb2d..34598a4f52b 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -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_ diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp index f2dfdee96a0..1ac03f4f190 100644 --- a/lldb/source/lldb.cpp +++ b/lldb/source/lldb.cpp @@ -62,6 +62,10 @@ #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(); |