[Lldb-commits] [lldb] r212069 - Add lldb-gdbserver support for Linux x86_64.
Todd Fiala
todd.fiala at gmail.com
Mon Jun 30 14:05:19 PDT 2014
Author: tfiala
Date: Mon Jun 30 16:05:18 2014
New Revision: 212069
URL: http://llvm.org/viewvc/llvm-project?rev=212069&view=rev
Log:
Add lldb-gdbserver support for Linux x86_64.
This change brings in lldb-gdbserver (llgs) specifically for Linux x86_64.
(More architectures coming soon).
Not every debugserver option is covered yet. Currently
the lldb-gdbserver command line can start unattached,
start attached to a pid (process-name attach not supported yet),
or accept lldb attaching and launching a process or connecting
by process id.
The history of this large change can be found here:
https://github.com/tfiala/lldb/tree/dev-tfiala-native-protocol-linux-x86_64
Until mid/late April, I was not sharing the work and continued
to rebase it off of head (developed via id tfiala at google.com). I switched over to
user todd.fiala at gmail.com in the middle, and once I went to github, I did
merges rather than rebasing so I could share with others.
Added:
lldb/trunk/include/lldb/Target/NativeRegisterContext.h
lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h
lldb/trunk/include/lldb/lldb-private-forward.h
lldb/trunk/source/Host/common/NativeBreakpoint.cpp
lldb/trunk/source/Host/common/NativeBreakpoint.h
lldb/trunk/source/Host/common/NativeBreakpointList.cpp
lldb/trunk/source/Host/common/NativeBreakpointList.h
lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
lldb/trunk/source/Host/common/NativeProcessProtocol.h
lldb/trunk/source/Host/common/NativeThreadProtocol.cpp
lldb/trunk/source/Host/common/NativeThreadProtocol.h
lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp
lldb/trunk/source/Host/common/SoftwareBreakpoint.h
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp
lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h
lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp
lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h
lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h
lldb/trunk/source/Target/NativeRegisterContext.cpp
lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp
Removed:
lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp
lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h
Modified:
lldb/trunk/.gitignore
lldb/trunk/docs/lldb-gdb-remote.txt
lldb/trunk/include/lldb/Core/UserID.h
lldb/trunk/include/lldb/Host/Debug.h
lldb/trunk/include/lldb/Host/Host.h
lldb/trunk/include/lldb/Target/MemoryRegionInfo.h
lldb/trunk/include/lldb/Target/Platform.h
lldb/trunk/include/lldb/Target/Process.h
lldb/trunk/include/lldb/lldb-enumerations.h
lldb/trunk/include/lldb/lldb-private-enumerations.h
lldb/trunk/lldb.xcodeproj/project.pbxproj
lldb/trunk/source/Core/ModuleList.cpp
lldb/trunk/source/Expression/IRMemoryMap.cpp
lldb/trunk/source/Host/common/CMakeLists.txt
lldb/trunk/source/Host/linux/Host.cpp
lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp
lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h
lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt
lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt
lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h
lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
lldb/trunk/source/Target/CMakeLists.txt
lldb/trunk/source/Target/Platform.cpp
lldb/trunk/source/Target/Process.cpp
lldb/trunk/source/Utility/StringExtractor.cpp
lldb/trunk/source/Utility/StringExtractor.h
lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
lldb/trunk/source/Utility/StringExtractorGDBRemote.h
lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py
lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py
lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py
lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py
lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py
lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py
lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
lldb/trunk/test/tools/lldb-gdbserver/main.cpp
lldb/trunk/tools/debugserver/source/RNBRemote.cpp
lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp
lldb/trunk/tools/lldb-platform/lldb-platform.cpp
Modified: lldb/trunk/.gitignore
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/.gitignore?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/.gitignore (original)
+++ lldb/trunk/.gitignore Mon Jun 30 16:05:18 2014
@@ -25,3 +25,6 @@ build/
llvm-build/
*xcuserdata
test/20*
+
+# We should ignore Xcode-style embedding of llvm/ at lldb root dir.
+/llvm/
Modified: lldb/trunk/docs/lldb-gdb-remote.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/docs/lldb-gdb-remote.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/docs/lldb-gdb-remote.txt (original)
+++ lldb/trunk/docs/lldb-gdb-remote.txt Mon Jun 30 16:05:18 2014
@@ -207,7 +207,7 @@ With LLDB, for register information, rem
support for the "qRegisterInfoN" packet where "N" is a zero based
base16 register number that must start at zero and increase by one
for each register that is supported. The response is done in typical
-GDB remote fashion where a serious of "KEY:VALUE;" pairs are returned.
+GDB remote fashion where a series of "KEY:VALUE;" pairs are returned.
An example for the x86_64 registers is included below:
send packet: $qRegisterInfo0#00
Modified: lldb/trunk/include/lldb/Core/UserID.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/UserID.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/UserID.h (original)
+++ lldb/trunk/include/lldb/Core/UserID.h Mon Jun 30 16:05:18 2014
@@ -19,12 +19,12 @@ namespace lldb_private {
/// @class UserID UserID.h "lldb/Core/UserID.h"
/// @brief A mix in class that contains a generic user ID.
///
-/// UserID is desinged as a mix in class that can contain an integer
-/// based unique identifier for a varietly of objects in lldb.
+/// UserID is designed as a mix in class that can contain an integer
+/// based unique identifier for a variety of objects in lldb.
///
/// The value for this identifier is chosen by each parser plug-in. A
/// value should be chosen that makes sense for each kind of object
-/// should and allows quick access to further and more in depth parsing.
+/// and should allow quick access to further and more in depth parsing.
///
/// Symbol table entries can use this to store the original symbol table
/// index, functions can use it to store the symbol table index or the
Modified: lldb/trunk/include/lldb/Host/Debug.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Debug.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Debug.h (original)
+++ lldb/trunk/include/lldb/Host/Debug.h Mon Jun 30 16:05:18 2014
@@ -10,14 +10,11 @@
#ifndef liblldb_Debug_h_
#define liblldb_Debug_h_
-#include "lldb/lldb-private.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/Mutex.h"
#include <vector>
+#include "lldb/lldb-private.h"
namespace lldb_private {
-
+
//------------------------------------------------------------------
// Tells a thread what it needs to do when the process is resumed.
//------------------------------------------------------------------
@@ -27,7 +24,7 @@ namespace lldb_private {
lldb::StateType state; // Valid values are eStateStopped/eStateSuspended, eStateRunning, and eStateStepping.
int signal; // When resuming this thread, resume it with this signal if this value is > 0
};
-
+
//------------------------------------------------------------------
// A class that contains instructions for all threads for
// NativeProcessProtocol::Resume(). Each thread can either run, stay
@@ -43,15 +40,14 @@ namespace lldb_private {
m_signal_handled ()
{
}
-
+
ResumeActionList (lldb::StateType default_action, int signal) :
m_actions(),
m_signal_handled ()
{
SetDefaultThreadActionIfNeeded (default_action, signal);
}
-
-
+
ResumeActionList (const ResumeAction *actions, size_t num_actions) :
m_actions (),
m_signal_handled ()
@@ -62,7 +58,7 @@ namespace lldb_private {
m_signal_handled.assign (num_actions, false);
}
}
-
+
~ResumeActionList()
{
}
@@ -72,14 +68,14 @@ namespace lldb_private {
{
return m_actions.empty();
}
-
+
void
Append (const ResumeAction &action)
{
m_actions.push_back (action);
m_signal_handled.push_back (false);
}
-
+
void
AppendAction (lldb::tid_t tid,
lldb::StateType state,
@@ -88,25 +84,25 @@ namespace lldb_private {
ResumeAction action = { tid, state, signal };
Append (action);
}
-
+
void
AppendResumeAll ()
{
AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateRunning);
}
-
+
void
AppendSuspendAll ()
{
AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStopped);
}
-
+
void
AppendStepAll ()
{
AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStepping);
}
-
+
const ResumeAction *
GetActionForThread (lldb::tid_t tid, bool default_ok) const
{
@@ -120,7 +116,7 @@ namespace lldb_private {
return GetActionForThread (LLDB_INVALID_THREAD_ID, false);
return NULL;
}
-
+
size_t
NumActionsWithState (lldb::StateType state) const
{
@@ -133,7 +129,7 @@ namespace lldb_private {
}
return count;
}
-
+
bool
SetDefaultThreadActionIfNeeded (lldb::StateType action, int signal)
{
@@ -147,7 +143,7 @@ namespace lldb_private {
}
return false;
}
-
+
void
SetSignalHandledForThread (lldb::tid_t tid) const
{
@@ -161,26 +157,26 @@ namespace lldb_private {
}
}
}
-
+
const ResumeAction *
GetFirst() const
{
return m_actions.data();
}
-
+
size_t
GetSize () const
{
return m_actions.size();
}
-
+
void
Clear()
{
m_actions.clear();
m_signal_handled.clear();
}
-
+
protected:
std::vector<ResumeAction> m_actions;
mutable std::vector<bool> m_signal_handled;
@@ -191,13 +187,13 @@ namespace lldb_private {
lldb::StopReason reason;
union
{
- // eStopTypeSignal
+ // eStopReasonSignal
struct
{
uint32_t signo;
} signal;
-
- // eStopTypeException
+
+ // eStopReasonException
struct
{
uint64_t type;
@@ -206,201 +202,5 @@ namespace lldb_private {
} exception;
} details;
};
-
- //------------------------------------------------------------------
- // NativeThreadProtocol
- //------------------------------------------------------------------
- class NativeThreadProtocol {
-
- public:
- NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) :
- m_process (process),
- m_tid (tid)
- {
- }
-
- virtual ~NativeThreadProtocol()
- {
- }
- virtual const char *GetName() = 0;
- virtual lldb::StateType GetState () = 0;
- virtual Error ReadRegister (uint32_t reg, RegisterValue ®_value) = 0;
- virtual Error WriteRegister (uint32_t reg, const RegisterValue ®_value) = 0;
- virtual Error SaveAllRegisters (lldb::DataBufferSP &data_sp) = 0;
- virtual Error RestoreAllRegisters (lldb::DataBufferSP &data_sp) = 0;
- virtual bool GetStopReason (ThreadStopInfo &stop_info) = 0;
-
- lldb::tid_t
- GetID() const
- {
- return m_tid;
- }
- protected:
- NativeProcessProtocol *m_process;
- lldb::tid_t m_tid;
- };
-
-
- //------------------------------------------------------------------
- // NativeProcessProtocol
- //------------------------------------------------------------------
- class NativeProcessProtocol {
- public:
-
- static NativeProcessProtocol *
- CreateInstance (lldb::pid_t pid);
-
- // lldb_private::Host calls should be used to launch a process for debugging, and
- // then the process should be attached to. When attaching to a process
- // lldb_private::Host calls should be used to locate the process to attach to,
- // and then this function should be called.
- NativeProcessProtocol (lldb::pid_t pid) :
- m_pid (pid),
- m_threads(),
- m_threads_mutex (Mutex::eMutexTypeRecursive),
- m_state (lldb::eStateInvalid),
- m_exit_status(0),
- m_exit_description()
- {
- }
-
- public:
- virtual ~NativeProcessProtocol ()
- {
- }
-
- virtual Error Resume (const ResumeActionList &resume_actions) = 0;
- virtual Error Halt () = 0;
- virtual Error Detach () = 0;
- virtual Error Signal (int signo) = 0;
- virtual Error Kill () = 0;
-
- virtual Error ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0;
- virtual Error WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
- virtual Error AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
- virtual Error DeallocateMemory (lldb::addr_t addr) = 0;
-
- virtual lldb::addr_t GetSharedLibraryInfoAddress () = 0;
-
- virtual bool IsAlive () = 0;
- virtual size_t UpdateThreads () = 0;
- virtual bool GetArchitecture (ArchSpec &arch) = 0;
-
- //----------------------------------------------------------------------
- // Breakpoint functions
- //----------------------------------------------------------------------
- virtual Error SetBreakpoint (lldb::addr_t addr, size_t size, bool hardware) = 0;
- virtual Error RemoveBreakpoint (lldb::addr_t addr, size_t size) = 0;
-
- //----------------------------------------------------------------------
- // Watchpoint functions
- //----------------------------------------------------------------------
- virtual uint32_t GetMaxWatchpoints () = 0;
- virtual Error SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0;
- virtual Error RemoveWatchpoint (lldb::addr_t addr) = 0;
-
-
- //----------------------------------------------------------------------
- // Accessors
- //----------------------------------------------------------------------
- lldb::pid_t
- GetID() const
- {
- return m_pid;
- }
-
- lldb::StateType
- GetState () const
- {
- return m_state;
- }
-
- bool
- IsRunning () const
- {
- return m_state == lldb::eStateRunning || IsStepping();
- }
-
- bool
- IsStepping () const
- {
- return m_state == lldb::eStateStepping;
- }
-
- bool
- CanResume () const
- {
- return m_state == lldb::eStateStopped;
- }
-
-
- void
- SetState (lldb::StateType state)
- {
- m_state = state;
- }
-
- //----------------------------------------------------------------------
- // Exit Status
- //----------------------------------------------------------------------
- virtual bool
- GetExitStatus (int *status)
- {
- if (m_state == lldb::eStateExited)
- {
- *status = m_exit_status;
- return true;
- }
- *status = 0;
- return false;
- }
- virtual bool
- SetExitStatus (int status, const char *exit_description)
- {
- // Exit status already set
- if (m_state == lldb::eStateExited)
- return false;
- m_state = lldb::eStateExited;
- m_exit_status = status;
- if (exit_description && exit_description[0])
- m_exit_description = exit_description;
- else
- m_exit_description.clear();
- return true;
- }
-
- //----------------------------------------------------------------------
- // Access to threads
- //----------------------------------------------------------------------
- lldb::NativeThreadProtocolSP
- GetThreadAtIndex (uint32_t idx)
- {
- Mutex::Locker locker(m_threads_mutex);
- if (idx < m_threads.size())
- return m_threads[idx];
- return lldb::NativeThreadProtocolSP();
- }
-
- lldb::NativeThreadProtocolSP
- GetThreadByID (lldb::tid_t tid)
- {
- Mutex::Locker locker(m_threads_mutex);
- for (auto thread_sp : m_threads)
- {
- if (thread_sp->GetID() == tid)
- return thread_sp;
- }
- return lldb::NativeThreadProtocolSP();
- }
-
- protected:
- lldb::pid_t m_pid;
- std::vector<lldb::NativeThreadProtocolSP> m_threads;
- mutable Mutex m_threads_mutex;
- lldb::StateType m_state;
- int m_exit_status;
- std::string m_exit_description;
- };
-
}
#endif // #ifndef liblldb_Debug_h_
Modified: lldb/trunk/include/lldb/Host/Host.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Host.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Host.h (original)
+++ lldb/trunk/include/lldb/Host/Host.h Mon Jun 30 16:05:18 2014
@@ -503,6 +503,9 @@ public:
static lldb::DataBufferSP
GetAuxvData (lldb_private::Process *process);
+ static lldb::DataBufferSP
+ GetAuxvData (lldb::pid_t pid);
+
static lldb::TargetSP
GetDummyTarget (Debugger &debugger);
Modified: lldb/trunk/include/lldb/Target/MemoryRegionInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/MemoryRegionInfo.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/MemoryRegionInfo.h (original)
+++ lldb/trunk/include/lldb/Target/MemoryRegionInfo.h Mon Jun 30 16:05:18 2014
@@ -10,6 +10,7 @@
#ifndef lldb_MemoryRegionInfo_h
#define lldb_MemoryRegionInfo_h
+#include "lldb/Core/RangeMap.h"
#include "lldb/Utility/Range.h"
namespace lldb_private
Added: lldb/trunk/include/lldb/Target/NativeRegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/NativeRegisterContext.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/NativeRegisterContext.h (added)
+++ lldb/trunk/include/lldb/Target/NativeRegisterContext.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,190 @@
+//===-- NativeRegisterContext.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_NativeRegisterContext_h_
+#define liblldb_NativeRegisterContext_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class NativeThreadProtocol;
+
+class NativeRegisterContext:
+ public std::enable_shared_from_this<NativeRegisterContext>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~NativeRegisterContext ();
+
+ // void
+ // InvalidateIfNeeded (bool force);
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ // virtual void
+ // InvalidateAllRegisters () = 0;
+
+ virtual uint32_t
+ GetRegisterCount () const = 0;
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg) const = 0;
+
+ const char *
+ GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const;
+
+ virtual uint32_t
+ GetRegisterSetCount () const = 0;
+
+ virtual const RegisterSet *
+ GetRegisterSet (uint32_t set_index) const = 0;
+
+ virtual Error
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) = 0;
+
+ virtual Error
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) = 0;
+
+ virtual Error
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0;
+
+ virtual Error
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0;
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, lldb::addr_t src_len, RegisterValue ®_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, lldb::addr_t dst_len, const RegisterValue ®_value);
+
+ //------------------------------------------------------------------
+ // Subclasses should not override these
+ //------------------------------------------------------------------
+ virtual lldb::tid_t
+ GetThreadID() const;
+
+ virtual NativeThreadProtocol &
+ GetThread ()
+ {
+ return m_thread;
+ }
+
+ const RegisterInfo *
+ GetRegisterInfoByName (const char *reg_name, uint32_t start_idx = 0);
+
+ const RegisterInfo *
+ GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num);
+
+ lldb::addr_t
+ GetPC (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ Error
+ SetPC (lldb::addr_t pc);
+
+ lldb::addr_t
+ GetSP (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ Error
+ SetSP (lldb::addr_t sp);
+
+ lldb::addr_t
+ GetFP (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ Error
+ SetFP (lldb::addr_t fp);
+
+ const char *
+ GetRegisterName (uint32_t reg);
+
+ lldb::addr_t
+ GetReturnAddress (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ lldb::addr_t
+ GetFlags (lldb::addr_t fail_value = 0);
+
+ lldb::addr_t
+ ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value);
+
+ lldb::addr_t
+ ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value);
+
+ Error
+ WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval);
+
+ Error
+ WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval);
+
+ // uint32_t
+ // GetStopID () const
+ // {
+ // return m_stop_id;
+ // }
+
+ // void
+ // SetStopID (uint32_t stop_id)
+ // {
+ // m_stop_id = stop_id;
+ // }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from RegisterContext can see and modify these
+ //------------------------------------------------------------------
+ NativeThreadProtocol &m_thread; // The thread that this register context belongs to.
+ uint32_t m_concrete_frame_idx; // The concrete frame index for this register context
+ // uint32_t m_stop_id; // The stop ID that any data in this context is valid for
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (NativeRegisterContext);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_NativeRegisterContext_h_
Added: lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h (added)
+++ lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContextRegisterInfo.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextRegisterInfo_h
+#define lldb_NativeRegisterContextRegisterInfo_h
+
+#include <memory>
+
+#include "NativeRegisterContext.h"
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+
+namespace lldb_private
+{
+ class NativeRegisterContextRegisterInfo: public NativeRegisterContext
+ {
+ public:
+ ///
+ /// Construct a NativeRegisterContextRegisterInfo, taking ownership
+ /// of the register_info_interface pointer.
+ ///
+ NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info_interface);
+
+ uint32_t
+ GetRegisterCount () const override;
+
+ const RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg_index) const override;
+
+ const RegisterInfoInterface&
+ GetRegisterInfoInterface () const;
+
+ private:
+ std::unique_ptr<RegisterInfoInterface> m_register_info_interface_up;
+ };
+}
+#endif
Modified: lldb/trunk/include/lldb/Target/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Platform.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Platform.h (original)
+++ lldb/trunk/include/lldb/Target/Platform.h Mon Jun 30 16:05:18 2014
@@ -18,6 +18,7 @@
// Other libraries and framework includes
// Project includes
+#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-public.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ConstString.h"
@@ -25,6 +26,10 @@
#include "lldb/Interpreter/Options.h"
#include "lldb/Host/Mutex.h"
+// TODO pull NativeDelegate class out of NativeProcessProtocol so we
+// can just forward ref the NativeDelegate rather than include it here.
+#include "../../../source/Host/common/NativeProcessProtocol.h"
+
namespace lldb_private {
//----------------------------------------------------------------------
@@ -858,6 +863,65 @@ namespace lldb_private {
virtual const std::vector<ConstString> &
GetTrapHandlerSymbolNames ();
+ //------------------------------------------------------------------
+ /// Launch a process for debugging.
+ ///
+ /// This differs from Launch in that it returns a NativeProcessProtocol.
+ /// Currently used by lldb-gdbserver.
+ ///
+ /// @param[in] launch_info
+ /// Information required to launch the process.
+ ///
+ /// @param[in] native_delegate
+ /// The delegate that will receive messages regarding the
+ /// inferior. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @param[out] process_sp
+ /// On successful return from the method, this parameter
+ /// contains the shared pointer to the
+ /// NativeProcessProtocol that can be used to manipulate
+ /// the native process.
+ ///
+ /// @return
+ /// An error object indicating if the operation succeeded,
+ /// and if not, what error occurred.
+ //------------------------------------------------------------------
+ virtual Error
+ LaunchNativeProcess (
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp);
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process on the given platform.
+ ///
+ /// This method differs from Attach() in that it returns a
+ /// NativeProcessProtocol. Currently this is used by lldb-gdbserver.
+ ///
+ /// @param[in] pid
+ /// pid of the process locatable by the platform.
+ ///
+ /// @param[in] native_delegate
+ /// The delegate that will receive messages regarding the
+ /// inferior. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @param[out] process_sp
+ /// On successful return from the method, this parameter
+ /// contains the shared pointer to the
+ /// NativeProcessProtocol that can be used to manipulate
+ /// the native process.
+ ///
+ /// @return
+ /// An error object indicating if the operation succeeded,
+ /// and if not, what error occurred.
+ //------------------------------------------------------------------
+ virtual Error
+ AttachNativeProcess (lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp);
+
protected:
bool m_is_host;
// Set to true when we are able to actually set the OS version while
Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Mon Jun 30 16:05:18 2014
@@ -1097,6 +1097,17 @@ public:
virtual DynamicLoader *
GetDynamicLoader ();
+ //------------------------------------------------------------------
+ // Returns AUXV structure found in many ELF-based environments.
+ //
+ // The default action is to return an empty data buffer.
+ //
+ // @return
+ // A data buffer containing the contents of the AUXV data.
+ //------------------------------------------------------------------
+ virtual const lldb::DataBufferSP
+ GetAuxvData();
+
protected:
virtual JITLoaderList &
GetJITLoaders ();
Modified: lldb/trunk/include/lldb/lldb-enumerations.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-enumerations.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-enumerations.h (original)
+++ lldb/trunk/include/lldb/lldb-enumerations.h Mon Jun 30 16:05:18 2014
@@ -788,6 +788,27 @@ namespace lldb {
} ExpressionEvaluationPhase;
+ //----------------------------------------------------------------------
+ // Watchpoint Kind
+ // Indicates what types of events cause the watchpoint to fire.
+ // Used by Native*Protocol-related classes.
+ //----------------------------------------------------------------------
+ typedef enum WatchpointKind
+ {
+ eWatchpointKindRead = (1u << 0),
+ eWatchpointKindWrite = (1u << 1)
+ } WatchpointKind;
+
+ typedef enum GdbSignal
+ {
+ eGdbSignalBadAccess = 0x91,
+ eGdbSignalBadInstruction = 0x92,
+ eGdbSignalArithmetic = 0x93,
+ eGdbSignalEmulation = 0x94,
+ eGdbSignalSoftware = 0x95,
+ eGdbSignalBreakpoint = 0x96
+ } GdbRemoteSignal;
+
} // namespace lldb
Modified: lldb/trunk/include/lldb/lldb-private-enumerations.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-enumerations.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-enumerations.h (original)
+++ lldb/trunk/include/lldb/lldb-private-enumerations.h Mon Jun 30 16:05:18 2014
@@ -246,6 +246,16 @@ enum class LineStatus {
Done // Lines are complete
};
+//----------------------------------------------------------------------
+// Exit Type for inferior processes
+//----------------------------------------------------------------------
+typedef enum ExitType {
+ eExitTypeInvalid,
+ eExitTypeExit, // The exit status represents the return code from normal program exit (i.e. WIFEXITED() was true)
+ eExitTypeSignal, // The exit status represents the signal number that caused the program to exit (i.e. WIFSIGNALED() was true)
+ eExitTypeStop, // The exit status represents the stop signal that caused the program to exit (i.e. WIFSTOPPED() was true)
+} ExitType;
+
} // namespace lldb_private
Added: lldb/trunk/include/lldb/lldb-private-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-forward.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-forward.h (added)
+++ lldb/trunk/include/lldb/lldb-private-forward.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,39 @@
+//===-- lldb-private-forward.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_private_forward_h_
+#define LLDB_lldb_private_forward_h_
+
+#if defined(__cplusplus)
+
+#include <memory>
+
+namespace lldb_private
+{
+ // ---------------------------------------------------------------
+ // Class forward decls.
+ // ---------------------------------------------------------------
+ class NativeBreakpoint;
+ class NativeBreakpointList;
+ class NativeProcessProtocol;
+ class NativeRegisterContext;
+ class NativeThreadProtocol;
+
+ // ---------------------------------------------------------------
+ // SP/WP decls.
+ // ---------------------------------------------------------------
+ typedef std::shared_ptr<NativeBreakpoint> NativeBreakpointSP;
+ typedef std::shared_ptr<lldb_private::NativeProcessProtocol> NativeProcessProtocolSP;
+ typedef std::weak_ptr<lldb_private::NativeProcessProtocol> NativeProcessProtocolWP;
+ typedef std::shared_ptr<lldb_private::NativeRegisterContext> NativeRegisterContextSP;
+ typedef std::shared_ptr<lldb_private::NativeThreadProtocol> NativeThreadProtocolSP;
+}
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef LLDB_lldb_private_forward_h_
Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Jun 30 16:05:18 2014
@@ -51,20 +51,33 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23059A0519532B96007B8189 /* LinuxSignals.cpp */; };
23059A101958B319007B8189 /* SBUnixSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23059A0F1958B319007B8189 /* SBUnixSignals.cpp */; };
23059A121958B3B2007B8189 /* SBUnixSignals.h in Headers */ = {isa = PBXBuildFile; fileRef = 23059A111958B37B007B8189 /* SBUnixSignals.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 232CB615191E00CD00EF39FC /* NativeBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */; };
+ 232CB616191E00CD00EF39FC /* NativeBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */; };
+ 232CB617191E00CD00EF39FC /* NativeBreakpointList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */; };
+ 232CB618191E00CD00EF39FC /* NativeBreakpointList.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */; };
+ 232CB619191E00CD00EF39FC /* NativeProcessProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */; };
+ 232CB61A191E00CD00EF39FC /* NativeProcessProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */; };
+ 232CB61B191E00CD00EF39FC /* NativeThreadProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */; };
+ 232CB61C191E00CD00EF39FC /* NativeThreadProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */; };
+ 232CB61D191E00CD00EF39FC /* SoftwareBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */; };
+ 232CB61E191E00CD00EF39FC /* SoftwareBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */; };
233B007D1960C9F90090E598 /* ProcessInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B007B1960C9E60090E598 /* ProcessInfo.cpp */; };
233B007F1960CB280090E598 /* ProcessLaunchInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B007E1960CB280090E598 /* ProcessLaunchInfo.cpp */; };
- 233B009419610B1F0090E598 /* LinuxSignals.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008C19610B1F0090E598 /* LinuxSignals.cpp */; };
- 233B009519610B1F0090E598 /* LinuxSignals.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008D19610B1F0090E598 /* LinuxSignals.h */; };
233B009619610B1F0090E598 /* LinuxThread.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008E19610B1F0090E598 /* LinuxThread.cpp */; };
233B009719610B1F0090E598 /* LinuxThread.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008F19610B1F0090E598 /* LinuxThread.h */; };
233B009819610B1F0090E598 /* ProcessLinux.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009019610B1F0090E598 /* ProcessLinux.cpp */; };
233B009919610B1F0090E598 /* ProcessLinux.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009119610B1F0090E598 /* ProcessLinux.h */; };
233B009A19610B1F0090E598 /* ProcessMonitor.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009219610B1F0090E598 /* ProcessMonitor.cpp */; };
233B009B19610B1F0090E598 /* ProcessMonitor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009319610B1F0090E598 /* ProcessMonitor.h */; };
+ 239F5B2F19296DC500083917 /* NativeRegisterContextLinux_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 239F5B2E19296DC500083917 /* NativeRegisterContextLinux_x86_64.h */; };
+ 23EDE3321926843600F6A132 /* NativeRegisterContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 23EDE3311926843600F6A132 /* NativeRegisterContext.h */; };
+ 23EDE33319269E7C00F6A132 /* NativeRegisterContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23EDE3301926839700F6A132 /* NativeRegisterContext.cpp */; };
23EFE389193D1ABC00E54E54 /* SBTypeEnumMember.h in Headers */ = {isa = PBXBuildFile; fileRef = 23EFE388193D1ABC00E54E54 /* SBTypeEnumMember.h */; settings = {ATTRIBUTES = (Public, ); }; };
23EFE38B193D1AEC00E54E54 /* SBTypeEnumMember.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23EFE38A193D1AEC00E54E54 /* SBTypeEnumMember.cpp */; };
+ 23F4034D1926E0F60046DC9B /* NativeRegisterContextRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23F403481926CC250046DC9B /* NativeRegisterContextRegisterInfo.cpp */; };
260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; };
260157C71885F52500F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; };
260157C81885F53100F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; };
@@ -692,7 +705,6 @@
AF1F7B07189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF1F7B05189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp */; };
AF1F7B08189C904B0087DB9C /* AppleGetPendingItemsHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1F7B06189C904B0087DB9C /* AppleGetPendingItemsHandler.h */; };
AF23B4DB19009C66003E2A58 /* FreeBSDSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF23B4D919009C66003E2A58 /* FreeBSDSignals.cpp */; };
- AF23B4DC19009C66003E2A58 /* FreeBSDSignals.h in Headers */ = {isa = PBXBuildFile; fileRef = AF23B4DA19009C66003E2A58 /* FreeBSDSignals.h */; };
AF254E31170CCC33007AE5C9 /* PlatformDarwinKernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF254E2F170CCC33007AE5C9 /* PlatformDarwinKernel.cpp */; };
AF254E32170CCC33007AE5C9 /* PlatformDarwinKernel.h in Headers */ = {isa = PBXBuildFile; fileRef = AF254E30170CCC33007AE5C9 /* PlatformDarwinKernel.h */; };
AF25AB26188F685C0030DEC3 /* AppleGetQueuesHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF25AB24188F685C0030DEC3 /* AppleGetQueuesHandler.cpp */; };
@@ -861,14 +873,13 @@
dstPath = "$(DEVELOPER_DIR)/usr/share/man/man1/";
dstSubfolderSpec = 0;
files = (
+ 23EDE3321926843600F6A132 /* NativeRegisterContext.h in CopyFiles */,
233B009819610B1F0090E598 /* ProcessLinux.cpp in CopyFiles */,
233B009619610B1F0090E598 /* LinuxThread.cpp in CopyFiles */,
233B009A19610B1F0090E598 /* ProcessMonitor.cpp in CopyFiles */,
233B009719610B1F0090E598 /* LinuxThread.h in CopyFiles */,
233B009919610B1F0090E598 /* ProcessLinux.h in CopyFiles */,
233B009B19610B1F0090E598 /* ProcessMonitor.h in CopyFiles */,
- 233B009419610B1F0090E598 /* LinuxSignals.cpp in CopyFiles */,
- 233B009519610B1F0090E598 /* LinuxSignals.h in CopyFiles */,
AF90106515AB7D3600FF120D /* lldb.1 in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
@@ -891,14 +902,29 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 23059A0519532B96007B8189 /* LinuxSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LinuxSignals.cpp; path = Utility/LinuxSignals.cpp; sourceTree = "<group>"; };
+ 23059A0619532B96007B8189 /* LinuxSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LinuxSignals.h; path = Utility/LinuxSignals.h; sourceTree = "<group>"; };
23059A0F1958B319007B8189 /* SBUnixSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBUnixSignals.cpp; path = source/API/SBUnixSignals.cpp; sourceTree = "<group>"; };
23059A111958B37B007B8189 /* SBUnixSignals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBUnixSignals.h; path = include/lldb/API/SBUnixSignals.h; sourceTree = "<group>"; };
+ 23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-x86-register-enums.h"; path = "Utility/lldb-x86-register-enums.h"; sourceTree = "<group>"; };
+ 232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeBreakpoint.cpp; path = source/Host/common/NativeBreakpoint.cpp; sourceTree = "<group>"; };
+ 232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeBreakpoint.h; path = source/Host/common/NativeBreakpoint.h; sourceTree = "<group>"; };
+ 232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeBreakpointList.cpp; path = source/Host/common/NativeBreakpointList.cpp; sourceTree = "<group>"; };
+ 232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeBreakpointList.h; path = source/Host/common/NativeBreakpointList.h; sourceTree = "<group>"; };
+ 232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = NativeProcessProtocol.cpp; path = source/Host/common/NativeProcessProtocol.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ 232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeProcessProtocol.h; path = source/Host/common/NativeProcessProtocol.h; sourceTree = "<group>"; };
+ 232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeThreadProtocol.cpp; path = source/Host/common/NativeThreadProtocol.cpp; sourceTree = "<group>"; };
+ 232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeThreadProtocol.h; path = source/Host/common/NativeThreadProtocol.h; sourceTree = "<group>"; };
+ 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SoftwareBreakpoint.cpp; path = source/Host/common/SoftwareBreakpoint.cpp; sourceTree = "<group>"; };
+ 232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SoftwareBreakpoint.h; path = source/Host/common/SoftwareBreakpoint.h; sourceTree = "<group>"; };
+ 232CB62B19213AC200EF39FC /* NativeProcessLinux.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeProcessLinux.cpp; sourceTree = "<group>"; };
+ 232CB62C19213AC200EF39FC /* NativeProcessLinux.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; path = NativeProcessLinux.h; sourceTree = "<group>"; };
+ 232CB62D19213AC200EF39FC /* NativeThreadLinux.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeThreadLinux.cpp; sourceTree = "<group>"; };
+ 232CB62E19213AC200EF39FC /* NativeThreadLinux.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativeThreadLinux.h; sourceTree = "<group>"; };
233B007919609DB40090E598 /* ProcessLaunchInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ProcessLaunchInfo.h; path = include/lldb/Target/ProcessLaunchInfo.h; sourceTree = "<group>"; };
233B007A1960A0440090E598 /* ProcessInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ProcessInfo.h; path = include/lldb/Target/ProcessInfo.h; sourceTree = "<group>"; };
233B007B1960C9E60090E598 /* ProcessInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessInfo.cpp; path = source/Target/ProcessInfo.cpp; sourceTree = "<group>"; };
233B007E1960CB280090E598 /* ProcessLaunchInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessLaunchInfo.cpp; path = source/Target/ProcessLaunchInfo.cpp; sourceTree = "<group>"; };
- 233B008C19610B1F0090E598 /* LinuxSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinuxSignals.cpp; sourceTree = "<group>"; };
- 233B008D19610B1F0090E598 /* LinuxSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinuxSignals.h; sourceTree = "<group>"; };
233B008E19610B1F0090E598 /* LinuxThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinuxThread.cpp; sourceTree = "<group>"; };
233B008F19610B1F0090E598 /* LinuxThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinuxThread.h; sourceTree = "<group>"; };
233B009019610B1F0090E598 /* ProcessLinux.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProcessLinux.cpp; sourceTree = "<group>"; };
@@ -909,9 +935,15 @@
233B00A1196113730090E598 /* ProcFileReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ProcFileReader.cpp; sourceTree = "<group>"; };
233B00A2196113730090E598 /* ProcFileReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProcFileReader.h; sourceTree = "<group>"; };
2360092C193FB21500189DB1 /* MemoryRegionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MemoryRegionInfo.h; path = include/lldb/Target/MemoryRegionInfo.h; sourceTree = "<group>"; };
+ 239F5B2E19296DC500083917 /* NativeRegisterContextLinux_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContextLinux_x86_64.h; path = Utility/NativeRegisterContextLinux_x86_64.h; sourceTree = "<group>"; };
+ 239F5B3019298D4600083917 /* NativeRegisterContextLinux_x86_64.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContextLinux_x86_64.cpp; path = Utility/NativeRegisterContextLinux_x86_64.cpp; sourceTree = "<group>"; };
+ 23EDE3301926839700F6A132 /* NativeRegisterContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContext.cpp; path = source/Target/NativeRegisterContext.cpp; sourceTree = "<group>"; };
+ 23EDE3311926843600F6A132 /* NativeRegisterContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContext.h; path = include/lldb/Target/NativeRegisterContext.h; sourceTree = "<group>"; };
23EDE3371926AAD500F6A132 /* RegisterInfoInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RegisterInfoInterface.h; path = Utility/RegisterInfoInterface.h; sourceTree = "<group>"; };
23EFE388193D1ABC00E54E54 /* SBTypeEnumMember.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeEnumMember.h; path = include/lldb/API/SBTypeEnumMember.h; sourceTree = "<group>"; };
23EFE38A193D1AEC00E54E54 /* SBTypeEnumMember.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SBTypeEnumMember.cpp; path = source/API/SBTypeEnumMember.cpp; sourceTree = "<group>"; };
+ 23F403471926C8D50046DC9B /* NativeRegisterContextRegisterInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContextRegisterInfo.h; path = include/lldb/Target/NativeRegisterContextRegisterInfo.h; sourceTree = "<group>"; };
+ 23F403481926CC250046DC9B /* NativeRegisterContextRegisterInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContextRegisterInfo.cpp; path = source/Target/NativeRegisterContextRegisterInfo.cpp; sourceTree = "<group>"; };
260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = "<absolute>"; };
260223E7115F06D500A601A2 /* SBCommunication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommunication.h; path = include/lldb/API/SBCommunication.h; sourceTree = "<group>"; };
260223E8115F06E500A601A2 /* SBCommunication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommunication.cpp; path = source/API/SBCommunication.cpp; sourceTree = "<group>"; };
@@ -2186,10 +2218,12 @@
233B008B196106E90090E598 /* Linux */ = {
isa = PBXGroup;
children = (
- 233B008C19610B1F0090E598 /* LinuxSignals.cpp */,
- 233B008D19610B1F0090E598 /* LinuxSignals.h */,
233B008E19610B1F0090E598 /* LinuxThread.cpp */,
233B008F19610B1F0090E598 /* LinuxThread.h */,
+ 232CB62B19213AC200EF39FC /* NativeProcessLinux.cpp */,
+ 232CB62C19213AC200EF39FC /* NativeProcessLinux.h */,
+ 232CB62D19213AC200EF39FC /* NativeThreadLinux.cpp */,
+ 232CB62E19213AC200EF39FC /* NativeThreadLinux.h */,
233B009019610B1F0090E598 /* ProcessLinux.cpp */,
233B009119610B1F0090E598 /* ProcessLinux.h */,
233B009219610B1F0090E598 /* ProcessMonitor.cpp */,
@@ -2882,6 +2916,8 @@
B28058A0139988B0002D96D0 /* InferiorCallPOSIX.cpp */,
B28058A2139988C6002D96D0 /* InferiorCallPOSIX.h */,
B2D3033612EFA5C500F84EB3 /* InstructionUtils.h */,
+ 23059A0519532B96007B8189 /* LinuxSignals.cpp */,
+ 23059A0619532B96007B8189 /* LinuxSignals.h */,
26474C9E18D0CAEC0073DEBA /* RegisterContext_mips64.h */,
26474C9F18D0CAEC0073DEBA /* RegisterContext_x86.h */,
26957D9213D381C900670048 /* RegisterContextDarwin_arm.cpp */,
@@ -2939,6 +2975,9 @@
26E3EEE411A9901300FBADB6 /* UnwindMacOSXFrameBackchain.h */,
26E3EEE311A9901300FBADB6 /* UnwindMacOSXFrameBackchain.cpp */,
23EDE3371926AAD500F6A132 /* RegisterInfoInterface.h */,
+ 239F5B2E19296DC500083917 /* NativeRegisterContextLinux_x86_64.h */,
+ 239F5B3019298D4600083917 /* NativeRegisterContextLinux_x86_64.cpp */,
+ 23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */,
);
name = Utility;
sourceTree = "<group>";
@@ -3376,10 +3415,20 @@
26FA4315130103F400E71120 /* FileSpec.h */,
26BC7DD410F1B7D500F91463 /* Host.h */,
26BC7DD510F1B7D500F91463 /* Mutex.h */,
+ 232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */,
+ 232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */,
+ 232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */,
+ 232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */,
+ 232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */,
+ 232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */,
+ 232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */,
+ 232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */,
A36FF33D17D8E98800244D40 /* OptionParser.h */,
26BC7DD610F1B7D500F91463 /* Predicate.h */,
26D7E45B13D5E2F9007FD12B /* SocketAddress.h */,
26D7E45C13D5E30A007FD12B /* SocketAddress.cpp */,
+ 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */,
+ 232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */,
2689B0A4113EE3CD00A4AEDB /* Symbols.h */,
268DA871130095D000C9483A /* Terminal.h */,
26B4E26E112F35F700AB3F64 /* TimeValue.h */,
@@ -3486,6 +3535,8 @@
26BC7DEF10F1B80200F91463 /* Target */ = {
isa = PBXGroup;
children = (
+ 23EDE3311926843600F6A132 /* NativeRegisterContext.h */,
+ 23EDE3301926839700F6A132 /* NativeRegisterContext.cpp */,
497E7B331188ED300065CCA1 /* ABI.h */,
497E7B9D1188F6690065CCA1 /* ABI.cpp */,
4CB443BB1249920C00C13DC2 /* CPPLanguageRuntime.h */,
@@ -3583,6 +3634,8 @@
26E3EEBD11A9870400FBADB6 /* Unwind.h */,
264D8D4E13661BCC003A368F /* UnwindAssembly.h */,
264D8D4F13661BD7003A368F /* UnwindAssembly.cpp */,
+ 23F403471926C8D50046DC9B /* NativeRegisterContextRegisterInfo.h */,
+ 23F403481926CC250046DC9B /* NativeRegisterContextRegisterInfo.cpp */,
);
name = Target;
sourceTree = "<group>";
@@ -4103,6 +4156,7 @@
26FFC19C14FC072100087D58 /* DYLDRendezvous.h in Headers */,
AF1F7B08189C904B0087DB9C /* AppleGetPendingItemsHandler.h in Headers */,
AF2BCA6D18C7EFDE005B4526 /* JITLoaderGDB.h in Headers */,
+ 232CB61E191E00CD00EF39FC /* SoftwareBreakpoint.h in Headers */,
26BC17B218C7F4CB00D2196D /* ThreadElfCore.h in Headers */,
26FFC19E14FC072100087D58 /* DynamicLoaderPOSIXDYLD.h in Headers */,
AF254E32170CCC33007AE5C9 /* PlatformDarwinKernel.h in Headers */,
@@ -4120,6 +4174,7 @@
260CC63115D04377002BF2E0 /* OptionValueProperties.h in Headers */,
260CC63215D04377002BF2E0 /* OptionValueDictionary.h in Headers */,
262173A118395D3800C52091 /* SectionLoadHistory.h in Headers */,
+ 232CB61A191E00CD00EF39FC /* NativeProcessProtocol.h in Headers */,
260CC63315D04377002BF2E0 /* OptionValueEnumeration.h in Headers */,
AF45FDE618A1F3AC0007051C /* AppleGetThreadItemInfoHandler.h in Headers */,
260A63171861008E00FECF8E /* IOHandler.h in Headers */,
@@ -4147,15 +4202,18 @@
260CC63A15D04377002BF2E0 /* OptionValueUUID.h in Headers */,
260A248E15D06C50009981B0 /* OptionValues.h in Headers */,
AF061F88182C97ED00B6A19C /* RegisterContextHistory.h in Headers */,
+ 239F5B2F19296DC500083917 /* NativeRegisterContextLinux_x86_64.h in Headers */,
26DAED6015D327A200E15819 /* OptionValuePathMappings.h in Headers */,
26ACEC2815E077AE00E94760 /* Property.h in Headers */,
26491E3B15E1DB8600CBFFC2 /* OptionValueRegex.h in Headers */,
2697A39515E404BA003E682C /* OptionValueArch.h in Headers */,
- AF23B4DC19009C66003E2A58 /* FreeBSDSignals.h in Headers */,
26474CBF18D0CB2D0073DEBA /* RegisterContextMach_i386.h in Headers */,
26474CC118D0CB2D0073DEBA /* RegisterContextMach_x86_64.h in Headers */,
2698699D15E6CBD0002415FF /* OperatingSystemPython.h in Headers */,
+ 232CB618191E00CD00EF39FC /* NativeBreakpointList.h in Headers */,
260D9B2715EC369500960137 /* ModuleSpec.h in Headers */,
+ 232CB61C191E00CD00EF39FC /* NativeThreadProtocol.h in Headers */,
+ 232CB616191E00CD00EF39FC /* NativeBreakpoint.h in Headers */,
947A1D651616476B0017C8D1 /* CommandObjectPlugin.h in Headers */,
262ED0051631FA2800879631 /* OptionGroupString.h in Headers */,
26474CA918D0CB070073DEBA /* RegisterContextFreeBSD_i386.h in Headers */,
@@ -4606,6 +4664,7 @@
2689001813353DDE00698AC0 /* CommandObjectExpression.cpp in Sources */,
2689001A13353DDE00698AC0 /* CommandObjectFrame.cpp in Sources */,
2689001B13353DDE00698AC0 /* CommandObjectHelp.cpp in Sources */,
+ 23F4034D1926E0F60046DC9B /* NativeRegisterContextRegisterInfo.cpp in Sources */,
2689001D13353DDE00698AC0 /* CommandObjectLog.cpp in Sources */,
262173A318395D4600C52091 /* SectionLoadHistory.cpp in Sources */,
2689001E13353DDE00698AC0 /* CommandObjectMemory.cpp in Sources */,
@@ -4652,6 +4711,7 @@
2689004313353E0400698AC0 /* Mangled.cpp in Sources */,
2689004413353E0400698AC0 /* Module.cpp in Sources */,
2689004513353E0400698AC0 /* ModuleChild.cpp in Sources */,
+ 23EDE33319269E7C00F6A132 /* NativeRegisterContext.cpp in Sources */,
2689004613353E0400698AC0 /* ModuleList.cpp in Sources */,
2689004713353E0400698AC0 /* PluginManager.cpp in Sources */,
AF0C112818580CD800C4C45B /* QueueItem.cpp in Sources */,
@@ -4672,6 +4732,7 @@
2689005313353E0400698AC0 /* UserID.cpp in Sources */,
2689005413353E0400698AC0 /* UserSettingsController.cpp in Sources */,
2689005513353E0400698AC0 /* UUID.cpp in Sources */,
+ 23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */,
2689005613353E0400698AC0 /* Value.cpp in Sources */,
2689005713353E0400698AC0 /* ValueObject.cpp in Sources */,
2689005813353E0400698AC0 /* ValueObjectChild.cpp in Sources */,
@@ -4829,13 +4890,17 @@
268900F913353E6F00698AC0 /* Thread.cpp in Sources */,
268900FA13353E6F00698AC0 /* ThreadList.cpp in Sources */,
268900FB13353E6F00698AC0 /* ThreadPlan.cpp in Sources */,
+ 232CB619191E00CD00EF39FC /* NativeProcessProtocol.cpp in Sources */,
268900FC13353E6F00698AC0 /* ThreadPlanBase.cpp in Sources */,
268900FD13353E6F00698AC0 /* ThreadPlanCallFunction.cpp in Sources */,
268900FE13353E6F00698AC0 /* ThreadPlanCallUserExpression.cpp in Sources */,
268900FF13353E6F00698AC0 /* ThreadPlanShouldStopHere.cpp in Sources */,
2689010013353E6F00698AC0 /* ThreadPlanStepInstruction.cpp in Sources */,
+ 232CB61B191E00CD00EF39FC /* NativeThreadProtocol.cpp in Sources */,
2689010113353E6F00698AC0 /* ThreadPlanStepOut.cpp in Sources */,
2689010213353E6F00698AC0 /* ThreadPlanStepOverBreakpoint.cpp in Sources */,
+ 232CB617191E00CD00EF39FC /* NativeBreakpointList.cpp in Sources */,
+ 232CB615191E00CD00EF39FC /* NativeBreakpoint.cpp in Sources */,
2689010313353E6F00698AC0 /* ThreadPlanStepRange.cpp in Sources */,
2689010413353E6F00698AC0 /* ThreadPlanStepInRange.cpp in Sources */,
2689010513353E6F00698AC0 /* ThreadPlanStepOverRange.cpp in Sources */,
@@ -4894,6 +4959,7 @@
26DB3E191379E7AD0080DC73 /* ABIMacOSX_arm64.cpp in Sources */,
26DB3E1C1379E7AD0080DC73 /* ABIMacOSX_i386.cpp in Sources */,
26DB3E1F1379E7AD0080DC73 /* ABISysV_x86_64.cpp in Sources */,
+ 232CB61D191E00CD00EF39FC /* SoftwareBreakpoint.cpp in Sources */,
26D1803E16CEBFD300EDFB5B /* KQueue.cpp in Sources */,
26A69C5F137A17A500262477 /* RegisterValue.cpp in Sources */,
2690B3711381D5C300ECFBAE /* Memory.cpp in Sources */,
Modified: lldb/trunk/source/Core/ModuleList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ModuleList.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Core/ModuleList.cpp (original)
+++ lldb/trunk/source/Core/ModuleList.cpp Mon Jun 30 16:05:18 2014
@@ -1003,6 +1003,7 @@ ModuleList::GetSharedModule
file_spec.GetPath(path, sizeof(path));
if (path[0] == '\0')
module_file_spec.GetPath(path, sizeof(path));
+ // How can this check ever be true? This branch it is false, and we haven't modified file_spec.
if (file_spec.Exists())
{
std::string uuid_str;
Modified: lldb/trunk/source/Expression/IRMemoryMap.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRMemoryMap.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Expression/IRMemoryMap.cpp (original)
+++ lldb/trunk/source/Expression/IRMemoryMap.cpp Mon Jun 30 16:05:18 2014
@@ -249,6 +249,7 @@ IRMemoryMap::Allocation::Allocation (lld
lldb::addr_t
IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error)
{
+ lldb_private::Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
error.Clear();
lldb::ProcessSP process_sp;
@@ -280,6 +281,8 @@ IRMemoryMap::Malloc (size_t size, uint8_
break;
case eAllocationPolicyMirror:
process_sp = m_process_wp.lock();
+ if (log)
+ log->Printf ("IRMemoryMap::%s process_sp=0x%" PRIx64 ", process_sp->CanJIT()=%s, process_sp->IsAlive()=%s", __FUNCTION__, (lldb::addr_t) process_sp.get (), process_sp && process_sp->CanJIT () ? "true" : "false", process_sp && process_sp->IsAlive () ? "true" : "false");
if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
{
allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
@@ -288,6 +291,8 @@ IRMemoryMap::Malloc (size_t size, uint8_
}
else
{
+ if (log)
+ log->Printf ("IRMemoryMap::%s switching to eAllocationPolicyHostOnly due to failed condition (see previous expr log message)", __FUNCTION__);
policy = eAllocationPolicyHostOnly;
allocation_address = FindSpace(allocation_size);
if (allocation_address == LLDB_INVALID_ADDRESS)
@@ -335,7 +340,7 @@ IRMemoryMap::Malloc (size_t size, uint8_
alignment,
policy);
- if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ if (log)
{
const char * policy_string;
Modified: lldb/trunk/source/Host/common/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/CMakeLists.txt (original)
+++ lldb/trunk/source/Host/common/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -8,9 +8,14 @@ add_lldb_library(lldbHostCommon
FileSpec.cpp
Host.cpp
Mutex.cpp
+ NativeBreakpoint.cpp
+ NativeBreakpointList.cpp
+ NativeProcessProtocol.cpp
+ NativeThreadProtocol.cpp
OptionParser.cpp
ProcessRunLock.cpp
SocketAddress.cpp
+ SoftwareBreakpoint.cpp
Symbols.cpp
Terminal.cpp
TimeValue.cpp
Added: lldb/trunk/source/Host/common/NativeBreakpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpoint.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpoint.cpp (added)
+++ lldb/trunk/source/Host/common/NativeBreakpoint.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,116 @@
+//===-- NativeBreakpoint.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeBreakpoint.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+NativeBreakpoint::NativeBreakpoint (lldb::addr_t addr) :
+ m_addr (addr),
+ m_ref_count (1),
+ m_enabled (true)
+{
+ assert (addr != LLDB_INVALID_ADDRESS && "breakpoint set for invalid address");
+}
+
+NativeBreakpoint::~NativeBreakpoint ()
+{
+}
+
+void
+NativeBreakpoint::AddRef ()
+{
+ ++m_ref_count;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " bumped up, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);
+}
+
+int32_t
+NativeBreakpoint::DecRef ()
+{
+ --m_ref_count;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " ref count decremented, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);
+
+ return m_ref_count;
+}
+
+Error
+NativeBreakpoint::Enable ()
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_enabled)
+ {
+ // We're already enabled. Just log and exit.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already enabled, ignoring.", __FUNCTION__, m_addr);
+ return Error ();
+ }
+
+ // Log and enable.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enabling...", __FUNCTION__, m_addr);
+
+ Error error = DoEnable ();
+ if (error.Success ())
+ {
+ m_enabled = true;
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable SUCCESS.", __FUNCTION__, m_addr);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+ }
+
+ return error;
+}
+
+Error
+NativeBreakpoint::Disable ()
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (!m_enabled)
+ {
+ // We're already disabled. Just log and exit.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already disabled, ignoring.", __FUNCTION__, m_addr);
+ return Error ();
+ }
+
+ // Log and disable.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disabling...", __FUNCTION__, m_addr);
+
+ Error error = DoDisable ();
+ if (error.Success ())
+ {
+ m_enabled = false;
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable SUCCESS.", __FUNCTION__, m_addr);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+ }
+
+ return error;
+}
Added: lldb/trunk/source/Host/common/NativeBreakpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpoint.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpoint.h (added)
+++ lldb/trunk/source/Host/common/NativeBreakpoint.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,66 @@
+//===-- NativeBreakpoint.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_NativeBreakpoint_h_
+#define liblldb_NativeBreakpoint_h_
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private
+{
+ class NativeBreakpointList;
+
+ class NativeBreakpoint
+ {
+ friend class NativeBreakpointList;
+
+ public:
+ // The assumption is that derived breakpoints are enabled when created.
+ NativeBreakpoint (lldb::addr_t addr);
+
+ virtual
+ ~NativeBreakpoint ();
+
+ Error
+ Enable ();
+
+ Error
+ Disable ();
+
+ lldb::addr_t
+ GetAddress () const { return m_addr; }
+
+ bool
+ IsEnabled () const { return m_enabled; }
+
+ virtual bool
+ IsSoftwareBreakpoint () const = 0;
+
+ protected:
+ const lldb::addr_t m_addr;
+ int32_t m_ref_count;
+
+ virtual Error
+ DoEnable () = 0;
+
+ virtual Error
+ DoDisable () = 0;
+
+ private:
+ bool m_enabled;
+
+ // -----------------------------------------------------------
+ // interface for NativeBreakpointList
+ // -----------------------------------------------------------
+ void AddRef ();
+ int32_t DecRef ();
+ };
+}
+
+#endif // ifndef liblldb_NativeBreakpoint_h_
Added: lldb/trunk/source/Host/common/NativeBreakpointList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpointList.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpointList.cpp (added)
+++ lldb/trunk/source/Host/common/NativeBreakpointList.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,199 @@
+//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeBreakpointList.h"
+
+#include "lldb/Core/Log.h"
+
+#include "NativeBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeBreakpointList::NativeBreakpointList () :
+ m_mutex (Mutex::eMutexTypeRecursive)
+{
+}
+
+Error
+NativeBreakpointList::AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false");
+
+ Mutex::Locker locker (m_mutex);
+
+ // Check if the breakpoint is already set.
+ auto iter = m_breakpoints.find (addr);
+ if (iter != m_breakpoints.end ())
+ {
+ // Yes - bump up ref count.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already enabled, upping ref count", __FUNCTION__, addr);
+
+ iter->second->AddRef ();
+ return Error ();
+ }
+
+ // Create a new breakpoint using the given create func.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false");
+
+ NativeBreakpointSP breakpoint_sp;
+ Error error = create_func (addr, size_hint, hardware, breakpoint_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s -- FAILED: %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false", error.AsCString ());
+ return error;
+ }
+
+ // Remember the breakpoint.
+ assert (breakpoint_sp && "NativeBreakpoint create function succeeded but returned NULL breakpoint");
+ m_breakpoints.insert (BreakpointMap::value_type (addr, breakpoint_sp));
+
+ return error;
+}
+
+Error
+NativeBreakpointList::DecRef (lldb::addr_t addr)
+{
+ Error error;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Check if the breakpoint is already set.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ error.SetErrorString ("breakpoint not found");
+ return error;
+ }
+
+ // Decrement ref count.
+ const int32_t new_ref_count = iter->second->DecRef ();
+ assert (new_ref_count >= 0 && "NativeBreakpoint ref count went negative");
+
+ if (new_ref_count > 0)
+ {
+ // Still references to this breakpoint. Leave it alone.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- new breakpoint ref count %" PRIu32, __FUNCTION__, addr, new_ref_count);
+ return error;
+ }
+
+ // Breakpoint has no more references. Disable it if it's not
+ // already disabled.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removing due to no remaining references", __FUNCTION__, addr);
+
+ // If it's enabled, we need to disable it.
+ if (iter->second->IsEnabled ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- currently enabled, now disabling", __FUNCTION__, addr);
+ error = iter->second->Disable ();
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removal FAILED: %s", __FUNCTION__, addr, error.AsCString ());
+ // Continue since we still want to take it out of the breakpoint list.
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already disabled, nothing to do", __FUNCTION__, addr);
+ }
+
+ // Take the breakpoint out of the list.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removed from breakpoint map", __FUNCTION__, addr);
+
+ m_breakpoints.erase (iter);
+ return error;
+}
+
+Error
+NativeBreakpointList::EnableBreakpoint (lldb::addr_t addr)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ return Error ("breakpoint not found");
+ }
+
+ // Enable it.
+ return iter->second->Enable ();
+}
+
+Error
+NativeBreakpointList::DisableBreakpoint (lldb::addr_t addr)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ return Error ("breakpoint not found");
+ }
+
+ // Disable it.
+ return iter->second->Disable ();
+}
+
+Error
+NativeBreakpointList::GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ breakpoint_sp.reset ();
+ return Error ("breakpoint not found");
+ }
+
+ // Disable it.
+ breakpoint_sp = iter->second;
+ return Error ();
+}
+
Added: lldb/trunk/source/Host/common/NativeBreakpointList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpointList.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpointList.h (added)
+++ lldb/trunk/source/Host/common/NativeBreakpointList.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,53 @@
+//===-- NativeBreakpointList.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_NativeBreakpointList_h_
+#define liblldb_NativeBreakpointList_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+// #include "lldb/Host/NativeBreakpoint.h"
+
+#include <functional>
+#include <map>
+
+namespace lldb_private
+{
+ class NativeBreakpointList
+ {
+ public:
+ typedef std::function<Error (lldb::addr_t addr, size_t size_hint, bool hardware, NativeBreakpointSP &breakpoint_sp)> CreateBreakpointFunc;
+
+ NativeBreakpointList ();
+
+ Error
+ AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func);
+
+ Error
+ DecRef (lldb::addr_t addr);
+
+ Error
+ EnableBreakpoint (lldb::addr_t addr);
+
+ Error
+ DisableBreakpoint (lldb::addr_t addr);
+
+ Error
+ GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp);
+
+ private:
+ typedef std::map<lldb::addr_t, NativeBreakpointSP> BreakpointMap;
+
+ Mutex m_mutex;
+ BreakpointMap m_breakpoints;
+ };
+}
+
+#endif // ifndef liblldb_NativeBreakpointList_h_
Added: lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeProcessProtocol.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeProcessProtocol.cpp (added)
+++ lldb/trunk/source/Host/common/NativeProcessProtocol.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,397 @@
+//===-- NativeProcessProtocol.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessProtocol.h"
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/NativeRegisterContext.h"
+
+#include "NativeThreadProtocol.h"
+#include "SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// -----------------------------------------------------------------------------
+// NativeProcessProtocol Members
+// -----------------------------------------------------------------------------
+
+NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) :
+ m_pid (pid),
+ m_threads (),
+ m_current_thread_id (LLDB_INVALID_THREAD_ID),
+ m_threads_mutex (Mutex::eMutexTypeRecursive),
+ m_state (lldb::eStateInvalid),
+ m_state_mutex (Mutex::eMutexTypeRecursive),
+ m_exit_type (eExitTypeInvalid),
+ m_exit_status (0),
+ m_exit_description (),
+ m_delegates_mutex (Mutex::eMutexTypeRecursive),
+ m_delegates (),
+ m_breakpoint_list (),
+ m_terminal_fd (-1),
+ m_stop_id (0)
+{
+}
+
+lldb_private::Error
+NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
+{
+ // Default: not implemented.
+ return Error ("not implemented");
+}
+
+bool
+NativeProcessProtocol::GetExitStatus (ExitType *exit_type, int *status, std::string &exit_description)
+{
+ if (m_state == lldb::eStateExited)
+ {
+ *exit_type = m_exit_type;
+ *status = m_exit_status;
+ exit_description = m_exit_description;
+ return true;
+ }
+
+ *status = 0;
+ return false;
+}
+
+bool
+NativeProcessProtocol::SetExitStatus (ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange)
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s(%d, %d, %s, %s) called",
+ __FUNCTION__,
+ exit_type,
+ status,
+ exit_description ? exit_description : "nullptr",
+ bNotifyStateChange ? "true" : "false");
+
+ // Exit status already set
+ if (m_state == lldb::eStateExited)
+ {
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s exit status already set to %d, ignoring new set to %d", __FUNCTION__, m_exit_status, status);
+ return false;
+ }
+
+ m_state = lldb::eStateExited;
+
+ m_exit_type = exit_type;
+ m_exit_status = status;
+ if (exit_description && exit_description[0])
+ m_exit_description = exit_description;
+ else
+ m_exit_description.clear();
+
+ if (bNotifyStateChange)
+ SynchronouslyNotifyProcessStateChanged (lldb::eStateExited);
+
+ return true;
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ if (idx < m_threads.size ())
+ return m_threads[idx];
+ return NativeThreadProtocolSP ();
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadByID (lldb::tid_t tid)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ if (thread_sp->GetID() == tid)
+ return thread_sp;
+ }
+ return NativeThreadProtocolSP ();
+}
+
+bool
+NativeProcessProtocol::IsAlive () const
+{
+ return m_state != eStateDetached
+ && m_state != eStateExited
+ && m_state != eStateInvalid
+ && m_state != eStateUnloaded;
+}
+
+bool
+NativeProcessProtocol::GetByteOrder (lldb::ByteOrder &byte_order) const
+{
+ ArchSpec process_arch;
+ if (!GetArchitecture (process_arch))
+ return false;
+ byte_order = process_arch.GetByteOrder ();
+ return true;
+}
+
+uint32_t
+NativeProcessProtocol::GetMaxWatchpoints () const
+{
+ // This default implementation will return the number of
+ // *hardware* breakpoints available. MacOSX and other OS
+ // implementations that support software breakpoints will want to
+ // override this correctly for their implementation.
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // get any thread
+ NativeThreadProtocolSP thread_sp (const_cast<NativeProcessProtocol*> (this)->GetThreadAtIndex (0));
+ if (!thread_sp)
+ {
+ if (log)
+ log->Warning ("NativeProcessProtocol::%s (): failed to find a thread to grab a NativeRegisterContext!", __FUNCTION__);
+ return 0;
+ }
+
+ NativeRegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext ());
+ if (!reg_ctx_sp)
+ {
+ if (log)
+ log->Warning ("NativeProcessProtocol::%s (): failed to get a RegisterContextNativeProcess from the first thread!", __FUNCTION__);
+ return 0;
+ }
+
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints ();
+}
+
+Error
+NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ // This default implementation assumes setting the watchpoint for
+ // the process will require setting the watchpoint for each of the
+ // threads. Furthermore, it will track watchpoints set for the
+ // process and will add them to each thread that is attached to
+ // via the (FIXME implement) OnThreadAttached () method.
+
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // FIXME save the watchpoint on the set of process watchpoint vars
+ // so we can add them to a thread each time a new thread is registered.
+
+ // Update the thread list
+ UpdateThreads ();
+
+ // Keep track of the threads we successfully set the watchpoint
+ // for. If one of the thread watchpoint setting operations fails,
+ // back off and remove the watchpoint for all the threads that
+ // were successfully set so we get back to a consistent state.
+ std::vector<NativeThreadProtocolSP> watchpoint_established_threads;
+
+ // Tell each thread to set a watchpoint. In the event that
+ // hardware watchpoints are requested but the SetWatchpoint fails,
+ // try to set a software watchpoint as a fallback. It's
+ // conceivable that if there are more threads than hardware
+ // watchpoints available, some of the threads will fail to set
+ // hardware watchpoints while software ones may be available.
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ Error thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, hardware);
+ if (thread_error.Fail () && hardware)
+ {
+ // Try software watchpoints since we failed on hardware watchpoint setting
+ // and we may have just run out of hardware watchpoints.
+ thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, false);
+ if (thread_error.Success ())
+ {
+ if (log)
+ log->Warning ("hardware watchpoint requested but software watchpoint set");
+ }
+ }
+
+ if (thread_error.Success ())
+ {
+ // Remember that we set this watchpoint successfully in
+ // case we need to clear it later.
+ watchpoint_established_threads.push_back (thread_sp);
+ }
+ else
+ {
+ // Unset the watchpoint for each thread we successfully
+ // set so that we get back to a consistent state of "not
+ // set" for the watchpoint.
+ for (auto unwatch_thread_sp : watchpoint_established_threads)
+ {
+ Error remove_error = unwatch_thread_sp->RemoveWatchpoint (addr);
+ if (remove_error.Fail () && log)
+ {
+ log->Warning ("NativeProcessProtocol::%s (): RemoveWatchpoint failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
+ __FUNCTION__, GetID (), unwatch_thread_sp->GetID (), remove_error.AsCString ());
+ }
+ }
+
+ return thread_error;
+ }
+ }
+ return Error ();
+}
+
+Error
+NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr)
+{
+ // FIXME remove the watchpoint on the set of process watchpoint vars
+ // so we can add them to a thread each time a new thread is registered.
+
+ // Update the thread list
+ UpdateThreads ();
+
+ Error overall_error;
+
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ const Error thread_error = thread_sp->RemoveWatchpoint (addr);
+ if (thread_error.Fail ())
+ {
+ // Keep track of the first thread error if any threads
+ // fail. We want to try to remove the watchpoint from
+ // every thread, though, even if one or more have errors.
+ if (!overall_error.Fail ())
+ overall_error = thread_error;
+ }
+ }
+ return overall_error;
+}
+
+bool
+NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate)
+{
+ Mutex::Locker locker (m_delegates_mutex);
+ if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ())
+ return false;
+
+ m_delegates.push_back (&native_delegate);
+ native_delegate.InitializeDelegate (this);
+ return true;
+}
+
+bool
+NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate)
+{
+ Mutex::Locker locker (m_delegates_mutex);
+
+ const auto initial_size = m_delegates.size ();
+ m_delegates.erase (remove (m_delegates.begin (), m_delegates.end (), &native_delegate), m_delegates.end ());
+
+ // We removed the delegate if the count of delegates shrank after
+ // removing all copies of the given native_delegate from the vector.
+ return m_delegates.size () < initial_size;
+}
+
+void
+NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType state)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ Mutex::Locker locker (m_delegates_mutex);
+ for (auto native_delegate: m_delegates)
+ native_delegate->ProcessStateChanged (this, state);
+
+ if (log)
+ {
+ if (!m_delegates.empty ())
+ {
+ log->Printf ("NativeProcessProtocol::%s: sent state notification [%s] from process %" PRIu64,
+ __FUNCTION__, lldb_private::StateAsCString (state), GetID ());
+ }
+ else
+ {
+ log->Printf ("NativeProcessProtocol::%s: would send state notification [%s] from process %" PRIu64 ", but no delegates",
+ __FUNCTION__, lldb_private::StateAsCString (state), GetID ());
+ }
+ }
+}
+
+Error
+NativeProcessProtocol::SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ return m_breakpoint_list.AddRef (addr, size_hint, false,
+ [this] (lldb::addr_t addr, size_t size_hint, bool /* hardware */, NativeBreakpointSP &breakpoint_sp)->Error
+ { return SoftwareBreakpoint::CreateSoftwareBreakpoint (*this, addr, size_hint, breakpoint_sp); });
+}
+
+Error
+NativeProcessProtocol::RemoveBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.DecRef (addr);
+}
+
+Error
+NativeProcessProtocol::EnableBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.EnableBreakpoint (addr);
+}
+
+Error
+NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.DisableBreakpoint (addr);
+}
+
+lldb::StateType
+NativeProcessProtocol::GetState () const
+{
+ Mutex::Locker locker (m_state_mutex);
+ return m_state;
+}
+
+void
+NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates)
+{
+ Mutex::Locker locker (m_state_mutex);
+ m_state = state;
+
+ if (StateIsStoppedState (state, false))
+ {
+ ++m_stop_id;
+
+ // Give process a chance to do any stop id bump processing, such as
+ // clearing cached data that is invalidated each time the process runs.
+ // Note if/when we support some threads running, we'll end up needing
+ // to manage this per thread and per process.
+ DoStopIDBumped (m_stop_id);
+ }
+
+ // Optionally notify delegates of the state change.
+ if (notify_delegates)
+ SynchronouslyNotifyProcessStateChanged (state);
+}
+
+uint32_t NativeProcessProtocol::GetStopID () const
+{
+ Mutex::Locker locker (m_state_mutex);
+ return m_stop_id;
+}
+
+void
+NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */)
+{
+ // Default implementation does nothing.
+}
Added: lldb/trunk/source/Host/common/NativeProcessProtocol.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeProcessProtocol.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeProcessProtocol.h (added)
+++ lldb/trunk/source/Host/common/NativeProcessProtocol.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,321 @@
+//===-- NativeProcessProtocol.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_NativeProcessProtocol_h_
+#define liblldb_NativeProcessProtocol_h_
+
+#include <vector>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+
+#include "NativeBreakpointList.h"
+
+namespace lldb_private
+{
+ class MemoryRegionInfo;
+ class ResumeActionList;
+
+ //------------------------------------------------------------------
+ // NativeProcessProtocol
+ //------------------------------------------------------------------
+ class NativeProcessProtocol :
+ public std::enable_shared_from_this<NativeProcessProtocol>
+ {
+ friend class SoftwareBreakpoint;
+
+ public:
+ static NativeProcessProtocol *
+ CreateInstance (lldb::pid_t pid);
+
+ // lldb_private::Host calls should be used to launch a process for debugging, and
+ // then the process should be attached to. When attaching to a process
+ // lldb_private::Host calls should be used to locate the process to attach to,
+ // and then this function should be called.
+ NativeProcessProtocol (lldb::pid_t pid);
+
+ public:
+ virtual ~NativeProcessProtocol ()
+ {
+ }
+
+ virtual Error
+ Resume (const ResumeActionList &resume_actions) = 0;
+
+ virtual Error
+ Halt () = 0;
+
+ virtual Error
+ Detach () = 0;
+
+ //------------------------------------------------------------------
+ /// Sends a process a UNIX signal \a signal.
+ ///
+ /// Implementer note: the WillSignal ()/DidSignal () calls
+ /// from the Process class are not replicated here since no
+ /// concrete classes implemented any behavior for those and
+ /// put all the work in DoSignal (...).
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ Signal (int signo) = 0;
+
+ virtual Error
+ Kill () = 0;
+
+ //----------------------------------------------------------------------
+ // Memory and memory region functions
+ //----------------------------------------------------------------------
+
+ virtual Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info);
+
+ virtual Error
+ ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0;
+
+ virtual Error
+ WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
+
+ virtual Error
+ AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
+
+ virtual Error
+ DeallocateMemory (lldb::addr_t addr) = 0;
+
+ virtual lldb::addr_t
+ GetSharedLibraryInfoAddress () = 0;
+
+ virtual bool
+ IsAlive () const;
+
+ virtual size_t
+ UpdateThreads () = 0;
+
+ virtual bool
+ GetArchitecture (ArchSpec &arch) const = 0;
+
+ //----------------------------------------------------------------------
+ // Breakpoint functions
+ //----------------------------------------------------------------------
+ virtual Error
+ SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) = 0;
+
+ virtual Error
+ RemoveBreakpoint (lldb::addr_t addr);
+
+ virtual Error
+ EnableBreakpoint (lldb::addr_t addr);
+
+ virtual Error
+ DisableBreakpoint (lldb::addr_t addr);
+
+ //----------------------------------------------------------------------
+ // Watchpoint functions
+ //----------------------------------------------------------------------
+ virtual uint32_t
+ GetMaxWatchpoints () const;
+
+ virtual Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware);
+
+ virtual Error
+ RemoveWatchpoint (lldb::addr_t addr);
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ lldb::pid_t
+ GetID() const
+ {
+ return m_pid;
+ }
+
+ lldb::StateType
+ GetState () const;
+
+ bool
+ IsRunning () const
+ {
+ return m_state == lldb::eStateRunning || IsStepping();
+ }
+
+ bool
+ IsStepping () const
+ {
+ return m_state == lldb::eStateStepping;
+ }
+
+ bool
+ CanResume () const
+ {
+ return m_state == lldb::eStateStopped;
+ }
+
+ bool
+ GetByteOrder (lldb::ByteOrder &byte_order) const;
+
+ //----------------------------------------------------------------------
+ // Exit Status
+ //----------------------------------------------------------------------
+ virtual bool
+ GetExitStatus (lldb_private::ExitType *exit_type, int *status, std::string &exit_description);
+
+ virtual bool
+ SetExitStatus (lldb_private::ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange);
+
+ //----------------------------------------------------------------------
+ // Access to threads
+ //----------------------------------------------------------------------
+ NativeThreadProtocolSP
+ GetThreadAtIndex (uint32_t idx);
+
+ NativeThreadProtocolSP
+ GetThreadByID (lldb::tid_t tid);
+
+ void
+ SetCurrentThreadID (lldb::tid_t tid)
+ {
+ m_current_thread_id = tid;
+ }
+
+ lldb::tid_t
+ GetCurrentThreadID ()
+ {
+ return m_current_thread_id;
+ }
+
+ NativeThreadProtocolSP
+ GetCurrentThread ()
+ {
+ return GetThreadByID (m_current_thread_id);
+ }
+
+ //----------------------------------------------------------------------
+ // Access to inferior stdio
+ //----------------------------------------------------------------------
+ virtual
+ int GetTerminalFileDescriptor ()
+ {
+ return m_terminal_fd;
+ }
+
+ //----------------------------------------------------------------------
+ // Stop id interface
+ //----------------------------------------------------------------------
+
+ uint32_t
+ GetStopID () const;
+
+ // ---------------------------------------------------------------------
+ // Callbacks for low-level process state changes
+ // ---------------------------------------------------------------------
+ class NativeDelegate
+ {
+ public:
+ virtual
+ ~NativeDelegate () {}
+
+ virtual void
+ InitializeDelegate (NativeProcessProtocol *process) = 0;
+
+ virtual void
+ ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) = 0;
+ };
+
+ //------------------------------------------------------------------
+ /// Register a native delegate.
+ ///
+ /// Clients can register nofication callbacks by passing in a
+ /// NativeDelegate impl and passing it into this function.
+ ///
+ /// Note: it is required that the lifetime of the
+ /// native_delegate outlive the NativeProcessProtocol.
+ ///
+ /// @param[in] native_delegate
+ /// A NativeDelegate impl to be called when certain events
+ /// happen within the NativeProcessProtocol or related threads.
+ ///
+ /// @return
+ /// true if the delegate was registered successfully;
+ /// false if the delegate was already registered.
+ ///
+ /// @see NativeProcessProtocol::NativeDelegate.
+ //------------------------------------------------------------------
+ bool
+ RegisterNativeDelegate (NativeDelegate &native_delegate);
+
+ //------------------------------------------------------------------
+ /// Unregister a native delegate previously registered.
+ ///
+ /// @param[in] native_delegate
+ /// A NativeDelegate impl previously registered with this process.
+ ///
+ /// @return Returns \b true if the NativeDelegate was
+ /// successfully removed from the process, \b false otherwise.
+ ///
+ /// @see NativeProcessProtocol::NativeDelegate
+ //------------------------------------------------------------------
+ bool
+ UnregisterNativeDelegate (NativeDelegate &native_delegate);
+
+ protected:
+ lldb::pid_t m_pid;
+
+ std::vector<NativeThreadProtocolSP> m_threads;
+ lldb::tid_t m_current_thread_id;
+ mutable Mutex m_threads_mutex;
+
+ lldb::StateType m_state;
+ mutable Mutex m_state_mutex;
+
+ lldb_private::ExitType m_exit_type;
+ int m_exit_status;
+ std::string m_exit_description;
+ Mutex m_delegates_mutex;
+ std::vector<NativeDelegate*> m_delegates;
+ NativeBreakpointList m_breakpoint_list;
+ int m_terminal_fd;
+ uint32_t m_stop_id;
+
+ // -----------------------------------------------------------
+ // Internal interface for state handling
+ // -----------------------------------------------------------
+ void
+ SetState (lldb::StateType state, bool notify_delegates = true);
+
+ // Derived classes need not impelment this. It can be used as a
+ // hook to clear internal caches that should be invalidated when
+ // stop ids change.
+ //
+ // Note this function is called with the state mutex obtained
+ // by the caller.
+ virtual void
+ DoStopIDBumped (uint32_t newBumpId);
+
+ // -----------------------------------------------------------
+ // Internal interface for software breakpoints
+ // -----------------------------------------------------------
+ Error
+ SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint);
+
+ virtual Error
+ GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) = 0;
+
+ private:
+
+ void
+ SynchronouslyNotifyProcessStateChanged (lldb::StateType state);
+ };
+}
+
+#endif // #ifndef liblldb_NativeProcessProtocol_h_
Added: lldb/trunk/source/Host/common/NativeThreadProtocol.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeThreadProtocol.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeThreadProtocol.cpp (added)
+++ lldb/trunk/source/Host/common/NativeThreadProtocol.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,97 @@
+//===-- NativeThreadProtocol.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadProtocol.h"
+
+#include "NativeProcessProtocol.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeThreadProtocol::NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) :
+ m_process_wp (process->shared_from_this ()),
+ m_tid (tid)
+{
+}
+
+Error
+NativeThreadProtocol::ReadRegister (uint32_t reg, RegisterValue ®_value)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+
+ const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+ if (!reg_info)
+ return Error ("no register info for reg num %" PRIu32, reg);
+
+ return register_context_sp->ReadRegister (reg_info, reg_value);;
+}
+
+Error
+NativeThreadProtocol::WriteRegister (uint32_t reg, const RegisterValue ®_value)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+
+ const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+ if (!reg_info)
+ return Error ("no register info for reg num %" PRIu32, reg);
+
+ return register_context_sp->WriteRegister (reg_info, reg_value);
+}
+
+Error
+NativeThreadProtocol::SaveAllRegisters (lldb::DataBufferSP &data_sp)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+ return register_context_sp->WriteAllRegisterValues (data_sp);
+}
+
+Error
+NativeThreadProtocol::RestoreAllRegisters (lldb::DataBufferSP &data_sp)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+ return register_context_sp->ReadAllRegisterValues (data_sp);
+}
+
+NativeProcessProtocolSP
+NativeThreadProtocol::GetProcess ()
+{
+ return m_process_wp.lock ();
+}
+
+uint32_t
+NativeThreadProtocol::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const
+{
+ // Default: no translation. Do the real translation where there
+ // is access to the host signal numbers.
+ switch (stop_info.reason)
+ {
+ case eStopReasonSignal:
+ return stop_info.details.signal.signo;
+ break;
+
+ case eStopReasonException:
+ // FIXME verify the way to specify pass-thru here.
+ return static_cast<uint32_t> (stop_info.details.exception.type);
+ break;
+
+ default:
+ assert (0 && "unexpected stop_info.reason found");
+ return 0;
+ }
+}
Added: lldb/trunk/source/Host/common/NativeThreadProtocol.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeThreadProtocol.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeThreadProtocol.h (added)
+++ lldb/trunk/source/Host/common/NativeThreadProtocol.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,85 @@
+//===-- NativeThreadProtocol.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_NativeThreadProtocol_h_
+#define liblldb_NativeThreadProtocol_h_
+
+#include <memory>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Debug.h"
+
+namespace lldb_private
+{
+ //------------------------------------------------------------------
+ // NativeThreadProtocol
+ //------------------------------------------------------------------
+ class NativeThreadProtocol:
+ public std::enable_shared_from_this<NativeThreadProtocol>
+ {
+ public:
+ NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid);
+
+ virtual ~NativeThreadProtocol()
+ {
+ }
+
+ virtual const char *
+ GetName() = 0;
+
+ virtual lldb::StateType
+ GetState () = 0;
+
+ virtual NativeRegisterContextSP
+ GetRegisterContext () = 0;
+
+ virtual Error
+ ReadRegister (uint32_t reg, RegisterValue ®_value);
+
+ virtual Error
+ WriteRegister (uint32_t reg, const RegisterValue ®_value);
+
+ virtual Error
+ SaveAllRegisters (lldb::DataBufferSP &data_sp);
+
+ virtual Error
+ RestoreAllRegisters (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ GetStopReason (ThreadStopInfo &stop_info) = 0;
+
+ virtual uint32_t
+ TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const;
+
+ lldb::tid_t
+ GetID() const
+ {
+ return m_tid;
+ }
+
+ NativeProcessProtocolSP
+ GetProcess ();
+
+ // ---------------------------------------------------------------------
+ // Thread-specific watchpoints
+ // ---------------------------------------------------------------------
+ virtual Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0;
+
+ virtual Error
+ RemoveWatchpoint (lldb::addr_t addr) = 0;
+
+ protected:
+ NativeProcessProtocolWP m_process_wp;
+ lldb::tid_t m_tid;
+ };
+}
+
+#endif // #ifndef liblldb_NativeThreadProtocol_h_
Added: lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp (added)
+++ lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,296 @@
+//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SoftwareBreakpoint.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/Mutex.h"
+
+#include "NativeProcessProtocol.h"
+
+using namespace lldb_private;
+
+// -------------------------------------------------------------------
+// static members
+// -------------------------------------------------------------------
+
+Error
+SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ // Validate the address.
+ if (addr == LLDB_INVALID_ADDRESS)
+ return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__);
+
+ // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint
+ // trap for the breakpoint site.
+ size_t bp_opcode_size = 0;
+ const uint8_t *bp_opcode_bytes = NULL;
+ Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes);
+
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Validate size of trap opcode.
+ if (bp_opcode_size == 0)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+ }
+
+ if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+ }
+
+ // Validate that we received opcodes.
+ if (!bp_opcode_bytes)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+ }
+
+ // Enable the breakpoint.
+ uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+ error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ());
+ return error;
+ }
+
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+ // Set the breakpoint and verified it was written properly. Now
+ // create a breakpoint remover that understands how to undo this
+ // breakpoint.
+ breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size));
+ return Error ();
+}
+
+Error
+SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes)
+{
+ assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range");
+ assert (bp_opcode_bytes && "bp_opcode_bytes is NULL");
+ assert (saved_opcode_bytes && "saved_opcode_bytes is NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ // Save the original opcodes by reading them so we can restore later.
+ lldb::addr_t bytes_read = 0;
+
+ Error error = process.ReadMemory(addr, saved_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we read as many bytes as we expected.
+ if (bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
+ return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
+ }
+
+ // Write a software breakpoint in place of the original opcode.
+ lldb::addr_t bytes_written = 0;
+ error = process.WriteMemory (addr, bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_written);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we wrote as many bytes as we expected.
+ if (bytes_written != static_cast<lldb::addr_t> (bp_opcode_size))
+ {
+ error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_written);
+ if (log)
+ log->PutCString (error.AsCString ());
+ return error;
+ }
+
+ uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+ lldb::addr_t verify_bytes_read = 0;
+ error = process.ReadMemory(addr, verify_bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), verify_bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we read as many verification bytes as we expected.
+ if (verify_bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
+ return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
+ }
+
+ if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+ return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+ }
+
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+ return Error ();
+}
+
+// -------------------------------------------------------------------
+// instance-level members
+// -------------------------------------------------------------------
+
+SoftwareBreakpoint::SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size) :
+ NativeBreakpoint (addr),
+ m_process (process),
+ m_saved_opcodes (),
+ m_trap_opcodes (),
+ m_opcode_size (opcode_size)
+{
+ assert ( opcode_size > 0 && "setting software breakpoint with no trap opcodes");
+ assert ( opcode_size <= MAX_TRAP_OPCODE_SIZE && "trap opcode size too large");
+
+ ::memcpy (m_saved_opcodes, saved_opcodes, opcode_size);
+ ::memcpy (m_trap_opcodes, trap_opcodes, opcode_size);
+}
+
+Error
+SoftwareBreakpoint::DoEnable ()
+{
+ return EnableSoftwareBreakpoint (m_process, m_addr, m_opcode_size, m_trap_opcodes, m_saved_opcodes);
+}
+
+Error
+SoftwareBreakpoint::DoDisable ()
+{
+ Error error;
+ assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr);
+
+ assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes");
+
+ if (m_opcode_size > 0)
+ {
+ // Clear a software breakoint instruction
+ uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE];
+ bool break_op_found = false;
+ assert (m_opcode_size <= sizeof (curr_break_op));
+
+ // Read the breakpoint opcode
+ lldb::addr_t bytes_read = 0;
+ error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read);
+ if (error.Success () && (bytes_read < static_cast<lldb::addr_t> (m_opcode_size)))
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_read);
+ }
+ if (error.Success ())
+ {
+ bool verify = false;
+ // Make sure we have the a breakpoint opcode exists at this address
+ if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0)
+ {
+ break_op_found = true;
+ // We found a valid breakpoint opcode at this address, now restore
+ // the saved opcode.
+ lldb::addr_t bytes_written = 0;
+ error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written);
+ if (error.Success () && (bytes_written < static_cast<lldb::addr_t> (m_opcode_size)))
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_written);
+ }
+ if (error.Success ())
+ {
+ verify = true;
+ }
+ }
+ else
+ {
+ error.SetErrorString("Original breakpoint trap is no longer in memory.");
+ // Set verify to true and so we can check if the original opcode has already been restored
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE];
+ assert (m_opcode_size <= sizeof (verify_opcode));
+ // Verify that our original opcode made it back to the inferior
+
+ lldb::addr_t verify_bytes_read = 0;
+ error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read);
+ if (error.Success () && (verify_bytes_read < static_cast<lldb::addr_t> (m_opcode_size)))
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, verify_bytes_read);
+ }
+ if (error.Success ())
+ {
+ // compare the memory we just read with the original opcode
+ if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0)
+ {
+ // SUCCESS
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr);
+ return error;
+ }
+ else
+ {
+ if (break_op_found)
+ error.SetErrorString("Failed to restore original opcode.");
+ }
+ }
+ else
+ error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+ }
+ }
+ }
+
+ if (log && error.Fail ())
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
+ __FUNCTION__,
+ m_addr,
+ error.AsCString());
+ return error;
+}
+
+bool
+SoftwareBreakpoint::IsSoftwareBreakpoint () const
+{
+ return true;
+}
+
Added: lldb/trunk/source/Host/common/SoftwareBreakpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/SoftwareBreakpoint.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/SoftwareBreakpoint.h (added)
+++ lldb/trunk/source/Host/common/SoftwareBreakpoint.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,51 @@
+//===-- SoftwareBreakpoint.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_SoftwareBreakpoint_h_
+#define liblldb_SoftwareBreakpoint_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "NativeBreakpoint.h"
+
+namespace lldb_private
+{
+ class SoftwareBreakpoint : public NativeBreakpoint
+ {
+ public:
+ static Error
+ CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_spn);
+
+ SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size);
+
+ protected:
+ Error
+ DoEnable () override;
+
+ Error
+ DoDisable () override;
+
+ bool
+ IsSoftwareBreakpoint () const override;
+
+ private:
+ /// Max number of bytes that a software trap opcode sequence can occupy.
+ static const size_t MAX_TRAP_OPCODE_SIZE = 8;
+
+ NativeProcessProtocol &m_process;
+ uint8_t m_saved_opcodes [MAX_TRAP_OPCODE_SIZE];
+ uint8_t m_trap_opcodes [MAX_TRAP_OPCODE_SIZE];
+ const size_t m_opcode_size;
+
+ static Error
+ EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes);
+
+ };
+}
+
+#endif // #ifndef liblldb_SoftwareBreakpoint_h_
Modified: lldb/trunk/source/Host/linux/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/linux/Host.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Host/linux/Host.cpp (original)
+++ lldb/trunk/source/Host/linux/Host.cpp Mon Jun 30 16:05:18 2014
@@ -175,6 +175,12 @@ Host::GetAuxvData(lldb_private::Process
return ProcFileReader::ReadIntoDataBuffer (process->GetID(), "auxv");
}
+lldb::DataBufferSP
+Host::GetAuxvData (lldb::pid_t pid)
+{
+ return ProcFileReader::ReadIntoDataBuffer (pid, "auxv");
+}
+
static bool
IsDirNumeric(const char *dname)
{
Modified: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp Mon Jun 30 16:05:18 2014
@@ -57,11 +57,10 @@ ParseAuxvEntry(DataExtractor &data,
DataBufferSP
AuxVector::GetAuxvData()
{
-#if defined(__linux__) || defined(__FreeBSD__)
- if (m_process->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
- return static_cast<ProcessElfCore *>(m_process)->GetAuxvData();
-#endif
- return lldb_private::Host::GetAuxvData(m_process);
+ if (m_process)
+ return m_process->GetAuxvData ();
+ else
+ return DataBufferSP ();
}
void
Modified: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp Mon Jun 30 16:05:18 2014
@@ -14,6 +14,7 @@
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@@ -28,21 +29,61 @@ using namespace lldb_private;
static addr_t
ResolveRendezvousAddress(Process *process)
{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
addr_t info_location;
addr_t info_addr;
Error error;
+ // Try to get it from our process. This might be a remote process and might
+ // grab it via some remote-specific mechanism.
info_location = process->GetImageInfoAddress();
+ if (log)
+ log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
+ // If the process fails to return an address, fall back to seeing if the local object file can help us find it.
if (info_location == LLDB_INVALID_ADDRESS)
+ {
+ Target *target = process ? &process->GetTarget() : nullptr;
+ if (target)
+ {
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(target);
+
+ if (addr.IsValid())
+ {
+ info_location = addr.GetLoadAddress(target);
+ if (log)
+ log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__);
+ }
+ }
+ }
+
+ if (info_location == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("%s FAILED - invalid info address", __FUNCTION__);
return LLDB_INVALID_ADDRESS;
+ }
info_addr = process->ReadPointerFromMemory(info_location, error);
if (error.Fail())
+ {
+ if (log)
+ log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ());
return LLDB_INVALID_ADDRESS;
+ }
if (info_addr == 0)
+ {
+ if (log)
+ log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location);
return LLDB_INVALID_ADDRESS;
+ }
return info_addr;
}
@@ -56,6 +97,8 @@ DYLDRendezvous::DYLDRendezvous(Process *
m_added_soentries(),
m_removed_soentries()
{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
m_thread_info.valid = false;
// Cache a copy of the executable path
@@ -63,13 +106,24 @@ DYLDRendezvous::DYLDRendezvous(Process *
{
Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
if (exe_mod)
+ {
exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+ if (log)
+ log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", __FUNCTION__, m_exe_path);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__);
+ }
}
}
bool
DYLDRendezvous::Resolve()
{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
const size_t word_size = 4;
Rendezvous info;
size_t address_size;
@@ -79,12 +133,16 @@ DYLDRendezvous::Resolve()
address_size = m_process->GetAddressByteSize();
padding = address_size - word_size;
+ if (log)
+ log->Printf ("DYLDRendezvous::%s address size: %zu, padding %zu", __FUNCTION__, address_size, padding);
if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
cursor = info_addr = ResolveRendezvousAddress(m_process);
else
cursor = info_addr = m_rendezvous_addr;
-
+ if (log)
+ log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor);
+
if (cursor == LLDB_INVALID_ADDRESS)
return false;
Modified: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp Mon Jun 30 16:05:18 2014
@@ -33,6 +33,10 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Process.h"
+#if defined(__linux__)
+#include "../../Process/Linux/NativeProcessLinux.h"
+#endif
+
using namespace lldb;
using namespace lldb_private;
@@ -487,3 +491,58 @@ PlatformLinux::CalculateTrapHandlerSymbo
{
m_trap_handlers.push_back (ConstString ("_sigtramp"));
}
+
+Error
+PlatformLinux::LaunchNativeProcess (
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+#if !defined(__linux__)
+ return Error("only implemented on Linux hosts");
+#else
+ if (!IsHost ())
+ return Error("PlatformLinux::%s (): cannot launch a debug process when not the host", __FUNCTION__);
+
+ // Retrieve the exe module.
+ lldb::ModuleSP exe_module_sp;
+
+ Error error = ResolveExecutable (
+ launch_info.GetExecutableFile (),
+ launch_info.GetArchitecture (),
+ exe_module_sp,
+ NULL);
+
+ if (!error.Success ())
+ return error;
+
+ if (!exe_module_sp)
+ return Error("exe_module_sp could not be resolved for %s", launch_info.GetExecutableFile ().GetPath ().c_str ());
+
+ // Launch it for debugging
+ error = NativeProcessLinux::LaunchProcess (
+ exe_module_sp.get (),
+ launch_info,
+ native_delegate,
+ process_sp);
+
+ return error;
+#endif
+}
+
+Error
+PlatformLinux::AttachNativeProcess (lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+#if !defined(__linux__)
+ return Error("only implemented on Linux hosts");
+#else
+ if (!IsHost ())
+ return Error("PlatformLinux::%s (): cannot attach to a debug process when not the host", __FUNCTION__);
+
+ // Launch it for debugging
+ return NativeProcessLinux::AttachToProcess (pid, native_delegate, process_sp);
+#endif
+}
+
Modified: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h (original)
+++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h Mon Jun 30 16:05:18 2014
@@ -103,9 +103,20 @@ namespace lldb_private {
virtual void
CalculateTrapHandlerSymbolNames ();
+ Error
+ LaunchNativeProcess (
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp) override;
+
+ Error
+ AttachNativeProcess (lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp) override;
+
protected:
lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote darwin OS
-
+
private:
DISALLOW_COPY_AND_ASSIGN (PlatformLinux);
};
Modified: lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -5,10 +5,11 @@ include_directories(../POSIX)
include_directories(../Utility)
add_lldb_library(lldbPluginProcessLinux
+ NativeProcessLinux.cpp
+ NativeThreadLinux.cpp
ProcessLinux.cpp
ProcessMonitor.cpp
ProcFileReader.cpp
- LinuxSignals.cpp
LinuxThread.cpp
)
Removed: lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp?rev=212068&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp (removed)
@@ -1,69 +0,0 @@
-//===-- LinuxSignals.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 <signal.h>
-
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "LinuxSignals.h"
-
-LinuxSignals::LinuxSignals()
- : UnixSignals()
-{
- Reset();
-}
-
-void
-LinuxSignals::Reset()
-{
- m_signals.clear();
-
-#define ADDSIGNAL(S, SUPPRESS, STOP, NOTIFY, DESCRIPTION) \
- AddSignal(SIG ## S, "SIG" #S, #S, SUPPRESS, STOP, NOTIFY, DESCRIPTION)
-
- ADDSIGNAL(HUP, false, true, true, "hangup");
- ADDSIGNAL(INT, true, true, true, "interrupt");
- ADDSIGNAL(QUIT, false, true, true, "quit");
- ADDSIGNAL(ILL, false, true, true, "illegal instruction");
- ADDSIGNAL(TRAP, true, true, true, "trace trap (not reset when caught)");
- ADDSIGNAL(ABRT, false, true, true, "abort");
- ADDSIGNAL(IOT, false, true, true, "abort");
- ADDSIGNAL(BUS, false, true, true, "bus error");
- ADDSIGNAL(FPE, false, true, true, "floating point exception");
- ADDSIGNAL(KILL, false, true, true, "kill");
- ADDSIGNAL(USR1, false, true, true, "user defined signal 1");
- ADDSIGNAL(SEGV, false, true, true, "segmentation violation");
- ADDSIGNAL(USR2, false, true, true, "user defined signal 2");
- ADDSIGNAL(PIPE, false, true, true, "write to pipe with reading end closed");
- ADDSIGNAL(ALRM, false, false, true, "alarm");
- ADDSIGNAL(TERM, false, true, true, "termination requested");
-#ifdef SIGSTKFLT
- ADDSIGNAL(STKFLT, false, true, true, "stack fault");
-#endif
- ADDSIGNAL(CHLD, false, false, true, "child process exit");
- ADDSIGNAL(CONT, false, true, true, "process continue");
- ADDSIGNAL(STOP, true, true, true, "process stop");
- ADDSIGNAL(TSTP, false, true, true, "tty stop");
- ADDSIGNAL(TTIN, false, true, true, "background tty read");
- ADDSIGNAL(TTOU, false, true, true, "background tty write");
- ADDSIGNAL(URG, false, true, true, "urgent data on socket");
- ADDSIGNAL(XCPU, false, true, true, "CPU resource exceeded");
- ADDSIGNAL(XFSZ, false, true, true, "file size limit exceeded");
- ADDSIGNAL(VTALRM, false, true, true, "virtual alarm");
- ADDSIGNAL(PROF, false, true, true, "profiling alarm");
- ADDSIGNAL(WINCH, false, true, true, "window size change");
- ADDSIGNAL(POLL, false, true, true, "pollable event");
- ADDSIGNAL(IO, false, true, true, "input/output ready");
- ADDSIGNAL(PWR, false, true, true, "power failure");
- ADDSIGNAL(SYS, false, true, true, "invalid system call");
-
-#undef ADDSIGNAL
-}
Removed: lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h?rev=212068&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h (removed)
@@ -1,31 +0,0 @@
-//===-- LinuxSignals.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_LinuxSignals_H_
-#define liblldb_LinuxSignals_H_
-
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Target/UnixSignals.h"
-
-/// Linux specific set of Unix signals.
-class LinuxSignals
- : public lldb_private::UnixSignals
-{
-public:
- LinuxSignals();
-
-private:
- void
- Reset();
-};
-
-#endif
Added: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,3465 @@
+//===-- NativeProcessLinux.cpp -------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "NativeProcessLinux.h"
+
+// C Includes
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+
+// C++ Includes
+#include <fstream>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include "Host/common/NativeBreakpoint.h"
+#include "Utility/StringExtractor.h"
+
+#include "Plugins/Process/Utility/LinuxSignals.h"
+#include "NativeThreadLinux.h"
+#include "ProcFileReader.h"
+#include "ProcessPOSIXLog.h"
+
+#define DEBUG_PTRACE_MAXBYTES 20
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS 12
+#endif
+#ifndef PTRACE_SETREGS
+ #define PTRACE_SETREGS 13
+#endif
+#ifndef PTRACE_GETREGSET
+ #define PTRACE_GETREGSET 0x4204
+#endif
+#ifndef PTRACE_SETREGSET
+ #define PTRACE_SETREGSET 0x4205
+#endif
+#ifndef PTRACE_GET_THREAD_AREA
+ #define PTRACE_GET_THREAD_AREA 25
+#endif
+#ifndef PTRACE_ARCH_PRCTL
+ #define PTRACE_ARCH_PRCTL 30
+#endif
+#ifndef ARCH_GET_FS
+ #define ARCH_SET_GS 0x1001
+ #define ARCH_SET_FS 0x1002
+ #define ARCH_GET_FS 0x1003
+ #define ARCH_GET_GS 0x1004
+#endif
+
+
+// Support hardware breakpoints in case it has not been defined
+#ifndef TRAP_HWBKPT
+ #define TRAP_HWBKPT 4
+#endif
+
+// Try to define a macro to encapsulate the tgkill syscall
+// fall back on kill() if tgkill isn't available
+#define tgkill(pid, tid, sig) syscall(SYS_tgkill, pid, tid, sig)
+
+// We disable the tracing of ptrace calls for integration builds to
+// avoid the additional indirection and checks.
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+#define PTRACE(req, pid, addr, data, data_size) \
+ PtraceWrapper((req), (pid), (addr), (data), (data_size), #req, __FILE__, __LINE__)
+#else
+#define PTRACE(req, pid, addr, data, data_size) \
+ PtraceWrapper((req), (pid), (addr), (data), (data_size))
+#endif
+
+// Private bits we only need internally.
+namespace
+{
+ using namespace lldb;
+ using namespace lldb_private;
+
+ const UnixSignals&
+ GetUnixSignals ()
+ {
+ static process_linux::LinuxSignals signals;
+ return signals;
+ }
+
+ const char *
+ GetFilePath (const lldb_private::ProcessLaunchInfo::FileAction *file_action, const char *default_path)
+ {
+ const char *pts_name = "/dev/pts/";
+ const char *path = NULL;
+
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ {
+ path = file_action->GetPath ();
+ // By default the stdio paths passed in will be pseudo-terminal
+ // (/dev/pts). If so, convert to using a different default path
+ // instead to redirect I/O to the debugger console. This should
+ // also handle user overrides to /dev/null or a different file.
+ if (!path || ::strncmp (path, pts_name, ::strlen (pts_name)) == 0)
+ path = default_path;
+ }
+ }
+
+ return path;
+ }
+
+ Error
+ ResolveProcessArchitecture (lldb::pid_t pid, Platform &platform, ArchSpec &arch)
+ {
+ // Grab process info for the running process.
+ ProcessInstanceInfo process_info;
+ if (!platform.GetProcessInfo (pid, process_info))
+ return lldb_private::Error("failed to get process info");
+
+ // Resolve the executable module.
+ ModuleSP exe_module_sp;
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths ());
+ Error error = platform.ResolveExecutable(
+ process_info.GetExecutableFile (),
+ platform.GetSystemArchitecture (),
+ exe_module_sp,
+ executable_search_paths.GetSize () ? &executable_search_paths : NULL);
+
+ if (!error.Success ())
+ return error;
+
+ // Check if we've got our architecture from the exe_module.
+ arch = exe_module_sp->GetArchitecture ();
+ if (arch.IsValid ())
+ return Error();
+ else
+ return Error("failed to retrieve a valid architecture from the exe module");
+ }
+
+ void
+ DisplayBytes (lldb_private::StreamString &s, void *bytes, uint32_t count)
+ {
+ uint8_t *ptr = (uint8_t *)bytes;
+ const uint32_t loop_count = std::min<uint32_t>(DEBUG_PTRACE_MAXBYTES, count);
+ for(uint32_t i=0; i<loop_count; i++)
+ {
+ s.Printf ("[%x]", *ptr);
+ ptr++;
+ }
+ }
+
+ void
+ PtraceDisplayBytes(int &req, void *data, size_t data_size)
+ {
+ StreamString buf;
+ Log *verbose_log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (
+ POSIX_LOG_PTRACE | POSIX_LOG_VERBOSE));
+
+ if (verbose_log)
+ {
+ switch(req)
+ {
+ case PTRACE_POKETEXT:
+ {
+ DisplayBytes(buf, &data, 8);
+ verbose_log->Printf("PTRACE_POKETEXT %s", buf.GetData());
+ break;
+ }
+ case PTRACE_POKEDATA:
+ {
+ DisplayBytes(buf, &data, 8);
+ verbose_log->Printf("PTRACE_POKEDATA %s", buf.GetData());
+ break;
+ }
+ case PTRACE_POKEUSER:
+ {
+ DisplayBytes(buf, &data, 8);
+ verbose_log->Printf("PTRACE_POKEUSER %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETREGS:
+ {
+ DisplayBytes(buf, data, data_size);
+ verbose_log->Printf("PTRACE_SETREGS %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETFPREGS:
+ {
+ DisplayBytes(buf, data, data_size);
+ verbose_log->Printf("PTRACE_SETFPREGS %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETSIGINFO:
+ {
+ DisplayBytes(buf, data, sizeof(siginfo_t));
+ verbose_log->Printf("PTRACE_SETSIGINFO %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETREGSET:
+ {
+ // Extract iov_base from data, which is a pointer to the struct IOVEC
+ DisplayBytes(buf, *(void **)data, data_size);
+ verbose_log->Printf("PTRACE_SETREGSET %s", buf.GetData());
+ break;
+ }
+ default:
+ {
+ }
+ }
+ }
+ }
+
+ // Wrapper for ptrace to catch errors and log calls.
+ // Note that ptrace sets errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*)
+ long
+ PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size,
+ const char* reqName, const char* file, int line)
+ {
+ long int result;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE));
+
+ PtraceDisplayBytes(req, data, data_size);
+
+ errno = 0;
+ if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
+ result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), *(unsigned int *)addr, data);
+ else
+ result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), addr, data);
+
+ if (log)
+ log->Printf("ptrace(%s, %" PRIu64 ", %p, %p, %zu)=%lX called from file %s line %d",
+ reqName, pid, addr, data, data_size, result, file, line);
+
+ PtraceDisplayBytes(req, data, data_size);
+
+ if (log && errno != 0)
+ {
+ const char* str;
+ switch (errno)
+ {
+ case ESRCH: str = "ESRCH"; break;
+ case EINVAL: str = "EINVAL"; break;
+ case EBUSY: str = "EBUSY"; break;
+ case EPERM: str = "EPERM"; break;
+ default: str = "<unknown>";
+ }
+ log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
+ }
+
+ return result;
+ }
+
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Wrapper for ptrace when logging is not required.
+ // Sets errno to 0 prior to calling ptrace.
+ long
+ PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size)
+ {
+ long result = 0;
+ errno = 0;
+ if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
+ result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), *(unsigned int *)addr, data);
+ else
+ result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), addr, data);
+ return result;
+ }
+#endif
+
+ //------------------------------------------------------------------------------
+ // Static implementations of NativeProcessLinux::ReadMemory and
+ // NativeProcessLinux::WriteMemory. This enables mutual recursion between these
+ // functions without needed to go thru the thread funnel.
+
+ static lldb::addr_t
+ DoReadMemory (
+ lldb::pid_t pid,
+ lldb::addr_t vm_addr,
+ void *buf,
+ lldb::addr_t size,
+ Error &error)
+ {
+ // ptrace word size is determined by the host, not the child
+ static const unsigned word_size = sizeof(void*);
+ unsigned char *dst = static_cast<unsigned char*>(buf);
+ lldb::addr_t bytes_read;
+ lldb::addr_t remainder;
+ long data;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL));
+ if (log)
+ ProcessPOSIXLog::IncNestLevel();
+ if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY))
+ log->Printf ("NativeProcessLinux::%s(%" PRIu64 ", %d, %p, %p, %zd, _)", __FUNCTION__,
+ pid, word_size, (void*)vm_addr, buf, size);
+
+ assert(sizeof(data) >= word_size);
+ for (bytes_read = 0; bytes_read < size; bytes_read += remainder)
+ {
+ errno = 0;
+ data = PTRACE(PTRACE_PEEKDATA, pid, (void*)vm_addr, NULL, 0);
+ if (errno)
+ {
+ error.SetErrorToErrno();
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return bytes_read;
+ }
+
+ remainder = size - bytes_read;
+ remainder = remainder > word_size ? word_size : remainder;
+
+ // Copy the data into our buffer
+ for (unsigned i = 0; i < remainder; ++i)
+ dst[i] = ((data >> i*8) & 0xFF);
+
+ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+ {
+ uintptr_t print_dst = 0;
+ // Format bytes from data by moving into print_dst for log output
+ for (unsigned i = 0; i < remainder; ++i)
+ print_dst |= (((data >> i*8) & 0xFF) << i*8);
+ log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+ (void*)vm_addr, print_dst, (unsigned long)data);
+ }
+
+ vm_addr += word_size;
+ dst += word_size;
+ }
+
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return bytes_read;
+ }
+
+ static lldb::addr_t
+ DoWriteMemory(
+ lldb::pid_t pid,
+ lldb::addr_t vm_addr,
+ const void *buf,
+ lldb::addr_t size,
+ Error &error)
+ {
+ // ptrace word size is determined by the host, not the child
+ static const unsigned word_size = sizeof(void*);
+ const unsigned char *src = static_cast<const unsigned char*>(buf);
+ lldb::addr_t bytes_written = 0;
+ lldb::addr_t remainder;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL));
+ if (log)
+ ProcessPOSIXLog::IncNestLevel();
+ if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY))
+ log->Printf ("NativeProcessLinux::%s(%" PRIu64 ", %u, %p, %p, %" PRIu64 ")", __FUNCTION__,
+ pid, word_size, (void*)vm_addr, buf, size);
+
+ 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;
+ assert(sizeof(data) >= word_size);
+ for (unsigned i = 0; i < word_size; ++i)
+ data |= (unsigned long)src[i] << i*8;
+
+ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+ log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+ (void*)vm_addr, *(unsigned long*)src, data);
+
+ if (PTRACE(PTRACE_POKEDATA, pid, (void*)vm_addr, (void*)data, 0))
+ {
+ error.SetErrorToErrno();
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return bytes_written;
+ }
+ }
+ else
+ {
+ unsigned char buff[8];
+ if (DoReadMemory(pid, vm_addr,
+ buff, word_size, error) != word_size)
+ {
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return bytes_written;
+ }
+
+ memcpy(buff, src, remainder);
+
+ if (DoWriteMemory(pid, vm_addr,
+ buff, word_size, error) != word_size)
+ {
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return bytes_written;
+ }
+
+ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+ log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+ (void*)vm_addr, *(unsigned long*)src, *(unsigned long*)buff);
+ }
+
+ vm_addr += word_size;
+ src += word_size;
+ }
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return bytes_written;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class Operation
+ /// @brief Represents a NativeProcessLinux 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 NativeProcessLinux 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
+ /// NativeProcessLinux must perform via the single virtual function Execute, thus
+ /// encapsulating the code that needs to run in the privileged context.
+ class Operation
+ {
+ public:
+ Operation () : m_error() { }
+
+ virtual
+ ~Operation() {}
+
+ virtual void
+ Execute (NativeProcessLinux *process) = 0;
+
+ const Error &
+ GetError () const { return m_error; }
+
+ protected:
+ Error m_error;
+ };
+
+ //------------------------------------------------------------------------------
+ /// @class ReadOperation
+ /// @brief Implements NativeProcessLinux::ReadMemory.
+ class ReadOperation : public Operation
+ {
+ public:
+ ReadOperation (
+ lldb::addr_t addr,
+ void *buff,
+ lldb::addr_t size,
+ size_t &result) :
+ Operation (),
+ m_addr (addr),
+ m_buff (buff),
+ m_size (size),
+ m_result (result)
+ {
+ }
+
+ void Execute (NativeProcessLinux *process) override;
+
+ private:
+ lldb::addr_t m_addr;
+ void *m_buff;
+ lldb::addr_t m_size;
+ lldb::addr_t &m_result;
+ };
+
+ void
+ ReadOperation::Execute (NativeProcessLinux *process)
+ {
+ m_result = DoReadMemory (process->GetID (), m_addr, m_buff, m_size, m_error);
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class WriteOperation
+ /// @brief Implements NativeProcessLinux::WriteMemory.
+ class WriteOperation : public Operation
+ {
+ public:
+ WriteOperation (
+ lldb::addr_t addr,
+ const void *buff,
+ lldb::addr_t size,
+ lldb::addr_t &result) :
+ Operation (),
+ m_addr (addr),
+ m_buff (buff),
+ m_size (size),
+ m_result (result)
+ {
+ }
+
+ void Execute (NativeProcessLinux *process) override;
+
+ private:
+ lldb::addr_t m_addr;
+ const void *m_buff;
+ lldb::addr_t m_size;
+ lldb::addr_t &m_result;
+ };
+
+ void
+ WriteOperation::Execute(NativeProcessLinux *process)
+ {
+ m_result = DoWriteMemory (process->GetID (), m_addr, m_buff, m_size, m_error);
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class ReadRegOperation
+ /// @brief Implements NativeProcessLinux::ReadRegisterValue.
+ class ReadRegOperation : public Operation
+ {
+ public:
+ ReadRegOperation(lldb::tid_t tid, uint32_t offset, const char *reg_name,
+ RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(static_cast<uintptr_t> (offset)), m_reg_name(reg_name),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ uintptr_t m_offset;
+ const char *m_reg_name;
+ RegisterValue &m_value;
+ bool &m_result;
+ };
+
+ void
+ ReadRegOperation::Execute(NativeProcessLinux *monitor)
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+
+ // Set errno to zero so that we can detect a failed peek.
+ errno = 0;
+ lldb::addr_t data = PTRACE(PTRACE_PEEKUSER, m_tid, (void*)m_offset, NULL, 0);
+ if (errno)
+ m_result = false;
+ else
+ {
+ m_value = data;
+ m_result = true;
+ }
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() reg %s: 0x%" PRIx64, __FUNCTION__,
+ m_reg_name, data);
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class WriteRegOperation
+ /// @brief Implements NativeProcessLinux::WriteRegisterValue.
+ class WriteRegOperation : public Operation
+ {
+ public:
+ WriteRegOperation(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ const RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset), m_reg_name(reg_name),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ uintptr_t m_offset;
+ const char *m_reg_name;
+ const RegisterValue &m_value;
+ bool &m_result;
+ };
+
+ void
+ WriteRegOperation::Execute(NativeProcessLinux *monitor)
+ {
+ void* buf;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+
+ buf = (void*) m_value.GetAsUInt64();
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() reg %s: %p", __FUNCTION__, m_reg_name, buf);
+ if (PTRACE(PTRACE_POKEUSER, m_tid, (void*)m_offset, buf, 0))
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class ReadGPROperation
+ /// @brief Implements NativeProcessLinux::ReadGPR.
+ class ReadGPROperation : public Operation
+ {
+ public:
+ ReadGPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+ : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ size_t m_buf_size;
+ bool &m_result;
+ };
+
+ void
+ ReadGPROperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_GETREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class ReadFPROperation
+ /// @brief Implements NativeProcessLinux::ReadFPR.
+ class ReadFPROperation : public Operation
+ {
+ public:
+ ReadFPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+ : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ size_t m_buf_size;
+ bool &m_result;
+ };
+
+ void
+ ReadFPROperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_GETFPREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class ReadRegisterSetOperation
+ /// @brief Implements NativeProcessLinux::ReadRegisterSet.
+ class ReadRegisterSetOperation : public Operation
+ {
+ public:
+ ReadRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result)
+ : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ size_t m_buf_size;
+ const unsigned int m_regset;
+ bool &m_result;
+ };
+
+ void
+ ReadRegisterSetOperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_GETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0)
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class WriteGPROperation
+ /// @brief Implements NativeProcessLinux::WriteGPR.
+ class WriteGPROperation : public Operation
+ {
+ public:
+ WriteGPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+ : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ size_t m_buf_size;
+ bool &m_result;
+ };
+
+ void
+ WriteGPROperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_SETREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class WriteFPROperation
+ /// @brief Implements NativeProcessLinux::WriteFPR.
+ class WriteFPROperation : public Operation
+ {
+ public:
+ WriteFPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+ : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ size_t m_buf_size;
+ bool &m_result;
+ };
+
+ void
+ WriteFPROperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_SETFPREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class WriteRegisterSetOperation
+ /// @brief Implements NativeProcessLinux::WriteRegisterSet.
+ class WriteRegisterSetOperation : public Operation
+ {
+ public:
+ WriteRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result)
+ : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result)
+ { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ size_t m_buf_size;
+ const unsigned int m_regset;
+ bool &m_result;
+ };
+
+ void
+ WriteRegisterSetOperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_SETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0)
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class ResumeOperation
+ /// @brief Implements NativeProcessLinux::Resume.
+ class ResumeOperation : public Operation
+ {
+ public:
+ ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) :
+ m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+ };
+
+ void
+ ResumeOperation::Execute(NativeProcessLinux *monitor)
+ {
+ intptr_t data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PTRACE_CONT, m_tid, NULL, (void*)data, 0))
+ {
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno));
+ m_result = false;
+ }
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class SingleStepOperation
+ /// @brief Implements NativeProcessLinux::SingleStep.
+ class SingleStepOperation : public Operation
+ {
+ public:
+ SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result)
+ : m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+ };
+
+ void
+ SingleStepOperation::Execute(NativeProcessLinux *monitor)
+ {
+ intptr_t data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PTRACE_SINGLESTEP, m_tid, NULL, (void*)data, 0))
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class SiginfoOperation
+ /// @brief Implements NativeProcessLinux::GetSignalInfo.
+ class SiginfoOperation : public Operation
+ {
+ public:
+ SiginfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err)
+ : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ void *m_info;
+ bool &m_result;
+ int &m_err;
+ };
+
+ void
+ SiginfoOperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_GETSIGINFO, m_tid, NULL, m_info, 0)) {
+ m_result = false;
+ m_err = errno;
+ }
+ else
+ m_result = true;
+ }
+
+ //------------------------------------------------------------------------------
+ /// @class EventMessageOperation
+ /// @brief Implements NativeProcessLinux::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(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ unsigned long *m_message;
+ bool &m_result;
+ };
+
+ void
+ EventMessageOperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (PTRACE(PTRACE_GETEVENTMSG, m_tid, NULL, m_message, 0))
+ m_result = false;
+ else
+ m_result = true;
+ }
+
+ class DetachOperation : public Operation
+ {
+ public:
+ DetachOperation(lldb::tid_t tid, Error &result) : m_tid(tid), m_error(result) { }
+
+ void Execute(NativeProcessLinux *monitor);
+
+ private:
+ lldb::tid_t m_tid;
+ Error &m_error;
+ };
+
+ void
+ DetachOperation::Execute(NativeProcessLinux *monitor)
+ {
+ if (ptrace(PT_DETACH, m_tid, NULL, 0) < 0)
+ m_error.SetErrorToErrno();
+ }
+
+}
+
+using namespace lldb_private;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static bool
+EnsureFDFlags(int fd, int flags, Error &error)
+{
+ int status;
+
+ if ((status = fcntl(fd, F_GETFL)) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ return true;
+}
+
+NativeProcessLinux::OperationArgs::OperationArgs(NativeProcessLinux *monitor)
+ : m_monitor(monitor)
+{
+ sem_init(&m_semaphore, 0, 0);
+}
+
+NativeProcessLinux::OperationArgs::~OperationArgs()
+{
+ sem_destroy(&m_semaphore);
+}
+
+NativeProcessLinux::LaunchArgs::LaunchArgs(NativeProcessLinux *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir)
+ : OperationArgs(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),
+ m_working_dir(working_dir) { }
+
+NativeProcessLinux::LaunchArgs::~LaunchArgs()
+{ }
+
+NativeProcessLinux::AttachArgs::AttachArgs(NativeProcessLinux *monitor,
+ lldb::pid_t pid)
+ : OperationArgs(monitor), m_pid(pid) { }
+
+NativeProcessLinux::AttachArgs::~AttachArgs()
+{ }
+
+// -----------------------------------------------------------------------------
+// Public Static Methods
+// -----------------------------------------------------------------------------
+
+lldb_private::Error
+NativeProcessLinux::LaunchProcess (
+ lldb_private::Module *exe_module,
+ lldb_private::ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &native_process_sp)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ Error error;
+
+ // Verify the working directory is valid if one was specified.
+ const char* working_dir = launch_info.GetWorkingDirectory ();
+ if (working_dir)
+ {
+ FileSpec working_dir_fs (working_dir, true);
+ if (!working_dir_fs || working_dir_fs.GetFileType () != FileSpec::eFileTypeDirectory)
+ {
+ error.SetErrorStringWithFormat ("No such file or directory: %s", working_dir);
+ return error;
+ }
+ }
+
+ const lldb_private::ProcessLaunchInfo::FileAction *file_action;
+
+ // Default of NULL will mean to use existing open file descriptors.
+ const char *stdin_path = NULL;
+ const char *stdout_path = NULL;
+ const char *stderr_path = NULL;
+
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ stdin_path = GetFilePath (file_action, stdin_path);
+
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ stdout_path = GetFilePath (file_action, stdout_path);
+
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ stderr_path = GetFilePath (file_action, stderr_path);
+
+ // Create the NativeProcessLinux in launch mode.
+ native_process_sp.reset (new NativeProcessLinux ());
+
+ if (log)
+ {
+ int i = 0;
+ for (const char **args = launch_info.GetArguments ().GetConstArgumentVector (); *args; ++args, ++i)
+ {
+ log->Printf ("NativeProcessLinux::%s arg %d: \"%s\"", __FUNCTION__, i, *args ? *args : "nullptr");
+ ++i;
+ }
+ }
+
+ if (!native_process_sp->RegisterNativeDelegate (native_delegate))
+ {
+ native_process_sp.reset ();
+ error.SetErrorStringWithFormat ("failed to register the native delegate");
+ return error;
+ }
+
+ reinterpret_cast<NativeProcessLinux*> (native_process_sp.get ())->LaunchInferior (
+ exe_module,
+ launch_info.GetArguments ().GetConstArgumentVector (),
+ launch_info.GetEnvironmentEntries ().GetConstArgumentVector (),
+ stdin_path,
+ stdout_path,
+ stderr_path,
+ working_dir,
+ error);
+
+ if (error.Fail ())
+ {
+ native_process_sp.reset ();
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed to launch process: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ launch_info.SetProcessID (native_process_sp->GetID ());
+
+ return error;
+}
+
+lldb_private::Error
+NativeProcessLinux::AttachToProcess (
+ lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &native_process_sp)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log && log->GetMask ().Test (POSIX_LOG_VERBOSE))
+ log->Printf ("NativeProcessLinux::%s(pid = %" PRIi64 ")", __FUNCTION__, pid);
+
+ // Grab the current platform architecture. This should be Linux,
+ // since this code is only intended to run on a Linux host.
+ PlatformSP platform_sp (Platform::GetDefaultPlatform ());
+ if (!platform_sp)
+ return Error("failed to get a valid default platform");
+
+ // Retrieve the architecture for the running process.
+ ArchSpec process_arch;
+ Error error = ResolveProcessArchitecture (pid, *platform_sp.get (), process_arch);
+ if (!error.Success ())
+ return error;
+
+ native_process_sp.reset (new NativeProcessLinux ());
+
+ if (!native_process_sp->RegisterNativeDelegate (native_delegate))
+ {
+ native_process_sp.reset (new NativeProcessLinux ());
+ error.SetErrorStringWithFormat ("failed to register the native delegate");
+ return error;
+ }
+
+ reinterpret_cast<NativeProcessLinux*> (native_process_sp.get ())->AttachToInferior (pid, error);
+ if (!error.Success ())
+ {
+ native_process_sp.reset ();
+ return error;
+ }
+
+ return error;
+}
+
+// -----------------------------------------------------------------------------
+// Public Instance Methods
+// -----------------------------------------------------------------------------
+
+NativeProcessLinux::NativeProcessLinux () :
+ NativeProcessProtocol (LLDB_INVALID_PROCESS_ID),
+ m_arch (),
+ m_operation_thread (LLDB_INVALID_HOST_THREAD),
+ m_monitor_thread (LLDB_INVALID_HOST_THREAD),
+ m_operation (nullptr),
+ m_operation_mutex (),
+ m_operation_pending (),
+ m_operation_done (),
+ m_wait_for_stop_tids (),
+ m_wait_for_stop_tids_mutex (),
+ m_supports_mem_region (eLazyBoolCalculate),
+ m_mem_region_cache (),
+ m_mem_region_cache_mutex ()
+{
+}
+
+//------------------------------------------------------------------------------
+/// The basic design of the NativeProcessLinux 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)
+/// launching 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.
+void
+NativeProcessLinux::LaunchInferior (
+ Module *module,
+ const char *argv[],
+ const char *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ lldb_private::Error &error)
+{
+ if (module)
+ m_arch = module->GetArchitecture ();
+
+ SetState(eStateLaunching);
+
+ std::unique_ptr<LaunchArgs> args(
+ new LaunchArgs(
+ this, module, argv, envp,
+ stdin_path, stdout_path, stderr_path,
+ working_dir));
+
+ sem_init(&m_operation_pending, 0, 0);
+ sem_init(&m_operation_done, 0, 0);
+
+ StartLaunchOpThread(args.get(), 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())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess(
+ NativeProcessLinux::MonitorCallback, this, GetID(), true);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Process attach failed to create monitor thread for NativeProcessLinux::MonitorCallback.");
+ return;
+ }
+}
+
+void
+NativeProcessLinux::AttachToInferior (lldb::pid_t pid, lldb_private::Error &error)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ")", __FUNCTION__, pid);
+
+ // We can use the Host for everything except the ResolveExecutable portion.
+ PlatformSP platform_sp = Platform::GetDefaultPlatform ();
+ if (!platform_sp)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 "): no default platform set", __FUNCTION__, pid);
+ error.SetErrorString ("no default platform available");
+ }
+
+ // Gather info about the process.
+ ProcessInstanceInfo process_info;
+ platform_sp->GetProcessInfo (pid, process_info);
+
+ // Resolve the executable module
+ ModuleSP exe_module_sp;
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+
+ error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(),
+ Host::GetArchitecture(),
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ if (!error.Success())
+ return;
+
+ // Set the architecture to the exe architecture.
+ m_arch = exe_module_sp->GetArchitecture();
+ if (log)
+ log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ") detected architecture %s", __FUNCTION__, pid, m_arch.GetArchitectureName ());
+
+ m_pid = pid;
+ SetState(eStateAttaching);
+
+ sem_init (&m_operation_pending, 0, 0);
+ sem_init (&m_operation_done, 0, 0);
+
+ std::unique_ptr<AttachArgs> args (new AttachArgs (this, pid));
+
+ StartAttachOpThread(args.get (), 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 attach was a success.
+ if (!args->m_error.Success ())
+ {
+ StopOpThread ();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess (
+ NativeProcessLinux::MonitorCallback, this, GetID (), true);
+ if (!IS_VALID_LLDB_HOST_THREAD (m_monitor_thread))
+ {
+ error.SetErrorToGenericError ();
+ error.SetErrorString ("Process attach failed to create monitor thread for NativeProcessLinux::MonitorCallback.");
+ return;
+ }
+}
+
+NativeProcessLinux::~NativeProcessLinux()
+{
+ StopMonitor();
+}
+
+//------------------------------------------------------------------------------
+// Thread setup and tear down.
+
+void
+NativeProcessLinux::StartLaunchOpThread(LaunchArgs *args, Error &error)
+{
+ static const char *g_thread_name = "lldb.process.nativelinux.operation";
+
+ if (IS_VALID_LLDB_HOST_THREAD (m_operation_thread))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate (g_thread_name, LaunchOpThread, args, &error);
+}
+
+void *
+NativeProcessLinux::LaunchOpThread(void *arg)
+{
+ LaunchArgs *args = static_cast<LaunchArgs*>(arg);
+
+ if (!Launch(args)) {
+ sem_post(&args->m_semaphore);
+ return NULL;
+ }
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+NativeProcessLinux::Launch(LaunchArgs *args)
+{
+ NativeProcessLinux *monitor = args->m_monitor;
+ assert (monitor && "monitor is NULL");
+ if (!monitor)
+ return false;
+
+ 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;
+ const char *working_dir = args->m_working_dir;
+
+ lldb_utility::PseudoTerminal terminal;
+ const size_t err_len = 1024;
+ char err_str[err_len];
+ lldb::pid_t pid;
+ NativeThreadProtocolSP thread_sp;
+
+ lldb::ThreadSP inferior;
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Propagate the environment if one is not supplied.
+ if (envp == NULL || envp[0] == NULL)
+ envp = const_cast<const char **>(environ);
+
+ if ((pid = terminal.Fork(err_str, err_len)) == static_cast<lldb::pid_t> (-1))
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Process fork failed.");
+ goto FINISH;
+ }
+
+ // Recognized child exit status codes.
+ enum {
+ ePtraceFailed = 1,
+ eDupStdinFailed,
+ eDupStdoutFailed,
+ eDupStderrFailed,
+ eChdirFailed,
+ eExecFailed,
+ eSetGidFailed
+ };
+
+ // Child process.
+ if (pid == 0)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior process preparing to fork", __FUNCTION__);
+
+ // Trace this process.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior process issuing PTRACE_TRACEME", __FUNCTION__);
+
+ if (PTRACE(PTRACE_TRACEME, 0, NULL, NULL, 0) < 0)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior process PTRACE_TRACEME failed", __FUNCTION__);
+ exit(ePtraceFailed);
+ }
+
+ // Do not inherit setgid powers.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior process resetting gid", __FUNCTION__);
+
+ if (setgid(getgid()) != 0)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior process setgid() failed", __FUNCTION__);
+ exit(eSetGidFailed);
+ }
+
+ // Attempt to have our own process group.
+ // TODO verify if we really want this.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior process resetting process group", __FUNCTION__);
+
+ if (setpgid(0, 0) != 0)
+ {
+ if (log)
+ {
+ const int error_code = errno;
+ log->Printf ("NativeProcessLinux::%s inferior setpgid() failed, errno=%d (%s), continuing with existing proccess group %" PRIu64,
+ __FUNCTION__,
+ error_code,
+ strerror (error_code),
+ static_cast<lldb::pid_t> (getpgid (0)));
+ }
+ // Don't allow this to prevent an inferior exec.
+ }
+
+ // Dup file descriptors 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))
+ exit(eDupStdinFailed);
+
+ if (stdout_path != NULL && stdout_path[0])
+ if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStdoutFailed);
+
+ if (stderr_path != NULL && stderr_path[0])
+ if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStderrFailed);
+
+ // Change working directory
+ if (working_dir != NULL && working_dir[0])
+ if (0 != ::chdir(working_dir))
+ exit(eChdirFailed);
+
+ // Execute. We should never return.
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ exit(eExecFailed);
+ }
+
+ // Wait for the child process to trap on its call to execve.
+ ::pid_t wpid;
+ int status;
+ if ((wpid = waitpid(pid, &status, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s waitpid for inferior failed with %s", __FUNCTION__, args->m_error.AsCString ());
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ monitor->SetState (StateType::eStateInvalid);
+
+ goto FINISH;
+ }
+ else if (WIFEXITED(status))
+ {
+ // open, dup or execve likely failed for some reason.
+ args->m_error.SetErrorToGenericError();
+ switch (WEXITSTATUS(status))
+ {
+ case ePtraceFailed:
+ args->m_error.SetErrorString("Child ptrace failed.");
+ break;
+ case eDupStdinFailed:
+ args->m_error.SetErrorString("Child open stdin failed.");
+ break;
+ case eDupStdoutFailed:
+ args->m_error.SetErrorString("Child open stdout failed.");
+ break;
+ case eDupStderrFailed:
+ args->m_error.SetErrorString("Child open stderr failed.");
+ break;
+ case eChdirFailed:
+ args->m_error.SetErrorString("Child failed to set working directory.");
+ break;
+ case eExecFailed:
+ args->m_error.SetErrorString("Child exec failed.");
+ break;
+ case eSetGidFailed:
+ args->m_error.SetErrorString("Child setgid failed.");
+ break;
+ default:
+ args->m_error.SetErrorString("Child returned unknown exit status.");
+ break;
+ }
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s inferior exited with status %d before issuing a STOP",
+ __FUNCTION__,
+ WEXITSTATUS(status));
+ }
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ monitor->SetState (StateType::eStateInvalid);
+
+ goto FINISH;
+ }
+ assert(WIFSTOPPED(status) && (wpid == static_cast<::pid_t> (pid)) &&
+ "Could not sync with inferior process.");
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior started, now in stopped state", __FUNCTION__);
+
+ if (!SetDefaultPtraceOpts(pid))
+ {
+ args->m_error.SetErrorToErrno();
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior failed to set default ptrace options: %s",
+ __FUNCTION__,
+ args->m_error.AsCString ());
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ monitor->SetState (StateType::eStateInvalid);
+
+ goto FINISH;
+ }
+
+ // Release the master terminal descriptor and pass it off to the
+ // NativeProcessLinux instance. Similarly stash the inferior pid.
+ monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ monitor->m_pid = pid;
+
+ // Set the terminal fd to be in non blocking mode (it simplifies the
+ // implementation of ProcessLinux::GetSTDOUT to have a non-blocking
+ // descriptor to read from).
+ if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior EnsureFDFlags failed for ensuring terminal O_NONBLOCK setting: %s",
+ __FUNCTION__,
+ args->m_error.AsCString ());
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ monitor->SetState (StateType::eStateInvalid);
+
+ goto FINISH;
+ }
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
+
+ thread_sp = monitor->AddThread (static_cast<lldb::tid_t> (pid));
+ assert (thread_sp && "AddThread() returned a nullptr thread");
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGSTOP);
+ monitor->SetCurrentThreadID (thread_sp->GetID ());
+
+ // Let our process instance know the thread has stopped.
+ monitor->SetState (StateType::eStateStopped);
+
+FINISH:
+ if (log)
+ {
+ if (args->m_error.Success ())
+ {
+ log->Printf ("NativeProcessLinux::%s inferior launching succeeded", __FUNCTION__);
+ }
+ else
+ {
+ log->Printf ("NativeProcessLinux::%s inferior launching failed: %s",
+ __FUNCTION__,
+ args->m_error.AsCString ());
+ }
+ }
+ return args->m_error.Success();
+}
+
+void
+NativeProcessLinux::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
+{
+ static const char *g_thread_name = "lldb.process.linux.operation";
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
+}
+
+void *
+NativeProcessLinux::AttachOpThread(void *arg)
+{
+ AttachArgs *args = static_cast<AttachArgs*>(arg);
+
+ if (!Attach(args)) {
+ sem_post(&args->m_semaphore);
+ return NULL;
+ }
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+NativeProcessLinux::Attach(AttachArgs *args)
+{
+ lldb::pid_t pid = args->m_pid;
+
+ NativeProcessLinux *monitor = args->m_monitor;
+ lldb::ThreadSP inferior;
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Use a map to keep track of the threads which we have attached/need to attach.
+ Host::TidMap tids_to_attach;
+ if (pid <= 1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
+ goto FINISH;
+ }
+
+ while (Host::FindProcessThreads(pid, tids_to_attach))
+ {
+ for (Host::TidMap::iterator it = tids_to_attach.begin();
+ it != tids_to_attach.end();)
+ {
+ if (it->second == false)
+ {
+ lldb::tid_t tid = it->first;
+
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ if (PTRACE(PTRACE_ATTACH, tid, NULL, NULL, 0) < 0)
+ {
+ // No such thread. The thread may have exited.
+ // More error handling may be needed.
+ if (errno == ESRCH)
+ {
+ it = tids_to_attach.erase(it);
+ continue;
+ }
+ else
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ }
+
+ int status;
+ // Need to use __WALL otherwise we receive an error with errno=ECHLD
+ // At this point we should have a thread stopped if waitpid succeeds.
+ if ((status = waitpid(tid, NULL, __WALL)) < 0)
+ {
+ // No such thread. The thread may have exited.
+ // More error handling may be needed.
+ if (errno == ESRCH)
+ {
+ it = tids_to_attach.erase(it);
+ continue;
+ }
+ else
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ }
+
+ if (!SetDefaultPtraceOpts(tid))
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
+
+ it->second = true;
+
+ // Create the thread, mark it as stopped.
+ NativeThreadProtocolSP thread_sp (monitor->AddThread (static_cast<lldb::tid_t> (tid)));
+ assert (thread_sp && "AddThread() returned a nullptr");
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGSTOP);
+ monitor->SetCurrentThreadID (thread_sp->GetID ());
+ }
+
+ // move the loop forward
+ ++it;
+ }
+ }
+
+ if (tids_to_attach.size() > 0)
+ {
+ monitor->m_pid = pid;
+ // Let our process instance know the thread has stopped.
+ monitor->SetState (StateType::eStateStopped);
+ }
+ else
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("No such process.");
+ }
+
+ FINISH:
+ return args->m_error.Success();
+}
+
+bool
+NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid)
+{
+ long ptrace_opts = 0;
+
+ // Have the child raise an event on exit. This is used to keep the child in
+ // limbo until it is destroyed.
+ ptrace_opts |= PTRACE_O_TRACEEXIT;
+
+ // Have the tracer trace threads which spawn in the inferior process.
+ // TODO: if we want to support tracing the inferiors' child, add the
+ // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
+ ptrace_opts |= PTRACE_O_TRACECLONE;
+
+ // Have the tracer notify us before execve returns
+ // (needed to disable legacy SIGTRAP generation)
+ ptrace_opts |= PTRACE_O_TRACEEXEC;
+
+ return PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts, 0) >= 0;
+}
+
+static ExitType convert_pid_status_to_exit_type (int status)
+{
+ if (WIFEXITED (status))
+ return ExitType::eExitTypeExit;
+ else if (WIFSIGNALED (status))
+ return ExitType::eExitTypeSignal;
+ else if (WIFSTOPPED (status))
+ return ExitType::eExitTypeStop;
+ else
+ {
+ // We don't know what this is.
+ return ExitType::eExitTypeInvalid;
+ }
+}
+
+static int convert_pid_status_to_return_code (int status)
+{
+ if (WIFEXITED (status))
+ return WEXITSTATUS (status);
+ else if (WIFSIGNALED (status))
+ return WTERMSIG (status);
+ else if (WIFSTOPPED (status))
+ return WSTOPSIG (status);
+ else
+ {
+ // We don't know what this is.
+ return ExitType::eExitTypeInvalid;
+ }
+}
+
+// Main process monitoring waitpid-loop handler.
+bool
+NativeProcessLinux::MonitorCallback(void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ NativeProcessLinux *const process = static_cast<NativeProcessLinux*>(callback_baton);
+ assert (process && "process is null");
+ if (!process)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " callback_baton was null, can't determine process to use", __FUNCTION__, pid);
+ return true;
+ }
+
+ // Certain activities differ based on whether the pid is the tid of the main thread.
+ const bool is_main_thread = (pid == process->GetID ());
+
+ // Assume we keep monitoring by default.
+ bool stop_monitoring = false;
+
+ // Handle when the thread exits.
+ if (exited)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() got exit signal, tid = %" PRIu64 " (%s main thread)", __FUNCTION__, pid, is_main_thread ? "is" : "is not");
+
+ // This is a thread that exited. Ensure we're not tracking it anymore.
+ const bool thread_found = process->StopTrackingThread (pid);
+
+ if (is_main_thread)
+ {
+ // We only set the exit status and notify the delegate if we haven't already set the process
+ // state to an exited state. We normally should have received a SIGTRAP | (PTRACE_EVENT_EXIT << 8)
+ // for the main thread.
+ const bool already_notified = (process->GetState() == StateType::eStateExited) | (process->GetState () == StateType::eStateCrashed);
+ if (!already_notified)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " handling main thread exit (%s), expected exit state already set but state was %s instead, setting exit state now", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found", StateAsCString (process->GetState ()));
+ // The main thread exited. We're done monitoring. Report to delegate.
+ process->SetExitStatus (convert_pid_status_to_exit_type (status), convert_pid_status_to_return_code (status), nullptr, true);
+
+ // Notify delegate that our process has exited.
+ process->SetState (StateType::eStateExited, true);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " main thread now exited (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found");
+ }
+ return true;
+ }
+ else
+ {
+ // Do we want to report to the delegate in this case? I think not. If this was an orderly
+ // thread exit, we would already have received the SIGTRAP | (PTRACE_EVENT_EXIT << 8) signal,
+ // and we would have done an all-stop then.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " handling non-main thread exit (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found");
+
+ // Not the main thread, we keep going.
+ return false;
+ }
+ }
+
+ // Get details on the signal raised.
+ siginfo_t info;
+ int ptrace_err = 0;
+
+ if (!process->GetSignalInfo (pid, &info, ptrace_err))
+ {
+ if (ptrace_err == EINVAL)
+ {
+ // This is the first part of the Linux ptrace group-stop mechanism.
+ // The tracer (i.e. NativeProcessLinux) is expected to inject the signal
+ // into the tracee (i.e. inferior) at this point.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() resuming from group-stop", __FUNCTION__);
+
+ // The inferior process is in 'group-stop', so deliver the stopping signal.
+ const bool signal_delivered = process->Resume (pid, info.si_signo);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " group-stop signal delivery of signal 0x%x (%s) - %s", __FUNCTION__, pid, info.si_signo, GetUnixSignals ().GetSignalAsCString (info.si_signo), signal_delivered ? "success" : "failed");
+
+ assert(signal_delivered && "SIGSTOP delivery failed while in 'group-stop' state");
+
+ stop_monitoring = false;
+ }
+ else
+ {
+ // ptrace(GETSIGINFO) failed (but not due to group-stop).
+
+ // A return value of ESRCH means the thread/process is no longer on the system,
+ // so it was killed somehow outside of our control. Either way, we can't do anything
+ // with it anymore.
+
+ // We stop monitoring if it was the main thread.
+ stop_monitoring = is_main_thread;
+
+ // Stop tracking the metadata for the thread since it's entirely off the system now.
+ const bool thread_found = process->StopTrackingThread (pid);
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d (%s, %s, %s)",
+ __FUNCTION__, strerror(ptrace_err), pid, signal, status, ptrace_err == ESRCH ? "thread/process killed" : "unknown reason", is_main_thread ? "is main thread" : "is not main thread", thread_found ? "thread metadata removed" : "thread metadata not found");
+
+ if (is_main_thread)
+ {
+ // Notify the delegate - our process is not available but appears to have been killed outside
+ // our control. Is eStateExited the right exit state in this case?
+ process->SetExitStatus (convert_pid_status_to_exit_type (status), convert_pid_status_to_return_code (status), nullptr, true);
+ process->SetState (StateType::eStateExited, true);
+ }
+ else
+ {
+ // This thread was pulled out from underneath us. Anything to do here? Do we want to do an all stop?
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " non-main thread exit occurred, didn't tell delegate anything since thread disappeared out from underneath us", __FUNCTION__, process->GetID (), pid);
+ }
+ }
+ }
+ else
+ {
+ // We have retrieved the signal info. Dispatch appropriately.
+ if (info.si_signo == SIGTRAP)
+ process->MonitorSIGTRAP(&info, pid);
+ else
+ process->MonitorSignal(&info, pid, exited);
+
+ stop_monitoring = false;
+ }
+
+ return stop_monitoring;
+}
+
+void
+NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ const bool is_main_thread = (pid == GetID ());
+
+ assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
+ if (!info)
+ return;
+
+ // See if we can find a thread for this signal.
+ NativeThreadProtocolSP thread_sp = GetThreadByID (pid);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " no thread found for tid %" PRIu64, __FUNCTION__, GetID (), pid);
+ }
+
+ switch (info->si_code)
+ {
+ // TODO: these two cases are required if we want to support tracing of the inferiors' children. We'd need this to debug a monitor.
+ // case (SIGTRAP | (PTRACE_EVENT_FORK << 8)):
+ // case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)):
+
+ case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)):
+ {
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+
+ unsigned long event_message = 0;
+ if (GetEventMessage(pid, &event_message))
+ tid = static_cast<lldb::tid_t> (event_message);
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " received thread creation event for tid %" PRIu64, __FUNCTION__, pid, tid);
+
+ // If we don't track the thread yet: create it, mark as stopped.
+ // If we do track it, this is the wait we needed. Now resume the new thread.
+ // In all cases, resume the current (i.e. main process) thread.
+ bool already_tracked = false;
+ thread_sp = GetOrCreateThread (tid, already_tracked);
+ assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
+
+ // If the thread was already tracked, it means the created thread already received its SI_USER notification of creation.
+ if (already_tracked)
+ {
+ // FIXME loops like we want to stop all theads here.
+ // StopAllThreads
+
+ // We can now resume the newly created thread since it is fully created.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+ Resume (tid, LLDB_INVALID_SIGNAL_NUMBER);
+ }
+ else
+ {
+ // Mark the thread as currently launching. Need to wait for SIGTRAP clone on the main thread before
+ // this thread is ready to go.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetLaunching ();
+ }
+
+ // In all cases, we can resume the main thread here.
+ Resume (pid, LLDB_INVALID_SIGNAL_NUMBER);
+ break;
+ }
+
+ case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)):
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received exec event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP);
+ // FIXME stop all threads, mark thread stop reason as ThreadStopInfo.reason = eStopReasonExec;
+ break;
+
+ case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
+ {
+ // The inferior process or one of its threads is about to exit.
+ // Maintain the process or thread in a state of "limbo" until we are
+ // explicitly commanded to detach, destroy, resume, etc.
+ unsigned long data = 0;
+ if (!GetEventMessage(pid, &data))
+ data = -1;
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s() received PTRACE_EVENT_EXIT, data = %lx (WIFEXITED=%s,WIFSIGNALED=%s), pid = %" PRIu64 " (%s)",
+ __FUNCTION__,
+ data, WIFEXITED (data) ? "true" : "false", WIFSIGNALED (data) ? "true" : "false",
+ pid,
+ is_main_thread ? "is main thread" : "not main thread");
+ }
+
+ // Set the thread to exited.
+ if (thread_sp)
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetExited ();
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " failed to retrieve thread for tid %" PRIu64", cannot set thread state", __FUNCTION__, GetID (), pid);
+ }
+
+ if (is_main_thread)
+ {
+ SetExitStatus (convert_pid_status_to_exit_type (data), convert_pid_status_to_return_code (data), nullptr, true);
+ // Resume the thread so it completely exits.
+ Resume (pid, LLDB_INVALID_SIGNAL_NUMBER);
+ }
+ else
+ {
+ // FIXME figure out the path where we plan to reap the metadata for the thread.
+ }
+
+ break;
+ }
+
+ case 0:
+ case TRAP_TRACE:
+ // We receive this on single stepping.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)", __FUNCTION__, pid);
+
+ if (thread_sp)
+ {
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+ SetCurrentThreadID (thread_sp->GetID ());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 " single stepping received trace but thread not found", __FUNCTION__, GetID (), pid);
+ }
+
+ // Tell the process we have a stop (from single stepping).
+ SetState (StateType::eStateStopped, true);
+ break;
+
+ case SI_KERNEL:
+ case TRAP_BRKPT:
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
+
+ // Mark the thread as stopped at breakpoint.
+ if (thread_sp)
+ {
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+ Error error = FixupBreakpointPCAsNeeded (thread_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s", __FUNCTION__, pid, error.AsCString ());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 ": warning, cannot process software breakpoint since no thread metadata", __FUNCTION__, pid);
+ }
+
+
+ // Tell the process we have a stop from this thread.
+ SetCurrentThreadID (pid);
+ SetState (StateType::eStateStopped, true);
+ break;
+
+ case TRAP_HWBKPT:
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received watchpoint event, pid = %" PRIu64, __FUNCTION__, pid);
+
+ // Mark the thread as stopped at watchpoint.
+ // The address is at (lldb::addr_t)info->si_addr if we need it.
+ if (thread_sp)
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ": warning, cannot process hardware breakpoint since no thread metadata", __FUNCTION__, GetID (), pid);
+ }
+
+ // Tell the process we have a stop from this thread.
+ SetCurrentThreadID (pid);
+ SetState (StateType::eStateStopped, true);
+ break;
+
+ case SIGTRAP:
+ case (SIGTRAP | 0x80):
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received system call stop event, pid %" PRIu64 "tid %" PRIu64, __FUNCTION__, GetID (), pid);
+ // Ignore these signals until we know more about them.
+ Resume(pid, 0);
+ break;
+
+ default:
+ assert(false && "Unexpected SIGTRAP code!");
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 "tid %" PRIu64 " received unhandled SIGTRAP code: 0x%" PRIx64, __FUNCTION__, GetID (), pid, static_cast<uint64_t> (SIGTRAP | (PTRACE_EVENT_CLONE << 8)));
+ break;
+
+ }
+}
+
+void
+NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited)
+{
+ int signo = info->si_signo;
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
+ // kill(2) or raise(3). Similarly for tgkill(2) on Linux.
+ //
+ // IOW, user generated signals never generate what we consider to be a
+ // "crash".
+ //
+ // Similarly, ACK signals generated by this monitor.
+
+ // See if we can find a thread for this signal.
+ NativeThreadProtocolSP thread_sp = GetThreadByID (pid);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " no thread found for tid %" PRIu64, __FUNCTION__, GetID (), pid);
+ }
+
+ // Handle the signal.
+ if (info->si_code == SI_TKILL || info->si_code == SI_USER)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received signal %s (%d) with code %s, (siginfo pid = %d (%s), waitpid pid = %" PRIu64 ")",
+ __FUNCTION__,
+ GetUnixSignals ().GetSignalAsCString (signo),
+ signo,
+ (info->si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"),
+ info->si_pid,
+ (info->si_pid == getpid ()) ? "is monitor" : "is not monitor",
+ pid);
+
+ if ((info->si_pid == 0) && info->si_code == SI_USER)
+ {
+ // A new thread creation is being signaled. This is one of two parts that come in
+ // a non-deterministic order. pid is the thread id.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": new thread notification",
+ __FUNCTION__, GetID (), pid);
+
+ // Did we already create the thread?
+ bool already_tracked = false;
+ thread_sp = GetOrCreateThread (pid, already_tracked);
+ assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
+
+ // If the thread was already tracked, it means the main thread already received its SIGTRAP for the create.
+ if (already_tracked)
+ {
+ // We can now resume this thread up since it is fully created.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+ Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
+ }
+ else
+ {
+ // Mark the thread as currently launching. Need to wait for SIGTRAP clone on the main thread before
+ // this thread is ready to go.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetLaunching ();
+ }
+ }
+ else if (info->si_pid == getpid () && (signo == SIGSTOP))
+ {
+ // This is a tgkill()-based stop.
+ if (thread_sp)
+ {
+ // An inferior thread just stopped. Mark it as such.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
+ SetCurrentThreadID (thread_sp->GetID ());
+
+ // Remove this tid from the wait-for-stop set.
+ Mutex::Locker locker (m_wait_for_stop_tids_mutex);
+
+ auto removed_count = m_wait_for_stop_tids.erase (thread_sp->GetID ());
+ if (removed_count < 1)
+ {
+ log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": tgkill()-stopped thread not in m_wait_for_stop_tids",
+ __FUNCTION__, GetID (), thread_sp->GetID ());
+
+ }
+
+ // If this is the last thread in the m_wait_for_stop_tids, we need to notify
+ // the delegate that a stop has occurred now that every thread that was supposed
+ // to stop has stopped.
+ if (m_wait_for_stop_tids.empty ())
+ {
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", setting process state to stopped now that all tids marked for stop have completed",
+ __FUNCTION__,
+ GetID (),
+ pid);
+ }
+ SetState (StateType::eStateStopped, true);
+ }
+ }
+ }
+ else
+ {
+ // Hmm, not sure what to do with this.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " unsure how to handle SI_KILL or SI_USER signal", __FUNCTION__, GetID ());
+ }
+
+ return;
+ }
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received signal %s", __FUNCTION__, GetUnixSignals ().GetSignalAsCString (signo));
+
+ switch (signo)
+ {
+ case SIGSEGV:
+ {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+
+ // FIXME figure out how to propagate this properly. Seems like it
+ // should go in ThreadStopInfo.
+ // We can get more details on the exact nature of the crash here.
+ // ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
+ if (!exited)
+ {
+ // This is just a pre-signal-delivery notification of the incoming signal.
+ // Send a stop to the debugger.
+ if (thread_sp)
+ {
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
+ SetCurrentThreadID (thread_sp->GetID ());
+ }
+ SetState (StateType::eStateStopped, true);
+ }
+ else
+ {
+ if (thread_sp)
+ {
+ // FIXME figure out what type this is.
+ const uint64_t exception_type = static_cast<uint64_t> (SIGSEGV);
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetCrashedWithException (exception_type, fault_addr);
+ }
+ SetState (StateType::eStateCrashed, true);
+ }
+ }
+ break;
+
+ case SIGILL:
+ {
+ // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ // Can get the reason from here.
+ // ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info);
+ // FIXME save the crash reason
+ SetState (StateType::eStateCrashed, true);
+ }
+ break;
+
+ case SIGFPE:
+ {
+ // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ // Can get the crash reason from below.
+ // ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info);
+ // FIXME save the crash reason
+ SetState (StateType::eStateCrashed, true);
+ }
+ break;
+
+ case SIGBUS:
+ {
+ // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ // Can get the crash reason from below.
+ // ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info);
+ // FIXME save the crash reason
+ SetState (StateType::eStateCrashed);
+ }
+ break;
+
+ default:
+ // FIXME Stop all threads here.
+ break;
+ }
+}
+
+Error
+NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
+{
+ Error error;
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s called: pid %" PRIu64, __FUNCTION__, GetID ());
+
+ int run_thread_count = 0;
+ int stop_thread_count = 0;
+ int step_thread_count = 0;
+
+ std::vector<NativeThreadProtocolSP> new_stop_threads;
+
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not contain NULL threads");
+ NativeThreadLinux *const linux_thread_p = reinterpret_cast<NativeThreadLinux*> (thread_sp.get ());
+
+ const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true);
+ assert (action && "NULL ResumeAction returned for thread during Resume ()");
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s processing resume action state %s for pid %" PRIu64 " tid %" PRIu64,
+ __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+ }
+
+ switch (action->state)
+ {
+ case eStateRunning:
+ // Run the thread, possibly feeding it the signal.
+ linux_thread_p->SetRunning ();
+ if (action->signal > 0)
+ {
+ // Resume the thread and deliver the given signal,
+ // then mark as delivered.
+ Resume (thread_sp->GetID (), action->signal);
+ resume_actions.SetSignalHandledForThread (thread_sp->GetID ());
+ }
+ else
+ {
+ // Just resume the thread with no signal.
+ Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
+ }
+ ++run_thread_count;
+ break;
+
+ case eStateStepping:
+ // Note: if we have multiple threads, we may need to stop
+ // the other threads first, then step this one.
+ linux_thread_p->SetStepping ();
+ if (SingleStep (thread_sp->GetID (), 0))
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step succeeded",
+ __FUNCTION__, GetID (), thread_sp->GetID ());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step failed",
+ __FUNCTION__, GetID (), thread_sp->GetID ());
+ }
+ ++step_thread_count;
+ break;
+
+ case eStateSuspended:
+ case eStateStopped:
+ if (!StateIsStoppedState (linux_thread_p->GetState (), false))
+ new_stop_threads.push_back (thread_sp);
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s no need to stop pid %" PRIu64 " tid %" PRIu64 ", thread state already %s",
+ __FUNCTION__, GetID (), thread_sp->GetID (), StateAsCString (linux_thread_p->GetState ()));
+ }
+
+ ++stop_thread_count;
+ break;
+
+ default:
+ return Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+ }
+ }
+
+ // If any thread was set to run, notify the process state as running.
+ if (run_thread_count > 0)
+ SetState (StateType::eStateRunning, true);
+
+ // Now do a tgkill SIGSTOP on each thread we want to stop.
+ if (!new_stop_threads.empty ())
+ {
+ // Lock the m_wait_for_stop_tids set so we can fill it with every thread we expect to have stopped.
+ Mutex::Locker stop_thread_id_locker (m_wait_for_stop_tids_mutex);
+ for (auto thread_sp : new_stop_threads)
+ {
+ // Send a stop signal to the thread.
+ const int result = tgkill (GetID (), thread_sp->GetID (), SIGSTOP);
+ if (result != 0)
+ {
+ // tgkill failed.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s error: tgkill SIGSTOP for pid %" PRIu64 " tid %" PRIu64 "failed, retval %d",
+ __FUNCTION__, GetID (), thread_sp->GetID (), result);
+ }
+ else
+ {
+ // tgkill succeeded. Don't mark the thread state, though. Let the signal
+ // handling mark it.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s tgkill SIGSTOP for pid %" PRIu64 " tid %" PRIu64 " succeeded",
+ __FUNCTION__, GetID (), thread_sp->GetID ());
+
+ // Add it to the set of threads we expect to signal a stop.
+ // We won't tell the delegate about it until this list drains to empty.
+ m_wait_for_stop_tids.insert (thread_sp->GetID ());
+ }
+ }
+ }
+
+ return error;
+}
+
+Error
+NativeProcessLinux::Halt ()
+{
+ Error error;
+
+ // FIXME check if we're already stopped
+ const bool is_stopped = false;
+ if (is_stopped)
+ return error;
+
+ if (kill (GetID (), SIGSTOP) != 0)
+ error.SetErrorToErrno ();
+
+ return error;
+}
+
+Error
+NativeProcessLinux::Detach ()
+{
+ Error error;
+
+ // Tell ptrace to detach from the process.
+ if (GetID () != LLDB_INVALID_PROCESS_ID)
+ error = Detach (GetID ());
+
+ // Stop monitoring the inferior.
+ StopMonitor ();
+
+ // No error.
+ return error;
+}
+
+Error
+NativeProcessLinux::Signal (int signo)
+{
+ Error error;
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s: sending signal %d (%s) to pid %" PRIu64,
+ __FUNCTION__, signo, GetUnixSignals ().GetSignalAsCString (signo), GetID ());
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+NativeProcessLinux::Kill ()
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s called for PID %" PRIu64, __FUNCTION__, GetID ());
+
+ Error error;
+
+ switch (m_state)
+ {
+ case StateType::eStateInvalid:
+ case StateType::eStateExited:
+ case StateType::eStateCrashed:
+ case StateType::eStateDetached:
+ case StateType::eStateUnloaded:
+ // Nothing to do - the process is already dead.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s ignored for PID %" PRIu64 " due to current state: %s", __FUNCTION__, GetID (), StateAsCString (m_state));
+ return error;
+
+ case StateType::eStateConnected:
+ case StateType::eStateAttaching:
+ case StateType::eStateLaunching:
+ case StateType::eStateStopped:
+ case StateType::eStateRunning:
+ case StateType::eStateStepping:
+ case StateType::eStateSuspended:
+ // We can try to kill a process in these states.
+ break;
+ }
+
+ if (kill (GetID (), SIGKILL) != 0)
+ {
+ error.SetErrorToErrno ();
+ return error;
+ }
+
+ return error;
+}
+
+static Error
+ParseMemoryRegionInfoFromProcMapsLine (const std::string &maps_line, MemoryRegionInfo &memory_region_info)
+{
+ memory_region_info.Clear();
+
+ StringExtractor line_extractor (maps_line.c_str ());
+
+ // Format: {address_start_hex}-{address_end_hex} perms offset dev inode pathname
+ // perms: rwxp (letter is present if set, '-' if not, final character is p=private, s=shared).
+
+ // Parse out the starting address
+ lldb::addr_t start_address = line_extractor.GetHexMaxU64 (false, 0);
+
+ // Parse out hyphen separating start and end address from range.
+ if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != '-'))
+ return Error ("malformed /proc/{pid}/maps entry, missing dash between address range");
+
+ // Parse out the ending address
+ lldb::addr_t end_address = line_extractor.GetHexMaxU64 (false, start_address);
+
+ // Parse out the space after the address.
+ if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != ' '))
+ return Error ("malformed /proc/{pid}/maps entry, missing space after range");
+
+ // Save the range.
+ memory_region_info.GetRange ().SetRangeBase (start_address);
+ memory_region_info.GetRange ().SetRangeEnd (end_address);
+
+ // Parse out each permission entry.
+ if (line_extractor.GetBytesLeft () < 4)
+ return Error ("malformed /proc/{pid}/maps entry, missing some portion of permissions");
+
+ // Handle read permission.
+ const char read_perm_char = line_extractor.GetChar ();
+ if (read_perm_char == 'r')
+ memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eYes);
+ else
+ {
+ assert ( (read_perm_char == '-') && "unexpected /proc/{pid}/maps read permission char" );
+ memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
+ }
+
+ // Handle write permission.
+ const char write_perm_char = line_extractor.GetChar ();
+ if (write_perm_char == 'w')
+ memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eYes);
+ else
+ {
+ assert ( (write_perm_char == '-') && "unexpected /proc/{pid}/maps write permission char" );
+ memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
+ }
+
+ // Handle execute permission.
+ const char exec_perm_char = line_extractor.GetChar ();
+ if (exec_perm_char == 'x')
+ memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eYes);
+ else
+ {
+ assert ( (exec_perm_char == '-') && "unexpected /proc/{pid}/maps exec permission char" );
+ memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
+ }
+
+ return Error ();
+}
+
+Error
+NativeProcessLinux::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
+{
+ // FIXME review that the final memory region returned extends to the end of the virtual address space,
+ // with no perms if it is not mapped.
+
+ // Use an approach that reads memory regions from /proc/{pid}/maps.
+ // Assume proc maps entries are in ascending order.
+ // FIXME assert if we find differently.
+ Mutex::Locker locker (m_mem_region_cache_mutex);
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ Error error;
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo)
+ {
+ // We're done.
+ error.SetErrorString ("unsupported");
+ return error;
+ }
+
+ // If our cache is empty, pull the latest. There should always be at least one memory region
+ // if memory region handling is supported.
+ if (m_mem_region_cache.empty ())
+ {
+ error = ProcFileReader::ProcessLineByLine (GetID (), "maps",
+ [&] (const std::string &line) -> bool
+ {
+ MemoryRegionInfo info;
+ const Error parse_error = ParseMemoryRegionInfoFromProcMapsLine (line, info);
+ if (parse_error.Success ())
+ {
+ m_mem_region_cache.push_back (info);
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed to parse proc maps line '%s': %s", __FUNCTION__, line.c_str (), error.AsCString ());
+ return false;
+ }
+ });
+
+ // If we had an error, we'll mark unsupported.
+ if (error.Fail ())
+ {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return error;
+ }
+ else if (m_mem_region_cache.empty ())
+ {
+ // No entries after attempting to read them. This shouldn't happen if /proc/{pid}/maps
+ // is supported. Assume we don't support map entries via procfs.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed to find any procfs maps entries, assuming no support for memory region metadata retrieval", __FUNCTION__);
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ error.SetErrorString ("not supported");
+ return error;
+ }
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s read %" PRIu64 " memory region entries from /proc/%" PRIu64 "/maps", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()), GetID ());
+
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s reusing %" PRIu64 " cached memory region entries", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()));
+ }
+
+ lldb::addr_t prev_base_address = 0;
+
+ // FIXME start by finding the last region that is <= target address using binary search. Data is sorted.
+ // There can be a ton of regions on pthreads apps with lots of threads.
+ for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end (); ++it)
+ {
+ MemoryRegionInfo &proc_entry_info = *it;
+
+ // Sanity check assumption that /proc/{pid}/maps entries are ascending.
+ assert ((proc_entry_info.GetRange ().GetRangeBase () >= prev_base_address) && "descending /proc/pid/maps entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange ().GetRangeBase ();
+
+ // If the target address comes before this entry, indicate distance to next region.
+ if (load_addr < proc_entry_info.GetRange ().GetRangeBase ())
+ {
+ range_info.GetRange ().SetRangeBase (load_addr);
+ range_info.GetRange ().SetByteSize (proc_entry_info.GetRange ().GetRangeBase () - load_addr);
+ range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
+
+ return error;
+ }
+ else if (proc_entry_info.GetRange ().Contains (load_addr))
+ {
+ // The target address is within the memory region we're processing here.
+ range_info = proc_entry_info;
+ return error;
+ }
+
+ // The target memory address comes somewhere after the region we just parsed.
+ }
+
+ // If we made it here, we didn't find an entry that contained the given address.
+ error.SetErrorString ("address comes after final region");
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed to find map entry for address 0x%" PRIx64 ": %s", __FUNCTION__, load_addr, error.AsCString ());
+
+ return error;
+}
+
+void
+NativeProcessLinux::DoStopIDBumped (uint32_t newBumpId)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s(newBumpId=%" PRIu32 ") called", __FUNCTION__, newBumpId);
+
+ {
+ Mutex::Locker locker (m_mem_region_cache_mutex);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s clearing %" PRIu64 " entries from the cache", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()));
+ m_mem_region_cache.clear ();
+ }
+}
+
+Error
+NativeProcessLinux::AllocateMemory (
+ lldb::addr_t size,
+ uint32_t permissions,
+ lldb::addr_t &addr)
+{
+ // FIXME implementing this requires the equivalent of
+ // InferiorCallPOSIX::InferiorCallMmap, which depends on
+ // functional ThreadPlans working with Native*Protocol.
+#if 1
+ return Error ("not implemented yet");
+#else
+ addr = LLDB_INVALID_ADDRESS;
+
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ // TODO implement this directly in NativeProcessLinux
+ // (and lift to NativeProcessPOSIX if/when that class is
+ // refactored out).
+ if (InferiorCallMmap(this, addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
+ m_addr_to_mmap_size[addr] = size;
+ return Error ();
+ } else {
+ addr = LLDB_INVALID_ADDRESS;
+ return Error("unable to allocate %" PRIu64 " bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
+ }
+#endif
+}
+
+Error
+NativeProcessLinux::DeallocateMemory (lldb::addr_t addr)
+{
+ // FIXME see comments in AllocateMemory - required lower-level
+ // bits not in place yet (ThreadPlans)
+ return Error ("not implemented");
+}
+
+lldb::addr_t
+NativeProcessLinux::GetSharedLibraryInfoAddress ()
+{
+#if 1
+ // punt on this for now
+ return LLDB_INVALID_ADDRESS;
+#else
+ // Return the image info address for the exe module
+#if 1
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ ModuleSP module_sp;
+ Error error = GetExeModuleSP (module_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Warning ("NativeProcessLinux::%s failed to retrieve exe module: %s", __FUNCTION__, error.AsCString ());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ if (module_sp == nullptr)
+ {
+ if (log)
+ log->Warning ("NativeProcessLinux::%s exe module returned was NULL", __FUNCTION__);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ ObjectFileSP object_file_sp = module_sp->GetObjectFile ();
+ if (object_file_sp == nullptr)
+ {
+ if (log)
+ log->Warning ("NativeProcessLinux::%s exe module returned a NULL object file", __FUNCTION__);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ return obj_file_sp->GetImageInfoAddress();
+#else
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(target);
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ return LLDB_INVALID_ADDRESS;
+#endif
+#endif // punt on this for now
+}
+
+size_t
+NativeProcessLinux::UpdateThreads ()
+{
+ // The NativeProcessLinux monitoring threads are always up to date
+ // with respect to thread state and they keep the thread list
+ // populated properly. All this method needs to do is return the
+ // thread count.
+ Mutex::Locker locker (m_threads_mutex);
+ return m_threads.size ();
+}
+
+bool
+NativeProcessLinux::GetArchitecture (ArchSpec &arch) const
+{
+ arch = m_arch;
+ return true;
+}
+
+Error
+NativeProcessLinux::GetSoftwareBreakpointSize (NativeRegisterContextSP context_sp, uint32_t &actual_opcode_size)
+{
+ // FIXME put this behind a breakpoint protocol class that can be
+ // set per architecture. Need ARM, MIPS support here.
+ static const uint8_t g_i386_opcode [] = { 0xCC };
+
+ switch (m_arch.GetMachine ())
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ actual_opcode_size = static_cast<uint32_t> (sizeof(g_i386_opcode));
+ return Error ();
+
+ default:
+ assert(false && "CPU type not supported!");
+ return Error ("CPU type not supported");
+ }
+}
+
+Error
+NativeProcessLinux::SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware)
+{
+ if (hardware)
+ return Error ("NativeProcessLinux does not support hardware breakpoints");
+ else
+ return SetSoftwareBreakpoint (addr, size);
+}
+
+Error
+NativeProcessLinux::GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes)
+{
+ // FIXME put this behind a breakpoint protocol class that can be
+ // set per architecture. Need ARM, MIPS support here.
+ static const uint8_t g_i386_opcode [] = { 0xCC };
+
+ switch (m_arch.GetMachine ())
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ trap_opcode_bytes = g_i386_opcode;
+ actual_opcode_size = sizeof(g_i386_opcode);
+ return Error ();
+
+ default:
+ assert(false && "CPU type not supported!");
+ return Error ("CPU type not supported");
+ }
+}
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGSEGV(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGSEGV);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGSEGV");
+ break;
+ case SI_KERNEL:
+ // Linux will occasionally send spurious SI_KERNEL codes.
+ // (this is poorly documented in sigaction)
+ // One way to get this is via unaligned SIMD loads.
+ reason = ProcessMessage::eInvalidAddress; // for lack of anything better
+ break;
+ case SEGV_MAPERR:
+ reason = ProcessMessage::eInvalidAddress;
+ break;
+ case SEGV_ACCERR:
+ reason = ProcessMessage::ePrivilegedAddress;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGILL(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGILL);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGILL");
+ break;
+ case ILL_ILLOPC:
+ reason = ProcessMessage::eIllegalOpcode;
+ break;
+ case ILL_ILLOPN:
+ reason = ProcessMessage::eIllegalOperand;
+ break;
+ case ILL_ILLADR:
+ reason = ProcessMessage::eIllegalAddressingMode;
+ break;
+ case ILL_ILLTRP:
+ reason = ProcessMessage::eIllegalTrap;
+ break;
+ case ILL_PRVOPC:
+ reason = ProcessMessage::ePrivilegedOpcode;
+ break;
+ case ILL_PRVREG:
+ reason = ProcessMessage::ePrivilegedRegister;
+ break;
+ case ILL_COPROC:
+ reason = ProcessMessage::eCoprocessorError;
+ break;
+ case ILL_BADSTK:
+ reason = ProcessMessage::eInternalStackError;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGFPE(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGFPE);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGFPE");
+ break;
+ case FPE_INTDIV:
+ reason = ProcessMessage::eIntegerDivideByZero;
+ break;
+ case FPE_INTOVF:
+ reason = ProcessMessage::eIntegerOverflow;
+ break;
+ case FPE_FLTDIV:
+ reason = ProcessMessage::eFloatDivideByZero;
+ break;
+ case FPE_FLTOVF:
+ reason = ProcessMessage::eFloatOverflow;
+ break;
+ case FPE_FLTUND:
+ reason = ProcessMessage::eFloatUnderflow;
+ break;
+ case FPE_FLTRES:
+ reason = ProcessMessage::eFloatInexactResult;
+ break;
+ case FPE_FLTINV:
+ reason = ProcessMessage::eFloatInvalidOperation;
+ break;
+ case FPE_FLTSUB:
+ reason = ProcessMessage::eFloatSubscriptRange;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGBUS(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGBUS);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGBUS");
+ break;
+ case BUS_ADRALN:
+ reason = ProcessMessage::eIllegalAlignment;
+ break;
+ case BUS_ADRERR:
+ reason = ProcessMessage::eIllegalAddress;
+ break;
+ case BUS_OBJERR:
+ reason = ProcessMessage::eHardwareError;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+void
+NativeProcessLinux::ServeOperation(OperationArgs *args)
+{
+ NativeProcessLinux *monitor = args->m_monitor;
+
+ // We are finised with the arguments and are ready to go. Sync with the
+ // parent thread and start serving operations on the inferior.
+ sem_post(&args->m_semaphore);
+
+ for(;;)
+ {
+ // wait for next pending operation
+ if (sem_wait(&monitor->m_operation_pending))
+ {
+ if (errno == EINTR)
+ continue;
+ assert(false && "Unexpected errno from sem_wait");
+ }
+
+ reinterpret_cast<Operation*>(monitor->m_operation)->Execute(monitor);
+
+ // notify calling thread that operation is complete
+ sem_post(&monitor->m_operation_done);
+ }
+}
+
+void
+NativeProcessLinux::DoOperation(void *op)
+{
+ Mutex::Locker lock(m_operation_mutex);
+
+ m_operation = op;
+
+ // notify operation thread that an operation is ready to be processed
+ sem_post(&m_operation_pending);
+
+ // wait for operation to complete
+ while (sem_wait(&m_operation_done))
+ {
+ if (errno == EINTR)
+ continue;
+ assert(false && "Unexpected errno from sem_wait");
+ }
+}
+
+Error
+NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read)
+{
+ ReadOperation op(addr, buf, size, bytes_read);
+ DoOperation(&op);
+ return op.GetError ();
+}
+
+Error
+NativeProcessLinux::WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written)
+{
+ WriteOperation op(addr, buf, size, bytes_written);
+ DoOperation(&op);
+ return op.GetError ();
+}
+
+bool
+NativeProcessLinux::ReadRegisterValue(lldb::tid_t tid, uint32_t offset, const char* reg_name,
+ uint32_t size, RegisterValue &value)
+{
+ bool result;
+ ReadRegOperation op(tid, offset, reg_name, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char* reg_name, const RegisterValue &value)
+{
+ bool result;
+ WriteRegOperation op(tid, offset, reg_name, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadGPROperation op(tid, buf, buf_size, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadFPROperation op(tid, buf, buf_size, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ bool result;
+ ReadRegisterSetOperation op(tid, buf, buf_size, regset, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteGPROperation op(tid, buf, buf_size, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteFPROperation op(tid, buf, buf_size, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ bool result;
+ WriteRegisterSetOperation op(tid, buf, buf_size, regset, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
+ GetUnixSignals().GetSignalAsCString (signo));
+ ResumeOperation op (tid, signo, result);
+ DoOperation (&op);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
+ return result;
+}
+
+bool
+NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ SingleStepOperation op(tid, signo, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo, int &ptrace_err)
+{
+ bool result;
+ SiginfoOperation op(tid, siginfo, result, ptrace_err);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+NativeProcessLinux::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+ bool result;
+ EventMessageOperation op(tid, message, result);
+ DoOperation(&op);
+ return result;
+}
+
+lldb_private::Error
+NativeProcessLinux::Detach(lldb::tid_t tid)
+{
+ lldb_private::Error error;
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ DetachOperation op(tid, error);
+ DoOperation(&op);
+ }
+ return error;
+}
+
+bool
+NativeProcessLinux::DupDescriptor(const char *path, int fd, int flags)
+{
+ int target_fd = open(path, flags, 0666);
+
+ if (target_fd == -1)
+ return false;
+
+ return (dup2(target_fd, fd) == -1) ? false : true;
+}
+
+void
+NativeProcessLinux::StopMonitoringChildProcess()
+{
+ lldb::thread_result_t thread_result;
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ Host::ThreadCancel(m_monitor_thread, NULL);
+ Host::ThreadJoin(m_monitor_thread, &thread_result, NULL);
+ m_monitor_thread = LLDB_INVALID_HOST_THREAD;
+ }
+}
+
+void
+NativeProcessLinux::StopMonitor()
+{
+ StopMonitoringChildProcess();
+ StopOpThread();
+ sem_destroy(&m_operation_pending);
+ sem_destroy(&m_operation_done);
+
+ // TODO: validate whether this still holds, fix up comment.
+ // Note: ProcessPOSIX passes the m_terminal_fd file descriptor to
+ // Process::SetSTDIOFileDescriptor, which in turn transfers ownership of
+ // the descriptor to a ConnectionFileDescriptor object. Consequently
+ // even though still has the file descriptor, we shouldn't close it here.
+}
+
+void
+NativeProcessLinux::StopOpThread()
+{
+ lldb::thread_result_t result;
+
+ if (!IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ Host::ThreadCancel(m_operation_thread, NULL);
+ Host::ThreadJoin(m_operation_thread, &result, NULL);
+ m_operation_thread = LLDB_INVALID_HOST_THREAD;
+}
+
+bool
+NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id)
+{
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not contain NULL threads");
+ if (thread_sp->GetID () == thread_id)
+ {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+NativeThreadProtocolSP
+NativeProcessLinux::MaybeGetThreadNoLock (lldb::tid_t thread_id)
+{
+ // CONSIDER organize threads by map - we can do better than linear.
+ for (auto thread_sp : m_threads)
+ {
+ if (thread_sp->GetID () == thread_id)
+ return thread_sp;
+ }
+
+ // We don't have this thread.
+ return NativeThreadProtocolSP ();
+}
+
+bool
+NativeProcessLinux::StopTrackingThread (lldb::tid_t thread_id)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto it = m_threads.begin (); it != m_threads.end (); ++it)
+ {
+ if (*it && ((*it)->GetID () == thread_id))
+ {
+ m_threads.erase (it);
+ return true;
+ }
+ }
+
+ // Didn't find it.
+ return false;
+}
+
+NativeThreadProtocolSP
+NativeProcessLinux::AddThread (lldb::tid_t thread_id)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ Mutex::Locker locker (m_threads_mutex);
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " adding thread with tid %" PRIu64,
+ __FUNCTION__,
+ GetID (),
+ thread_id);
+ }
+
+ assert (!HasThreadNoLock (thread_id) && "attempted to add a thread by id that already exists");
+
+ // If this is the first thread, save it as the current thread
+ if (m_threads.empty ())
+ SetCurrentThreadID (thread_id);
+
+ NativeThreadProtocolSP thread_sp (new NativeThreadLinux (this, thread_id));
+ m_threads.push_back (thread_sp);
+
+ return thread_sp;
+}
+
+NativeThreadProtocolSP
+NativeProcessLinux::GetOrCreateThread (lldb::tid_t thread_id, bool &created)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ Mutex::Locker locker (m_threads_mutex);
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " get/create thread with tid %" PRIu64,
+ __FUNCTION__,
+ GetID (),
+ thread_id);
+ }
+
+ // Retrieve the thread if it is already getting tracked.
+ NativeThreadProtocolSP thread_sp = MaybeGetThreadNoLock (thread_id);
+ if (thread_sp)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": thread already tracked, returning",
+ __FUNCTION__,
+ GetID (),
+ thread_id);
+ created = false;
+ return thread_sp;
+
+ }
+
+ // Create the thread metadata since it isn't being tracked.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": thread didn't exist, tracking now",
+ __FUNCTION__,
+ GetID (),
+ thread_id);
+
+ thread_sp.reset (new NativeThreadLinux (this, thread_id));
+ m_threads.push_back (thread_sp);
+ created = true;
+
+ return thread_sp;
+}
+
+Error
+NativeProcessLinux::FixupBreakpointPCAsNeeded (NativeThreadProtocolSP &thread_sp)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ Error error;
+
+ // Get a linux thread pointer.
+ if (!thread_sp)
+ {
+ error.SetErrorString ("null thread_sp");
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+ NativeThreadLinux *const linux_thread_p = reinterpret_cast<NativeThreadLinux*> (thread_sp.get());
+
+ // Find out the size of a breakpoint (might depend on where we are in the code).
+ NativeRegisterContextSP context_sp = linux_thread_p->GetRegisterContext ();
+ if (!context_sp)
+ {
+ error.SetErrorString ("cannot get a NativeRegisterContext for the thread");
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ uint32_t breakpoint_size = 0;
+ error = GetSoftwareBreakpointSize (context_sp, breakpoint_size);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s GetBreakpointSize() failed: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s breakpoint size: %" PRIu32, __FUNCTION__, breakpoint_size);
+ }
+
+ // First try probing for a breakpoint at a software breakpoint location: PC - breakpoint size.
+ const lldb::addr_t initial_pc_addr = context_sp->GetPC ();
+ lldb::addr_t breakpoint_addr = initial_pc_addr;
+ if (breakpoint_size > static_cast<lldb::addr_t> (0))
+ {
+ // Do not allow breakpoint probe to wrap around.
+ if (breakpoint_addr >= static_cast<lldb::addr_t> (breakpoint_size))
+ breakpoint_addr -= static_cast<lldb::addr_t> (breakpoint_size);
+ }
+
+ // Check if we stopped because of a breakpoint.
+ NativeBreakpointSP breakpoint_sp;
+ error = m_breakpoint_list.GetBreakpoint (breakpoint_addr, breakpoint_sp);
+ if (!error.Success () || !breakpoint_sp)
+ {
+ // We didn't find one at a software probe location. Nothing to do.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " no lldb breakpoint found at current pc with adjustment: 0x%" PRIx64, __FUNCTION__, GetID (), breakpoint_addr);
+ return Error ();
+ }
+
+ // If the breakpoint is not a software breakpoint, nothing to do.
+ if (!breakpoint_sp->IsSoftwareBreakpoint ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", not software, nothing to adjust", __FUNCTION__, GetID (), breakpoint_addr);
+ return Error ();
+ }
+
+ //
+ // We have a software breakpoint and need to adjust the PC.
+ //
+
+ // Sanity check.
+ if (breakpoint_size == 0)
+ {
+ // Nothing to do! How did we get here?
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", it is software, but the size is zero, nothing to do (unexpected)", __FUNCTION__, GetID (), breakpoint_addr);
+ return Error ();
+ }
+
+ // Change the program counter.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": changing PC from 0x%" PRIx64 " to 0x%" PRIx64, __FUNCTION__, GetID (), linux_thread_p->GetID (), initial_pc_addr, breakpoint_addr);
+
+ error = context_sp->SetPC (breakpoint_addr);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": failed to set PC: %s", __FUNCTION__, GetID (), linux_thread_p->GetID (), error.AsCString ());
+ return error;
+ }
+
+ return error;
+}
Added: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,379 @@
+//===-- NativeProcessLinux.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_NativeProcessLinux_H_
+#define liblldb_NativeProcessLinux_H_
+
+// C Includes
+#include <semaphore.h>
+#include <signal.h>
+
+// C++ Includes
+#include <unordered_set>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+
+#include "Host/common/NativeProcessProtocol.h"
+
+namespace lldb_private
+{
+ class Error;
+ class Module;
+ class Scalar;
+
+ /// @class NativeProcessLinux
+ /// @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 broadcasted.
+ class NativeProcessLinux: public NativeProcessProtocol
+ {
+ public:
+
+ // ---------------------------------------------------------------------
+ // Public Static Methods
+ // ---------------------------------------------------------------------
+ static lldb_private::Error
+ LaunchProcess (
+ Module *exe_module,
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &native_process_sp);
+
+ static lldb_private::Error
+ AttachToProcess (
+ lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &native_process_sp);
+
+ // ---------------------------------------------------------------------
+ // Public Instance Methods
+ // ---------------------------------------------------------------------
+
+ ~NativeProcessLinux() override;
+
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol Interface
+ // ---------------------------------------------------------------------
+ Error
+ Resume (const ResumeActionList &resume_actions) override;
+
+ Error
+ Halt () override;
+
+ Error
+ Detach () override;
+
+ Error
+ Signal (int signo) override;
+
+ Error
+ Kill () override;
+
+ Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info) override;
+
+ Error
+ ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) override;
+
+ Error
+ WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) override;
+
+ Error
+ AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) override;
+
+ Error
+ DeallocateMemory (lldb::addr_t addr) override;
+
+ lldb::addr_t
+ GetSharedLibraryInfoAddress () override;
+
+ size_t
+ UpdateThreads () override;
+
+ bool
+ GetArchitecture (ArchSpec &arch) const override;
+
+ Error
+ SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) override;
+
+ void
+ DoStopIDBumped (uint32_t newBumpId) override;
+
+ // ---------------------------------------------------------------------
+ // Interface used by NativeRegisterContext-derived classes.
+ // ---------------------------------------------------------------------
+
+ /// Reads the contents from the register identified by the given (architecture
+ /// dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextLinux derivatives.
+ bool
+ ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ unsigned size, lldb_private::RegisterValue &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(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ const lldb_private::RegisterValue &value);
+
+ /// Reads all general purpose registers into the specified buffer.
+ bool
+ ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads generic floating point registers into the specified buffer.
+ bool
+ ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads the specified register set into the specified buffer.
+ /// For instance, the extended floating-point register set.
+ bool
+ ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes all general purpose registers into the specified buffer.
+ bool
+ WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes generic floating point registers into the specified buffer.
+ bool
+ WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes the specified register set into the specified buffer.
+ /// For instance, the extended floating-point register set.
+ bool
+ WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ protected:
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol protected interface
+ // ---------------------------------------------------------------------
+ Error
+ GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) override;
+
+ private:
+
+ lldb_private::ArchSpec m_arch;
+
+ lldb::thread_t m_operation_thread;
+ lldb::thread_t m_monitor_thread;
+
+ // current operation which must be executed on the priviliged thread
+ void *m_operation;
+ lldb_private::Mutex m_operation_mutex;
+
+ // semaphores notified when Operation is ready to be processed and when
+ // the operation is complete.
+ sem_t m_operation_pending;
+ sem_t m_operation_done;
+
+ // Set of tids we're waiting to stop before we notify the delegate of
+ // the stopped state. We only notify the delegate after all threads
+ // ordered to stop have signaled their stop.
+ std::unordered_set<lldb::tid_t> m_wait_for_stop_tids;
+ lldb_private::Mutex m_wait_for_stop_tids_mutex;
+
+ lldb_private::LazyBool m_supports_mem_region;
+ std::vector<MemoryRegionInfo> m_mem_region_cache;
+ lldb_private::Mutex m_mem_region_cache_mutex;
+
+
+ struct OperationArgs
+ {
+ OperationArgs(NativeProcessLinux *monitor);
+
+ ~OperationArgs();
+
+ NativeProcessLinux *m_monitor; // The monitor performing the attach.
+ sem_t m_semaphore; // Posted to once operation complete.
+ lldb_private::Error m_error; // Set if process operation failed.
+ };
+
+ /// @class LauchArgs
+ ///
+ /// @brief Simple structure to pass data to the thread responsible for
+ /// launching a child process.
+ struct LaunchArgs : OperationArgs
+ {
+ LaunchArgs(NativeProcessLinux *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir);
+
+ ~LaunchArgs();
+
+ 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.
+ const char *m_working_dir; // Working directory or NULL.
+ };
+
+ struct AttachArgs : OperationArgs
+ {
+ AttachArgs(NativeProcessLinux *monitor,
+ lldb::pid_t pid);
+
+ ~AttachArgs();
+
+ lldb::pid_t m_pid; // pid of the process to be attached.
+ };
+
+ // ---------------------------------------------------------------------
+ // Private Instance Methods
+ // ---------------------------------------------------------------------
+ NativeProcessLinux ();
+
+ /// Launches an inferior process ready for debugging. Forms the
+ /// implementation of Process::DoLaunch.
+ void
+ LaunchInferior (
+ Module *module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ Error &error);
+
+ /// Attaches to an existing process. Forms the
+ /// implementation of Process::DoLaunch.
+ void
+ AttachToInferior (lldb::pid_t pid, Error &error);
+
+ void
+ StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
+
+ static void *
+ LaunchOpThread(void *arg);
+
+ static bool
+ Launch(LaunchArgs *args);
+
+ void
+ StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+
+ static void *
+ AttachOpThread(void *args);
+
+ static bool
+ Attach(AttachArgs *args);
+
+ static bool
+ SetDefaultPtraceOpts(const lldb::pid_t);
+
+ static void
+ ServeOperation(OperationArgs *args);
+
+ static bool
+ DupDescriptor(const char *path, int fd, int flags);
+
+ static bool
+ MonitorCallback(void *callback_baton,
+ lldb::pid_t pid, bool exited, int signal, int status);
+
+ void
+ MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid);
+
+ void
+ MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited);
+
+#if 0
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGSEGV(const siginfo_t *info);
+
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGILL(const siginfo_t *info);
+
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGFPE(const siginfo_t *info);
+
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGBUS(const siginfo_t *info);
+#endif
+
+ void
+ DoOperation(void *op);
+
+ /// Stops the child monitor thread.
+ void
+ StopMonitoringChildProcess();
+
+ /// Stops the operation thread used to attach/launch a process.
+ void
+ StopOpThread();
+
+ /// Stops monitoring the child process thread.
+ void
+ StopMonitor();
+
+ bool
+ HasThreadNoLock (lldb::tid_t thread_id);
+
+ NativeThreadProtocolSP
+ MaybeGetThreadNoLock (lldb::tid_t thread_id);
+
+ bool
+ StopTrackingThread (lldb::tid_t thread_id);
+
+ NativeThreadProtocolSP
+ AddThread (lldb::tid_t thread_id);
+
+ NativeThreadProtocolSP
+ GetOrCreateThread (lldb::tid_t thread_id, bool &created);
+
+ Error
+ GetSoftwareBreakpointSize (NativeRegisterContextSP context_sp, uint32_t &actual_opcode_size);
+
+ Error
+ FixupBreakpointPCAsNeeded (NativeThreadProtocolSP &thread_sp);
+
+ /// 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, int &ptrace_err);
+
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread ID to the memory pointed to by @p
+ /// message.
+ bool
+ GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ /// Resumes the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ Resume(lldb::tid_t tid, uint32_t signo);
+
+ /// Single steps the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ SingleStep(lldb::tid_t tid, uint32_t signo);
+
+ lldb_private::Error
+ Detach(lldb::tid_t tid);
+ };
+} // End lldb_private namespace.
+
+#endif // #ifndef liblldb_NativeProcessLinux_H_
Added: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,363 @@
+//===-- NativeThreadLinux.cpp --------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadLinux.h"
+
+#include <signal.h>
+
+#include "NativeProcessLinux.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private-log.h"
+#include "Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+ void LogThreadStopInfo (Log &log, const ThreadStopInfo &stop_info, const char *const header)
+ {
+ switch (stop_info.reason)
+ {
+ case eStopReasonSignal:
+ log.Printf ("%s: %s: signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
+ return;
+ case eStopReasonException:
+ log.Printf ("%s: %s: exception type 0x%" PRIx64, __FUNCTION__, header, stop_info.details.exception.type);
+ return;
+ default:
+ log.Printf ("%s: %s: invalid stop reason %" PRIu32, __FUNCTION__, header, static_cast<uint32_t> (stop_info.reason));
+ }
+ }
+}
+
+NativeThreadLinux::NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid) :
+ NativeThreadProtocol (process, tid),
+ m_state (StateType::eStateInvalid),
+ m_stop_info (),
+ m_reg_context_sp ()
+{
+}
+
+const char *
+NativeThreadLinux::GetName()
+{
+ NativeProcessProtocolSP process_sp = m_process_wp.lock ();
+ if (!process_sp)
+ return "<unknown: no process>";
+
+ // const NativeProcessLinux *const process = reinterpret_cast<NativeProcessLinux*> (process_sp->get ());
+ return Host::GetThreadName (process_sp->GetID (), GetID ()).c_str ();
+}
+
+lldb::StateType
+NativeThreadLinux::GetState ()
+{
+ return m_state;
+}
+
+
+bool
+NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ switch (m_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ if (log)
+ LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread: ");
+ stop_info = m_stop_info;
+ if (log)
+ LogThreadStopInfo (*log, stop_info, "returned stop_info: ");
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ default:
+ if (log)
+ {
+ log->Printf ("NativeThreadLinux::%s tid %" PRIu64 " in state %s cannot answer stop reason",
+ __FUNCTION__, GetID (), StateAsCString (m_state));
+ }
+ return false;
+ }
+}
+
+lldb_private::NativeRegisterContextSP
+NativeThreadLinux::GetRegisterContext ()
+{
+ // Return the register context if we already created it.
+ if (m_reg_context_sp)
+ return m_reg_context_sp;
+
+ // First select the appropriate RegisterInfoInterface.
+ RegisterInfoInterface *reg_interface = nullptr;
+ NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
+ if (!m_process_sp)
+ return NativeRegisterContextSP ();
+
+ ArchSpec target_arch;
+ if (!m_process_sp->GetArchitecture (target_arch))
+ return NativeRegisterContextSP ();
+
+ switch (target_arch.GetTriple().getOS())
+ {
+ case llvm::Triple::Linux:
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (Host::GetArchitecture().GetAddressByteSize() == 4)
+ {
+ // 32-bit hosts run with a RegisterContextLinux_i386 context.
+ reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch));
+ }
+ else
+ {
+ assert((Host::GetArchitecture ().GetAddressByteSize () == 8) && "Register setting path assumes this is a 64-bit host");
+ // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
+ reg_interface = static_cast<RegisterInfoInterface*> (new RegisterContextLinux_x86_64 (target_arch));
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ assert(reg_interface && "OS or CPU not supported!");
+ if (!reg_interface)
+ return NativeRegisterContextSP ();
+
+ // Now create the register context.
+ switch (target_arch.GetMachine())
+ {
+#if 0
+ case llvm::Triple::mips64:
+ {
+ RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+#endif
+#if 0
+ case llvm::Triple::x86:
+#endif
+ case llvm::Triple::x86_64:
+ {
+ const uint32_t concrete_frame_idx = 0;
+ m_reg_context_sp.reset (new NativeRegisterContextLinux_x86_64(*this, concrete_frame_idx, reg_interface));
+ break;
+ }
+ default:
+ break;
+ }
+
+ return m_reg_context_sp;
+}
+
+Error
+NativeThreadLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ // TODO implement
+ return Error ("not implemented");
+}
+
+Error
+NativeThreadLinux::RemoveWatchpoint (lldb::addr_t addr)
+{
+ // TODO implement
+ return Error ("not implemented");
+}
+
+void
+NativeThreadLinux::SetLaunching ()
+{
+ const StateType new_state = StateType::eStateLaunching;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ // Also mark it as stopped since launching temporarily stops the newly created thread
+ // in the ptrace machinery.
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.details.signal.signo = SIGSTOP;
+}
+
+
+void
+NativeThreadLinux::SetRunning ()
+{
+ const StateType new_state = StateType::eStateRunning;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void
+NativeThreadLinux::SetStepping ()
+{
+ const StateType new_state = StateType::eStateStepping;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void
+NativeThreadLinux::SetStoppedBySignal (uint32_t signo)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("NativeThreadLinux::%s called with signal 0x%" PRIx32, __FUNCTION__, signo);
+
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.details.signal.signo = signo;
+}
+
+void
+NativeThreadLinux::SetStoppedByBreakpoint ()
+{
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+bool
+NativeThreadLinux::IsStoppedAtBreakpoint ()
+{
+ // Are we stopped? If not, this can't be a breakpoint.
+ if (GetState () != StateType::eStateStopped)
+ return false;
+
+ // Was the stop reason a signal with signal number SIGTRAP? If not, not a breakpoint.
+ return (m_stop_info.reason == StopReason::eStopReasonSignal) &&
+ (m_stop_info.details.signal.signo == SIGTRAP);
+}
+
+void
+NativeThreadLinux::SetCrashedWithException (uint64_t exception_type, lldb::addr_t exception_addr)
+{
+ const StateType new_state = StateType::eStateCrashed;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonException;
+ m_stop_info.details.exception.type = exception_type;
+ m_stop_info.details.exception.data_count = 1;
+ m_stop_info.details.exception.data[0] = exception_addr;
+}
+
+
+void
+NativeThreadLinux::SetSuspended ()
+{
+ const StateType new_state = StateType::eStateSuspended;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ // FIXME what makes sense here? Do we need a suspended StopReason?
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void
+NativeThreadLinux::SetExited ()
+{
+ const StateType new_state = StateType::eStateExited;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonThreadExiting;
+}
+
+void
+NativeThreadLinux::MaybeLogStateChange (lldb::StateType new_state)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ // If we're not logging, we're done.
+ if (!log)
+ return;
+
+ // If this is a state change to the same state, we're done.
+ lldb::StateType old_state = m_state;
+ if (new_state == old_state)
+ return;
+
+ NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
+ lldb::pid_t pid = m_process_sp ? m_process_sp->GetID () : LLDB_INVALID_PROCESS_ID;
+
+ // Log it.
+ log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 ") changing from state %s to %s", pid, GetID (), StateAsCString (old_state), StateAsCString (new_state));
+}
+
+static
+uint32_t MaybeTranslateHostSignoToGdbSigno (uint32_t host_signo)
+{
+ switch (host_signo)
+ {
+ case SIGSEGV: return eGdbSignalBadAccess;
+ case SIGILL: return eGdbSignalBadInstruction;
+ case SIGFPE: return eGdbSignalArithmetic;
+ // NOTE: debugserver sends SIGTRAP through unmodified. Do the same here.
+ // case SIGTRAP: return eGdbSignalBreakpoint;
+
+ // Nothing for eGdbSignalSoftware (0x95).
+ // Nothing for eGdbSignalEmulation (0x94).
+
+ default:
+ // No translations.
+ return host_signo;
+ }
+}
+
+uint32_t
+NativeThreadLinux::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const
+{
+ switch (stop_info.reason)
+ {
+ case eStopReasonSignal:
+ return MaybeTranslateHostSignoToGdbSigno (stop_info.details.signal.signo);
+ break;
+
+ case eStopReasonException:
+ // FIXME verify how we handle exception type.
+ return MaybeTranslateHostSignoToGdbSigno (static_cast<uint32_t> (stop_info.details.exception.type));
+ break;
+
+ default:
+ assert (0 && "unexpected stop_info.reason found");
+ return 0;
+ }
+}
+
Added: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,97 @@
+//===-- NativeThreadLinux.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_NativeThreadLinux_H_
+#define liblldb_NativeThreadLinux_H_
+
+#include "lldb/lldb-private-forward.h"
+#include "../../../Host/common/NativeThreadProtocol.h"
+
+namespace lldb_private
+{
+ class NativeProcessLinux;
+
+ class NativeThreadLinux : public NativeThreadProtocol
+ {
+ friend class NativeProcessLinux;
+
+ public:
+ NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid);
+
+ // ---------------------------------------------------------------------
+ // NativeThreadProtocol Interface
+ // ---------------------------------------------------------------------
+ const char *
+ GetName() override;
+
+ lldb::StateType
+ GetState () override;
+
+ bool
+ GetStopReason (ThreadStopInfo &stop_info) override;
+
+ NativeRegisterContextSP
+ GetRegisterContext () override;
+
+ Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override;
+
+ Error
+ RemoveWatchpoint (lldb::addr_t addr) override;
+
+ uint32_t
+ TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const override;
+
+ private:
+ // ---------------------------------------------------------------------
+ // Interface for friend classes
+ // ---------------------------------------------------------------------
+ void
+ SetLaunching ();
+
+ void
+ SetRunning ();
+
+ void
+ SetStepping ();
+
+ void
+ SetStoppedBySignal (uint32_t signo);
+
+ void
+ SetStoppedByBreakpoint ();
+
+ bool
+ IsStoppedAtBreakpoint ();
+
+ void
+ SetCrashedWithException (uint64_t exception_type, lldb::addr_t exception_addr);
+
+ void
+ SetSuspended ();
+
+ void
+ SetExited ();
+
+ // ---------------------------------------------------------------------
+ // Private interface
+ // ---------------------------------------------------------------------
+ void
+ MaybeLogStateChange (lldb::StateType new_state);
+
+ // ---------------------------------------------------------------------
+ // Member Variables
+ // ---------------------------------------------------------------------
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ NativeRegisterContextSP m_reg_context_sp;
+ };
+}
+
+#endif // #ifndef liblldb_NativeThreadLinux_H_
Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h Mon Jun 30 16:05:18 2014
@@ -17,10 +17,11 @@
// Other libraries and framework includes
#include "lldb/Target/Process.h"
-#include "LinuxSignals.h"
#include "ProcessMessage.h"
#include "ProcessPOSIX.h"
+#include "Plugins/Process/Utility/LinuxSignals.h"
+
class ProcessMonitor;
class ProcessLinux :
@@ -107,7 +108,7 @@ public:
private:
/// Linux-specific signal set.
- LinuxSignals m_linux_signals;
+ process_linux::LinuxSignals m_linux_signals;
lldb_private::FileSpec *m_core_file;
Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Mon Jun 30 16:05:18 2014
@@ -1228,8 +1228,12 @@ ProcessMonitor::Launch(LaunchArgs *args)
// Wait for the child process to to trap on its call to execve.
lldb::pid_t wpid;
+ ::pid_t raw_pid;
int status;
- if ((wpid = waitpid(pid, &status, 0)) < 0)
+
+ raw_pid = waitpid(pid, &status, 0);
+ wpid = static_cast <lldb::pid_t> (raw_pid);
+ if (raw_pid < 0)
{
args->m_error.SetErrorToErrno();
goto FINISH;
Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Mon Jun 30 16:05:18 2014
@@ -934,3 +934,16 @@ ProcessPOSIX::IsAThreadRunning()
}
return is_running;
}
+
+const DataBufferSP
+ProcessPOSIX::GetAuxvData ()
+{
+ // If we're the local platform, we can ask the host for auxv data.
+ PlatformSP platform_sp = m_target.GetPlatform ();
+ if (platform_sp && platform_sp->IsHost ())
+ return lldb_private::Host::GetAuxvData(this);
+
+ // Somewhat unexpected - the process is not running locally or we don't have a platform.
+ assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?");
+ return DataBufferSP ();
+}
Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h Mon Jun 30 16:05:18 2014
@@ -141,6 +141,9 @@ public:
virtual size_t
PutSTDIN(const char *buf, size_t len, lldb_private::Error &error);
+ const lldb::DataBufferSP
+ GetAuxvData () override;
+
//--------------------------------------------------------------------------
// ProcessPOSIX internal API.
Modified: lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -8,6 +8,8 @@ add_lldb_library(lldbPluginProcessUtilit
HistoryThread.cpp
HistoryUnwind.cpp
InferiorCallPOSIX.cpp
+ LinuxSignals.cpp
+ NativeRegisterContextLinux_x86_64.cpp
RegisterContextDarwin_arm.cpp
RegisterContextDarwin_arm64.cpp
RegisterContextDarwin_i386.cpp
Added: lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,79 @@
+//===-- LinuxSignals.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 <signal.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "LinuxSignals.h"
+
+using namespace process_linux;
+
+LinuxSignals::LinuxSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+void
+LinuxSignals::Reset()
+{
+ m_signals.clear();
+
+ // FIXME we now need *Signals classes on systems that are different OSes (e.g. LinuxSignals
+ // needed on MacOSX to debug Linux from MacOSX, and similar scenarios, used by ProcessGDBRemote). These must be defined
+ // not based on OS includes and defines.
+
+#define ADDSIGNAL(S, SUPPRESS, STOP, NOTIFY, DESCRIPTION) \
+ AddSignal(SIG ## S, "SIG" #S, #S, SUPPRESS, STOP, NOTIFY, DESCRIPTION)
+
+ ADDSIGNAL(HUP, false, true, true, "hangup");
+ ADDSIGNAL(INT, true, true, true, "interrupt");
+ ADDSIGNAL(QUIT, false, true, true, "quit");
+ ADDSIGNAL(ILL, false, true, true, "illegal instruction");
+ ADDSIGNAL(TRAP, true, true, true, "trace trap (not reset when caught)");
+ ADDSIGNAL(ABRT, false, true, true, "abort");
+ ADDSIGNAL(IOT, false, true, true, "abort");
+ ADDSIGNAL(BUS, false, true, true, "bus error");
+ ADDSIGNAL(FPE, false, true, true, "floating point exception");
+ ADDSIGNAL(KILL, false, true, true, "kill");
+ ADDSIGNAL(USR1, false, true, true, "user defined signal 1");
+ ADDSIGNAL(SEGV, false, true, true, "segmentation violation");
+ ADDSIGNAL(USR2, false, true, true, "user defined signal 2");
+ ADDSIGNAL(PIPE, false, true, true, "write to pipe with reading end closed");
+ ADDSIGNAL(ALRM, false, false, true, "alarm");
+ ADDSIGNAL(TERM, false, true, true, "termination requested");
+#ifdef SIGSTKFLT
+ ADDSIGNAL(STKFLT, false, true, true, "stack fault");
+#endif
+ ADDSIGNAL(CHLD, false, false, true, "child process exit");
+ ADDSIGNAL(CONT, false, true, true, "process continue");
+ ADDSIGNAL(STOP, true, true, true, "process stop");
+ ADDSIGNAL(TSTP, false, true, true, "tty stop");
+ ADDSIGNAL(TTIN, false, true, true, "background tty read");
+ ADDSIGNAL(TTOU, false, true, true, "background tty write");
+ ADDSIGNAL(URG, false, true, true, "urgent data on socket");
+ ADDSIGNAL(XCPU, false, true, true, "CPU resource exceeded");
+ ADDSIGNAL(XFSZ, false, true, true, "file size limit exceeded");
+ ADDSIGNAL(VTALRM, false, true, true, "virtual alarm");
+ ADDSIGNAL(PROF, false, true, true, "profiling alarm");
+ ADDSIGNAL(WINCH, false, true, true, "window size change");
+#ifdef SIGPOLL
+ ADDSIGNAL(POLL, false, true, true, "pollable event");
+#endif
+ ADDSIGNAL(IO, false, true, true, "input/output ready");
+#ifdef SIGPWR
+ ADDSIGNAL(PWR, false, true, true, "power failure");
+#endif
+ ADDSIGNAL(SYS, false, true, true, "invalid system call");
+
+#undef ADDSIGNAL
+}
Added: lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,35 @@
+//===-- LinuxSignals.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_LinuxSignals_H_
+#define liblldb_LinuxSignals_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace process_linux
+{
+
+ /// Linux specific set of Unix signals.
+ class LinuxSignals
+ : public lldb_private::UnixSignals
+ {
+ public:
+ LinuxSignals();
+
+ private:
+ void
+ Reset();
+ };
+}
+
+#endif
Added: lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,1040 @@
+//===-- NativeRegisterContextLinux_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 "NativeRegisterContextLinux_x86_64.h"
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+
+using namespace lldb_private;
+
+// ----------------------------------------------------------------------------
+// Private namespace.
+// ----------------------------------------------------------------------------
+
+namespace
+{
+ // x86 32-bit general purpose registers.
+ const uint32_t
+ g_gpr_regnums_i386[] =
+ {
+ gpr_eax_i386,
+ gpr_ebx_i386,
+ gpr_ecx_i386,
+ gpr_edx_i386,
+ gpr_edi_i386,
+ gpr_esi_i386,
+ gpr_ebp_i386,
+ gpr_esp_i386,
+ gpr_eip_i386,
+ gpr_eflags_i386,
+ gpr_cs_i386,
+ gpr_fs_i386,
+ gpr_gs_i386,
+ gpr_ss_i386,
+ gpr_ds_i386,
+ gpr_es_i386,
+ gpr_ax_i386,
+ gpr_bx_i386,
+ gpr_cx_i386,
+ gpr_dx_i386,
+ gpr_di_i386,
+ gpr_si_i386,
+ gpr_bp_i386,
+ gpr_sp_i386,
+ gpr_ah_i386,
+ gpr_bh_i386,
+ gpr_ch_i386,
+ gpr_dh_i386,
+ gpr_al_i386,
+ gpr_bl_i386,
+ gpr_cl_i386,
+ gpr_dl_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386,
+ "g_gpr_regnums_i386 has wrong number of register infos");
+
+ // x86 32-bit floating point registers.
+ const uint32_t
+ g_fpu_regnums_i386[] =
+ {
+ fpu_fctrl_i386,
+ fpu_fstat_i386,
+ fpu_ftag_i386,
+ fpu_fop_i386,
+ fpu_fiseg_i386,
+ fpu_fioff_i386,
+ fpu_foseg_i386,
+ fpu_fooff_i386,
+ fpu_mxcsr_i386,
+ fpu_mxcsrmask_i386,
+ fpu_st0_i386,
+ fpu_st1_i386,
+ fpu_st2_i386,
+ fpu_st3_i386,
+ fpu_st4_i386,
+ fpu_st5_i386,
+ fpu_st6_i386,
+ fpu_st7_i386,
+ fpu_mm0_i386,
+ fpu_mm1_i386,
+ fpu_mm2_i386,
+ fpu_mm3_i386,
+ fpu_mm4_i386,
+ fpu_mm5_i386,
+ fpu_mm6_i386,
+ fpu_mm7_i386,
+ fpu_xmm0_i386,
+ fpu_xmm1_i386,
+ fpu_xmm2_i386,
+ fpu_xmm3_i386,
+ fpu_xmm4_i386,
+ fpu_xmm5_i386,
+ fpu_xmm6_i386,
+ fpu_xmm7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
+ "g_fpu_regnums_i386 has wrong number of register infos");
+
+ // x86 32-bit AVX registers.
+ const uint32_t
+ g_avx_regnums_i386[] =
+ {
+ fpu_ymm0_i386,
+ fpu_ymm1_i386,
+ fpu_ymm2_i386,
+ fpu_ymm3_i386,
+ fpu_ymm4_i386,
+ fpu_ymm5_i386,
+ fpu_ymm6_i386,
+ fpu_ymm7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386,
+ " g_avx_regnums_i386 has wrong number of register infos");
+
+ // x86 64-bit general purpose registers.
+ static const
+ uint32_t g_gpr_regnums_x86_64[] =
+ {
+ gpr_rax_x86_64,
+ gpr_rbx_x86_64,
+ gpr_rcx_x86_64,
+ gpr_rdx_x86_64,
+ gpr_rdi_x86_64,
+ gpr_rsi_x86_64,
+ gpr_rbp_x86_64,
+ gpr_rsp_x86_64,
+ gpr_r8_x86_64,
+ gpr_r9_x86_64,
+ gpr_r10_x86_64,
+ gpr_r11_x86_64,
+ gpr_r12_x86_64,
+ gpr_r13_x86_64,
+ gpr_r14_x86_64,
+ gpr_r15_x86_64,
+ gpr_rip_x86_64,
+ gpr_rflags_x86_64,
+ gpr_cs_x86_64,
+ gpr_fs_x86_64,
+ gpr_gs_x86_64,
+ gpr_ss_x86_64,
+ gpr_ds_x86_64,
+ gpr_es_x86_64,
+ gpr_eax_x86_64,
+ gpr_ebx_x86_64,
+ gpr_ecx_x86_64,
+ gpr_edx_x86_64,
+ gpr_edi_x86_64,
+ gpr_esi_x86_64,
+ gpr_ebp_x86_64,
+ gpr_esp_x86_64,
+ gpr_r8d_x86_64, // Low 32 bits or r8
+ gpr_r9d_x86_64, // Low 32 bits or r9
+ gpr_r10d_x86_64, // Low 32 bits or r10
+ gpr_r11d_x86_64, // Low 32 bits or r11
+ gpr_r12d_x86_64, // Low 32 bits or r12
+ gpr_r13d_x86_64, // Low 32 bits or r13
+ gpr_r14d_x86_64, // Low 32 bits or r14
+ gpr_r15d_x86_64, // Low 32 bits or r15
+ gpr_ax_x86_64,
+ gpr_bx_x86_64,
+ gpr_cx_x86_64,
+ gpr_dx_x86_64,
+ gpr_di_x86_64,
+ gpr_si_x86_64,
+ gpr_bp_x86_64,
+ gpr_sp_x86_64,
+ gpr_r8w_x86_64, // Low 16 bits or r8
+ gpr_r9w_x86_64, // Low 16 bits or r9
+ gpr_r10w_x86_64, // Low 16 bits or r10
+ gpr_r11w_x86_64, // Low 16 bits or r11
+ gpr_r12w_x86_64, // Low 16 bits or r12
+ gpr_r13w_x86_64, // Low 16 bits or r13
+ gpr_r14w_x86_64, // Low 16 bits or r14
+ gpr_r15w_x86_64, // Low 16 bits or r15
+ gpr_ah_x86_64,
+ gpr_bh_x86_64,
+ gpr_ch_x86_64,
+ gpr_dh_x86_64,
+ gpr_al_x86_64,
+ gpr_bl_x86_64,
+ gpr_cl_x86_64,
+ gpr_dl_x86_64,
+ gpr_dil_x86_64,
+ gpr_sil_x86_64,
+ gpr_bpl_x86_64,
+ gpr_spl_x86_64,
+ gpr_r8l_x86_64, // Low 8 bits or r8
+ gpr_r9l_x86_64, // Low 8 bits or r9
+ gpr_r10l_x86_64, // Low 8 bits or r10
+ gpr_r11l_x86_64, // Low 8 bits or r11
+ gpr_r12l_x86_64, // Low 8 bits or r12
+ gpr_r13l_x86_64, // Low 8 bits or r13
+ gpr_r14l_x86_64, // Low 8 bits or r14
+ gpr_r15l_x86_64, // Low 8 bits or r15
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64,
+ "g_gpr_regnums_x86_64 has wrong number of register infos");
+
+ // x86 64-bit floating point registers.
+ static const uint32_t
+ g_fpu_regnums_x86_64[] =
+ {
+ fpu_fctrl_x86_64,
+ fpu_fstat_x86_64,
+ fpu_ftag_x86_64,
+ fpu_fop_x86_64,
+ fpu_fiseg_x86_64,
+ fpu_fioff_x86_64,
+ fpu_foseg_x86_64,
+ fpu_fooff_x86_64,
+ fpu_mxcsr_x86_64,
+ fpu_mxcsrmask_x86_64,
+ fpu_st0_x86_64,
+ fpu_st1_x86_64,
+ fpu_st2_x86_64,
+ fpu_st3_x86_64,
+ fpu_st4_x86_64,
+ fpu_st5_x86_64,
+ fpu_st6_x86_64,
+ fpu_st7_x86_64,
+ fpu_mm0_x86_64,
+ fpu_mm1_x86_64,
+ fpu_mm2_x86_64,
+ fpu_mm3_x86_64,
+ fpu_mm4_x86_64,
+ fpu_mm5_x86_64,
+ fpu_mm6_x86_64,
+ fpu_mm7_x86_64,
+ fpu_xmm0_x86_64,
+ fpu_xmm1_x86_64,
+ fpu_xmm2_x86_64,
+ fpu_xmm3_x86_64,
+ fpu_xmm4_x86_64,
+ fpu_xmm5_x86_64,
+ fpu_xmm6_x86_64,
+ fpu_xmm7_x86_64,
+ fpu_xmm8_x86_64,
+ fpu_xmm9_x86_64,
+ fpu_xmm10_x86_64,
+ fpu_xmm11_x86_64,
+ fpu_xmm12_x86_64,
+ fpu_xmm13_x86_64,
+ fpu_xmm14_x86_64,
+ fpu_xmm15_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
+ "g_fpu_regnums_x86_64 has wrong number of register infos");
+
+ // x86 64-bit AVX registers.
+ static const uint32_t
+ g_avx_regnums_x86_64[] =
+ {
+ fpu_ymm0_x86_64,
+ fpu_ymm1_x86_64,
+ fpu_ymm2_x86_64,
+ fpu_ymm3_x86_64,
+ fpu_ymm4_x86_64,
+ fpu_ymm5_x86_64,
+ fpu_ymm6_x86_64,
+ fpu_ymm7_x86_64,
+ fpu_ymm8_x86_64,
+ fpu_ymm9_x86_64,
+ fpu_ymm10_x86_64,
+ fpu_ymm11_x86_64,
+ fpu_ymm12_x86_64,
+ fpu_ymm13_x86_64,
+ fpu_ymm14_x86_64,
+ fpu_ymm15_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64,
+ "g_avx_regnums_x86_64 has wrong number of register infos");
+
+ // Number of register sets provided by this context.
+ enum
+ {
+ k_num_extended_register_sets = 1,
+ k_num_register_sets = 3
+ };
+
+ // Register sets for x86 32-bit.
+ static const RegisterSet
+ g_reg_sets_i386[k_num_register_sets] =
+ {
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }
+ };
+
+ // Register sets for x86 64-bit.
+ static const RegisterSet
+ g_reg_sets_x86_64[k_num_register_sets] =
+ {
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }
+ };
+}
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR))
+
+// ----------------------------------------------------------------------------
+// Required ptrace defines.
+// ----------------------------------------------------------------------------
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+#define NT_X86_XSTATE 0x202
+#endif
+
+// ----------------------------------------------------------------------------
+// NativeRegisterContextLinux_x86_64 members.
+// ----------------------------------------------------------------------------
+
+NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p) :
+ NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p),
+ m_fpr_type (eFPRTypeNotValid),
+ m_fpr (),
+ m_iovec (),
+ m_ymm_set (),
+ m_reg_info (),
+ m_gpr_x86_64 ()
+{
+ // Set up data about ranges of valid registers.
+ switch (reg_info_interface_p->GetTargetArchitecture ().GetMachine ())
+ {
+ case llvm::Triple::x86:
+ m_reg_info.num_registers = k_num_registers_i386;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_i386;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_i386;
+ m_reg_info.num_avx_registers = k_num_avx_registers_i386;
+ m_reg_info.last_gpr = k_last_gpr_i386;
+ m_reg_info.first_fpr = k_first_fpr_i386;
+ m_reg_info.last_fpr = k_last_fpr_i386;
+ m_reg_info.first_st = fpu_st0_i386;
+ m_reg_info.last_st = fpu_st7_i386;
+ m_reg_info.first_mm = fpu_mm0_i386;
+ m_reg_info.last_mm = fpu_mm7_i386;
+ m_reg_info.first_xmm = fpu_xmm0_i386;
+ m_reg_info.last_xmm = fpu_xmm7_i386;
+ m_reg_info.first_ymm = fpu_ymm0_i386;
+ m_reg_info.last_ymm = fpu_ymm7_i386;
+ m_reg_info.first_dr = dr0_i386;
+ m_reg_info.gpr_flags = gpr_eflags_i386;
+ break;
+ case llvm::Triple::x86_64:
+ m_reg_info.num_registers = k_num_registers_x86_64;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64;
+ m_reg_info.num_avx_registers = k_num_avx_registers_x86_64;
+ m_reg_info.last_gpr = k_last_gpr_x86_64;
+ m_reg_info.first_fpr = k_first_fpr_x86_64;
+ m_reg_info.last_fpr = k_last_fpr_x86_64;
+ m_reg_info.first_st = fpu_st0_x86_64;
+ m_reg_info.last_st = fpu_st7_x86_64;
+ m_reg_info.first_mm = fpu_mm0_x86_64;
+ m_reg_info.last_mm = fpu_mm7_x86_64;
+ m_reg_info.first_xmm = fpu_xmm0_x86_64;
+ m_reg_info.last_xmm = fpu_xmm15_x86_64;
+ m_reg_info.first_ymm = fpu_ymm0_x86_64;
+ m_reg_info.last_ymm = fpu_ymm15_x86_64;
+ m_reg_info.first_dr = dr0_x86_64;
+ m_reg_info.gpr_flags = gpr_rflags_x86_64;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ // Initialize m_iovec to point to the buffer and buffer size
+ // using the conventions of Berkeley style UIO structures, as required
+ // by PTRACE extensions.
+ m_iovec.iov_base = &m_fpr.xstate.xsave;
+ m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
+
+ // Clear out the FPR state.
+ ::memset(&m_fpr, 0, sizeof(FPR));
+}
+
+// CONSIDER after local and llgs debugging are merged, register set support can
+// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
+uint32_t
+NativeRegisterContextLinux_x86_64::GetRegisterSetCount () const
+{
+ uint32_t sets = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+ {
+ if (IsRegisterSetAvailable (set_index))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const lldb_private::RegisterSet *
+NativeRegisterContextLinux_x86_64::GetRegisterSet (uint32_t set_index) const
+{
+ if (!IsRegisterSetAvailable (set_index))
+ return nullptr;
+
+ switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ())
+ {
+ case llvm::Triple::x86:
+ return &g_reg_sets_i386[set_index];
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set_index];
+ default:
+ assert (false && "Unhandled target architecture.");
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value)
+{
+ Error error;
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
+ if (!reg_info)
+ {
+ error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
+ return error;
+ }
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ {
+ error.SetErrorString ("NativeProcessProtocol is NULL");
+ return error;
+ }
+
+ NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+ if (!process_p->ReadRegisterValue(m_thread.GetID(),
+ reg_info->byte_offset,
+ reg_info->name,
+ reg_info->byte_size,
+ reg_value))
+ error.SetErrorString ("NativeProcessLinux::ReadRegisterValue() failed");
+
+ return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value)
+{
+ Error error;
+
+ if (!reg_info)
+ {
+ error.SetErrorString ("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM)
+ {
+ // This is likely an internal register for lldb use only and should not be directly queried.
+ error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name);
+ return error;
+ }
+
+ if (IsFPR(reg, GetFPRType()))
+ {
+ if (!ReadFPR())
+ {
+ error.SetErrorString ("failed to read floating point register");
+ return error;
+ }
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+
+ error = ReadRegisterRaw(full_reg, reg_value);
+
+ if (error.Success ())
+ {
+ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+ if (is_subreg && (reg_info->byte_offset & 0x1))
+ reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
+
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (reg_value.GetByteSize() > reg_info->byte_size)
+ reg_value.SetType(reg_info);
+ }
+ return error;
+ }
+
+ if (reg_info->encoding == lldb::eEncodingVector)
+ {
+ lldb::ByteOrder byte_order = GetByteOrder();
+
+ if (byte_order != lldb::eByteOrderInvalid)
+ {
+ if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
+ reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
+ reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
+ reg_value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
+ {
+ // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
+ if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+ reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
+ else
+ {
+ error.SetErrorString ("failed to copy ymm register value");
+ return error;
+ }
+ }
+
+ if (reg_value.GetType() != RegisterValue::eTypeBytes)
+ error.SetErrorString ("write failed - type was expected to be RegisterValue::eTypeBytes");
+
+ return error;
+ }
+
+ error.SetErrorString ("byte order is invalid");
+ return error;
+ }
+
+ // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
+ assert (reg_info->byte_offset < sizeof(m_fpr));
+ uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ reg_value.SetUInt16(*(uint16_t *)src);
+ break;
+ case 4:
+ reg_value.SetUInt32(*(uint32_t *)src);
+ break;
+ case 8:
+ reg_value.SetUInt64(*(uint64_t *)src);
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
+ break;
+ }
+
+ return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::WriteRegister(const uint32_t reg,
+ const RegisterValue &value)
+{
+ Error error;
+
+ uint32_t reg_to_write = reg;
+ RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ error = ReadRegister(full_reg_info, full_value);
+ if (error.Fail ())
+ return error;
+
+ lldb::ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ {
+ error.SetErrorString ("NativeProcessProtocol is NULL");
+ return error;
+ }
+
+ const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
+ assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
+ if (!register_to_write_info_p)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
+ return error;
+ }
+
+ NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+ if (!process_p->WriteRegisterValue(m_thread.GetID(),
+ register_to_write_info_p->byte_offset,
+ register_to_write_info_p->name,
+ value_to_write))
+ error.SetErrorString ("NativeProcessLinux::WriteRegisterValue() failed");
+
+ return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value)
+{
+ assert (reg_info && "reg_info is null");
+
+ const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg_index == LLDB_INVALID_REGNUM)
+ return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
+
+ if (IsGPR(reg_index))
+ return WriteRegister(reg_index, reg_value);
+
+ if (IsFPR(reg_index, GetFPRType()))
+ {
+ if (reg_info->encoding == lldb::eEncodingVector)
+ {
+ if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
+ ::memcpy (m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ if (reg_index >= m_reg_info.first_ymm && reg_index <= m_reg_info.last_ymm)
+ {
+ if (GetFPRType() != eFPRTypeXSAVE)
+ return Error ("target processor does not support AVX");
+
+ // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
+ ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+ if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
+ return Error ("CopyYMMtoXSTATE() failed");
+ }
+ }
+ else
+ {
+ // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
+ assert (reg_info->byte_offset < sizeof(m_fpr));
+ uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ *(uint16_t *)dst = reg_value.GetAsUInt16();
+ break;
+ case 4:
+ *(uint32_t *)dst = reg_value.GetAsUInt32();
+ break;
+ case 8:
+ *(uint64_t *)dst = reg_value.GetAsUInt64();
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
+ }
+ }
+
+ if (WriteFPR())
+ {
+ if (IsAVX(reg_index))
+ {
+ if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
+ return Error ("CopyYMMtoXSTATE() failed");
+ }
+ return Error ();
+ }
+ }
+ return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ if (!ReadGPR ())
+ {
+ error.SetErrorString ("ReadGPR() failed");
+ return error;
+ }
+
+ if (!ReadFPR ())
+ {
+ error.SetErrorString ("ReadFPR() failed");
+ return error;
+ }
+
+ uint8_t *dst = data_sp->GetBytes ();
+ if (dst == nullptr)
+ {
+ error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ ::memcpy (dst, &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
+ dst += GetRegisterInfoInterface ().GetGPRSize ();
+ if (GetFPRType () == eFPRTypeFXSAVE)
+ ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+ else if (GetFPRType () == eFPRTypeXSAVE)
+ {
+ lldb::ByteOrder byte_order = GetByteOrder ();
+
+ // Assemble the YMM register content from the register halves.
+ for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
+ {
+ if (!CopyXSTATEtoYMM (reg, byte_order))
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyXSTATEtoYMM() failed for reg num %" PRIu32, __FUNCTION__, reg);
+ return error;
+ }
+ }
+
+ // Copy the extended register state including the assembled ymm registers.
+ ::memcpy (dst, &m_fpr, sizeof (m_fpr));
+ }
+ else
+ {
+ assert (false && "how do we save the floating point registers?");
+ error.SetErrorString ("unsure how to save the floating point registers");
+ }
+
+ return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
+ return error;
+ }
+
+
+ uint8_t *src = data_sp->GetBytes ();
+ if (src == nullptr)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
+ return error;
+ }
+ ::memcpy (&m_gpr_x86_64, src, GetRegisterInfoInterface ().GetGPRSize ());
+
+ if (!WriteGPR ())
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
+ return error;
+ }
+
+ src += GetRegisterInfoInterface ().GetGPRSize ();
+ if (GetFPRType () == eFPRTypeFXSAVE)
+ ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
+ else if (GetFPRType () == eFPRTypeXSAVE)
+ ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
+
+ if (!WriteFPR ())
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
+ return error;
+ }
+
+ if (GetFPRType() == eFPRTypeXSAVE)
+ {
+ lldb::ByteOrder byte_order = GetByteOrder();
+
+ // Parse the YMM register content from the register halves.
+ for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
+ {
+ if (!CopyYMMtoXSTATE (reg, byte_order))
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyYMMtoXSTATE() failed for reg num %" PRIu32, __FUNCTION__, reg);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) const
+{
+ // Note: Extended register sets are assumed to be at the end of g_reg_sets.
+ uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+
+ if (GetFPRType () == eFPRTypeXSAVE)
+ {
+ // AVX is the first extended register set.
+ ++num_sets;
+ }
+ return (set_index < num_sets);
+}
+
+lldb::ByteOrder
+NativeRegisterContextLinux_x86_64::GetByteOrder() const
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ return byte_order;
+
+ if (!process_sp->GetByteOrder (byte_order))
+ {
+ // FIXME log here
+ }
+
+ return byte_order;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const
+{
+ // GPRs come first.
+ return reg_index <= m_reg_info.last_gpr;
+}
+
+NativeRegisterContextLinux_x86_64::FPRType
+NativeRegisterContextLinux_x86_64::GetFPRType () const
+{
+ if (m_fpr_type == eFPRTypeNotValid)
+ {
+ // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx.
+
+ // Try and see if AVX register retrieval works.
+ m_fpr_type = eFPRTypeXSAVE;
+ if (!const_cast<NativeRegisterContextLinux_x86_64*> (this)->ReadFPR ())
+ {
+ // Fall back to general floating point with no AVX support.
+ m_fpr_type = eFPRTypeFXSAVE;
+ }
+ }
+
+ return m_fpr_type;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const
+{
+ return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) const
+{
+ bool generic_fpr = IsFPR(reg_index);
+
+ if (fpr_type == eFPRTypeXSAVE)
+ return generic_fpr || IsAVX(reg_index);
+ return generic_fpr;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::WriteFPR()
+{
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ return false;
+ NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+ if (GetFPRType() == eFPRTypeFXSAVE)
+ return process_p->WriteFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave));
+
+ if (GetFPRType() == eFPRTypeXSAVE)
+ return process_p->WriteRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const
+{
+ return (m_reg_info.first_ymm <= reg_index && reg_index <= m_reg_info.last_ymm);
+}
+
+bool
+NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX (reg_index))
+ return false;
+
+ if (byte_order == lldb::eByteOrderLittle)
+ {
+ ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
+ m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (XMMReg));
+ ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
+ m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (YMMHReg));
+ return true;
+ }
+
+ if (byte_order == lldb::eByteOrderBig)
+ {
+ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
+ m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
+ m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+
+}
+
+bool
+NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == lldb::eByteOrderLittle)
+ {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ sizeof(YMMHReg));
+ return true;
+ }
+
+ if (byte_order == lldb::eByteOrderBig)
+ {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ sizeof(XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+bool
+NativeRegisterContextLinux_x86_64::ReadFPR ()
+{
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ return false;
+ NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+ const FPRType fpr_type = GetFPRType ();
+ switch (fpr_type)
+ {
+ case FPRType::eFPRTypeFXSAVE:
+ return process_p->ReadFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave));
+
+ case FPRType::eFPRTypeXSAVE:
+ return process_p->ReadRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE);
+
+ default:
+ return false;
+ }
+}
+
+bool
+NativeRegisterContextLinux_x86_64::ReadGPR()
+{
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ return false;
+ NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+ return process_p->ReadGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
+}
+
+bool
+NativeRegisterContextLinux_x86_64::WriteGPR()
+{
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ return false;
+ NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+ return process_p->WriteGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
+}
+
Added: lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,135 @@
+//===-- NativeRegisterContextLinux_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 lldb_NativeRegisterContextLinux_x86_64_h
+#define lldb_NativeRegisterContextLinux_x86_64_h
+
+#include "lldb/Target/NativeRegisterContextRegisterInfo.h"
+#include "RegisterContext_x86.h"
+#include "lldb-x86-register-enums.h"
+
+namespace lldb_private
+{
+ class NativeProcessLinux;
+
+ class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextRegisterInfo
+ {
+ public:
+ NativeRegisterContextLinux_x86_64 (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p);
+
+ uint32_t
+ GetRegisterSetCount () const override;
+
+ const RegisterSet *
+ GetRegisterSet (uint32_t set_index) const override;
+
+ Error
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) override;
+
+ Error
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) override;
+
+ Error
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
+
+ Error
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+
+ private:
+
+ // Private member types.
+ enum FPRType
+ {
+ eFPRTypeNotValid = 0,
+ eFPRTypeFXSAVE,
+ eFPRTypeXSAVE
+ };
+
+ // Info about register ranges.
+ struct RegInfo
+ {
+ uint32_t num_registers;
+ uint32_t num_gpr_registers;
+ uint32_t num_fpr_registers;
+ uint32_t num_avx_registers;
+
+ uint32_t last_gpr;
+ uint32_t first_fpr;
+ uint32_t last_fpr;
+
+ uint32_t first_st;
+ uint32_t last_st;
+ uint32_t first_mm;
+ uint32_t last_mm;
+ uint32_t first_xmm;
+ uint32_t last_xmm;
+ uint32_t first_ymm;
+ uint32_t last_ymm;
+
+ uint32_t first_dr;
+ uint32_t gpr_flags;
+ };
+
+ // Private member variables.
+ mutable FPRType m_fpr_type;
+ FPR m_fpr;
+ IOVEC m_iovec;
+ YMM m_ymm_set;
+ RegInfo m_reg_info;
+ uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64];
+
+ // Private member methods.
+ lldb_private::Error
+ WriteRegister(const uint32_t reg, const RegisterValue &value);
+
+ bool IsRegisterSetAvailable (uint32_t set_index) const;
+
+ lldb::ByteOrder
+ GetByteOrder() const;
+
+ bool
+ IsGPR(uint32_t reg_index) const;
+
+ FPRType
+ GetFPRType () const;
+
+ bool
+ IsFPR(uint32_t reg_index) const;
+
+ bool
+ WriteFPR();
+
+ bool IsFPR(uint32_t reg_index, FPRType fpr_type) const;
+
+ bool
+ CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order);
+
+ bool
+ CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+
+ bool
+ IsAVX (uint32_t reg_index) const;
+
+ bool
+ ReadFPR ();
+
+ lldb_private::Error
+ ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value);
+
+ bool
+ ReadGPR();
+
+ bool
+ WriteGPR();
+ };
+}
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_x86_64_h
+
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp Mon Jun 30 16:05:18 2014
@@ -62,18 +62,14 @@ RegisterContextFreeBSD_i386::RegisterCon
{
}
-RegisterContextFreeBSD_i386::~RegisterContextFreeBSD_i386()
-{
-}
-
size_t
-RegisterContextFreeBSD_i386::GetGPRSize()
+RegisterContextFreeBSD_i386::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextFreeBSD_i386::GetRegisterInfo()
+RegisterContextFreeBSD_i386::GetRegisterInfo() const
{
switch (m_target_arch.GetMachine())
{
@@ -84,3 +80,9 @@ RegisterContextFreeBSD_i386::GetRegister
return NULL;
}
}
+
+uint32_t
+RegisterContextFreeBSD_i386::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,15 @@ class RegisterContextFreeBSD_i386
{
public:
RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextFreeBSD_i386();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
};
#endif
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp Mon Jun 30 16:05:18 2014
@@ -71,20 +71,23 @@ RegisterContextFreeBSD_mips64::RegisterC
{
}
-RegisterContextFreeBSD_mips64::~RegisterContextFreeBSD_mips64()
-{
-}
-
size_t
-RegisterContextFreeBSD_mips64::GetGPRSize()
+RegisterContextFreeBSD_mips64::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextFreeBSD_mips64::GetRegisterInfo()
+RegisterContextFreeBSD_mips64::GetRegisterInfo() const
{
assert (m_target_arch.GetCore() == ArchSpec::eCore_mips64);
return g_register_infos_mips64;
}
+uint32_t
+RegisterContextFreeBSD_mips64::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0]));
+}
+
+
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,15 @@ class RegisterContextFreeBSD_mips64:
{
public:
RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextFreeBSD_mips64();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
};
#endif
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp Mon Jun 30 16:05:18 2014
@@ -67,10 +67,17 @@ struct dbreg {
#include "RegisterInfos_x86_64.h"
#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+static std::vector<lldb_private::RegisterInfo>&
+GetSharedRegisterInfoVector ()
+{
+ static std::vector<lldb_private::RegisterInfo> register_infos;
+ return register_infos;
+}
+
static const RegisterInfo *
GetRegisterInfo_i386(const lldb_private::ArchSpec& arch)
{
- static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ static std::vector<lldb_private::RegisterInfo> g_register_infos (GetSharedRegisterInfoVector ());
// Allocate RegisterInfo only once
if (g_register_infos.empty())
@@ -92,33 +99,61 @@ GetRegisterInfo_i386(const lldb_private:
return &g_register_infos[0];
}
-RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) :
- lldb_private::RegisterInfoInterface(target_arch)
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr (const lldb_private::ArchSpec& target_arch)
{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386 (target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
}
-RegisterContextFreeBSD_x86_64::~RegisterContextFreeBSD_x86_64()
+static uint32_t
+PrivateGetRegisterCount (const lldb_private::ArchSpec& target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ // This vector should have already been filled.
+ assert (!GetSharedRegisterInfoVector ().empty () && "i386 register info vector not filled.");
+ return static_cast<uint32_t> (GetSharedRegisterInfoVector().size ());
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p (PrivateGetRegisterInfoPtr (target_arch)),
+ m_register_count (PrivateGetRegisterCount (target_arch))
{
}
size_t
-RegisterContextFreeBSD_x86_64::GetGPRSize()
+RegisterContextFreeBSD_x86_64::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextFreeBSD_x86_64::GetRegisterInfo()
+RegisterContextFreeBSD_x86_64::GetRegisterInfo() const
{
- switch (m_target_arch.GetMachine())
- {
- case llvm::Triple::x86:
- return GetRegisterInfo_i386 (m_target_arch);
- case llvm::Triple::x86_64:
- return g_register_infos_x86_64;
- default:
- assert(false && "Unhandled target architecture.");
- return NULL;
- }
+ return m_register_info_p;
}
+uint32_t
+RegisterContextFreeBSD_x86_64::GetRegisterCount () const
+{
+ return m_register_count;
+}
+
+
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,19 @@ class RegisterContextFreeBSD_x86_64:
{
public:
RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextFreeBSD_x86_64();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ const uint32_t m_register_count;
};
#endif
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp Mon Jun 30 16:05:18 2014
@@ -100,18 +100,14 @@ RegisterContextLinux_i386::RegisterConte
{
}
-RegisterContextLinux_i386::~RegisterContextLinux_i386()
-{
-}
-
size_t
-RegisterContextLinux_i386::GetGPRSize()
+RegisterContextLinux_i386::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextLinux_i386::GetRegisterInfo()
+RegisterContextLinux_i386::GetRegisterInfo() const
{
switch (m_target_arch.GetMachine())
{
@@ -122,3 +118,10 @@ RegisterContextLinux_i386::GetRegisterIn
return NULL;
}
}
+
+uint32_t
+RegisterContextLinux_i386::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}
+
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,15 @@ class RegisterContextLinux_i386
{
public:
RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextLinux_i386();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
};
#endif
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp Mon Jun 30 16:05:18 2014
@@ -80,10 +80,17 @@ struct UserArea
#include "RegisterInfos_x86_64.h"
#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+static std::vector<lldb_private::RegisterInfo>&
+GetPrivateRegisterInfoVector ()
+{
+ static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
static const RegisterInfo *
GetRegisterInfo_i386(const lldb_private::ArchSpec &arch)
{
- static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ static std::vector<lldb_private::RegisterInfo> g_register_infos (GetPrivateRegisterInfoVector ());
// Allocate RegisterInfo only once
if (g_register_infos.empty())
@@ -105,33 +112,60 @@ GetRegisterInfo_i386(const lldb_private:
return &g_register_infos[0];
}
-RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) :
- lldb_private::RegisterInfoInterface(target_arch)
+static const RegisterInfo *
+GetRegisterInfoPtr (const ArchSpec &target_arch)
{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386 (target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
}
-RegisterContextLinux_x86_64::~RegisterContextLinux_x86_64()
+static uint32_t
+GetRegisterInfoCount (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ {
+ assert (!GetPrivateRegisterInfoVector ().empty () && "i386 register info not yet filled.");
+ return static_cast<uint32_t> (GetPrivateRegisterInfoVector ().size ());
+ }
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p (GetRegisterInfoPtr (target_arch)),
+ m_register_info_count (GetRegisterInfoCount (target_arch))
{
}
size_t
-RegisterContextLinux_x86_64::GetGPRSize()
+RegisterContextLinux_x86_64::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextLinux_x86_64::GetRegisterInfo()
+RegisterContextLinux_x86_64::GetRegisterInfo() const
{
- switch (m_target_arch.GetMachine())
- {
- case llvm::Triple::x86:
- return GetRegisterInfo_i386 (m_target_arch);
- case llvm::Triple::x86_64:
- return g_register_infos_x86_64;
- default:
- assert(false && "Unhandled target architecture.");
- return NULL;
- }
+ return m_register_info_p;
}
+uint32_t
+RegisterContextLinux_x86_64::GetRegisterCount () const
+{
+ return m_register_info_count;
+}
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,19 @@ class RegisterContextLinux_x86_64
{
public:
RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextLinux_x86_64();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
};
#endif
Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h Mon Jun 30 16:05:18 2014
@@ -10,6 +10,8 @@
#ifndef lldb_RegisterInfoInterface_h
#define lldb_RegisterInfoInterface_h
+#include "lldb/Core/ArchSpec.h"
+
namespace lldb_private
{
@@ -25,12 +27,20 @@ namespace lldb_private
virtual ~RegisterInfoInterface () {}
virtual size_t
- GetGPRSize () = 0;
+ GetGPRSize () const = 0;
virtual const lldb_private::RegisterInfo *
- GetRegisterInfo () = 0;
+ GetRegisterInfo () const = 0;
+
+ virtual uint32_t
+ GetRegisterCount () const = 0;
+
+ const lldb_private::ArchSpec&
+ GetTargetArchitecture() const
+ { return m_target_arch; }
public:
+ // FIXME make private.
lldb_private::ArchSpec m_target_arch;
};
Added: lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,292 @@
+//===-- lldb-x86-register-enums.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_x86_register_enums_h
+#define lldb_x86_register_enums_h
+
+namespace lldb_private
+{
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all i386 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_i386,
+ gpr_eax_i386 = k_first_gpr_i386,
+ gpr_ebx_i386,
+ gpr_ecx_i386,
+ gpr_edx_i386,
+ gpr_edi_i386,
+ gpr_esi_i386,
+ gpr_ebp_i386,
+ gpr_esp_i386,
+ gpr_eip_i386,
+ gpr_eflags_i386,
+ gpr_cs_i386,
+ gpr_fs_i386,
+ gpr_gs_i386,
+ gpr_ss_i386,
+ gpr_ds_i386,
+ gpr_es_i386,
+
+ k_first_alias_i386,
+ gpr_ax_i386 = k_first_alias_i386,
+ gpr_bx_i386,
+ gpr_cx_i386,
+ gpr_dx_i386,
+ gpr_di_i386,
+ gpr_si_i386,
+ gpr_bp_i386,
+ gpr_sp_i386,
+ gpr_ah_i386,
+ gpr_bh_i386,
+ gpr_ch_i386,
+ gpr_dh_i386,
+ gpr_al_i386,
+ gpr_bl_i386,
+ gpr_cl_i386,
+ gpr_dl_i386,
+ k_last_alias_i386 = gpr_dl_i386,
+
+ k_last_gpr_i386 = k_last_alias_i386,
+
+ k_first_fpr_i386,
+ fpu_fctrl_i386 = k_first_fpr_i386,
+ fpu_fstat_i386,
+ fpu_ftag_i386,
+ fpu_fop_i386,
+ fpu_fiseg_i386,
+ fpu_fioff_i386,
+ fpu_foseg_i386,
+ fpu_fooff_i386,
+ fpu_mxcsr_i386,
+ fpu_mxcsrmask_i386,
+ fpu_st0_i386,
+ fpu_st1_i386,
+ fpu_st2_i386,
+ fpu_st3_i386,
+ fpu_st4_i386,
+ fpu_st5_i386,
+ fpu_st6_i386,
+ fpu_st7_i386,
+ fpu_mm0_i386,
+ fpu_mm1_i386,
+ fpu_mm2_i386,
+ fpu_mm3_i386,
+ fpu_mm4_i386,
+ fpu_mm5_i386,
+ fpu_mm6_i386,
+ fpu_mm7_i386,
+ fpu_xmm0_i386,
+ fpu_xmm1_i386,
+ fpu_xmm2_i386,
+ fpu_xmm3_i386,
+ fpu_xmm4_i386,
+ fpu_xmm5_i386,
+ fpu_xmm6_i386,
+ fpu_xmm7_i386,
+ k_last_fpr_i386 = fpu_xmm7_i386,
+
+ k_first_avx_i386,
+ fpu_ymm0_i386 = k_first_avx_i386,
+ fpu_ymm1_i386,
+ fpu_ymm2_i386,
+ fpu_ymm3_i386,
+ fpu_ymm4_i386,
+ fpu_ymm5_i386,
+ fpu_ymm6_i386,
+ fpu_ymm7_i386,
+ k_last_avx_i386 = fpu_ymm7_i386,
+
+ dr0_i386,
+ dr1_i386,
+ dr2_i386,
+ dr3_i386,
+ dr4_i386,
+ dr5_i386,
+ dr6_i386,
+ dr7_i386,
+
+ k_num_registers_i386,
+ k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1,
+ k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1,
+ k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1
+ };
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all x86_64 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_x86_64,
+ gpr_rax_x86_64 = k_first_gpr_x86_64,
+ gpr_rbx_x86_64,
+ gpr_rcx_x86_64,
+ gpr_rdx_x86_64,
+ gpr_rdi_x86_64,
+ gpr_rsi_x86_64,
+ gpr_rbp_x86_64,
+ gpr_rsp_x86_64,
+ gpr_r8_x86_64,
+ gpr_r9_x86_64,
+ gpr_r10_x86_64,
+ gpr_r11_x86_64,
+ gpr_r12_x86_64,
+ gpr_r13_x86_64,
+ gpr_r14_x86_64,
+ gpr_r15_x86_64,
+ gpr_rip_x86_64,
+ gpr_rflags_x86_64,
+ gpr_cs_x86_64,
+ gpr_fs_x86_64,
+ gpr_gs_x86_64,
+ gpr_ss_x86_64,
+ gpr_ds_x86_64,
+ gpr_es_x86_64,
+
+ k_first_alias_x86_64,
+ gpr_eax_x86_64 = k_first_alias_x86_64,
+ gpr_ebx_x86_64,
+ gpr_ecx_x86_64,
+ gpr_edx_x86_64,
+ gpr_edi_x86_64,
+ gpr_esi_x86_64,
+ gpr_ebp_x86_64,
+ gpr_esp_x86_64,
+ gpr_r8d_x86_64, // Low 32 bits of r8
+ gpr_r9d_x86_64, // Low 32 bits of r9
+ gpr_r10d_x86_64, // Low 32 bits of r10
+ gpr_r11d_x86_64, // Low 32 bits of r11
+ gpr_r12d_x86_64, // Low 32 bits of r12
+ gpr_r13d_x86_64, // Low 32 bits of r13
+ gpr_r14d_x86_64, // Low 32 bits of r14
+ gpr_r15d_x86_64, // Low 32 bits of r15
+ gpr_ax_x86_64,
+ gpr_bx_x86_64,
+ gpr_cx_x86_64,
+ gpr_dx_x86_64,
+ gpr_di_x86_64,
+ gpr_si_x86_64,
+ gpr_bp_x86_64,
+ gpr_sp_x86_64,
+ gpr_r8w_x86_64, // Low 16 bits of r8
+ gpr_r9w_x86_64, // Low 16 bits of r9
+ gpr_r10w_x86_64, // Low 16 bits of r10
+ gpr_r11w_x86_64, // Low 16 bits of r11
+ gpr_r12w_x86_64, // Low 16 bits of r12
+ gpr_r13w_x86_64, // Low 16 bits of r13
+ gpr_r14w_x86_64, // Low 16 bits of r14
+ gpr_r15w_x86_64, // Low 16 bits of r15
+ gpr_ah_x86_64,
+ gpr_bh_x86_64,
+ gpr_ch_x86_64,
+ gpr_dh_x86_64,
+ gpr_al_x86_64,
+ gpr_bl_x86_64,
+ gpr_cl_x86_64,
+ gpr_dl_x86_64,
+ gpr_dil_x86_64,
+ gpr_sil_x86_64,
+ gpr_bpl_x86_64,
+ gpr_spl_x86_64,
+ gpr_r8l_x86_64, // Low 8 bits of r8
+ gpr_r9l_x86_64, // Low 8 bits of r9
+ gpr_r10l_x86_64, // Low 8 bits of r10
+ gpr_r11l_x86_64, // Low 8 bits of r11
+ gpr_r12l_x86_64, // Low 8 bits of r12
+ gpr_r13l_x86_64, // Low 8 bits of r13
+ gpr_r14l_x86_64, // Low 8 bits of r14
+ gpr_r15l_x86_64, // Low 8 bits of r15
+ k_last_alias_x86_64 = gpr_r15l_x86_64,
+
+ k_last_gpr_x86_64 = k_last_alias_x86_64,
+
+ k_first_fpr_x86_64,
+ fpu_fctrl_x86_64 = k_first_fpr_x86_64,
+ fpu_fstat_x86_64,
+ fpu_ftag_x86_64,
+ fpu_fop_x86_64,
+ fpu_fiseg_x86_64,
+ fpu_fioff_x86_64,
+ fpu_foseg_x86_64,
+ fpu_fooff_x86_64,
+ fpu_mxcsr_x86_64,
+ fpu_mxcsrmask_x86_64,
+ fpu_st0_x86_64,
+ fpu_st1_x86_64,
+ fpu_st2_x86_64,
+ fpu_st3_x86_64,
+ fpu_st4_x86_64,
+ fpu_st5_x86_64,
+ fpu_st6_x86_64,
+ fpu_st7_x86_64,
+ fpu_mm0_x86_64,
+ fpu_mm1_x86_64,
+ fpu_mm2_x86_64,
+ fpu_mm3_x86_64,
+ fpu_mm4_x86_64,
+ fpu_mm5_x86_64,
+ fpu_mm6_x86_64,
+ fpu_mm7_x86_64,
+ fpu_xmm0_x86_64,
+ fpu_xmm1_x86_64,
+ fpu_xmm2_x86_64,
+ fpu_xmm3_x86_64,
+ fpu_xmm4_x86_64,
+ fpu_xmm5_x86_64,
+ fpu_xmm6_x86_64,
+ fpu_xmm7_x86_64,
+ fpu_xmm8_x86_64,
+ fpu_xmm9_x86_64,
+ fpu_xmm10_x86_64,
+ fpu_xmm11_x86_64,
+ fpu_xmm12_x86_64,
+ fpu_xmm13_x86_64,
+ fpu_xmm14_x86_64,
+ fpu_xmm15_x86_64,
+ k_last_fpr_x86_64 = fpu_xmm15_x86_64,
+
+ k_first_avx_x86_64,
+ fpu_ymm0_x86_64 = k_first_avx_x86_64,
+ fpu_ymm1_x86_64,
+ fpu_ymm2_x86_64,
+ fpu_ymm3_x86_64,
+ fpu_ymm4_x86_64,
+ fpu_ymm5_x86_64,
+ fpu_ymm6_x86_64,
+ fpu_ymm7_x86_64,
+ fpu_ymm8_x86_64,
+ fpu_ymm9_x86_64,
+ fpu_ymm10_x86_64,
+ fpu_ymm11_x86_64,
+ fpu_ymm12_x86_64,
+ fpu_ymm13_x86_64,
+ fpu_ymm14_x86_64,
+ fpu_ymm15_x86_64,
+ k_last_avx_x86_64 = fpu_ymm15_x86_64,
+
+ dr0_x86_64,
+ dr1_x86_64,
+ dr2_x86_64,
+ dr3_x86_64,
+ dr4_x86_64,
+ dr5_x86_64,
+ dr6_x86_64,
+ dr7_x86_64,
+
+ k_num_registers_x86_64,
+ k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1,
+ k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1,
+ k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1
+ };
+
+}
+
+#endif // #ifndef lldb_x86_register_enums_h
Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h Mon Jun 30 16:05:18 2014
@@ -132,7 +132,7 @@ public:
// Returns AUXV structure found in the core file
const lldb::DataBufferSP
- GetAuxvData();
+ GetAuxvData() override;
protected:
void
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Mon Jun 30 16:05:18 2014
@@ -1586,6 +1586,8 @@ GDBRemoteCommunicationClient::GetGDBServ
bool
GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS));
+
if (force || m_qHostInfo_is_valid == eLazyBoolCalculate)
{
m_qHostInfo_is_valid = eLazyBoolNo;
@@ -1819,6 +1821,9 @@ GDBRemoteCommunicationClient::GetHostInf
{
assert (byte_order == m_host_arch.GetByteOrder());
}
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ());
}
if (!distribution_id.empty ())
m_host_arch.SetDistributionId (distribution_id.c_str ());
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Mon Jun 30 16:05:18 2014
@@ -14,19 +14,26 @@
// C Includes
// C++ Includes
+#include <cstring>
+
// Other libraries and framework includes
#include "llvm/ADT/Triple.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Debug.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/File.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "../../../Host/common/NativeProcessProtocol.h"
+#include "../../../Host/common/NativeThreadProtocol.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -37,6 +44,22 @@ using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
+// GDBRemote Errors
+//----------------------------------------------------------------------
+
+namespace
+{
+ enum GDBRemoteServerError
+ {
+ // Set to the first unused error number in literal form below
+ eErrorFirst = 29,
+ eErrorNoProcess = eErrorFirst,
+ eErrorResume,
+ eErrorExitStatus
+ };
+}
+
+//----------------------------------------------------------------------
// GDBRemoteCommunicationServer constructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
@@ -50,12 +73,28 @@ GDBRemoteCommunicationServer::GDBRemoteC
m_proc_infos (),
m_proc_infos_index (0),
m_port_map (),
- m_port_offset(0)
+ m_port_offset(0),
+ m_current_tid (LLDB_INVALID_THREAD_ID),
+ m_continue_tid (LLDB_INVALID_THREAD_ID),
+ m_debugged_process_mutex (Mutex::eMutexTypeRecursive),
+ m_debugged_process_sp (),
+ m_debugger_sp (),
+ m_stdio_communication ("process.stdio"),
+ m_exit_now (false),
+ m_inferior_prev_state (StateType::eStateInvalid),
+ m_thread_suffix_supported (false),
+ m_list_threads_in_stop_reply (false),
+ m_active_auxv_buffer_sp (),
+ m_saved_registers_mutex (),
+ m_saved_registers_map (),
+ m_next_saved_registers_id (1)
{
+ assert(is_platform && "must be lldb-platform if debugger is not specified");
}
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform,
- const lldb::PlatformSP& platform_sp) :
+ const lldb::PlatformSP& platform_sp,
+ lldb::DebuggerSP &debugger_sp) :
GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
m_platform_sp (platform_sp),
m_async_thread (LLDB_INVALID_HOST_THREAD),
@@ -66,9 +105,24 @@ GDBRemoteCommunicationServer::GDBRemoteC
m_proc_infos (),
m_proc_infos_index (0),
m_port_map (),
- m_port_offset(0)
+ m_port_offset(0),
+ m_current_tid (LLDB_INVALID_THREAD_ID),
+ m_continue_tid (LLDB_INVALID_THREAD_ID),
+ m_debugged_process_mutex (Mutex::eMutexTypeRecursive),
+ m_debugged_process_sp (),
+ m_debugger_sp (debugger_sp),
+ m_stdio_communication ("process.stdio"),
+ m_exit_now (false),
+ m_inferior_prev_state (StateType::eStateInvalid),
+ m_thread_suffix_supported (false),
+ m_list_threads_in_stop_reply (false),
+ m_active_auxv_buffer_sp (),
+ m_saved_registers_mutex (),
+ m_saved_registers_map (),
+ m_next_saved_registers_id (1)
{
assert(platform_sp);
+ assert((is_platform || debugger_sp) && "must specify non-NULL debugger_sp when lldb-gdbserver");
}
//----------------------------------------------------------------------
@@ -78,37 +132,14 @@ GDBRemoteCommunicationServer::~GDBRemote
{
}
-
-//void *
-//GDBRemoteCommunicationServer::AsyncThread (void *arg)
-//{
-// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
-//
-// Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
-// if (log)
-// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
-//
-// StringExtractorGDBRemote packet;
-//
-// while ()
-// {
-// if (packet.
-// }
-//
-// if (log)
-// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
-//
-// process->m_async_thread = LLDB_INVALID_HOST_THREAD;
-// return NULL;
-//}
-//
-bool
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
Error &error,
bool &interrupt,
bool &quit)
{
StringExtractorGDBRemote packet;
+
PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
if (packet_result == PacketResult::Success)
{
@@ -124,11 +155,6 @@ GDBRemoteCommunicationServer::GetPacketA
quit = true;
break;
- case StringExtractorGDBRemote::eServerPacketType_interrupt:
- error.SetErrorString("interrupt received");
- interrupt = true;
- break;
-
default:
case StringExtractorGDBRemote::eServerPacketType_unimplemented:
packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
@@ -164,6 +190,7 @@ GDBRemoteCommunicationServer::GetPacketA
case StringExtractorGDBRemote::eServerPacketType_k:
packet_result = Handle_k (packet);
+ quit = true;
break;
case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
@@ -174,6 +201,10 @@ GDBRemoteCommunicationServer::GetPacketA
packet_result = Handle_qGroupName (packet);
break;
+ case StringExtractorGDBRemote::eServerPacketType_qProcessInfo:
+ packet_result = Handle_qProcessInfo (packet);
+ break;
+
case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
packet_result = Handle_qProcessInfoPID (packet);
break;
@@ -238,6 +269,26 @@ GDBRemoteCommunicationServer::GetPacketA
packet_result = Handle_qPlatform_shell (packet);
break;
+ case StringExtractorGDBRemote::eServerPacketType_C:
+ packet_result = Handle_C (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_c:
+ packet_result = Handle_c (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_vCont:
+ packet_result = Handle_vCont (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_vCont_actions:
+ packet_result = Handle_vCont_actions (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_stop_reason: // ?
+ packet_result = Handle_stop_reason (packet);
+ break;
+
case StringExtractorGDBRemote::eServerPacketType_vFile_open:
packet_result = Handle_vFile_Open (packet);
break;
@@ -281,6 +332,92 @@ GDBRemoteCommunicationServer::GetPacketA
case StringExtractorGDBRemote::eServerPacketType_vFile_unlink:
packet_result = Handle_vFile_unlink (packet);
break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qRegisterInfo:
+ packet_result = Handle_qRegisterInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qfThreadInfo:
+ packet_result = Handle_qfThreadInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qsThreadInfo:
+ packet_result = Handle_qsThreadInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_p:
+ packet_result = Handle_p (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_P:
+ packet_result = Handle_P (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_H:
+ packet_result = Handle_H (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_m:
+ packet_result = Handle_m (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_M:
+ packet_result = Handle_M (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported:
+ packet_result = Handle_qMemoryRegionInfoSupported (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo:
+ packet_result = Handle_qMemoryRegionInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_interrupt:
+ if (IsGdbServer ())
+ packet_result = Handle_interrupt (packet);
+ else
+ {
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ }
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_Z:
+ packet_result = Handle_Z (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_z:
+ packet_result = Handle_z (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_s:
+ packet_result = Handle_s (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qSupported:
+ packet_result = Handle_qSupported (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported:
+ packet_result = Handle_QThreadSuffixSupported (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply:
+ packet_result = Handle_QListThreadsInStopReply (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read:
+ packet_result = Handle_qXfer_auxv_read (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState:
+ packet_result = Handle_QSaveRegisterState (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState:
+ packet_result = Handle_QRestoreRegisterState (packet);
+ break;
}
}
else
@@ -295,7 +432,12 @@ GDBRemoteCommunicationServer::GetPacketA
error.SetErrorString("timeout");
}
}
- return packet_result == PacketResult::Success;
+
+ // Check if anything occurred that would force us to want to exit.
+ if (m_exit_now)
+ quit = true;
+
+ return packet_result;
}
lldb_private::Error
@@ -318,6 +460,96 @@ GDBRemoteCommunicationServer::SetLaunchF
lldb_private::Error
GDBRemoteCommunicationServer::LaunchProcess ()
{
+ // FIXME This looks an awful lot like we could override this in
+ // derived classes, one for lldb-platform, the other for lldb-gdbserver.
+ if (IsGdbServer ())
+ return LaunchDebugServerProcess ();
+ else
+ return LaunchPlatformProcess ();
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::LaunchDebugServerProcess ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
+ return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ lldb_private::Error error;
+ {
+ Mutex::Locker locker (m_debugged_process_mutex);
+ assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists");
+ error = m_platform_sp->LaunchNativeProcess (
+ m_process_launch_info,
+ *this,
+ m_debugged_process_sp);
+ }
+
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
+ return error;
+ }
+
+ // Setup stdout/stderr mapping from inferior.
+ auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+ if (terminal_fd >= 0)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ }
+
+ printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ());
+
+ // Add to list of spawned processes.
+ lldb::pid_t pid;
+ if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID)
+ {
+ // add to spawned pids
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ // On an lldb-gdbserver, we would expect there to be only one.
+ assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+ m_spawned_pids.insert (pid);
+ }
+ }
+
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s beginning check to wait for launched application to hit first stop", __FUNCTION__);
+
+ int iteration = 0;
+ // Wait for the process to hit its first stop state.
+ while (!StateIsStoppedState (m_debugged_process_sp->GetState (), false))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s waiting for launched process to hit first stop (%d)...", __FUNCTION__, iteration++);
+
+ // FIXME use a sleep method with finer granularity.
+ sleep (1);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s launched application has hit first stop", __FUNCTION__);
+
+ }
+
+ return error;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::LaunchPlatformProcess ()
+{
if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
@@ -341,359 +573,1013 @@ GDBRemoteCommunicationServer::LaunchProc
lldb::pid_t pid;
if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID )
{
- Mutex::Locker locker (m_spawned_pids_mutex);
- m_spawned_pids.insert(pid);
+ // add to spawned pids
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(pid);
+ }
}
return error;
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
+lldb_private::Error
+GDBRemoteCommunicationServer::AttachToProcess (lldb::pid_t pid)
{
- // TODO: Log the packet we aren't handling...
- return SendPacketNoLock ("", 0);
-}
+ Error error;
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
-{
- char packet[16];
- int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
- assert (packet_len < (int)sizeof(packet));
- return SendPacketNoLock (packet, packet_len);
-}
+ if (!IsGdbServer ())
+ {
+ error.SetErrorString("cannot AttachToProcess () unless process is lldb-gdbserver");
+ return error;
+ }
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64, __FUNCTION__, pid);
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::SendOKResponse ()
-{
- return SendPacketNoLock ("OK", 2);
+ // Scope for mutex locker.
+ {
+ // Before we try to attach, make sure we aren't already monitoring something else.
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (!m_spawned_pids.empty ())
+ {
+ error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin());
+ return error;
+ }
+
+ // Try to attach.
+ error = m_platform_sp->AttachNativeProcess (pid, *this, m_debugged_process_sp);
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ());
+ return error;
+ }
+
+ // Setup stdout/stderr mapping from inferior.
+ auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+ if (terminal_fd >= 0)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ }
+
+ printf ("Attached to process %" PRIu64 "...\n", pid);
+
+ // Add to list of spawned processes.
+ assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+ m_spawned_pids.insert (pid);
+
+ return error;
+ }
}
-bool
-GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
+void
+GDBRemoteCommunicationServer::InitializeDelegate (lldb_private::NativeProcessProtocol *process)
{
- return GetAck() == PacketResult::Success;
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (process->GetState ()));
+ }
}
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol *process)
{
- StreamString response;
-
- // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- ArchSpec host_arch (Host::GetArchitecture ());
- const llvm::Triple &host_triple = host_arch.GetTriple();
- response.PutCString("triple:");
- response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
- response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+ // send W notification
+ ExitType exit_type = ExitType::eExitTypeInvalid;
+ int return_code = 0;
+ std::string exit_description;
- const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
- if (distribution_id)
+ const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description);
+ if (!got_exit_info)
{
- response.PutCString("distribution_id:");
- response.PutCStringAsRawHex8(distribution_id);
- response.PutCString(";");
- }
-
- uint32_t cpu = host_arch.GetMachOCPUType();
- uint32_t sub = host_arch.GetMachOCPUSubType();
- if (cpu != LLDB_INVALID_CPUTYPE)
- response.Printf ("cputype:%u;", cpu);
- if (sub != LLDB_INVALID_CPUTYPE)
- response.Printf ("cpusubtype:%u;", sub);
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ());
- if (cpu == ArchSpec::kCore_arm_any)
- response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
+ StreamGDBRemote response;
+ response.PutChar ('E');
+ response.PutHex8 (GDBRemoteServerError::eErrorExitStatus);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
else
- response.Printf("watchpoint_exceptions_received:after;");
-
- switch (lldb::endian::InlHostByteOrder())
{
- case eByteOrderBig: response.PutCString ("endian:big;"); break;
- case eByteOrderLittle: response.PutCString ("endian:little;"); break;
- case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
- default: response.PutCString ("endian:unknown;"); break;
- }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ());
- uint32_t major = UINT32_MAX;
- uint32_t minor = UINT32_MAX;
- uint32_t update = UINT32_MAX;
- if (Host::GetOSVersion (major, minor, update))
- {
- if (major != UINT32_MAX)
+ StreamGDBRemote response;
+
+ char return_type_code;
+ switch (exit_type)
{
- response.Printf("os_version:%u", major);
- if (minor != UINT32_MAX)
- {
- response.Printf(".%u", minor);
- if (update != UINT32_MAX)
- response.Printf(".%u", update);
- }
- response.PutChar(';');
+ case ExitType::eExitTypeExit: return_type_code = 'W'; break;
+ case ExitType::eExitTypeSignal: return_type_code = 'X'; break;
+ case ExitType::eExitTypeStop: return_type_code = 'S'; break;
+
+ case ExitType::eExitTypeInvalid:
+ default: return_type_code = 'E'; break;
}
+ response.PutChar (return_type_code);
+
+ // POSIX exit status limited to unsigned 8 bits.
+ response.PutHex8 (return_code);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
+}
- std::string s;
- if (Host::GetOSBuildString (s))
+static void
+AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap)
+{
+ int64_t i;
+ if (swap)
{
- response.PutCString ("os_build:");
- response.PutCStringAsRawHex8(s.c_str());
- response.PutChar(';');
+ for (i = buf_size-1; i >= 0; i--)
+ response.PutHex8 (buf[i]);
}
- if (Host::GetOSKernelDescription (s))
+ else
{
- response.PutCString ("os_kernel:");
- response.PutCStringAsRawHex8(s.c_str());
- response.PutChar(';');
+ for (i = 0; i < buf_size; i++)
+ response.PutHex8 (buf[i]);
}
-#if defined(__APPLE__)
+}
-#if defined(__arm__) || defined(__arm64__)
- // For iOS devices, we are connected through a USB Mux so we never pretend
- // to actually have a hostname as far as the remote lldb that is connecting
- // to this lldb-platform is concerned
- response.PutCString ("hostname:");
- response.PutCStringAsRawHex8("127.0.0.1");
- response.PutChar(';');
-#else // #if defined(__arm__) || defined(__arm64__)
- if (Host::GetHostname (s))
+static void
+WriteRegisterValueInHexFixedWidth (StreamString &response,
+ NativeRegisterContextSP ®_ctx_sp,
+ const RegisterInfo ®_info,
+ const RegisterValue *reg_value_p)
+{
+ RegisterValue reg_value;
+ if (!reg_value_p)
{
- response.PutCString ("hostname:");
- response.PutCStringAsRawHex8(s.c_str());
- response.PutChar(';');
+ Error error = reg_ctx_sp->ReadRegister (®_info, reg_value);
+ if (error.Success ())
+ reg_value_p = ®_value;
+ // else log.
}
-#endif // #if defined(__arm__) || defined(__arm64__)
-#else // #if defined(__APPLE__)
- if (Host::GetHostname (s))
+ if (reg_value_p)
{
- response.PutCString ("hostname:");
- response.PutCStringAsRawHex8(s.c_str());
- response.PutChar(';');
+ AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false);
+ }
+ else
+ {
+ // Zero-out any unreadable values.
+ if (reg_info.byte_size > 0)
+ {
+ std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0');
+ AppendHexValue (response, zeros.data(), zeros.size(), false);
+ }
}
-#endif // #if defined(__APPLE__)
-
- return SendPacketNoLock (response.GetData(), response.GetSize());
}
+// WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value);
+
+
static void
-CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
-{
- response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
- proc_info.GetProcessID(),
- proc_info.GetParentProcessID(),
- proc_info.GetUserID(),
- proc_info.GetGroupID(),
- proc_info.GetEffectiveUserID(),
- proc_info.GetEffectiveGroupID());
- response.PutCString ("name:");
- response.PutCStringAsRawHex8(proc_info.GetName());
- response.PutChar(';');
- const ArchSpec &proc_arch = proc_info.GetArchitecture();
- if (proc_arch.IsValid())
- {
- const llvm::Triple &proc_triple = proc_arch.GetTriple();
- response.PutCString("triple:");
- response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
- response.PutChar(';');
- }
+WriteGdbRegnumWithFixedWidthHexRegisterValue (StreamString &response,
+ NativeRegisterContextSP ®_ctx_sp,
+ const RegisterInfo ®_info,
+ const RegisterValue ®_value)
+{
+ // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX
+ // gdb register number, and VVVVVVVV is the correct number of hex bytes
+ // as ASCII for the register value.
+ if (reg_info.kinds[eRegisterKindGDB] == LLDB_INVALID_REGNUM)
+ return;
+
+ response.Printf ("%.02x:", reg_info.kinds[eRegisterKindGDB]);
+ WriteRegisterValueInHexFixedWidth (response, reg_ctx_sp, reg_info, ®_value);
+ response.PutChar (';');
}
+
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid)
{
- // Packet format: "qProcessInfoPID:%i" where %i is the pid
- packet.SetFilePos(::strlen ("qProcessInfoPID:"));
- lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
- if (pid != LLDB_INVALID_PROCESS_ID)
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer ())
{
- ProcessInstanceInfo proc_info;
- if (Host::GetProcessInfo(pid, proc_info))
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
+
+ // Ensure we have a debugged process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (50);
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s preparing packet for pid %" PRIu64 " tid %" PRIu64,
+ __FUNCTION__, m_debugged_process_sp->GetID (), tid);
+
+ // Ensure we can get info on the given thread.
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+ if (!thread_sp)
+ return SendErrorResponse (51);
+
+ // Grab the reason this thread stopped.
+ struct ThreadStopInfo tid_stop_info;
+ if (!thread_sp->GetStopReason (tid_stop_info))
+ return SendErrorResponse (52);
+
+ const bool did_exec = tid_stop_info.reason == eStopReasonExec;
+ // FIXME implement register handling for exec'd inferiors.
+ // if (did_exec)
+ // {
+ // const bool force = true;
+ // InitializeRegisters(force);
+ // }
+
+ StreamString response;
+ // Output the T packet with the thread
+ response.PutChar ('T');
+ int signum = tid_stop_info.details.signal.signo;
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64,
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ tid,
+ signum,
+ tid_stop_info.reason,
+ tid_stop_info.details.exception.type);
+ }
+
+ switch (tid_stop_info.reason)
+ {
+ case eStopReasonSignal:
+ case eStopReasonException:
+ signum = thread_sp->TranslateStopInfoToGdbSignal (tid_stop_info);
+ break;
+ default:
+ signum = 0;
+ if (log)
{
- StreamString response;
- CreateProcessInfoResponse (proc_info, response);
- return SendPacketNoLock (response.GetData(), response.GetSize());
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " has stop reason %d, using signo = 0 in stop reply response",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ tid,
+ tid_stop_info.reason);
}
+ break;
}
- return SendErrorResponse (1);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
-{
- m_proc_infos_index = 0;
- m_proc_infos.Clear();
+ // Print the signal number.
+ response.PutHex8 (signum & 0xff);
- ProcessInstanceInfoMatch match_info;
- packet.SetFilePos(::strlen ("qfProcessInfo"));
- if (packet.GetChar() == ':')
+ // Include the tid.
+ response.Printf ("thread:%" PRIx64 ";", tid);
+
+ // Include the thread name if there is one.
+ const char *thread_name = thread_sp->GetName ();
+ if (thread_name && thread_name[0])
{
+ size_t thread_name_len = strlen(thread_name);
- std::string key;
- std::string value;
- while (packet.GetNameColonValue(key, value))
+ if (::strcspn (thread_name, "$#+-;:") == thread_name_len)
{
- bool success = true;
- if (key.compare("name") == 0)
- {
- StringExtractor extractor;
- extractor.GetStringRef().swap(value);
- extractor.GetHexByteString (value);
- match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
- }
- else if (key.compare("name_match") == 0)
+ response.PutCString ("name:");
+ response.PutCString (thread_name);
+ }
+ else
+ {
+ // The thread name contains special chars, send as hex bytes.
+ response.PutCString ("hexname:");
+ response.PutCStringAsRawHex8 (thread_name);
+ }
+ response.PutChar (';');
+ }
+
+ // FIXME look for analog
+ // thread_identifier_info_data_t thread_ident_info;
+ // if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
+ // {
+ // if (thread_ident_info.dispatch_qaddr != 0)
+ // ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';';
+ // }
+
+ // If a 'QListThreadsInStopReply' was sent to enable this feature, we
+ // will send all thread IDs back in the "threads" key whose value is
+ // a listc of hex thread IDs separated by commas:
+ // "threads:10a,10b,10c;"
+ // This will save the debugger from having to send a pair of qfThreadInfo
+ // and qsThreadInfo packets, but it also might take a lot of room in the
+ // stop reply packet, so it must be enabled only on systems where there
+ // are no limits on packet lengths.
+ if (m_list_threads_in_stop_reply)
+ {
+ response.PutCString ("threads:");
+
+ uint32_t thread_index = 0;
+ NativeThreadProtocolSP listed_thread_sp;
+ for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+ {
+ if (thread_index > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx64, listed_thread_sp->GetID ());
+ }
+ response.PutChar (';');
+ }
+
+ //
+ // Expedite registers.
+ //
+
+ // Grab the register context.
+ NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext ();
+ if (reg_ctx_sp)
+ {
+ // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers.
+ const RegisterSet *reg_set_p;
+ if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers);
+
+ for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p)
{
- if (value.compare("equals") == 0)
+ const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p);
+ if (reg_info_p == nullptr)
{
- match_info.SetNameMatchType (eNameMatchEquals);
- }
- else if (value.compare("starts_with") == 0)
- {
- match_info.SetNameMatchType (eNameMatchStartsWith);
- }
- else if (value.compare("ends_with") == 0)
- {
- match_info.SetNameMatchType (eNameMatchEndsWith);
- }
- else if (value.compare("contains") == 0)
- {
- match_info.SetNameMatchType (eNameMatchContains);
- }
- else if (value.compare("regex") == 0)
- {
- match_info.SetNameMatchType (eNameMatchRegularExpression);
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p);
}
- else
+ else if (reg_info_p->value_regs == nullptr)
{
- success = false;
+ // Only expediate registers that are not contained in other registers.
+ RegisterValue reg_value;
+ Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value);
+ if (error.Success ())
+ WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value);
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ());
+
+ }
}
}
- else if (key.compare("pid") == 0)
- {
- match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
- }
- else if (key.compare("parent_pid") == 0)
- {
- match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
- }
- else if (key.compare("uid") == 0)
- {
- match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("gid") == 0)
- {
- match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("euid") == 0)
- {
- match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("egid") == 0)
- {
- match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
- }
- else if (key.compare("all_users") == 0)
- {
- match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
- }
- else if (key.compare("triple") == 0)
- {
- match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
- }
- else
- {
- success = false;
- }
+ }
+ }
- if (!success)
- return SendErrorResponse (2);
+ if (did_exec)
+ {
+ response.PutCString ("reason:exec;");
+ }
+ else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type)
+ {
+ response.PutCString ("metype:");
+ response.PutHex64 (tid_stop_info.details.exception.type);
+ response.PutCString (";mecount:");
+ response.PutHex32 (tid_stop_info.details.exception.data_count);
+ response.PutChar (';');
+
+ for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i)
+ {
+ response.PutCString ("medata:");
+ response.PutHex64 (tid_stop_info.details.exception.data[i]);
+ response.PutChar (';');
}
}
- if (Host::FindProcesses (match_info, m_proc_infos))
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServer::HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // Send the exit result, and don't flush output.
+ // Note: flushing output here would join the inferior stdio reflection thread, which
+ // would gunk up the waitpid monitor thread that is calling this.
+ PacketResult result = SendStopReasonForState (StateType::eStateExited, false);
+ if (result != PacketResult::Success)
{
- // We found something, return the first item by calling the get
- // subsequent process info packet handler...
- return Handle_qsProcessInfo (packet);
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
}
- return SendErrorResponse (3);
+
+ // Remove the process from the list of spawned pids.
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.erase (process->GetID ()) < 1)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ());
+
+ }
+ }
+
+ // FIXME can't do this yet - since process state propagation is currently
+ // synchronous, it is running off the NativeProcessProtocol's innards and
+ // will tear down the NPP while it still has code to execute.
+#if 0
+ // Clear the NativeProcessProtocol pointer.
+ {
+ Mutex::Locker locker (m_debugged_process_mutex);
+ m_debugged_process_sp.reset();
+ }
+#endif
+
+ // Close the pipe to the inferior terminal i/o if we launched it
+ // and set one up. Otherwise, 'k' and its flush of stdio could
+ // end up waiting on a thread join that will never end. Consider
+ // adding a timeout to the connection thread join call so we
+ // can avoid that scenario altogether.
+ MaybeCloseInferiorTerminalConnection ();
+
+ // We are ready to exit the debug monitor.
+ m_exit_now = true;
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process)
{
- if (m_proc_infos_index < m_proc_infos.GetSize())
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // Send the stop reason unless this is the stop after the
+ // launch or attach.
+ switch (m_inferior_prev_state)
{
- StreamString response;
- CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
- ++m_proc_infos_index;
- return SendPacketNoLock (response.GetData(), response.GetSize());
+ case eStateLaunching:
+ case eStateAttaching:
+ // Don't send anything per debugserver behavior.
+ break;
+ default:
+ // In all other cases, send the stop reason.
+ PacketResult result = SendStopReasonForState (StateType::eStateStopped, false);
+ if (result != PacketResult::Success)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
+ }
+ break;
}
- return SendErrorResponse (4);
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state)
{
- // Packet format: "qUserName:%i" where %i is the uid
- packet.SetFilePos(::strlen ("qUserName:"));
- uint32_t uid = packet.GetU32 (UINT32_MAX);
- if (uid != UINT32_MAX)
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
{
- std::string name;
- if (Host::GetUserName (uid, name))
+ log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (state));
+ }
+
+ switch (state)
+ {
+ case StateType::eStateExited:
+ HandleInferiorState_Exited (process);
+ break;
+
+ case StateType::eStateStopped:
+ HandleInferiorState_Stopped (process);
+ break;
+
+ default:
+ if (log)
{
- StreamString response;
- response.PutCStringAsRawHex8 (name.c_str());
- return SendPacketNoLock (response.GetData(), response.GetSize());
+ log->Printf ("GDBRemoteCommunicationServer::%s didn't handle state change for pid %" PRIu64 ", new state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (state));
}
+ break;
}
- return SendErrorResponse (5);
+ // Remember the previous state reported to us.
+ m_inferior_prev_state = state;
}
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::SendONotification (const char *buffer, uint32_t len)
{
- // Packet format: "qGroupName:%i" where %i is the gid
- packet.SetFilePos(::strlen ("qGroupName:"));
- uint32_t gid = packet.GetU32 (UINT32_MAX);
- if (gid != UINT32_MAX)
+ if ((buffer == nullptr) || (len == 0))
{
- std::string name;
- if (Host::GetGroupName (gid, name))
- {
- StreamString response;
- response.PutCStringAsRawHex8 (name.c_str());
- return SendPacketNoLock (response.GetData(), response.GetSize());
- }
+ // Nothing to send.
+ return PacketResult::Success;
}
- return SendErrorResponse (6);
+
+ StreamString response;
+ response.PutChar ('O');
+ response.PutBytesAsRawHex8 (buffer, len);
+
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+lldb_private::Error
+GDBRemoteCommunicationServer::SetSTDIOFileDescriptor (int fd)
{
- packet.SetFilePos(::strlen ("qSpeedTest:"));
+ Error error;
- std::string key;
- std::string value;
- bool success = packet.GetNameColonValue(key, value);
- if (success && key.compare("response_size") == 0)
+ // Set up the Read Thread for reading/handling process I/O
+ std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true));
+ if (!conn_up)
{
- uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
- if (success)
- {
- if (response_size == 0)
- return SendOKResponse();
- StreamString response;
- uint32_t bytes_left = response_size;
- response.PutCString("data:");
- while (bytes_left > 0)
- {
+ error.SetErrorString ("failed to create ConnectionFileDescriptor");
+ return error;
+ }
+
+ m_stdio_communication.SetConnection (conn_up.release());
+ if (!m_stdio_communication.IsConnected ())
+ {
+ error.SetErrorString ("failed to set connection for inferior I/O communication");
+ return error;
+ }
+
+ m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
+ m_stdio_communication.StartReadThread();
+
+ return error;
+}
+
+void
+GDBRemoteCommunicationServer::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ GDBRemoteCommunicationServer *server = reinterpret_cast<GDBRemoteCommunicationServer*> (baton);
+ static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len));
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
+{
+ // TODO: Log the packet we aren't handling...
+ return SendPacketNoLock ("", 0);
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
+{
+ char packet[16];
+ int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
+ assert (packet_len < (int)sizeof(packet));
+ return SendPacketNoLock (packet, packet_len);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : "");
+ return SendErrorResponse (0x03);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendOKResponse ()
+{
+ return SendPacketNoLock ("OK", 2);
+}
+
+bool
+GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
+{
+ return GetAck() == PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+
+ ArchSpec host_arch (Host::GetArchitecture ());
+ const llvm::Triple &host_triple = host_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
+ response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+
+ const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
+ if (distribution_id)
+ {
+ response.PutCString("distribution_id:");
+ response.PutCStringAsRawHex8(distribution_id);
+ response.PutCString(";");
+ }
+
+ // Only send out MachO info when lldb-platform/llgs is running on a MachO host.
+#if defined(__APPLE__)
+ uint32_t cpu = host_arch.GetMachOCPUType();
+ uint32_t sub = host_arch.GetMachOCPUSubType();
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cputype:%u;", cpu);
+ if (sub != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cpusubtype:%u;", sub);
+
+ if (cpu == ArchSpec::kCore_arm_any)
+ response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
+ else
+ response.Printf("watchpoint_exceptions_received:after;");
+#else
+ response.Printf("watchpoint_exceptions_received:after;");
+#endif
+
+ switch (lldb::endian::InlHostByteOrder())
+ {
+ case eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default: response.PutCString ("endian:unknown;"); break;
+ }
+
+ uint32_t major = UINT32_MAX;
+ uint32_t minor = UINT32_MAX;
+ uint32_t update = UINT32_MAX;
+ if (Host::GetOSVersion (major, minor, update))
+ {
+ if (major != UINT32_MAX)
+ {
+ response.Printf("os_version:%u", major);
+ if (minor != UINT32_MAX)
+ {
+ response.Printf(".%u", minor);
+ if (update != UINT32_MAX)
+ response.Printf(".%u", update);
+ }
+ response.PutChar(';');
+ }
+ }
+
+ std::string s;
+ if (Host::GetOSBuildString (s))
+ {
+ response.PutCString ("os_build:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+ if (Host::GetOSKernelDescription (s))
+ {
+ response.PutCString ("os_kernel:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+#if defined(__APPLE__)
+
+#if defined(__arm__) || defined(__arm64__)
+ // For iOS devices, we are connected through a USB Mux so we never pretend
+ // to actually have a hostname as far as the remote lldb that is connecting
+ // to this lldb-platform is concerned
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8("127.0.0.1");
+ response.PutChar(';');
+#else // #if defined(__arm__) || defined(__arm64__)
+ if (Host::GetHostname (s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+#endif // #if defined(__arm__) || defined(__arm64__)
+
+#else // #if defined(__APPLE__)
+ if (Host::GetHostname (s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+#endif // #if defined(__APPLE__)
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+static void
+CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+ response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+ response.PutCString ("name:");
+ response.PutCStringAsRawHex8(proc_info.GetName());
+ response.PutChar(';');
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutChar(';');
+ }
+}
+
+static void
+CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+ response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const uint32_t cpu_type = proc_arch.GetMachOCPUType();
+ if (cpu_type != 0)
+ response.Printf ("cputype:%" PRIx32 ";", cpu_type);
+
+ const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType();
+ if (cpu_subtype != 0)
+ response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype);
+
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+ const std::string vendor = proc_triple.getVendorName ();
+ if (!vendor.empty ())
+ response.Printf ("vendor:%s;", vendor.c_str ());
+
+ std::string ostype = proc_triple.getOSName ();
+ // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64.
+ if (proc_triple.getVendor () == llvm::Triple::Apple)
+ {
+ switch (proc_triple.getArch ())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::arm64:
+ ostype = "ios";
+ break;
+ default:
+ // No change.
+ break;
+ }
+ }
+ response.Printf ("ostype:%s;", ostype.c_str ());
+
+
+ switch (proc_arch.GetByteOrder ())
+ {
+ case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default:
+ // Nothing.
+ break;
+ }
+
+ if (proc_triple.isArch64Bit ())
+ response.PutCString ("ptrsize:8;");
+ else if (proc_triple.isArch32Bit ())
+ response.PutCString ("ptrsize:4;");
+ else if (proc_triple.isArch16Bit ())
+ response.PutCString ("ptrsize:2;");
+ }
+
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
+{
+ // Only the gdb server handles this.
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse (packet.GetStringRef ().c_str ());
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo (m_debugged_process_sp->GetID (), proc_info))
+ {
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+ }
+
+ return SendErrorResponse (1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qProcessInfoPID:%i" where %i is the pid
+ packet.SetFilePos(::strlen ("qProcessInfoPID:"));
+ lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo(pid, proc_info))
+ {
+ StreamString response;
+ CreateProcessInfoResponse (proc_info, response);
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
+{
+ m_proc_infos_index = 0;
+ m_proc_infos.Clear();
+
+ ProcessInstanceInfoMatch match_info;
+ packet.SetFilePos(::strlen ("qfProcessInfo"));
+ if (packet.GetChar() == ':')
+ {
+
+ std::string key;
+ std::string value;
+ while (packet.GetNameColonValue(key, value))
+ {
+ bool success = true;
+ if (key.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.GetHexByteString (value);
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
+ }
+ else if (key.compare("name_match") == 0)
+ {
+ if (value.compare("equals") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEquals);
+ }
+ else if (value.compare("starts_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchStartsWith);
+ }
+ else if (value.compare("ends_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEndsWith);
+ }
+ else if (value.compare("contains") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchContains);
+ }
+ else if (value.compare("regex") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchRegularExpression);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else if (key.compare("pid") == 0)
+ {
+ match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("parent_pid") == 0)
+ {
+ match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("uid") == 0)
+ {
+ match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("gid") == 0)
+ {
+ match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("euid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("egid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("all_users") == 0)
+ {
+ match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
+ }
+ else if (key.compare("triple") == 0)
+ {
+ match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
+ }
+ else
+ {
+ success = false;
+ }
+
+ if (!success)
+ return SendErrorResponse (2);
+ }
+ }
+
+ if (Host::FindProcesses (match_info, m_proc_infos))
+ {
+ // We found something, return the first item by calling the get
+ // subsequent process info packet handler...
+ return Handle_qsProcessInfo (packet);
+ }
+ return SendErrorResponse (3);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+{
+ if (m_proc_infos_index < m_proc_infos.GetSize())
+ {
+ StreamString response;
+ CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
+ ++m_proc_infos_index;
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse (4);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qUserName:%i" where %i is the uid
+ packet.SetFilePos(::strlen ("qUserName:"));
+ uint32_t uid = packet.GetU32 (UINT32_MAX);
+ if (uid != UINT32_MAX)
+ {
+ std::string name;
+ if (Host::GetUserName (uid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (5);
+
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qGroupName:%i" where %i is the gid
+ packet.SetFilePos(::strlen ("qGroupName:"));
+ uint32_t gid = packet.GetU32 (UINT32_MAX);
+ if (gid != UINT32_MAX)
+ {
+ std::string name;
+ if (Host::GetGroupName (gid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (6);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qSpeedTest:"));
+
+ std::string key;
+ std::string value;
+ bool success = packet.GetNameColonValue(key, value);
+ if (success && key.compare("response_size") == 0)
+ {
+ uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
+ if (success)
+ {
+ if (response_size == 0)
+ return SendOKResponse();
+ StreamString response;
+ uint32_t bytes_left = response_size;
+ response.PutCString("data:");
+ while (bytes_left > 0)
+ {
if (bytes_left >= 26)
{
response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -701,906 +1587,2621 @@ GDBRemoteCommunicationServer::Handle_qSp
}
else
{
- response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
- bytes_left = 0;
+ response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left = 0;
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (7);
+}
+
+//
+//static bool
+//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
+//{
+// const int time_delta_usecs = 100000;
+// const int num_retries = timeout_in_seconds/time_delta_usecs;
+// for (int i=0; i<num_retries; i++)
+// {
+// struct proc_bsdinfo bsd_info;
+// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
+// (uint64_t) 0,
+// &bsd_info,
+// PROC_PIDTBSDINFO_SIZE);
+//
+// switch (error)
+// {
+// case EINVAL:
+// case ENOTSUP:
+// case ESRCH:
+// case EPERM:
+// return false;
+//
+// default:
+// break;
+//
+// case 0:
+// if (bsd_info.pbi_status == SSTOP)
+// return true;
+// }
+// ::usleep (time_delta_usecs);
+// }
+// return false;
+//}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
+{
+ // The 'A' packet is the most over designed packet ever here with
+ // redundant argument indexes, redundant argument lengths and needed hex
+ // encoded argument string values. Really all that is needed is a comma
+ // separated hex encoded argument value list, but we will stay true to the
+ // documented version of the 'A' packet here...
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ int actual_arg_index = 0;
+
+ packet.SetFilePos(1); // Skip the 'A'
+ bool success = true;
+ while (success && packet.GetBytesLeft() > 0)
+ {
+ // Decode the decimal argument string length. This length is the
+ // number of hex nibbles in the argument string value.
+ const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+ if (arg_len == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument hex string length is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument index. We ignore this really becuase
+ // who would really send down the arguments in a random order???
+ const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
+ if (arg_idx == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument index is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument string value from hex bytes
+ // back into a UTF8 string and make sure the length
+ // matches the one supplied in the packet
+ std::string arg;
+ if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2))
+ success = false;
+ else
+ {
+ // If there are any bytes left
+ if (packet.GetBytesLeft())
+ {
+ if (packet.GetChar() != ',')
+ success = false;
+ }
+
+ if (success)
+ {
+ if (arg_idx == 0)
+ m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
+ m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ());
+ ++actual_arg_index;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ {
+ m_process_launch_error = LaunchProcess ();
+ if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ return SendOKResponse ();
+ }
+ else
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("GDBRemoteCommunicationServer::%s failed to launch exe: %s",
+ __FUNCTION__,
+ m_process_launch_error.AsCString());
+
+ }
+ }
+ return SendErrorResponse (8);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ if (IsGdbServer ())
+ {
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ // Make sure we set the current thread so g and p packets return
+ // the data the gdb will expect.
+ lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+ SetCurrentThreadID (tid);
+
+ NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread ();
+ if (!thread_sp)
+ return SendErrorResponse (69);
+
+ response.Printf ("QC%" PRIx64, thread_sp->GetID ());
+ }
+ else
+ {
+ // NOTE: lldb should now be using qProcessInfo for process IDs. This path here
+ // should not be used. It is reporting process id instead of thread id. The
+ // correct answer doesn't seem to make much sense for lldb-platform.
+ // CONSIDER: flip to "unsupported".
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+ response.Printf("QC%" PRIx64, pid);
+
+ // this should always be platform here
+ assert (m_is_platform && "this code path should only be traversed for lldb-platform");
+
+ if (m_is_platform)
+ {
+ // If we launch a process and this GDB server is acting as a platform,
+ // then we need to clear the process launch state so we can start
+ // launching another process. In order to launch a process a bunch or
+ // packets need to be sent: environment packets, working directory,
+ // disable ASLR, and many more settings. When we launch a process we
+ // then need to know when to clear this information. Currently we are
+ // selecting the 'qC' packet as that packet which seems to make the most
+ // sense.
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_process_launch_info.Clear();
+ }
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
+{
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ FreePortForProcess(pid);
+ return m_spawned_pids.erase(pid) > 0;
+}
+bool
+GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
+ server->DebugserverProcessReaped (pid);
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid)
+{
+ // reap a process that we were debugging (but not debugserver)
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ return m_spawned_pids.erase(pid) > 0;
+}
+
+bool
+GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
+ server->DebuggedProcessReaped (pid);
+ return true;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ return SendErrorResponse(9);
+#else
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ if (m_is_platform)
+ {
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ Error error;
+ std::string hostname;
+ // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
+ // with the TMPDIR environnement variable
+ packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
+ std::string name;
+ std::string value;
+ uint16_t port = UINT16_MAX;
+ while (packet.GetNameColonValue(name, value))
+ {
+ if (name.compare ("host") == 0)
+ hostname.swap(value);
+ else if (name.compare ("port") == 0)
+ port = Args::StringToUInt32(value.c_str(), 0, 0);
+ }
+ if (port == UINT16_MAX)
+ port = GetNextAvailablePort();
+
+ // Spawn a new thread to accept the port that gets bound after
+ // binding to port 0 (zero).
+
+ if (error.Success())
+ {
+ // Spawn a debugserver and try to get the port it listens to.
+ ProcessLaunchInfo debugserver_launch_info;
+ if (hostname.empty())
+ hostname = "127.0.0.1";
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);
+
+ debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
+
+ error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(),
+ port,
+ debugserver_launch_info,
+ port);
+
+ lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+
+
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(debugserver_pid);
+ if (port > 0)
+ AssociatePortWithProcess(port, debugserver_pid);
+ }
+ else
+ {
+ if (port > 0)
+ FreePort (port);
+ }
+
+ if (error.Success())
+ {
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
+ assert (response_len < (int)sizeof(response));
+ PacketResult packet_result = SendPacketNoLock (response, response_len);
+
+ if (packet_result != PacketResult::Success)
+ {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ ::kill (debugserver_pid, SIGINT);
}
+ return packet_result;
+ }
+ }
+ }
+ return SendErrorResponse (9);
+#endif
+}
+
+bool
+GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)
+{
+ // make sure we know about this process
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return false;
+ }
+
+ // first try a SIGTERM (standard kill)
+ Host::Kill (pid, SIGTERM);
+
+ // check if that worked
+ for (size_t i=0; i<10; ++i)
+ {
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // it is now killed
+ return true;
+ }
+ }
+ usleep (10000);
+ }
+
+ // check one more time after the final usleep
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // the launched process still lives. Now try killling it again,
+ // this time with an unblockable signal.
+ Host::Kill (pid, SIGKILL);
+
+ for (size_t i=0; i<10; ++i)
+ {
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // it is now killed
+ return true;
+ }
+ }
+ usleep (10000);
+ }
+
+ // check one more time after the final usleep
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // no luck - the process still lives
+ return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+
+ lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+ // verify that we know anything about this pid.
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // not a pid we know about
+ return SendErrorResponse (10);
+ }
+ }
+
+ // go ahead and attempt to kill the spawned process
+ if (KillSpawnedProcess (pid))
+ return SendOKResponse ();
+ else
+ return SendErrorResponse (11);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet)
+{
+ // ignore for now if we're lldb_platform
+ if (m_is_platform)
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+ // shutdown all spawned processes
+ std::set<lldb::pid_t> spawned_pids_copy;
+
+ // copy pids
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
+ }
+
+ // nuke the spawned processes
+ for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
+ {
+ lldb::pid_t spawned_pid = *it;
+ if (!KillSpawnedProcess (spawned_pid))
+ {
+ fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
+ }
+ }
+
+ FlushInferiorOutput ();
+
+ // No OK response for kill packet.
+ // return SendOKResponse ();
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
+{
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ StreamString response;
+ response.PutChar('E');
+ response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QEnvironment:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QLaunchArch:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ const char* arch_triple = packet.Peek();
+ ArchSpec arch_spec(arch_triple,NULL);
+ m_process_launch_info.SetArchitecture(arch_spec);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(13);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (m_is_platform)
+ {
+#ifdef _WIN32
+ // Not implemented on Windows
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented");
+#else
+ // If this packet is sent to a platform, then change the current working directory
+ if (::chdir(path.c_str()) != 0)
+ return SendErrorResponse(errno);
+#endif
+ }
+ else
+ {
+ m_process_launch_info.SwapWorkingDirectory (path);
+ }
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ if (m_is_platform)
+ {
+ // If this packet is sent to a platform, then change the current working directory
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, sizeof(cwd)) == NULL)
+ {
+ return SendErrorResponse(errno);
+ }
+ else
+ {
+ response.PutBytesAsRawHex8(cwd, strlen(cwd));
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ else
+ {
+ const char *working_dir = m_process_launch_info.GetWorkingDirectory();
+ if (working_dir && working_dir[0])
+ {
+ response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ else
+ {
+ return SendErrorResponse(14);
+ }
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDIN:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (15);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDOUT:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (16);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDERR:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (17);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_C (StringExtractorGDBRemote &packet)
+{
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ // Pull out the signal number.
+ packet.SetFilePos (::strlen ("C"));
+ if (packet.GetBytesLeft () < 1)
+ {
+ // Shouldn't be using a C without a signal.
+ return SendIllFormedResponse (packet, "C packet specified without signal.");
+ }
+ const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (signo == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse (packet, "failed to parse signal number");
+
+ // Handle optional continue address.
+ if (packet.GetBytesLeft () > 0)
+ {
+ // FIXME add continue at address support for $C{signo}[;{continue-address}].
+ if (*packet.Peek () == ';')
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ else
+ return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}");
+ }
+
+ lldb_private::ResumeActionList resume_actions (StateType::eStateRunning, 0);
+ Error error;
+
+ // We have two branches: what to do if a continue thread is specified (in which case we target
+ // sending the signal to that thread), or when we don't have a continue thread set (in which
+ // case we send a signal to the process).
+
+ // TODO discuss with Greg Clayton, make sure this makes sense.
+
+ lldb::tid_t signal_tid = GetContinueThreadID ();
+ if (signal_tid != LLDB_INVALID_THREAD_ID)
+ {
+ // The resume action for the continue thread (or all threads if a continue thread is not set).
+ lldb_private::ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) };
+
+ // Add the action for the continue thread (or all threads when the continue thread isn't present).
+ resume_actions.Append (action);
+ }
+ else
+ {
+ // Send the signal to the process since we weren't targeting a specific continue thread with the signal.
+ error = m_debugged_process_sp->Signal (signo);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to send signal for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+
+ return SendErrorResponse (0x52);
+ }
+ }
+
+ // Resume the threads.
+ error = m_debugged_process_sp->Resume (resume_actions);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to resume threads for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+
+ return SendErrorResponse (0x38);
+ }
+
+ // Don't send an "OK" packet; response is the stopped/exited message.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment)
+{
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // We reuse this method in vCont - don't double adjust the file position.
+ if (!skip_file_pos_adjustment)
+ packet.SetFilePos (::strlen ("c"));
+
+ // For now just support all continue.
+ const bool has_continue_address = (packet.GetBytesLeft () > 0);
+ if (has_continue_address)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ());
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ }
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ // Build the ResumeActionList
+ lldb_private::ResumeActionList actions (StateType::eStateRunning, 0);
+
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s c failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from continue.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &packet)
+{
+ if (!IsGdbServer ())
+ {
+ // only llgs supports $vCont.
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ }
+
+ // We handle $vCont messages for c.
+ // TODO add C, s and S.
+ StreamString response;
+ response.Printf("vCont;c;C;s;S");
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vCont (StringExtractorGDBRemote &packet)
+{
+ if (!IsGdbServer ())
+ {
+ // only llgs supports $vCont
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ }
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s handling vCont packet", __FUNCTION__);
+
+ packet.SetFilePos (::strlen ("vCont"));
+
+ // Check if this is all continue (no options or ";c").
+ if (!packet.GetBytesLeft () || (::strcmp (packet.Peek (), ";c") == 0))
+ {
+ // Move the packet past the ";c".
+ if (packet.GetBytesLeft ())
+ packet.SetFilePos (packet.GetFilePos () + ::strlen (";c"));
+
+ const bool skip_file_pos_adjustment = true;
+ return Handle_c (packet, skip_file_pos_adjustment);
+ }
+ else if (::strcmp (packet.Peek (), ";s") == 0)
+ {
+ // Move past the ';', then do a simple 's'.
+ packet.SetFilePos (packet.GetFilePos () + 1);
+ return Handle_s (packet);
+ }
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ ResumeActionList thread_actions;
+
+ while (packet.GetBytesLeft () && *packet.Peek () == ';')
+ {
+ // Skip the semi-colon.
+ packet.GetChar ();
+
+ // Build up the thread action.
+ ResumeAction thread_action;
+ thread_action.tid = LLDB_INVALID_THREAD_ID;
+ thread_action.state = eStateInvalid;
+ thread_action.signal = 0;
+
+ const char action = packet.GetChar ();
+ switch (action)
+ {
+ case 'C':
+ thread_action.signal = packet.GetHexMaxU32 (false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action");
+ // Fall through to next case...
+
+ case 'c':
+ // Continue
+ thread_action.state = eStateRunning;
+ break;
+
+ case 'S':
+ thread_action.signal = packet.GetHexMaxU32 (false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action");
+ // Fall through to next case...
+
+ case 's':
+ // Step
+ thread_action.state = eStateStepping;
+ break;
+
+ default:
+ return SendIllFormedResponse (packet, "Unsupported vCont action");
+ break;
+ }
+
+ // Parse out optional :{thread-id} value.
+ if (packet.GetBytesLeft () && (*packet.Peek () == ':'))
+ {
+ // Consume the separator.
+ packet.GetChar ();
+
+ thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID);
+ if (thread_action.tid == LLDB_INVALID_THREAD_ID)
+ return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet");
+ }
+
+ thread_actions.Append (thread_action);
+ }
+
+ // If a default action for all other threads wasn't mentioned
+ // then we should stop the threads.
+ thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
+
+ Error error = m_debugged_process_sp->Resume (thread_actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s vCont failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from vCont.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
+{
+ // Send response first before changing m_send_acks to we ack this packet
+ PacketResult packet_result = SendOKResponse ();
+ m_send_acks = false;
+ return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_mkdir:"));
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = Host::MakeDirectory(path.c_str(),mode);
+ if (error.Success())
+ return SendPacketNoLock ("OK", 2);
+ else
+ return SendErrorResponse(error.GetError());
+ }
+ return SendErrorResponse(20);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_chmod:"));
+
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = Host::SetFilePermissions (path.c_str(), mode);
+ if (error.Success())
+ return SendPacketNoLock ("OK", 2);
+ else
+ return SendErrorResponse(error.GetError());
+ }
+ return SendErrorResponse(19);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:open:"));
+ std::string path;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (!path.empty())
+ {
+ if (packet.GetChar() == ',')
+ {
+ uint32_t flags = packet.GetHexMaxU32(false, 0);
+ if (packet.GetChar() == ',')
+ {
+ mode_t mode = packet.GetHexMaxU32(false, 0600);
+ Error error;
+ int fd = ::open (path.c_str(), flags, mode);
+ const int save_errno = fd == -1 ? errno : 0;
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", fd);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ }
+ return SendErrorResponse(18);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:close:"));
+ int fd = packet.GetS32(-1);
+ Error error;
+ int err = -1;
+ int save_errno = 0;
+ if (fd >= 0)
+ {
+ err = close(fd);
+ save_errno = err == -1 ? errno : 0;
+ }
+ else
+ {
+ save_errno = EINVAL;
+ }
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", err);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ // Not implemented on Windows
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented");
+#else
+ StreamGDBRemote response;
+ packet.SetFilePos(::strlen("vFile:pread:"));
+ int fd = packet.GetS32(-1);
+ if (packet.GetChar() == ',')
+ {
+ uint64_t count = packet.GetU64(UINT64_MAX);
+ if (packet.GetChar() == ',')
+ {
+ uint64_t offset = packet.GetU64(UINT32_MAX);
+ if (count == UINT64_MAX)
+ {
+ response.Printf("F-1:%i", EINVAL);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+
+ std::string buffer(count, 0);
+ const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
+ const int save_errno = bytes_read == -1 ? errno : 0;
+ response.PutChar('F');
+ response.Printf("%zi", bytes_read);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ else
+ {
+ response.PutChar(';');
+ response.PutEscapedBytes(&buffer[0], bytes_read);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(21);
+
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented");
+#else
+ packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+ StreamGDBRemote response;
+ response.PutChar('F');
+
+ int fd = packet.GetU32(UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ off_t offset = packet.GetU64(UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string buffer;
+ if (packet.GetEscapedBinaryData(buffer))
+ {
+ const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
+ const int save_errno = bytes_written == -1 ? errno : 0;
+ response.Printf("%zi", bytes_written);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ }
+ else
+ {
+ response.Printf ("-1,%i", EINVAL);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(27);
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:size:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutHex64(retcode);
+ if (retcode == UINT64_MAX)
+ {
+ response.PutChar(',');
+ response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(22);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:mode:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ Error error;
+ const uint32_t mode = File::GetPermissions(path.c_str(), error);
+ StreamString response;
+ response.Printf("F%u", mode);
+ if (mode == 0 || error.Fail())
+ response.Printf(",%i", (int)error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(23);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:exists:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutChar(',');
+ if (retcode)
+ response.PutChar('1');
+ else
+ response.PutChar('0');
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(24);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:symlink:"));
+ std::string dst, src;
+ packet.GetHexByteStringTerminatedBy(dst, ',');
+ packet.GetChar(); // Skip ',' char
+ packet.GetHexByteString(src);
+ Error error = Host::Symlink(src.c_str(), dst.c_str());
+ StreamString response;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:unlink:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = Host::Unlink(path.c_str());
+ StreamString response;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_shell:"));
+ std::string path;
+ std::string working_dir;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (!path.empty())
+ {
+ if (packet.GetChar() == ',')
+ {
+ // FIXME: add timeout to qPlatform_shell packet
+ // uint32_t timeout = packet.GetHexMaxU32(false, 32);
+ uint32_t timeout = 10;
+ if (packet.GetChar() == ',')
+ packet.GetHexByteString(working_dir);
+ int status, signo;
+ std::string output;
+ Error err = Host::RunShellCommand(path.c_str(),
+ working_dir.empty() ? NULL : working_dir.c_str(),
+ &status, &signo, &output, timeout);
+ StreamGDBRemote response;
+ if (err.Fail())
+ {
+ response.PutCString("F,");
+ response.PutHex32(UINT32_MAX);
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex32(status);
+ response.PutChar(',');
+ response.PutHex32(signo);
+ response.PutChar(',');
+ response.PutEscapedBytes(output.c_str(), output.size());
}
- return SendPacketNoLock (response.GetData(), response.GetSize());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
}
- return SendErrorResponse (7);
+ return SendErrorResponse(24);
}
-//
-//static bool
-//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
-//{
-// const int time_delta_usecs = 100000;
-// const int num_retries = timeout_in_seconds/time_delta_usecs;
-// for (int i=0; i<num_retries; i++)
-// {
-// struct proc_bsdinfo bsd_info;
-// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
-// (uint64_t) 0,
-// &bsd_info,
-// PROC_PIDTBSDINFO_SIZE);
-//
-// switch (error)
-// {
-// case EINVAL:
-// case ENOTSUP:
-// case ESRCH:
-// case EPERM:
-// return false;
-//
-// default:
-// break;
-//
-// case 0:
-// if (bsd_info.pbi_status == SSTOP)
-// return true;
-// }
-// ::usleep (time_delta_usecs);
-// }
-// return false;
-//}
+void
+GDBRemoteCommunicationServer::SetCurrentThreadID (lldb::tid_t tid)
+{
+ assert (IsGdbServer () && "SetCurrentThreadID() called when not GdbServer code");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s setting current thread id to %" PRIu64, __FUNCTION__, tid);
+
+ m_current_tid = tid;
+ if (m_debugged_process_sp)
+ m_debugged_process_sp->SetCurrentThreadID (m_current_tid);
+}
+
+void
+GDBRemoteCommunicationServer::SetContinueThreadID (lldb::tid_t tid)
+{
+ assert (IsGdbServer () && "SetContinueThreadID() called when not GdbServer code");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid);
+
+ m_continue_tid = tid;
+}
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_stop_reason (StringExtractorGDBRemote &packet)
{
- // The 'A' packet is the most over designed packet ever here with
- // redundant argument indexes, redundant argument lengths and needed hex
- // encoded argument string values. Really all that is needed is a comma
- // separated hex encoded argument value list, but we will stay true to the
- // documented version of the 'A' packet here...
+ // Handle the $? gdbremote command.
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_stop_reason() unimplemented");
- packet.SetFilePos(1); // Skip the 'A'
- bool success = true;
- while (success && packet.GetBytesLeft() > 0)
+ // If no process, indicate error
+ if (!m_debugged_process_sp)
+ return SendErrorResponse (02);
+
+ return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ switch (process_state)
{
- // Decode the decimal argument string length. This length is the
- // number of hex nibbles in the argument string value.
- const uint32_t arg_len = packet.GetU32(UINT32_MAX);
- if (arg_len == UINT32_MAX)
- success = false;
- else
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ // NOTE: gdb protocol doc looks like it should return $OK
+ // when everything is running (i.e. no stopped result).
+ return PacketResult::Success; // Ignore
+
+ case eStateSuspended:
+ case eStateStopped:
+ case eStateCrashed:
{
- // Make sure the argument hex string length is followed by a comma
- if (packet.GetChar() != ',')
- success = false;
- else
- {
- // Decode the argument index. We ignore this really becuase
- // who would really send down the arguments in a random order???
- const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
- if (arg_idx == UINT32_MAX)
- success = false;
- else
- {
- // Make sure the argument index is followed by a comma
- if (packet.GetChar() != ',')
- success = false;
- else
- {
- // Decode the argument string value from hex bytes
- // back into a UTF8 string and make sure the length
- // matches the one supplied in the packet
- std::string arg;
- if (packet.GetHexByteString(arg) != (arg_len / 2))
- success = false;
- else
- {
- // If there are any bytes lft
- if (packet.GetBytesLeft())
- {
- if (packet.GetChar() != ',')
- success = false;
- }
+ lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+ // Make sure we set the current thread so g and p packets return
+ // the data the gdb will expect.
+ SetCurrentThreadID (tid);
+ return SendStopReplyPacketForThread (tid);
+ }
- if (success)
- {
- if (arg_idx == 0)
- m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
- m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
- }
- }
- }
- }
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ if (flush_on_exit)
+ FlushInferiorOutput ();
+ return SendWResponse(m_debugged_process_sp.get());
+
+ default:
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", current state reporting not handled: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ StateAsCString (process_state));
}
- }
+ break;
}
+
+ return SendErrorResponse (0);
+}
- if (success)
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
+{
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:MD5:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
{
- // FIXME: remove linux restriction once eLaunchFlagDebug is supported
-#if !defined (__linux__)
- m_process_launch_info.GetFlags().Set (eLaunchFlagDebug);
-#endif
- m_process_launch_error = LaunchProcess ();
- if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ uint64_t a,b;
+ StreamGDBRemote response;
+ if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
{
- return SendOKResponse ();
+ response.PutCString("F,");
+ response.PutCString("x");
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex64(a);
+ response.PutHex64(b);
}
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
- return SendErrorResponse (8);
+ return SendErrorResponse(25);
}
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_qRegisterInfo (StringExtractorGDBRemote &packet)
{
- lldb::pid_t pid = m_process_launch_info.GetProcessID();
- StreamString response;
- response.Printf("QC%" PRIx64, pid);
- if (m_is_platform)
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qRegisterInfo() unimplemented");
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ // Ensure we have a thread.
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0));
+ if (!thread_sp)
+ return SendErrorResponse (69);
+
+ // Get the register context for the first thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ return SendErrorResponse (69);
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("qRegisterInfo"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ return SendErrorResponse (69);
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetRegisterCount ())
+ return SendErrorResponse (69);
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return SendErrorResponse (69);
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ response.PutCString ("name:");
+ response.PutCString (reg_info->name);
+ response.PutChar (';');
+
+ if (reg_info->alt_name && reg_info->alt_name[0])
+ {
+ response.PutCString ("alt-name:");
+ response.PutCString (reg_info->alt_name);
+ response.PutChar (';');
+ }
+
+ response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset);
+
+ switch (reg_info->encoding)
{
- // If we launch a process and this GDB server is acting as a platform,
- // then we need to clear the process launch state so we can start
- // launching another process. In order to launch a process a bunch or
- // packets need to be sent: environment packets, working directory,
- // disable ASLR, and many more settings. When we launch a process we
- // then need to know when to clear this information. Currently we are
- // selecting the 'qC' packet as that packet which seems to make the most
- // sense.
- if (pid != LLDB_INVALID_PROCESS_ID)
+ case eEncodingUint: response.PutCString ("encoding:uint;"); break;
+ case eEncodingSint: response.PutCString ("encoding:sint;"); break;
+ case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break;
+ case eEncodingVector: response.PutCString ("encoding:vector;"); break;
+ default: break;
+ }
+
+ switch (reg_info->format)
+ {
+ case eFormatBinary: response.PutCString ("format:binary;"); break;
+ case eFormatDecimal: response.PutCString ("format:decimal;"); break;
+ case eFormatHex: response.PutCString ("format:hex;"); break;
+ case eFormatFloat: response.PutCString ("format:float;"); break;
+ case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break;
+ case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break;
+ case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break;
+ case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break;
+ case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break;
+ case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break;
+ case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break;
+ case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break;
+ default: break;
+ };
+
+ const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index);
+ if (register_set_name)
+ {
+ response.PutCString ("set:");
+ response.PutCString (register_set_name);
+ response.PutChar (';');
+ }
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM)
+ response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]);
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
+ response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
+
+ switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break;
+ case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break;
+ case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break;
+ case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break;
+ case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break;
+ case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break;
+ case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break;
+ case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break;
+ case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break;
+ case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break;
+ case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break;
+ case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break;
+ case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break;
+ default: break;
+ }
+
+ if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+ {
+ response.PutCString ("container-regs:");
+ int i = 0;
+ for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
{
- m_process_launch_info.Clear();
+ if (i > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx32, *reg_num);
}
+ response.PutChar (';');
}
- return SendPacketNoLock (response.GetData(), response.GetSize());
-}
-bool
-GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
-{
- Mutex::Locker locker (m_spawned_pids_mutex);
- FreePortForProcess(pid);
- return m_spawned_pids.erase(pid) > 0;
+ if (reg_info->invalidate_regs && reg_info->invalidate_regs[0])
+ {
+ response.PutCString ("invalidate-regs:");
+ int i = 0;
+ for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
+ {
+ if (i > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx32, *reg_num);
+ }
+ response.PutChar (';');
+ }
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
-bool
-GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
- lldb::pid_t pid,
- bool exited,
- int signal, // Zero for no signal
- int status) // Exit value of process if signal is zero
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qfThreadInfo (StringExtractorGDBRemote &packet)
{
- GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
- server->DebugserverProcessReaped (pid);
- return true;
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented");
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ StreamGDBRemote response;
+ response.PutChar ('m');
+
+ NativeThreadProtocolSP thread_sp;
+ uint32_t thread_index;
+ for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index);
+ thread_sp;
+ ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+ {
+ if (thread_index > 0)
+ response.PutChar(',');
+ response.Printf ("%" PRIx64, thread_sp->GetID ());
+ }
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
-bool
-GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid)
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qsThreadInfo (StringExtractorGDBRemote &packet)
{
- // reap a process that we were debugging (but not debugserver)
- Mutex::Locker locker (m_spawned_pids_mutex);
- return m_spawned_pids.erase(pid) > 0;
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_qsThreadInfo() unimplemented");
+
+ // FIXME for now we return the full thread list in the initial packet and always do nothing here.
+ return SendPacketNoLock ("l", 1);
}
-bool
-GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton,
- lldb::pid_t pid,
- bool exited,
- int signal, // Zero for no signal
- int status) // Exit value of process if signal is zero
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_p (StringExtractorGDBRemote &packet)
{
- GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
- server->DebuggedProcessReaped (pid);
- return true;
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_p() unimplemented");
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("p"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ());
+ return SendErrorResponse (0x15);
+ }
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+ return SendErrorResponse (0x15);
+ }
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ // Retrieve the value
+ RegisterValue reg_value;
+ Error error = reg_context_sp->ReadRegister (reg_info, reg_value);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+ return SendErrorResponse (0x15);
+ }
+
+ const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ());
+ if (!data)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index);
+ return SendErrorResponse (0x15);
+ }
+
+ // FIXME flip as needed to get data in big/little endian format for this host.
+ for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i)
+ response.PutHex8 (data[i]);
+
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
}
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_P (StringExtractorGDBRemote &packet)
{
-#ifdef _WIN32
- return SendErrorResponse(9);
-#else
- // Spawn a local debugserver as a platform so we can then attach or launch
- // a process...
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_P() unimplemented");
- if (m_is_platform)
+ // Ensure there is more content.
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "Empty P packet");
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("P"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
{
- // Sleep and wait a bit for debugserver to start to listen...
- ConnectionFileDescriptor file_conn;
- Error error;
- std::string hostname;
- // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
- // with the TMPDIR environnement variable
- packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
- std::string name;
- std::string value;
- uint16_t port = UINT16_MAX;
- while (packet.GetNameColonValue(name, value))
- {
- if (name.compare ("host") == 0)
- hostname.swap(value);
- else if (name.compare ("port") == 0)
- port = Args::StringToUInt32(value.c_str(), 0, 0);
- }
- if (port == UINT16_MAX)
- port = GetNextAvailablePort();
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x29);
+ }
- // Spawn a new thread to accept the port that gets bound after
- // binding to port 0 (zero).
+ // Note debugserver would send an E30 here.
+ if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '='))
+ return SendIllFormedResponse (packet, "P packet missing '=' char after register number");
- if (error.Success())
- {
- // Spawn a debugserver and try to get the port it listens to.
- ProcessLaunchInfo debugserver_launch_info;
- if (hostname.empty())
- hostname = "127.0.0.1";
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
- if (log)
- log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);
+ // Get process architecture.
+ ArchSpec process_arch;
+ if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to retrieve inferior architecture", __FUNCTION__);
+ return SendErrorResponse (0x49);
+ }
- debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
-
- error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(),
- port,
- debugserver_launch_info,
- port);
+ // Parse out the value.
+ const uint64_t raw_value = packet.GetHexMaxU64 (process_arch.GetByteOrder () == lldb::eByteOrderLittle, std::numeric_limits<uint64_t>::max ());
- lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available (thread index 0)", __FUNCTION__);
+ return SendErrorResponse (0x28);
+ }
+ // Get the thread's register context.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
- if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- m_spawned_pids.insert(debugserver_pid);
- if (port > 0)
- AssociatePortWithProcess(port, debugserver_pid);
- }
- else
- {
- if (port > 0)
- FreePort (port);
- }
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+ return SendErrorResponse (0x48);
+ }
- if (error.Success())
- {
- char response[256];
- const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
- assert (response_len < (int)sizeof(response));
- PacketResult packet_result = SendPacketNoLock (response, response_len);
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ());
+ return SendErrorResponse (0x47);
+ }
- if (packet_result != PacketResult::Success)
- {
- if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
- ::kill (debugserver_pid, SIGINT);
- }
- return packet_result;
- }
- }
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ // FIXME Could be suffixed with a thread: parameter.
+ // That thread then needs to be fed back into the reg context retrieval above.
+ Error error = reg_context_sp->WriteRegisterFromUnsigned (reg_info, raw_value);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+ return SendErrorResponse (0x32);
}
- return SendErrorResponse (9);
-#endif
+
+ return SendOKResponse();
}
-bool
-GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_H (StringExtractorGDBRemote &packet)
{
- // make sure we know about this process
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_H() unimplemented");
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return false;
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
}
- // first try a SIGTERM (standard kill)
- Host::Kill (pid, SIGTERM);
-
- // check if that worked
- for (size_t i=0; i<10; ++i)
+ // Parse out which variant of $H is requested.
+ packet.SetFilePos (strlen("H"));
+ if (packet.GetBytesLeft () < 1)
{
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- {
- // it is now killed
- return true;
- }
- }
- usleep (10000);
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, H command missing {g,c} variant", __FUNCTION__);
+ return SendIllFormedResponse (packet, "H command missing {g,c} variant");
}
- // check one more time after the final usleep
+ const char h_variant = packet.GetChar ();
+ switch (h_variant)
{
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return true;
+ case 'g':
+ break;
+
+ case 'c':
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, invalid $H variant %c", __FUNCTION__, h_variant);
+ return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
}
- // the launched process still lives. Now try killling it again,
- // this time with an unblockable signal.
- Host::Kill (pid, SIGKILL);
+ // Parse out the thread number.
+ // FIXME return a parse success/fail value. All values are valid here.
+ const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ());
- for (size_t i=0; i<10; ++i)
+ // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread).
+ if (tid != LLDB_INVALID_THREAD_ID && tid != 0)
{
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+ if (!thread_sp)
{
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- {
- // it is now killed
- return true;
- }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid);
+ return SendErrorResponse (0x15);
}
- usleep (10000);
}
- // check one more time after the final usleep
- // Scope for locker
+ // Now switch the given thread type.
+ switch (h_variant)
{
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return true;
+ case 'g':
+ SetCurrentThreadID (tid);
+ break;
+
+ case 'c':
+ SetContinueThreadID (tid);
+ break;
+
+ default:
+ assert (false && "unsupported $H variant - shouldn't get here");
+ return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
}
- // no luck - the process still lives
- return false;
+ return SendOKResponse();
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
- lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ {
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
- // verify that we know anything about this pid.
- // Scope for locker
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- Mutex::Locker locker (m_spawned_pids_mutex);
- if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Build the ResumeActionList - stop everything.
+ lldb_private::ResumeActionList actions (StateType::eStateStopped, 0);
+
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
{
- // not a pid we know about
- return SendErrorResponse (10);
+ log->Printf ("GDBRemoteCommunicationServer::%s failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
}
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
}
- // go ahead and attempt to kill the spawned process
- if (KillSpawnedProcess (pid))
- return SendOKResponse ();
- else
- return SendErrorResponse (11);
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from stop all.
+ return PacketResult::Success;
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_m (StringExtractorGDBRemote &packet)
{
- // ignore for now if we're lldb_platform
- if (m_is_platform)
- return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- // shutdown all spawned processes
- std::set<lldb::pid_t> spawned_pids_copy;
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ {
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
- // copy pids
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- Mutex::Locker locker (m_spawned_pids_mutex);
- spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
}
- // nuke the spawned processes
- for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
+ // Parse out the memory address.
+ packet.SetFilePos (strlen("m"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short m packet");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed read.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in m packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in m packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0)
{
- lldb::pid_t spawned_pid = *it;
- if (!KillSpawnedProcess (spawned_pid))
- {
- fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
- }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s nothing to read: zero-length packet", __FUNCTION__);
+ return PacketResult::Success;
}
- // TODO figure out how to shut down gracefully at this point
- return SendOKResponse ();
-}
+ // Allocate the response buffer.
+ std::string buf(byte_count, '\0');
+ if (buf.empty())
+ return SendErrorResponse (0x78);
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
-{
- if (m_process_launch_error.Success())
- return SendOKResponse();
- StreamString response;
- response.PutChar('E');
- response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
- return SendPacketNoLock (response.GetData(), response.GetSize());
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QEnvironment:"));
- const uint32_t bytes_left = packet.GetBytesLeft();
- if (bytes_left > 0)
+ // Retrieve the process memory.
+ lldb::addr_t bytes_read = 0;
+ lldb_private::Error error = m_debugged_process_sp->ReadMemory (read_addr, &buf[0], byte_count, bytes_read);
+ if (error.Fail ())
{
- m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
- return SendOKResponse ();
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ());
+ return SendErrorResponse (0x08);
}
- return SendErrorResponse (12);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QLaunchArch:"));
- const uint32_t bytes_left = packet.GetBytesLeft();
- if (bytes_left > 0)
+ if (bytes_read == 0)
{
- const char* arch_triple = packet.Peek();
- ArchSpec arch_spec(arch_triple,NULL);
- m_process_launch_info.SetArchitecture(arch_spec);
- return SendOKResponse();
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, bytes_read, byte_count);
+ return SendErrorResponse (0x08);
}
- return SendErrorResponse(13);
+
+ StreamGDBRemote response;
+ for (lldb::addr_t i = 0; i < bytes_read; ++i)
+ response.PutHex8(buf[i]);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+ packet.SetFilePos(::strlen ("QSetDetachOnError:"));
if (packet.GetU32(0))
- m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
else
- m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError);
return SendOKResponse ();
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetDetachOnError:"));
- if (packet.GetU32(0))
- m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
- else
- m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError);
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_M (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ {
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
+
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos (strlen("M"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short M packet");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed read.
+ const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in M packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in M packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s nothing to write: zero-length packet", __FUNCTION__);
+ return PacketResult::Success;
+ }
+
+ // Validate colon.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':'))
+ return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length");
+
+ // Allocate the conversion buffer.
+ std::vector<uint8_t> buf(byte_count, 0);
+ if (buf.empty())
+ return SendErrorResponse (0x78);
+
+ // Convert the hex memory write contents to bytes.
+ StreamGDBRemote response;
+ const uint64_t convert_count = static_cast<uint64_t> (packet.GetHexBytes (&buf[0], byte_count, 0));
+ if (convert_count != byte_count)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count);
+ return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length");
+ }
+
+ // Write the process memory.
+ lldb::addr_t bytes_written = 0;
+ lldb_private::Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+
+ if (bytes_written == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, bytes_written, byte_count);
+ return SendErrorResponse (0x09);
+ }
+
return SendOKResponse ();
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen ("QSetWorkingDir:"));
- std::string path;
- packet.GetHexByteString(path);
- if (m_is_platform)
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported
+ // request, but we're not guaranteed to be attached to a process. For now we'll assume the
+ // client only asks this when a process is being debugged.
+
+ // Ensure we have a process running; otherwise, we can't figure this out
+ // since we won't have a NativeProcessProtocol.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
-#ifdef _WIN32
- // Not implemented on Windows
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented");
-#else
- // If this packet is sent to a platform, then change the current working directory
- if (::chdir(path.c_str()) != 0)
- return SendErrorResponse(errno);
-#endif
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
}
- else
+
+ // Test if we can get any region back when asking for the region around NULL.
+ MemoryRegionInfo region_info;
+ const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info);
+ if (error.Fail ())
{
- m_process_launch_info.SwapWorkingDirectory (path);
+ // We don't support memory region info collection for this NativeProcessProtocol.
+ return SendUnimplementedResponse ("");
}
- return SendOKResponse ();
+
+ return SendOKResponse();
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet)
{
- StreamString response;
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (m_is_platform)
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- // If this packet is sent to a platform, then change the current working directory
- char cwd[PATH_MAX];
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- {
- return SendErrorResponse(errno);
- }
- else
- {
- response.PutBytesAsRawHex8(cwd, strlen(cwd));
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos (strlen("qMemoryRegionInfo:"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet");
+
+ // Read the address. Punting on validation.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ StreamGDBRemote response;
+
+ // Get the memory region info for the target address.
+ MemoryRegionInfo region_info;
+ const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info);
+ if (error.Fail ())
+ {
+ // Return the error message.
+
+ response.PutCString ("error:");
+ response.PutCStringAsRawHex8 (error.AsCString ());
+ response.PutChar (';');
}
else
{
- const char *working_dir = m_process_launch_info.GetWorkingDirectory();
- if (working_dir && working_dir[0])
- {
- response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
- else
+ // Range start and size.
+ response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ());
+
+ // Permissions.
+ if (region_info.GetReadable () ||
+ region_info.GetWritable () ||
+ region_info.GetExecutable ())
{
- return SendErrorResponse(14);
+ // Write permissions info.
+ response.PutCString ("permissions:");
+
+ if (region_info.GetReadable ())
+ response.PutChar ('r');
+ if (region_info.GetWritable ())
+ response.PutChar('w');
+ if (region_info.GetExecutable())
+ response.PutChar ('x');
+
+ response.PutChar (';');
}
}
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_Z (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen ("QSetSTDIN:"));
- ProcessLaunchInfo::FileAction file_action;
- std::string path;
- packet.GetHexByteString(path);
- const bool read = false;
- const bool write = true;
- if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- m_process_launch_info.AppendFileAction(file_action);
- return SendOKResponse ();
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
}
- return SendErrorResponse (15);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetSTDOUT:"));
- ProcessLaunchInfo::FileAction file_action;
- std::string path;
- packet.GetHexByteString(path);
- const bool read = true;
- const bool write = false;
- if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+ // Parse out software or hardware breakpoint requested.
+ packet.SetFilePos (strlen("Z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+ bool want_hardware = false;
+
+ const char breakpoint_type_char = packet.GetChar ();
+ switch (breakpoint_type_char)
{
- m_process_launch_info.AppendFileAction(file_action);
- return SendOKResponse ();
+ case '0': want_hardware = false; want_breakpoint = true; break;
+ case '1': want_hardware = true; want_breakpoint = true; break;
+ case '2': want_breakpoint = false; break;
+ case '3': want_breakpoint = false; break;
+ default:
+ return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier");
+
}
- return SendErrorResponse (16);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen ("QSetSTDERR:"));
- ProcessLaunchInfo::FileAction file_action;
- std::string path;
- packet.GetHexByteString(path);
- const bool read = true;
- const bool write = false;
- if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after breakpoint type");
+
+ // FIXME implement watchpoint support.
+ if (!want_breakpoint)
+ return SendUnimplementedResponse ("watchpoint support not yet implemented");
+
+ // Parse out the breakpoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing address");
+ const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address");
+
+ // Parse out the breakpoint kind (i.e. size hint for opcode size).
+ const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (kind == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse kind argument");
+
+ if (want_breakpoint)
{
- m_process_launch_info.AppendFileAction(file_action);
- return SendOKResponse ();
+ // Try to set the breakpoint.
+ const Error error = m_debugged_process_sp->SetBreakpoint (breakpoint_addr, kind, want_hardware);
+ if (error.Success ())
+ return SendOKResponse ();
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to set breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
}
- return SendErrorResponse (17);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
-{
- // Send response first before changing m_send_acks to we ack this packet
- PacketResult packet_result = SendOKResponse ();
- m_send_acks = false;
- return packet_result;
+ // FIXME fix up after watchpoints are handled.
+ return SendUnimplementedResponse ("");
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen("qPlatform_mkdir:"));
- mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
- if (packet.GetChar() == ',')
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- std::string path;
- packet.GetHexByteString(path);
- Error error = Host::MakeDirectory(path.c_str(),mode);
- if (error.Success())
- return SendPacketNoLock ("OK", 2);
- else
- return SendErrorResponse(error.GetError());
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
}
- return SendErrorResponse(20);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("qPlatform_chmod:"));
-
- mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
- if (packet.GetChar() == ',')
+ // Parse out software or hardware breakpoint requested.
+ packet.SetFilePos (strlen("Z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+
+ const char breakpoint_type_char = packet.GetChar ();
+ switch (breakpoint_type_char)
{
- std::string path;
- packet.GetHexByteString(path);
- Error error = Host::SetFilePermissions (path.c_str(), mode);
- if (error.Success())
- return SendPacketNoLock ("OK", 2);
- else
- return SendErrorResponse(error.GetError());
+ case '0': want_breakpoint = true; break;
+ case '1': want_breakpoint = true; break;
+ case '2': want_breakpoint = false; break;
+ case '3': want_breakpoint = false; break;
+ default:
+ return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier");
+
}
- return SendErrorResponse(19);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:open:"));
- std::string path;
- packet.GetHexByteStringTerminatedBy(path,',');
- if (!path.empty())
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after breakpoint type");
+
+ // FIXME implement watchpoint support.
+ if (!want_breakpoint)
+ return SendUnimplementedResponse ("watchpoint support not yet implemented");
+
+ // Parse out the breakpoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing address");
+ const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address");
+
+ // Parse out the breakpoint kind (i.e. size hint for opcode size).
+ const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (kind == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed z packet, failed to parse kind argument");
+
+ if (want_breakpoint)
{
- if (packet.GetChar() == ',')
+ // Try to set the breakpoint.
+ const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr);
+ if (error.Success ())
+ return SendOKResponse ();
+ else
{
- uint32_t flags = packet.GetHexMaxU32(false, 0);
- if (packet.GetChar() == ',')
- {
- mode_t mode = packet.GetHexMaxU32(false, 0600);
- Error error;
- int fd = ::open (path.c_str(), flags, mode);
- const int save_errno = fd == -1 ? errno : 0;
- StreamString response;
- response.PutChar('F');
- response.Printf("%i", fd);
- if (save_errno)
- response.Printf(",%i", save_errno);
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to remove breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x09);
}
}
- return SendErrorResponse(18);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:close:"));
- int fd = packet.GetS32(-1);
- Error error;
- int err = -1;
- int save_errno = 0;
- if (fd >= 0)
- {
- err = close(fd);
- save_errno = err == -1 ? errno : 0;
- }
- else
- {
- save_errno = EINVAL;
- }
- StreamString response;
- response.PutChar('F');
- response.Printf("%i", err);
- if (save_errno)
- response.Printf(",%i", save_errno);
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ // FIXME fix up after watchpoints are handled.
+ return SendUnimplementedResponse ("");
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_s (StringExtractorGDBRemote &packet)
{
-#ifdef _WIN32
- // Not implemented on Windows
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented");
-#else
- StreamGDBRemote response;
- packet.SetFilePos(::strlen("vFile:pread:"));
- int fd = packet.GetS32(-1);
- if (packet.GetChar() == ',')
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- uint64_t count = packet.GetU64(UINT64_MAX);
- if (packet.GetChar() == ',')
- {
- uint64_t offset = packet.GetU64(UINT32_MAX);
- if (count == UINT64_MAX)
- {
- response.Printf("F-1:%i", EINVAL);
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
-
- std::string buffer(count, 0);
- const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
- const int save_errno = bytes_read == -1 ? errno : 0;
- response.PutChar('F');
- response.Printf("%zi", bytes_read);
- if (save_errno)
- response.Printf(",%i", save_errno);
- else
- {
- response.PutChar(';');
- response.PutEscapedBytes(&buffer[0], bytes_read);
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
- }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x32);
+ }
+
+ // We first try to use a continue thread id. If any one or any all set, use the current thread.
+ // Bail out if we don't have a thread id.
+ lldb::tid_t tid = GetContinueThreadID ();
+ if (tid == 0 || tid == LLDB_INVALID_THREAD_ID)
+ tid = GetCurrentThreadID ();
+ if (tid == LLDB_INVALID_THREAD_ID)
+ return SendErrorResponse (0x33);
+
+ // Double check that we have such a thread.
+ // TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
+ NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid);
+ if (!thread_sp || thread_sp->GetID () != tid)
+ return SendErrorResponse (0x33);
+
+ // Create the step action for the given thread.
+ lldb_private::ResumeAction action = { tid, eStateStepping, 0 };
+
+ // Setup the actions list.
+ lldb_private::ResumeActionList actions;
+ actions.Append (action);
+
+ // All other threads stop while we're single stepping a thread.
+ actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ());
+ return SendErrorResponse(0x49);
}
- return SendErrorResponse(21);
+ // No response here - the stop or exit will come from the resulting action.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qSupported (StringExtractorGDBRemote &packet)
+{
+ StreamGDBRemote response;
+
+ // Features common to lldb-platform and llgs.
+ uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less
+ response.Printf ("PacketSize=%x", max_packet_size);
+
+ response.PutCString (";QStartNoAckMode+");
+ response.PutCString (";QThreadSuffixSupported+");
+ response.PutCString (";QListThreadsInStopReply+");
+#if defined(__linux__)
+ response.PutCString (";qXfer:auxv:read+");
#endif
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet)
{
-#ifdef _WIN32
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented");
-#else
- packet.SetFilePos(::strlen("vFile:pwrite:"));
+ m_thread_suffix_supported = true;
+ return SendOKResponse();
+}
- StreamGDBRemote response;
- response.PutChar('F');
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet)
+{
+ m_list_threads_in_stop_reply = true;
+ return SendOKResponse();
+}
- int fd = packet.GetU32(UINT32_MAX);
- if (packet.GetChar() == ',')
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet)
+{
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+ // *BSD impls should be able to do this too.
+#if defined(__linux__)
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Parse out the offset.
+ packet.SetFilePos (strlen("qXfer:auxv:read::"));
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+ const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+ if (auxv_offset == std::numeric_limits<uint64_t>::max ())
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+ // Parse out comma.
+ if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',')
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset");
+
+ // Parse out the length.
+ const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+ if (auxv_length == std::numeric_limits<uint64_t>::max ())
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length");
+
+ // Grab the auxv data if we need it.
+ if (!m_active_auxv_buffer_sp)
{
- off_t offset = packet.GetU64(UINT32_MAX);
- if (packet.GetChar() == ',')
+ // Make sure we have a valid process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
- std::string buffer;
- if (packet.GetEscapedBinaryData(buffer))
- {
- const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
- const int save_errno = bytes_written == -1 ? errno : 0;
- response.Printf("%zi", bytes_written);
- if (save_errno)
- response.Printf(",%i", save_errno);
- }
- else
- {
- response.Printf ("-1,%i", EINVAL);
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x10);
+ }
+
+ // Grab the auxv data.
+ m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ());
+ if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0)
+ {
+ // Hmm, no auxv data, call that an error.
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no auxv data retrieved", __FUNCTION__);
+ m_active_auxv_buffer_sp.reset ();
+ return SendErrorResponse (0x11);
}
}
- return SendErrorResponse(27);
-#endif
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:size:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
+ // FIXME find out if/how I lock the stream here.
+
+ StreamGDBRemote response;
+ bool done_with_buffer = false;
+
+ if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ())
{
- lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
- StreamString response;
- response.PutChar('F');
- response.PutHex64(retcode);
- if (retcode == UINT64_MAX)
+ // We have nothing left to send. Mark the buffer as complete.
+ response.PutChar ('l');
+ done_with_buffer = true;
+ }
+ else
+ {
+ // Figure out how many bytes are available starting at the given offset.
+ const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset;
+
+ // Figure out how many bytes we're going to read.
+ const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length;
+
+ // Mark the response type according to whether we're reading the remainder of the auxv data.
+ if (bytes_to_read >= bytes_remaining)
{
- response.PutChar(',');
- response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ // There will be nothing left to read after this
+ response.PutChar ('l');
+ done_with_buffer = true;
}
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ else
+ {
+ // There will still be bytes to read after this request.
+ response.PutChar ('m');
+ }
+
+ // Now write the data in encoded binary form.
+ response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read);
}
- return SendErrorResponse(22);
+
+ if (done_with_buffer)
+ m_active_auxv_buffer_sp.reset ();
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+#else
+ return SendUnimplementedResponse ("not implemented on this platform");
+#endif
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen("vFile:mode:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+ // Move past packet name.
+ packet.SetFilePos (strlen ("QSaveRegisterState"));
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
{
- Error error;
- const uint32_t mode = File::GetPermissions(path.c_str(), error);
- StreamString response;
- response.Printf("F%u", mode);
- if (mode == 0 || error.Fail())
- response.Printf(",%i", (int)error.GetError());
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet");
+ else
+ return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
}
- return SendErrorResponse(23);
+
+ // Grab the register context for the thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Save registers to a buffer.
+ DataBufferSP register_data_sp;
+ Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x75);
+ }
+
+ // Allocate a new save id.
+ const uint32_t save_id = GetNextSavedRegistersID ();
+ assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id");
+
+ // Save the register data buffer under the save id.
+ {
+ Mutex::Locker locker (m_saved_registers_mutex);
+ m_saved_registers_map[save_id] = register_data_sp;
+ }
+
+ // Write the response.
+ StreamGDBRemote response;
+ response.Printf ("%" PRIu32, save_id);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen("vFile:exists:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+ // Parse out save id.
+ packet.SetFilePos (strlen ("QRestoreRegisterState:"));
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id");
+
+ const uint32_t save_id = packet.GetU32 (0);
+ if (save_id == 0)
{
- bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
- StreamString response;
- response.PutChar('F');
- response.PutChar(',');
- if (retcode)
- response.PutChar('1');
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__);
+ return SendErrorResponse (0x76);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet");
else
- response.PutChar('0');
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
}
- return SendErrorResponse(24);
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
-{
- packet.SetFilePos(::strlen("vFile:symlink:"));
- std::string dst, src;
- packet.GetHexByteStringTerminatedBy(dst, ',');
- packet.GetChar(); // Skip ',' char
- packet.GetHexByteString(src);
- Error error = Host::Symlink(src.c_str(), dst.c_str());
- StreamString response;
- response.Printf("F%u,%u", error.GetError(), error.GetError());
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ // Grab the register context for the thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Retrieve register state buffer, then remove from the list.
+ DataBufferSP register_data_sp;
+ {
+ Mutex::Locker locker (m_saved_registers_mutex);
+
+ // Find the register set buffer for the given save id.
+ auto it = m_saved_registers_map.find (save_id);
+ if (it == m_saved_registers_map.end ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id);
+ return SendErrorResponse (0x77);
+ }
+ register_data_sp = it->second;
+
+ // Remove it from the map.
+ m_saved_registers_map.erase (it);
+ }
+
+ Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x77);
+ }
+
+ return SendOKResponse();
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::FlushInferiorOutput ()
{
- packet.SetFilePos(::strlen("vFile:unlink:"));
- std::string path;
- packet.GetHexByteString(path);
- Error error = Host::Unlink(path.c_str());
- StreamString response;
- response.Printf("F%u,%u", error.GetError(), error.GetError());
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ // If we're not monitoring an inferior's terminal, ignore this.
+ if (!m_stdio_communication.IsConnected())
+ return;
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__);
+
+ // FIXME implement a timeout on the join.
+ m_stdio_communication.JoinReadThread();
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::MaybeCloseInferiorTerminalConnection ()
{
- packet.SetFilePos(::strlen("qPlatform_shell:"));
- std::string path;
- std::string working_dir;
- packet.GetHexByteStringTerminatedBy(path,',');
- if (!path.empty())
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Tell the stdio connection to shut down.
+ if (m_stdio_communication.IsConnected())
{
- if (packet.GetChar() == ',')
+ auto connection = m_stdio_communication.GetConnection();
+ if (connection)
{
- // FIXME: add timeout to qPlatform_shell packet
- // uint32_t timeout = packet.GetHexMaxU32(false, 32);
- uint32_t timeout = 10;
- if (packet.GetChar() == ',')
- packet.GetHexByteString(working_dir);
- int status, signo;
- std::string output;
- Error err = Host::RunShellCommand(path.c_str(),
- working_dir.empty() ? NULL : working_dir.c_str(),
- &status, &signo, &output, timeout);
- StreamGDBRemote response;
- if (err.Fail())
+ Error error;
+ connection->Disconnect (&error);
+
+ if (error.Success ())
{
- response.PutCString("F,");
- response.PutHex32(UINT32_MAX);
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__);
}
else
{
- response.PutCString("F,");
- response.PutHex32(status);
- response.PutChar(',');
- response.PutHex32(signo);
- response.PutChar(',');
- response.PutEscapedBytes(output.c_str(), output.size());
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ());
}
- return SendPacketNoLock(response.GetData(), response.GetSize());
}
}
- return SendErrorResponse(24);
}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
-{
- return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");
-}
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+lldb_private::NativeThreadProtocolSP
+GDBRemoteCommunicationServer::GetThreadFromSuffix (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen("vFile:MD5:"));
- std::string path;
- packet.GetHexByteString(path);
- if (!path.empty())
- {
- uint64_t a,b;
- StreamGDBRemote response;
- if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
+ NativeThreadProtocolSP thread_sp;
+
+ // We have no thread if we don't have a process.
+ if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)
+ return thread_sp;
+
+ // If the client hasn't asked for thread suffix support, there will not be a thread suffix.
+ // Use the current thread in that case.
+ if (!m_thread_suffix_supported)
+ {
+ const lldb::tid_t current_tid = GetCurrentThreadID ();
+ if (current_tid == LLDB_INVALID_THREAD_ID)
+ return thread_sp;
+ else if (current_tid == 0)
{
- response.PutCString("F,");
- response.PutCString("x");
+ // Pick a thread.
+ return m_debugged_process_sp->GetThreadAtIndex (0);
}
else
- {
- response.PutCString("F,");
- response.PutHex64(a);
- response.PutHex64(b);
- }
- return SendPacketNoLock(response.GetData(), response.GetSize());
+ return m_debugged_process_sp->GetThreadByID (current_tid);
}
- return SendErrorResponse(25);
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Parse out the ';'.
+ if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';')
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return thread_sp;
+ }
+
+ if (!packet.GetBytesLeft ())
+ return thread_sp;
+
+ // Parse out thread: portion.
+ if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return thread_sp;
+ }
+ packet.SetFilePos (packet.GetFilePos () + strlen("thread:"));
+ const lldb::tid_t tid = packet.GetHexMaxU64(false, 0);
+ if (tid != 0)
+ return m_debugged_process_sp->GetThreadByID (tid);
+
+ return thread_sp;
+}
+
+lldb::tid_t
+GDBRemoteCommunicationServer::GetCurrentThreadID () const
+{
+ if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID)
+ {
+ // Use whatever the debug process says is the current thread id
+ // since the protocol either didn't specify or specified we want
+ // any/all threads marked as the current thread.
+ if (!m_debugged_process_sp)
+ return LLDB_INVALID_THREAD_ID;
+ return m_debugged_process_sp->GetCurrentThreadID ();
+ }
+ // Use the specific current thread id set by the gdb remote protocol.
+ return m_current_tid;
+}
+
+uint32_t
+GDBRemoteCommunicationServer::GetNextSavedRegistersID ()
+{
+ Mutex::Locker locker (m_saved_registers_mutex);
+ return m_next_saved_registers_id++;
}
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h Mon Jun 30 16:05:18 2014
@@ -14,16 +14,23 @@
// C++ Includes
#include <vector>
#include <set>
+#include <unordered_map>
// Other libraries and framework includes
// Project includes
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Communication.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
#include "GDBRemoteCommunication.h"
+#include "../../../Host/common/NativeProcessProtocol.h"
+
class ProcessGDBRemote;
class StringExtractorGDBRemote;
-class GDBRemoteCommunicationServer : public GDBRemoteCommunication
+class GDBRemoteCommunicationServer :
+ public GDBRemoteCommunication,
+ public lldb_private::NativeProcessProtocol::NativeDelegate
{
public:
typedef std::map<uint16_t, lldb::pid_t> PortMap;
@@ -38,12 +45,13 @@ public:
GDBRemoteCommunicationServer(bool is_platform);
GDBRemoteCommunicationServer(bool is_platform,
- const lldb::PlatformSP& platform_sp);
+ const lldb::PlatformSP& platform_sp,
+ lldb::DebuggerSP& debugger_sp);
virtual
~GDBRemoteCommunicationServer();
- bool
+ PacketResult
GetPacketAndSendResponse (uint32_t timeout_usec,
lldb_private::Error &error,
bool &interrupt,
@@ -188,6 +196,28 @@ public:
lldb_private::Error
LaunchProcess ();
+ //------------------------------------------------------------------
+ /// Attach to a process.
+ ///
+ /// This method supports attaching llgs to a process accessible via the
+ /// configured Platform.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of the
+ /// attach operation.
+ //------------------------------------------------------------------
+ lldb_private::Error
+ AttachToProcess (lldb::pid_t pid);
+
+ //------------------------------------------------------------------
+ // NativeProcessProtocol::NativeDelegate overrides
+ //------------------------------------------------------------------
+ void
+ InitializeDelegate (lldb_private::NativeProcessProtocol *process) override;
+
+ void
+ ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) override;
+
protected:
lldb::PlatformSP m_platform_sp;
lldb::thread_t m_async_thread;
@@ -199,7 +229,20 @@ protected:
uint32_t m_proc_infos_index;
PortMap m_port_map;
uint16_t m_port_offset;
-
+ lldb::tid_t m_current_tid;
+ lldb::tid_t m_continue_tid;
+ lldb_private::Mutex m_debugged_process_mutex;
+ lldb_private::NativeProcessProtocolSP m_debugged_process_sp;
+ lldb::DebuggerSP m_debugger_sp;
+ Communication m_stdio_communication;
+ bool m_exit_now; // use in asynchronous handling to indicate process should exit.
+ lldb::StateType m_inferior_prev_state;
+ bool m_thread_suffix_supported;
+ bool m_list_threads_in_stop_reply;
+ lldb::DataBufferSP m_active_auxv_buffer_sp;
+ lldb_private::Mutex m_saved_registers_mutex;
+ std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
+ uint32_t m_next_saved_registers_id;
PacketResult
SendUnimplementedResponse (const char *packet);
@@ -208,9 +251,24 @@ protected:
SendErrorResponse (uint8_t error);
PacketResult
+ SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message);
+
+ PacketResult
SendOKResponse ();
PacketResult
+ SendONotification (const char *buffer, uint32_t len);
+
+ PacketResult
+ SendWResponse (lldb_private::NativeProcessProtocol *process);
+
+ PacketResult
+ SendStopReplyPacketForThread (lldb::tid_t tid);
+
+ PacketResult
+ SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit);
+
+ PacketResult
Handle_A (StringExtractorGDBRemote &packet);
PacketResult
@@ -233,7 +291,10 @@ protected:
PacketResult
Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
-
+
+ PacketResult
+ Handle_qProcessInfo (StringExtractorGDBRemote &packet);
+
PacketResult
Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
@@ -284,7 +345,22 @@ protected:
PacketResult
Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
-
+
+ PacketResult
+ Handle_C (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment = false);
+
+ PacketResult
+ Handle_vCont (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vCont_actions (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_stop_reason (StringExtractorGDBRemote &packet);
+
PacketResult
Handle_vFile_Open (StringExtractorGDBRemote &packet);
@@ -321,6 +397,84 @@ protected:
PacketResult
Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
+ PacketResult
+ Handle_qRegisterInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qfThreadInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qsThreadInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_p (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_P (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_H (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_interrupt (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_m (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_M (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_Z (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_z (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_s (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSaveRegisterState (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet);
+
+ void
+ SetCurrentThreadID (lldb::tid_t tid);
+
+ lldb::tid_t
+ GetCurrentThreadID () const;
+
+ void
+ SetContinueThreadID (lldb::tid_t tid);
+
+ lldb::tid_t
+ GetContinueThreadID () const { return m_continue_tid; }
+
+ lldb_private::Error
+ SetSTDIOFileDescriptor (int fd);
+
+ static void
+ STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
private:
bool
DebugserverProcessReaped (lldb::pid_t pid);
@@ -345,6 +499,38 @@ private:
bool
KillSpawnedProcess (lldb::pid_t pid);
+ bool
+ IsGdbServer ()
+ {
+ return !m_is_platform;
+ }
+
+ /// Launch a process from lldb-gdbserver
+ lldb_private::Error
+ LaunchDebugServerProcess ();
+
+ /// Launch a process from lldb-platform
+ lldb_private::Error
+ LaunchPlatformProcess ();
+
+ void
+ HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process);
+
+ void
+ HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process);
+
+ void
+ FlushInferiorOutput ();
+
+ lldb_private::NativeThreadProtocolSP
+ GetThreadFromSuffix (StringExtractorGDBRemote &packet);
+
+ uint32_t
+ GetNextSavedRegistersID ();
+
+ void
+ MaybeCloseInferiorTerminalConnection ();
+
//------------------------------------------------------------------
// For GDBRemoteCommunicationServer only
//------------------------------------------------------------------
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Mon Jun 30 16:05:18 2014
@@ -61,7 +61,9 @@
// Project includes
#include "lldb/Host/Host.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/LinuxSignals.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
#include "Utility/StringExtractorGDBRemote.h"
@@ -285,7 +287,8 @@ ProcessGDBRemote::ProcessGDBRemote(Targe
m_waiting_for_attach (false),
m_destroy_tried_resuming (false),
m_command_sp (),
- m_breakpoint_pc_offset (0)
+ m_breakpoint_pc_offset (0),
+ m_unix_signals_sp (new UnixSignals ())
{
m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
@@ -628,6 +631,7 @@ ProcessGDBRemote::WillAttachToProcessWit
Error
ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
Error error (WillLaunchOrAttach ());
if (error.Fail())
@@ -678,7 +682,11 @@ ProcessGDBRemote::DoConnectRemote (Strea
error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url);
}
- if (error.Success()
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false");
+
+
+ if (error.Success()
&& !GetTarget().GetArchitecture().IsValid()
&& m_gdb_comm.GetHostArchitecture().IsValid())
{
@@ -689,6 +697,42 @@ ProcessGDBRemote::DoConnectRemote (Strea
GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture());
}
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ());
+
+ // Set the Unix signals properly for the target.
+ // FIXME Add a gdb-remote packet to discover dynamically.
+ if (error.Success ())
+ {
+ const ArchSpec arch_spec = GetTarget ().GetArchitecture ();
+ if (arch_spec.IsValid ())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": determining unix signals type based on architecture %s, triple %s", __FUNCTION__, GetID (), arch_spec.GetArchitectureName () ? arch_spec.GetArchitectureName () : "<null>", arch_spec.GetTriple ().getTriple ().c_str ());
+
+ switch (arch_spec.GetTriple ().getOS ())
+ {
+ case llvm::Triple::Linux:
+ m_unix_signals_sp.reset (new process_linux::LinuxSignals ());
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s using Linux unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+ break;
+ case llvm::Triple::OpenBSD:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ m_unix_signals_sp.reset (new FreeBSDSignals ());
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s using *BSD unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+ break;
+ default:
+ m_unix_signals_sp.reset (new UnixSignals ());
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s using generic unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+ break;
+ }
+ }
+ }
+
return error;
}
@@ -1040,6 +1084,13 @@ ProcessGDBRemote::DidLaunch ()
DidLaunchOrAttach ();
}
+UnixSignals&
+ProcessGDBRemote::GetUnixSignals ()
+{
+ assert (m_unix_signals_sp && "m_unix_signals_sp is null");
+ return *m_unix_signals_sp;
+}
+
Error
ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid)
{
@@ -2231,6 +2282,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t
lldb::addr_t
ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
{
+ lldb_private::Log *log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS));
addr_t allocated_addr = LLDB_INVALID_ADDRESS;
LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
@@ -2256,7 +2308,11 @@ ProcessGDBRemote::DoAllocateMemory (size
eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0))
m_addr_to_mmap_size[allocated_addr] = size;
else
+ {
allocated_addr = LLDB_INVALID_ADDRESS;
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__);
+ }
break;
}
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Mon Jun 30 16:05:18 2014
@@ -91,6 +91,9 @@ public:
virtual void
DidLaunch ();
+ lldb_private::UnixSignals&
+ GetUnixSignals () override;
+
virtual lldb_private::Error
WillAttachToProcessWithID (lldb::pid_t pid);
@@ -305,8 +308,8 @@ protected:
bool
ParseRegisters(lldb_private::ScriptInterpreterObject *registers_array);
- virtual const lldb::DataBufferSP
- GetAuxvData();
+ const lldb::DataBufferSP
+ GetAuxvData() override;
lldb_private::StructuredData::ObjectSP
GetExtendedInfoForThread (lldb::tid_t tid);
@@ -357,7 +360,9 @@ protected:
bool m_destroy_tried_resuming;
lldb::CommandObjectSP m_command_sp;
int64_t m_breakpoint_pc_offset;
-
+ std::shared_ptr<lldb_private::UnixSignals> m_unix_signals_sp;
+
+
bool
StartAsyncThread ();
Modified: lldb/trunk/source/Target/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Target/CMakeLists.txt (original)
+++ lldb/trunk/source/Target/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -10,6 +10,8 @@ add_lldb_library(lldbTarget
JITLoaderList.cpp
LanguageRuntime.cpp
Memory.cpp
+ NativeRegisterContext.cpp
+ NativeRegisterContextRegisterInfo.cpp
ObjCLanguageRuntime.cpp
OperatingSystem.cpp
PathMappingList.cpp
Added: lldb/trunk/source/Target/NativeRegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/NativeRegisterContext.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Target/NativeRegisterContext.cpp (added)
+++ lldb/trunk/source/Target/NativeRegisterContext.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,470 @@
+//===-- NativeRegisterContext.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/NativeRegisterContext.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) :
+ m_thread (thread),
+ m_concrete_frame_idx (concrete_frame_idx)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+NativeRegisterContext::~NativeRegisterContext()
+{
+}
+
+// FIXME revisit invalidation, process stop ids, etc. Right now we don't
+// support caching in NativeRegisterContext. We can do this later by
+// utilizing NativeProcessProtocol::GetStopID () and adding a stop id to
+// NativeRegisterContext.
+
+// void
+// NativeRegisterContext::InvalidateIfNeeded (bool force)
+// {
+// ProcessSP process_sp (m_thread.GetProcess());
+// bool invalidate = force;
+// uint32_t process_stop_id = UINT32_MAX;
+
+// if (process_sp)
+// process_stop_id = process_sp->GetStopID();
+// else
+// invalidate = true;
+
+// if (!invalidate)
+// invalidate = process_stop_id != GetStopID();
+
+// if (invalidate)
+// {
+// InvalidateAllRegisters ();
+// SetStopID (process_stop_id);
+// }
+// }
+
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx)
+{
+ if (reg_name && reg_name[0])
+ {
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = start_idx; reg < num_registers; ++reg)
+ {
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+
+ if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) ||
+ (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0))
+ {
+ return reg_info;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num)
+{
+ const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return nullptr;
+ return GetRegisterInfoAtIndex (reg_num);
+}
+
+const char *
+NativeRegisterContext::GetRegisterName (uint32_t reg)
+{
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info)
+ return reg_info->name;
+ return nullptr;
+}
+
+const char*
+NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const
+{
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return nullptr;
+
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index)
+ {
+ const RegisterSet *const reg_set = GetRegisterSet (set_index);
+ if (!reg_set)
+ continue;
+
+ for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index)
+ {
+ const uint32_t reg_num = reg_set->registers[reg_num_index];
+ // FIXME double check we're checking the right register kind here.
+ if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num)
+ {
+ // The given register is a member of this register set. Return the register set name.
+ return reg_set->name;
+ }
+ }
+ }
+
+ // Didn't find it.
+ return nullptr;
+}
+
+lldb::addr_t
+NativeRegisterContext::GetPC (lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ if (log)
+ log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value);
+
+ const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value);
+
+ if (log)
+ log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval);
+
+ return retval;
+}
+
+Error
+NativeRegisterContext::SetPC (lldb::addr_t pc)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ return WriteRegisterFromUnsigned (reg, pc);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetSP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetSP (lldb::addr_t sp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return WriteRegisterFromUnsigned (reg, sp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetFP (lldb::addr_t fp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return WriteRegisterFromUnsigned (reg, fp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFlags (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+
+lldb::addr_t
+NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value)
+{
+ if (reg != LLDB_INVALID_REGNUM)
+ return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value);
+ return fail_value;
+}
+
+uint64_t
+NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ if (reg_info)
+ {
+ RegisterValue value;
+ Error error = ReadRegister (reg_info, value);
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64());
+ return value.GetAsUInt64();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__);
+ }
+ return fail_value;
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+ if (reg == LLDB_INVALID_REGNUM)
+ return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
+ return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval);
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval)
+{
+ assert (reg_info);
+ if (!reg_info)
+ return Error ("reg_info is nullptr");
+
+ RegisterValue value;
+ if (!value.SetUInt(uval, reg_info->byte_size))
+ return Error ("RegisterValue::SetUInt () failed");
+
+ return WriteRegister (reg_info, value);
+}
+
+lldb::tid_t
+NativeRegisterContext::GetThreadID() const
+{
+ return m_thread.GetID();
+}
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareBreakpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ return false;
+}
+
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareWatchpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+NativeRegisterContext::HardwareSingleStep (bool enable)
+{
+ return false;
+}
+
+Error
+NativeRegisterContext::ReadRegisterValueFromMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t src_addr,
+ lldb::addr_t src_len,
+ RegisterValue ®_value)
+{
+ Error error;
+ if (reg_info == nullptr)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return error;
+ }
+
+
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Error! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ if (src_len > RegisterValue::kMaxRegisterByteSize)
+ {
+ error.SetErrorString ("register too small to receive memory data");
+ return error;
+ }
+
+ const lldb::addr_t dst_len = reg_info->byte_size;
+
+ if (src_len > dst_len)
+ {
+ error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)", src_len, reg_info->name, dst_len);
+ return error;
+ }
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ {
+ error.SetErrorString("invalid process");
+ return error;
+ }
+
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Read the memory
+ lldb::addr_t bytes_read;
+ error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read);
+ if (error.Fail ())
+ return error;
+
+ // Make sure the memory read succeeded...
+ if (bytes_read != src_len)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", bytes_read, src_len);
+ return error;
+ }
+
+ // We now have a memory buffer that contains the part or all of the register
+ // value. Set the register value using this memory data.
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ {
+ error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed");
+ return error;
+ }
+
+ reg_value.SetFromMemoryData (
+ reg_info,
+ src,
+ src_len,
+ byte_order,
+ error);
+
+ return error;
+}
+
+Error
+NativeRegisterContext::WriteRegisterValueToMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t dst_addr,
+ lldb::addr_t dst_len,
+ const RegisterValue ®_value)
+{
+
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ Error error;
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (process_sp)
+ {
+
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ return Error ("NativeProcessProtocol::GetByteOrder () failed");
+
+ const lldb::addr_t bytes_copied = reg_value.GetAsMemoryData (
+ reg_info,
+ dst,
+ dst_len,
+ byte_order,
+ error);
+
+ if (error.Success())
+ {
+ if (bytes_copied == 0)
+ {
+ error.SetErrorString("byte copy failed.");
+ }
+ else
+ {
+ lldb::addr_t bytes_written;
+ error = process_sp->WriteMemory (dst_addr, dst, bytes_copied, bytes_written);
+ if (error.Fail ())
+ return error;
+
+ if (bytes_written != bytes_copied)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes", bytes_written, bytes_copied);
+ }
+ }
+ }
+ }
+ else
+ error.SetErrorString("invalid process");
+
+ return error;
+}
+
+uint32_t
+NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+
Added: lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp (added)
+++ lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContex.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Target/NativeRegisterContextRegisterInfo.h"
+
+using namespace lldb_private;
+
+NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info_interface) :
+ NativeRegisterContext (thread, concrete_frame_idx),
+ m_register_info_interface_up (register_info_interface)
+{
+ assert (register_info_interface && "null register_info_interface");
+}
+
+uint32_t
+NativeRegisterContextRegisterInfo::GetRegisterCount () const
+{
+ return m_register_info_interface_up->GetRegisterCount ();
+}
+
+const RegisterInfo *
+NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const
+{
+ if (reg_index <= GetRegisterCount ())
+ return m_register_info_interface_up->GetRegisterInfo () + reg_index;
+ else
+ return nullptr;
+}
+
+const RegisterInfoInterface&
+NativeRegisterContextRegisterInfo::GetRegisterInfoInterface () const
+{
+ return *m_register_info_interface_up;
+}
Modified: lldb/trunk/source/Target/Platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Platform.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Target/Platform.cpp (original)
+++ lldb/trunk/source/Target/Platform.cpp Mon Jun 30 16:05:18 2014
@@ -527,12 +527,10 @@ RecurseCopy_Callback (void *baton,
case FileSpec::eFileTypeInvalid:
case FileSpec::eFileTypeOther:
case FileSpec::eFileTypeUnknown:
+ default:
rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
break;
- default:
- return FileSpec::eEnumerateDirectoryResultQuit; // unsupported file type, bail out
- break;
}
}
@@ -1189,6 +1187,27 @@ Platform::CalculateMD5 (const FileSpec&
return false;
}
+Error
+Platform::LaunchNativeProcess (
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+ // Platforms should override this implementation if they want to
+ // support lldb-gdbserver.
+ return Error("unimplemented");
+}
+
+Error
+Platform::AttachNativeProcess (lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+ // Platforms should override this implementation if they want to
+ // support lldb-gdbserver.
+ return Error("unimplemented");
+}
+
void
Platform::SetLocalCacheDirectory (const char* local)
{
Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Mon Jun 30 16:05:18 2014
@@ -2529,6 +2529,7 @@ Process::CanJIT ()
{
if (m_can_jit == eCanJITDontKnow)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
Error err;
uint64_t allocated_memory = AllocateMemory(8,
@@ -2536,9 +2537,17 @@ Process::CanJIT ()
err);
if (err.Success())
+ {
m_can_jit = eCanJITYes;
+ if (log)
+ log->Printf ("Process::%s pid %" PRIu64 " allocation test passed, CanJIT () is true", __FUNCTION__, GetID ());
+ }
else
+ {
m_can_jit = eCanJITNo;
+ if (log)
+ log->Printf ("Process::%s pid %" PRIu64 " allocation test failed, CanJIT () is false: %s", __FUNCTION__, GetID (), err.AsCString ());
+ }
DeallocateMemory (allocated_memory);
}
@@ -2788,6 +2797,12 @@ Process::GetDynamicLoader ()
return m_dyld_ap.get();
}
+const lldb::DataBufferSP
+Process::GetAuxvData()
+{
+ return DataBufferSP ();
+}
+
JITLoaderList &
Process::GetJITLoaders ()
{
Modified: lldb/trunk/source/Utility/StringExtractor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractor.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractor.cpp (original)
+++ lldb/trunk/source/Utility/StringExtractor.cpp Mon Jun 30 16:05:18 2014
@@ -419,6 +419,18 @@ StringExtractor::GetHexByteString (std::
}
size_t
+StringExtractor::GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length)
+{
+ str.clear();
+
+ uint32_t nibble_count = 0;
+ for (const char *pch = Peek(); (nibble_count < nibble_length) && (pch != nullptr); str.append(1, GetHexU8(0, false)), pch = Peek (), nibble_count += 2)
+ {}
+
+ return str.size();
+}
+
+size_t
StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
char terminator)
{
@@ -428,6 +440,7 @@ StringExtractor::GetHexByteStringTermina
str.append(1, ch);
if (Peek() && *Peek() == terminator)
return str.size();
+
str.clear();
return str.size();
}
Modified: lldb/trunk/source/Utility/StringExtractor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractor.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractor.h (original)
+++ lldb/trunk/source/Utility/StringExtractor.h Mon Jun 30 16:05:18 2014
@@ -129,6 +129,9 @@ public:
GetHexByteString (std::string &str);
size_t
+ GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length);
+
+ size_t
GetHexByteStringTerminatedBy (std::string &str,
char terminator);
Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp Mon Jun 30 16:05:18 2014
@@ -179,6 +179,7 @@ StringExtractorGDBRemote::GetServerPacke
if (PACKET_STARTS_WITH ("qSpeedTest:")) return eServerPacketType_qSpeedTest;
if (PACKET_MATCHES ("qShlibInfoAddr")) return eServerPacketType_qShlibInfoAddr;
if (PACKET_MATCHES ("qStepPacketSupported")) return eServerPacketType_qStepPacketSupported;
+ if (PACKET_STARTS_WITH ("qSupported")) return eServerPacketType_qSupported;
if (PACKET_MATCHES ("qSyncThreadStateSupported")) return eServerPacketType_qSyncThreadStateSupported;
break;
@@ -199,6 +200,10 @@ StringExtractorGDBRemote::GetServerPacke
if (PACKET_STARTS_WITH ("qWatchpointSupportInfo:")) return eServerPacketType_qWatchpointSupportInfo;
if (PACKET_MATCHES ("qWatchpointSupportInfo")) return eServerPacketType_qWatchpointSupportInfoSupported;
break;
+
+ case 'X':
+ if (PACKET_STARTS_WITH ("qXfer:auxv:read::")) return eServerPacketType_qXfer_auxv_read;
+ break;
}
break;
case 'v':
Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.h (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.h Mon Jun 30 16:05:18 2014
@@ -106,12 +106,14 @@ public:
eServerPacketType_qRegisterInfo,
eServerPacketType_qShlibInfoAddr,
eServerPacketType_qStepPacketSupported,
+ eServerPacketType_qSupported,
eServerPacketType_qSyncThreadStateSupported,
eServerPacketType_qThreadExtraInfo,
eServerPacketType_qThreadStopInfo,
eServerPacketType_qVAttachOrWaitSupported,
eServerPacketType_qWatchpointSupportInfo,
eServerPacketType_qWatchpointSupportInfoSupported,
+ eServerPacketType_qXfer_auxv_read,
eServerPacketType_vAttach,
eServerPacketType_vAttachWait,
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py Mon Jun 30 16:05:18 2014
@@ -86,7 +86,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_supports_auxv_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -111,7 +110,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_auxv_data_is_correct_size_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -152,7 +150,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_auxv_keys_look_valid_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -200,7 +197,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_auxv_chunked_reads_work_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py Mon Jun 30 16:05:18 2014
@@ -62,7 +62,6 @@ class TestGdbRemoteExpeditedRegisters(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_stop_notification_contains_any_registers_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -87,7 +86,6 @@ class TestGdbRemoteExpeditedRegisters(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_stop_notification_contains_no_duplicate_registers_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -107,7 +105,6 @@ class TestGdbRemoteExpeditedRegisters(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_stop_notification_contains_pc_register_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -127,7 +124,6 @@ class TestGdbRemoteExpeditedRegisters(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_stop_notification_contains_fp_register_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -147,7 +143,6 @@ class TestGdbRemoteExpeditedRegisters(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_stop_notification_contains_sp_register_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py Mon Jun 30 16:05:18 2014
@@ -100,7 +100,6 @@ class TestGdbRemoteRegisterState(gdbremo
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_grp_register_save_restore_works_with_suffix_llgs_dwarf(self):
USE_THREAD_SUFFIX = True
self.init_llgs_test()
@@ -119,7 +118,6 @@ class TestGdbRemoteRegisterState(gdbremo
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_grp_register_save_restore_works_no_suffix_llgs_dwarf(self):
USE_THREAD_SUFFIX = False
self.init_llgs_test()
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py Mon Jun 30 16:05:18 2014
@@ -15,7 +15,6 @@ class TestGdbRemoteSingleStep(gdbremote_
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_single_step_only_steps_one_instruction_with_s_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py Mon Jun 30 16:05:18 2014
@@ -83,7 +83,6 @@ class TestGdbRemoteThreadsInStopReply(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_QListThreadsInStopReply_supported_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -105,7 +104,6 @@ class TestGdbRemoteThreadsInStopReply(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_stop_reply_reports_multiple_threads_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -127,8 +125,7 @@ class TestGdbRemoteThreadsInStopReply(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
- def test_no_QThreadsInStopReply_supplies_no_threads_llgs_dwarf(self):
+ def test_no_QListThreadsInStopReply_supplies_no_threads_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
self.set_inferior_startup_launch()
@@ -164,7 +161,6 @@ class TestGdbRemoteThreadsInStopReply(gd
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_stop_reply_reports_correct_threads_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py Mon Jun 30 16:05:18 2014
@@ -41,8 +41,6 @@ class TestGdbRemote_vCont(gdbremote_test
self.vCont_supports_c()
@llgs_test
- @dwarf_test
- @unittest2.expectedFailure()
def test_vCont_supports_c_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -57,7 +55,6 @@ class TestGdbRemote_vCont(gdbremote_test
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_vCont_supports_C_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -72,7 +69,6 @@ class TestGdbRemote_vCont(gdbremote_test
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_vCont_supports_s_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -87,7 +83,6 @@ class TestGdbRemote_vCont(gdbremote_test
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_vCont_supports_S_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -103,7 +98,6 @@ class TestGdbRemote_vCont(gdbremote_test
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_single_step_only_steps_one_instruction_with_Hc_vCont_s_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -120,7 +114,6 @@ class TestGdbRemote_vCont(gdbremote_test
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_single_step_only_steps_one_instruction_with_vCont_s_thread_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -128,7 +121,5 @@ class TestGdbRemote_vCont(gdbremote_test
self.single_step_only_steps_one_instruction(use_Hc_packet=False, step_instruction="vCont;s:{thread}")
-
-
if __name__ == '__main__':
unittest2.main()
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Mon Jun 30 16:05:18 2014
@@ -63,7 +63,6 @@ class LldbGdbServerTestCase(gdbremote_te
self.thread_suffix_supported()
@llgs_test
- @unittest2.expectedFailure()
def test_thread_suffix_supported_llgs(self):
self.init_llgs_test()
self.thread_suffix_supported()
@@ -85,7 +84,6 @@ class LldbGdbServerTestCase(gdbremote_te
self.list_threads_in_stop_reply_supported()
@llgs_test
- @unittest2.expectedFailure()
def test_list_threads_in_stop_reply_supported_llgs(self):
self.init_llgs_test()
self.list_threads_in_stop_reply_supported()
@@ -143,7 +141,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_inferior_exit_0_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -176,7 +173,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_inferior_exit_42_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -207,7 +203,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_c_packet_works_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -240,7 +235,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_inferior_print_exit_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -272,7 +266,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_first_launch_stop_reply_thread_matches_first_qC_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -308,7 +301,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qProcessInfo_returns_running_process_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -343,7 +335,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_attach_commandline_qProcessInfo_reports_correct_pid_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -376,7 +367,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qProcessInfo_reports_valid_endian_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -410,7 +400,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_attach_commandline_continue_app_exits_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -445,7 +434,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_attach_commandline_kill_after_initial_stop_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -484,7 +472,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qRegisterInfo_returns_one_valid_result_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -519,7 +506,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qRegisterInfo_returns_all_valid_results_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -568,7 +554,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qRegisterInfo_contains_required_generics_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -606,7 +591,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qRegisterInfo_contains_at_least_one_register_set_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -635,10 +619,8 @@ class LldbGdbServerTestCase(gdbremote_te
register_sets = { reg_info['set']:1 for reg_info in reg_infos if 'set' in reg_info }
self.assertTrue("Advanced Vector Extensions" in register_sets)
-
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qRegisterInfo_contains_avx_registers_on_linux_x86_64_llgs_dwarf(self):
# Skip this test if not Linux x86_64.
if platform.system() != "Linux" or platform.processor() != "x86_64":
@@ -673,7 +655,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qThreadInfo_contains_thread_launch_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -690,7 +671,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qThreadInfo_contains_thread_attach_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -735,7 +715,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qThreadInfo_matches_qC_launch_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -752,7 +731,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qThreadInfo_matches_qC_attach_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -810,7 +788,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_p_returns_correct_data_size_for_each_qRegisterInfo_launch_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -827,7 +804,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_p_returns_correct_data_size_for_each_qRegisterInfo_attach_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -873,7 +849,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_Hg_switches_to_3_threads_launch_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -890,7 +865,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_Hg_switches_to_3_threads_attach_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1010,7 +984,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_Hc_then_Csignal_signals_correct_thread_launch_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1073,7 +1046,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_m_packet_reads_memory_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1101,7 +1073,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qMemoryRegionInfo_is_supported_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1165,7 +1136,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qMemoryRegionInfo_reports_code_address_as_executable_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1229,7 +1199,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qMemoryRegionInfo_reports_stack_address_as_readable_writeable_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1294,7 +1263,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qMemoryRegionInfo_reports_heap_address_as_readable_writeable_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1411,7 +1379,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_software_breakpoint_set_and_remove_work_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1442,7 +1409,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_qSupported_returns_known_stub_features_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1503,7 +1469,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_written_M_content_reads_back_correctly_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1550,7 +1515,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_P_writes_all_gpr_registers_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
@@ -1659,7 +1623,6 @@ class LldbGdbServerTestCase(gdbremote_te
@llgs_test
@dwarf_test
- @unittest2.expectedFailure()
def test_P_and_p_thread_suffix_work_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
Modified: lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py Mon Jun 30 16:05:18 2014
@@ -1024,3 +1024,4 @@ class GdbRemoteTestCaseBase(TestBase):
(state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
self.assertTrue(state_reached)
self.assertEquals(step_count, 1)
+
Modified: lldb/trunk/test/tools/lldb-gdbserver/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/main.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/main.cpp (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/main.cpp Mon Jun 30 16:05:18 2014
@@ -92,9 +92,12 @@ signal_handler (int signo)
switch (signo)
{
case SIGSEGV:
- // Fix up the pointer we're writing to. This needs to happen if nothing intercepts the SIGSEGV
- // (i.e. if somebody runs this from the command line).
- longjmp(g_jump_buffer, 1);
+ if (g_is_segfaulting)
+ {
+ // Fix up the pointer we're writing to. This needs to happen if nothing intercepts the SIGSEGV
+ // (i.e. if somebody runs this from the command line).
+ longjmp(g_jump_buffer, 1);
+ }
break;
case SIGUSR1:
if (g_is_segfaulting)
Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Mon Jun 30 16:05:18 2014
@@ -2326,6 +2326,7 @@ RNBRemote::SendStopReplyPacketForThread
{
size_t thread_name_len = strlen(thread_name);
+
if (::strcspn (thread_name, "$#+-;:") == thread_name_len)
ostrm << std::hex << "name:" << thread_name << ';';
else
Modified: lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp (original)
+++ lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp Mon Jun 30 16:05:18 2014
@@ -52,6 +52,7 @@ static struct option g_long_options[] =
{ "lldb-command", required_argument, NULL, 'c' },
{ "log-file", required_argument, NULL, 'l' },
{ "log-flags", required_argument, NULL, 'f' },
+ { "attach", required_argument, NULL, 'a' },
{ NULL, 0, NULL, 0 }
};
@@ -59,21 +60,38 @@ static struct option g_long_options[] =
//----------------------------------------------------------------------
// Watch for signals
//----------------------------------------------------------------------
-int g_sigpipe_received = 0;
+static int g_sigpipe_received = 0;
+static int g_sighup_received_count = 0;
+
void
signal_handler(int signo)
{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ fprintf (stderr, "lldb-gdbserver:%s received signal %d\n", __FUNCTION__, signo);
+ if (log)
+ log->Printf ("lldb-gdbserver:%s received signal %d", __FUNCTION__, signo);
+
switch (signo)
{
case SIGPIPE:
g_sigpipe_received = 1;
break;
case SIGHUP:
+#if 1
+ ++g_sighup_received_count;
+
+ // For now, swallow SIGHUP.
+ if (log)
+ log->Printf ("lldb-gdbserver:%s swallowing SIGHUP (receive count=%d)", __FUNCTION__, g_sighup_received_count);
+ signal (SIGHUP, signal_handler);
+#else
// Use SIGINT first, if that does not work, use SIGHUP as a last resort.
// And we should not call exit() here because it results in the global destructors
// to be invoked and wreaking havoc on the threads still running.
Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-gdbserver...\n");
abort();
+#endif
break;
}
}
@@ -124,21 +142,221 @@ terminate_lldb_gdbserver ()
PluginManager::Terminate ();
}
+static void
+run_lldb_commands (const lldb::DebuggerSP &debugger_sp, const std::vector<std::string> lldb_commands)
+{
+ for (const auto &lldb_command : lldb_commands)
+ {
+ printf("(lldb) %s\n", lldb_command.c_str ());
+
+ lldb_private::CommandReturnObject result;
+ debugger_sp->GetCommandInterpreter ().HandleCommand (lldb_command.c_str (), eLazyBoolNo, result);
+ const char *output = result.GetOutputData ();
+ if (output && output[0])
+ puts (output);
+ }
+}
+
+static lldb::PlatformSP
+setup_platform (const std::string platform_name)
+{
+ lldb::PlatformSP platform_sp;
+
+ if (platform_name.empty())
+ {
+ printf ("using the default platform: ");
+ platform_sp = Platform::GetDefaultPlatform ();
+ printf ("%s\n", platform_sp->GetPluginName ().AsCString ());
+ return platform_sp;
+ }
+
+ Error error;
+ platform_sp = Platform::Create (platform_name.c_str(), error);
+ if (error.Fail ())
+ {
+ // the host platform isn't registered with that name (at
+ // least, not always. Check if the given name matches
+ // the default platform name. If so, use it.
+ if ( Platform::GetDefaultPlatform () && ( Platform::GetDefaultPlatform ()->GetPluginName () == ConstString (platform_name.c_str()) ) )
+ {
+ platform_sp = Platform::GetDefaultPlatform ();
+ }
+ else
+ {
+ fprintf (stderr, "error: failed to create platform with name '%s'\n", platform_name.c_str());
+ dump_available_platforms (stderr);
+ exit (1);
+ }
+ }
+ printf ("using platform: %s\n", platform_name.c_str ());
+
+ return platform_sp;
+}
+
+void
+handle_attach_to_pid (GDBRemoteCommunicationServer &gdb_server, lldb::pid_t pid)
+{
+ Error error = gdb_server.AttachToProcess (pid);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, error.AsCString());
+ exit(1);
+ }
+}
+
+void
+handle_attach_to_process_name (GDBRemoteCommunicationServer &gdb_server, const std::string &process_name)
+{
+ // FIXME implement.
+}
+
+void
+handle_attach (GDBRemoteCommunicationServer &gdb_server, const std::string &attach_target)
+{
+ assert (!attach_target.empty () && "attach_target cannot be empty");
+
+ // First check if the attach_target is convertable to a long. If so, we'll use it as a pid.
+ char *end_p = nullptr;
+ const long int pid = strtol (attach_target.c_str (), &end_p, 10);
+
+ // We'll call it a match if the entire argument is consumed.
+ if (end_p && static_cast<size_t> (end_p - attach_target.c_str ()) == attach_target.size ())
+ handle_attach_to_pid (gdb_server, static_cast<lldb::pid_t> (pid));
+ else
+ handle_attach_to_process_name (gdb_server, attach_target);
+}
+
+void
+handle_launch (GDBRemoteCommunicationServer &gdb_server, int argc, const char *const argv[])
+{
+ Error error;
+ error = gdb_server.SetLaunchArguments (argv, argc);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to set launch args for '%s': %s\n", argv[0], error.AsCString());
+ exit(1);
+ }
+
+ unsigned int launch_flags = eLaunchFlagStopAtEntry | eLaunchFlagDebug;
+
+ error = gdb_server.SetLaunchFlags (launch_flags);
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to set launch flags for '%s': %s\n", argv[0], error.AsCString());
+ exit(1);
+ }
+
+ error = gdb_server.LaunchProcess ();
+ if (error.Fail ())
+ {
+ fprintf (stderr, "error: failed to launch '%s': %s\n", argv[0], error.AsCString());
+ exit(1);
+ }
+}
+
+void
+start_listener (GDBRemoteCommunicationServer &gdb_server, const char *const host_and_port, const char *const progname)
+{
+ Error error;
+
+ if (host_and_port && host_and_port[0])
+ {
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ std::string final_host_and_port;
+ std::string listening_host;
+ std::string listening_port;
+
+ // If host_and_port starts with ':', default the host to be "localhost" and expect the remainder to be the port.
+ if (host_and_port[0] == ':')
+ final_host_and_port.append ("localhost");
+ final_host_and_port.append (host_and_port);
+
+ const std::string::size_type colon_pos = final_host_and_port.find(':');
+ if (colon_pos != std::string::npos)
+ {
+ listening_host = final_host_and_port.substr(0, colon_pos);
+ listening_port = final_host_and_port.substr(colon_pos + 1);
+ }
+
+ std::string connect_url ("listen://");
+ connect_url.append (final_host_and_port);
+
+ printf ("Listening to port %s for a connection from %s...\n", listening_port.c_str (), listening_host.c_str ());
+ if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+ {
+ printf ("Connection established.\n");
+ gdb_server.SetConnection (conn_ap.release());
+ }
+ else
+ {
+ fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ());
+ display_usage (progname);
+ exit (1);
+ }
+ }
+
+ if (gdb_server.IsConnected())
+ {
+ // After we connected, we need to get an initial ack from...
+ if (gdb_server.HandshakeWithClient(&error))
+ {
+ // We'll use a half a second timeout interval so that an exit conditions can
+ // be checked that often.
+ const uint32_t TIMEOUT_USEC = 500000;
+
+ bool interrupt = false;
+ bool done = false;
+ while (!interrupt && !done && (g_sighup_received_count < 1))
+ {
+ const GDBRemoteCommunication::PacketResult result = gdb_server.GetPacketAndSendResponse (TIMEOUT_USEC, error, interrupt, done);
+ if ((result != GDBRemoteCommunication::PacketResult::Success) &&
+ (result != GDBRemoteCommunication::PacketResult::ErrorReplyTimeout))
+ {
+ // We're bailing out - we only support successful handling and timeouts.
+ fprintf(stderr, "leaving packet loop due to PacketResult %d\n", result);
+ break;
+ }
+ }
+
+ if (error.Fail())
+ {
+ fprintf(stderr, "error: %s\n", error.AsCString());
+ }
+ }
+ else
+ {
+ fprintf(stderr, "error: handshake with client failed\n");
+ }
+ }
+ }
+ else
+ {
+ fprintf (stderr, "no connection information provided, unable to run\n");
+ display_usage (progname);
+ exit (1);
+ }
+}
+
//----------------------------------------------------------------------
// main
//----------------------------------------------------------------------
int
main (int argc, char *argv[])
{
- const char *progname = argv[0];
+ // Setup signal handlers first thing.
signal (SIGPIPE, signal_handler);
signal (SIGHUP, signal_handler);
+
+ const char *progname = argv[0];
int long_option_index = 0;
StreamSP log_stream_sp;
Args log_args;
Error error;
int ch;
std::string platform_name;
+ std::string attach_target;
initialize_lldb_gdbserver ();
@@ -215,6 +433,11 @@ main (int argc, char *argv[])
platform_name = optarg;
break;
+ case 'a': // attach {pid|process_name}
+ if (optarg && optarg[0])
+ attach_target = optarg;
+ break;
+
case 'h': /* fall-through is intentional */
case '?':
show_usage = true;
@@ -235,7 +458,7 @@ main (int argc, char *argv[])
ProcessGDBRemoteLog::EnableLog (log_stream_sp, 0,log_args.GetConstArgumentVector(), log_stream_sp.get());
}
- // Skip any options we consumed with getopt_long_only
+ // Skip any options we consumed with getopt_long_only.
argc -= optind;
argv += optind;
@@ -245,155 +468,29 @@ main (int argc, char *argv[])
exit(255);
}
- // Run any commands requested
- for (const auto &lldb_command : lldb_commands)
- {
- printf("(lldb) %s\n", lldb_command.c_str ());
-
- lldb_private::CommandReturnObject result;
- debugger_sp->GetCommandInterpreter ().HandleCommand (lldb_command.c_str (), eLazyBoolNo, result);
- const char *output = result.GetOutputData ();
- if (output && output[0])
- puts (output);
- }
+ // Run any commands requested.
+ run_lldb_commands (debugger_sp, lldb_commands);
- // setup the platform that GDBRemoteCommunicationServer will use
- lldb::PlatformSP platform_sp;
- if (platform_name.empty())
- {
- printf ("using the default platform: ");
- platform_sp = Platform::GetDefaultPlatform ();
- printf ("%s\n", platform_sp->GetPluginName ().AsCString ());
- }
- else
- {
- Error error;
- platform_sp = Platform::Create (platform_name.c_str(), error);
- if (error.Fail ())
- {
- // the host platform isn't registered with that name (at
- // least, not always. Check if the given name matches
- // the default platform name. If so, use it.
- if ( Platform::GetDefaultPlatform () && ( Platform::GetDefaultPlatform ()->GetPluginName () == ConstString (platform_name.c_str()) ) )
- {
- platform_sp = Platform::GetDefaultPlatform ();
- }
- else
- {
- fprintf (stderr, "error: failed to create platform with name '%s'\n", platform_name.c_str());
- dump_available_platforms (stderr);
- exit (1);
- }
- }
- printf ("using platform: %s\n", platform_name.c_str ());
- }
+ // Setup the platform that GDBRemoteCommunicationServer will use.
+ lldb::PlatformSP platform_sp = setup_platform (platform_name);
const bool is_platform = false;
- GDBRemoteCommunicationServer gdb_server (is_platform, platform_sp);
+ GDBRemoteCommunicationServer gdb_server (is_platform, platform_sp, debugger_sp);
- const char *host_and_port = argv[0];
+ const char *const host_and_port = argv[0];
argc -= 1;
argv += 1;
+
// Any arguments left over are for the the program that we need to launch. If there
// are no arguments, then the GDB server will start up and wait for an 'A' packet
- // to launch a program, or a vAttach packet to attach to an existing process.
- if (argc > 0)
- {
- error = gdb_server.SetLaunchArguments (argv, argc);
- if (error.Fail ())
- {
- fprintf (stderr, "error: failed to set launch args for '%s': %s\n", argv[0], error.AsCString());
- exit(1);
- }
-
- unsigned int launch_flags = eLaunchFlagStopAtEntry;
-#if !defined(__linux__)
- // linux doesn't yet handle eLaunchFlagDebug
- launch_flags |= eLaunchFlagDebug;
-#endif
- error = gdb_server.SetLaunchFlags (launch_flags);
- if (error.Fail ())
- {
- fprintf (stderr, "error: failed to set launch flags for '%s': %s\n", argv[0], error.AsCString());
- exit(1);
- }
-
- error = gdb_server.LaunchProcess ();
- if (error.Fail ())
- {
- fprintf (stderr, "error: failed to launch '%s': %s\n", argv[0], error.AsCString());
- exit(1);
- }
- }
-
- if (host_and_port && host_and_port[0])
- {
- std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
- if (conn_ap.get())
- {
- std::string final_host_and_port;
- std::string listening_host;
- std::string listening_port;
-
- // If host_and_port starts with ':', default the host to be "localhost" and expect the remainder to be the port.
- if (host_and_port[0] == ':')
- final_host_and_port.append ("localhost");
- final_host_and_port.append (host_and_port);
-
- const std::string::size_type colon_pos = final_host_and_port.find(':');
- if (colon_pos != std::string::npos)
- {
- listening_host = final_host_and_port.substr(0, colon_pos);
- listening_port = final_host_and_port.substr(colon_pos + 1);
- }
-
- std::string connect_url ("listen://");
- connect_url.append (final_host_and_port);
-
- printf ("Listening to port %s for a connection from %s...\n", listening_port.c_str (), listening_host.c_str ());
- if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
- {
- printf ("Connection established.\n");
- gdb_server.SetConnection (conn_ap.release());
- }
- else
- {
- fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ());
- display_usage (progname);
- exit (1);
- }
- }
-
- if (gdb_server.IsConnected())
- {
- // After we connected, we need to get an initial ack from...
- if (gdb_server.HandshakeWithClient(&error))
- {
- bool interrupt = false;
- bool done = false;
- while (!interrupt && !done)
- {
- if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
- break;
- }
+ // to launch a program, or a vAttach packet to attach to an existing process, unless
+ // explicitly asked to attach with the --attach={pid|program_name} form.
+ if (!attach_target.empty ())
+ handle_attach (gdb_server, attach_target);
+ else if (argc > 0)
+ handle_launch (gdb_server, argc, argv);
- if (error.Fail())
- {
- fprintf(stderr, "error: %s\n", error.AsCString());
- }
- }
- else
- {
- fprintf(stderr, "error: handshake with client failed\n");
- }
- }
- }
- else
- {
- fprintf (stderr, "no connection information provided, unable to run\n");
- display_usage (progname);
- exit (1);
- }
+ start_listener (gdb_server, host_and_port, progname);
terminate_lldb_gdbserver ();
Modified: lldb/trunk/tools/lldb-platform/lldb-platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-platform/lldb-platform.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-platform/lldb-platform.cpp (original)
+++ lldb/trunk/tools/lldb-platform/lldb-platform.cpp Mon Jun 30 16:05:18 2014
@@ -286,7 +286,7 @@ main (int argc, char *argv[])
bool done = false;
while (!interrupt && !done)
{
- if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
+ if (gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success)
break;
}
More information about the lldb-commits
mailing list