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
# 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
// Other libraries and framework includes
# include "llvm/ADT/Triple.h"
# include "lldb/Interpreter/Args.h"
# include "lldb/Core/ConnectionFileDescriptor.h"
# include "lldb/Core/Log.h"
# include "lldb/Core/State.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Host/Endian.h"
2013-11-06 11:48:53 -05:00
# include "lldb/Host/File.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Host.h"
# include "lldb/Host/TimeValue.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"
// Project includes
# include "Utility/StringExtractorGDBRemote.h"
# include "ProcessGDBRemote.h"
# include "ProcessGDBRemoteLog.h"
using namespace lldb ;
using namespace lldb_private ;
//----------------------------------------------------------------------
// GDBRemoteCommunicationServer constructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServer : : GDBRemoteCommunicationServer ( bool is_platform ) :
GDBRemoteCommunication ( " gdb-remote.server " , " gdb-remote.server.rx_packet " , is_platform ) ,
2014-02-18 11:23:10 -05:00
m_platform_sp ( Platform : : GetDefaultPlatform ( ) ) ,
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 ( ) ,
m_port_offset ( 0 )
2013-08-23 13:46:38 -04:00
{
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunicationServer : : GDBRemoteCommunicationServer ( bool is_platform ,
const lldb : : PlatformSP & platform_sp ) :
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 ( ) ,
m_port_offset ( 0 )
{
assert ( platform_sp ) ;
}
2013-08-23 13:46:38 -04:00
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServer : : ~ GDBRemoteCommunicationServer ( )
{
}
//void *
//GDBRemoteCommunicationServer::AsyncThread (void *arg)
//{
// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
//
// Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
// if (log)
// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
//
// StringExtractorGDBRemote packet;
2013-11-06 11:48:53 -05:00
//
2013-08-23 13:46:38 -04:00
// while ()
// {
// if (packet.
// }
//
// if (log)
// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
//
// process->m_async_thread = LLDB_INVALID_HOST_THREAD;
// return NULL;
//}
//
bool
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-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 ;
case StringExtractorGDBRemote : : eServerPacketType_interrupt :
error . SetErrorString ( " interrupt received " ) ;
interrupt = 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 ) ;
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 ;
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 ;
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
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 ;
}
}
else
{
if ( ! IsConnected ( ) )
{
error . SetErrorString ( " lost connection " ) ;
quit = true ;
}
else
{
error . SetErrorString ( " timeout " ) ;
}
}
return packet_result = = PacketResult : : Success ;
}
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 ( )
{
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.
lldb : : pid_t pid ;
if ( ( pid = m_process_launch_info . GetProcessID ( ) ) ! = LLDB_INVALID_PROCESS_ID )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -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-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : SendUnimplementedResponse ( const char * )
{
// TODO: Log the packet we aren't handling...
return SendPacketNoLock ( " " , 0 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
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 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : SendOKResponse ( )
{
return SendPacketNoLock ( " OK " , 2 ) ;
}
bool
GDBRemoteCommunicationServer : : HandshakeWithClient ( Error * error_ptr )
{
2014-02-18 11:23:10 -05:00
return GetAck ( ) = = PacketResult : : Success ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qHostInfo ( StringExtractorGDBRemote & packet )
{
StreamString response ;
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
// $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
ArchSpec host_arch ( Host : : GetArchitecture ( ) ) ;
const llvm : : Triple & host_triple = host_arch . GetTriple ( ) ;
response . PutCString ( " triple: " ) ;
response . PutCStringAsRawHex8 ( host_triple . getTriple ( ) . c_str ( ) ) ;
response . Printf ( " ;ptrsize:%u; " , host_arch . GetAddressByteSize ( ) ) ;
2014-02-18 11:23:10 -05:00
const char * distribution_id = host_arch . GetDistributionId ( ) . AsCString ( ) ;
if ( distribution_id )
{
response . PutCString ( " distribution_id: " ) ;
response . PutCStringAsRawHex8 ( distribution_id ) ;
response . PutCString ( " ; " ) ;
}
2013-08-23 13:46:38 -04:00
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 ) ;
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
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; " ) ;
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
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 ;
}
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
uint32_t major = UINT32_MAX ;
uint32_t minor = UINT32_MAX ;
uint32_t update = UINT32_MAX ;
if ( Host : : GetOSVersion ( major , minor , update ) )
{
if ( major ! = UINT32_MAX )
{
response . Printf ( " os_version:%u " , major ) ;
if ( minor ! = UINT32_MAX )
{
response . Printf ( " .%u " , minor ) ;
if ( update ! = UINT32_MAX )
response . Printf ( " .%u " , update ) ;
}
response . PutChar ( ' ; ' ) ;
}
}
std : : string s ;
if ( Host : : GetOSBuildString ( s ) )
{
response . PutCString ( " os_build: " ) ;
response . PutCStringAsRawHex8 ( s . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
if ( Host : : GetOSKernelDescription ( s ) )
{
response . PutCString ( " os_kernel: " ) ;
response . PutCStringAsRawHex8 ( s . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
2013-12-03 13:51:59 -05:00
# if defined(__APPLE__)
# if defined(__arm__)
// 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 ( " localhost " ) ;
response . PutChar ( ' ; ' ) ;
# else // #if defined(__arm__)
if ( Host : : GetHostname ( s ) )
{
response . PutCString ( " hostname: " ) ;
response . PutCStringAsRawHex8 ( s . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
# endif // #if defined(__arm__)
# else // #if defined(__APPLE__)
2013-08-23 13:46:38 -04:00
if ( Host : : GetHostname ( s ) )
{
response . PutCString ( " hostname: " ) ;
response . PutCStringAsRawHex8 ( s . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
2013-12-03 13:51:59 -05:00
# endif // #if defined(__APPLE__)
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-08-23 13:46:38 -04:00
}
static void
CreateProcessInfoResponse ( const ProcessInstanceInfo & proc_info , StreamString & response )
{
response . Printf ( " pid:% " PRIu64 " ;ppid:% " PRIu64 " ;uid:%i;gid:%i;euid:%i;egid:%i; " ,
proc_info . GetProcessID ( ) ,
proc_info . GetParentProcessID ( ) ,
proc_info . GetUserID ( ) ,
proc_info . GetGroupID ( ) ,
proc_info . GetEffectiveUserID ( ) ,
proc_info . GetEffectiveGroupID ( ) ) ;
response . PutCString ( " name: " ) ;
response . PutCStringAsRawHex8 ( proc_info . GetName ( ) ) ;
response . PutChar ( ' ; ' ) ;
const ArchSpec & proc_arch = proc_info . GetArchitecture ( ) ;
if ( proc_arch . IsValid ( ) )
{
const llvm : : Triple & proc_triple = proc_arch . GetTriple ( ) ;
response . PutCString ( " triple: " ) ;
response . PutCStringAsRawHex8 ( proc_triple . getTriple ( ) . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
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 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qfProcessInfo ( StringExtractorGDBRemote & packet )
{
m_proc_infos_index = 0 ;
m_proc_infos . Clear ( ) ;
ProcessInstanceInfoMatch match_info ;
packet . SetFilePos ( : : strlen ( " qfProcessInfo " ) ) ;
if ( packet . GetChar ( ) = = ' : ' )
{
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
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 ) ;
}
2013-11-06 11:48:53 -05:00
else if ( value . compare ( " regex " ) = = 0 )
2013-08-23 13:46:38 -04:00
{
match_info . SetNameMatchType ( eNameMatchRegularExpression ) ;
}
2013-11-06 11:48:53 -05:00
else
2013-08-23 13:46:38 -04:00
{
success = false ;
}
}
else if ( key . compare ( " pid " ) = = 0 )
{
match_info . GetProcessInfo ( ) . SetProcessID ( Args : : StringToUInt32 ( value . c_str ( ) , LLDB_INVALID_PROCESS_ID , 0 , & success ) ) ;
}
else if ( key . compare ( " parent_pid " ) = = 0 )
{
match_info . GetProcessInfo ( ) . SetParentProcessID ( Args : : StringToUInt32 ( value . c_str ( ) , LLDB_INVALID_PROCESS_ID , 0 , & success ) ) ;
}
else if ( key . compare ( " uid " ) = = 0 )
{
match_info . GetProcessInfo ( ) . SetUserID ( Args : : StringToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
}
else if ( key . compare ( " gid " ) = = 0 )
{
match_info . GetProcessInfo ( ) . SetGroupID ( Args : : StringToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
}
else if ( key . compare ( " euid " ) = = 0 )
{
match_info . GetProcessInfo ( ) . SetEffectiveUserID ( Args : : StringToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
}
else if ( key . compare ( " egid " ) = = 0 )
{
match_info . GetProcessInfo ( ) . SetEffectiveGroupID ( Args : : StringToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 , & success ) ) ;
}
else if ( key . compare ( " all_users " ) = = 0 )
{
match_info . SetMatchAllUsers ( Args : : StringToBoolean ( value . c_str ( ) , false , & success ) ) ;
}
else if ( key . compare ( " triple " ) = = 0 )
{
match_info . GetProcessInfo ( ) . GetArchitecture ( ) . SetTriple ( value . c_str ( ) , NULL ) ;
}
else
{
success = false ;
}
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
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 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
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 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qUserName ( StringExtractorGDBRemote & packet )
{
// Packet format: "qUserName:%i" where %i is the uid
packet . SetFilePos ( : : strlen ( " qUserName: " ) ) ;
uint32_t uid = packet . GetU32 ( UINT32_MAX ) ;
if ( uid ! = UINT32_MAX )
{
std : : string name ;
if ( Host : : GetUserName ( uid , name ) )
{
StreamString response ;
response . PutCStringAsRawHex8 ( name . c_str ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
}
return SendErrorResponse ( 5 ) ;
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qGroupName ( StringExtractorGDBRemote & packet )
{
// Packet format: "qGroupName:%i" where %i is the gid
packet . SetFilePos ( : : strlen ( " qGroupName: " ) ) ;
uint32_t gid = packet . GetU32 ( UINT32_MAX ) ;
if ( gid ! = UINT32_MAX )
{
std : : string name ;
if ( Host : : GetGroupName ( gid , name ) )
{
StreamString response ;
response . PutCStringAsRawHex8 ( name . c_str ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
}
return SendErrorResponse ( 6 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qSpeedTest ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " qSpeedTest: " ) ) ;
std : : string key ;
std : : string value ;
bool success = packet . GetNameColonValue ( key , value ) ;
if ( success & & key . compare ( " response_size " ) = = 0 )
{
uint32_t response_size = Args : : StringToUInt32 ( value . c_str ( ) , 0 , 0 , & success ) ;
if ( success )
{
if ( response_size = = 0 )
return SendOKResponse ( ) ;
StreamString response ;
uint32_t bytes_left = response_size ;
response . PutCString ( " data: " ) ;
while ( bytes_left > 0 )
{
if ( bytes_left > = 26 )
{
response . PutCString ( " ABCDEFGHIJKLMNOPQRSTUVWXYZ " ) ;
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 void *
AcceptPortFromInferior ( void * arg )
{
const char * connect_url = ( const char * ) arg ;
ConnectionFileDescriptor file_conn ;
Error error ;
if ( file_conn . Connect ( connect_url , & error ) = = eConnectionStatusSuccess )
{
char pid_str [ 256 ] ;
: : memset ( pid_str , 0 , sizeof ( pid_str ) ) ;
ConnectionStatus status ;
const size_t pid_str_len = file_conn . Read ( pid_str , sizeof ( pid_str ) , 0 , status , NULL ) ;
if ( pid_str_len > 0 )
{
int pid = atoi ( pid_str ) ;
return ( void * ) ( intptr_t ) pid ;
}
}
return NULL ;
}
//
//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;
2013-11-06 11:48:53 -05:00
// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
// (uint64_t) 0,
// &bsd_info,
2013-08-23 13:46:38 -04:00
// PROC_PIDTBSDINFO_SIZE);
2013-11-06 11:48:53 -05:00
//
2013-08-23 13:46:38 -04:00
// switch (error)
// {
// case EINVAL:
// case ENOTSUP:
// case ESRCH:
// case EPERM:
// return false;
2013-11-06 11:48:53 -05:00
//
2013-08-23 13:46:38 -04:00
// default:
// break;
2013-11-06 11:48:53 -05:00
//
2013-08-23 13:46:38 -04:00
// case 0:
// if (bsd_info.pbi_status == SSTOP)
// return true;
// }
// ::usleep (time_delta_usecs);
// }
// return false;
//}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_A ( StringExtractorGDBRemote & packet )
{
2013-11-06 11:48:53 -05:00
// 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
2013-08-23 13:46:38 -04:00
// separated hex encoded argument value list, but we will stay true to the
// documented version of the 'A' packet here...
packet . SetFilePos ( 1 ) ; // Skip the 'A'
bool success = true ;
while ( success & & packet . GetBytesLeft ( ) > 0 )
{
// Decode the decimal argument string length. This length is the
// number of hex nibbles in the argument string value.
const uint32_t arg_len = packet . GetU32 ( UINT32_MAX ) ;
if ( arg_len = = UINT32_MAX )
success = false ;
else
{
// Make sure the argument hex string length is followed by a comma
if ( packet . GetChar ( ) ! = ' , ' )
success = false ;
else
{
// Decode the argument index. We ignore this really becuase
// who would really send down the arguments in a random order???
const uint32_t arg_idx = packet . GetU32 ( UINT32_MAX ) ;
if ( arg_idx = = UINT32_MAX )
success = false ;
else
{
// Make sure the argument index is followed by a comma
if ( packet . GetChar ( ) ! = ' , ' )
success = false ;
else
{
// Decode the argument string value from hex bytes
// back into a UTF8 string and make sure the length
// matches the one supplied in the packet
std : : string arg ;
if ( packet . GetHexByteString ( arg ) ! = ( arg_len / 2 ) )
success = false ;
else
{
// If there are any bytes lft
if ( packet . GetBytesLeft ( ) )
{
if ( packet . GetChar ( ) ! = ' , ' )
success = false ;
}
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
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 ( success )
{
2014-02-18 11:23:10 -05:00
// FIXME: remove linux restriction once eLaunchFlagDebug is supported
# if !defined (__linux__)
2013-08-23 13:46:38 -04:00
m_process_launch_info . GetFlags ( ) . Set ( eLaunchFlagDebug ) ;
2014-02-18 11:23:10 -05:00
# endif
m_process_launch_error = LaunchProcess ( ) ;
2013-08-23 13:46:38 -04:00
if ( m_process_launch_info . GetProcessID ( ) ! = LLDB_INVALID_PROCESS_ID )
{
return SendOKResponse ( ) ;
}
}
return SendErrorResponse ( 8 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qC ( StringExtractorGDBRemote & packet )
{
lldb : : pid_t pid = m_process_launch_info . GetProcessID ( ) ;
StreamString response ;
response . Printf ( " QC% " PRIx64 , pid ) ;
if ( m_is_platform )
{
2013-11-06 11:48:53 -05:00
// 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
2013-08-23 13:46:38 -04:00
// launching another process. In order to launch a process a bunch or
// packets need to be sent: environment packets, working directory,
2013-11-06 11:48:53 -05:00
// disable ASLR, and many more settings. When we launch a process we
2013-08-23 13:46:38 -04:00
// 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 ( ) ) ;
}
2013-11-06 11:48:53 -05:00
bool
GDBRemoteCommunicationServer : : DebugserverProcessReaped ( lldb : : pid_t pid )
{
Mutex : : Locker locker ( m_spawned_pids_mutex ) ;
2013-12-03 13:51:59 -05:00
FreePortForProcess ( pid ) ;
2013-11-06 11:48:53 -05:00
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 ;
}
2013-08-23 13:46:38 -04:00
bool
2014-02-18 11:23:10 -05:00
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
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qLaunchGDBServer ( StringExtractorGDBRemote & packet )
{
2013-11-06 11:48:53 -05:00
# ifdef _WIN32
2014-02-18 11:23:10 -05:00
return SendErrorResponse ( 9 ) ;
2013-11-06 11:48:53 -05:00
# else
2013-08-23 13:46:38 -04:00
// Spawn a local debugserver as a platform so we can then attach or launch
// a process...
if ( m_is_platform )
{
// Sleep and wait a bit for debugserver to start to listen...
ConnectionFileDescriptor file_conn ;
Error error ;
2013-11-06 11:48:53 -05:00
std : : string hostname ;
// TODO: /tmp/ should not be hardcoded. User might want to override /tmp
// with the TMPDIR environnement variable
2013-12-03 13:51:59 -05:00
packet . SetFilePos ( : : strlen ( " qLaunchGDBServer; " ) ) ;
std : : string name ;
std : : string value ;
uint16_t port = UINT16_MAX ;
while ( packet . GetNameColonValue ( name , value ) )
2013-08-23 13:46:38 -04:00
{
2013-12-03 13:51:59 -05:00
if ( name . compare ( " host " ) = = 0 )
hostname . swap ( value ) ;
else if ( name . compare ( " port " ) = = 0 )
port = Args : : StringToUInt32 ( value . c_str ( ) , 0 , 0 ) ;
2013-08-23 13:46:38 -04:00
}
2013-12-03 13:51:59 -05:00
if ( port = = UINT16_MAX )
port = GetNextAvailablePort ( ) ;
2013-11-06 11:48:53 -05:00
2013-12-03 13:51:59 -05:00
// Spawn a new thread to accept the port that gets bound after
// binding to port 0 (zero).
2013-11-06 11:48:53 -05:00
2013-12-03 13:51:59 -05:00
if ( error . Success ( ) )
{
// Spawn a debugserver and try to get the port it listens to.
ProcessLaunchInfo debugserver_launch_info ;
if ( hostname . empty ( ) )
hostname = " localhost " ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PLATFORM ) ) ;
if ( log )
2014-02-18 11:23:10 -05:00
log - > Printf ( " Launching debugserver with: %s:%u... \n " , hostname . c_str ( ) , port ) ;
2013-12-03 13:51:59 -05:00
debugserver_launch_info . SetMonitorProcessCallback ( ReapDebugserverProcess , this , false ) ;
2014-02-18 11:23:10 -05:00
error = StartDebugserverProcess ( hostname . empty ( ) ? NULL : hostname . c_str ( ) ,
port ,
debugserver_launch_info ,
port ) ;
2013-12-03 13:51:59 -05:00
lldb : : pid_t debugserver_pid = debugserver_launch_info . GetProcessID ( ) ;
if ( debugserver_pid ! = LLDB_INVALID_PROCESS_ID )
2013-08-23 13:46:38 -04:00
{
2013-12-03 13:51:59 -05:00
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 ) ;
}
2013-11-06 11:48:53 -05:00
2013-12-03 13:51:59 -05:00
if ( error . Success ( ) )
{
2014-02-18 11:23:10 -05:00
char response [ 256 ] ;
const int response_len = : : snprintf ( response , sizeof ( response ) , " pid:% " PRIu64 " ;port:%u; " , debugserver_pid , port + m_port_offset ) ;
assert ( response_len < sizeof ( response ) ) ;
PacketResult packet_result = SendPacketNoLock ( response , response_len ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
if ( packet_result ! = PacketResult : : Success )
2013-12-03 13:51:59 -05:00
{
if ( debugserver_pid ! = LLDB_INVALID_PROCESS_ID )
: : kill ( debugserver_pid , SIGINT ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
return packet_result ;
2013-08-23 13:46:38 -04:00
}
}
}
2013-11-06 11:48:53 -05:00
return SendErrorResponse ( 9 ) ;
# endif
}
bool
2014-02-18 11:23:10 -05:00
GDBRemoteCommunicationServer : : KillSpawnedProcess ( lldb : : pid_t pid )
2013-11-06 11:48:53 -05:00
{
2014-02-18 11:23:10 -05:00
// make sure we know about this process
2013-11-06 11:48:53 -05:00
{
2014-02-18 11:23:10 -05:00
Mutex : : Locker locker ( m_spawned_pids_mutex ) ;
if ( m_spawned_pids . find ( pid ) = = m_spawned_pids . end ( ) )
return false ;
}
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
// first try a SIGTERM (standard kill)
Host : : Kill ( pid , SIGTERM ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
// check if that worked
for ( size_t i = 0 ; i < 10 ; + + i )
{
2013-11-06 11:48:53 -05:00
{
Mutex : : Locker locker ( m_spawned_pids_mutex ) ;
if ( m_spawned_pids . find ( pid ) = = m_spawned_pids . end ( ) )
2014-02-18 11:23:10 -05:00
{
// it is now killed
return true ;
}
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
usleep ( 10000 ) ;
}
// check one more time after the final usleep
{
Mutex : : Locker locker ( m_spawned_pids_mutex ) ;
if ( m_spawned_pids . find ( pid ) = = m_spawned_pids . end ( ) )
return true ;
}
// the launched process still lives. Now try killling it again,
// this time with an unblockable signal.
Host : : Kill ( pid , SIGKILL ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
for ( size_t i = 0 ; i < 10 ; + + i )
{
2013-11-06 11:48:53 -05:00
{
2014-02-18 11:23:10 -05:00
Mutex : : Locker locker ( m_spawned_pids_mutex ) ;
if ( m_spawned_pids . find ( pid ) = = m_spawned_pids . end ( ) )
2013-11-06 11:48:53 -05:00
{
2014-02-18 11:23:10 -05:00
// it is now killed
return true ;
2013-11-06 11:48:53 -05:00
}
}
2014-02-18 11:23:10 -05:00
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 ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
// 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 ( ) )
2013-11-06 11:48:53 -05:00
{
2014-02-18 11:23:10 -05:00
// not a pid we know about
return SendErrorResponse ( 10 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
}
// 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 ( ) ) ;
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
// 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 ) )
2013-11-06 11:48:53 -05:00
{
2014-02-18 11:23:10 -05:00
fprintf ( stderr , " %s: failed to kill spawned pid % " PRIu64 " , ignoring. \n " , __FUNCTION__ , spawned_pid ) ;
2013-11-06 11:48:53 -05:00
}
}
2014-02-18 11:23:10 -05:00
// TODO figure out how to shut down gracefully at this point
return SendOKResponse ( ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_qLaunchSuccess ( StringExtractorGDBRemote & packet )
{
if ( m_process_launch_error . Success ( ) )
return SendOKResponse ( ) ;
2013-11-06 11:48:53 -05:00
StreamString response ;
2013-08-23 13:46:38 -04:00
response . PutChar ( ' E ' ) ;
response . PutCString ( m_process_launch_error . AsCString ( " <unknown error> " ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
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 ( ) ;
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 12 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
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 ( ) ;
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 13 ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
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 ( ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_QSetWorkingDir ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " QSetWorkingDir: " ) ) ;
std : : string path ;
packet . GetHexByteString ( path ) ;
2013-12-03 13:51:59 -05:00
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 ) ;
}
2013-08-23 13:46:38 -04:00
return SendOKResponse ( ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-12-03 13:51:59 -05:00
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 ) ) ;
2014-02-18 11:23:10 -05:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-12-03 13:51:59 -05:00
}
}
else
{
const char * working_dir = m_process_launch_info . GetWorkingDirectory ( ) ;
if ( working_dir & & working_dir [ 0 ] )
{
response . PutBytesAsRawHex8 ( working_dir , strlen ( working_dir ) ) ;
2014-02-18 11:23:10 -05:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-12-03 13:51:59 -05:00
}
else
{
return SendErrorResponse ( 14 ) ;
}
}
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_QSetSTDIN ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " QSetSTDIN: " ) ) ;
ProcessLaunchInfo : : FileAction file_action ;
std : : string path ;
packet . GetHexByteString ( path ) ;
const bool read = false ;
const bool write = true ;
if ( file_action . Open ( STDIN_FILENO , path . c_str ( ) , read , write ) )
{
m_process_launch_info . AppendFileAction ( file_action ) ;
return SendOKResponse ( ) ;
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 15 ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_QSetSTDOUT ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " QSetSTDOUT: " ) ) ;
ProcessLaunchInfo : : FileAction file_action ;
std : : string path ;
packet . GetHexByteString ( path ) ;
const bool read = true ;
const bool write = false ;
if ( file_action . Open ( STDOUT_FILENO , path . c_str ( ) , read , write ) )
{
m_process_launch_info . AppendFileAction ( file_action ) ;
return SendOKResponse ( ) ;
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 16 ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_QSetSTDERR ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " QSetSTDERR: " ) ) ;
ProcessLaunchInfo : : FileAction file_action ;
std : : string path ;
packet . GetHexByteString ( path ) ;
const bool read = true ;
const bool write = false ;
if ( file_action . Open ( STDERR_FILENO , path . c_str ( ) , read , write ) )
{
m_process_launch_info . AppendFileAction ( file_action ) ;
return SendOKResponse ( ) ;
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 17 ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-08-23 13:46:38 -04:00
GDBRemoteCommunicationServer : : Handle_QStartNoAckMode ( StringExtractorGDBRemote & packet )
{
// Send response first before changing m_send_acks to we ack this packet
2014-02-18 11:23:10 -05:00
PacketResult packet_result = SendOKResponse ( ) ;
2013-08-23 13:46:38 -04:00
m_send_acks = false ;
2014-02-18 11:23:10 -05:00
return packet_result ;
2013-08-23 13:46:38 -04:00
}
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-12-03 13:51:59 -05:00
GDBRemoteCommunicationServer : : Handle_qPlatform_mkdir ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2013-12-03 13:51:59 -05:00
packet . SetFilePos ( : : strlen ( " qPlatform_mkdir: " ) ) ;
2013-11-06 11:48:53 -05:00
mode_t mode = packet . GetHexMaxU32 ( false , UINT32_MAX ) ;
2013-12-03 13:51:59 -05:00
if ( packet . GetChar ( ) = = ' , ' )
{
std : : string path ;
packet . GetHexByteString ( path ) ;
Error error = Host : : MakeDirectory ( path . c_str ( ) , mode ) ;
if ( error . Success ( ) )
return SendPacketNoLock ( " OK " , 2 ) ;
else
return SendErrorResponse ( error . GetError ( ) ) ;
}
return SendErrorResponse ( 20 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-12-03 13:51:59 -05:00
GDBRemoteCommunicationServer : : Handle_qPlatform_chmod ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " qPlatform_chmod: " ) ) ;
mode_t mode = packet . GetHexMaxU32 ( false , UINT32_MAX ) ;
if ( packet . GetChar ( ) = = ' , ' )
{
std : : string path ;
packet . GetHexByteString ( path ) ;
Error error = Host : : SetFilePermissions ( path . c_str ( ) , mode ) ;
if ( error . Success ( ) )
return SendPacketNoLock ( " OK " , 2 ) ;
else
return SendErrorResponse ( error . GetError ( ) ) ;
}
return SendErrorResponse ( 19 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_Open ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " vFile:open: " ) ) ;
std : : string path ;
packet . GetHexByteStringTerminatedBy ( path , ' , ' ) ;
2013-12-03 13:51:59 -05:00
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 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
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 ) ;
2013-12-03 13:51:59 -05:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_pRead ( StringExtractorGDBRemote & packet )
{
# ifdef _WIN32
// Not implemented on Windows
2013-12-03 13:51:59 -05:00
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented " ) ;
2013-11-06 11:48:53 -05:00
# else
StreamGDBRemote response ;
packet . SetFilePos ( : : strlen ( " vFile:pread: " ) ) ;
int fd = packet . GetS32 ( - 1 ) ;
2013-12-03 13:51:59 -05:00
if ( packet . GetChar ( ) = = ' , ' )
2013-11-06 11:48:53 -05:00
{
2013-12-03 13:51:59 -05:00
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 ( ) ) ;
}
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 21 ) ;
2013-11-06 11:48:53 -05:00
# endif
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_pWrite ( StringExtractorGDBRemote & packet )
{
# ifdef _WIN32
2013-12-03 13:51:59 -05:00
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented " ) ;
2013-11-06 11:48:53 -05:00
# else
packet . SetFilePos ( : : strlen ( " vFile:pwrite: " ) ) ;
StreamGDBRemote response ;
response . PutChar ( ' F ' ) ;
int fd = packet . GetU32 ( UINT32_MAX ) ;
2013-12-03 13:51:59 -05:00
if ( packet . GetChar ( ) = = ' , ' )
2013-11-06 11:48:53 -05:00
{
2013-12-03 13:51:59 -05:00
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 ( ) ) ;
}
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 27 ) ;
2013-11-06 11:48:53 -05:00
# endif
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_Size ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " vFile:size: " ) ) ;
std : : string path ;
packet . GetHexByteString ( path ) ;
2013-12-03 13:51:59 -05:00
if ( ! path . empty ( ) )
2013-11-06 11:48:53 -05:00
{
2013-12-03 13:51:59 -05:00
lldb : : user_id_t retcode = Host : : GetFileSize ( FileSpec ( path . c_str ( ) , false ) ) ;
StreamString response ;
response . PutChar ( ' F ' ) ;
response . PutHex64 ( retcode ) ;
if ( retcode = = UINT64_MAX )
{
response . PutChar ( ' , ' ) ;
response . PutHex64 ( retcode ) ; // TODO: replace with Host::GetSyswideErrorCode()
}
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 22 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_Mode ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " vFile:mode: " ) ) ;
std : : string path ;
packet . GetHexByteString ( path ) ;
2013-12-03 13:51:59 -05:00
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 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_Exists ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " vFile:exists: " ) ) ;
std : : string path ;
packet . GetHexByteString ( path ) ;
2013-12-03 13:51:59 -05:00
if ( ! path . empty ( ) )
{
bool retcode = Host : : GetFileExists ( FileSpec ( path . c_str ( ) , false ) ) ;
StreamString response ;
response . PutChar ( ' F ' ) ;
response . PutChar ( ' , ' ) ;
if ( retcode )
response . PutChar ( ' 1 ' ) ;
else
response . PutChar ( ' 0 ' ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
return SendErrorResponse ( 24 ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-12-03 13:51:59 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_symlink ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " vFile:symlink: " ) ) ;
std : : string dst , src ;
packet . GetHexByteStringTerminatedBy ( dst , ' , ' ) ;
packet . GetChar ( ) ; // Skip ',' char
packet . GetHexByteString ( src ) ;
Error error = Host : : Symlink ( src . c_str ( ) , dst . c_str ( ) ) ;
2013-11-06 11:48:53 -05:00
StreamString response ;
2013-12-03 13:51:59 -05:00
response . Printf ( " F%u,%u " , error . GetError ( ) , error . GetError ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-12-03 13:51:59 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_unlink ( StringExtractorGDBRemote & packet )
2013-11-06 11:48:53 -05:00
{
2013-12-03 13:51:59 -05:00
packet . SetFilePos ( : : strlen ( " vFile:unlink: " ) ) ;
std : : string path ;
packet . GetHexByteString ( path ) ;
Error error = Host : : Unlink ( path . c_str ( ) ) ;
StreamString response ;
response . Printf ( " F%u,%u " , error . GetError ( ) , error . GetError ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-12-03 13:51:59 -05:00
GDBRemoteCommunicationServer : : Handle_qPlatform_shell ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " qPlatform_shell: " ) ) ;
2013-11-06 11:48:53 -05:00
std : : string path ;
std : : string working_dir ;
packet . GetHexByteStringTerminatedBy ( path , ' , ' ) ;
2013-12-03 13:51:59 -05:00
if ( ! path . empty ( ) )
2013-11-06 11:48:53 -05:00
{
2013-12-03 13:51:59 -05:00
if ( packet . GetChar ( ) = = ' , ' )
{
// FIXME: add timeout to qPlatform_shell packet
// uint32_t timeout = packet.GetHexMaxU32(false, 32);
uint32_t timeout = 10 ;
if ( packet . GetChar ( ) = = ' , ' )
packet . GetHexByteString ( working_dir ) ;
int status , signo ;
std : : string output ;
Error err = Host : : RunShellCommand ( path . c_str ( ) ,
working_dir . empty ( ) ? NULL : working_dir . c_str ( ) ,
& status , & signo , & output , timeout ) ;
StreamGDBRemote response ;
if ( err . Fail ( ) )
{
response . PutCString ( " F, " ) ;
response . PutHex32 ( UINT32_MAX ) ;
}
else
{
response . PutCString ( " F, " ) ;
response . PutHex32 ( status ) ;
response . PutChar ( ' , ' ) ;
response . PutHex32 ( signo ) ;
response . PutChar ( ' , ' ) ;
response . PutEscapedBytes ( output . c_str ( ) , output . size ( ) ) ;
}
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 24 ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_Stat ( StringExtractorGDBRemote & packet )
{
2013-12-03 13:51:59 -05:00
return SendUnimplementedResponse ( " GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented " ) ;
2013-11-06 11:48:53 -05:00
}
2014-02-18 11:23:10 -05:00
GDBRemoteCommunication : : PacketResult
2013-11-06 11:48:53 -05:00
GDBRemoteCommunicationServer : : Handle_vFile_MD5 ( StringExtractorGDBRemote & packet )
{
2013-12-03 13:51:59 -05:00
packet . SetFilePos ( : : strlen ( " vFile:MD5: " ) ) ;
2013-11-06 11:48:53 -05:00
std : : string path ;
packet . GetHexByteString ( path ) ;
2013-12-03 13:51:59 -05:00
if ( ! path . empty ( ) )
2013-11-06 11:48:53 -05:00
{
2013-12-03 13:51:59 -05:00
uint64_t a , b ;
StreamGDBRemote response ;
if ( Host : : CalculateMD5 ( FileSpec ( path . c_str ( ) , false ) , a , b ) = = false )
{
response . PutCString ( " F, " ) ;
response . PutCString ( " x " ) ;
}
else
{
response . PutCString ( " F, " ) ;
response . PutHex64 ( a ) ;
response . PutHex64 ( b ) ;
}
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00
return SendErrorResponse ( 25 ) ;
2013-11-06 11:48:53 -05:00
}
2013-12-03 13:51:59 -05:00