2011-07-15 18:02:58 +00:00
//===-- ProcessKDP.cpp ------------------------------------------*- C++ -*-===//
2011-07-15 03:27:12 +00:00
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
# include <errno.h>
# include <stdlib.h>
// C++ Includes
// Other libraries and framework includes
2011-07-17 20:36:25 +00:00
# include "lldb/Core/ConnectionFileDescriptor.h"
2011-07-20 03:41:06 +00:00
# include "lldb/Core/Debugger.h"
2011-07-15 03:27:12 +00:00
# include "lldb/Core/PluginManager.h"
2012-08-29 21:13:06 +00:00
# include "lldb/Core/Module.h"
2012-09-29 04:02:01 +00:00
# include "lldb/Core/ModuleSpec.h"
2011-07-15 03:27:12 +00:00
# include "lldb/Core/State.h"
2012-09-29 04:02:01 +00:00
# include "lldb/Core/UUID.h"
2011-07-15 03:27:12 +00:00
# include "lldb/Host/Host.h"
2012-09-29 04:02:01 +00:00
# include "lldb/Host/Symbols.h"
2012-10-19 22:22:57 +00:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandObject.h"
# include "lldb/Interpreter/CommandObjectMultiword.h"
# include "lldb/Interpreter/CommandReturnObject.h"
# include "lldb/Interpreter/OptionGroupString.h"
# include "lldb/Interpreter/OptionGroupUInt64.h"
2012-08-29 21:13:06 +00:00
# include "lldb/Symbol/ObjectFile.h"
2012-09-21 16:31:20 +00:00
# include "lldb/Target/RegisterContext.h"
2011-07-15 16:31:38 +00:00
# include "lldb/Target/Target.h"
2011-07-19 03:57:15 +00:00
# include "lldb/Target/Thread.h"
2011-07-15 03:27:12 +00:00
2013-08-27 05:04:57 +00:00
# define USEC_PER_SEC 1000000
2011-07-15 03:27:12 +00:00
// Project includes
# include "ProcessKDP.h"
# include "ProcessKDPLog.h"
2011-07-19 03:57:15 +00:00
# include "ThreadKDP.h"
2012-10-03 01:29:34 +00:00
# include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
2012-10-25 00:25:13 +00:00
# include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
2012-10-19 22:22:57 +00:00
# include "Utility/StringExtractor.h"
2011-07-15 03:27:12 +00:00
using namespace lldb ;
using namespace lldb_private ;
2013-07-15 22:54:20 +00:00
namespace {
static PropertyDefinition
g_properties [ ] =
{
{ " packet-timeout " , OptionValue : : eTypeUInt64 , true , 5 , NULL , NULL , " Specify the default packet timeout in seconds. " } ,
{ NULL , OptionValue : : eTypeInvalid , false , 0 , NULL , NULL , NULL }
} ;
enum
{
ePropertyPacketTimeout
} ;
class PluginProperties : public Properties
{
public :
static ConstString
GetSettingName ( )
{
return ProcessKDP : : GetPluginNameStatic ( ) ;
}
PluginProperties ( ) :
Properties ( )
{
m_collection_sp . reset ( new OptionValueProperties ( GetSettingName ( ) ) ) ;
m_collection_sp - > Initialize ( g_properties ) ;
}
virtual
~ PluginProperties ( )
{
}
uint64_t
GetPacketTimeout ( )
{
const uint32_t idx = ePropertyPacketTimeout ;
return m_collection_sp - > GetPropertyAtIndexAsUInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
}
} ;
typedef std : : shared_ptr < PluginProperties > ProcessKDPPropertiesSP ;
static const ProcessKDPPropertiesSP &
GetGlobalPluginProperties ( )
{
static ProcessKDPPropertiesSP g_settings_sp ;
if ( ! g_settings_sp )
g_settings_sp . reset ( new PluginProperties ( ) ) ;
return g_settings_sp ;
}
} // anonymous namespace end
2013-05-07 18:35:34 +00:00
static const lldb : : tid_t g_kernel_tid = 1 ;
2013-05-10 21:47:16 +00:00
ConstString
2011-07-15 03:27:12 +00:00
ProcessKDP : : GetPluginNameStatic ( )
{
2013-05-10 21:47:16 +00:00
static ConstString g_name ( " kdp-remote " ) ;
return g_name ;
2011-07-15 03:27:12 +00:00
}
const char *
ProcessKDP : : GetPluginDescriptionStatic ( )
{
return " KDP Remote protocol based debugging plug-in for darwin kernel debugging. " ;
}
void
ProcessKDP : : Terminate ( )
{
PluginManager : : UnregisterPlugin ( ProcessKDP : : CreateInstance ) ;
}
2012-02-09 06:16:32 +00:00
lldb : : ProcessSP
ProcessKDP : : CreateInstance ( Target & target ,
Listener & listener ,
const FileSpec * crash_file_path )
2011-07-15 03:27:12 +00:00
{
2012-02-09 06:16:32 +00:00
lldb : : ProcessSP process_sp ;
if ( crash_file_path = = NULL )
process_sp . reset ( new ProcessKDP ( target , listener ) ) ;
return process_sp ;
2011-07-15 03:27:12 +00:00
}
bool
2011-07-17 20:36:25 +00:00
ProcessKDP : : CanDebug ( Target & target , bool plugin_specified_by_name )
2011-07-15 03:27:12 +00:00
{
2011-10-21 21:41:45 +00:00
if ( plugin_specified_by_name )
return true ;
2011-07-15 03:27:12 +00:00
// For now we are just making sure the file exists for a given module
2011-08-11 02:48:45 +00:00
Module * exe_module = target . GetExecutableModulePointer ( ) ;
if ( exe_module )
2011-07-15 03:27:12 +00:00
{
const llvm : : Triple & triple_ref = target . GetArchitecture ( ) . GetTriple ( ) ;
2012-05-08 01:45:38 +00:00
switch ( triple_ref . getOS ( ) )
2011-07-15 03:27:12 +00:00
{
2012-05-08 01:45:38 +00:00
case llvm : : Triple : : Darwin : // Should use "macosx" for desktop and "ios" for iOS, but accept darwin just in case
case llvm : : Triple : : MacOSX : // For desktop targets
case llvm : : Triple : : IOS : // For arm targets
if ( triple_ref . getVendor ( ) = = llvm : : Triple : : Apple )
{
ObjectFile * exe_objfile = exe_module - > GetObjectFile ( ) ;
if ( exe_objfile - > GetType ( ) = = ObjectFile : : eTypeExecutable & &
exe_objfile - > GetStrata ( ) = = ObjectFile : : eStrataKernel )
return true ;
}
break ;
default :
break ;
2011-07-15 03:27:12 +00:00
}
}
2011-10-21 21:41:45 +00:00
return false ;
2011-07-15 03:27:12 +00:00
}
//----------------------------------------------------------------------
// ProcessKDP constructor
//----------------------------------------------------------------------
ProcessKDP : : ProcessKDP ( Target & target , Listener & listener ) :
Process ( target , listener ) ,
m_comm ( " lldb.process.kdp-remote.communication " ) ,
2012-02-16 06:50:00 +00:00
m_async_broadcaster ( NULL , " lldb.process.kdp-remote.async-broadcaster " ) ,
2012-09-25 02:40:06 +00:00
m_async_thread ( LLDB_INVALID_HOST_THREAD ) ,
2012-10-03 01:29:34 +00:00
m_dyld_plugin_name ( ) ,
2012-10-19 22:22:57 +00:00
m_kernel_load_addr ( LLDB_INVALID_ADDRESS ) ,
2013-05-07 18:35:34 +00:00
m_command_sp ( ) ,
m_kernel_thread_wp ( )
2011-07-15 03:27:12 +00:00
{
2012-09-21 16:31:20 +00:00
m_async_broadcaster . SetEventName ( eBroadcastBitAsyncThreadShouldExit , " async thread should exit " ) ;
m_async_broadcaster . SetEventName ( eBroadcastBitAsyncContinue , " async thread continue " ) ;
2013-07-15 22:54:20 +00:00
const uint64_t timeout_seconds = GetGlobalPluginProperties ( ) - > GetPacketTimeout ( ) ;
if ( timeout_seconds > 0 )
m_comm . SetPacketTimeout ( timeout_seconds ) ;
2011-07-15 03:27:12 +00:00
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
ProcessKDP : : ~ ProcessKDP ( )
{
Clear ( ) ;
2011-11-17 04:46:02 +00:00
// We need to call finalize on the process before destroying ourselves
// to make sure all of the broadcaster cleanup goes as planned. If we
// destruct this class, then Process::~Process() might have problems
// trying to fully destroy the broadcaster.
Finalize ( ) ;
2011-07-15 03:27:12 +00:00
}
//----------------------------------------------------------------------
// PluginInterface
//----------------------------------------------------------------------
2013-05-10 21:47:16 +00:00
lldb_private : : ConstString
2011-07-15 03:27:12 +00:00
ProcessKDP : : GetPluginName ( )
{
return GetPluginNameStatic ( ) ;
}
uint32_t
ProcessKDP : : GetPluginVersion ( )
{
return 1 ;
}
Error
ProcessKDP : : WillLaunch ( Module * module )
{
Error error ;
error . SetErrorString ( " launching not supported in kdp-remote plug-in " ) ;
return error ;
}
Error
ProcessKDP : : WillAttachToProcessWithID ( lldb : : pid_t pid )
{
Error error ;
error . SetErrorString ( " attaching to a by process ID not supported in kdp-remote plug-in " ) ;
return error ;
}
Error
ProcessKDP : : WillAttachToProcessWithName ( const char * process_name , bool wait_for_launch )
{
Error error ;
error . SetErrorString ( " attaching to a by process name not supported in kdp-remote plug-in " ) ;
return error ;
}
Error
2012-09-29 04:02:01 +00:00
ProcessKDP : : DoConnectRemote ( Stream * strm , const char * remote_url )
2011-07-15 03:27:12 +00:00
{
Error error ;
2012-09-21 16:31:20 +00:00
// Don't let any JIT happen when doing KDP as we can't allocate
// memory and we don't want to be mucking with threads that might
// already be handling exceptions
SetCanJIT ( false ) ;
2011-07-17 20:36:25 +00:00
if ( remote_url = = NULL | | remote_url [ 0 ] = = ' \0 ' )
2012-09-21 16:31:20 +00:00
{
error . SetErrorStringWithFormat ( " invalid connection URL '%s' " , remote_url ) ;
return error ;
}
2011-07-17 20:36:25 +00:00
2013-04-18 22:45:39 +00:00
std : : unique_ptr < ConnectionFileDescriptor > conn_ap ( new ConnectionFileDescriptor ( ) ) ;
2011-07-17 20:36:25 +00:00
if ( conn_ap . get ( ) )
{
// Only try once for now.
// TODO: check if we should be retrying?
const uint32_t max_retry_count = 1 ;
for ( uint32_t retry_count = 0 ; retry_count < max_retry_count ; + + retry_count )
{
if ( conn_ap - > Connect ( remote_url , & error ) = = eConnectionStatusSuccess )
break ;
usleep ( 100000 ) ;
}
}
if ( conn_ap - > IsConnected ( ) )
{
const uint16_t reply_port = conn_ap - > GetReadPort ( ) ;
if ( reply_port ! = 0 )
{
m_comm . SetConnection ( conn_ap . release ( ) ) ;
if ( m_comm . SendRequestReattach ( reply_port ) )
{
if ( m_comm . SendRequestConnect ( reply_port , reply_port , " Greetings from LLDB... " ) )
{
m_comm . GetVersion ( ) ;
uint32_t cpu = m_comm . GetCPUType ( ) ;
uint32_t sub = m_comm . GetCPUSubtype ( ) ;
ArchSpec kernel_arch ;
kernel_arch . SetArchitecture ( eArchTypeMachO , cpu , sub ) ;
m_target . SetArchitecture ( kernel_arch ) ;
2012-09-29 04:02:01 +00:00
2012-10-25 00:25:13 +00:00
/* Get the kernel's UUID and load address via KDP_KERNELVERSION packet. */
/* An EFI kdp session has neither UUID nor load address. */
2012-09-29 04:02:01 +00:00
UUID kernel_uuid = m_comm . GetUUID ( ) ;
addr_t kernel_load_addr = m_comm . GetLoadAddress ( ) ;
2012-10-25 00:25:13 +00:00
if ( m_comm . RemoteIsEFI ( ) )
{
m_dyld_plugin_name = DynamicLoaderStatic : : GetPluginNameStatic ( ) ;
}
2013-05-09 23:52:21 +00:00
else if ( m_comm . RemoteIsDarwinKernel ( ) )
2012-09-29 04:02:01 +00:00
{
2013-05-09 23:52:21 +00:00
m_dyld_plugin_name = DynamicLoaderDarwinKernel : : GetPluginNameStatic ( ) ;
2013-05-06 23:02:03 +00:00
if ( kernel_load_addr ! = LLDB_INVALID_ADDRESS )
{
m_kernel_load_addr = kernel_load_addr ;
}
2012-09-29 04:02:01 +00:00
}
2012-09-25 02:40:06 +00:00
// Set the thread ID
UpdateThreadListIfNeeded ( ) ;
2011-07-19 03:57:15 +00:00
SetID ( 1 ) ;
2011-08-22 02:49:39 +00:00
GetThreadList ( ) ;
2011-07-19 03:57:15 +00:00
SetPrivateState ( eStateStopped ) ;
2011-07-20 03:41:06 +00:00
StreamSP async_strm_sp ( m_target . GetDebugger ( ) . GetAsyncOutputStream ( ) ) ;
if ( async_strm_sp )
{
2011-07-21 01:12:01 +00:00
const char * cstr ;
if ( ( cstr = m_comm . GetKernelVersion ( ) ) ! = NULL )
2011-07-20 03:41:06 +00:00
{
2011-07-21 01:12:01 +00:00
async_strm_sp - > Printf ( " Version: %s \n " , cstr ) ;
2011-07-20 03:41:06 +00:00
async_strm_sp - > Flush ( ) ;
}
2011-07-21 01:12:01 +00:00
// if ((cstr = m_comm.GetImagePath ()) != NULL)
// {
// async_strm_sp->Printf ("Image Path: %s\n", cstr);
// async_strm_sp->Flush();
// }
2011-07-20 03:41:06 +00:00
}
2011-07-17 20:36:25 +00:00
}
2012-09-25 02:40:06 +00:00
else
{
error . SetErrorString ( " KDP_REATTACH failed " ) ;
}
2011-07-17 20:36:25 +00:00
}
else
{
2012-09-25 02:40:06 +00:00
error . SetErrorString ( " KDP_REATTACH failed " ) ;
2011-07-17 20:36:25 +00:00
}
}
else
{
error . SetErrorString ( " invalid reply port from UDP connection " ) ;
}
}
else
{
if ( error . Success ( ) )
error . SetErrorStringWithFormat ( " failed to connect to '%s' " , remote_url ) ;
}
if ( error . Fail ( ) )
m_comm . Disconnect ( ) ;
2011-07-15 03:27:12 +00:00
return error ;
}
//----------------------------------------------------------------------
// Process Control
//----------------------------------------------------------------------
Error
2011-11-03 21:22:33 +00:00
ProcessKDP : : DoLaunch ( Module * exe_module ,
2013-12-09 22:52:50 +00:00
ProcessLaunchInfo & launch_info )
2011-07-15 03:27:12 +00:00
{
Error error ;
error . SetErrorString ( " launching not supported in kdp-remote plug-in " ) ;
return error ;
}
Error
ProcessKDP : : DoAttachToProcessWithID ( lldb : : pid_t attach_pid )
{
Error error ;
error . SetErrorString ( " attach to process by ID is not suppported in kdp remote debugging " ) ;
return error ;
}
Error
2012-02-25 01:07:38 +00:00
ProcessKDP : : DoAttachToProcessWithID ( lldb : : pid_t attach_pid , const ProcessAttachInfo & attach_info )
{
Error error ;
error . SetErrorString ( " attach to process by ID is not suppported in kdp remote debugging " ) ;
return error ;
}
Error
2013-12-23 22:32:54 +00:00
ProcessKDP : : DoAttachToProcessWithName ( const char * process_name , const ProcessAttachInfo & attach_info )
2011-07-15 03:27:12 +00:00
{
Error error ;
error . SetErrorString ( " attach to process by name is not suppported in kdp remote debugging " ) ;
return error ;
}
void
ProcessKDP : : DidAttach ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( ProcessKDPLog : : GetLogIfAllCategoriesSet ( KDP_LOG_PROCESS ) ) ;
2011-07-15 03:27:12 +00:00
if ( log )
2011-10-11 21:17:10 +00:00
log - > Printf ( " ProcessKDP::DidAttach() " ) ;
2011-07-15 03:27:12 +00:00
if ( GetID ( ) ! = LLDB_INVALID_PROCESS_ID )
{
// TODO: figure out the register context that we will use
}
}
2012-10-03 01:29:34 +00:00
addr_t
ProcessKDP : : GetImageInfoAddress ( )
{
return m_kernel_load_addr ;
}
lldb_private : : DynamicLoader *
ProcessKDP : : GetDynamicLoader ( )
{
if ( m_dyld_ap . get ( ) = = NULL )
2013-05-11 03:09:05 +00:00
m_dyld_ap . reset ( DynamicLoader : : FindPlugin ( this , m_dyld_plugin_name . IsEmpty ( ) ? NULL : m_dyld_plugin_name . GetCString ( ) ) ) ;
2012-10-03 01:29:34 +00:00
return m_dyld_ap . get ( ) ;
}
2011-07-15 03:27:12 +00:00
Error
ProcessKDP : : WillResume ( )
{
return Error ( ) ;
}
Error
ProcessKDP : : DoResume ( )
{
Error error ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessKDPLog : : GetLogIfAllCategoriesSet ( KDP_LOG_PROCESS ) ) ;
2012-09-21 16:31:20 +00:00
// Only start the async thread if we try to do any process control
if ( ! IS_VALID_LLDB_HOST_THREAD ( m_async_thread ) )
StartAsyncThread ( ) ;
2012-09-25 02:40:06 +00:00
bool resume = false ;
2012-09-21 16:31:20 +00:00
2012-09-25 02:40:06 +00:00
// With KDP there is only one thread we can tell what to do
2013-05-07 18:35:34 +00:00
ThreadSP kernel_thread_sp ( m_thread_list . FindThreadByProtocolID ( g_kernel_tid ) ) ;
2012-09-25 02:40:06 +00:00
if ( kernel_thread_sp )
2012-09-21 01:55:30 +00:00
{
2012-09-25 02:40:06 +00:00
const StateType thread_resume_state = kernel_thread_sp - > GetTemporaryResumeState ( ) ;
2013-05-09 01:55:29 +00:00
if ( log )
log - > Printf ( " ProcessKDP::DoResume() thread_resume_state = %s " , StateAsCString ( thread_resume_state ) ) ;
2012-09-21 16:31:20 +00:00
switch ( thread_resume_state )
2012-09-21 01:55:30 +00:00
{
2012-09-21 16:31:20 +00:00
case eStateSuspended :
// Nothing to do here when a thread will stay suspended
// we just leave the CPU mask bit set to zero for the thread
2013-05-09 01:55:29 +00:00
if ( log )
log - > Printf ( " ProcessKDP::DoResume() = suspended??? " ) ;
2012-09-21 16:31:20 +00:00
break ;
case eStateStepping :
2013-04-02 20:32:37 +00:00
{
lldb : : RegisterContextSP reg_ctx_sp ( kernel_thread_sp - > GetRegisterContext ( ) ) ;
if ( reg_ctx_sp )
{
2013-05-09 01:55:29 +00:00
if ( log )
log - > Printf ( " ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (true); " ) ;
2013-04-02 20:32:37 +00:00
reg_ctx_sp - > HardwareSingleStep ( true ) ;
resume = true ;
}
else
{
error . SetErrorStringWithFormat ( " KDP thread 0x%llx has no register context " , kernel_thread_sp - > GetID ( ) ) ;
}
}
2012-09-25 02:40:06 +00:00
break ;
2012-09-21 16:31:20 +00:00
case eStateRunning :
2013-04-02 20:32:37 +00:00
{
lldb : : RegisterContextSP reg_ctx_sp ( kernel_thread_sp - > GetRegisterContext ( ) ) ;
2013-05-09 01:55:29 +00:00
if ( reg_ctx_sp )
{
if ( log )
log - > Printf ( " ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (false); " ) ;
reg_ctx_sp - > HardwareSingleStep ( false ) ;
resume = true ;
}
else
{
error . SetErrorStringWithFormat ( " KDP thread 0x%llx has no register context " , kernel_thread_sp - > GetID ( ) ) ;
}
2013-04-02 20:32:37 +00:00
}
2012-09-21 16:31:20 +00:00
break ;
2012-09-25 02:40:06 +00:00
2012-09-21 16:31:20 +00:00
default :
2012-09-25 02:40:06 +00:00
// The only valid thread resume states are listed above
2012-09-21 16:31:20 +00:00
assert ( ! " invalid thread resume state " ) ;
break ;
2012-09-21 01:55:30 +00:00
}
}
2012-09-25 02:40:06 +00:00
if ( resume )
2012-09-21 16:31:20 +00:00
{
2012-09-25 02:40:06 +00:00
if ( log )
log - > Printf ( " ProcessKDP::DoResume () sending resume " ) ;
2012-09-21 16:31:20 +00:00
2012-09-25 02:40:06 +00:00
if ( m_comm . SendRequestResume ( ) )
2012-09-21 16:31:20 +00:00
{
m_async_broadcaster . BroadcastEvent ( eBroadcastBitAsyncContinue ) ;
SetPrivateState ( eStateRunning ) ;
}
else
error . SetErrorString ( " KDP resume failed " ) ;
}
2012-09-21 01:55:30 +00:00
else
2012-09-21 16:31:20 +00:00
{
2012-09-25 02:40:06 +00:00
error . SetErrorString ( " kernel thread is suspended " ) ;
2012-09-21 16:31:20 +00:00
}
2011-07-15 03:27:12 +00:00
return error ;
}
2012-09-25 02:40:06 +00:00
lldb : : ThreadSP
2013-05-07 18:35:34 +00:00
ProcessKDP : : GetKernelThread ( )
2012-09-25 02:40:06 +00:00
{
// KDP only tells us about one thread/core. Any other threads will usually
// be the ones that are read from memory by the OS plug-ins.
2013-05-07 18:35:34 +00:00
ThreadSP thread_sp ( m_kernel_thread_wp . lock ( ) ) ;
2012-09-25 02:40:06 +00:00
if ( ! thread_sp )
2013-05-07 18:35:34 +00:00
{
thread_sp . reset ( new ThreadKDP ( * this , g_kernel_tid ) ) ;
m_kernel_thread_wp = thread_sp ;
}
2012-09-25 02:40:06 +00:00
return thread_sp ;
}
2012-04-10 00:18:59 +00:00
bool
2011-08-22 02:49:39 +00:00
ProcessKDP : : UpdateThreadList ( ThreadList & old_thread_list , ThreadList & new_thread_list )
2011-07-15 03:27:12 +00:00
{
// locker will keep a mutex locked until it goes out of scope
2013-03-27 23:08:40 +00:00
Log * log ( ProcessKDPLog : : GetLogIfAllCategoriesSet ( KDP_LOG_THREAD ) ) ;
2011-07-15 03:27:12 +00:00
if ( log & & log - > GetMask ( ) . Test ( KDP_LOG_VERBOSE ) )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::%s (pid = % " PRIu64 " ) " , __FUNCTION__ , GetID ( ) ) ;
2011-07-15 03:27:12 +00:00
2013-04-11 22:23:34 +00:00
// Even though there is a CPU mask, it doesn't mean we can see each CPU
2012-09-25 02:40:06 +00:00
// indivudually, there is really only one. Lets call this thread 1.
2013-05-07 18:35:34 +00:00
ThreadSP thread_sp ( old_thread_list . FindThreadByProtocolID ( g_kernel_tid , false ) ) ;
if ( ! thread_sp )
thread_sp = GetKernelThread ( ) ;
new_thread_list . AddThread ( thread_sp ) ;
2012-09-25 02:40:06 +00:00
2012-04-10 00:18:59 +00:00
return new_thread_list . GetSize ( false ) > 0 ;
2011-07-15 03:27:12 +00:00
}
void
ProcessKDP : : RefreshStateAfterStop ( )
{
// Let all threads recover from stopping and do any clean up based
// on the previous thread state (if any).
m_thread_list . RefreshStateAfterStop ( ) ;
}
Error
ProcessKDP : : DoHalt ( bool & caused_stop )
{
Error error ;
2012-09-25 02:40:06 +00:00
if ( m_comm . IsRunning ( ) )
2011-07-15 03:27:12 +00:00
{
2012-09-25 02:40:06 +00:00
if ( m_destroy_in_process )
2011-07-15 03:27:12 +00:00
{
2012-09-25 02:40:06 +00:00
// If we are attemping to destroy, we need to not return an error to
// Halt or DoDestroy won't get called.
// We are also currently running, so send a process stopped event
SetPrivateState ( eStateStopped ) ;
2011-07-15 03:27:12 +00:00
}
2012-09-25 02:40:06 +00:00
else
2011-07-15 03:27:12 +00:00
{
2012-09-25 02:40:06 +00:00
error . SetErrorString ( " KDP cannot interrupt a running kernel " ) ;
2011-07-15 03:27:12 +00:00
}
}
return error ;
}
Error
2013-05-02 00:27:30 +00:00
ProcessKDP : : DoDetach ( bool keep_stopped )
2011-07-15 03:27:12 +00:00
{
Error error ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessKDPLog : : GetLogIfAllCategoriesSet ( KDP_LOG_PROCESS ) ) ;
2011-07-15 03:27:12 +00:00
if ( log )
2013-05-02 00:27:30 +00:00
log - > Printf ( " ProcessKDP::DoDetach(keep_stopped = %i) " , keep_stopped ) ;
2011-07-15 03:27:12 +00:00
2012-09-25 02:40:06 +00:00
if ( m_comm . IsRunning ( ) )
2011-07-15 03:27:12 +00:00
{
2012-09-25 02:40:06 +00:00
// We are running and we can't interrupt a running kernel, so we need
// to just close the connection to the kernel and hope for the best
}
else
{
DisableAllBreakpointSites ( ) ;
m_thread_list . DiscardThreadPlans ( ) ;
2013-05-02 00:27:30 +00:00
// If we are going to keep the target stopped, then don't send the disconnect message.
if ( ! keep_stopped & & m_comm . IsConnected ( ) )
2011-07-17 20:36:25 +00:00
{
2013-05-09 01:55:29 +00:00
const bool success = m_comm . SendRequestDisconnect ( ) ;
2012-09-25 02:40:06 +00:00
if ( log )
{
2013-05-09 01:55:29 +00:00
if ( success )
log - > PutCString ( " ProcessKDP::DoDetach() detach packet sent successfully " ) ;
2012-09-25 02:40:06 +00:00
else
2013-05-09 00:05:35 +00:00
log - > PutCString ( " ProcessKDP::DoDetach() connection channel shutdown failed " ) ;
2012-09-25 02:40:06 +00:00
}
2013-05-09 01:55:29 +00:00
m_comm . Disconnect ( ) ;
2011-07-17 20:36:25 +00:00
}
2011-07-15 03:27:12 +00:00
}
2012-09-25 02:40:06 +00:00
StopAsyncThread ( ) ;
2012-01-31 04:56:17 +00:00
m_comm . Clear ( ) ;
2011-07-15 03:27:12 +00:00
SetPrivateState ( eStateDetached ) ;
ResumePrivateStateThread ( ) ;
//KillDebugserverProcess ();
return error ;
}
Error
ProcessKDP : : DoDestroy ( )
{
2012-09-21 16:31:20 +00:00
// For KDP there really is no difference between destroy and detach
2013-05-02 00:27:30 +00:00
bool keep_stopped = false ;
return DoDetach ( keep_stopped ) ;
2011-07-15 03:27:12 +00:00
}
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
bool
ProcessKDP : : IsAlive ( )
{
return m_comm . IsConnected ( ) & & m_private_state . GetValue ( ) ! = eStateExited ;
}
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
size_t
ProcessKDP : : DoReadMemory ( addr_t addr , void * buf , size_t size , Error & error )
{
2011-07-19 03:57:15 +00:00
if ( m_comm . IsConnected ( ) )
return m_comm . SendRequestReadMemory ( addr , buf , size , error ) ;
error . SetErrorString ( " not connected " ) ;
2011-07-15 03:27:12 +00:00
return 0 ;
}
size_t
ProcessKDP : : DoWriteMemory ( addr_t addr , const void * buf , size_t size , Error & error )
{
2012-09-21 16:31:20 +00:00
if ( m_comm . IsConnected ( ) )
return m_comm . SendRequestWriteMemory ( addr , buf , size , error ) ;
error . SetErrorString ( " not connected " ) ;
2011-07-15 03:27:12 +00:00
return 0 ;
}
lldb : : addr_t
ProcessKDP : : DoAllocateMemory ( size_t size , uint32_t permissions , Error & error )
{
error . SetErrorString ( " memory allocation not suppported in kdp remote debugging " ) ;
return LLDB_INVALID_ADDRESS ;
}
Error
ProcessKDP : : DoDeallocateMemory ( lldb : : addr_t addr )
{
Error error ;
error . SetErrorString ( " memory deallocation not suppported in kdp remote debugging " ) ;
return error ;
}
Error
2013-02-15 02:06:30 +00:00
ProcessKDP : : EnableBreakpointSite ( BreakpointSite * bp_site )
2011-07-15 03:27:12 +00:00
{
2011-07-20 03:41:06 +00:00
if ( m_comm . LocalBreakpointsAreSupported ( ) )
{
Error error ;
2011-07-21 01:12:01 +00:00
if ( ! bp_site - > IsEnabled ( ) )
{
if ( m_comm . SendRequestBreakpoint ( true , bp_site - > GetLoadAddress ( ) ) )
{
bp_site - > SetEnabled ( true ) ;
bp_site - > SetType ( BreakpointSite : : eExternal ) ;
}
else
{
error . SetErrorString ( " KDP set breakpoint failed " ) ;
}
}
2011-07-20 03:41:06 +00:00
return error ;
}
2011-07-15 03:27:12 +00:00
return EnableSoftwareBreakpoint ( bp_site ) ;
}
Error
2013-02-15 02:06:30 +00:00
ProcessKDP : : DisableBreakpointSite ( BreakpointSite * bp_site )
2011-07-15 03:27:12 +00:00
{
2011-07-20 03:41:06 +00:00
if ( m_comm . LocalBreakpointsAreSupported ( ) )
{
Error error ;
2011-07-21 01:12:01 +00:00
if ( bp_site - > IsEnabled ( ) )
{
BreakpointSite : : Type bp_type = bp_site - > GetType ( ) ;
if ( bp_type = = BreakpointSite : : eExternal )
{
2012-09-25 02:40:06 +00:00
if ( m_destroy_in_process & & m_comm . IsRunning ( ) )
{
// We are trying to destroy our connection and we are running
2011-07-21 01:12:01 +00:00
bp_site - > SetEnabled ( false ) ;
2012-09-25 02:40:06 +00:00
}
2011-07-21 01:12:01 +00:00
else
2012-09-25 02:40:06 +00:00
{
if ( m_comm . SendRequestBreakpoint ( false , bp_site - > GetLoadAddress ( ) ) )
bp_site - > SetEnabled ( false ) ;
else
error . SetErrorString ( " KDP remove breakpoint failed " ) ;
}
2011-07-21 01:12:01 +00:00
}
else
{
error = DisableSoftwareBreakpoint ( bp_site ) ;
}
}
2011-07-20 03:41:06 +00:00
return error ;
}
2011-07-15 03:27:12 +00:00
return DisableSoftwareBreakpoint ( bp_site ) ;
}
Error
2012-12-18 02:03:49 +00:00
ProcessKDP : : EnableWatchpoint ( Watchpoint * wp , bool notify )
2011-07-15 03:27:12 +00:00
{
Error error ;
error . SetErrorString ( " watchpoints are not suppported in kdp remote debugging " ) ;
return error ;
}
Error
2012-12-18 02:03:49 +00:00
ProcessKDP : : DisableWatchpoint ( Watchpoint * wp , bool notify )
2011-07-15 03:27:12 +00:00
{
Error error ;
error . SetErrorString ( " watchpoints are not suppported in kdp remote debugging " ) ;
return error ;
}
void
ProcessKDP : : Clear ( )
{
m_thread_list . Clear ( ) ;
}
Error
ProcessKDP : : DoSignal ( int signo )
{
Error error ;
error . SetErrorString ( " sending signals is not suppported in kdp remote debugging " ) ;
return error ;
}
void
ProcessKDP : : Initialize ( )
{
static bool g_initialized = false ;
if ( g_initialized = = false )
{
g_initialized = true ;
PluginManager : : RegisterPlugin ( GetPluginNameStatic ( ) ,
GetPluginDescriptionStatic ( ) ,
2013-07-15 22:54:20 +00:00
CreateInstance ,
DebuggerInitialize ) ;
2011-07-15 03:27:12 +00:00
Log : : Callbacks log_callbacks = {
ProcessKDPLog : : DisableLog ,
ProcessKDPLog : : EnableLog ,
ProcessKDPLog : : ListLogCategories
} ;
Log : : RegisterLogChannel ( ProcessKDP : : GetPluginNameStatic ( ) , log_callbacks ) ;
}
}
2013-07-15 22:54:20 +00:00
void
ProcessKDP : : DebuggerInitialize ( lldb_private : : Debugger & debugger )
{
if ( ! PluginManager : : GetSettingForProcessPlugin ( debugger , PluginProperties : : GetSettingName ( ) ) )
{
const bool is_global_setting = true ;
PluginManager : : CreateSettingForProcessPlugin ( debugger ,
GetGlobalPluginProperties ( ) - > GetValueProperties ( ) ,
ConstString ( " Properties for the kdp-remote process plug-in. " ) ,
is_global_setting ) ;
}
}
2011-07-15 03:27:12 +00:00
bool
ProcessKDP : : StartAsyncThread ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( ProcessKDPLog : : GetLogIfAllCategoriesSet ( KDP_LOG_PROCESS ) ) ;
2011-07-15 03:27:12 +00:00
if ( log )
2012-09-21 16:31:20 +00:00
log - > Printf ( " ProcessKDP::StartAsyncThread () " ) ;
2011-07-15 03:27:12 +00:00
2012-09-21 16:31:20 +00:00
if ( IS_VALID_LLDB_HOST_THREAD ( m_async_thread ) )
return true ;
2011-07-15 03:27:12 +00:00
m_async_thread = Host : : ThreadCreate ( " <lldb.process.kdp-remote.async> " , ProcessKDP : : AsyncThread , this , NULL ) ;
return IS_VALID_LLDB_HOST_THREAD ( m_async_thread ) ;
}
void
ProcessKDP : : StopAsyncThread ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( ProcessKDPLog : : GetLogIfAllCategoriesSet ( KDP_LOG_PROCESS ) ) ;
2011-07-15 03:27:12 +00:00
if ( log )
2012-09-21 16:31:20 +00:00
log - > Printf ( " ProcessKDP::StopAsyncThread () " ) ;
2011-07-15 03:27:12 +00:00
m_async_broadcaster . BroadcastEvent ( eBroadcastBitAsyncThreadShouldExit ) ;
// Stop the stdio thread
if ( IS_VALID_LLDB_HOST_THREAD ( m_async_thread ) )
{
Host : : ThreadJoin ( m_async_thread , NULL , NULL ) ;
2012-09-21 16:31:20 +00:00
m_async_thread = LLDB_INVALID_HOST_THREAD ;
2011-07-15 03:27:12 +00:00
}
}
void *
ProcessKDP : : AsyncThread ( void * arg )
{
ProcessKDP * process = ( ProcessKDP * ) arg ;
2012-09-21 16:31:20 +00:00
const lldb : : pid_t pid = process - > GetID ( ) ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessKDPLog : : GetLogIfAllCategoriesSet ( KDP_LOG_PROCESS ) ) ;
2011-07-15 03:27:12 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::AsyncThread (arg = %p, pid = % " PRIu64 " ) thread starting... " , arg , pid ) ;
2011-07-15 03:27:12 +00:00
Listener listener ( " ProcessKDP::AsyncThread " ) ;
EventSP event_sp ;
const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
eBroadcastBitAsyncThreadShouldExit ;
2012-09-21 16:31:20 +00:00
2011-07-15 03:27:12 +00:00
if ( listener . StartListeningForEvents ( & process - > m_async_broadcaster , desired_event_mask ) = = desired_event_mask )
{
bool done = false ;
while ( ! done )
{
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::AsyncThread (pid = % " PRIu64 " ) listener.WaitForEvent (NULL, event_sp)... " ,
2012-09-21 16:31:20 +00:00
pid ) ;
2011-07-15 03:27:12 +00:00
if ( listener . WaitForEvent ( NULL , event_sp ) )
{
2012-09-21 16:31:20 +00:00
uint32_t event_type = event_sp - > GetType ( ) ;
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::AsyncThread (pid = % " PRIu64 " ) Got an event of type: %d... " ,
2012-09-21 16:31:20 +00:00
pid ,
event_type ) ;
// When we are running, poll for 1 second to try and get an exception
// to indicate the process has stopped. If we don't get one, check to
// make sure no one asked us to exit
bool is_running = false ;
DataExtractor exc_reply_packet ;
do
2011-07-15 03:27:12 +00:00
{
switch ( event_type )
{
2012-09-21 16:31:20 +00:00
case eBroadcastBitAsyncContinue :
2011-07-15 03:27:12 +00:00
{
2012-09-21 16:31:20 +00:00
is_running = true ;
if ( process - > m_comm . WaitForPacketWithTimeoutMicroSeconds ( exc_reply_packet , 1 * USEC_PER_SEC ) )
2011-07-15 03:27:12 +00:00
{
2013-05-07 18:35:34 +00:00
ThreadSP thread_sp ( process - > GetKernelThread ( ) ) ;
2013-04-02 20:32:37 +00:00
if ( thread_sp )
{
lldb : : RegisterContextSP reg_ctx_sp ( thread_sp - > GetRegisterContext ( ) ) ;
if ( reg_ctx_sp )
reg_ctx_sp - > InvalidateAllRegisters ( ) ;
static_cast < ThreadKDP * > ( thread_sp . get ( ) ) - > SetStopInfoFrom_KDP_EXCEPTION ( exc_reply_packet ) ;
}
2012-09-25 02:40:06 +00:00
2012-09-21 16:31:20 +00:00
// TODO: parse the stop reply packet
2012-09-25 02:40:06 +00:00
is_running = false ;
2012-09-21 16:31:20 +00:00
process - > SetPrivateState ( eStateStopped ) ;
}
else
{
// Check to see if we are supposed to exit. There is no way to
// interrupt a running kernel, so all we can do is wait for an
// exception or detach...
if ( listener . GetNextEvent ( event_sp ) )
{
// We got an event, go through the loop again
event_type = event_sp - > GetType ( ) ;
}
2011-07-15 03:27:12 +00:00
}
}
2012-09-21 16:31:20 +00:00
break ;
2011-07-15 03:27:12 +00:00
2012-09-21 16:31:20 +00:00
case eBroadcastBitAsyncThreadShouldExit :
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::AsyncThread (pid = % " PRIu64 " ) got eBroadcastBitAsyncThreadShouldExit... " ,
2012-09-21 16:31:20 +00:00
pid ) ;
2011-07-15 03:27:12 +00:00
done = true ;
2012-09-21 16:31:20 +00:00
is_running = false ;
break ;
default :
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::AsyncThread (pid = % " PRIu64 " ) got unknown event 0x%8.8x " ,
2012-09-21 16:31:20 +00:00
pid ,
event_type ) ;
done = true ;
is_running = false ;
break ;
2011-07-15 03:27:12 +00:00
}
2012-09-21 16:31:20 +00:00
} while ( is_running ) ;
2011-07-15 03:27:12 +00:00
}
else
{
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::AsyncThread (pid = % " PRIu64 " ) listener.WaitForEvent (NULL, event_sp) => false " ,
2012-09-21 16:31:20 +00:00
pid ) ;
2011-07-15 03:27:12 +00:00
done = true ;
}
}
}
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessKDP::AsyncThread (arg = %p, pid = % " PRIu64 " ) thread exiting... " ,
2012-09-21 16:31:20 +00:00
arg ,
pid ) ;
2011-07-15 03:27:12 +00:00
process - > m_async_thread = LLDB_INVALID_HOST_THREAD ;
return NULL ;
}
2012-10-19 22:22:57 +00:00
class CommandObjectProcessKDPPacketSend : public CommandObjectParsed
{
private :
OptionGroupOptions m_option_group ;
OptionGroupUInt64 m_command_byte ;
OptionGroupString m_packet_data ;
virtual Options *
GetOptions ( )
{
return & m_option_group ;
}
public :
CommandObjectProcessKDPPacketSend ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" process plugin packet send " ,
" Send a custom packet through the KDP protocol by specifying the command byte and the packet payload data. A packet will be sent with a correct header and payload, and the raw result bytes will be displayed as a string value. " ,
NULL ) ,
m_option_group ( interpreter ) ,
m_command_byte ( LLDB_OPT_SET_1 , true , " command " , ' c ' , 0 , eArgTypeNone , " Specify the command byte to use when sending the KDP request packet. " , 0 ) ,
m_packet_data ( LLDB_OPT_SET_1 , false , " payload " , ' p ' , 0 , eArgTypeNone , " Specify packet payload bytes as a hex ASCII string with no spaces or hex prefixes. " , NULL )
{
m_option_group . Append ( & m_command_byte , LLDB_OPT_SET_ALL , LLDB_OPT_SET_1 ) ;
m_option_group . Append ( & m_packet_data , LLDB_OPT_SET_ALL , LLDB_OPT_SET_1 ) ;
m_option_group . Finalize ( ) ;
}
~ CommandObjectProcessKDPPacketSend ( )
{
}
bool
DoExecute ( Args & command , CommandReturnObject & result )
{
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc = = 0 )
{
if ( ! m_command_byte . GetOptionValue ( ) . OptionWasSet ( ) )
{
result . AppendError ( " the --command option must be set to a valid command byte " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
else
{
const uint64_t command_byte = m_command_byte . GetOptionValue ( ) . GetUInt64Value ( 0 ) ;
if ( command_byte > 0 & & command_byte < = UINT8_MAX )
{
ProcessKDP * process = ( ProcessKDP * ) m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
if ( process )
{
const StateType state = process - > GetState ( ) ;
if ( StateIsStoppedState ( state , true ) )
{
std : : vector < uint8_t > payload_bytes ;
const char * ascii_hex_bytes_cstr = m_packet_data . GetOptionValue ( ) . GetCurrentValue ( ) ;
if ( ascii_hex_bytes_cstr & & ascii_hex_bytes_cstr [ 0 ] )
{
StringExtractor extractor ( ascii_hex_bytes_cstr ) ;
const size_t ascii_hex_bytes_cstr_len = extractor . GetStringRef ( ) . size ( ) ;
if ( ascii_hex_bytes_cstr_len & 1 )
{
result . AppendErrorWithFormat ( " payload data must contain an even number of ASCII hex characters: '%s' " , ascii_hex_bytes_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
payload_bytes . resize ( ascii_hex_bytes_cstr_len / 2 ) ;
if ( extractor . GetHexBytes ( & payload_bytes [ 0 ] , payload_bytes . size ( ) , ' \xdd ' ) ! = payload_bytes . size ( ) )
{
result . AppendErrorWithFormat ( " payload data must only contain ASCII hex characters (no spaces or hex prefixes): '%s' " , ascii_hex_bytes_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
Error error ;
DataExtractor reply ;
process - > GetCommunication ( ) . SendRawRequest ( command_byte ,
payload_bytes . empty ( ) ? NULL : payload_bytes . data ( ) ,
payload_bytes . size ( ) ,
reply ,
error ) ;
if ( error . Success ( ) )
{
// Copy the binary bytes into a hex ASCII string for the result
StreamString packet ;
packet . PutBytesAsRawHex8 ( reply . GetDataStart ( ) ,
reply . GetByteSize ( ) ,
lldb : : endian : : InlHostByteOrder ( ) ,
lldb : : endian : : InlHostByteOrder ( ) ) ;
result . AppendMessage ( packet . GetString ( ) . c_str ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return true ;
}
else
{
const char * error_cstr = error . AsCString ( ) ;
if ( error_cstr & & error_cstr [ 0 ] )
result . AppendError ( error_cstr ) ;
else
result . AppendErrorWithFormat ( " unknown error 0x%8.8x " , error . GetError ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else
{
result . AppendErrorWithFormat ( " process must be stopped in order to send KDP packets, state is %s " , StateAsCString ( state ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
result . AppendError ( " invalid process " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
2012-11-29 21:49:15 +00:00
result . AppendErrorWithFormat ( " invalid command byte 0x% " PRIx64 " , valid values are 1 - 255 " , command_byte ) ;
2012-10-19 22:22:57 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
}
}
}
else
{
result . AppendErrorWithFormat ( " '%s' takes no arguments, only options. " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return false ;
}
} ;
class CommandObjectProcessKDPPacket : public CommandObjectMultiword
{
private :
public :
CommandObjectProcessKDPPacket ( CommandInterpreter & interpreter ) :
CommandObjectMultiword ( interpreter ,
" process plugin packet " ,
" Commands that deal with KDP remote packets. " ,
NULL )
{
LoadSubCommand ( " send " , CommandObjectSP ( new CommandObjectProcessKDPPacketSend ( interpreter ) ) ) ;
}
~ CommandObjectProcessKDPPacket ( )
{
}
} ;
class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword
{
public :
CommandObjectMultiwordProcessKDP ( CommandInterpreter & interpreter ) :
CommandObjectMultiword ( interpreter ,
" process plugin " ,
" A set of commands for operating on a ProcessKDP process. " ,
" process plugin <subcommand> [<subcommand-options>] " )
{
LoadSubCommand ( " packet " , CommandObjectSP ( new CommandObjectProcessKDPPacket ( interpreter ) ) ) ;
}
~ CommandObjectMultiwordProcessKDP ( )
{
}
} ;
CommandObject *
ProcessKDP : : GetPluginCommandObject ( )
{
if ( ! m_command_sp )
m_command_sp . reset ( new CommandObjectMultiwordProcessKDP ( GetTarget ( ) . GetDebugger ( ) . GetCommandInterpreter ( ) ) ) ;
return m_command_sp . get ( ) ;
}