2013-08-23 13:46:38 -04:00
//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
2013-11-06 11:48:53 -05:00
# include <errno.h>
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
# include "lldb/Host/Config.h"
2013-08-23 13:46:38 -04:00
# include "GDBRemoteCommunicationServer.h"
2013-11-06 11:48:53 -05:00
# include "lldb/Core/StreamGDBRemote.h"
2013-08-23 13:46:38 -04:00
// C Includes
// C++ Includes
2014-11-25 16:00:58 -05:00
# include <cstring>
# include <chrono>
# include <thread>
2013-08-23 13:46:38 -04:00
// Other libraries and framework includes
# include "llvm/ADT/Triple.h"
# include "lldb/Interpreter/Args.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Core/Debugger.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/Log.h"
# include "lldb/Core/State.h"
# include "lldb/Core/StreamString.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Host/ConnectionFileDescriptor.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Host/Debug.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Endian.h"
2013-11-06 11:48:53 -05:00
# include "lldb/Host/File.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Host/FileSystem.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Host.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Host/HostInfo.h"
2015-02-08 20:44:09 -05:00
# include "lldb/Host/StringConvert.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/TimeValue.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Target/FileAction.h"
2014-02-18 11:23:10 -05:00
# include "lldb/Target/Platform.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/Process.h"
2015-02-08 20:44:09 -05:00
# include "lldb/Host/common/NativeRegisterContext.h"
# include "lldb/Host/common/NativeProcessProtocol.h"
# include "lldb/Host/common/NativeThreadProtocol.h"
2013-08-23 13:46:38 -04:00
// Project includes
# include "Utility/StringExtractorGDBRemote.h"
2015-02-08 20:44:09 -05:00
# include "Utility/UriParser.h"
2013-08-23 13:46:38 -04:00
# include "ProcessGDBRemote.h"
# include "ProcessGDBRemoteLog.h"
using namespace lldb ;
using namespace lldb_private ;
2014-11-25 16:00:58 -05:00
//----------------------------------------------------------------------
// GDBRemote Errors
//----------------------------------------------------------------------
namespace
{
enum GDBRemoteServerError
{
// Set to the first unused error number in literal form below
eErrorFirst = 29 ,
eErrorNoProcess = eErrorFirst ,
eErrorResume ,
eErrorExitStatus
} ;
}
2013-08-23 13:46:38 -04:00
//----------------------------------------------------------------------
// GDBRemoteCommunicationServer constructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServer : : GDBRemoteCommunicationServer ( bool is_platform ) :
GDBRemoteCommunication ( " gdb-remote.server " , " gdb-remote.server.rx_packet " , is_platform ) ,
2015-02-06 16:38:51 -05:00
m_platform_sp ( Platform : : GetHostPlatform ( ) ) ,
2013-08-23 13:46:38 -04:00
m_async_thread ( LLDB_INVALID_HOST_THREAD ) ,
m_process_launch_info ( ) ,
m_process_launch_error ( ) ,
2013-11-06 11:48:53 -05:00
m_spawned_pids ( ) ,
m_spawned_pids_mutex ( Mutex : : eMutexTypeRecursive ) ,
2013-08-23 13:46:38 -04:00
m_proc_infos ( ) ,
m_proc_infos_index ( 0 ) ,
2013-12-03 13:51:59 -05:00
m_port_map ( ) ,
2014-11-25 16:00:58 -05:00
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 )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
assert ( is_platform & & " must be lldb-platform if debugger is not specified " ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunicationServer : : GDBRemoteCommunicationServer ( bool is_platform ,
2014-11-25 16:00:58 -05:00
const lldb : : PlatformSP & platform_sp ,
lldb : : DebuggerSP & debugger_sp ) :
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication ( " gdb-remote.server " , " gdb-remote.server.rx_packet " , is_platform ) ,
m_platform_sp ( platform_sp ) ,
m_async_thread ( LLDB_INVALID_HOST_THREAD ) ,
m_process_launch_info ( ) ,
m_process_launch_error ( ) ,
m_spawned_pids ( ) ,
m_spawned_pids_mutex ( Mutex : : eMutexTypeRecursive ) ,
m_proc_infos ( ) ,
m_proc_infos_index ( 0 ) ,
m_port_map ( ) ,
2014-11-25 16:00:58 -05:00
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 )
2014-02-18 11:23:10 -05:00
{
assert ( platform_sp ) ;
2014-11-25 16:00:58 -05:00
assert ( ( is_platform | | debugger_sp ) & & " must specify non-NULL debugger_sp when lldb-gdbserver " ) ;
2014-02-18 11:23:10 -05:00
}
2013-08-23 13:46:38 -04:00
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServer : : ~ GDBRemoteCommunicationServer ( )
{
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : GetPacketAndSendResponse ( uint32_t timeout_usec ,
2013-08-23 13:46:38 -04:00
Error & error ,
2013-11-06 11:48:53 -05:00
bool & interrupt ,
2013-08-23 13:46:38 -04:00
bool & quit )
{
StringExtractorGDBRemote packet ;
2014-11-25 16:00:58 -05:00
2014-02-18 11:23:10 -05:00
PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock ( packet , timeout_usec ) ;
if ( packet_result = = PacketResult : : Success )
2013-08-23 13:46:38 -04:00
{
const StringExtractorGDBRemote : : ServerPacketType packet_type = packet . GetServerPacketType ( ) ;
switch ( packet_type )
{
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_nack :
case StringExtractorGDBRemote : : eServerPacketType_ack :
break ;
case StringExtractorGDBRemote : : eServerPacketType_invalid :
error . SetErrorString ( " invalid packet " ) ;
quit = true ;
break ;
default :
case StringExtractorGDBRemote : : eServerPacketType_unimplemented :
packet_result = SendUnimplementedResponse ( packet . GetStringRef ( ) . c_str ( ) ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_A :
packet_result = Handle_A ( packet ) ;
break ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qfProcessInfo :
packet_result = Handle_qfProcessInfo ( packet ) ;
break ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qsProcessInfo :
packet_result = Handle_qsProcessInfo ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qC :
packet_result = Handle_qC ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qHostInfo :
packet_result = Handle_qHostInfo ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qLaunchGDBServer :
packet_result = Handle_qLaunchGDBServer ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qKillSpawnedProcess :
packet_result = Handle_qKillSpawnedProcess ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_k :
packet_result = Handle_k ( packet ) ;
2014-11-25 16:00:58 -05:00
quit = true ;
2014-02-18 11:23:10 -05:00
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qLaunchSuccess :
packet_result = Handle_qLaunchSuccess ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qGroupName :
packet_result = Handle_qGroupName ( packet ) ;
break ;
2014-11-25 16:00:58 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qProcessInfo :
packet_result = Handle_qProcessInfo ( packet ) ;
break ;
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qProcessInfoPID :
packet_result = Handle_qProcessInfoPID ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_qSpeedTest :
packet_result = Handle_qSpeedTest ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_qUserName :
packet_result = Handle_qUserName ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_qGetWorkingDir :
packet_result = Handle_qGetWorkingDir ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_QEnvironment :
packet_result = Handle_QEnvironment ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_QLaunchArch :
packet_result = Handle_QLaunchArch ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_QSetDisableASLR :
packet_result = Handle_QSetDisableASLR ( packet ) ;
break ;
2014-11-25 16:00:58 -05:00
case StringExtractorGDBRemote : : eServerPacketType_QSetDetachOnError :
packet_result = Handle_QSetDetachOnError ( packet ) ;
break ;
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_QSetSTDIN :
packet_result = Handle_QSetSTDIN ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_QSetSTDOUT :
packet_result = Handle_QSetSTDOUT ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_QSetSTDERR :
packet_result = Handle_QSetSTDERR ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_QSetWorkingDir :
packet_result = Handle_QSetWorkingDir ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_QStartNoAckMode :
packet_result = Handle_QStartNoAckMode ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_qPlatform_mkdir :
packet_result = Handle_qPlatform_mkdir ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_qPlatform_chmod :
packet_result = Handle_qPlatform_chmod ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_qPlatform_shell :
packet_result = Handle_qPlatform_shell ( packet ) ;
break ;
2013-08-23 13:46:38 -04:00
2015-02-08 20:44:09 -05:00
case StringExtractorGDBRemote : : eServerPacketType_qWatchpointSupportInfo :
packet_result = Handle_qWatchpointSupportInfo ( packet ) ;
break ;
2014-11-25 16:00:58 -05:00
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 ;
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_open :
packet_result = Handle_vFile_Open ( packet ) ;
break ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_close :
packet_result = Handle_vFile_Close ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_pread :
packet_result = Handle_vFile_pRead ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_pwrite :
packet_result = Handle_vFile_pWrite ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_size :
packet_result = Handle_vFile_Size ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_mode :
packet_result = Handle_vFile_Mode ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_exists :
packet_result = Handle_vFile_Exists ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_stat :
packet_result = Handle_vFile_Stat ( packet ) ;
break ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_md5 :
packet_result = Handle_vFile_MD5 ( packet ) ;
break ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
case StringExtractorGDBRemote : : eServerPacketType_vFile_symlink :
packet_result = Handle_vFile_symlink ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_vFile_unlink :
packet_result = Handle_vFile_unlink ( packet ) ;
break ;
2014-11-25 16:00:58 -05:00
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 ;
2015-02-08 20:44:09 -05:00
case StringExtractorGDBRemote : : eServerPacketType_I :
packet_result = Handle_I ( packet ) ;
break ;
2014-11-25 16:00:58 -05:00
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 ;
case StringExtractorGDBRemote : : eServerPacketType_vAttach :
packet_result = Handle_vAttach ( packet ) ;
break ;
2015-02-06 16:38:51 -05:00
case StringExtractorGDBRemote : : eServerPacketType_D :
packet_result = Handle_D ( packet ) ;
break ;
case StringExtractorGDBRemote : : eServerPacketType_qThreadStopInfo :
packet_result = Handle_qThreadStopInfo ( packet ) ;
break ;
2014-02-18 11:23:10 -05:00
}
}
else
{
if ( ! IsConnected ( ) )
{
error . SetErrorString ( " lost connection " ) ;
quit = true ;
}
else
{
error . SetErrorString ( " timeout " ) ;
}
}
2014-11-25 16:00:58 -05:00
// Check if anything occurred that would force us to want to exit.
if ( m_exit_now )
quit = true ;
return packet_result ;
2014-02-18 11:23:10 -05:00
}
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
lldb_private : : Error
GDBRemoteCommunicationServer : : SetLaunchArguments ( const char * const args [ ] , int argc )
{
if ( ( argc < 1 ) | | ! args | | ! args [ 0 ] | | ! args [ 0 ] [ 0 ] )
return lldb_private : : Error ( " %s: no process command line specified to launch " , __FUNCTION__ ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
m_process_launch_info . SetArguments ( const_cast < const char * * > ( args ) , true ) ;
return lldb_private : : Error ( ) ;
}
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
lldb_private : : Error
GDBRemoteCommunicationServer : : SetLaunchFlags ( unsigned int launch_flags )
{
m_process_launch_info . GetFlags ( ) . Set ( launch_flags ) ;
return lldb_private : : Error ( ) ;
}
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
lldb_private : : Error
GDBRemoteCommunicationServer : : LaunchProcess ( )
2014-11-25 16:00:58 -05:00
{
// 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 ( ) )
2015-02-06 16:38:51 -05:00
return LaunchProcessForDebugging ( ) ;
2014-11-25 16:00:58 -05:00
else
return LaunchPlatformProcess ( ) ;
}
2015-02-06 16:38:51 -05:00
bool
GDBRemoteCommunicationServer : : ShouldRedirectInferiorOutputOverGdbRemote ( const lldb_private : : ProcessLaunchInfo & launch_info ) const
{
// Retrieve the file actions specified for stdout and stderr.
auto stdout_file_action = launch_info . GetFileActionForFD ( STDOUT_FILENO ) ;
auto stderr_file_action = launch_info . GetFileActionForFD ( STDERR_FILENO ) ;
// If neither stdout and stderr file actions are specified, we're not doing anything special, so
// assume we want to redirect stdout/stderr over gdb-remote $O messages.
if ( ( stdout_file_action = = nullptr ) & & ( stderr_file_action = = nullptr ) )
{
// Send stdout/stderr over the gdb-remote protocol.
return true ;
}
// Any other setting for either stdout or stderr implies we are either suppressing
// it (with /dev/null) or we've got it set to a PTY. Either way, we don't want the
// output over gdb-remote.
return false ;
}
2014-11-25 16:00:58 -05:00
lldb_private : : Error
2015-02-06 16:38:51 -05:00
GDBRemoteCommunicationServer : : LaunchProcessForDebugging ( )
2014-11-25 16:00:58 -05:00
{
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 ;
}
2015-02-06 16:38:51 -05:00
// Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as needed.
// llgs local-process debugging may specify PTYs, which will eliminate the need to reflect inferior
// stdout/stderr over the gdb-remote protocol.
if ( ShouldRedirectInferiorOutputOverGdbRemote ( m_process_launch_info ) )
2014-11-25 16:00:58 -05:00
{
if ( log )
2015-02-06 16:38:51 -05:00
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
// Setup stdout/stderr mapping from inferior to $O
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 ) ;
}
2014-11-25 16:00:58 -05:00
}
else
{
if ( log )
2015-02-06 16:38:51 -05:00
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
2014-11-25 16:00:58 -05:00
}
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
2015-02-06 16:38:51 -05:00
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 ) ;
2014-11-25 16:00:58 -05:00
}
return error ;
}
lldb_private : : Error
GDBRemoteCommunicationServer : : LaunchPlatformProcess ( )
2014-02-18 11:23:10 -05:00
{
if ( ! m_process_launch_info . GetArguments ( ) . GetArgumentCount ( ) )
return lldb_private : : Error ( " %s: no process command line specified to launch " , __FUNCTION__ ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
// specify the process monitor if not already set. This should
// generally be what happens since we need to reap started
// processes.
if ( ! m_process_launch_info . GetMonitorProcessCallback ( ) )
m_process_launch_info . SetMonitorProcessCallback ( ReapDebuggedProcess , this , false ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
lldb_private : : Error error = m_platform_sp - > LaunchProcess ( m_process_launch_info ) ;
if ( ! error . Success ( ) )
{
fprintf ( stderr , " %s: failed to launch executable %s " , __FUNCTION__ , m_process_launch_info . GetArguments ( ) . GetArgumentAtIndex ( 0 ) ) ;
return error ;
}
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
printf ( " Launched '%s' as process % " PRIu64 " ... \n " , m_process_launch_info . GetArguments ( ) . GetArgumentAtIndex ( 0 ) , m_process_launch_info . GetProcessID ( ) ) ;
2013-12-03 13:51:59 -05:00
2014-02-18 11:23:10 -05:00
// add to list of spawned processes. On an lldb-gdbserver, we
// would expect there to be only one.
2015-02-08 20:44:09 -05:00
const auto pid = m_process_launch_info . GetProcessID ( ) ;
if ( pid ! = LLDB_INVALID_PROCESS_ID )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// add to spawned pids
2015-02-08 20:44:09 -05:00
Mutex : : Locker locker ( m_spawned_pids_mutex ) ;
m_spawned_pids . insert ( pid ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
return error ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
lldb_private : : Error
GDBRemoteCommunicationServer : : AttachToProcess ( lldb : : pid_t pid )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
Error error ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
if ( ! IsGdbServer ( ) )
{
error . SetErrorString ( " cannot AttachToProcess () unless process is lldb-gdbserver " ) ;
return error ;
}
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64 , __FUNCTION__ , pid ) ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
// 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 ;
}
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
void
GDBRemoteCommunicationServer : : InitializeDelegate ( lldb_private : : NativeProcessProtocol * process )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 ( ) ) ) ;
}
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : SendWResponse ( lldb_private : : NativeProcessProtocol * process )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
assert ( process & & " process cannot be NULL " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// send W notification
ExitType exit_type = ExitType : : eExitTypeInvalid ;
int return_code = 0 ;
std : : string exit_description ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
const bool got_exit_info = process - > GetExitStatus ( & exit_type , & return_code , exit_description ) ;
if ( ! got_exit_info )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64 " , failed to retrieve process exit status " , __FUNCTION__ , process - > GetID ( ) ) ;
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
StreamGDBRemote response ;
response . PutChar ( ' E ' ) ;
response . PutHex8 ( GDBRemoteServerError : : eErrorExitStatus ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
2013-08-23 13:46:38 -04:00
else
{
2014-11-25 16:00:58 -05:00
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 ( ) ) ;
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
StreamGDBRemote response ;
char return_type_code ;
switch ( exit_type )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
case ExitType : : eExitTypeExit :
return_type_code = ' W ' ;
break ;
case ExitType : : eExitTypeSignal :
return_type_code = ' X ' ;
break ;
case ExitType : : eExitTypeStop :
return_type_code = ' S ' ;
break ;
2014-11-25 16:00:58 -05:00
case ExitType : : eExitTypeInvalid :
2015-02-06 16:38:51 -05:00
return_type_code = ' E ' ;
break ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
response . PutChar ( return_type_code ) ;
// POSIX exit status limited to unsigned 8 bits.
response . PutHex8 ( return_code ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
static void
AppendHexValue ( StreamString & response , const uint8_t * buf , uint32_t buf_size , bool swap )
{
int64_t i ;
if ( swap )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
for ( i = buf_size - 1 ; i > = 0 ; i - - )
response . PutHex8 ( buf [ i ] ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
else
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
for ( i = 0 ; i < buf_size ; i + + )
response . PutHex8 ( buf [ i ] ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
}
2013-12-03 13:51:59 -05:00
2014-11-25 16:00:58 -05:00
static void
WriteRegisterValueInHexFixedWidth ( StreamString & response ,
NativeRegisterContextSP & reg_ctx_sp ,
const RegisterInfo & reg_info ,
const RegisterValue * reg_value_p )
{
RegisterValue reg_value ;
if ( ! reg_value_p )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
Error error = reg_ctx_sp - > ReadRegister ( & reg_info , reg_value ) ;
if ( error . Success ( ) )
reg_value_p = & reg_value ;
// else log.
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
if ( reg_value_p )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 ) ;
}
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
// WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value);
2013-08-23 13:46:38 -04:00
static void
2014-11-25 16:00:58 -05:00
WriteGdbRegnumWithFixedWidthHexRegisterValue ( StreamString & response ,
NativeRegisterContextSP & reg_ctx_sp ,
const RegisterInfo & reg_info ,
const RegisterValue & reg_value )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// 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 , & reg_value ) ;
response . PutChar ( ' ; ' ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : SendStopReplyPacketForThread ( lldb : : tid_t tid )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
// Ensure we're llgs.
if ( ! IsGdbServer ( ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// 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 ;
2015-02-08 20:44:09 -05:00
std : : string description ;
if ( ! thread_sp - > GetStopReason ( tid_stop_info , description ) )
2014-11-25 16:00:58 -05:00
return SendErrorResponse ( 52 ) ;
// FIXME implement register handling for exec'd inferiors.
2015-02-08 20:44:09 -05:00
// if (tid_stop_info.reason == eStopReasonExec)
2014-11-25 16:00:58 -05:00
// {
// 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 ) ;
}
// Print the signal number.
response . PutHex8 ( signum & 0xff ) ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
// Include the tid.
response . Printf ( " thread:% " PRIx64 " ; " , tid ) ;
// Include the thread name if there is one.
2015-02-06 16:38:51 -05:00
const std : : string thread_name = thread_sp - > GetName ( ) ;
if ( ! thread_name . empty ( ) )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
size_t thread_name_len = thread_name . length ( ) ;
2013-11-06 11:48:53 -05:00
2015-02-06 16:38:51 -05:00
if ( : : strcspn ( thread_name . c_str ( ) , " $#+-;: " ) = = thread_name_len )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
response . PutCString ( " name: " ) ;
2015-02-06 16:38:51 -05:00
response . PutCString ( thread_name . c_str ( ) ) ;
2014-11-25 16:00:58 -05:00
}
else
{
// The thread name contains special chars, send as hex bytes.
response . PutCString ( " hexname: " ) ;
2015-02-06 16:38:51 -05:00
response . PutCStringAsRawHex8 ( thread_name . c_str ( ) ) ;
2014-11-25 16:00:58 -05:00
}
response . PutChar ( ' ; ' ) ;
}
// If a 'QListThreadsInStopReply' was sent to enable this feature, we
// will send all thread IDs back in the "threads" key whose value is
// a list 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 )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
const RegisterInfo * const reg_info_p = reg_ctx_sp - > GetRegisterInfoAtIndex ( * reg_num_p ) ;
if ( reg_info_p = = nullptr )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
else if ( reg_info_p - > value_regs = = nullptr )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// 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 ( ) ) ;
}
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
}
}
2013-11-06 11:48:53 -05:00
2015-02-08 20:44:09 -05:00
const char * reason_str = nullptr ;
switch ( tid_stop_info . reason )
{
case eStopReasonTrace :
reason_str = " trace " ;
break ;
case eStopReasonBreakpoint :
reason_str = " breakpoint " ;
break ;
case eStopReasonWatchpoint :
reason_str = " watchpoint " ;
break ;
case eStopReasonSignal :
reason_str = " signal " ;
break ;
case eStopReasonException :
reason_str = " exception " ;
break ;
case eStopReasonExec :
reason_str = " exec " ;
break ;
case eStopReasonInstrumentation :
case eStopReasonInvalid :
case eStopReasonPlanComplete :
case eStopReasonThreadExiting :
case eStopReasonNone :
break ;
}
if ( reason_str ! = nullptr )
{
response . Printf ( " reason:%s; " , reason_str ) ;
}
if ( ! description . empty ( ) )
2014-11-25 16:00:58 -05:00
{
2015-02-08 20:44:09 -05:00
// Description may contains special chars, send as hex bytes.
response . PutCString ( " description: " ) ;
response . PutCStringAsRawHex8 ( description . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
2014-11-25 16:00:58 -05:00
}
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 ( ' ; ' ) ;
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
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 )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed to send stop notification for PID % " PRIu64 " , state: eStateExited " , __FUNCTION__ , process - > GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
// 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 ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
void
GDBRemoteCommunicationServer : : HandleInferiorState_Stopped ( lldb_private : : NativeProcessProtocol * process )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 ;
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
void
GDBRemoteCommunicationServer : : ProcessStateChanged ( lldb_private : : NativeProcessProtocol * process , lldb : : StateType state )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
assert ( process & & " process cannot be NULL " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
log - > Printf ( " GDBRemoteCommunicationServer::%s didn't handle state change for pid % " PRIu64 " , new state: %s " ,
__FUNCTION__ ,
process - > GetID ( ) ,
StateAsCString ( state ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
break ;
2013-08-23 13:46:38 -04:00
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// Remember the previous state reported to us.
m_inferior_prev_state = state ;
}
void
GDBRemoteCommunicationServer : : DidExec ( NativeProcessProtocol * process )
{
ClearProcessSpecificData ( ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : SendONotification ( const char * buffer , uint32_t len )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
if ( ( buffer = = nullptr ) | | ( len = = 0 ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// Nothing to send.
return PacketResult : : Success ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
StreamString response ;
response . PutChar ( ' O ' ) ;
response . PutBytesAsRawHex8 ( buffer , len ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
lldb_private : : Error
GDBRemoteCommunicationServer : : SetSTDIOFileDescriptor ( int fd )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
Error error ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
// Set up the Read Thread for reading/handling process I/O
std : : unique_ptr < ConnectionFileDescriptor > conn_up ( new ConnectionFileDescriptor ( fd , true ) ) ;
if ( ! conn_up )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 ( HostInfo : : GetArchitecture ( ) ) ;
const llvm : : Triple & host_triple = host_arch . GetTriple ( ) ;
response . PutCString ( " triple: " ) ;
2015-02-06 16:38:51 -05:00
response . PutCStringAsRawHex8 ( host_triple . getTriple ( ) . c_str ( ) ) ;
2014-11-25 16:00:58 -05:00
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 ( HostInfo : : 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 ( HostInfo : : GetOSBuildString ( s ) )
{
response . PutCString ( " os_build: " ) ;
response . PutCStringAsRawHex8 ( s . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
if ( HostInfo : : GetOSKernelDescription ( s ) )
{
response . PutCString ( " os_kernel: " ) ;
response . PutCStringAsRawHex8 ( s . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
# if defined(__APPLE__)
# if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
// 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__) || defined(__aarch64__)
if ( HostInfo : : GetHostname ( s ) )
{
response . PutCString ( " hostname: " ) ;
response . PutCStringAsRawHex8 ( s . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
# endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
# else // #if defined(__APPLE__)
if ( HostInfo : : 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: " ) ;
2015-02-06 16:38:51 -05:00
response . PutCStringAsRawHex8 ( proc_triple . getTriple ( ) . c_str ( ) ) ;
2014-11-25 16:00:58 -05:00
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 llvm : : Triple & proc_triple = proc_arch . GetTriple ( ) ;
# if defined(__APPLE__)
// We'll send cputype/cpusubtype.
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 std : : string vendor = proc_triple . getVendorName ( ) ;
if ( ! vendor . empty ( ) )
response . Printf ( " vendor:%s; " , vendor . c_str ( ) ) ;
# else
// We'll send the triple.
2015-02-06 16:38:51 -05:00
response . PutCString ( " triple: " ) ;
response . PutCStringAsRawHex8 ( proc_triple . getTriple ( ) . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
2014-11-25 16:00:58 -05:00
# endif
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 : : aarch64 :
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 )
{
2015-02-08 20:44:09 -05:00
lldb : : pid_t pid = LLDB_INVALID_PROCESS_ID ;
if ( IsGdbServer ( ) )
2014-11-25 16:00:58 -05:00
{
2015-02-08 20:44:09 -05:00
// 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 ) ;
pid = m_debugged_process_sp - > GetID ( ) ;
2014-11-25 16:00:58 -05:00
}
2015-02-08 20:44:09 -05:00
else if ( m_is_platform )
{
pid = m_process_launch_info . GetProcessID ( ) ;
m_process_launch_info . Clear ( ) ;
}
else
return SendUnimplementedResponse ( packet . GetStringRef ( ) . c_str ( ) ) ;
if ( pid = = LLDB_INVALID_PROCESS_ID )
return SendErrorResponse ( 1 ) ;
ProcessInstanceInfo proc_info ;
if ( ! Host : : GetProcessInfo ( pid , proc_info ) )
return SendErrorResponse ( 1 ) ;
StreamString response ;
CreateProcessInfoResponse_DebugServerStyle ( proc_info , response ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2014-11-25 16:00:58 -05:00
}
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 )
{
2015-02-08 20:44:09 -05:00
match_info . GetProcessInfo ( ) . SetProcessID ( StringConvert : : ToUInt32 ( value . c_str ( ) , LLDB_INVALID_PROCESS_ID , 0 , & success ) ) ;
2014-11-25 16:00:58 -05:00
}
else if ( key . compare ( " parent_pid " ) = = 0 )
{
2015-02-08 20:44:09 -05:00
match_info . GetProcessInfo ( ) . SetParentProcessID ( StringConvert : : ToUInt32 ( value . c_str ( ) , LLDB_INVALID_PROCESS_ID , 0 , & success ) ) ;
2014-11-25 16:00:58 -05:00
}
else if ( key . compare ( " uid " ) = = 0 )
{
2015-02-08 20:44:09 -05:00
match_info . GetProcessInfo ( ) . SetUserID ( StringConvert : : ToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
2014-11-25 16:00:58 -05:00
}
else if ( key . compare ( " gid " ) = = 0 )
{
2015-02-08 20:44:09 -05:00
match_info . GetProcessInfo ( ) . SetGroupID ( StringConvert : : ToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
2014-11-25 16:00:58 -05:00
}
else if ( key . compare ( " euid " ) = = 0 )
{
2015-02-08 20:44:09 -05:00
match_info . GetProcessInfo ( ) . SetEffectiveUserID ( StringConvert : : ToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
2014-11-25 16:00:58 -05:00
}
else if ( key . compare ( " egid " ) = = 0 )
{
2015-02-08 20:44:09 -05:00
match_info . GetProcessInfo ( ) . SetEffectiveGroupID ( StringConvert : : ToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
2014-11-25 16:00:58 -05:00
}
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 )
{
# if !defined(LLDB_DISABLE_POSIX)
// 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 ( HostInfo : : LookupUserName ( uid , name ) )
{
StreamString response ;
response . PutCStringAsRawHex8 ( name . c_str ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
}
# endif
return SendErrorResponse ( 5 ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServer : : Handle_qGroupName ( StringExtractorGDBRemote & packet )
{
# if !defined(LLDB_DISABLE_POSIX)
// 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 ( HostInfo : : LookupGroupName ( gid , name ) )
{
StreamString response ;
response . PutCStringAsRawHex8 ( name . c_str ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
}
# endif
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 )
{
2015-02-08 20:44:09 -05:00
uint32_t response_size = StringConvert : : ToUInt32 ( value . c_str ( ) , 0 , 0 , & success ) ;
2014-11-25 16:00:58 -05:00
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 " ) ;
bytes_left - = 26 ;
}
else
{
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 because
// 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
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PLATFORM ) ) ;
// Spawn a local debugserver as a platform so we can then attach or launch
// a process...
if ( m_is_platform )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() called " , __FUNCTION__ ) ;
// Sleep and wait a bit for debugserver to start to listen...
ConnectionFileDescriptor file_conn ;
std : : string hostname ;
// TODO: /tmp/ should not be hardcoded. User might want to override /tmp
// with the TMPDIR environment 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 )
2015-02-08 20:44:09 -05:00
port = StringConvert : : ToUInt32 ( value . c_str ( ) , 0 , 0 ) ;
2014-11-25 16:00:58 -05:00
}
if ( port = = UINT16_MAX )
port = GetNextAvailablePort ( ) ;
// Spawn a new thread to accept the port that gets bound after
// binding to port 0 (zero).
2015-02-08 20:44:09 -05:00
// ignore the hostname send from the remote end, just use the ip address
// that we're currently communicating with as the hostname
2014-11-25 16:00:58 -05:00
// Spawn a debugserver and try to get the port it listens to.
ProcessLaunchInfo debugserver_launch_info ;
if ( hostname . empty ( ) )
hostname = " 127.0.0.1 " ;
if ( log )
log - > Printf ( " Launching debugserver with: %s:%u... \n " , hostname . c_str ( ) , port ) ;
2015-02-08 20:44:09 -05:00
// Do not run in a new session so that it can not linger after the
// platform closes.
debugserver_launch_info . SetLaunchInSeparateProcessGroup ( false ) ;
2014-11-25 16:00:58 -05:00
debugserver_launch_info . SetMonitorProcessCallback ( ReapDebugserverProcess , this , false ) ;
2015-02-08 20:44:09 -05:00
std : : string platform_scheme ;
std : : string platform_ip ;
int platform_port ;
std : : string platform_path ;
bool ok = UriParser : : Parse ( GetConnection ( ) - > GetURI ( ) . c_str ( ) , platform_scheme , platform_ip , platform_port , platform_path ) ;
assert ( ok ) ;
Error error = StartDebugserverProcess (
platform_ip . c_str ( ) ,
2014-11-25 16:00:58 -05:00
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 ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() debugserver launched successfully as pid % " PRIu64 , __FUNCTION__ , debugserver_pid ) ;
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 ;
}
else
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() debugserver launch failed: %s " , __FUNCTION__ , error . AsCString ( ) ) ;
}
}
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 killing 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: " ) ) ;
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: " ) ) ;
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: " ) ) ;
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 ( ) ) ;
}
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 ) ;
}
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 = FileSystem : : 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 = FileSystem : : 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 = FileSystem : : 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 = FileSystem : : 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 = FileSystem : : 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 = FileSystem : : 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 ( ) = = ' , ' )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// 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 ( ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
response . PutCString ( " F, " ) ;
response . PutHex32 ( UINT32_MAX ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
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 ( ) ) ;
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
return SendErrorResponse ( 24 ) ;
}
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 ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
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 ) ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
m_continue_tid = tid ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServer : : Handle_stop_reason ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// Handle the $? gdbremote command.
if ( ! IsGdbServer ( ) )
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_stop_reason() unimplemented " ) ;
// 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 )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 :
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
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 ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
return SendErrorResponse ( 0 ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_Stat ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented " ) ;
}
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServer : : Handle_vFile_MD5 ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " vFile:MD5: " ) ) ;
std : : string path ;
packet . GetHexByteString ( path ) ;
if ( ! path . empty ( ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
uint64_t a , b ;
StreamGDBRemote response ;
if ( FileSystem : : CalculateMD5 ( FileSpec ( path . c_str ( ) , false ) , a , b ) = = false )
{
response . PutCString ( " F, " ) ;
response . PutCString ( " x " ) ;
}
2013-08-23 13:46:38 -04:00
else
{
2014-11-25 16:00:58 -05:00
response . PutCString ( " F, " ) ;
response . PutHex64 ( a ) ;
response . PutHex64 ( b ) ;
}
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
return SendErrorResponse ( 25 ) ;
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServer : : Handle_qRegisterInfo ( StringExtractorGDBRemote & packet )
{
// 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.
2015-02-08 20:44:09 -05:00
if ( reg_index > = reg_context_sp - > GetUserRegisterCount ( ) )
2014-11-25 16:00:58 -05:00
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 )
{
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 )
{
if ( i > 0 )
response . PutChar ( ' , ' ) ;
response . Printf ( " % " PRIx32 , * reg_num ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
response . PutChar ( ' ; ' ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
if ( reg_info - > invalidate_regs & & reg_info - > invalidate_regs [ 0 ] )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
if ( i > 0 )
response . PutChar ( ' , ' ) ;
response . Printf ( " % " PRIx32 , * reg_num ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
response . PutChar ( ' ; ' ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : Handle_qfThreadInfo ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// Ensure we're llgs.
if ( ! IsGdbServer ( ) )
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// Fail if we don't have a current process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() no process (%s), returning OK " , __FUNCTION__ , m_debugged_process_sp ? " invalid process id " : " null m_debugged_process_sp " ) ;
return SendOKResponse ( ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
StreamGDBRemote response ;
response . PutChar ( ' m ' ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() starting thread iteration " , __FUNCTION__ ) ;
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 ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() iterated thread % " PRIu32 " (%s, tid=0x% " PRIx64 " ) " , __FUNCTION__ , thread_index , thread_sp ? " is not null " : " null " , thread_sp ? thread_sp - > GetID ( ) : LLDB_INVALID_THREAD_ID ) ;
if ( thread_index > 0 )
response . PutChar ( ' , ' ) ;
response . Printf ( " % " PRIx64 , thread_sp - > GetID ( ) ) ;
}
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() finished thread iteration " , __FUNCTION__ ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServer : : Handle_qsThreadInfo ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
// 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 ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServer : : Handle_p ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
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 ) ;
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// 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 ) ;
}
2014-02-18 11:23:10 -05:00
2014-11-25 16:00:58 -05:00
// Return the end of registers response if we've iterated one past the end of the register set.
2015-02-08 20:44:09 -05:00
if ( reg_index > = reg_context_sp - > GetUserRegisterCount ( ) )
2014-11-25 16:00:58 -05:00
{
if ( log )
2015-02-08 20:44:09 -05:00
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, requested register % " PRIu32 " beyond register count % " PRIu32 , __FUNCTION__ , reg_index , reg_context_sp - > GetUserRegisterCount ( ) ) ;
2014-11-25 16:00:58 -05:00
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 ( ) ) ;
2014-02-18 11:23:10 -05:00
}
GDBRemoteCommunication : : PacketResult
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : Handle_P ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
// Ensure we're llgs.
if ( ! IsGdbServer ( ) )
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_P() unimplemented " ) ;
// 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 ( ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, could not parse register number from request \" %s \" " , __FUNCTION__ , packet . GetStringRef ( ) . c_str ( ) ) ;
return SendErrorResponse ( 0x29 ) ;
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// Note debugserver would send an E30 here.
if ( ( packet . GetBytesLeft ( ) < 1 ) | | ( packet . GetChar ( ) ! = ' = ' ) )
return SendIllFormedResponse ( packet , " P packet missing '=' char after register number " ) ;
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// 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 ) ;
}
2013-12-03 13:51:59 -05:00
2014-11-25 16:00:58 -05:00
// Parse out the value.
2015-02-08 20:44:09 -05:00
uint8_t reg_bytes [ 32 ] ; // big enough to support up to 256 bit ymmN register
size_t reg_size = packet . GetHexBytesAvail ( reg_bytes , sizeof ( reg_bytes ) ) ;
2013-12-03 13:51:59 -05:00
2014-11-25 16:00:58 -05:00
// 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 ) ;
}
2013-12-03 13:51:59 -05:00
2014-11-25 16:00:58 -05:00
// 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 ) ;
}
2013-12-03 13:51:59 -05:00
2015-02-08 20:44:09 -05:00
const RegisterInfo * reg_info = reg_context_sp - > GetRegisterInfoAtIndex ( reg_index ) ;
2014-11-25 16:00:58 -05:00
if ( ! reg_info )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, requested register % " PRIu32 " returned NULL " , __FUNCTION__ , reg_index ) ;
return SendErrorResponse ( 0x48 ) ;
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// Return the end of registers response if we've iterated one past the end of the register set.
2015-02-08 20:44:09 -05:00
if ( reg_index > = reg_context_sp - > GetUserRegisterCount ( ) )
2014-11-25 16:00:58 -05:00
{
if ( log )
2015-02-08 20:44:09 -05:00
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, requested register % " PRIu32 " beyond register count % " PRIu32 , __FUNCTION__ , reg_index , reg_context_sp - > GetUserRegisterCount ( ) ) ;
2014-11-25 16:00:58 -05:00
return SendErrorResponse ( 0x47 ) ;
}
2013-11-06 11:48:53 -05:00
2015-02-08 20:44:09 -05:00
if ( reg_size ! = reg_info - > byte_size )
{
return SendIllFormedResponse ( packet , " P packet register size is incorrect " ) ;
}
2014-11-25 16:00:58 -05:00
// Build the reginfos response.
StreamGDBRemote response ;
2015-02-08 20:44:09 -05:00
RegisterValue reg_value ( reg_bytes , reg_size , process_arch . GetByteOrder ( ) ) ;
Error error = reg_context_sp - > WriteRegister ( reg_info , reg_value ) ;
2014-11-25 16:00:58 -05:00
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 ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
return SendOKResponse ( ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_H ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
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 ) )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
2014-02-18 11:23:10 -05:00
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// Parse out which variant of $H is requested.
packet . SetFilePos ( strlen ( " H " ) ) ;
if ( packet . GetBytesLeft ( ) < 1 )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, H command missing {g,c} variant " , __FUNCTION__ ) ;
return SendIllFormedResponse ( packet , " H command missing {g,c} variant " ) ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
const char h_variant = packet . GetChar ( ) ;
switch ( h_variant )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
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 " ) ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
// 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 ( ) ) ;
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread).
if ( tid ! = LLDB_INVALID_THREAD_ID & & tid ! = 0 )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
NativeThreadProtocolSP thread_sp ( m_debugged_process_sp - > GetThreadByID ( tid ) ) ;
if ( ! thread_sp )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, tid % " PRIu64 " not found " , __FUNCTION__ , tid ) ;
return SendErrorResponse ( 0x15 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
// Now switch the given thread type.
switch ( h_variant )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
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 " ) ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
return SendOKResponse ( ) ;
2014-02-18 11:23:10 -05:00
}
2015-02-08 20:44:09 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_I ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// Ensure we're llgs.
if ( ! IsGdbServer ( ) )
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_I() unimplemented " ) ;
// Fail if we don't have a current process.
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 ) ;
}
packet . SetFilePos ( : : strlen ( " I " ) ) ;
char tmp [ 4096 ] ;
for ( ; ; )
{
size_t read = packet . GetHexBytesAvail ( tmp , sizeof ( tmp ) ) ;
if ( read = = 0 )
{
break ;
}
// write directly to stdin *this might block if stdin buffer is full*
// TODO: enqueue this block in circular buffer and send window size to remote host
ConnectionStatus status ;
Error error ;
m_stdio_communication . Write ( tmp , read , status , & error ) ;
if ( error . Fail ( ) )
{
return SendErrorResponse ( 0x15 ) ;
}
}
return SendOKResponse ( ) ;
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_interrupt ( StringExtractorGDBRemote & packet )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
2014-02-18 11:23:10 -05:00
2014-11-25 16:00:58 -05:00
// Ensure we're llgs.
if ( ! IsGdbServer ( ) )
{
// Only supported on llgs
return SendUnimplementedResponse ( " " ) ;
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// Fail if we don't have a current process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
2015-02-06 16:38:51 -05:00
// Interrupt the process.
Error error = m_debugged_process_sp - > Interrupt ( ) ;
2014-11-25 16:00:58 -05:00
if ( error . Fail ( ) )
{
if ( log )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
log - > Printf ( " GDBRemoteCommunicationServer::%s failed for process % " PRIu64 " : %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
return SendErrorResponse ( GDBRemoteServerError : : eErrorResume ) ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s stopped process % " PRIu64 , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
// No response required from stop all.
return PacketResult : : Success ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_m ( StringExtractorGDBRemote & packet )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// Ensure we're llgs.
if ( ! IsGdbServer ( ) )
{
// Only supported on llgs
return SendUnimplementedResponse ( " " ) ;
}
2014-02-18 11:23:10 -05:00
2014-11-25 16:00:58 -05:00
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
// 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 )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s nothing to read: zero-length packet " , __FUNCTION__ ) ;
return PacketResult : : Success ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
2014-11-25 16:00:58 -05:00
// Allocate the response buffer.
std : : string buf ( byte_count , ' \0 ' ) ;
if ( buf . empty ( ) )
return SendErrorResponse ( 0x78 ) ;
// 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 ( ) )
{
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 ) ;
}
if ( bytes_read = = 0 )
{
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 ) ;
}
StreamGDBRemote response ;
for ( lldb : : addr_t i = 0 ; i < bytes_read ; + + i )
response . PutHex8 ( buf [ i ] ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : Handle_QSetDetachOnError ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
packet . SetFilePos ( : : strlen ( " QSetDetachOnError: " ) ) ;
if ( packet . GetU32 ( 0 ) )
m_process_launch_info . GetFlags ( ) . Set ( eLaunchFlagDetachOnError ) ;
else
m_process_launch_info . GetFlags ( ) . Clear ( eLaunchFlagDetachOnError ) ;
return SendOKResponse ( ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_M ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// Ensure we're llgs.
if ( ! IsGdbServer ( ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// Only supported on llgs
return SendUnimplementedResponse ( " " ) ;
2013-08-23 13:46:38 -04:00
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
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 ) ;
2013-11-06 11:48:53 -05:00
}
2013-08-23 13:46:38 -04:00
return SendOKResponse ( ) ;
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_qMemoryRegionInfoSupported ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
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 ) )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
// 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 ( ) )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
// We don't support memory region info collection for this NativeProcessProtocol.
return SendUnimplementedResponse ( " " ) ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
return SendOKResponse ( ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_qMemoryRegionInfo ( StringExtractorGDBRemote & packet )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2013-12-03 13:51:59 -05:00
2014-11-25 16:00:58 -05:00
// 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 ) )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
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 ( ' ; ' ) ;
2013-12-03 13:51:59 -05:00
}
else
{
2014-11-25 16:00:58 -05:00
// 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 ( ) )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
// 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 ( ' ; ' ) ;
2013-12-03 13:51:59 -05:00
}
}
2014-11-25 16:00:58 -05:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_Z ( StringExtractorGDBRemote & packet )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// 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 ) )
2013-08-23 13:46:38 -04:00
{
2015-02-08 20:44:09 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
2013-08-23 13:46:38 -04:00
}
2015-02-08 20:44:09 -05:00
// Parse out software or hardware breakpoint or watchpoint requested.
2014-11-25 16:00:58 -05:00
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 ;
2015-02-08 20:44:09 -05:00
const GDBStoppointType stoppoint_type =
GDBStoppointType ( packet . GetS32 ( eStoppointInvalid ) ) ;
switch ( stoppoint_type )
{
case eBreakpointSoftware :
want_hardware = false ; want_breakpoint = true ; break ;
case eBreakpointHardware :
want_hardware = true ; want_breakpoint = true ; break ;
case eWatchpointWrite :
want_hardware = true ; want_breakpoint = false ; break ;
case eWatchpointRead :
want_hardware = true ; want_breakpoint = false ; break ;
case eWatchpointReadWrite :
want_hardware = true ; want_breakpoint = false ; break ;
case eStoppointInvalid :
2014-11-25 16:00:58 -05:00
return SendIllFormedResponse ( packet , " Z packet had invalid software/hardware specifier " ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
2015-02-08 20:44:09 -05:00
return SendIllFormedResponse ( packet , " Malformed Z packet, expecting comma after stoppoint type " ) ;
2014-11-25 16:00:58 -05:00
2015-02-08 20:44:09 -05:00
// Parse out the stoppoint address.
2014-11-25 16:00:58 -05:00
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short Z packet, missing address " ) ;
2015-02-08 20:44:09 -05:00
const lldb : : addr_t addr = packet . GetHexMaxU64 ( false , 0 ) ;
2014-11-25 16:00:58 -05:00
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
return SendIllFormedResponse ( packet , " Malformed Z packet, expecting comma after address " ) ;
2015-02-08 20:44:09 -05:00
// Parse out the stoppoint size (i.e. size hint for opcode size).
const uint32_t size = packet . GetHexMaxU32 ( false , std : : numeric_limits < uint32_t > : : max ( ) ) ;
if ( size = = std : : numeric_limits < uint32_t > : : max ( ) )
return SendIllFormedResponse ( packet , " Malformed Z packet, failed to parse size argument " ) ;
2014-11-25 16:00:58 -05:00
if ( want_breakpoint )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
// Try to set the breakpoint.
2015-02-08 20:44:09 -05:00
const Error error = m_debugged_process_sp - > SetBreakpoint ( addr , size , want_hardware ) ;
2014-11-25 16:00:58 -05:00
if ( error . Success ( ) )
return SendOKResponse ( ) ;
2015-02-08 20:44:09 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_BREAKPOINTS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64
" failed to set breakpoint: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
return SendErrorResponse ( 0x09 ) ;
2013-08-23 13:46:38 -04:00
}
2015-02-08 20:44:09 -05:00
else
{
uint32_t watch_flags =
stoppoint_type = = eWatchpointWrite
? watch_flags = 0x1 // Write
: watch_flags = 0x3 ; // ReadWrite
2013-08-23 13:46:38 -04:00
2015-02-08 20:44:09 -05:00
// Try to set the watchpoint.
const Error error = m_debugged_process_sp - > SetWatchpoint (
addr , size , watch_flags , want_hardware ) ;
if ( error . Success ( ) )
return SendOKResponse ( ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_WATCHPOINTS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64
" failed to set watchpoint: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
return SendErrorResponse ( 0x09 ) ;
}
2013-08-23 13:46:38 -04:00
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_z ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
// 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 ) )
2013-12-03 13:51:59 -05:00
{
2015-02-08 20:44:09 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
2013-12-03 13:51:59 -05:00
}
2015-02-08 20:44:09 -05:00
// Parse out software or hardware breakpoint or watchpoint requested.
2015-02-06 16:38:51 -05:00
packet . SetFilePos ( strlen ( " z " ) ) ;
2014-11-25 16:00:58 -05:00
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short z packet, missing software/hardware specifier " ) ;
bool want_breakpoint = true ;
2015-02-08 20:44:09 -05:00
const GDBStoppointType stoppoint_type =
GDBStoppointType ( packet . GetS32 ( eStoppointInvalid ) ) ;
switch ( stoppoint_type )
2013-12-03 13:51:59 -05:00
{
2015-02-08 20:44:09 -05:00
case eBreakpointHardware : want_breakpoint = true ; break ;
case eBreakpointSoftware : want_breakpoint = true ; break ;
case eWatchpointWrite : want_breakpoint = false ; break ;
case eWatchpointRead : want_breakpoint = false ; break ;
case eWatchpointReadWrite : want_breakpoint = false ; break ;
2014-11-25 16:00:58 -05:00
default :
return SendIllFormedResponse ( packet , " z packet had invalid software/hardware specifier " ) ;
2013-12-03 13:51:59 -05:00
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
2015-02-08 20:44:09 -05:00
return SendIllFormedResponse ( packet , " Malformed z packet, expecting comma after stoppoint type " ) ;
2014-11-25 16:00:58 -05:00
2015-02-08 20:44:09 -05:00
// Parse out the stoppoint address.
2014-11-25 16:00:58 -05:00
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short z packet, missing address " ) ;
2015-02-08 20:44:09 -05:00
const lldb : : addr_t addr = packet . GetHexMaxU64 ( false , 0 ) ;
2014-11-25 16:00:58 -05:00
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
return SendIllFormedResponse ( packet , " Malformed z packet, expecting comma after address " ) ;
2015-02-08 20:44:09 -05:00
/*
// Parse out the stoppoint size (i.e. size hint for opcode size).
const uint32_t size = packet . GetHexMaxU32 ( false , std : : numeric_limits < uint32_t > : : max ( ) ) ;
if ( size = = std : : numeric_limits < uint32_t > : : max ( ) )
return SendIllFormedResponse ( packet , " Malformed z packet, failed to parse size argument " ) ;
*/
2014-11-25 16:00:58 -05:00
if ( want_breakpoint )
2013-12-03 13:51:59 -05:00
{
2015-02-06 16:38:51 -05:00
// Try to clear the breakpoint.
2015-02-08 20:44:09 -05:00
const Error error = m_debugged_process_sp - > RemoveBreakpoint ( addr ) ;
2014-11-25 16:00:58 -05:00
if ( error . Success ( ) )
return SendOKResponse ( ) ;
2015-02-08 20:44:09 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_BREAKPOINTS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64
" failed to remove breakpoint: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
return SendErrorResponse ( 0x09 ) ;
}
else
{
// Try to clear the watchpoint.
const Error error = m_debugged_process_sp - > RemoveWatchpoint ( addr ) ;
if ( error . Success ( ) )
return SendOKResponse ( ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_WATCHPOINTS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s pid % " PRIu64
" failed to remove watchpoint: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
return SendErrorResponse ( 0x09 ) ;
2013-12-03 13:51:59 -05:00
}
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_s ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
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 ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x32 ) ;
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00
2014-11-25 16:00:58 -05:00
// 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 ) ;
}
// 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+ " ) ;
2013-11-06 11:48:53 -05:00
# endif
2014-11-25 16:00:58 -05:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_QThreadSuffixSupported ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
m_thread_suffix_supported = true ;
return SendOKResponse ( ) ;
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_QListThreadsInStopReply ( StringExtractorGDBRemote & packet )
{
m_list_threads_in_stop_reply = true ;
return SendOKResponse ( ) ;
}
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
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 )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
// Make sure we have a valid process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
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 ) ;
2013-12-03 13:51:59 -05:00
}
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
// 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 ( ) )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
// 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 )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
// There will be nothing left to read after this
response . PutChar ( ' l ' ) ;
done_with_buffer = true ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
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 ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
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
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_QSaveRegisterState ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
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 )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
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 " ) ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
// 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 ( ) ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_QRestoreRegisterState ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
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 )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
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 " ) ;
2013-12-03 13:51:59 -05:00
else
2014-11-25 16:00:58 -05:00
return SendIllFormedResponse ( packet , " No thread was is set with the Hg packet " ) ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
// 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 ( ) ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_vAttach ( StringExtractorGDBRemote & packet )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// We don't support if we're not llgs.
if ( ! IsGdbServer ( ) )
return SendUnimplementedResponse ( " only supported for lldb-gdbserver " ) ;
// Consume the ';' after vAttach.
packet . SetFilePos ( strlen ( " vAttach " ) ) ;
if ( ! packet . GetBytesLeft ( ) | | packet . GetChar ( ) ! = ' ; ' )
return SendIllFormedResponse ( packet , " vAttach missing expected ';' " ) ;
// Grab the PID to which we will attach (assume hex encoding).
lldb : : pid_t pid = packet . GetU32 ( LLDB_INVALID_PROCESS_ID , 16 ) ;
if ( pid = = LLDB_INVALID_PROCESS_ID )
return SendIllFormedResponse ( packet , " vAttach failed to parse the process id " ) ;
// Attempt to attach.
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s attempting to attach to pid % " PRIu64 , __FUNCTION__ , pid ) ;
Error error = AttachToProcess ( pid ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed to attach to pid % " PRIu64 " : %s \n " , __FUNCTION__ , pid , error . AsCString ( ) ) ;
return SendErrorResponse ( 0x01 ) ;
}
// Notify we attached by sending a stop packet.
return SendStopReasonForState ( m_debugged_process_sp - > GetState ( ) , true ) ;
2015-02-06 16:38:51 -05:00
}
2014-11-25 16:00:58 -05:00
2015-02-06 16:38:51 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_D ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// We don't support if we're not llgs.
if ( ! IsGdbServer ( ) )
return SendUnimplementedResponse ( " only supported for lldb-gdbserver " ) ;
// Scope for mutex locker.
Mutex : : Locker locker ( m_spawned_pids_mutex ) ;
// Fail if we don't have a current process.
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 ) ;
}
if ( m_spawned_pids . find ( m_debugged_process_sp - > GetID ( ) ) = = m_spawned_pids . end ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed to find PID % " PRIu64 " in spawned pids list " ,
__FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
return SendErrorResponse ( 0x1 ) ;
}
lldb : : pid_t pid = LLDB_INVALID_PROCESS_ID ;
// Consume the ';' after D.
packet . SetFilePos ( 1 ) ;
if ( packet . GetBytesLeft ( ) )
{
if ( packet . GetChar ( ) ! = ' ; ' )
return SendIllFormedResponse ( packet , " D missing expected ';' " ) ;
// Grab the PID from which we will detach (assume hex encoding).
pid = packet . GetU32 ( LLDB_INVALID_PROCESS_ID , 16 ) ;
if ( pid = = LLDB_INVALID_PROCESS_ID )
return SendIllFormedResponse ( packet , " D failed to parse the process id " ) ;
}
if ( pid ! = LLDB_INVALID_PROCESS_ID & &
m_debugged_process_sp - > GetID ( ) ! = pid )
{
return SendIllFormedResponse ( packet , " Invalid pid " ) ;
}
if ( m_stdio_communication . IsConnected ( ) )
{
m_stdio_communication . StopReadThread ( ) ;
}
const Error error = m_debugged_process_sp - > Detach ( ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed to detach from pid % " PRIu64 " : %s \n " ,
__FUNCTION__ , m_debugged_process_sp - > GetID ( ) , error . AsCString ( ) ) ;
return SendErrorResponse ( 0x01 ) ;
}
m_spawned_pids . erase ( m_debugged_process_sp - > GetID ( ) ) ;
return SendOKResponse ( ) ;
}
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_qThreadStopInfo ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// We don't support if we're not llgs.
if ( ! IsGdbServer ( ) )
return SendUnimplementedResponse ( " only supported for lldb-gdbserver " ) ;
packet . SetFilePos ( strlen ( " qThreadStopInfo " ) ) ;
const lldb : : tid_t tid = packet . GetHexMaxU32 ( false , LLDB_INVALID_THREAD_ID ) ;
if ( tid = = LLDB_INVALID_THREAD_ID )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s failed, could not parse thread id from request \" %s \" " , __FUNCTION__ , packet . GetStringRef ( ) . c_str ( ) ) ;
return SendErrorResponse ( 0x15 ) ;
}
return SendStopReplyPacketForThread ( tid ) ;
2013-11-06 11:48:53 -05:00
}
2015-02-08 20:44:09 -05:00
GDBRemoteCommunicationServer : : PacketResult
GDBRemoteCommunicationServer : : Handle_qWatchpointSupportInfo ( 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 ) ;
packet . SetFilePos ( strlen ( " qWatchpointSupportInfo " ) ) ;
if ( packet . GetBytesLeft ( ) = = 0 )
return SendOKResponse ( ) ;
if ( packet . GetChar ( ) ! = ' : ' )
return SendErrorResponse ( 67 ) ;
uint32_t num = m_debugged_process_sp - > GetMaxWatchpoints ( ) ;
StreamGDBRemote response ;
response . Printf ( " num:%d; " , num ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
2014-11-25 16:00:58 -05:00
void
GDBRemoteCommunicationServer : : FlushInferiorOutput ( )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
// 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 ( ) ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
void
GDBRemoteCommunicationServer : : MaybeCloseInferiorTerminalConnection ( )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// Tell the stdio connection to shut down.
if ( m_stdio_communication . IsConnected ( ) )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
auto connection = m_stdio_communication . GetConnection ( ) ;
if ( connection )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
Error error ;
connection - > Disconnect ( & error ) ;
if ( error . Success ( ) )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s disconnect process terminal stdio - SUCCESS " , __FUNCTION__ ) ;
2013-12-03 13:51:59 -05:00
}
else
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s disconnect process terminal stdio - FAIL: %s " , __FUNCTION__ , error . AsCString ( ) ) ;
2013-12-03 13:51:59 -05:00
}
}
2013-11-06 11:48:53 -05:00
}
}
2014-11-25 16:00:58 -05:00
lldb_private : : NativeThreadProtocolSP
GDBRemoteCommunicationServer : : GetThreadFromSuffix ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
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 )
2013-11-06 11:48:53 -05:00
{
2014-11-25 16:00:58 -05:00
const lldb : : tid_t current_tid = GetCurrentThreadID ( ) ;
if ( current_tid = = LLDB_INVALID_THREAD_ID )
return thread_sp ;
else if ( current_tid = = 0 )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
// Pick a thread.
return m_debugged_process_sp - > GetThreadAtIndex ( 0 ) ;
2013-12-03 13:51:59 -05:00
}
else
2014-11-25 16:00:58 -05:00
return m_debugged_process_sp - > GetThreadByID ( current_tid ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
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 + + ;
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00
2014-11-25 16:00:58 -05:00
void
GDBRemoteCommunicationServer : : ClearProcessSpecificData ( )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | GDBR_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s() " , __FUNCTION__ ) ;
// Clear any auxv cached data.
// *BSD impls should be able to do this too.
# if defined(__linux__)
if ( log )
log - > Printf ( " GDBRemoteCommunicationServer::%s clearing auxv buffer (previously %s) " ,
__FUNCTION__ ,
m_active_auxv_buffer_sp ? " was set " : " was not set " ) ;
m_active_auxv_buffer_sp . reset ( ) ;
# endif
}