[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