2015-07-03 12:57:06 -04:00
//===-- GDBRemoteCommunicationServerLLGS.cpp --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include <errno.h>
# include "lldb/Host/Config.h"
# include "GDBRemoteCommunicationServerLLGS.h"
# include "lldb/Core/StreamGDBRemote.h"
// C Includes
// C++ Includes
# include <cstring>
# include <chrono>
# include <thread>
// Other libraries and framework includes
# include "llvm/ADT/Triple.h"
# include "lldb/Interpreter/Args.h"
# include "lldb/Core/DataBuffer.h"
# include "lldb/Core/Log.h"
# include "lldb/Core/RegisterValue.h"
# include "lldb/Core/State.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Host/ConnectionFileDescriptor.h"
# include "lldb/Host/Debug.h"
# include "lldb/Host/Endian.h"
# include "lldb/Host/File.h"
# include "lldb/Host/FileSystem.h"
# include "lldb/Host/Host.h"
# include "lldb/Host/HostInfo.h"
# include "lldb/Host/StringConvert.h"
# include "lldb/Host/TimeValue.h"
# include "lldb/Target/FileAction.h"
# include "lldb/Target/MemoryRegionInfo.h"
# include "lldb/Target/Platform.h"
# include "lldb/Host/common/NativeRegisterContext.h"
# include "lldb/Host/common/NativeProcessProtocol.h"
# include "lldb/Host/common/NativeThreadProtocol.h"
2015-12-30 06:55:28 -05:00
# include "lldb/Utility/JSON.h"
# include "lldb/Utility/LLDBAssert.h"
2015-07-03 12:57:06 -04:00
// Project includes
# include "Utility/StringExtractorGDBRemote.h"
# include "Utility/UriParser.h"
# include "ProcessGDBRemote.h"
# include "ProcessGDBRemoteLog.h"
using namespace lldb ;
using namespace lldb_private ;
using namespace lldb_private : : process_gdb_remote ;
using namespace llvm ;
//----------------------------------------------------------------------
// GDBRemote Errors
//----------------------------------------------------------------------
namespace
{
enum GDBRemoteServerError
{
// Set to the first unused error number in literal form below
eErrorFirst = 29 ,
eErrorNoProcess = eErrorFirst ,
eErrorResume ,
eErrorExitStatus
} ;
}
//----------------------------------------------------------------------
// GDBRemoteCommunicationServerLLGS constructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServerLLGS : : GDBRemoteCommunicationServerLLGS (
2015-09-06 10:32:30 -04:00
const lldb : : PlatformSP & platform_sp ,
MainLoop & mainloop ) :
2015-07-03 12:57:06 -04:00
GDBRemoteCommunicationServerCommon ( " gdb-remote.server " , " gdb-remote.server.rx_packet " ) ,
m_platform_sp ( platform_sp ) ,
2015-09-06 10:32:30 -04:00
m_mainloop ( mainloop ) ,
2015-07-03 12:57:06 -04:00
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_stdio_communication ( " process.stdio " ) ,
m_inferior_prev_state ( StateType : : eStateInvalid ) ,
m_active_auxv_buffer_sp ( ) ,
m_saved_registers_mutex ( ) ,
m_saved_registers_map ( ) ,
2015-09-06 10:32:30 -04:00
m_next_saved_registers_id ( 1 ) ,
m_handshake_completed ( false )
2015-07-03 12:57:06 -04:00
{
assert ( platform_sp ) ;
RegisterPacketHandlers ( ) ;
}
void
GDBRemoteCommunicationServerLLGS : : RegisterPacketHandlers ( )
{
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_C ,
& GDBRemoteCommunicationServerLLGS : : Handle_C ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_c ,
& GDBRemoteCommunicationServerLLGS : : Handle_c ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_D ,
& GDBRemoteCommunicationServerLLGS : : Handle_D ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_H ,
& GDBRemoteCommunicationServerLLGS : : Handle_H ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_I ,
& GDBRemoteCommunicationServerLLGS : : Handle_I ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_interrupt ,
& GDBRemoteCommunicationServerLLGS : : Handle_interrupt ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_m ,
2015-12-30 06:55:28 -05:00
& GDBRemoteCommunicationServerLLGS : : Handle_memory_read ) ;
2015-07-03 12:57:06 -04:00
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_M ,
& GDBRemoteCommunicationServerLLGS : : Handle_M ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_p ,
& GDBRemoteCommunicationServerLLGS : : Handle_p ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_P ,
& GDBRemoteCommunicationServerLLGS : : Handle_P ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qC ,
& GDBRemoteCommunicationServerLLGS : : Handle_qC ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qfThreadInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_qfThreadInfo ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qFileLoadAddress ,
& GDBRemoteCommunicationServerLLGS : : Handle_qFileLoadAddress ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qGetWorkingDir ,
& GDBRemoteCommunicationServerLLGS : : Handle_qGetWorkingDir ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qMemoryRegionInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_qMemoryRegionInfo ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qMemoryRegionInfoSupported ,
& GDBRemoteCommunicationServerLLGS : : Handle_qMemoryRegionInfoSupported ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qProcessInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_qProcessInfo ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qRegisterInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_qRegisterInfo ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_QRestoreRegisterState ,
& GDBRemoteCommunicationServerLLGS : : Handle_QRestoreRegisterState ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_QSaveRegisterState ,
& GDBRemoteCommunicationServerLLGS : : Handle_QSaveRegisterState ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_QSetDisableASLR ,
& GDBRemoteCommunicationServerLLGS : : Handle_QSetDisableASLR ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_QSetWorkingDir ,
& GDBRemoteCommunicationServerLLGS : : Handle_QSetWorkingDir ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qsThreadInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_qsThreadInfo ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qThreadStopInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_qThreadStopInfo ) ;
2015-12-30 06:55:28 -05:00
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_jThreadsInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_jThreadsInfo ) ;
2015-07-03 12:57:06 -04:00
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qWatchpointSupportInfo ,
& GDBRemoteCommunicationServerLLGS : : Handle_qWatchpointSupportInfo ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_qXfer_auxv_read ,
& GDBRemoteCommunicationServerLLGS : : Handle_qXfer_auxv_read ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_s ,
& GDBRemoteCommunicationServerLLGS : : Handle_s ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_stop_reason ,
& GDBRemoteCommunicationServerLLGS : : Handle_stop_reason ) ; // ?
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_vAttach ,
& GDBRemoteCommunicationServerLLGS : : Handle_vAttach ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_vCont ,
& GDBRemoteCommunicationServerLLGS : : Handle_vCont ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_vCont_actions ,
& GDBRemoteCommunicationServerLLGS : : Handle_vCont_actions ) ;
2015-12-30 06:55:28 -05:00
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_x ,
& GDBRemoteCommunicationServerLLGS : : Handle_memory_read ) ;
2015-07-03 12:57:06 -04:00
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_Z ,
& GDBRemoteCommunicationServerLLGS : : Handle_Z ) ;
RegisterMemberFunctionHandler ( StringExtractorGDBRemote : : eServerPacketType_z ,
& GDBRemoteCommunicationServerLLGS : : Handle_z ) ;
RegisterPacketHandler ( StringExtractorGDBRemote : : eServerPacketType_k ,
[ this ] ( StringExtractorGDBRemote packet ,
Error & error ,
bool & interrupt ,
bool & quit )
{
quit = true ;
return this - > Handle_k ( packet ) ;
} ) ;
}
Error
GDBRemoteCommunicationServerLLGS : : SetLaunchArguments ( const char * const args [ ] , int argc )
{
if ( ( argc < 1 ) | | ! args | | ! args [ 0 ] | | ! args [ 0 ] [ 0 ] )
return Error ( " %s: no process command line specified to launch " , __FUNCTION__ ) ;
m_process_launch_info . SetArguments ( const_cast < const char * * > ( args ) , true ) ;
return Error ( ) ;
}
Error
GDBRemoteCommunicationServerLLGS : : SetLaunchFlags ( unsigned int launch_flags )
{
m_process_launch_info . GetFlags ( ) . Set ( launch_flags ) ;
return Error ( ) ;
}
Error
GDBRemoteCommunicationServerLLGS : : LaunchProcess ( )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( ! m_process_launch_info . GetArguments ( ) . GetArgumentCount ( ) )
return Error ( " %s: no process command line specified to launch " , __FUNCTION__ ) ;
Error error ;
{
Mutex : : Locker locker ( m_debugged_process_mutex ) ;
assert ( ! m_debugged_process_sp & & " lldb-gdbserver creating debugged process but one already exists " ) ;
2015-09-06 10:32:30 -04:00
error = NativeProcessProtocol : : Launch (
2015-07-03 12:57:06 -04:00
m_process_launch_info ,
* this ,
2015-12-30 06:55:28 -05:00
m_mainloop ,
2015-07-03 12:57:06 -04:00
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 ;
}
// Handle mirroring of inferior stdout/stderr over the gdb-remote protocol
// as needed.
// llgs local-process debugging may specify PTY paths, which will make these
// file actions non-null
// process launch -i/e/o will also make these file actions non-null
// nullptr means that the traffic is expected to flow over gdb-remote protocol
if (
m_process_launch_info . GetFileActionForFD ( STDIN_FILENO ) = = nullptr | |
m_process_launch_info . GetFileActionForFD ( STDOUT_FILENO ) = = nullptr | |
m_process_launch_info . GetFileActionForFD ( STDERR_FILENO ) = = nullptr
)
{
// nullptr means it's not redirected to file or pty (in case of LLGS local)
// at least one of stdio will be transferred pty<->gdb-remote
// we need to give the pty master handle to this object to read and/or write
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d " , __FUNCTION__ , terminal_fd ) ;
error = SetSTDIOFileDescriptor ( terminal_fd ) ;
if ( error . Fail ( ) )
return error ;
}
else
{
if ( log )
log - > Printf ( " ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d " , __FUNCTION__ , terminal_fd ) ;
}
}
else
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
}
printf ( " Launched '%s' as process % " PRIu64 " ... \n " , m_process_launch_info . GetArguments ( ) . GetArgumentAtIndex ( 0 ) , m_process_launch_info . GetProcessID ( ) ) ;
return error ;
}
Error
GDBRemoteCommunicationServerLLGS : : AttachToProcess ( lldb : : pid_t pid )
{
Error error ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 , __FUNCTION__ , pid ) ;
2015-12-30 06:55:28 -05:00
// Before we try to attach, make sure we aren't already monitoring something else.
if ( m_debugged_process_sp & & m_debugged_process_sp - > GetID ( ) ! = LLDB_INVALID_PROCESS_ID )
return Error ( " cannot attach to a process % " PRIu64 " when another process with pid % " PRIu64 " is being debugged. " , pid , m_debugged_process_sp - > GetID ( ) ) ;
// Try to attach.
error = NativeProcessProtocol : : Attach ( pid , * this , m_mainloop , m_debugged_process_sp ) ;
if ( ! error . Success ( ) )
2015-07-03 12:57:06 -04:00
{
2015-12-30 06:55:28 -05:00
fprintf ( stderr , " %s: failed to attach to process % " PRIu64 " : %s " , __FUNCTION__ , pid , error . AsCString ( ) ) ;
return error ;
}
2015-07-03 12:57:06 -04:00
2015-12-30 06:55:28 -05:00
// Setup stdout/stderr mapping from inferior.
auto terminal_fd = m_debugged_process_sp - > GetTerminalFileDescriptor ( ) ;
if ( terminal_fd > = 0 )
{
if ( log )
log - > Printf ( " ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d " , __FUNCTION__ , terminal_fd ) ;
error = SetSTDIOFileDescriptor ( terminal_fd ) ;
if ( error . Fail ( ) )
2015-07-03 12:57:06 -04:00
return error ;
2015-12-30 06:55:28 -05:00
}
else
{
if ( log )
log - > Printf ( " ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d " , __FUNCTION__ , terminal_fd ) ;
}
2015-07-03 12:57:06 -04:00
2015-12-30 06:55:28 -05:00
printf ( " Attached to process % " PRIu64 " ... \n " , pid ) ;
2015-07-03 12:57:06 -04:00
2015-12-30 06:55:28 -05:00
return error ;
2015-07-03 12:57:06 -04:00
}
void
GDBRemoteCommunicationServerLLGS : : InitializeDelegate ( NativeProcessProtocol * process )
{
assert ( process & & " process cannot be NULL " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
{
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid % " PRIu64 " , current state: %s " ,
__FUNCTION__ ,
process - > GetID ( ) ,
StateAsCString ( process - > GetState ( ) ) ) ;
}
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : SendWResponse ( NativeProcessProtocol * process )
{
assert ( process & & " process cannot be NULL " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// send W notification
ExitType exit_type = ExitType : : eExitTypeInvalid ;
int return_code = 0 ;
std : : string exit_description ;
const bool got_exit_info = process - > GetExitStatus ( & exit_type , & return_code , exit_description ) ;
if ( ! got_exit_info )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " , failed to retrieve process exit status " , __FUNCTION__ , process - > GetID ( ) ) ;
StreamGDBRemote response ;
response . PutChar ( ' E ' ) ;
response . PutHex8 ( GDBRemoteServerError : : eErrorExitStatus ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
else
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " , returning exit type %d, return code %d [%s] " , __FUNCTION__ , process - > GetID ( ) , exit_type , return_code , exit_description . c_str ( ) ) ;
StreamGDBRemote response ;
char return_type_code ;
switch ( exit_type )
{
case ExitType : : eExitTypeExit :
return_type_code = ' W ' ;
break ;
case ExitType : : eExitTypeSignal :
return_type_code = ' X ' ;
break ;
case ExitType : : eExitTypeStop :
return_type_code = ' S ' ;
break ;
case ExitType : : eExitTypeInvalid :
return_type_code = ' E ' ;
break ;
}
response . PutChar ( return_type_code ) ;
// POSIX exit status limited to unsigned 8 bits.
response . PutHex8 ( return_code ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
}
static void
AppendHexValue ( StreamString & response , const uint8_t * buf , uint32_t buf_size , bool swap )
{
int64_t i ;
if ( swap )
{
for ( i = buf_size - 1 ; i > = 0 ; i - - )
response . PutHex8 ( buf [ i ] ) ;
}
else
{
for ( i = 0 ; i < buf_size ; i + + )
response . PutHex8 ( buf [ i ] ) ;
}
}
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 )
{
Error error = reg_ctx_sp - > ReadRegister ( & reg_info , reg_value ) ;
if ( error . Success ( ) )
reg_value_p = & reg_value ;
// else log.
}
if ( reg_value_p )
{
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 ) ;
}
}
}
2015-12-30 06:55:28 -05:00
static JSONObject : : SP
GetRegistersAsJSON ( NativeThreadProtocol & thread , bool abridged )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
NativeRegisterContextSP reg_ctx_sp = thread . GetRegisterContext ( ) ;
if ( ! reg_ctx_sp )
return nullptr ;
JSONObject : : SP register_object_sp = std : : make_shared < JSONObject > ( ) ;
# ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET
// 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 = reg_ctx_sp - > GetRegisterSet ( 0 ) ;
if ( ! reg_set_p )
return nullptr ;
for ( const uint32_t * reg_num_p = reg_set_p - > registers ; * reg_num_p ! = LLDB_INVALID_REGNUM ; + + reg_num_p )
{
uint32_t reg_num = * reg_num_p ;
# else
// Expedite only a couple of registers until we figure out why sending registers is
// expensive.
static const uint32_t k_expedited_registers [ ] = {
LLDB_REGNUM_GENERIC_PC , LLDB_REGNUM_GENERIC_SP , LLDB_REGNUM_GENERIC_FP , LLDB_REGNUM_GENERIC_RA , LLDB_INVALID_REGNUM
} ;
static const uint32_t k_abridged_expedited_registers [ ] = {
LLDB_REGNUM_GENERIC_PC , LLDB_INVALID_REGNUM
} ;
for ( const uint32_t * generic_reg_p = abridged ? k_abridged_expedited_registers : k_expedited_registers ;
* generic_reg_p ! = LLDB_INVALID_REGNUM ;
+ + generic_reg_p )
{
uint32_t reg_num = reg_ctx_sp - > ConvertRegisterKindToRegisterNumber ( eRegisterKindGeneric , * generic_reg_p ) ;
if ( reg_num = = LLDB_INVALID_REGNUM )
continue ; // Target does not support the given register.
# endif
const RegisterInfo * const reg_info_p = reg_ctx_sp - > GetRegisterInfoAtIndex ( reg_num ) ;
if ( reg_info_p = = nullptr )
{
if ( log )
log - > Printf ( " %s failed to get register info for register index % " PRIu32 ,
__FUNCTION__ , reg_num ) ;
continue ;
}
if ( reg_info_p - > value_regs ! = nullptr )
continue ; // Only expedite registers that are not contained in other registers.
RegisterValue reg_value ;
Error error = reg_ctx_sp - > ReadRegister ( reg_info_p , reg_value ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " %s failed to read register '%s' index % " PRIu32 " : %s " , __FUNCTION__ ,
reg_info_p - > name ? reg_info_p - > name : " <unnamed-register> " , reg_num ,
error . AsCString ( ) ) ;
continue ;
}
StreamString stream ;
WriteRegisterValueInHexFixedWidth ( stream , reg_ctx_sp , * reg_info_p , & reg_value ) ;
register_object_sp - > SetObject ( std : : to_string ( reg_num ) ,
std : : make_shared < JSONString > ( stream . GetString ( ) ) ) ;
}
return register_object_sp ;
}
static const char *
GetStopReasonString ( StopReason stop_reason )
{
switch ( stop_reason )
{
case eStopReasonTrace :
return " trace " ;
case eStopReasonBreakpoint :
return " breakpoint " ;
case eStopReasonWatchpoint :
return " watchpoint " ;
case eStopReasonSignal :
return " signal " ;
case eStopReasonException :
return " exception " ;
case eStopReasonExec :
return " exec " ;
case eStopReasonInstrumentation :
case eStopReasonInvalid :
case eStopReasonPlanComplete :
case eStopReasonThreadExiting :
case eStopReasonNone :
break ; // ignored
}
return nullptr ;
}
static JSONArray : : SP
GetJSONThreadsInfo ( NativeProcessProtocol & process , bool abridged )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
JSONArray : : SP threads_array_sp = std : : make_shared < JSONArray > ( ) ;
// Ensure we can get info on the given thread.
uint32_t thread_idx = 0 ;
for ( NativeThreadProtocolSP thread_sp ;
( thread_sp = process . GetThreadAtIndex ( thread_idx ) ) ! = nullptr ;
+ + thread_idx )
{
lldb : : tid_t tid = thread_sp - > GetID ( ) ;
// Grab the reason this thread stopped.
struct ThreadStopInfo tid_stop_info ;
std : : string description ;
if ( ! thread_sp - > GetStopReason ( tid_stop_info , description ) )
return nullptr ;
const int signum = tid_stop_info . details . signal . signo ;
if ( log )
{
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " tid % " PRIu64 " got signal signo = %d, reason = %d, exc_type = % " PRIu64 ,
__FUNCTION__ ,
process . GetID ( ) ,
tid ,
signum ,
tid_stop_info . reason ,
tid_stop_info . details . exception . type ) ;
}
JSONObject : : SP thread_obj_sp = std : : make_shared < JSONObject > ( ) ;
threads_array_sp - > AppendObject ( thread_obj_sp ) ;
if ( JSONObject : : SP registers_sp = GetRegistersAsJSON ( * thread_sp , abridged ) )
thread_obj_sp - > SetObject ( " registers " , registers_sp ) ;
thread_obj_sp - > SetObject ( " tid " , std : : make_shared < JSONNumber > ( tid ) ) ;
if ( signum ! = 0 )
thread_obj_sp - > SetObject ( " signal " , std : : make_shared < JSONNumber > ( signum ) ) ;
const std : : string thread_name = thread_sp - > GetName ( ) ;
if ( ! thread_name . empty ( ) )
thread_obj_sp - > SetObject ( " name " , std : : make_shared < JSONString > ( thread_name ) ) ;
if ( const char * stop_reason_str = GetStopReasonString ( tid_stop_info . reason ) )
thread_obj_sp - > SetObject ( " reason " , std : : make_shared < JSONString > ( stop_reason_str ) ) ;
if ( ! description . empty ( ) )
thread_obj_sp - > SetObject ( " description " , std : : make_shared < JSONString > ( description ) ) ;
if ( ( tid_stop_info . reason = = eStopReasonException ) & & tid_stop_info . details . exception . type )
{
thread_obj_sp - > SetObject ( " metype " ,
std : : make_shared < JSONNumber > ( tid_stop_info . details . exception . type ) ) ;
JSONArray : : SP medata_array_sp = std : : make_shared < JSONArray > ( ) ;
for ( uint32_t i = 0 ; i < tid_stop_info . details . exception . data_count ; + + i )
{
medata_array_sp - > AppendObject ( std : : make_shared < JSONNumber > (
tid_stop_info . details . exception . data [ i ] ) ) ;
}
thread_obj_sp - > SetObject ( " medata " , medata_array_sp ) ;
}
// TODO: Expedite interesting regions of inferior memory
}
return threads_array_sp ;
}
2015-07-03 12:57:06 -04:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : SendStopReplyPacketForThread ( lldb : : tid_t tid )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
// 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 ( " GDBRemoteCommunicationServerLLGS::%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 ;
std : : string description ;
if ( ! thread_sp - > GetStopReason ( tid_stop_info , description ) )
return SendErrorResponse ( 52 ) ;
// FIXME implement register handling for exec'd inferiors.
// if (tid_stop_info.reason == eStopReasonExec)
// {
// 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 ( " GDBRemoteCommunicationServerLLGS::%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 ) ;
// Include the tid.
response . Printf ( " thread:% " PRIx64 " ; " , tid ) ;
// Include the thread name if there is one.
const std : : string thread_name = thread_sp - > GetName ( ) ;
if ( ! thread_name . empty ( ) )
{
size_t thread_name_len = thread_name . length ( ) ;
if ( : : strcspn ( thread_name . c_str ( ) , " $#+-;: " ) = = thread_name_len )
{
response . PutCString ( " name: " ) ;
response . PutCString ( thread_name . c_str ( ) ) ;
}
else
{
// The thread name contains special chars, send as hex bytes.
response . PutCString ( " hexname: " ) ;
response . PutCStringAsRawHex8 ( thread_name . c_str ( ) ) ;
}
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 ( ' ; ' ) ;
2015-12-30 06:55:28 -05:00
// Include JSON info that describes the stop reason for any threads
// that actually have stop reasons. We use the new "jstopinfo" key
// whose values is hex ascii JSON that contains the thread IDs
// thread stop info only for threads that have stop reasons. Only send
// this if we have more than one thread otherwise this packet has all
// the info it needs.
if ( thread_index > 0 )
{
const bool threads_with_valid_stop_info_only = true ;
JSONArray : : SP threads_info_sp = GetJSONThreadsInfo ( * m_debugged_process_sp ,
threads_with_valid_stop_info_only ) ;
if ( threads_info_sp )
{
response . PutCString ( " jstopinfo: " ) ;
StreamString unescaped_response ;
threads_info_sp - > Write ( unescaped_response ) ;
response . PutCStringAsRawHex8 ( unescaped_response . GetData ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
else if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to prepare a jstopinfo field for pid % " PRIu64 ,
__FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
}
2015-07-03 12:57:06 -04:00
}
//
// 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 ( " GDBRemoteCommunicationServerLLGS::%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 )
{
const RegisterInfo * const reg_info_p = reg_ctx_sp - > GetRegisterInfoAtIndex ( * reg_num_p ) ;
if ( reg_info_p = = nullptr )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to get register info for register set '%s', register index % " PRIu32 , __FUNCTION__ , reg_set_p - > name ? reg_set_p - > name : " <unnamed-set> " , * reg_num_p ) ;
}
else if ( reg_info_p - > value_regs = = nullptr )
{
// 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 ( ) )
{
response . Printf ( " %.02x: " , * reg_num_p ) ;
WriteRegisterValueInHexFixedWidth ( response , reg_ctx_sp , * reg_info_p , & reg_value ) ;
response . PutChar ( ' ; ' ) ;
}
else
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( ) ) ;
}
}
}
}
}
2015-12-30 06:55:28 -05:00
const char * reason_str = GetStopReasonString ( tid_stop_info . reason ) ;
2015-07-03 12:57:06 -04:00
if ( reason_str ! = nullptr )
{
response . Printf ( " reason:%s; " , reason_str ) ;
}
if ( ! description . empty ( ) )
{
// Description may contains special chars, send as hex bytes.
response . PutCString ( " description: " ) ;
response . PutCStringAsRawHex8 ( description . c_str ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
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 ( ' ; ' ) ;
}
}
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
void
GDBRemoteCommunicationServerLLGS : : HandleInferiorState_Exited ( NativeProcessProtocol * process )
{
assert ( process & & " process cannot be NULL " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s called " , __FUNCTION__ ) ;
2015-12-30 06:55:28 -05:00
PacketResult result = SendStopReasonForState ( StateType : : eStateExited ) ;
2015-07-03 12:57:06 -04:00
if ( result ! = PacketResult : : Success )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID % " PRIu64 " , state: eStateExited " , __FUNCTION__ , process - > GetID ( ) ) ;
}
// Close the pipe to the inferior terminal i/o if we launched it
2015-12-30 06:55:28 -05:00
// and set one up.
2015-07-03 12:57:06 -04:00
MaybeCloseInferiorTerminalConnection ( ) ;
// We are ready to exit the debug monitor.
m_exit_now = true ;
}
void
GDBRemoteCommunicationServerLLGS : : HandleInferiorState_Stopped ( NativeProcessProtocol * process )
{
assert ( process & & " process cannot be NULL " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s called " , __FUNCTION__ ) ;
// Send the stop reason unless this is the stop after the
// launch or attach.
switch ( m_inferior_prev_state )
{
case eStateLaunching :
case eStateAttaching :
// Don't send anything per debugserver behavior.
break ;
default :
// In all other cases, send the stop reason.
2015-12-30 06:55:28 -05:00
PacketResult result = SendStopReasonForState ( StateType : : eStateStopped ) ;
2015-07-03 12:57:06 -04:00
if ( result ! = PacketResult : : Success )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID % " PRIu64 " , state: eStateExited " , __FUNCTION__ , process - > GetID ( ) ) ;
}
break ;
}
}
void
GDBRemoteCommunicationServerLLGS : : ProcessStateChanged ( NativeProcessProtocol * process , lldb : : StateType state )
{
assert ( process & & " process cannot be NULL " ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
{
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid % " PRIu64 " , state: %s " ,
__FUNCTION__ ,
process - > GetID ( ) ,
StateAsCString ( state ) ) ;
}
switch ( state )
{
2015-12-30 06:55:28 -05:00
case StateType : : eStateRunning :
StartSTDIOForwarding ( ) ;
2015-07-03 12:57:06 -04:00
break ;
case StateType : : eStateStopped :
2015-12-30 06:55:28 -05:00
// Make sure we get all of the pending stdout/stderr from the inferior
// and send it to the lldb host before we send the state change
// notification
SendProcessOutput ( ) ;
// Then stop the forwarding, so that any late output (see llvm.org/pr25652) does not
// interfere with our protocol.
StopSTDIOForwarding ( ) ;
2015-07-03 12:57:06 -04:00
HandleInferiorState_Stopped ( process ) ;
break ;
2015-12-30 06:55:28 -05:00
case StateType : : eStateExited :
// Same as above
SendProcessOutput ( ) ;
StopSTDIOForwarding ( ) ;
HandleInferiorState_Exited ( process ) ;
break ;
2015-07-03 12:57:06 -04:00
default :
if ( log )
{
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s didn't handle state change for pid % " PRIu64 " , new state: %s " ,
__FUNCTION__ ,
process - > GetID ( ) ,
StateAsCString ( state ) ) ;
}
break ;
}
// Remember the previous state reported to us.
m_inferior_prev_state = state ;
}
void
GDBRemoteCommunicationServerLLGS : : DidExec ( NativeProcessProtocol * process )
{
ClearProcessSpecificData ( ) ;
}
2015-09-06 10:32:30 -04:00
void
GDBRemoteCommunicationServerLLGS : : DataAvailableCallback ( )
{
Log * log ( GetLogIfAnyCategoriesSet ( GDBR_LOG_COMM ) ) ;
if ( ! m_handshake_completed )
{
if ( ! HandshakeWithClient ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting " ,
__FUNCTION__ ) ;
m_mainloop . RequestTermination ( ) ;
return ;
}
m_handshake_completed = true ;
}
bool interrupt = false ;
bool done = false ;
Error error ;
while ( true )
{
const PacketResult result = GetPacketAndSendResponse ( 0 , error , interrupt , done ) ;
if ( result = = PacketResult : : ErrorReplyTimeout )
break ; // No more packets in the queue
if ( ( result ! = PacketResult : : Success ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s " ,
__FUNCTION__ , error . AsCString ( ) ) ;
m_mainloop . RequestTermination ( ) ;
break ;
}
}
}
Error
GDBRemoteCommunicationServerLLGS : : InitializeConnection ( std : : unique_ptr < Connection > & & connection )
{
IOObjectSP read_object_sp = connection - > GetReadObject ( ) ;
GDBRemoteCommunicationServer : : SetConnection ( connection . release ( ) ) ;
Error error ;
2015-12-30 06:55:28 -05:00
m_network_handle_up = m_mainloop . RegisterReadObject ( read_object_sp ,
2015-09-06 10:32:30 -04:00
[ this ] ( MainLoopBase & ) { DataAvailableCallback ( ) ; } , error ) ;
return error ;
}
2015-07-03 12:57:06 -04:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : SendONotification ( const char * buffer , uint32_t len )
{
if ( ( buffer = = nullptr ) | | ( len = = 0 ) )
{
// Nothing to send.
return PacketResult : : Success ;
}
StreamString response ;
response . PutChar ( ' O ' ) ;
response . PutBytesAsRawHex8 ( buffer , len ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
Error
GDBRemoteCommunicationServerLLGS : : SetSTDIOFileDescriptor ( int fd )
{
Error error ;
2015-12-30 06:55:28 -05:00
// Set up the reading/handling of process I/O
2015-07-03 12:57:06 -04:00
std : : unique_ptr < ConnectionFileDescriptor > conn_up ( new ConnectionFileDescriptor ( fd , true ) ) ;
if ( ! conn_up )
{
error . SetErrorString ( " failed to create ConnectionFileDescriptor " ) ;
return error ;
}
m_stdio_communication . SetCloseOnEOF ( false ) ;
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 ;
}
2015-12-30 06:55:28 -05:00
return Error ( ) ;
}
void
GDBRemoteCommunicationServerLLGS : : StartSTDIOForwarding ( )
{
// Don't forward if not connected (e.g. when attaching).
if ( ! m_stdio_communication . IsConnected ( ) )
return ;
2015-07-03 12:57:06 -04:00
// llgs local-process debugging may specify PTY paths, which will make these
// file actions non-null
// process launch -e/o will also make these file actions non-null
// nullptr means that the traffic is expected to flow over gdb-remote protocol
2015-12-30 06:55:28 -05:00
if ( m_process_launch_info . GetFileActionForFD ( STDOUT_FILENO ) & &
m_process_launch_info . GetFileActionForFD ( STDERR_FILENO ) )
return ;
Error error ;
lldbassert ( ! m_stdio_handle_up ) ;
m_stdio_handle_up = m_mainloop . RegisterReadObject (
m_stdio_communication . GetConnection ( ) - > GetReadObject ( ) ,
[ this ] ( MainLoopBase & ) { SendProcessOutput ( ) ; } , error ) ;
if ( ! m_stdio_handle_up )
2015-07-03 12:57:06 -04:00
{
2015-12-30 06:55:28 -05:00
// Not much we can do about the failure. Log it and continue without forwarding.
if ( Log * log = GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio forwarding: %s " ,
__FUNCTION__ , error . AsCString ( ) ) ;
2015-07-03 12:57:06 -04:00
}
2015-12-30 06:55:28 -05:00
}
2015-07-03 12:57:06 -04:00
2015-12-30 06:55:28 -05:00
void
GDBRemoteCommunicationServerLLGS : : StopSTDIOForwarding ( )
{
m_stdio_handle_up . reset ( ) ;
2015-07-03 12:57:06 -04:00
}
void
2015-12-30 06:55:28 -05:00
GDBRemoteCommunicationServerLLGS : : SendProcessOutput ( )
2015-07-03 12:57:06 -04:00
{
2015-12-30 06:55:28 -05:00
char buffer [ 1024 ] ;
ConnectionStatus status ;
Error error ;
while ( true )
{
size_t bytes_read = m_stdio_communication . Read ( buffer , sizeof buffer , 0 , status , & error ) ;
switch ( status )
{
case eConnectionStatusSuccess :
SendONotification ( buffer , bytes_read ) ;
break ;
case eConnectionStatusLostConnection :
case eConnectionStatusEndOfFile :
case eConnectionStatusError :
case eConnectionStatusNoConnection :
if ( Log * log = GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s Stopping stdio forwarding as communication returned status %d (error: %s) " , __FUNCTION__ , status , error . AsCString ( ) ) ;
m_stdio_handle_up . reset ( ) ;
return ;
case eConnectionStatusInterrupted :
case eConnectionStatusTimedOut :
return ;
}
}
2015-07-03 12:57:06 -04:00
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qProcessInfo ( StringExtractorGDBRemote & packet )
{
// 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 ) ;
lldb : : pid_t pid = m_debugged_process_sp - > GetID ( ) ;
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 ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qC ( StringExtractorGDBRemote & packet )
{
// 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 ) ;
StreamString response ;
response . Printf ( " QC% " PRIx64 , thread_sp - > GetID ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_k ( StringExtractorGDBRemote & packet )
{
2015-12-30 06:55:28 -05:00
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2015-07-03 12:57:06 -04:00
2015-12-30 06:55:28 -05:00
StopSTDIOForwarding ( ) ;
2015-07-03 12:57:06 -04:00
2015-12-30 06:55:28 -05:00
if ( ! m_debugged_process_sp )
2015-07-03 12:57:06 -04:00
{
2015-12-30 06:55:28 -05:00
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s No debugged process found. " , __FUNCTION__ ) ;
return PacketResult : : Success ;
2015-07-03 12:57:06 -04:00
}
2015-12-30 06:55:28 -05:00
Error error = m_debugged_process_sp - > Kill ( ) ;
if ( error . Fail ( ) & & log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged process % " PRIu64 " : %s " ,
__FUNCTION__ , m_debugged_process_sp - > GetID ( ) , error . AsCString ( ) ) ;
2015-07-03 12:57:06 -04:00
// No OK response for kill packet.
// return SendOKResponse ();
return PacketResult : : Success ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : 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
GDBRemoteCommunicationServerLLGS : : Handle_QSetWorkingDir ( StringExtractorGDBRemote & packet )
{
packet . SetFilePos ( : : strlen ( " QSetWorkingDir: " ) ) ;
std : : string path ;
packet . GetHexByteString ( path ) ;
m_process_launch_info . SetWorkingDirectory ( FileSpec { path , true } ) ;
return SendOKResponse ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qGetWorkingDir ( StringExtractorGDBRemote & packet )
{
FileSpec working_dir { m_process_launch_info . GetWorkingDirectory ( ) } ;
if ( working_dir )
{
StreamString response ;
response . PutCStringAsRawHex8 ( working_dir . GetCString ( ) ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
return SendErrorResponse ( 14 ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_C ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s called " , __FUNCTION__ ) ;
// Ensure we have a native process.
if ( ! m_debugged_process_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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} " ) ;
}
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).
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 ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%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
GDBRemoteCommunicationServerLLGS : : Handle_c ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s called " , __FUNCTION__ ) ;
packet . SetFilePos ( packet . GetFilePos ( ) + : : strlen ( " c " ) ) ;
// For now just support all continue.
const bool has_continue_address = ( packet . GetBytesLeft ( ) > 0 ) ;
if ( has_continue_address )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x36 ) ;
}
// Build the ResumeActionList
ResumeActionList actions ( StateType : : eStateRunning , 0 ) ;
Error error = m_debugged_process_sp - > Resume ( actions ) ;
if ( error . Fail ( ) )
{
if ( log )
{
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s c failed for process % " PRIu64 " : %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
}
return SendErrorResponse ( GDBRemoteServerError : : eErrorResume ) ;
}
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s continued process % " PRIu64 , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
// No response required from continue.
return PacketResult : : Success ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_vCont_actions ( StringExtractorGDBRemote & packet )
{
StreamString response ;
response . Printf ( " vCont;c;C;s;S " ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_vCont ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s handling vCont packet " , __FUNCTION__ ) ;
packet . SetFilePos ( : : strlen ( " vCont " ) ) ;
if ( packet . GetBytesLeft ( ) = = 0 )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s missing action from vCont package " , __FUNCTION__ ) ;
return SendIllFormedResponse ( packet , " Missing action from vCont package " ) ;
}
// Check if this is all continue (no options or ";c").
if ( : : strcmp ( packet . Peek ( ) , " ;c " ) = = 0 )
{
// Move past the ';', then do a simple 'c'.
packet . SetFilePos ( packet . GetFilePos ( ) + 1 ) ;
return Handle_c ( packet ) ;
}
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 ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s vCont failed for process % " PRIu64 " : %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
}
return SendErrorResponse ( GDBRemoteServerError : : eErrorResume ) ;
}
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s continued process % " PRIu64 , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
// No response required from vCont.
return PacketResult : : Success ;
}
void
GDBRemoteCommunicationServerLLGS : : SetCurrentThreadID ( lldb : : tid_t tid )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s setting current thread id to % " PRIu64 , __FUNCTION__ , tid ) ;
m_current_tid = tid ;
if ( m_debugged_process_sp )
m_debugged_process_sp - > SetCurrentThreadID ( m_current_tid ) ;
}
void
GDBRemoteCommunicationServerLLGS : : SetContinueThreadID ( lldb : : tid_t tid )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s setting continue thread id to % " PRIu64 , __FUNCTION__ , tid ) ;
m_continue_tid = tid ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_stop_reason ( StringExtractorGDBRemote & packet )
{
// Handle the $? gdbremote command.
// If no process, indicate error
if ( ! m_debugged_process_sp )
return SendErrorResponse ( 02 ) ;
2015-12-30 06:55:28 -05:00
return SendStopReasonForState ( m_debugged_process_sp - > GetState ( ) ) ;
2015-07-03 12:57:06 -04:00
}
GDBRemoteCommunication : : PacketResult
2015-12-30 06:55:28 -05:00
GDBRemoteCommunicationServerLLGS : : SendStopReasonForState ( lldb : : StateType process_state )
2015-07-03 12:57:06 -04:00
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
switch ( process_state )
{
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 :
{
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 ) ;
}
case eStateInvalid :
case eStateUnloaded :
case eStateExited :
return SendWResponse ( m_debugged_process_sp . get ( ) ) ;
default :
if ( log )
{
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " , current state reporting not handled: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
StateAsCString ( process_state ) ) ;
}
break ;
}
return SendErrorResponse ( 0 ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qRegisterInfo ( StringExtractorGDBRemote & packet )
{
// Fail if we don't have a current process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
return SendErrorResponse ( 68 ) ;
// Ensure we have a thread.
NativeThreadProtocolSP thread_sp ( m_debugged_process_sp - > GetThreadAtIndex ( 0 ) ) ;
if ( ! thread_sp )
return SendErrorResponse ( 69 ) ;
// Get the register context for the first thread.
NativeRegisterContextSP reg_context_sp ( thread_sp - > GetRegisterContext ( ) ) ;
if ( ! reg_context_sp )
return SendErrorResponse ( 69 ) ;
// Parse out the register number from the request.
packet . SetFilePos ( strlen ( " qRegisterInfo " ) ) ;
const uint32_t reg_index = packet . GetHexMaxU32 ( false , std : : numeric_limits < uint32_t > : : max ( ) ) ;
if ( reg_index = = std : : numeric_limits < uint32_t > : : max ( ) )
return SendErrorResponse ( 69 ) ;
// Return the end of registers response if we've iterated one past the end of the register set.
if ( reg_index > = reg_context_sp - > GetUserRegisterCount ( ) )
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 ( ' ; ' ) ;
}
2015-12-30 06:55:28 -05:00
if ( reg_info - > kinds [ RegisterKind : : eRegisterKindEHFrame ] ! = LLDB_INVALID_REGNUM )
response . Printf ( " ehframe:% " PRIu32 " ; " , reg_info - > kinds [ RegisterKind : : eRegisterKindEHFrame ] ) ;
2015-07-03 12:57:06 -04:00
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 ) ;
}
response . PutChar ( ' ; ' ) ;
}
if ( reg_info - > invalidate_regs & & reg_info - > invalidate_regs [ 0 ] )
{
response . PutCString ( " invalidate-regs: " ) ;
int i = 0 ;
for ( const uint32_t * reg_num = reg_info - > invalidate_regs ; * reg_num ! = LLDB_INVALID_REGNUM ; + + reg_num , + + i )
{
if ( i > 0 )
response . PutChar ( ' , ' ) ;
response . Printf ( " % " PRIx32 , * reg_num ) ;
}
response . PutChar ( ' ; ' ) ;
}
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qfThreadInfo ( StringExtractorGDBRemote & packet )
{
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 ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s() no process (%s), returning OK " , __FUNCTION__ , m_debugged_process_sp ? " invalid process id " : " null m_debugged_process_sp " ) ;
return SendOKResponse ( ) ;
}
StreamGDBRemote response ;
response . PutChar ( ' m ' ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s() finished thread iteration " , __FUNCTION__ ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qsThreadInfo ( StringExtractorGDBRemote & packet )
{
// FIXME for now we return the full thread list in the initial packet and always do nothing here.
return SendPacketNoLock ( " l " , 1 ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_p ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// 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 ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s failed, no thread available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
// Get the thread's register context.
NativeRegisterContextSP reg_context_sp ( thread_sp - > GetRegisterContext ( ) ) ;
if ( ! reg_context_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " tid % " PRIu64 " failed, no register context available for the thread " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) , thread_sp - > GetID ( ) ) ;
return SendErrorResponse ( 0x15 ) ;
}
// Return the end of registers response if we've iterated one past the end of the register set.
if ( reg_index > = reg_context_sp - > GetUserRegisterCount ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, requested register % " PRIu32 " beyond register count % " PRIu32 , __FUNCTION__ , reg_index , reg_context_sp - > GetUserRegisterCount ( ) ) ;
return SendErrorResponse ( 0x15 ) ;
}
const RegisterInfo * reg_info = reg_context_sp - > GetRegisterInfoAtIndex ( reg_index ) ;
if ( ! reg_info )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s failed to get data bytes from requested register % " PRIu32 , __FUNCTION__ , reg_index ) ;
return SendErrorResponse ( 0x15 ) ;
}
// FIXME flip as needed to get data in big/little endian format for this host.
for ( uint32_t i = 0 ; i < reg_value . GetByteSize ( ) ; + + i )
response . PutHex8 ( data [ i ] ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_P ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// 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 ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \" %s \" " , __FUNCTION__ , packet . GetStringRef ( ) . c_str ( ) ) ;
return SendErrorResponse ( 0x29 ) ;
}
// Note debugserver would send an E30 here.
if ( ( packet . GetBytesLeft ( ) < 1 ) | | ( packet . GetChar ( ) ! = ' = ' ) )
return SendIllFormedResponse ( packet , " P packet missing '=' char after register number " ) ;
// Get process architecture.
ArchSpec process_arch ;
if ( ! m_debugged_process_sp | | ! m_debugged_process_sp - > GetArchitecture ( process_arch ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to retrieve inferior architecture " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x49 ) ;
}
// Parse out the value.
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 ) ) ;
// Get the thread to use.
NativeThreadProtocolSP thread_sp = GetThreadFromSuffix ( packet ) ;
if ( ! thread_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no thread available (thread index 0) " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x28 ) ;
}
// Get the thread's register context.
NativeRegisterContextSP reg_context_sp ( thread_sp - > GetRegisterContext ( ) ) ;
if ( ! reg_context_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ) ;
}
const RegisterInfo * reg_info = reg_context_sp - > GetRegisterInfoAtIndex ( reg_index ) ;
if ( ! reg_info )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, requested register % " PRIu32 " returned NULL " , __FUNCTION__ , reg_index ) ;
return SendErrorResponse ( 0x48 ) ;
}
// Return the end of registers response if we've iterated one past the end of the register set.
if ( reg_index > = reg_context_sp - > GetUserRegisterCount ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, requested register % " PRIu32 " beyond register count % " PRIu32 , __FUNCTION__ , reg_index , reg_context_sp - > GetUserRegisterCount ( ) ) ;
return SendErrorResponse ( 0x47 ) ;
}
if ( reg_size ! = reg_info - > byte_size )
{
return SendIllFormedResponse ( packet , " P packet register size is incorrect " ) ;
}
// Build the reginfos response.
StreamGDBRemote response ;
RegisterValue reg_value ( reg_bytes , reg_size , process_arch . GetByteOrder ( ) ) ;
Error error = reg_context_sp - > WriteRegister ( reg_info , reg_value ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, write of requested register % " PRIu32 " (%s) failed: %s " , __FUNCTION__ , reg_index , reg_info - > name , error . AsCString ( ) ) ;
return SendErrorResponse ( 0x32 ) ;
}
return SendOKResponse ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_H ( StringExtractorGDBRemote & packet )
{
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 ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
// Parse out which variant of $H is requested.
packet . SetFilePos ( strlen ( " H " ) ) ;
if ( packet . GetBytesLeft ( ) < 1 )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, H command missing {g,c} variant " , __FUNCTION__ ) ;
return SendIllFormedResponse ( packet , " H command missing {g,c} variant " ) ;
}
const char h_variant = packet . GetChar ( ) ;
switch ( h_variant )
{
case ' g ' :
break ;
case ' c ' :
break ;
default :
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c " , __FUNCTION__ , h_variant ) ;
return SendIllFormedResponse ( packet , " H variant unsupported, should be c or g " ) ;
}
// 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 ( ) ) ;
// Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread).
if ( tid ! = LLDB_INVALID_THREAD_ID & & tid ! = 0 )
{
NativeThreadProtocolSP thread_sp ( m_debugged_process_sp - > GetThreadByID ( tid ) ) ;
if ( ! thread_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, tid % " PRIu64 " not found " , __FUNCTION__ , tid ) ;
return SendErrorResponse ( 0x15 ) ;
}
}
// Now switch the given thread type.
switch ( h_variant )
{
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 " ) ;
}
return SendOKResponse ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_I ( StringExtractorGDBRemote & packet )
{
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 ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_interrupt ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | 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 ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
// Interrupt the process.
Error error = m_debugged_process_sp - > Interrupt ( ) ;
if ( error . Fail ( ) )
{
if ( log )
{
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed for process % " PRIu64 " : %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
}
return SendErrorResponse ( GDBRemoteServerError : : eErrorResume ) ;
}
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s stopped process % " PRIu64 , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
// No response required from stop all.
return PacketResult : : Success ;
}
GDBRemoteCommunication : : PacketResult
2015-12-30 06:55:28 -05:00
GDBRemoteCommunicationServerLLGS : : Handle_memory_read ( StringExtractorGDBRemote & packet )
2015-07-03 12:57:06 -04:00
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 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 )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s nothing to read: zero-length packet " , __FUNCTION__ ) ;
2015-12-30 06:55:28 -05:00
return SendOKResponse ( ) ;
2015-07-03 12:57:06 -04:00
}
// Allocate the response buffer.
std : : string buf ( byte_count , ' \0 ' ) ;
if ( buf . empty ( ) )
return SendErrorResponse ( 0x78 ) ;
// Retrieve the process memory.
size_t bytes_read = 0 ;
Error error = m_debugged_process_sp - > ReadMemoryWithoutTrap ( read_addr , & buf [ 0 ] , byte_count , bytes_read ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " mem 0x% " PRIx64 " : read 0 of % " PRIu64 " requested bytes " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) , read_addr , byte_count ) ;
return SendErrorResponse ( 0x08 ) ;
}
StreamGDBRemote response ;
2015-12-30 06:55:28 -05:00
packet . SetFilePos ( 0 ) ;
char kind = packet . GetChar ( ' ? ' ) ;
if ( kind = = ' x ' )
response . PutEscapedBytes ( buf . data ( ) , byte_count ) ;
else
{
assert ( kind = = ' m ' ) ;
for ( size_t i = 0 ; i < bytes_read ; + + i )
response . PutHex8 ( buf [ i ] ) ;
}
2015-07-03 12:57:06 -04:00
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_M ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%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 = packet . GetHexBytes ( & buf [ 0 ] , byte_count , 0 ) ;
if ( convert_count ! = byte_count )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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.
size_t bytes_written = 0 ;
Error error = m_debugged_process_sp - > WriteMemory ( write_addr , & buf [ 0 ] , byte_count , bytes_written ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " mem 0x% " PRIx64 " : wrote 0 of % " PRIu64 " requested bytes " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) , write_addr , byte_count ) ;
return SendErrorResponse ( 0x09 ) ;
}
return SendOKResponse ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qMemoryRegionInfoSupported ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// 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 ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
// 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 ( ) )
{
// We don't support memory region info collection for this NativeProcessProtocol.
return SendUnimplementedResponse ( " " ) ;
}
return SendOKResponse ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qMemoryRegionInfo ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// Ensure we have a process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
// Parse out the memory address.
packet . SetFilePos ( strlen ( " qMemoryRegionInfo: " ) ) ;
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short qMemoryRegionInfo: packet " ) ;
// Read the address. Punting on validation.
const lldb : : addr_t read_addr = packet . GetHexMaxU64 ( false , 0 ) ;
StreamGDBRemote response ;
// Get the memory region info for the target address.
MemoryRegionInfo region_info ;
const Error error = m_debugged_process_sp - > GetMemoryRegionInfo ( read_addr , region_info ) ;
if ( error . Fail ( ) )
{
// Return the error message.
response . PutCString ( " error: " ) ;
response . PutCStringAsRawHex8 ( error . AsCString ( ) ) ;
response . PutChar ( ' ; ' ) ;
}
else
{
// 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 ( ) )
{
// Write permissions info.
response . PutCString ( " permissions: " ) ;
if ( region_info . GetReadable ( ) )
response . PutChar ( ' r ' ) ;
if ( region_info . GetWritable ( ) )
response . PutChar ( ' w ' ) ;
if ( region_info . GetExecutable ( ) )
response . PutChar ( ' x ' ) ;
response . PutChar ( ' ; ' ) ;
}
}
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_Z ( StringExtractorGDBRemote & packet )
{
// Ensure we have a process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
// Parse out software or hardware breakpoint or watchpoint requested.
packet . SetFilePos ( strlen ( " Z " ) ) ;
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short Z packet, missing software/hardware specifier " ) ;
bool want_breakpoint = true ;
bool want_hardware = false ;
2015-12-30 06:55:28 -05:00
uint32_t watch_flags = 0 ;
2015-07-03 12:57:06 -04: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 :
2015-12-30 06:55:28 -05:00
watch_flags = 1 ;
2015-07-03 12:57:06 -04:00
want_hardware = true ; want_breakpoint = false ; break ;
case eWatchpointRead :
2015-12-30 06:55:28 -05:00
watch_flags = 2 ;
2015-07-03 12:57:06 -04:00
want_hardware = true ; want_breakpoint = false ; break ;
case eWatchpointReadWrite :
2015-12-30 06:55:28 -05:00
watch_flags = 3 ;
2015-07-03 12:57:06 -04:00
want_hardware = true ; want_breakpoint = false ; break ;
case eStoppointInvalid :
return SendIllFormedResponse ( packet , " Z packet had invalid software/hardware specifier " ) ;
}
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
return SendIllFormedResponse ( packet , " Malformed Z packet, expecting comma after stoppoint type " ) ;
// Parse out the stoppoint address.
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short Z packet, missing address " ) ;
const lldb : : addr_t addr = packet . GetHexMaxU64 ( false , 0 ) ;
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
return SendIllFormedResponse ( packet , " Malformed Z packet, expecting comma after address " ) ;
// 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 " ) ;
if ( want_breakpoint )
{
// Try to set the breakpoint.
const Error error = m_debugged_process_sp - > SetBreakpoint ( addr , size , want_hardware ) ;
if ( error . Success ( ) )
return SendOKResponse ( ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_BREAKPOINTS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64
" failed to set breakpoint: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
return SendErrorResponse ( 0x09 ) ;
}
else
{
// 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 ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64
" failed to set watchpoint: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
return SendErrorResponse ( 0x09 ) ;
}
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_z ( StringExtractorGDBRemote & packet )
{
// Ensure we have a process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
// Parse out software or hardware breakpoint or watchpoint requested.
packet . SetFilePos ( strlen ( " z " ) ) ;
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short z packet, missing software/hardware specifier " ) ;
bool want_breakpoint = true ;
const GDBStoppointType stoppoint_type =
GDBStoppointType ( packet . GetS32 ( eStoppointInvalid ) ) ;
switch ( stoppoint_type )
{
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 ;
default :
return SendIllFormedResponse ( packet , " z packet had invalid software/hardware specifier " ) ;
}
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
return SendIllFormedResponse ( packet , " Malformed z packet, expecting comma after stoppoint type " ) ;
// Parse out the stoppoint address.
if ( packet . GetBytesLeft ( ) < 1 )
return SendIllFormedResponse ( packet , " Too short z packet, missing address " ) ;
const lldb : : addr_t addr = packet . GetHexMaxU64 ( false , 0 ) ;
if ( ( packet . GetBytesLeft ( ) < 1 ) | | packet . GetChar ( ) ! = ' , ' )
return SendIllFormedResponse ( packet , " Malformed z packet, expecting comma after address " ) ;
/*
// 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 " ) ;
*/
if ( want_breakpoint )
{
// Try to clear the breakpoint.
const Error error = m_debugged_process_sp - > RemoveBreakpoint ( addr ) ;
if ( error . Success ( ) )
return SendOKResponse ( ) ;
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_BREAKPOINTS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64
" failed to remove watchpoint: %s " ,
__FUNCTION__ ,
m_debugged_process_sp - > GetID ( ) ,
error . AsCString ( ) ) ;
return SendErrorResponse ( 0x09 ) ;
}
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_s ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
// Ensure we have a process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x32 ) ;
}
// We first try to use a continue thread id. If any one or any all set, use the current thread.
// Bail out if we don't have a thread id.
lldb : : tid_t tid = GetContinueThreadID ( ) ;
if ( tid = = 0 | | tid = = LLDB_INVALID_THREAD_ID )
tid = GetCurrentThreadID ( ) ;
if ( tid = = LLDB_INVALID_THREAD_ID )
return SendErrorResponse ( 0x33 ) ;
// Double check that we have such a thread.
// TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
NativeThreadProtocolSP thread_sp = m_debugged_process_sp - > GetThreadByID ( tid ) ;
if ( ! thread_sp | | thread_sp - > GetID ( ) ! = tid )
return SendErrorResponse ( 0x33 ) ;
// Create the step action for the given thread.
ResumeAction action = { tid , eStateStepping , 0 } ;
// Setup the actions list.
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 ( " GDBRemoteCommunicationServerLLGS::%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 ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qXfer_auxv_read ( StringExtractorGDBRemote & packet )
{
// *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 )
{
// Make sure we have a valid process.
if ( ! m_debugged_process_sp | | ( m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s failed, no auxv data retrieved " , __FUNCTION__ ) ;
m_active_auxv_buffer_sp . reset ( ) ;
return SendErrorResponse ( 0x11 ) ;
}
}
// 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 ( ) )
{
// 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 )
{
// There will be nothing left to read after this
response . PutChar ( ' l ' ) ;
done_with_buffer = true ;
}
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 ) ;
}
if ( done_with_buffer )
m_active_auxv_buffer_sp . reset ( ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
# else
return SendUnimplementedResponse ( " not implemented on this platform " ) ;
# endif
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_QSaveRegisterState ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// Move past packet name.
packet . SetFilePos ( strlen ( " QSaveRegisterState " ) ) ;
// 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 QSaveRegisterState packet " ) ;
else
return SendIllFormedResponse ( packet , " No thread was is set with the Hg packet " ) ;
}
// Grab the register context for the thread.
NativeRegisterContextSP reg_context_sp ( thread_sp - > GetRegisterContext ( ) ) ;
if ( ! reg_context_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " failed to save all register values: %s " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) , error . AsCString ( ) ) ;
return SendErrorResponse ( 0x75 ) ;
}
// Allocate a new save id.
const uint32_t save_id = GetNextSavedRegistersID ( ) ;
assert ( ( m_saved_registers_map . find ( save_id ) = = m_saved_registers_map . end ( ) ) & & " GetNextRegisterSaveID() returned an existing register save id " ) ;
// Save the register data buffer under the save id.
{
Mutex : : Locker locker ( m_saved_registers_mutex ) ;
m_saved_registers_map [ save_id ] = register_data_sp ;
}
// Write the response.
StreamGDBRemote response ;
response . Printf ( " % " PRIu32 , save_id ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_QRestoreRegisterState ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// 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 )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x76 ) ;
}
// Get the thread to use.
NativeThreadProtocolSP thread_sp = GetThreadFromSuffix ( packet ) ;
if ( ! thread_sp )
{
if ( m_thread_suffix_supported )
return SendIllFormedResponse ( packet , " No thread specified in QRestoreRegisterState packet " ) ;
else
return SendIllFormedResponse ( packet , " No thread was is set with the Hg packet " ) ;
}
// Grab the register context for the thread.
NativeRegisterContextSP reg_context_sp ( thread_sp - > GetRegisterContext ( ) ) ;
if ( ! reg_context_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%s pid % " PRIu64 " failed to restore all register values: %s " , __FUNCTION__ , m_debugged_process_sp - > GetID ( ) , error . AsCString ( ) ) ;
return SendErrorResponse ( 0x77 ) ;
}
return SendOKResponse ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_vAttach ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// 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 ( " GDBRemoteCommunicationServerLLGS::%s attempting to attach to pid % " PRIu64 , __FUNCTION__ , pid ) ;
Error error = AttachToProcess ( pid ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to attach to pid % " PRIu64 " : %s \n " , __FUNCTION__ , pid , error . AsCString ( ) ) ;
return SendErrorResponse ( 0x01 ) ;
}
// Notify we attached by sending a stop packet.
2015-12-30 06:55:28 -05:00
return SendStopReasonForState ( m_debugged_process_sp - > GetState ( ) ) ;
2015-07-03 12:57:06 -04:00
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_D ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2015-12-30 06:55:28 -05:00
StopSTDIOForwarding ( ) ;
2015-07-03 12:57:06 -04:00
// 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 ( " GDBRemoteCommunicationServerLLGS::%s failed, no process available " , __FUNCTION__ ) ;
return SendErrorResponse ( 0x15 ) ;
}
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 " ) ;
}
const Error error = m_debugged_process_sp - > Detach ( ) ;
if ( error . Fail ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to detach from pid % " PRIu64 " : %s \n " ,
__FUNCTION__ , m_debugged_process_sp - > GetID ( ) , error . AsCString ( ) ) ;
return SendErrorResponse ( 0x01 ) ;
}
return SendOKResponse ( ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qThreadStopInfo ( StringExtractorGDBRemote & packet )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
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 ( " GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \" %s \" " , __FUNCTION__ , packet . GetStringRef ( ) . c_str ( ) ) ;
return SendErrorResponse ( 0x15 ) ;
}
return SendStopReplyPacketForThread ( tid ) ;
}
2015-12-30 06:55:28 -05:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_jThreadsInfo ( StringExtractorGDBRemote & )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD ) ) ;
// 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 ( " GDBRemoteCommunicationServerLLGS::%s preparing packet for pid % " PRIu64 ,
__FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
StreamString response ;
const bool threads_with_valid_stop_info_only = false ;
JSONArray : : SP threads_array_sp = GetJSONThreadsInfo ( * m_debugged_process_sp ,
threads_with_valid_stop_info_only ) ;
if ( ! threads_array_sp )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s failed to prepare a packet for pid % " PRIu64 ,
__FUNCTION__ , m_debugged_process_sp - > GetID ( ) ) ;
return SendErrorResponse ( 52 ) ;
}
threads_array_sp - > Write ( response ) ;
StreamGDBRemote escaped_response ;
escaped_response . PutEscapedBytes ( response . GetData ( ) , response . GetSize ( ) ) ;
return SendPacketNoLock ( escaped_response . GetData ( ) , escaped_response . GetSize ( ) ) ;
}
2015-07-03 12:57:06 -04:00
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qWatchpointSupportInfo ( StringExtractorGDBRemote & packet )
{
// 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 ( ) ) ;
}
GDBRemoteCommunication : : PacketResult
GDBRemoteCommunicationServerLLGS : : Handle_qFileLoadAddress ( StringExtractorGDBRemote & packet )
{
// 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 ( 67 ) ;
packet . SetFilePos ( strlen ( " qFileLoadAddress: " ) ) ;
if ( packet . GetBytesLeft ( ) = = 0 )
return SendErrorResponse ( 68 ) ;
std : : string file_name ;
packet . GetHexByteString ( file_name ) ;
lldb : : addr_t file_load_address = LLDB_INVALID_ADDRESS ;
Error error = m_debugged_process_sp - > GetFileLoadAddress ( file_name , file_load_address ) ;
if ( error . Fail ( ) )
return SendErrorResponse ( 69 ) ;
if ( file_load_address = = LLDB_INVALID_ADDRESS )
return SendErrorResponse ( 1 ) ; // File not loaded
StreamGDBRemote response ;
response . PutHex64 ( file_load_address ) ;
return SendPacketNoLock ( response . GetData ( ) , response . GetSize ( ) ) ;
}
void
GDBRemoteCommunicationServerLLGS : : MaybeCloseInferiorTerminalConnection ( )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
// Tell the stdio connection to shut down.
if ( m_stdio_communication . IsConnected ( ) )
{
auto connection = m_stdio_communication . GetConnection ( ) ;
if ( connection )
{
Error error ;
connection - > Disconnect ( & error ) ;
if ( error . Success ( ) )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - SUCCESS " , __FUNCTION__ ) ;
}
else
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - FAIL: %s " , __FUNCTION__ , error . AsCString ( ) ) ;
}
}
}
}
NativeThreadProtocolSP
GDBRemoteCommunicationServerLLGS : : GetThreadFromSuffix ( StringExtractorGDBRemote & packet )
{
NativeThreadProtocolSP thread_sp ;
// We have no thread if we don't have a process.
if ( ! m_debugged_process_sp | | m_debugged_process_sp - > GetID ( ) = = LLDB_INVALID_PROCESS_ID )
return thread_sp ;
// If the client hasn't asked for thread suffix support, there will not be a thread suffix.
// Use the current thread in that case.
if ( ! m_thread_suffix_supported )
{
const lldb : : tid_t current_tid = GetCurrentThreadID ( ) ;
if ( current_tid = = LLDB_INVALID_THREAD_ID )
return thread_sp ;
else if ( current_tid = = 0 )
{
// Pick a thread.
return m_debugged_process_sp - > GetThreadAtIndex ( 0 ) ;
}
else
return m_debugged_process_sp - > GetThreadByID ( current_tid ) ;
}
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_THREAD ) ) ;
// Parse out the ';'.
if ( packet . GetBytesLeft ( ) < 1 | | packet . GetChar ( ) ! = ' ; ' )
{
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%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 ( " GDBRemoteCommunicationServerLLGS::%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
GDBRemoteCommunicationServerLLGS : : 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
GDBRemoteCommunicationServerLLGS : : GetNextSavedRegistersID ( )
{
Mutex : : Locker locker ( m_saved_registers_mutex ) ;
return m_next_saved_registers_id + + ;
}
void
GDBRemoteCommunicationServerLLGS : : ClearProcessSpecificData ( )
{
Log * log ( GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | GDBR_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s() " , __FUNCTION__ ) ;
// Clear any auxv cached data.
// *BSD impls should be able to do this too.
# if defined(__linux__)
if ( log )
log - > Printf ( " GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer (previously %s) " ,
__FUNCTION__ ,
m_active_auxv_buffer_sp ? " was set " : " was not set " ) ;
m_active_auxv_buffer_sp . reset ( ) ;
# endif
}
FileSpec
GDBRemoteCommunicationServerLLGS : : FindModuleFile ( const std : : string & module_path ,
const ArchSpec & arch )
{
if ( m_debugged_process_sp )
{
FileSpec file_spec ;
if ( m_debugged_process_sp - > GetLoadedModuleFileSpec ( module_path . c_str ( ) , file_spec ) . Success ( ) )
{
if ( file_spec . Exists ( ) )
return file_spec ;
}
}
return GDBRemoteCommunicationServerCommon : : FindModuleFile ( module_path , arch ) ;
}