[Lldb-commits] [lldb] r109318 - in /lldb/trunk: lib/ source/ source/Plugins/ source/Plugins/Process/Linux/
Stephen Wilson
wilsons at start.ca
Fri Jul 23 19:19:04 PDT 2010
Author: wilsons
Date: Fri Jul 23 21:19:04 2010
New Revision: 109318
URL: http://llvm.org/viewvc/llvm-project?rev=109318&view=rev
Log:
Add a new Process plugin for Linux.
This component is still at an early stage, but allows for simple
breakpoint/step-over operations and basic process control.
The makefiles are set up to build the plugin under Linux only.
Added:
lldb/trunk/source/Plugins/Process/Linux/
lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp
lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h
lldb/trunk/source/Plugins/Process/Linux/Makefile
lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
lldb/trunk/source/Plugins/Process/Linux/ProcessMessage.h
lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux.h
lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp
lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h
Modified:
lldb/trunk/lib/Makefile
lldb/trunk/source/Plugins/Makefile
lldb/trunk/source/lldb.cpp
Modified: lldb/trunk/lib/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lib/Makefile?rev=109318&r1=109317&r2=109318&view=diff
==============================================================================
--- lldb/trunk/lib/Makefile (original)
+++ lldb/trunk/lib/Makefile Fri Jul 23 21:19:04 2010
@@ -33,7 +33,6 @@
lldbPluginObjectFileELF.a \
lldbPluginSymbolFileDWARF.a \
lldbPluginSymbolFileSymtab.a \
- lldbPluginSymbolVendorMacOSX.a \
lldbSymbol.a \
lldbTarget.a \
lldbUtility.a \
@@ -65,11 +64,13 @@
lldbPluginObjectContainerUniversalMachO.a \
lldbPluginObjectFileMachO.a \
lldbPluginProcessGDBRemote.a \
- lldbPluginUtility.a
+ lldbPluginUtility.a \
+ lldbSymbolVendorMaxOSX.a
endif
ifeq ($(HOST_OS),Linux)
- USEDLIBS += lldbHostLinux.a
+ USEDLIBS += lldbHostLinux.a \
+ lldbPluginProcessLinux.a
endif
include $(LEVEL)/Makefile.common
Modified: lldb/trunk/source/Plugins/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Makefile?rev=109318&r1=109317&r2=109318&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Makefile (original)
+++ lldb/trunk/source/Plugins/Makefile Fri Jul 23 21:19:04 2010
@@ -12,10 +12,17 @@
include $(LLDB_LEVEL)/../../Makefile.config
-DIRS := ABI/MacOSX-i386 ABI/SysV-x86_64 Disassembler/llvm ObjectContainer/BSD-Archive ObjectFile/ELF SymbolFile/DWARF SymbolFile/Symtab
+DIRS := ABI/MacOSX-i386 ABI/SysV-x86_64 Disassembler/llvm \
+ ObjectContainer/BSD-Archive ObjectFile/ELF SymbolFile/DWARF \
+ SymbolFile/Symtab
ifeq ($(HOST_OS),Darwin)
- DIRS += DynamicLoader/MacOSX-DYLD ObjectContainer/Universal-Mach-O ObjectFile/Mach-O Process/gdb-remote Process/Utility SymbolVendor/MacOSX
+DIRS += DynamicLoader/MacOSX-DYLD ObjectContainer/Universal-Mach-O \
+ ObjectFile/Mach-O Process/gdb-remote Process/Utility SymbolVendor/MacOSX
+endif
+
+ifeq ($(HOST_OS),Linux)
+DIRS += Process/Linux
endif
include $(LLDB_LEVEL)/Makefile
Added: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp Fri Jul 23 21:19:04 2010
@@ -0,0 +1,198 @@
+//===-- LinuxThread.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "LinuxThread.h"
+#include "ProcessLinux.h"
+#include "ProcessMonitor.h"
+#include "RegisterContextLinux_x86_64.h"
+
+using namespace lldb_private;
+
+LinuxThread::LinuxThread(Process &process, lldb::tid_t tid)
+ : Thread(process, tid),
+ m_frame_ap(0),
+ m_register_ap(0),
+ m_note(eNone)
+{
+ ArchSpec arch = process.GetTarget().GetArchitecture();
+
+ switch (arch.GetGenericCPUType())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCPU_x86_64:
+ m_register_ap.reset(new RegisterContextLinux_x86_64(*this, NULL));
+ break;
+ }
+}
+
+ProcessMonitor &
+LinuxThread::GetMonitor()
+{
+ ProcessLinux *process = static_cast<ProcessLinux*>(CalculateProcess());
+ return process->GetMonitor();
+}
+
+void
+LinuxThread::RefreshStateAfterStop()
+{
+}
+
+const char *
+LinuxThread::GetInfo()
+{
+ return NULL;
+}
+
+uint32_t
+LinuxThread::GetStackFrameCount()
+{
+ return 0;
+}
+
+lldb::StackFrameSP
+LinuxThread::GetStackFrameAtIndex(uint32_t idx)
+{
+ if (idx == 0)
+ {
+ RegisterContextLinux *regs = GetRegisterContext();
+ StackFrame *frame = new StackFrame(
+ idx, *this, regs->GetFP(), regs->GetPC());
+ return lldb::StackFrameSP(frame);
+ }
+ else
+ return lldb::StackFrameSP();
+}
+
+RegisterContextLinux *
+LinuxThread::GetRegisterContext()
+{
+ return m_register_ap.get();
+}
+
+bool
+LinuxThread::SaveFrameZeroState(RegisterCheckpoint &checkpoint)
+{
+ return false;
+}
+
+bool
+LinuxThread::RestoreSaveFrameZero(const RegisterCheckpoint &checkpoint)
+{
+ return false;
+}
+
+RegisterContextLinux *
+LinuxThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
+{
+ return new RegisterContextLinux_x86_64(*this, frame);
+}
+
+bool
+LinuxThread::GetRawStopReason(StopInfo *stop_info)
+{
+ stop_info->Clear();
+
+ switch (m_note)
+ {
+ default:
+ stop_info->SetStopReasonToNone();
+ break;
+
+ case eBreak:
+ stop_info->SetStopReasonWithBreakpointSiteID(m_breakpoint->GetID());
+ break;
+
+ case eTrace:
+ stop_info->SetStopReasonToTrace();
+ }
+
+ return true;
+}
+
+bool
+LinuxThread::WillResume(lldb::StateType resume_state)
+{
+ SetResumeState(resume_state);
+ return Thread::WillResume(resume_state);
+}
+
+bool
+LinuxThread::Resume()
+{
+ lldb::StateType resume_state = GetResumeState();
+ ProcessMonitor &monitor = GetMonitor();
+ bool status;
+
+ switch (GetResumeState())
+ {
+ default:
+ assert(false && "Unexpected state for resume!");
+ status = false;
+ break;
+
+ case lldb::eStateSuspended:
+ // FIXME: Implement process suspension.
+ status = false;
+
+ case lldb::eStateRunning:
+ SetState(resume_state);
+ status = monitor.Resume(GetID());
+ break;
+
+ case lldb::eStateStepping:
+ SetState(resume_state);
+ status = GetRegisterContext()->HardwareSingleStep(true);
+ break;
+ }
+
+ m_note = eNone;
+ return status;
+}
+
+void
+LinuxThread::BreakNotify()
+{
+ bool status;
+
+ status = GetRegisterContext()->UpdateAfterBreakpoint();
+ assert(status && "Breakpoint update failed!");
+
+ // With our register state restored, resolve the breakpoint object
+ // corresponding to our current PC.
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site =
+ GetProcess().GetBreakpointSiteList().FindByAddress(pc);
+ assert(bp_site && bp_site->ValidForThisThread(this));
+
+ m_note = eBreak;
+ m_breakpoint = bp_site;
+}
+
+void
+LinuxThread::TraceNotify()
+{
+ m_note = eTrace;
+}
+
+void
+LinuxThread::ExitNotify()
+{
+ m_note = eExit;
+}
Added: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h Fri Jul 23 21:19:04 2010
@@ -0,0 +1,89 @@
+//===-- LinuxThread.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_LinuxThread_H_
+#define liblldb_LinuxThread_H_
+
+// C Includes
+// C++ Includes
+#include <memory>
+
+// Other libraries and framework includes
+#include "lldb/Target/Thread.h"
+#include "RegisterContextLinux.h"
+
+class ProcessMonitor;
+
+//------------------------------------------------------------------------------
+// @class LinuxThread
+// @brief Abstraction of a linux process (thread).
+class LinuxThread
+ : public lldb_private::Thread
+{
+public:
+ LinuxThread(lldb_private::Process &process, lldb::tid_t tid);
+
+ void
+ RefreshStateAfterStop();
+
+ bool
+ WillResume(lldb::StateType resume_state);
+
+ const char *
+ GetInfo();
+
+ uint32_t
+ GetStackFrameCount();
+
+ lldb::StackFrameSP
+ GetStackFrameAtIndex(uint32_t idx);
+
+ RegisterContextLinux *
+ GetRegisterContext();
+
+ bool
+ SaveFrameZeroState(RegisterCheckpoint &checkpoint);
+
+ bool
+ RestoreSaveFrameZero(const RegisterCheckpoint &checkpoint);
+
+ RegisterContextLinux *
+ CreateRegisterContextForFrame(lldb_private::StackFrame *frame);
+
+ bool
+ GetRawStopReason(StopInfo *stop_info);
+
+ //--------------------------------------------------------------------------
+ // These methods form a specialized interface to linux threads.
+ //
+ bool Resume();
+
+ void BreakNotify();
+ void TraceNotify();
+ void ExitNotify();
+
+private:
+ std::auto_ptr<lldb_private::StackFrame> m_frame_ap;
+ std::auto_ptr<RegisterContextLinux> m_register_ap;
+
+ lldb::BreakpointSiteSP m_breakpoint;
+
+ enum Notification {
+ eNone,
+ eBreak,
+ eTrace,
+ eExit
+ };
+
+ Notification m_note;
+
+ ProcessMonitor &GetMonitor();
+};
+
+#endif // #ifndef liblldb_LinuxThread_H_
Added: lldb/trunk/source/Plugins/Process/Linux/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/Makefile?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/Makefile (added)
+++ lldb/trunk/source/Plugins/Process/Linux/Makefile Fri Jul 23 21:19:04 2010
@@ -0,0 +1,14 @@
+##===- source/Plugins/Process/Linux/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 := lldbPluginProcessLinux
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
Added: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp Fri Jul 23 21:19:04 2010
@@ -0,0 +1,443 @@
+//===-- ProcessLinux.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
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessLinux.h"
+#include "ProcessMonitor.h"
+#include "LinuxThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static functions.
+
+Process*
+ProcessLinux::CreateInstance(Target& target, Listener &listener)
+{
+ return new ProcessLinux(target, listener);
+}
+
+void
+ProcessLinux::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (!g_initialized)
+ {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ g_initialized = true;
+ }
+}
+
+void
+ProcessLinux::Terminate()
+{
+}
+
+const char *
+ProcessLinux::GetPluginNameStatic()
+{
+ return "plugin.process.linux";
+}
+
+const char *
+ProcessLinux::GetPluginDescriptionStatic()
+{
+ return "Process plugin for Linux";
+}
+
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessLinux::ProcessLinux(Target& target, Listener &listener)
+ : Process(target, listener),
+ m_monitor(NULL),
+ m_module(NULL)
+{
+ // FIXME: Putting this code in the ctor and saving the byte order in a
+ // member variable is a hack to avoid const qual issues in GetByteOrder.
+ ObjectFile *obj_file = GetTarget().GetExecutableModule()->GetObjectFile();
+ m_byte_order = obj_file->GetByteOrder();
+}
+
+ProcessLinux::~ProcessLinux()
+{
+ delete m_monitor;
+}
+
+//------------------------------------------------------------------------------
+// Process protocol.
+
+bool
+ProcessLinux::CanDebug(Target &target)
+{
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target.GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ return false;
+}
+
+Error
+ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Error
+ProcessLinux::DoLaunch(Module *module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ SetPrivateState(eStateLaunching);
+ m_monitor = new ProcessMonitor(this, module,
+ argv, envp,
+ stdin_path, stdout_path, stderr_path,
+ error);
+
+ m_module = module;
+
+ if (!error.Success())
+ return error;
+
+ return error;
+}
+
+void
+ProcessLinux::DidLaunch()
+{
+ UpdateLoadedSections();
+}
+
+Error
+ProcessLinux::DoResume()
+{
+ assert(GetPrivateState() == eStateStopped && "Bad state for DoResume!");
+
+ // Set our state to running. This ensures inferior threads do not post a
+ // state change first.
+ SetPrivateState(eStateRunning);
+
+ bool did_resume = false;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ LinuxThread *thread = static_cast<LinuxThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ did_resume = thread->Resume() || did_resume;
+ }
+ assert(did_resume && "Process resume failed!");
+
+ return Error();
+}
+
+Error
+ProcessLinux::DoHalt()
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Error
+ProcessLinux::DoDetach()
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Error
+ProcessLinux::DoSignal(int signal)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Error
+ProcessLinux::DoDestroy()
+{
+ Error error;
+
+ if (!HasExited())
+ {
+ // Shut down the private state thread as we will syncronize with events
+ // ourselves. Discard all current thread plans.
+ PausePrivateStateThread();
+ GetThreadList().DiscardThreadPlans();
+
+ // Bringing the inferior into limbo will be caught by our monitor
+ // thread, in turn updating the process state.
+ if (!m_monitor->BringProcessIntoLimbo())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process termination failed.");
+ return error;
+ }
+
+ // Wait for the event to arrive. This guaranteed to be an exit event.
+ StateType state;
+ EventSP event;
+ do {
+ state = WaitForStateChangedEventsPrivate(NULL, event);
+ } while (state != eStateExited);
+
+ // Restart standard event handling and send the process the final kill,
+ // driving it out of limbo.
+ ResumePrivateStateThread();
+ }
+
+ if (kill(m_monitor->GetPID(), SIGKILL))
+ error.SetErrorToErrno();
+ return error;
+}
+
+void
+ProcessLinux::SendMessage(const ProcessMessage &message)
+{
+ Mutex::Locker lock(m_message_mutex);
+ m_message_queue.push(message);
+
+ switch (message.GetKind())
+ {
+ default:
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eExitMessage:
+ SetExitStatus(message.GetExitStatus(), NULL);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ SetExitStatus(-1, NULL);
+ break;
+ }
+}
+
+void
+ProcessLinux::RefreshStateAfterStop()
+{
+ Mutex::Locker lock(m_message_mutex);
+ if (m_message_queue.empty())
+ return;
+
+ ProcessMessage &message = m_message_queue.front();
+
+ // Resolve the thread this message corresponds to.
+ lldb::tid_t tid = message.GetTID();
+ LinuxThread *thread = static_cast<LinuxThread*>(
+ GetThreadList().FindThreadByID(tid, false).get());
+
+ switch (message.GetKind())
+ {
+ default:
+ assert(false && "Unexpected message kind!");
+ break;
+
+ case ProcessMessage::eExitMessage:
+ case ProcessMessage::eSignalMessage:
+ thread->ExitNotify();
+ break;
+
+ case ProcessMessage::eTraceMessage:
+ thread->TraceNotify();
+ break;
+
+ case ProcessMessage::eBreakpointMessage:
+ thread->BreakNotify();
+ break;
+ }
+
+ m_message_queue.pop();
+}
+
+bool
+ProcessLinux::IsAlive()
+{
+ StateType state = GetPrivateState();
+ return state != eStateExited && state != eStateInvalid;
+}
+
+size_t
+ProcessLinux::DoReadMemory(addr_t vm_addr,
+ void *buf, size_t size, Error &error)
+{
+ return m_monitor->ReadMemory(vm_addr, buf, size, error);
+}
+
+size_t
+ProcessLinux::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
+ Error &error)
+{
+ return m_monitor->WriteMemory(vm_addr, buf, size, error);
+}
+
+addr_t
+ProcessLinux::DoAllocateMemory(size_t size, uint32_t permissions,
+ Error &error)
+{
+ return 0;
+}
+
+addr_t
+ProcessLinux::AllocateMemory(size_t size, uint32_t permissions, Error &error)
+{
+ return 0;
+}
+
+Error
+ProcessLinux::DoDeallocateMemory(lldb::addr_t ptr)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+size_t
+ProcessLinux::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
+{
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+
+ ArchSpec arch = GetTarget().GetArchitecture();
+ const uint8_t *opcode = NULL;
+ size_t opcode_size = 0;
+
+ switch (arch.GetGenericCPUType())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCPU_i386:
+ case ArchSpec::eCPU_x86_64:
+ opcode = g_i386_opcode;
+ opcode_size = sizeof(g_i386_opcode);
+ break;
+ }
+
+ bp_site->SetTrapOpcode(opcode, opcode_size);
+ return opcode_size;
+}
+
+Error
+ProcessLinux::EnableBreakpoint(BreakpointSite *bp_site)
+{
+ return EnableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessLinux::DisableBreakpoint(BreakpointSite *bp_site)
+{
+ return DisableSoftwareBreakpoint(bp_site);
+}
+
+uint32_t
+ProcessLinux::UpdateThreadListIfNeeded()
+{
+ // Do not allow recursive updates.
+ return m_thread_list.GetSize(false);
+}
+
+ByteOrder
+ProcessLinux::GetByteOrder() const
+{
+ // FIXME: We should be able to extract this value directly. See comment in
+ // ProcessLinux().
+ return m_byte_order;
+}
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+const char *
+ProcessLinux::GetPluginName()
+{
+ return "process.linux";
+}
+
+const char *
+ProcessLinux::GetShortPluginName()
+{
+ return "process.linux";
+}
+
+uint32_t
+ProcessLinux::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessLinux::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+Error
+ProcessLinux::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Log *
+ProcessLinux::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+// Utility functions.
+
+void
+ProcessLinux::UpdateLoadedSections()
+{
+ ObjectFile *obj_file = m_module->GetObjectFile();
+ SectionList *sections = obj_file->GetSectionList();
+
+ // FIXME: SectionList provides iterator types, but no begin/end methods.
+ size_t num_sections = sections->GetSize();
+ for (unsigned i = 0; i < num_sections; ++i)
+ {
+ Section *section = sections->GetSectionAtIndex(i).get();
+
+ lldb::addr_t new_load_addr = section->GetFileAddress();
+ lldb::addr_t old_load_addr = GetSectionLoadAddress(section);
+
+ if (old_load_addr == LLDB_INVALID_ADDRESS ||
+ old_load_addr != new_load_addr)
+ SectionLoaded(section, new_load_addr);
+ }
+}
+
+bool
+ProcessLinux::HasExited()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateUnloaded:
+ case eStateCrashed:
+ case eStateDetached:
+ case eStateExited:
+ return true;
+ }
+
+ return false;
+}
Added: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h Fri Jul 23 21:19:04 2010
@@ -0,0 +1,188 @@
+//===-- ProcessLinux.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_ProcessLinux_H_
+#define liblldb_ProcessLinux_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "ProcessMessage.h"
+
+class ProcessMonitor;
+
+class ProcessLinux :
+ public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Static functions.
+ //------------------------------------------------------------------
+ static Process*
+ CreateInstance(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessLinux(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessLinux();
+
+ //------------------------------------------------------------------
+ // Process protocol.
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug(lldb_private::Target &target);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID(lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoLaunch(lldb_private::Module *module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path);
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb_private::Error
+ DoResume();
+
+ virtual lldb_private::Error
+ DoHalt();
+
+ virtual lldb_private::Error
+ DoDetach();
+
+ virtual lldb_private::Error
+ DoSignal(int signal);
+
+ virtual lldb_private::Error
+ DoDestroy();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual bool
+ IsAlive();
+
+ virtual size_t
+ DoReadMemory(lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory(size_t size, uint32_t permissions,
+ lldb_private::Error &error);
+
+ lldb::addr_t
+ AllocateMemory(size_t size, uint32_t permissions,
+ lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory(lldb::addr_t ptr);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
+
+ virtual lldb_private::Error
+ EnableBreakpoint(lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpoint(lldb_private::BreakpointSite *bp_site);
+
+ virtual uint32_t
+ UpdateThreadListIfNeeded();
+
+ virtual lldb::ByteOrder
+ GetByteOrder() const;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command,
+ lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm,
+ lldb_private::Args &command);
+
+ //--------------------------------------------------------------------------
+ // ProcessLinux internal API.
+
+ /// Registers the given message with this process.
+ void SendMessage(const ProcessMessage &message);
+
+ ProcessMonitor &GetMonitor() { return *m_monitor; }
+
+private:
+ /// Target byte order.
+ lldb::ByteOrder m_byte_order;
+
+ /// Process monitor;
+ ProcessMonitor *m_monitor;
+
+ /// The module we are executing.
+ lldb_private::Module *m_module;
+
+ /// Message queue notifying this instance of inferior process state changes.
+ lldb_private::Mutex m_message_mutex;
+ std::queue<ProcessMessage> m_message_queue;
+
+ /// Updates the loaded sections provided by the executable.
+ ///
+ /// FIXME: It would probably be better to delegate this task to the
+ /// DynamicLoader plugin, when we have one.
+ void UpdateLoadedSections();
+
+ /// Returns true if the process has exited.
+ bool HasExited();
+};
+
+#endif // liblldb_MacOSXProcess_H_
Added: lldb/trunk/source/Plugins/Process/Linux/ProcessMessage.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMessage.h?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMessage.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMessage.h Fri Jul 23 21:19:04 2010
@@ -0,0 +1,88 @@
+//===-- ProcessMessage.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_ProcessMessage_H_
+#define liblldb_ProcessMessage_H_
+
+#include <cassert>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+class ProcessMessage
+{
+public:
+
+ /// The type of signal this message can correspond to.
+ enum Kind
+ {
+ eInvalidMessage,
+ eExitMessage,
+ eLimboMessage,
+ eSignalMessage,
+ eTraceMessage,
+ eBreakpointMessage
+ };
+
+ ProcessMessage()
+ : m_kind(eInvalidMessage),
+ m_tid(LLDB_INVALID_PROCESS_ID),
+ m_data(0) { }
+
+ Kind GetKind() const { return m_kind; }
+
+ lldb::tid_t GetTID() const { return m_tid; }
+
+ static ProcessMessage Exit(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eExitMessage, status);
+ }
+
+ static ProcessMessage Limbo(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eLimboMessage, status);
+ }
+
+ static ProcessMessage Signal(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalMessage, signum);
+ }
+
+ static ProcessMessage Trace(lldb::tid_t tid) {
+ return ProcessMessage(tid, eTraceMessage);
+ }
+
+ static ProcessMessage Break(lldb::tid_t tid) {
+ return ProcessMessage(tid, eBreakpointMessage);
+ }
+
+ int GetExitStatus() const {
+ assert(GetKind() == eExitMessage || GetKind() == eLimboMessage);
+ return m_data;
+ }
+
+ int GetSignal() const {
+ assert(GetKind() == eSignalMessage);
+ return m_data;
+ }
+
+ int GetStopStatus() const {
+ assert(GetKind() == eSignalMessage);
+ return m_data;
+ }
+
+private:
+ ProcessMessage(lldb::tid_t tid, Kind kind, int data = 0)
+ : m_kind(kind),
+ m_tid(tid),
+ m_data(data) { }
+
+ Kind m_kind;
+ lldb::tid_t m_tid;
+ int m_data;
+};
+
+#endif // #ifndef liblldb_ProcessMessage_H_
Added: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Fri Jul 23 21:19:04 2010
@@ -0,0 +1,925 @@
+//===-- ProcessMonitor.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 <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include "LinuxThread.h"
+#include "ProcessLinux.h"
+#include "ProcessMonitor.h"
+
+
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static implementations of ProcessMonitor::ReadMemory and
+// ProcessMonitor::WriteMemory. This enables mutual recursion between these
+// functions without needed to go thru the thread funnel.
+
+static size_t
+DoReadMemory(lldb::pid_t pid, unsigned word_size,
+ lldb::addr_t vm_addr, void *buf, size_t size, Error &error)
+{
+ unsigned char *dst = static_cast<unsigned char*>(buf);
+ size_t bytes_read;
+ size_t remainder;
+ long data;
+
+ for (bytes_read = 0; bytes_read < size; bytes_read += remainder)
+ {
+ errno = 0;
+ data = ptrace(PTRACE_PEEKDATA, pid, vm_addr, NULL);
+
+ if (data == -1L && errno)
+ {
+ error.SetErrorToErrno();
+ return bytes_read;
+ }
+
+ remainder = size - bytes_read;
+ remainder = remainder > word_size ? word_size : remainder;
+ for (unsigned i = 0; i < remainder; ++i)
+ dst[i] = ((data >> i*8) & 0xFF);
+ vm_addr += word_size;
+ dst += word_size;
+ }
+
+ return bytes_read;
+}
+
+static size_t
+DoWriteMemory(lldb::pid_t pid, unsigned word_size,
+ lldb::addr_t vm_addr, const void *buf, size_t size, Error &error)
+{
+ const unsigned char *src = static_cast<const unsigned char*>(buf);
+ size_t bytes_written = 0;
+ size_t remainder;
+
+ for (bytes_written = 0; bytes_written < size; bytes_written += remainder)
+ {
+ remainder = size - bytes_written;
+ remainder = remainder > word_size ? word_size : remainder;
+
+ if (remainder == word_size)
+ {
+ unsigned long data = 0;
+ for (unsigned i = 0; i < word_size; ++i)
+ data |= (unsigned long)src[i] << i*8;
+
+ if (ptrace(PTRACE_POKEDATA, pid, vm_addr, data))
+ {
+ error.SetErrorToErrno();
+ return bytes_written;
+ }
+ }
+ else
+ {
+ unsigned char buff[8];
+ if (DoReadMemory(pid, word_size, vm_addr,
+ buff, word_size, error) != word_size)
+ return bytes_written;
+
+ memcpy(buff, src, remainder);
+
+ if (DoWriteMemory(pid, word_size, vm_addr,
+ buff, word_size, error) != word_size)
+ return bytes_written;
+ }
+
+ vm_addr += word_size;
+ src += word_size;
+ }
+ return bytes_written;
+}
+
+
+//------------------------------------------------------------------------------
+/// @class Operation
+/// @brief Represents a ProcessMonitor operation.
+///
+/// Under Linux, it is not possible to ptrace() from any other thread but the
+/// one that spawned or attached to the process from the start. Therefore, when
+/// a ProcessMonitor is asked to deliver or change the state of an inferior
+/// process the operation must be "funneled" to a specific thread to perform the
+/// task. The Operation class provides an abstract base for all services the
+/// ProcessMonitor must perform via the single virtual function Execute, thus
+/// encapsulating the code that needs to run in the privileged context.
+class Operation
+{
+public:
+ virtual void Execute(ProcessMonitor *monitor) = 0;
+};
+
+//------------------------------------------------------------------------------
+/// @class ReadOperation
+/// @brief Implements ProcessMonitor::ReadMemory.
+class ReadOperation : public Operation
+{
+public:
+ ReadOperation(lldb::addr_t addr, void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+ReadOperation::Execute(ProcessMonitor *monitor)
+{
+ const unsigned word_size = monitor->GetProcess().GetAddressByteSize();
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoReadMemory(pid, word_size, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadOperation
+/// @brief Implements ProcessMonitor::WriteMemory.
+class WriteOperation : public Operation
+{
+public:
+ WriteOperation(lldb::addr_t addr, const void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ const void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+WriteOperation::Execute(ProcessMonitor *monitor)
+{
+ const unsigned word_size = monitor->GetProcess().GetAddressByteSize();
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoWriteMemory(pid, word_size, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadRegOperation
+/// @brief Implements ProcessMonitor::ReadRegisterValue.
+class ReadRegOperation : public Operation
+{
+public:
+ ReadRegOperation(unsigned offset, Scalar &value, bool &result)
+ : m_offset(offset), m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ unsigned m_offset;
+ Scalar &m_value;
+ bool &m_result;
+};
+
+void
+ReadRegOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ // Set errno to zero so that we can detect a failed peek.
+ errno = 0;
+ unsigned long data = ptrace(PTRACE_PEEKUSER, pid, m_offset, NULL);
+
+ if (data == -1UL && errno)
+ m_result = false;
+ else
+ {
+ m_value = data;
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteRegOperation
+/// @brief Implements ProcessMonitor::WriteRegisterValue.
+class WriteRegOperation : public Operation
+{
+public:
+ WriteRegOperation(unsigned offset, const Scalar &value, bool &result)
+ : m_offset(offset), m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ unsigned m_offset;
+ const Scalar &m_value;
+ bool &m_result;
+};
+
+void
+WriteRegOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (ptrace(PTRACE_POKEUSER, pid, m_offset, m_value.ULong()))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ResumeOperation
+/// @brief Implements ProcessMonitor::Resume.
+class ResumeOperation : public Operation
+{
+public:
+ ResumeOperation(lldb::tid_t tid, bool &result) :
+ m_tid(tid), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ bool &m_result;
+};
+
+void
+ResumeOperation::Execute(ProcessMonitor *monitor)
+{
+ if (ptrace(PTRACE_CONT, m_tid, NULL, NULL))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ResumeOperation
+/// @brief Implements ProcessMonitor::SingleStep.
+class SingleStepOperation : public Operation
+{
+public:
+ SingleStepOperation(lldb::tid_t tid, bool &result)
+ : m_tid(tid), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ bool &m_result;
+};
+
+void
+SingleStepOperation::Execute(ProcessMonitor *monitor)
+{
+ if (ptrace(PTRACE_SINGLESTEP, m_tid, NULL, NULL))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class SiginfoOperation
+/// @brief Implements ProcessMonitor::GetSignalInfo.
+class SiginfoOperation : public Operation
+{
+public:
+ SiginfoOperation(lldb::tid_t tid, void *info, bool &result)
+ : m_tid(tid), m_info(info), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_info;
+ bool &m_result;
+};
+
+void
+SiginfoOperation::Execute(ProcessMonitor *monitor)
+{
+ if (ptrace(PTRACE_GETSIGINFO, m_tid, NULL, m_info))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class EventMessageOperation
+/// @brief Implements ProcessMonitor::GetEventMessage.
+class EventMessageOperation : public Operation
+{
+public:
+ EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result)
+ : m_tid(tid), m_message(message), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned long *m_message;
+ bool &m_result;
+};
+
+void
+EventMessageOperation::Execute(ProcessMonitor *monitor)
+{
+ if (ptrace(PTRACE_GETEVENTMSG, m_tid, NULL, m_message))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class KillOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class KillOperation : public Operation
+{
+public:
+ KillOperation(bool &result) : m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ bool &m_result;
+};
+
+void
+KillOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (ptrace(PTRACE_KILL, pid, NULL, NULL))
+ m_result = false;
+ else
+ m_result = true;
+
+#if 0
+ // First, stop the inferior process.
+ if (kill(pid, SIGSTOP))
+ {
+ m_result = false;
+ return;
+ }
+
+ // Clear any ptrace options. When PTRACE_O_TRACEEXIT is set, a plain
+ // PTRACE_KILL (or any termination signal) will not truely terminate the
+ // inferior process. Instead, the process is left in a state of "limbo"
+ // allowing us to interrogate its state. However in this case we really do
+ // want the process gone.
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL, 0UL))
+ {
+ m_result = false;
+ return;
+ }
+
+ // Kill it.
+ if (ptrace(PTRACE_KILL, pid, NULL, NULL))
+ m_result = false;
+ else
+ m_result = true;
+#endif
+}
+
+ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path)
+ : m_monitor(monitor),
+ m_module(module),
+ m_argv(argv),
+ m_envp(envp),
+ m_stdin_path(stdin_path),
+ m_stdout_path(stdout_path),
+ m_stderr_path(stderr_path)
+{
+ sem_init(&m_semaphore, 0, 0);
+}
+
+ProcessMonitor::LaunchArgs::~LaunchArgs()
+{
+ sem_destroy(&m_semaphore);
+}
+
+//------------------------------------------------------------------------------
+/// The basic design of the ProcessMonitor is built around two threads.
+///
+/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
+/// for changes in the debugee state. When a change is detected a
+/// ProcessMessage is sent to the associated ProcessLinux instance. This thread
+/// "drives" state changes in the debugger.
+///
+/// The second thread (@see OperationThread) is responsible for two things 1)
+/// lauching or attaching to the inferior process, and then 2) servicing
+/// operations such as register reads/writes, stepping, etc. See the comments
+/// on the Operation class for more info as to why this is needed.
+ProcessMonitor::ProcessMonitor(ProcessLinux *process,
+ Module *module,
+ const char *argv[],
+ const char *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ lldb_private::Error &error)
+ : m_process(process),
+ m_operation_thread(LLDB_INVALID_HOST_THREAD),
+ m_pid(LLDB_INVALID_PROCESS_ID),
+ m_terminal_fd(-1),
+ m_monitor_handle(0),
+ m_client_fd(-1),
+ m_server_fd(-1)
+{
+ LaunchArgs args(this, module, argv, envp,
+ stdin_path, stdout_path, stderr_path);
+
+ // Server/client descriptors.
+ if (!EnableIPC())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Monitor failed to initialize.");
+ }
+
+ StartOperationThread(&args, error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args.m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the launch was a success.
+ if (!args.m_error.Success())
+ {
+ StopOperationThread();
+ error = args.m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ if (!(m_monitor_handle = Host::StartMonitoringChildProcess(
+ ProcessMonitor::MonitorCallback, this, GetPID(), true)))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process launch failed.");
+ return;
+ }
+}
+
+ProcessMonitor::~ProcessMonitor()
+{
+ Host::StopMonitoringChildProcess(m_monitor_handle);
+ StopOperationThread();
+
+ close(m_terminal_fd);
+ close(m_client_fd);
+ close(m_server_fd);
+}
+
+//------------------------------------------------------------------------------
+// Thread setup and tear down.
+void
+ProcessMonitor::StartOperationThread(LaunchArgs *args, Error &error)
+{
+ static const char *g_thread_name = "lldb.process.linux.operation";
+
+ if (m_operation_thread != LLDB_INVALID_HOST_THREAD)
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, OperationThread, args, &error);
+}
+
+void
+ProcessMonitor::StopOperationThread()
+{
+ lldb::thread_result_t result;
+
+ if (m_operation_thread == LLDB_INVALID_HOST_THREAD)
+ return;
+
+ Host::ThreadCancel(m_operation_thread, NULL);
+ Host::ThreadJoin(m_operation_thread, &result, NULL);
+}
+
+void *
+ProcessMonitor::OperationThread(void *arg)
+{
+ LaunchArgs *args = static_cast<LaunchArgs*>(arg);
+
+ if (!Launch(args))
+ return NULL;
+
+ ServeOperation(args->m_monitor);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Launch(LaunchArgs *args)
+{
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessLinux &process = monitor->GetProcess();
+ const char **argv = args->m_argv;
+ const char **envp = args->m_envp;
+ const char *stdin_path = args->m_stdin_path;
+ const char *stdout_path = args->m_stdout_path;
+ const char *stderr_path = args->m_stderr_path;
+
+ lldb_utility::PseudoTerminal terminal;
+ const size_t err_len = 1024;
+ char err_str[err_len];
+ lldb::pid_t pid;
+
+ lldb::ThreadSP inferior;
+
+ // Pseudo terminal setup.
+ if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len))
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Could not open controlling TTY.");
+ goto FINISH;
+ }
+
+ if ((pid = terminal.Fork(err_str, err_len)) < 0)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Process fork failed.");
+ goto FINISH;
+ }
+
+ // Child process.
+ if (pid == 0)
+ {
+ // Trace this process.
+ ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+
+ // Do not inherit setgid powers.
+ setgid(getgid());
+
+ // Let us have our own process group.
+ setpgid(0, 0);
+
+ // Dup file discriptors if needed.
+ //
+ // FIXME: If two or more of the paths are the same we needlessly open
+ // the same file multiple times.
+ if (stdin_path != NULL && stdin_path[0])
+ if (!DupDescriptor(stdin_path, STDIN_FILENO, O_RDONLY | O_CREAT))
+ exit(1);
+
+ if (stdout_path != NULL && stdout_path[0])
+ if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ exit(1);
+
+ if (stderr_path != NULL && stderr_path[0])
+ if (!DupDescriptor(stderr_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ exit(1);
+
+ // Execute. We should never return.
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ exit(-1);
+ }
+
+ // Wait for the child process to to trap on its call to execve.
+ int status;
+ if ((status = waitpid(pid, NULL, 0)) < 0)
+ {
+ // execve likely failed for some reason.
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ assert(status == pid && "Could not sync with inferior process.");
+
+ // Have the child raise an event on exit. This is used to keep the child in
+ // limbo until it is destroyed.
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ // Release the master terminal descriptor and pass it off to the
+ // ProcessMonitor instance. Similarly stash the inferior pid.
+ monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ monitor->m_pid = pid;
+
+ // Update the process thread list with this new thread and mark it as
+ // current.
+ inferior.reset(new LinuxThread(process, pid));
+ process.GetThreadList().AddThread(inferior);
+ process.GetThreadList().SetCurrentThreadByID(pid);
+
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+
+FINISH:
+ // Sync with our parent thread now that the launch operation is complete.
+ sem_post(&args->m_semaphore);
+ return args->m_error.Success();
+}
+
+bool
+ProcessMonitor::EnableIPC()
+{
+ int fd[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd))
+ return false;
+
+ m_client_fd = fd[0];
+ m_server_fd = fd[1];
+ return true;
+}
+
+bool
+ProcessMonitor::MonitorCallback(void *callback_baton,
+ lldb::pid_t pid,
+ int signal,
+ int status)
+{
+ ProcessMessage message;
+ ProcessMonitor *monitor = static_cast<ProcessMonitor*>(callback_baton);
+ ProcessLinux *process = monitor->m_process;
+
+ switch (signal)
+ {
+ case 0:
+ // No signal. The child has exited normally.
+ message = ProcessMessage::Exit(pid, status);
+ break;
+
+ case SIGTRAP:
+ // Specially handle SIGTRAP and form the appropriate message.
+ message = MonitorSIGTRAP(monitor, pid);
+ break;
+
+ default:
+ // For all other signals simply notify the process instance. Note that
+ // the process exit status is set when the signal resulted in
+ // termination.
+ //
+ // FIXME: We need a specialized message to inform the process instance
+ // about "crashes".
+ if (status)
+ message = ProcessMessage::Exit(pid, status);
+ else
+ message = ProcessMessage::Signal(pid, signal);
+ }
+
+ process->SendMessage(message);
+ bool stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage;
+ return stop_monitoring;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, lldb::pid_t pid)
+{
+ siginfo_t info;
+ ProcessMessage message;
+ bool status;
+
+ status = monitor->GetSignalInfo(pid, &info);
+ assert(status && "GetSignalInfo failed!");
+
+ assert(info.si_signo == SIGTRAP && "Unexpected child signal!");
+
+ switch (info.si_code)
+ {
+ default:
+ assert(false && "Unexpected SIGTRAP code!");
+ break;
+
+ case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
+ {
+ // The inferior process is about to exit. Maintain the process in a
+ // state of "limbo" until we are explicitly commanded to detach,
+ // destroy, resume, etc.
+ unsigned long data = 0;
+ if (!monitor->GetEventMessage(pid, &data))
+ data = -1;
+ message = ProcessMessage::Exit(pid, (data >> 8));
+ break;
+ }
+
+ case 0:
+ case TRAP_TRACE:
+ message = ProcessMessage::Trace(pid);
+ break;
+
+ case SI_KERNEL:
+ case TRAP_BRKPT:
+ message = ProcessMessage::Break(pid);
+ break;
+ }
+
+ return message;
+}
+
+void
+ProcessMonitor::ServeOperation(ProcessMonitor *monitor)
+{
+ int status;
+ pollfd fdset;
+
+ fdset.fd = monitor->m_server_fd;
+ fdset.events = POLLIN | POLLPRI;
+ fdset.revents = 0;
+
+ for (;;)
+ {
+ if ((status = poll(&fdset, 1, -1)) < 0)
+ {
+ switch (errno)
+ {
+ default:
+ assert(false && "Unexpected poll() failure!");
+ continue;
+
+ case EINTR: continue; // Just poll again.
+ case EBADF: return; // Connection terminated.
+ }
+ }
+
+ assert(status == 1 && "Too many descriptors!");
+
+ if (fdset.revents & POLLIN)
+ {
+ Operation *op = NULL;
+
+ READ_AGAIN:
+ if ((status = read(fdset.fd, &op, sizeof(op))) < 0)
+ {
+ // There is only one acceptable failure.
+ assert(errno == EINTR);
+ goto READ_AGAIN;
+ }
+
+ assert(status == sizeof(op));
+ op->Execute(monitor);
+ write(fdset.fd, &op, sizeof(op));
+ }
+ }
+}
+
+void
+ProcessMonitor::DoOperation(Operation *op)
+{
+ int status;
+ Operation *ack = NULL;
+ Mutex::Locker lock(m_server_mutex);
+
+ // FIXME: Do proper error checking here.
+ write(m_client_fd, &op, sizeof(op));
+
+READ_AGAIN:
+ if ((status = read(m_client_fd, &ack, sizeof(ack))) < 0)
+ {
+ // If interrupted by a signal handler try again. Otherwise the monitor
+ // thread probably died and we have a stale file descriptor -- abort the
+ // operation.
+ if (errno == EINTR)
+ goto READ_AGAIN;
+ return;
+ }
+
+ assert(status == sizeof(ack));
+ assert(ack == op && "Invalid monitor thread response!");
+}
+
+size_t
+ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ size_t result;
+ ReadOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+size_t
+ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error)
+{
+ size_t result;
+ WriteOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterValue(unsigned offset, Scalar &value)
+{
+ bool result;
+ ReadRegOperation op(offset, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterValue(unsigned offset, const Scalar &value)
+{
+ bool result;
+ WriteRegOperation op(offset, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::Resume(lldb::tid_t tid)
+{
+ bool result;
+ ResumeOperation op(tid, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::SingleStep(lldb::tid_t tid)
+{
+ bool result;
+ SingleStepOperation op(tid, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::BringProcessIntoLimbo()
+{
+ bool result;
+ KillOperation op(result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetSignalInfo(lldb::tid_t tid, void *siginfo)
+{
+ bool result;
+ SiginfoOperation op(tid, siginfo, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+ bool result;
+ EventMessageOperation op(tid, message, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::DupDescriptor(const char *path, int fd, int flags)
+{
+ int target_fd = open(path, flags);
+
+ if (target_fd == -1)
+ return false;
+
+ return (dup2(fd, target_fd) == -1) ? false : true;
+}
Added: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Fri Jul 23 21:19:04 2010
@@ -0,0 +1,208 @@
+//===-- ProcessMonitor.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_ProcessMonitor_H_
+#define liblldb_ProcessMonitor_H_
+
+// C Includes
+#include <semaphore.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private
+{
+class Error;
+class Module;
+class Scalar;
+} // End lldb_private namespace.
+
+class ProcessLinux;
+class Operation;
+
+/// @class ProcessMonitor
+/// @brief Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process for
+/// debugging.
+///
+/// Changes in the inferior process state are propagated to the associated
+/// ProcessLinux instance by calling ProcessLinux::SendMessage with the
+/// appropriate ProcessMessage events.
+///
+/// A purposely minimal set of operations are provided to interrogate and change
+/// the inferior process state.
+class ProcessMonitor
+{
+public:
+
+ /// Launches an inferior process ready for debugging. Forms the
+ /// implementation of Process::DoLaunch.
+ ProcessMonitor(ProcessLinux *process,
+ lldb_private::Module *module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ lldb_private::Error &error);
+
+ ~ProcessMonitor();
+
+ /// Provides the process number of debugee.
+ lldb::pid_t
+ GetPID() const { return m_pid; }
+
+ /// Returns the process associated with this ProcessMonitor.
+ ProcessLinux &
+ GetProcess() { return *m_process; }
+
+ /// Returns a file descriptor to the controling terminal of the inferior
+ /// process.
+ ///
+ /// Reads from this file descriptor yeild both the standard output and
+ /// standard error of this debugee. Even if stderr and stdout were
+ /// redirected on launch it may still happen that data is available on this
+ /// descriptor (if the inferior process opens /dev/tty, for example).
+ ///
+ /// If this monitor was attached to an existing process this method returns
+ /// -1.
+ int
+ GetTerminalFD() const { return m_terminal_fd; }
+
+ /// Reads @p size bytes from address @vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoReadMemory.
+ size_t
+ ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Writes @p size bytes from address @p vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoWriteMemory.
+ size_t
+ WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Reads the contents from the register identified by the given (architecture
+ /// dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextLinux derivatives.
+ bool
+ ReadRegisterValue(unsigned offset, lldb_private::Scalar &value);
+
+ /// Writes the given value to the register identified by the given
+ /// (architecture dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextLinux derivatives.
+ bool
+ WriteRegisterValue(unsigned offset, const lldb_private::Scalar &value);
+
+ /// Writes a siginfo_t structure corresponding to the given thread ID to the
+ /// memory region pointed to by @p siginfo.
+ bool
+ GetSignalInfo(lldb::tid_t tid, void *siginfo);
+
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread IDto the memory pointed to by @p
+ /// message.
+ bool
+ GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ /// Resumes the given thread.
+ bool
+ Resume(lldb::tid_t tid);
+
+ /// Single steps the given thread.
+ bool
+ SingleStep(lldb::tid_t tid);
+
+ /// Sends the inferior process a PTRACE_KILL signal. The inferior will
+ /// still exists and can be interrogated. Once resumed it will exit as
+ /// though it received a SIGKILL.
+ bool
+ BringProcessIntoLimbo();
+
+private:
+ ProcessLinux *m_process;
+
+ lldb::thread_t m_operation_thread;
+ lldb::pid_t m_pid;
+ int m_terminal_fd;
+
+ uint32_t m_monitor_handle;
+
+ lldb_private::Mutex m_server_mutex;
+ int m_client_fd;
+ int m_server_fd;
+
+ /// @class LauchArgs
+ ///
+ /// @brief Simple structure to pass data to the thread responsible for
+ /// launching a child process.
+ struct LaunchArgs
+ {
+ LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path);
+
+ ~LaunchArgs();
+
+ ProcessMonitor *m_monitor; // The monitor performing the launch.
+ lldb_private::Module *m_module; // The executable image to launch.
+ char const **m_argv; // Process arguments.
+ char const **m_envp; // Process environment.
+ const char *m_stdin_path; // Redirect stdin or NULL.
+ const char *m_stdout_path; // Redirect stdout or NULL.
+ const char *m_stderr_path; // Redirect stderr or NULL.
+ sem_t m_semaphore; // Posted to once launch complete.
+ lldb_private::Error m_error; // Set if process launch failed.
+ };
+
+ void
+ StartOperationThread(LaunchArgs *args, lldb_private::Error &error);
+
+ void
+ StopOperationThread();
+
+ static void *
+ OperationThread(void *arg);
+
+ static bool
+ Launch(LaunchArgs *args);
+
+ bool
+ EnableIPC();
+
+ static void
+ ServeOperation(ProcessMonitor *monitor);
+
+ static bool
+ DupDescriptor(const char *path, int fd, int flags);
+
+ static bool
+ MonitorCallback(void *callback_baton,
+ lldb::pid_t pid, int signal, int status);
+
+ static ProcessMessage
+ MonitorSIGTRAP(ProcessMonitor *monitor, lldb::pid_t pid);
+
+ void
+ DoOperation(Operation *op);
+};
+
+#endif // #ifndef liblldb_ProcessMonitor_H_
Added: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux.h?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux.h Fri Jul 23 21:19:04 2010
@@ -0,0 +1,40 @@
+//===-- RegisterContext_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_RegisterContextLinux_H_
+#define liblldb_RegisterContextLinux_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Target/RegisterContext.h"
+
+//------------------------------------------------------------------------------
+/// @class RegisterContextLinux
+///
+/// @brief Extends RegisterClass with a few virtual operations useful on Linux.
+class RegisterContextLinux
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextLinux(lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame)
+ : RegisterContext(thread, frame) { }
+
+ /// Updates the register state of the associated thread after hitting a
+ /// breakpoint (if that make sense for the architecture). Default
+ /// implementation simply returns true for architectures which do not
+ /// require any upadte.
+ ///
+ /// @return
+ /// True if the operation succeeded and false otherwise.
+ virtual bool UpdateAfterBreakpoint() { return true; }
+};
+
+#endif // #ifndef liblldb_RegisterContextLinux_H_
Added: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp Fri Jul 23 21:19:04 2010
@@ -0,0 +1,653 @@
+//===-- RegisterContextLinux_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 <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Thread.h"
+
+#include "ProcessLinux.h"
+#include "ProcessMonitor.h"
+#include "RegisterContextLinux_x86_64.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// Internal codes for all x86_64 registers.
+enum
+{
+ gpr_rax = 0,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+ gpr_ss,
+ gpr_ds,
+ gpr_es,
+
+ // Number of GPR's.
+ k_num_gpr_registers,
+
+ fpu_fcw = k_num_gpr_registers,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+
+ // Total number of registers.
+ k_num_registers,
+
+ // Number of FPR's.
+ k_num_fpu_registers = k_num_registers - k_num_gpr_registers
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7
+};
+
+enum gdb_regnums
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fcw = 32,
+ gdb_fpu_fsw = 33,
+ gdb_fpu_ftw = 34,
+ gdb_fpu_cs = 35,
+ gdb_fpu_ip = 36,
+ gdb_fpu_ds = 37,
+ gdb_fpu_dp = 38,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56
+};
+
+static const
+uint32_t g_gpr_regnums[k_num_gpr_registers] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+ gpr_ss,
+ gpr_ds,
+ gpr_es
+};
+
+static const uint32_t
+g_fpu_regnums[k_num_fpu_registers] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static const RegisterSet
+g_reg_sets[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }
+};
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(RegisterContextLinux_x86_64::UserArea, regs) + \
+ offsetof(RegisterContextLinux_x86_64::GPR, regname))
+
+// Computes the offset of the given FPR in the user data area.
+#define FPR_OFFSET(regname) \
+ (offsetof(RegisterContextLinux_x86_64::UserArea, i387) + \
+ offsetof(RegisterContextLinux_x86_64::FPU, regname))
+
+// Number of bytes needed to represet a GPR.
+#define GPR_SIZE(reg) sizeof(((RegisterContextLinux_x86_64::GPR*)NULL)->reg)
+
+// Number of bytes needed to represet a FPR.
+#define FPR_SIZE(reg) sizeof(((RegisterContextLinux_x86_64::FPU*)NULL)->reg)
+
+// Number of bytes needed to represet the i'th FP register.
+#define FP_SIZE sizeof(((RegisterContextLinux_x86_64::MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represet an XMM register.
+#define XMM_SIZE sizeof(RegisterContextLinux_x86_64::XMMReg)
+
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, gpr_##reg, { kind1, kind2, kind3, kind4 } }
+
+#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \
+ { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, fpu_##reg, { kind1, kind2, kind3, kind4 } }
+
+#define DEFINE_FP(reg, i) \
+ { #reg#i, NULL, FP_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \
+ eFormatVectorOfUInt8, fpu_##reg##i, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i } }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \
+ eFormatVectorOfUInt8, fpu_##reg##i, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i } }
+
+static RegisterInfo
+g_register_infos[k_num_registers] =
+{
+ // General purpose registers.
+ DEFINE_GPR(rax, NULL, gcc_dwarf_gpr_rax, gcc_dwarf_gpr_rax, LLDB_INVALID_REGNUM, gdb_gpr_rax),
+ DEFINE_GPR(rbx, NULL, gcc_dwarf_gpr_rbx, gcc_dwarf_gpr_rbx, LLDB_INVALID_REGNUM, gdb_gpr_rbx),
+ DEFINE_GPR(rcx, NULL, gcc_dwarf_gpr_rcx, gcc_dwarf_gpr_rcx, LLDB_INVALID_REGNUM, gdb_gpr_rcx),
+ DEFINE_GPR(rdx, NULL, gcc_dwarf_gpr_rdx, gcc_dwarf_gpr_rdx, LLDB_INVALID_REGNUM, gdb_gpr_rdx),
+ DEFINE_GPR(rdi, NULL, gcc_dwarf_gpr_rdi, gcc_dwarf_gpr_rdi, LLDB_INVALID_REGNUM, gdb_gpr_rdi),
+ DEFINE_GPR(rsi, NULL, gcc_dwarf_gpr_rsi, gcc_dwarf_gpr_rsi, LLDB_INVALID_REGNUM, gdb_gpr_rsi),
+ DEFINE_GPR(rbp, "fp", gcc_dwarf_gpr_rbp, gcc_dwarf_gpr_rbp, LLDB_REGNUM_GENERIC_FP, gdb_gpr_rbp),
+ DEFINE_GPR(rsp, "sp", gcc_dwarf_gpr_rsp, gcc_dwarf_gpr_rsp, LLDB_REGNUM_GENERIC_SP, gdb_gpr_rsp),
+ DEFINE_GPR(r8, NULL, gcc_dwarf_gpr_r8, gcc_dwarf_gpr_r8, LLDB_INVALID_REGNUM, gdb_gpr_r8),
+ DEFINE_GPR(r9, NULL, gcc_dwarf_gpr_r9, gcc_dwarf_gpr_r9, LLDB_INVALID_REGNUM, gdb_gpr_r9),
+ DEFINE_GPR(r10, NULL, gcc_dwarf_gpr_r10, gcc_dwarf_gpr_r10, LLDB_INVALID_REGNUM, gdb_gpr_r10),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_gpr_r11, gcc_dwarf_gpr_r11, LLDB_INVALID_REGNUM, gdb_gpr_r11),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_gpr_r12, gcc_dwarf_gpr_r12, LLDB_INVALID_REGNUM, gdb_gpr_r12),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_gpr_r13, gcc_dwarf_gpr_r13, LLDB_INVALID_REGNUM, gdb_gpr_r13),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_gpr_r14, gcc_dwarf_gpr_r14, LLDB_INVALID_REGNUM, gdb_gpr_r14),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_gpr_r15, gcc_dwarf_gpr_r15, LLDB_INVALID_REGNUM, gdb_gpr_r15),
+ DEFINE_GPR(rip, "pc", gcc_dwarf_gpr_rip, gcc_dwarf_gpr_rip, LLDB_REGNUM_GENERIC_PC, gdb_gpr_rip),
+ DEFINE_GPR(rflags, "flags", LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags),
+ DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_cs),
+ DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_fs),
+ DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_gs),
+ DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ss),
+ DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ds),
+ DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_es),
+
+ // i387 Floating point registers.
+ DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fcw),
+ DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fsw),
+ DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ftw),
+ DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fop),
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ip),
+ // FIXME: Extract segment from ip.
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs),
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_dp),
+ // FIXME: Extract segment from dp.
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds),
+ DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_mxcsr),
+ DEFINE_FPR(mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ // FP registers.
+ DEFINE_FP(stmm, 0),
+ DEFINE_FP(stmm, 1),
+ DEFINE_FP(stmm, 2),
+ DEFINE_FP(stmm, 3),
+ DEFINE_FP(stmm, 4),
+ DEFINE_FP(stmm, 5),
+ DEFINE_FP(stmm, 6),
+ DEFINE_FP(stmm, 7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+ DEFINE_XMM(xmm, 8),
+ DEFINE_XMM(xmm, 9),
+ DEFINE_XMM(xmm, 10),
+ DEFINE_XMM(xmm, 11),
+ DEFINE_XMM(xmm, 12),
+ DEFINE_XMM(xmm, 13),
+ DEFINE_XMM(xmm, 14),
+ DEFINE_XMM(xmm, 15)
+};
+
+static unsigned GetRegOffset(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return g_register_infos[reg].byte_offset;
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(Thread &thread,
+ StackFrame *frame)
+ : RegisterContextLinux(thread, frame)
+{
+}
+
+RegisterContextLinux_x86_64::~RegisterContextLinux_x86_64()
+{
+}
+
+ProcessMonitor &
+RegisterContextLinux_x86_64::GetMonitor()
+{
+ ProcessLinux *process = static_cast<ProcessLinux*>(CalculateProcess());
+ return process->GetMonitor();
+}
+
+void
+RegisterContextLinux_x86_64::Invalidate()
+{
+}
+
+size_t
+RegisterContextLinux_x86_64::GetRegisterCount()
+{
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextLinux_x86_64::GetRegisterInfoAtIndex(uint32_t reg)
+{
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextLinux_x86_64::GetRegisterSetCount()
+{
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+RegisterContextLinux_x86_64::GetRegisterSet(uint32_t set)
+{
+ if (set < k_num_register_sets)
+ return &g_reg_sets[set];
+ else
+ return NULL;
+}
+
+bool
+RegisterContextLinux_x86_64::ReadRegisterValue(uint32_t reg,
+ Scalar &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(GetRegOffset(reg), value);
+}
+
+bool
+RegisterContextLinux_x86_64::ReadRegisterBytes(uint32_t reg,
+ DataExtractor &data)
+{
+ return false;
+}
+
+bool
+RegisterContextLinux_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextLinux_x86_64::WriteRegisterValue(uint32_t reg,
+ const Scalar &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(GetRegOffset(reg), value);
+}
+
+bool
+RegisterContextLinux_x86_64::WriteRegisterBytes(uint32_t reg,
+ DataExtractor &data,
+ uint32_t data_offset)
+{
+ return false;
+}
+
+bool
+RegisterContextLinux_x86_64::WriteAllRegisterValues(const DataBufferSP &data)
+{
+ return false;
+}
+
+bool
+RegisterContextLinux_x86_64::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+uint32_t
+RegisterContextLinux_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+ uint32_t num)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_ss;
+ case gdb_gpr_ds : return gpr_ds;
+ case gdb_gpr_es : return gpr_es;
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fcw : return fpu_fcw;
+ case gdb_fpu_fsw : return fpu_fsw;
+ case gdb_fpu_ftw : return fpu_ftw;
+ case gdb_fpu_cs : return fpu_cs;
+ case gdb_fpu_ip : return fpu_ip;
+ case gdb_fpu_ds : return fpu_ds;
+ case gdb_fpu_dp : return fpu_dp;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextLinux_x86_64::HardwareSingleStep(bool enable)
+{
+ return GetMonitor().SingleStep(GetThreadID());
+}
Added: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h?rev=109318&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h Fri Jul 23 21:19:04 2010
@@ -0,0 +1,155 @@
+//===-- RegisterContextLinux_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_RegisterContextLinux_x86_64_H_
+#define liblldb_RegisterContextLinux_x86_64_H_
+
+#include "RegisterContextLinux.h"
+
+class ProcessMonitor;
+
+class RegisterContextLinux_x86_64
+ : public RegisterContextLinux
+{
+public:
+ RegisterContextLinux_x86_64(lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame);
+
+ ~RegisterContextLinux_x86_64();
+
+ void
+ Invalidate();
+
+ size_t
+ GetRegisterCount();
+
+ const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex(uint32_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb::RegisterSet *
+ GetRegisterSet(uint32_t set);
+
+ bool
+ ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value);
+
+ bool
+ ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value);
+
+ bool
+ WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data,
+ uint32_t data_offset = 0);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+ struct GPR
+ {
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t orig_ax;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+ uint64_t fs_base;
+ uint64_t gs_base;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint16_t ftw;
+ uint16_t fop;
+ uint64_t ip;
+ uint64_t dp;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint32_t padding[24];
+ };
+
+ struct UserArea
+ {
+ GPR regs; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ int32_t pad0;
+ FPU i387; // FPU registers.
+ uint64_t tsize; // Text segment size.
+ uint64_t dsize; // Data segment size.
+ uint64_t ssize; // Stack segement size.
+ uint64_t start_code; // VM address of text.
+ uint64_t start_stack; // VM address of stack bottom (top in rsp).
+ int64_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ int32_t pad1;
+ uint64_t ar0; // Location of GPR's.
+ FPU* fpstate; // Location of FPR's.
+ uint64_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint64_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ uint64_t error_code; // CPU error code.
+ uint64_t fault_address; // Control register CR3.
+ };
+
+private:
+ UserArea user;
+
+ ProcessMonitor &GetMonitor();
+};
+
+#endif // #ifndef liblldb_RegisterContextLinux_x86_64_H_
Modified: lldb/trunk/source/lldb.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=109318&r1=109317&r2=109318&view=diff
==============================================================================
--- lldb/trunk/source/lldb.cpp (original)
+++ lldb/trunk/source/lldb.cpp Fri Jul 23 21:19:04 2010
@@ -22,6 +22,7 @@
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+
#ifdef __APPLE__
#include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h"
#include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h"
@@ -32,6 +33,10 @@
#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
#endif
+#ifdef __linux__
+#include "Plugins/Process/Linux/ProcessLinux.h"
+#endif
+
using namespace lldb_private;
@@ -55,10 +60,10 @@
DisassemblerLLVM::Initialize();
ObjectContainerBSDArchive::Initialize();
ObjectFileELF::Initialize();
- SymbolVendorMacOSX::Initialize();
SymbolFileDWARF::Initialize();
SymbolFileDWARFDebugMap::Initialize();
SymbolFileSymtab::Initialize();
+
#ifdef __APPLE__
ABIMacOSX_i386::Initialize();
ABISysV_x86_64::Initialize();
@@ -66,7 +71,12 @@
ObjectContainerUniversalMachO::Initialize();
ObjectFileMachO::Initialize();
ProcessGDBRemote::Initialize();
-// ProcessMacOSX::Initialize();
+ ProcessMacOSX::Initialize();
+ SymbolVendorMacOSX::Initialize();
+#endif
+
+#ifdef __linux__
+ ProcessLinux::Initialize();
#endif
}
}
@@ -84,16 +94,21 @@
DisassemblerLLVM::Terminate();
ObjectContainerBSDArchive::Terminate();
ObjectFileELF::Terminate();
- SymbolVendorMacOSX::Terminate();
SymbolFileDWARF::Terminate();
SymbolFileDWARFDebugMap::Terminate();
SymbolFileSymtab::Terminate();
+
#ifdef __APPLE__
DynamicLoaderMacOSXDYLD::Terminate();
ObjectContainerUniversalMachO::Terminate();
ObjectFileMachO::Terminate();
ProcessGDBRemote::Terminate();
-// ProcessMacOSX::Terminate();
+ ProcessMacOSX::Terminate();
+ SymbolVendorMacOSX::Terminate();
+#endif
+
+#ifdef __linux__
+ ProcessLinux::Terminate();
#endif
}
More information about the lldb-commits
mailing list