2013-08-23 13:46:38 -04:00
//===-- Process.cpp ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "lldb/Target/Process.h"
# include "lldb/Breakpoint/StoppointCallbackContext.h"
# include "lldb/Breakpoint/BreakpointLocation.h"
# include "lldb/Core/Event.h"
# include "lldb/Core/Debugger.h"
# include "lldb/Core/Log.h"
# include "lldb/Core/Module.h"
2015-07-03 12:57:06 -04:00
# include "lldb/Core/ModuleSpec.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/PluginManager.h"
# include "lldb/Core/State.h"
2014-02-18 11:23:10 -05:00
# include "lldb/Core/StreamFile.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Expression/ClangUserExpression.h"
2015-07-03 12:57:06 -04:00
# include "lldb/Expression/IRDynamicChecks.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Host/ConnectionFileDescriptor.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Host.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Host/HostInfo.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Host/Pipe.h"
2014-02-18 11:23:10 -05:00
# include "lldb/Host/Terminal.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Host/ThreadLauncher.h"
# include "lldb/Interpreter/CommandInterpreter.h"
2015-07-03 12:57:06 -04:00
# include "lldb/Interpreter/OptionValueProperties.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Symbol/Symbol.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/ABI.h"
# include "lldb/Target/DynamicLoader.h"
2015-07-03 12:57:06 -04:00
# include "lldb/Target/InstrumentationRuntime.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Target/JITLoader.h"
2015-07-03 12:57:06 -04:00
# include "lldb/Target/JITLoaderList.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Target/MemoryHistory.h"
2015-07-03 12:57:06 -04:00
# include "lldb/Target/MemoryRegionInfo.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/OperatingSystem.h"
# include "lldb/Target/LanguageRuntime.h"
# include "lldb/Target/CPPLanguageRuntime.h"
# include "lldb/Target/ObjCLanguageRuntime.h"
# include "lldb/Target/Platform.h"
# include "lldb/Target/RegisterContext.h"
# include "lldb/Target/StopInfo.h"
2013-11-06 11:48:53 -05:00
# include "lldb/Target/SystemRuntime.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/Target.h"
# include "lldb/Target/TargetList.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/ThreadPlan.h"
# include "lldb/Target/ThreadPlanBase.h"
2015-07-03 12:57:06 -04:00
# include "lldb/Target/UnixSignals.h"
# include "lldb/Utility/NameMatches.h"
2014-02-18 11:23:10 -05:00
# include "Plugins/Process/Utility/InferiorCallPOSIX.h"
2013-08-23 13:46:38 -04:00
using namespace lldb ;
using namespace lldb_private ;
// Comment out line below to disable memory caching, overriding the process setting
// target.process.disable-memory-cache
# define ENABLE_MEMORY_CACHING
# ifdef ENABLE_MEMORY_CACHING
# define DISABLE_MEM_CACHE_DEFAULT false
# else
# define DISABLE_MEM_CACHE_DEFAULT true
# endif
class ProcessOptionValueProperties : public OptionValueProperties
{
public :
ProcessOptionValueProperties ( const ConstString & name ) :
OptionValueProperties ( name )
{
}
// This constructor is used when creating ProcessOptionValueProperties when it
// is part of a new lldb_private::Process instance. It will copy all current
// global property values as needed
ProcessOptionValueProperties ( ProcessProperties * global_properties ) :
OptionValueProperties ( * global_properties - > GetValueProperties ( ) )
{
}
virtual const Property *
GetPropertyAtIndex ( const ExecutionContext * exe_ctx , bool will_modify , uint32_t idx ) const
{
2014-11-25 16:00:58 -05:00
// When getting the value for a key from the process options, we will always
2013-08-23 13:46:38 -04:00
// try and grab the setting from the current process if there is one. Else we just
// use the one from this instance.
if ( exe_ctx )
{
Process * process = exe_ctx - > GetProcessPtr ( ) ;
if ( process )
{
ProcessOptionValueProperties * instance_properties = static_cast < ProcessOptionValueProperties * > ( process - > GetValueProperties ( ) . get ( ) ) ;
if ( this ! = instance_properties )
return instance_properties - > ProtectedGetPropertyAtIndex ( idx ) ;
}
}
return ProtectedGetPropertyAtIndex ( idx ) ;
}
} ;
static PropertyDefinition
g_properties [ ] =
{
{ " disable-memory-cache " , OptionValue : : eTypeBoolean , false , DISABLE_MEM_CACHE_DEFAULT , NULL , NULL , " Disable reading and caching of memory in fixed-size units. " } ,
{ " extra-startup-command " , OptionValue : : eTypeArray , false , OptionValue : : eTypeString , NULL , NULL , " A list containing extra commands understood by the particular process plugin used. "
" For instance, to turn on debugserver logging set this to \" QSetLogging:bitmask=LOG_DEFAULT; \" " } ,
{ " ignore-breakpoints-in-expressions " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " If true, breakpoints will be ignored during expression evaluation. " } ,
{ " unwind-on-error-in-expressions " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " If true, errors in expression evaluation will unwind the stack back to the state before the call. " } ,
{ " python-os-plugin-path " , OptionValue : : eTypeFileSpec , false , true , NULL , NULL , " A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class. " } ,
{ " stop-on-sharedlibrary-events " , OptionValue : : eTypeBoolean , true , false , NULL , NULL , " If true, stop when a shared library is loaded or unloaded. " } ,
{ " detach-keeps-stopped " , OptionValue : : eTypeBoolean , true , false , NULL , NULL , " If true, detach will attempt to keep the process stopped. " } ,
2015-02-06 16:38:51 -05:00
{ " memory-cache-line-size " , OptionValue : : eTypeUInt64 , false , 512 , NULL , NULL , " The memory cache line size " } ,
2013-08-23 13:46:38 -04:00
{ NULL , OptionValue : : eTypeInvalid , false , 0 , NULL , NULL , NULL }
} ;
enum {
ePropertyDisableMemCache ,
ePropertyExtraStartCommand ,
ePropertyIgnoreBreakpointsInExpressions ,
ePropertyUnwindOnErrorInExpressions ,
ePropertyPythonOSPluginPath ,
ePropertyStopOnSharedLibraryEvents ,
2015-02-06 16:38:51 -05:00
ePropertyDetachKeepsStopped ,
ePropertyMemCacheLineSize
2013-08-23 13:46:38 -04:00
} ;
2015-02-06 16:38:51 -05:00
ProcessProperties : : ProcessProperties ( lldb_private : : Process * process ) :
Properties ( ) ,
m_process ( process ) // Can be NULL for global ProcessProperties
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
if ( process = = NULL )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
// Global process properties, set them up one time
2013-08-23 13:46:38 -04:00
m_collection_sp . reset ( new ProcessOptionValueProperties ( ConstString ( " process " ) ) ) ;
m_collection_sp - > Initialize ( g_properties ) ;
m_collection_sp - > AppendProperty ( ConstString ( " thread " ) ,
ConstString ( " Settings specific to threads. " ) ,
true ,
Thread : : GetGlobalProperties ( ) - > GetValueProperties ( ) ) ;
}
else
2015-02-06 16:38:51 -05:00
{
2013-08-23 13:46:38 -04:00
m_collection_sp . reset ( new ProcessOptionValueProperties ( Process : : GetGlobalProperties ( ) . get ( ) ) ) ;
2015-02-06 16:38:51 -05:00
m_collection_sp - > SetValueChangedCallback ( ePropertyPythonOSPluginPath , ProcessProperties : : OptionValueChangedCallback , this ) ;
}
2013-08-23 13:46:38 -04:00
}
ProcessProperties : : ~ ProcessProperties ( )
{
}
2015-02-06 16:38:51 -05:00
void
ProcessProperties : : OptionValueChangedCallback ( void * baton , OptionValue * option_value )
{
ProcessProperties * properties = ( ProcessProperties * ) baton ;
if ( properties - > m_process )
properties - > m_process - > LoadOperatingSystemPlugin ( true ) ;
}
2013-08-23 13:46:38 -04:00
bool
ProcessProperties : : GetDisableMemoryCache ( ) const
{
const uint32_t idx = ePropertyDisableMemCache ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
2015-02-06 16:38:51 -05:00
uint64_t
ProcessProperties : : GetMemoryCacheLineSize ( ) const
{
const uint32_t idx = ePropertyMemCacheLineSize ;
return m_collection_sp - > GetPropertyAtIndexAsUInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
}
2013-08-23 13:46:38 -04:00
Args
ProcessProperties : : GetExtraStartupCommands ( ) const
{
Args args ;
const uint32_t idx = ePropertyExtraStartCommand ;
m_collection_sp - > GetPropertyAtIndexAsArgs ( NULL , idx , args ) ;
return args ;
}
void
ProcessProperties : : SetExtraStartupCommands ( const Args & args )
{
const uint32_t idx = ePropertyExtraStartCommand ;
m_collection_sp - > SetPropertyAtIndexFromArgs ( NULL , idx , args ) ;
}
FileSpec
ProcessProperties : : GetPythonOSPluginPath ( ) const
{
const uint32_t idx = ePropertyPythonOSPluginPath ;
return m_collection_sp - > GetPropertyAtIndexAsFileSpec ( NULL , idx ) ;
}
void
ProcessProperties : : SetPythonOSPluginPath ( const FileSpec & file )
{
const uint32_t idx = ePropertyPythonOSPluginPath ;
m_collection_sp - > SetPropertyAtIndexAsFileSpec ( NULL , idx , file ) ;
}
bool
ProcessProperties : : GetIgnoreBreakpointsInExpressions ( ) const
{
const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
void
ProcessProperties : : SetIgnoreBreakpointsInExpressions ( bool ignore )
{
const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions ;
m_collection_sp - > SetPropertyAtIndexAsBoolean ( NULL , idx , ignore ) ;
}
bool
ProcessProperties : : GetUnwindOnErrorInExpressions ( ) const
{
const uint32_t idx = ePropertyUnwindOnErrorInExpressions ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
void
ProcessProperties : : SetUnwindOnErrorInExpressions ( bool ignore )
{
const uint32_t idx = ePropertyUnwindOnErrorInExpressions ;
m_collection_sp - > SetPropertyAtIndexAsBoolean ( NULL , idx , ignore ) ;
}
bool
ProcessProperties : : GetStopOnSharedLibraryEvents ( ) const
{
const uint32_t idx = ePropertyStopOnSharedLibraryEvents ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
void
ProcessProperties : : SetStopOnSharedLibraryEvents ( bool stop )
{
const uint32_t idx = ePropertyStopOnSharedLibraryEvents ;
m_collection_sp - > SetPropertyAtIndexAsBoolean ( NULL , idx , stop ) ;
}
bool
ProcessProperties : : GetDetachKeepsStopped ( ) const
{
const uint32_t idx = ePropertyDetachKeepsStopped ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
void
ProcessProperties : : SetDetachKeepsStopped ( bool stop )
{
const uint32_t idx = ePropertyDetachKeepsStopped ;
m_collection_sp - > SetPropertyAtIndexAsBoolean ( NULL , idx , stop ) ;
}
void
ProcessInstanceInfo : : Dump ( Stream & s , Platform * platform ) const
{
const char * cstr ;
if ( m_pid ! = LLDB_INVALID_PROCESS_ID )
s . Printf ( " pid = % " PRIu64 " \n " , m_pid ) ;
if ( m_parent_pid ! = LLDB_INVALID_PROCESS_ID )
s . Printf ( " parent = % " PRIu64 " \n " , m_parent_pid ) ;
if ( m_executable )
{
s . Printf ( " name = %s \n " , m_executable . GetFilename ( ) . GetCString ( ) ) ;
s . PutCString ( " file = " ) ;
m_executable . Dump ( & s ) ;
s . EOL ( ) ;
}
const uint32_t argc = m_arguments . GetArgumentCount ( ) ;
if ( argc > 0 )
{
for ( uint32_t i = 0 ; i < argc ; i + + )
{
const char * arg = m_arguments . GetArgumentAtIndex ( i ) ;
if ( i < 10 )
s . Printf ( " arg[%u] = %s \n " , i , arg ) ;
else
s . Printf ( " arg[%u] = %s \n " , i , arg ) ;
}
}
const uint32_t envc = m_environment . GetArgumentCount ( ) ;
if ( envc > 0 )
{
for ( uint32_t i = 0 ; i < envc ; i + + )
{
const char * env = m_environment . GetArgumentAtIndex ( i ) ;
if ( i < 10 )
s . Printf ( " env[%u] = %s \n " , i , env ) ;
else
s . Printf ( " env[%u] = %s \n " , i , env ) ;
}
}
if ( m_arch . IsValid ( ) )
s . Printf ( " arch = %s \n " , m_arch . GetTriple ( ) . str ( ) . c_str ( ) ) ;
if ( m_uid ! = UINT32_MAX )
{
cstr = platform - > GetUserName ( m_uid ) ;
s . Printf ( " uid = %-5u (%s) \n " , m_uid , cstr ? cstr : " " ) ;
}
if ( m_gid ! = UINT32_MAX )
{
cstr = platform - > GetGroupName ( m_gid ) ;
s . Printf ( " gid = %-5u (%s) \n " , m_gid , cstr ? cstr : " " ) ;
}
if ( m_euid ! = UINT32_MAX )
{
cstr = platform - > GetUserName ( m_euid ) ;
s . Printf ( " euid = %-5u (%s) \n " , m_euid , cstr ? cstr : " " ) ;
}
if ( m_egid ! = UINT32_MAX )
{
cstr = platform - > GetGroupName ( m_egid ) ;
s . Printf ( " egid = %-5u (%s) \n " , m_egid , cstr ? cstr : " " ) ;
}
}
void
ProcessInstanceInfo : : DumpTableHeader ( Stream & s , Platform * platform , bool show_args , bool verbose )
{
const char * label ;
if ( show_args | | verbose )
label = " ARGUMENTS " ;
else
label = " NAME " ;
if ( verbose )
{
s . Printf ( " PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE %s \n " , label ) ;
s . PutCString ( " ====== ====== ========== ========== ========== ========== ======================== ============================ \n " ) ;
}
else
{
2014-11-25 16:00:58 -05:00
s . Printf ( " PID PARENT USER TRIPLE %s \n " , label ) ;
s . PutCString ( " ====== ====== ========== ======================== ============================ \n " ) ;
2013-08-23 13:46:38 -04:00
}
}
void
ProcessInstanceInfo : : DumpAsTableRow ( Stream & s , Platform * platform , bool show_args , bool verbose ) const
{
if ( m_pid ! = LLDB_INVALID_PROCESS_ID )
{
const char * cstr ;
s . Printf ( " %-6 " PRIu64 " %-6 " PRIu64 " " , m_pid , m_parent_pid ) ;
if ( verbose )
{
cstr = platform - > GetUserName ( m_uid ) ;
if ( cstr & & cstr [ 0 ] ) // Watch for empty string that indicates lookup failed
s . Printf ( " %-10s " , cstr ) ;
else
s . Printf ( " %-10u " , m_uid ) ;
cstr = platform - > GetGroupName ( m_gid ) ;
if ( cstr & & cstr [ 0 ] ) // Watch for empty string that indicates lookup failed
s . Printf ( " %-10s " , cstr ) ;
else
s . Printf ( " %-10u " , m_gid ) ;
cstr = platform - > GetUserName ( m_euid ) ;
if ( cstr & & cstr [ 0 ] ) // Watch for empty string that indicates lookup failed
s . Printf ( " %-10s " , cstr ) ;
else
s . Printf ( " %-10u " , m_euid ) ;
cstr = platform - > GetGroupName ( m_egid ) ;
if ( cstr & & cstr [ 0 ] ) // Watch for empty string that indicates lookup failed
s . Printf ( " %-10s " , cstr ) ;
else
s . Printf ( " %-10u " , m_egid ) ;
s . Printf ( " %-24s " , m_arch . IsValid ( ) ? m_arch . GetTriple ( ) . str ( ) . c_str ( ) : " " ) ;
}
else
{
2014-11-25 16:00:58 -05:00
s . Printf ( " %-10s %-24s " ,
2013-08-23 13:46:38 -04:00
platform - > GetUserName ( m_euid ) ,
2014-11-25 16:00:58 -05:00
m_arch . IsValid ( ) ? m_arch . GetTriple ( ) . str ( ) . c_str ( ) : " " ) ;
2013-08-23 13:46:38 -04:00
}
if ( verbose | | show_args )
{
const uint32_t argc = m_arguments . GetArgumentCount ( ) ;
if ( argc > 0 )
{
for ( uint32_t i = 0 ; i < argc ; i + + )
{
if ( i > 0 )
s . PutChar ( ' ' ) ;
s . PutCString ( m_arguments . GetArgumentAtIndex ( i ) ) ;
}
}
}
else
{
s . PutCString ( GetName ( ) ) ;
}
s . EOL ( ) ;
}
}
Error
ProcessLaunchCommandOptions : : SetOptionValue ( uint32_t option_idx , const char * option_arg )
{
Error error ;
const int short_option = m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' s ' : // Stop at program entry point
launch_info . GetFlags ( ) . Set ( eLaunchFlagStopAtEntry ) ;
break ;
case ' i ' : // STDIN for read only
2014-11-25 16:00:58 -05:00
{
FileAction action ;
2015-07-03 12:57:06 -04:00
if ( action . Open ( STDIN_FILENO , FileSpec { option_arg , false } , true , false ) )
2014-11-25 16:00:58 -05:00
launch_info . AppendFileAction ( action ) ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
case ' o ' : // Open STDOUT for write only
2014-11-25 16:00:58 -05:00
{
FileAction action ;
2015-07-03 12:57:06 -04:00
if ( action . Open ( STDOUT_FILENO , FileSpec { option_arg , false } , false , true ) )
2014-11-25 16:00:58 -05:00
launch_info . AppendFileAction ( action ) ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
case ' e ' : // STDERR for write only
2014-11-25 16:00:58 -05:00
{
FileAction action ;
2015-07-03 12:57:06 -04:00
if ( action . Open ( STDERR_FILENO , FileSpec { option_arg , false } , false , true ) )
2014-11-25 16:00:58 -05:00
launch_info . AppendFileAction ( action ) ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
case ' p ' : // Process plug-in name
launch_info . SetProcessPluginName ( option_arg ) ;
break ;
case ' n ' : // Disable STDIO
2014-11-25 16:00:58 -05:00
{
FileAction action ;
2015-07-03 12:57:06 -04:00
const FileSpec dev_null { " /dev/null " , false } ;
if ( action . Open ( STDIN_FILENO , dev_null , true , false ) )
2014-11-25 16:00:58 -05:00
launch_info . AppendFileAction ( action ) ;
2015-07-03 12:57:06 -04:00
if ( action . Open ( STDOUT_FILENO , dev_null , false , true ) )
2014-11-25 16:00:58 -05:00
launch_info . AppendFileAction ( action ) ;
2015-07-03 12:57:06 -04:00
if ( action . Open ( STDERR_FILENO , dev_null , false , true ) )
2014-11-25 16:00:58 -05:00
launch_info . AppendFileAction ( action ) ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
case ' w ' :
2015-07-03 12:57:06 -04:00
launch_info . SetWorkingDirectory ( FileSpec { option_arg , false } ) ;
2013-08-23 13:46:38 -04:00
break ;
case ' t ' : // Open process in new terminal window
launch_info . GetFlags ( ) . Set ( eLaunchFlagLaunchInTTY ) ;
break ;
case ' a ' :
if ( ! launch_info . GetArchitecture ( ) . SetTriple ( option_arg , m_interpreter . GetPlatform ( true ) . get ( ) ) )
launch_info . GetArchitecture ( ) . SetTriple ( option_arg ) ;
break ;
2014-11-25 16:00:58 -05:00
case ' A ' : // Disable ASLR.
{
bool success ;
const bool disable_aslr_arg = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( success )
disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo ;
else
error . SetErrorStringWithFormat ( " Invalid boolean value for disable-aslr option: '%s' " , option_arg ? option_arg : " <null> " ) ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
}
2015-07-03 12:57:06 -04:00
case ' X ' : // shell expand args.
{
bool success ;
const bool expand_args = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( success )
launch_info . SetShellExpandArguments ( expand_args ) ;
else
error . SetErrorStringWithFormat ( " Invalid boolean value for shell-expand-args option: '%s' " , option_arg ? option_arg : " <null> " ) ;
break ;
}
2014-11-25 16:00:58 -05:00
case ' c ' :
2013-08-23 13:46:38 -04:00
if ( option_arg & & option_arg [ 0 ] )
2015-02-06 16:38:51 -05:00
launch_info . SetShell ( FileSpec ( option_arg , false ) ) ;
2013-08-23 13:46:38 -04:00
else
2015-02-06 16:38:51 -05:00
launch_info . SetShell ( HostInfo : : GetDefaultShell ( ) ) ;
2013-08-23 13:46:38 -04:00
break ;
case ' v ' :
launch_info . GetEnvironmentEntries ( ) . AppendArgument ( option_arg ) ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized short option character '%c' " , short_option ) ;
break ;
}
return error ;
}
OptionDefinition
ProcessLaunchCommandOptions : : g_option_table [ ] =
{
2014-11-25 16:00:58 -05:00
{ LLDB_OPT_SET_ALL , false , " stop-at-entry " , ' s ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " Stop at the entry point of the program when launching a process. " } ,
{ LLDB_OPT_SET_ALL , false , " disable-aslr " , ' A ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean , " Set whether to disable address space layout randomization when launching a process. " } ,
{ LLDB_OPT_SET_ALL , false , " plugin " , ' p ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypePlugin , " Name of the process plugin you want to use. " } ,
{ LLDB_OPT_SET_ALL , false , " working-dir " , ' w ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeDirectoryName , " Set the current working directory to <path> when running the inferior. " } ,
{ LLDB_OPT_SET_ALL , false , " arch " , ' a ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeArchitecture , " Set the architecture for the process to launch when ambiguous. " } ,
{ LLDB_OPT_SET_ALL , false , " environment " , ' v ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeNone , " Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries. " } ,
2015-07-03 12:57:06 -04:00
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3 , false , " shell " , ' c ' , OptionParser : : eOptionalArgument , NULL , NULL , 0 , eArgTypeFilename , " Run the process in a shell (not supported on all platforms). " } ,
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
{ LLDB_OPT_SET_1 , false , " stdin " , ' i ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeFilename , " Redirect stdin for the process to <filename>. " } ,
{ LLDB_OPT_SET_1 , false , " stdout " , ' o ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeFilename , " Redirect stdout for the process to <filename>. " } ,
{ LLDB_OPT_SET_1 , false , " stderr " , ' e ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeFilename , " Redirect stderr for the process to <filename>. " } ,
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
{ LLDB_OPT_SET_2 , false , " tty " , ' t ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " Start the process in a terminal (not supported on all platforms). " } ,
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
{ LLDB_OPT_SET_3 , false , " no-stdio " , ' n ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " Do not set up for terminal I/O to go to running process. " } ,
2015-07-03 12:57:06 -04:00
{ LLDB_OPT_SET_4 , false , " shell-expand-args " , ' X ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean , " Set whether to shell expand arguments to the process when launching. " } ,
2014-11-25 16:00:58 -05:00
{ 0 , false , NULL , 0 , 0 , NULL , NULL , 0 , eArgTypeNone , NULL }
2013-08-23 13:46:38 -04:00
} ;
bool
ProcessInstanceInfoMatch : : NameMatches ( const char * process_name ) const
{
if ( m_name_match_type = = eNameMatchIgnore | | process_name = = NULL )
return true ;
const char * match_name = m_match_info . GetName ( ) ;
if ( ! match_name )
return true ;
return lldb_private : : NameMatches ( process_name , m_name_match_type , match_name ) ;
}
bool
ProcessInstanceInfoMatch : : Matches ( const ProcessInstanceInfo & proc_info ) const
{
if ( ! NameMatches ( proc_info . GetName ( ) ) )
return false ;
if ( m_match_info . ProcessIDIsValid ( ) & &
m_match_info . GetProcessID ( ) ! = proc_info . GetProcessID ( ) )
return false ;
if ( m_match_info . ParentProcessIDIsValid ( ) & &
m_match_info . GetParentProcessID ( ) ! = proc_info . GetParentProcessID ( ) )
return false ;
if ( m_match_info . UserIDIsValid ( ) & &
m_match_info . GetUserID ( ) ! = proc_info . GetUserID ( ) )
return false ;
if ( m_match_info . GroupIDIsValid ( ) & &
m_match_info . GetGroupID ( ) ! = proc_info . GetGroupID ( ) )
return false ;
if ( m_match_info . EffectiveUserIDIsValid ( ) & &
m_match_info . GetEffectiveUserID ( ) ! = proc_info . GetEffectiveUserID ( ) )
return false ;
if ( m_match_info . EffectiveGroupIDIsValid ( ) & &
m_match_info . GetEffectiveGroupID ( ) ! = proc_info . GetEffectiveGroupID ( ) )
return false ;
if ( m_match_info . GetArchitecture ( ) . IsValid ( ) & &
! m_match_info . GetArchitecture ( ) . IsCompatibleMatch ( proc_info . GetArchitecture ( ) ) )
return false ;
return true ;
}
bool
ProcessInstanceInfoMatch : : MatchAllProcesses ( ) const
{
if ( m_name_match_type ! = eNameMatchIgnore )
return false ;
if ( m_match_info . ProcessIDIsValid ( ) )
return false ;
if ( m_match_info . ParentProcessIDIsValid ( ) )
return false ;
if ( m_match_info . UserIDIsValid ( ) )
return false ;
if ( m_match_info . GroupIDIsValid ( ) )
return false ;
if ( m_match_info . EffectiveUserIDIsValid ( ) )
return false ;
if ( m_match_info . EffectiveGroupIDIsValid ( ) )
return false ;
if ( m_match_info . GetArchitecture ( ) . IsValid ( ) )
return false ;
if ( m_match_all_users )
return false ;
return true ;
}
void
ProcessInstanceInfoMatch : : Clear ( )
{
m_match_info . Clear ( ) ;
m_name_match_type = eNameMatchIgnore ;
m_match_all_users = false ;
}
ProcessSP
Process : : FindPlugin ( Target & target , const char * plugin_name , Listener & listener , const FileSpec * crash_file_path )
{
static uint32_t g_process_unique_id = 0 ;
ProcessSP process_sp ;
ProcessCreateInstance create_callback = NULL ;
if ( plugin_name )
{
ConstString const_plugin_name ( plugin_name ) ;
create_callback = PluginManager : : GetProcessCreateCallbackForPluginName ( const_plugin_name ) ;
if ( create_callback )
{
process_sp = create_callback ( target , listener , crash_file_path ) ;
if ( process_sp )
{
if ( process_sp - > CanDebug ( target , true ) )
{
process_sp - > m_process_unique_id = + + g_process_unique_id ;
}
else
process_sp . reset ( ) ;
}
}
}
else
{
for ( uint32_t idx = 0 ; ( create_callback = PluginManager : : GetProcessCreateCallbackAtIndex ( idx ) ) ! = NULL ; + + idx )
{
process_sp = create_callback ( target , listener , crash_file_path ) ;
if ( process_sp )
{
if ( process_sp - > CanDebug ( target , false ) )
{
process_sp - > m_process_unique_id = + + g_process_unique_id ;
break ;
}
else
process_sp . reset ( ) ;
}
}
}
return process_sp ;
}
ConstString &
Process : : GetStaticBroadcasterClass ( )
{
static ConstString class_name ( " lldb.process " ) ;
return class_name ;
}
//----------------------------------------------------------------------
// Process constructor
//----------------------------------------------------------------------
Process : : Process ( Target & target , Listener & listener ) :
2014-11-25 16:00:58 -05:00
Process ( target , listener , Host : : GetUnixSignals ( ) )
{
// This constructor just delegates to the full Process constructor,
// defaulting to using the Host's UnixSignals.
}
Process : : Process ( Target & target , Listener & listener , const UnixSignalsSP & unix_signals_sp ) :
2015-02-06 16:38:51 -05:00
ProcessProperties ( this ) ,
2013-08-23 13:46:38 -04:00
UserID ( LLDB_INVALID_PROCESS_ID ) ,
2015-07-03 12:57:06 -04:00
Broadcaster ( & ( target . GetDebugger ( ) ) , Process : : GetStaticBroadcasterClass ( ) . AsCString ( ) ) ,
2013-08-23 13:46:38 -04:00
m_target ( target ) ,
m_public_state ( eStateUnloaded ) ,
m_private_state ( eStateUnloaded ) ,
m_private_state_broadcaster ( NULL , " lldb.process.internal_state_broadcaster " ) ,
m_private_state_control_broadcaster ( NULL , " lldb.process.internal_state_control_broadcaster " ) ,
m_private_state_listener ( " lldb.process.internal_state_listener " ) ,
m_private_state_control_wait ( ) ,
m_mod_id ( ) ,
m_process_unique_id ( 0 ) ,
m_thread_index_id ( 0 ) ,
m_thread_id_to_index_id_map ( ) ,
m_exit_status ( - 1 ) ,
m_exit_string ( ) ,
2015-02-06 16:38:51 -05:00
m_exit_status_mutex ( ) ,
2013-08-23 13:46:38 -04:00
m_thread_mutex ( Mutex : : eMutexTypeRecursive ) ,
m_thread_list_real ( this ) ,
m_thread_list ( this ) ,
2013-12-03 13:51:59 -05:00
m_extended_thread_list ( this ) ,
m_extended_thread_stop_id ( 0 ) ,
2014-02-18 11:23:10 -05:00
m_queue_list ( this ) ,
m_queue_list_stop_id ( 0 ) ,
2013-08-23 13:46:38 -04:00
m_notifications ( ) ,
m_image_tokens ( ) ,
m_listener ( listener ) ,
m_breakpoint_site_list ( ) ,
m_dynamic_checkers_ap ( ) ,
2014-11-25 16:00:58 -05:00
m_unix_signals_sp ( unix_signals_sp ) ,
2013-08-23 13:46:38 -04:00
m_abi_sp ( ) ,
m_process_input_reader ( ) ,
m_stdio_communication ( " process.stdio " ) ,
m_stdio_communication_mutex ( Mutex : : eMutexTypeRecursive ) ,
2015-07-03 12:57:06 -04:00
m_stdin_forward ( false ) ,
2013-08-23 13:46:38 -04:00
m_stdout_data ( ) ,
m_stderr_data ( ) ,
m_profile_data_comm_mutex ( Mutex : : eMutexTypeRecursive ) ,
m_profile_data ( ) ,
2015-07-03 12:57:06 -04:00
m_iohandler_sync ( 0 ) ,
2013-08-23 13:46:38 -04:00
m_memory_cache ( * this ) ,
m_allocated_memory_cache ( * this ) ,
m_should_detach ( false ) ,
m_next_event_action_ap ( ) ,
m_public_run_lock ( ) ,
m_private_run_lock ( ) ,
m_currently_handling_event ( false ) ,
2015-02-06 16:38:51 -05:00
m_stop_info_override_callback ( NULL ) ,
2015-07-03 12:57:06 -04:00
m_finalizing ( false ) ,
m_finalize_called ( false ) ,
2013-08-23 13:46:38 -04:00
m_clear_thread_plans_on_stop ( false ) ,
2015-07-03 12:57:06 -04:00
m_force_next_event_delivery ( false ) ,
2013-08-23 13:46:38 -04:00
m_last_broadcast_state ( eStateInvalid ) ,
m_destroy_in_process ( false ) ,
m_can_jit ( eCanJITDontKnow )
{
CheckInWithManager ( ) ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_OBJECT ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " %p Process::Process() " , static_cast < void * > ( this ) ) ;
if ( ! m_unix_signals_sp )
m_unix_signals_sp . reset ( new UnixSignals ( ) ) ;
2013-08-23 13:46:38 -04:00
SetEventName ( eBroadcastBitStateChanged , " state-changed " ) ;
SetEventName ( eBroadcastBitInterrupt , " interrupt " ) ;
SetEventName ( eBroadcastBitSTDOUT , " stdout-available " ) ;
SetEventName ( eBroadcastBitSTDERR , " stderr-available " ) ;
SetEventName ( eBroadcastBitProfileData , " profile-data-available " ) ;
m_private_state_control_broadcaster . SetEventName ( eBroadcastInternalStateControlStop , " control-stop " ) ;
m_private_state_control_broadcaster . SetEventName ( eBroadcastInternalStateControlPause , " control-pause " ) ;
m_private_state_control_broadcaster . SetEventName ( eBroadcastInternalStateControlResume , " control-resume " ) ;
listener . StartListeningForEvents ( this ,
eBroadcastBitStateChanged |
eBroadcastBitInterrupt |
eBroadcastBitSTDOUT |
eBroadcastBitSTDERR |
eBroadcastBitProfileData ) ;
m_private_state_listener . StartListeningForEvents ( & m_private_state_broadcaster ,
eBroadcastBitStateChanged |
eBroadcastBitInterrupt ) ;
m_private_state_listener . StartListeningForEvents ( & m_private_state_control_broadcaster ,
eBroadcastInternalStateControlStop |
eBroadcastInternalStateControlPause |
eBroadcastInternalStateControlResume ) ;
2014-11-25 16:00:58 -05:00
// We need something valid here, even if just the default UnixSignalsSP.
assert ( m_unix_signals_sp & & " null m_unix_signals_sp after initialization " ) ;
2013-08-23 13:46:38 -04:00
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
Process : : ~ Process ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_OBJECT ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " %p Process::~Process() " , static_cast < void * > ( this ) ) ;
2013-08-23 13:46:38 -04:00
StopPrivateStateThread ( ) ;
2015-02-06 16:38:51 -05:00
// ThreadList::Clear() will try to acquire this process's mutex, so
// explicitly clear the thread list here to ensure that the mutex
// is not destroyed before the thread list.
m_thread_list . Clear ( ) ;
2013-08-23 13:46:38 -04:00
}
const ProcessPropertiesSP &
Process : : GetGlobalProperties ( )
{
static ProcessPropertiesSP g_settings_sp ;
if ( ! g_settings_sp )
2015-02-06 16:38:51 -05:00
g_settings_sp . reset ( new ProcessProperties ( NULL ) ) ;
2013-08-23 13:46:38 -04:00
return g_settings_sp ;
}
void
Process : : Finalize ( )
{
2015-07-03 12:57:06 -04:00
m_finalizing = true ;
// Destroy this process if needed
2013-08-23 13:46:38 -04:00
switch ( GetPrivateState ( ) )
{
case eStateConnected :
case eStateAttaching :
case eStateLaunching :
case eStateStopped :
case eStateRunning :
case eStateStepping :
case eStateCrashed :
case eStateSuspended :
2015-07-03 12:57:06 -04:00
Destroy ( false ) ;
2013-08-23 13:46:38 -04:00
break ;
case eStateInvalid :
case eStateUnloaded :
case eStateDetached :
case eStateExited :
break ;
}
// Clear our broadcaster before we proceed with destroying
Broadcaster : : Clear ( ) ;
// Do any cleanup needed prior to being destructed... Subclasses
// that override this method should call this superclass method as well.
// We need to destroy the loader before the derived Process class gets destroyed
// since it is very likely that undoing the loader will require access to the real process.
m_dynamic_checkers_ap . reset ( ) ;
m_abi_sp . reset ( ) ;
m_os_ap . reset ( ) ;
2013-11-06 11:48:53 -05:00
m_system_runtime_ap . reset ( ) ;
2013-08-23 13:46:38 -04:00
m_dyld_ap . reset ( ) ;
2014-11-25 16:00:58 -05:00
m_jit_loaders_ap . reset ( ) ;
2013-08-23 13:46:38 -04:00
m_thread_list_real . Destroy ( ) ;
m_thread_list . Destroy ( ) ;
2013-12-03 13:51:59 -05:00
m_extended_thread_list . Destroy ( ) ;
2014-02-18 11:23:10 -05:00
m_queue_list . Clear ( ) ;
m_queue_list_stop_id = 0 ;
2013-08-23 13:46:38 -04:00
std : : vector < Notifications > empty_notifications ;
m_notifications . swap ( empty_notifications ) ;
m_image_tokens . clear ( ) ;
m_memory_cache . Clear ( ) ;
m_allocated_memory_cache . Clear ( ) ;
m_language_runtimes . clear ( ) ;
2015-02-06 16:38:51 -05:00
m_instrumentation_runtimes . clear ( ) ;
2013-08-23 13:46:38 -04:00
m_next_event_action_ap . reset ( ) ;
2015-02-06 16:38:51 -05:00
m_stop_info_override_callback = NULL ;
2015-07-03 12:57:06 -04:00
// Clear the last natural stop ID since it has a strong
// reference to this process
m_mod_id . SetStopEventForLastNaturalStopID ( EventSP ( ) ) ;
2013-08-23 13:46:38 -04:00
//#ifdef LLDB_CONFIGURATION_DEBUG
// StreamFile s(stdout, false);
// EventSP event_sp;
// while (m_private_state_listener.GetNextEvent(event_sp))
// {
// event_sp->Dump (&s);
// s.EOL();
// }
//#endif
// We have to be very careful here as the m_private_state_listener might
// contain events that have ProcessSP values in them which can keep this
// process around forever. These events need to be cleared out.
m_private_state_listener . Clear ( ) ;
m_public_run_lock . TrySetRunning ( ) ; // This will do nothing if already locked
m_public_run_lock . SetStopped ( ) ;
m_private_run_lock . TrySetRunning ( ) ; // This will do nothing if already locked
m_private_run_lock . SetStopped ( ) ;
m_finalize_called = true ;
}
void
Process : : RegisterNotificationCallbacks ( const Notifications & callbacks )
{
m_notifications . push_back ( callbacks ) ;
if ( callbacks . initialize ! = NULL )
callbacks . initialize ( callbacks . baton , this ) ;
}
bool
Process : : UnregisterNotificationCallbacks ( const Notifications & callbacks )
{
std : : vector < Notifications > : : iterator pos , end = m_notifications . end ( ) ;
for ( pos = m_notifications . begin ( ) ; pos ! = end ; + + pos )
{
if ( pos - > baton = = callbacks . baton & &
pos - > initialize = = callbacks . initialize & &
pos - > process_state_changed = = callbacks . process_state_changed )
{
m_notifications . erase ( pos ) ;
return true ;
}
}
return false ;
}
void
Process : : SynchronouslyNotifyStateChanged ( StateType state )
{
std : : vector < Notifications > : : iterator notification_pos , notification_end = m_notifications . end ( ) ;
for ( notification_pos = m_notifications . begin ( ) ; notification_pos ! = notification_end ; + + notification_pos )
{
if ( notification_pos - > process_state_changed )
notification_pos - > process_state_changed ( notification_pos - > baton , this , state ) ;
}
}
// FIXME: We need to do some work on events before the general Listener sees them.
// For instance if we are continuing from a breakpoint, we need to ensure that we do
// the little "insert real insn, step & stop" trick. But we can't do that when the
// event is delivered by the broadcaster - since that is done on the thread that is
// waiting for new events, so if we needed more than one event for our handling, we would
// stall. So instead we do it when we fetch the event off of the queue.
//
StateType
Process : : GetNextEvent ( EventSP & event_sp )
{
StateType state = eStateInvalid ;
if ( m_listener . GetNextEventForBroadcaster ( this , event_sp ) & & event_sp )
state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
return state ;
}
2015-07-03 12:57:06 -04:00
void
Process : : SyncIOHandler ( uint32_t iohandler_id , uint64_t timeout_msec )
2014-11-25 16:00:58 -05:00
{
// don't sync (potentially context switch) in case where there is no process IO
2015-07-03 12:57:06 -04:00
if ( ! m_process_input_reader )
return ;
2014-11-25 16:00:58 -05:00
2015-07-03 12:57:06 -04:00
TimeValue timeout = TimeValue : : Now ( ) ;
timeout . OffsetWithMicroSeconds ( timeout_msec * 1000 ) ;
uint32_t new_iohandler_id = 0 ;
m_iohandler_sync . WaitForValueNotEqualTo ( iohandler_id , new_iohandler_id , & timeout ) ;
2014-11-25 16:00:58 -05:00
2015-07-03 12:57:06 -04:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::%s waited for m_iohandler_sync to change from %u, new value is %u " , __FUNCTION__ , iohandler_id , new_iohandler_id ) ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
StateType
2015-02-06 16:38:51 -05:00
Process : : WaitForProcessToStop ( const TimeValue * timeout ,
EventSP * event_sp_ptr ,
bool wait_always ,
Listener * hijack_listener ,
Stream * stream )
2013-08-23 13:46:38 -04:00
{
// We can't just wait for a "stopped" event, because the stopped event may have restarted the target.
// We have to actually check each event, and in the case of a stopped event check the restarted flag
// on the event.
if ( event_sp_ptr )
event_sp_ptr - > reset ( ) ;
StateType state = GetState ( ) ;
// If we are exited or detached, we won't ever get back to any
// other valid state...
if ( state = = eStateDetached | | state = = eStateExited )
return state ;
2013-11-06 11:48:53 -05:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (timeout = %p) " , __FUNCTION__ ,
static_cast < const void * > ( timeout ) ) ;
2013-11-06 11:48:53 -05:00
if ( ! wait_always & &
StateIsStoppedState ( state , true ) & &
2015-07-03 12:57:06 -04:00
StateIsStoppedState ( GetPrivateState ( ) , true ) )
{
2013-11-06 11:48:53 -05:00
if ( log )
log - > Printf ( " Process::%s returning without waiting for events; process private and public states are already 'stopped'. " ,
__FUNCTION__ ) ;
2015-07-03 12:57:06 -04:00
// We need to toggle the run lock as this won't get done in
// SetPublicState() if the process is hijacked.
if ( hijack_listener )
m_public_run_lock . SetStopped ( ) ;
2013-11-06 11:48:53 -05:00
return state ;
}
2013-08-23 13:46:38 -04:00
while ( state ! = eStateInvalid )
{
EventSP event_sp ;
2014-02-18 11:23:10 -05:00
state = WaitForStateChangedEvents ( timeout , event_sp , hijack_listener ) ;
2013-08-23 13:46:38 -04:00
if ( event_sp_ptr & & event_sp )
* event_sp_ptr = event_sp ;
2015-02-06 16:38:51 -05:00
bool pop_process_io_handler = hijack_listener ! = NULL ;
Process : : HandleProcessStateChangedEvent ( event_sp , stream , pop_process_io_handler ) ;
2013-08-23 13:46:38 -04:00
switch ( state )
{
case eStateCrashed :
case eStateDetached :
case eStateExited :
case eStateUnloaded :
2014-02-18 11:23:10 -05:00
// We need to toggle the run lock as this won't get done in
// SetPublicState() if the process is hijacked.
if ( hijack_listener )
m_public_run_lock . SetStopped ( ) ;
2013-08-23 13:46:38 -04:00
return state ;
case eStateStopped :
if ( Process : : ProcessEventData : : GetRestartedFromEvent ( event_sp . get ( ) ) )
continue ;
else
2014-02-18 11:23:10 -05:00
{
// We need to toggle the run lock as this won't get done in
// SetPublicState() if the process is hijacked.
if ( hijack_listener )
m_public_run_lock . SetStopped ( ) ;
2013-08-23 13:46:38 -04:00
return state ;
2014-02-18 11:23:10 -05:00
}
2013-08-23 13:46:38 -04:00
default :
continue ;
}
}
return state ;
}
2015-02-06 16:38:51 -05:00
bool
Process : : HandleProcessStateChangedEvent ( const EventSP & event_sp ,
Stream * stream ,
bool & pop_process_io_handler )
{
const bool handle_pop = pop_process_io_handler = = true ;
pop_process_io_handler = false ;
ProcessSP process_sp = Process : : ProcessEventData : : GetProcessFromEvent ( event_sp . get ( ) ) ;
if ( ! process_sp )
return false ;
StateType event_state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( event_state = = eStateInvalid )
return false ;
switch ( event_state )
{
case eStateInvalid :
case eStateUnloaded :
case eStateAttaching :
case eStateLaunching :
case eStateStepping :
case eStateDetached :
{
if ( stream )
stream - > Printf ( " Process % " PRIu64 " %s \n " ,
process_sp - > GetID ( ) ,
StateAsCString ( event_state ) ) ;
if ( event_state = = eStateDetached )
pop_process_io_handler = true ;
}
break ;
case eStateConnected :
case eStateRunning :
// Don't be chatty when we run...
break ;
case eStateExited :
if ( stream )
process_sp - > GetStatus ( * stream ) ;
pop_process_io_handler = true ;
break ;
case eStateStopped :
case eStateCrashed :
case eStateSuspended :
// Make sure the program hasn't been auto-restarted:
if ( Process : : ProcessEventData : : GetRestartedFromEvent ( event_sp . get ( ) ) )
{
if ( stream )
{
size_t num_reasons = Process : : ProcessEventData : : GetNumRestartedReasons ( event_sp . get ( ) ) ;
if ( num_reasons > 0 )
{
// FIXME: Do we want to report this, or would that just be annoyingly chatty?
if ( num_reasons = = 1 )
{
const char * reason = Process : : ProcessEventData : : GetRestartedReasonAtIndex ( event_sp . get ( ) , 0 ) ;
stream - > Printf ( " Process % " PRIu64 " stopped and restarted: %s \n " ,
process_sp - > GetID ( ) ,
reason ? reason : " <UNKNOWN REASON> " ) ;
}
else
{
stream - > Printf ( " Process % " PRIu64 " stopped and restarted, reasons: \n " ,
process_sp - > GetID ( ) ) ;
for ( size_t i = 0 ; i < num_reasons ; i + + )
{
const char * reason = Process : : ProcessEventData : : GetRestartedReasonAtIndex ( event_sp . get ( ) , i ) ;
stream - > Printf ( " \t %s \n " , reason ? reason : " <UNKNOWN REASON> " ) ;
}
}
}
}
}
else
{
// Lock the thread list so it doesn't change on us, this is the scope for the locker:
{
ThreadList & thread_list = process_sp - > GetThreadList ( ) ;
Mutex : : Locker locker ( thread_list . GetMutex ( ) ) ;
ThreadSP curr_thread ( thread_list . GetSelectedThread ( ) ) ;
ThreadSP thread ;
StopReason curr_thread_stop_reason = eStopReasonInvalid ;
if ( curr_thread )
curr_thread_stop_reason = curr_thread - > GetStopReason ( ) ;
if ( ! curr_thread | |
! curr_thread - > IsValid ( ) | |
curr_thread_stop_reason = = eStopReasonInvalid | |
curr_thread_stop_reason = = eStopReasonNone )
{
// Prefer a thread that has just completed its plan over another thread as current thread.
ThreadSP plan_thread ;
ThreadSP other_thread ;
const size_t num_threads = thread_list . GetSize ( ) ;
size_t i ;
for ( i = 0 ; i < num_threads ; + + i )
{
thread = thread_list . GetThreadAtIndex ( i ) ;
StopReason thread_stop_reason = thread - > GetStopReason ( ) ;
switch ( thread_stop_reason )
{
case eStopReasonInvalid :
case eStopReasonNone :
break ;
case eStopReasonTrace :
case eStopReasonBreakpoint :
case eStopReasonWatchpoint :
case eStopReasonSignal :
case eStopReasonException :
case eStopReasonExec :
case eStopReasonThreadExiting :
case eStopReasonInstrumentation :
if ( ! other_thread )
other_thread = thread ;
break ;
case eStopReasonPlanComplete :
if ( ! plan_thread )
plan_thread = thread ;
break ;
}
}
if ( plan_thread )
thread_list . SetSelectedThreadByID ( plan_thread - > GetID ( ) ) ;
else if ( other_thread )
thread_list . SetSelectedThreadByID ( other_thread - > GetID ( ) ) ;
else
{
if ( curr_thread & & curr_thread - > IsValid ( ) )
thread = curr_thread ;
else
thread = thread_list . GetThreadAtIndex ( 0 ) ;
if ( thread )
thread_list . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
}
}
}
// Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
// e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
// have a hard time restarting the process.
if ( stream )
{
Debugger & debugger = process_sp - > GetTarget ( ) . GetDebugger ( ) ;
if ( debugger . GetTargetList ( ) . GetSelectedTarget ( ) . get ( ) = = & process_sp - > GetTarget ( ) )
{
const bool only_threads_with_stop_reason = true ;
const uint32_t start_frame = 0 ;
const uint32_t num_frames = 1 ;
const uint32_t num_frames_with_source = 1 ;
process_sp - > GetStatus ( * stream ) ;
process_sp - > GetThreadStatus ( * stream ,
only_threads_with_stop_reason ,
start_frame ,
num_frames ,
num_frames_with_source ) ;
}
else
{
uint32_t target_idx = debugger . GetTargetList ( ) . GetIndexOfTarget ( process_sp - > GetTarget ( ) . shared_from_this ( ) ) ;
if ( target_idx ! = UINT32_MAX )
stream - > Printf ( " Target %d: ( " , target_idx ) ;
else
stream - > Printf ( " Target <unknown index>: ( " ) ;
process_sp - > GetTarget ( ) . Dump ( stream , eDescriptionLevelBrief ) ;
stream - > Printf ( " ) stopped. \n " ) ;
}
}
// Pop the process IO handler
pop_process_io_handler = true ;
}
break ;
}
if ( handle_pop & & pop_process_io_handler )
process_sp - > PopProcessIOHandler ( ) ;
return true ;
}
2013-08-23 13:46:38 -04:00
StateType
Process : : WaitForState
(
const TimeValue * timeout ,
2014-02-18 11:23:10 -05:00
const StateType * match_states ,
const uint32_t num_match_states
2013-08-23 13:46:38 -04:00
)
{
EventSP event_sp ;
uint32_t i ;
StateType state = GetState ( ) ;
while ( state ! = eStateInvalid )
{
// If we are exited or detached, we won't ever get back to any
// other valid state...
if ( state = = eStateDetached | | state = = eStateExited )
return state ;
2014-02-18 11:23:10 -05:00
state = WaitForStateChangedEvents ( timeout , event_sp , NULL ) ;
2013-08-23 13:46:38 -04:00
for ( i = 0 ; i < num_match_states ; + + i )
{
if ( match_states [ i ] = = state )
return state ;
}
}
return state ;
}
bool
Process : : HijackProcessEvents ( Listener * listener )
{
if ( listener ! = NULL )
{
return HijackBroadcaster ( listener , eBroadcastBitStateChanged | eBroadcastBitInterrupt ) ;
}
else
return false ;
}
void
Process : : RestoreProcessEvents ( )
{
RestoreBroadcaster ( ) ;
}
bool
Process : : HijackPrivateProcessEvents ( Listener * listener )
{
if ( listener ! = NULL )
{
return m_private_state_broadcaster . HijackBroadcaster ( listener , eBroadcastBitStateChanged | eBroadcastBitInterrupt ) ;
}
else
return false ;
}
void
Process : : RestorePrivateProcessEvents ( )
{
m_private_state_broadcaster . RestoreBroadcaster ( ) ;
}
StateType
2014-02-18 11:23:10 -05:00
Process : : WaitForStateChangedEvents ( const TimeValue * timeout , EventSP & event_sp , Listener * hijack_listener )
2013-08-23 13:46:38 -04:00
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (timeout = %p, event_sp)... " , __FUNCTION__ ,
static_cast < const void * > ( timeout ) ) ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
Listener * listener = hijack_listener ;
if ( listener = = NULL )
listener = & m_listener ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
StateType state = eStateInvalid ;
2014-02-18 11:23:10 -05:00
if ( listener - > WaitForEventForBroadcasterWithType ( timeout ,
this ,
eBroadcastBitStateChanged | eBroadcastBitInterrupt ,
event_sp ) )
2013-08-23 13:46:38 -04:00
{
if ( event_sp & & event_sp - > GetType ( ) = = eBroadcastBitStateChanged )
state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
else if ( log )
log - > Printf ( " Process::%s got no event or was interrupted. " , __FUNCTION__ ) ;
}
if ( log )
log - > Printf ( " Process::%s (timeout = %p, event_sp) => %s " ,
2014-11-25 16:00:58 -05:00
__FUNCTION__ , static_cast < const void * > ( timeout ) ,
2013-08-23 13:46:38 -04:00
StateAsCString ( state ) ) ;
return state ;
}
Event *
Process : : PeekAtStateChangedEvents ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::%s... " , __FUNCTION__ ) ;
Event * event_ptr ;
event_ptr = m_listener . PeekAtNextEventForBroadcasterWithType ( this ,
eBroadcastBitStateChanged ) ;
if ( log )
{
if ( event_ptr )
{
log - > Printf ( " Process::%s (event_ptr) => %s " ,
__FUNCTION__ ,
StateAsCString ( ProcessEventData : : GetStateFromEvent ( event_ptr ) ) ) ;
}
else
{
log - > Printf ( " Process::%s no events found " ,
__FUNCTION__ ) ;
}
}
return event_ptr ;
}
StateType
Process : : WaitForStateChangedEventsPrivate ( const TimeValue * timeout , EventSP & event_sp )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (timeout = %p, event_sp)... " , __FUNCTION__ ,
static_cast < const void * > ( timeout ) ) ;
2013-08-23 13:46:38 -04:00
StateType state = eStateInvalid ;
if ( m_private_state_listener . WaitForEventForBroadcasterWithType ( timeout ,
& m_private_state_broadcaster ,
eBroadcastBitStateChanged | eBroadcastBitInterrupt ,
event_sp ) )
if ( event_sp & & event_sp - > GetType ( ) = = eBroadcastBitStateChanged )
state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
// This is a bit of a hack, but when we wait here we could very well return
// to the command-line, and that could disable the log, which would render the
// log we got above invalid.
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (timeout = %p, event_sp) => %s " ,
__FUNCTION__ , static_cast < const void * > ( timeout ) ,
state = = eStateInvalid ? " TIMEOUT " : StateAsCString ( state ) ) ;
2013-08-23 13:46:38 -04:00
return state ;
}
bool
Process : : WaitForEventsPrivate ( const TimeValue * timeout , EventSP & event_sp , bool control_only )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (timeout = %p, event_sp)... " , __FUNCTION__ ,
static_cast < const void * > ( timeout ) ) ;
2013-08-23 13:46:38 -04:00
if ( control_only )
return m_private_state_listener . WaitForEventForBroadcaster ( timeout , & m_private_state_control_broadcaster , event_sp ) ;
else
return m_private_state_listener . WaitForEvent ( timeout , event_sp ) ;
}
bool
Process : : IsRunning ( ) const
{
return StateIsRunningState ( m_public_state . GetValue ( ) ) ;
}
int
Process : : GetExitStatus ( )
{
2015-02-06 16:38:51 -05:00
Mutex : : Locker locker ( m_exit_status_mutex ) ;
2013-08-23 13:46:38 -04:00
if ( m_public_state . GetValue ( ) = = eStateExited )
return m_exit_status ;
return - 1 ;
}
const char *
Process : : GetExitDescription ( )
{
2015-02-06 16:38:51 -05:00
Mutex : : Locker locker ( m_exit_status_mutex ) ;
2013-08-23 13:46:38 -04:00
if ( m_public_state . GetValue ( ) = = eStateExited & & ! m_exit_string . empty ( ) )
return m_exit_string . c_str ( ) ;
return NULL ;
}
bool
Process : : SetExitStatus ( int status , const char * cstr )
{
2015-07-03 12:57:06 -04:00
// Use a mutex to protect setting the exit status.
Mutex : : Locker locker ( m_exit_status_mutex ) ;
2013-08-23 13:46:38 -04:00
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s) " ,
status , status ,
cstr ? " \" " : " " ,
cstr ? cstr : " NULL " ,
cstr ? " \" " : " " ) ;
// We were already in the exited state
if ( m_private_state . GetValue ( ) = = eStateExited )
{
if ( log )
log - > Printf ( " Process::SetExitStatus () ignoring exit status because state was already set to eStateExited " ) ;
return false ;
}
2015-02-06 16:38:51 -05:00
2015-07-03 12:57:06 -04:00
m_exit_status = status ;
if ( cstr )
m_exit_string = cstr ;
else
m_exit_string . clear ( ) ;
// When we exit, we no longer need to the communication channel
m_stdio_communication . Disconnect ( ) ;
m_stdio_communication . StopReadThread ( ) ;
m_stdin_forward = false ;
// And we don't need the input reader anymore as well
if ( m_process_input_reader )
{
m_process_input_reader - > SetIsDone ( true ) ;
m_process_input_reader - > Cancel ( ) ;
m_process_input_reader . reset ( ) ;
2015-02-06 16:38:51 -05:00
}
2013-08-23 13:46:38 -04:00
2015-07-03 12:57:06 -04:00
// Clear the last natural stop ID since it has a strong
// reference to this process
m_mod_id . SetStopEventForLastNaturalStopID ( EventSP ( ) ) ;
2013-08-23 13:46:38 -04:00
SetPrivateState ( eStateExited ) ;
2015-07-03 12:57:06 -04:00
// Allow subclasses to do some cleanup
DidExit ( ) ;
2013-08-23 13:46:38 -04:00
return true ;
}
// This static callback can be used to watch for local child processes on
2014-11-25 16:00:58 -05:00
// the current host. The child process exits, the process will be
2013-08-23 13:46:38 -04:00
// found in the global target list (we want to be completely sure that the
// lldb_private::Process doesn't go away before we can deliver the signal.
bool
Process : : SetProcessExitStatus ( void * callback_baton ,
lldb : : pid_t pid ,
bool exited ,
int signo , // Zero for no signal
int exit_status // Exit value of process if signal is zero
)
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::SetProcessExitStatus (baton=%p, pid=% " PRIu64 " , exited=%i, signal=%i, exit_status=%i) \n " ,
callback_baton ,
pid ,
exited ,
signo ,
exit_status ) ;
if ( exited )
{
TargetSP target_sp ( Debugger : : FindTargetWithProcessID ( pid ) ) ;
if ( target_sp )
{
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
if ( process_sp )
{
const char * signal_cstr = NULL ;
if ( signo )
signal_cstr = process_sp - > GetUnixSignals ( ) . GetSignalAsCString ( signo ) ;
process_sp - > SetExitStatus ( exit_status , signal_cstr ) ;
}
}
return true ;
}
return false ;
}
void
Process : : UpdateThreadListIfNeeded ( )
{
const uint32_t stop_id = GetStopID ( ) ;
if ( m_thread_list . GetSize ( false ) = = 0 | | stop_id ! = m_thread_list . GetStopID ( ) )
{
const StateType state = GetPrivateState ( ) ;
if ( StateIsStoppedState ( state , true ) )
{
Mutex : : Locker locker ( m_thread_list . GetMutex ( ) ) ;
// m_thread_list does have its own mutex, but we need to
// hold onto the mutex between the call to UpdateThreadList(...)
// and the os->UpdateThreadList(...) so it doesn't change on us
ThreadList & old_thread_list = m_thread_list ;
ThreadList real_thread_list ( this ) ;
ThreadList new_thread_list ( this ) ;
// Always update the thread list with the protocol specific
// thread list, but only update if "true" is returned
if ( UpdateThreadList ( m_thread_list_real , real_thread_list ) )
{
// Don't call into the OperatingSystem to update the thread list if we are shutting down, since
// that may call back into the SBAPI's, requiring the API lock which is already held by whoever is
// shutting us down, causing a deadlock.
if ( ! m_destroy_in_process )
{
OperatingSystem * os = GetOperatingSystem ( ) ;
if ( os )
{
// Clear any old backing threads where memory threads might have been
// backed by actual threads from the lldb_private::Process subclass
size_t num_old_threads = old_thread_list . GetSize ( false ) ;
for ( size_t i = 0 ; i < num_old_threads ; + + i )
old_thread_list . GetThreadAtIndex ( i , false ) - > ClearBackingThread ( ) ;
2015-07-03 12:57:06 -04:00
// Turn off dynamic types to ensure we don't run any expressions. Objective C
// can run an expression to determine if a SBValue is a dynamic type or not
// and we need to avoid this. OperatingSystem plug-ins can't run expressions
// that require running code...
Target & target = GetTarget ( ) ;
const lldb : : DynamicValueType saved_prefer_dynamic = target . GetPreferDynamicValue ( ) ;
if ( saved_prefer_dynamic ! = lldb : : eNoDynamicValues )
target . SetPreferDynamicValue ( lldb : : eNoDynamicValues ) ;
2013-08-23 13:46:38 -04:00
// Now let the OperatingSystem plug-in update the thread list
2015-07-03 12:57:06 -04:00
2013-08-23 13:46:38 -04:00
os - > UpdateThreadList ( old_thread_list , // Old list full of threads created by OS plug-in
real_thread_list , // The actual thread list full of threads created by each lldb_private::Process subclass
new_thread_list ) ; // The new thread list that we will show to the user that gets filled in
2015-07-03 12:57:06 -04:00
if ( saved_prefer_dynamic ! = lldb : : eNoDynamicValues )
target . SetPreferDynamicValue ( saved_prefer_dynamic ) ;
2013-08-23 13:46:38 -04:00
}
else
{
// No OS plug-in, the new thread list is the same as the real thread list
new_thread_list = real_thread_list ;
}
}
m_thread_list_real . Update ( real_thread_list ) ;
m_thread_list . Update ( new_thread_list ) ;
m_thread_list . SetStopID ( stop_id ) ;
2013-12-03 13:51:59 -05:00
if ( GetLastNaturalStopID ( ) ! = m_extended_thread_stop_id )
{
// Clear any extended threads that we may have accumulated previously
m_extended_thread_list . Clear ( ) ;
m_extended_thread_stop_id = GetLastNaturalStopID ( ) ;
2014-02-18 11:23:10 -05:00
m_queue_list . Clear ( ) ;
m_queue_list_stop_id = GetLastNaturalStopID ( ) ;
2013-12-03 13:51:59 -05:00
}
2013-08-23 13:46:38 -04:00
}
}
}
}
2014-02-18 11:23:10 -05:00
void
Process : : UpdateQueueListIfNeeded ( )
{
if ( m_system_runtime_ap . get ( ) )
{
if ( m_queue_list . GetSize ( ) = = 0 | | m_queue_list_stop_id ! = GetLastNaturalStopID ( ) )
{
const StateType state = GetPrivateState ( ) ;
if ( StateIsStoppedState ( state , true ) )
{
m_system_runtime_ap - > PopulateQueueList ( m_queue_list ) ;
m_queue_list_stop_id = GetLastNaturalStopID ( ) ;
}
}
}
}
2013-08-23 13:46:38 -04:00
ThreadSP
Process : : CreateOSPluginThread ( lldb : : tid_t tid , lldb : : addr_t context )
{
OperatingSystem * os = GetOperatingSystem ( ) ;
if ( os )
return os - > CreateThread ( tid , context ) ;
return ThreadSP ( ) ;
}
uint32_t
Process : : GetNextThreadIndexID ( uint64_t thread_id )
{
return AssignIndexIDToThread ( thread_id ) ;
}
bool
Process : : HasAssignedIndexIDToThread ( uint64_t thread_id )
{
std : : map < uint64_t , uint32_t > : : iterator iterator = m_thread_id_to_index_id_map . find ( thread_id ) ;
if ( iterator = = m_thread_id_to_index_id_map . end ( ) )
{
return false ;
}
else
{
return true ;
}
}
uint32_t
Process : : AssignIndexIDToThread ( uint64_t thread_id )
{
uint32_t result = 0 ;
std : : map < uint64_t , uint32_t > : : iterator iterator = m_thread_id_to_index_id_map . find ( thread_id ) ;
if ( iterator = = m_thread_id_to_index_id_map . end ( ) )
{
result = + + m_thread_index_id ;
m_thread_id_to_index_id_map [ thread_id ] = result ;
}
else
{
result = iterator - > second ;
}
return result ;
}
StateType
Process : : GetState ( )
{
// If any other threads access this we will need a mutex for it
return m_public_state . GetValue ( ) ;
}
2015-02-06 16:38:51 -05:00
bool
Process : : StateChangedIsExternallyHijacked ( )
{
if ( IsHijackedForEvent ( eBroadcastBitStateChanged ) )
{
if ( strcmp ( m_hijacking_listeners . back ( ) - > GetName ( ) , " lldb.Process.ResumeSynchronous.hijack " ) )
return true ;
}
return false ;
}
2013-08-23 13:46:38 -04:00
void
Process : : SetPublicState ( StateType new_state , bool restarted )
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::SetPublicState (state = %s, restarted = %i) " , StateAsCString ( new_state ) , restarted ) ;
const StateType old_state = m_public_state . GetValue ( ) ;
m_public_state . SetValue ( new_state ) ;
// On the transition from Run to Stopped, we unlock the writer end of the
// run lock. The lock gets locked in Resume, which is the public API
// to tell the program to run.
2015-02-06 16:38:51 -05:00
if ( ! StateChangedIsExternallyHijacked ( ) )
2013-08-23 13:46:38 -04:00
{
if ( new_state = = eStateDetached )
{
if ( log )
log - > Printf ( " Process::SetPublicState (%s) -- unlocking run lock for detach " , StateAsCString ( new_state ) ) ;
m_public_run_lock . SetStopped ( ) ;
}
else
{
const bool old_state_is_stopped = StateIsStoppedState ( old_state , false ) ;
const bool new_state_is_stopped = StateIsStoppedState ( new_state , false ) ;
if ( ( old_state_is_stopped ! = new_state_is_stopped ) )
{
if ( new_state_is_stopped & & ! restarted )
{
if ( log )
log - > Printf ( " Process::SetPublicState (%s) -- unlocking run lock " , StateAsCString ( new_state ) ) ;
m_public_run_lock . SetStopped ( ) ;
}
}
}
}
}
Error
Process : : Resume ( )
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::Resume -- locking run lock " ) ;
if ( ! m_public_run_lock . TrySetRunning ( ) )
{
Error error ( " Resume request failed - process still running. " ) ;
if ( log )
log - > Printf ( " Process::Resume: -- TrySetRunning failed, not resuming. " ) ;
return error ;
}
return PrivateResume ( ) ;
}
2015-02-06 16:38:51 -05:00
Error
Process : : ResumeSynchronous ( Stream * stream )
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::ResumeSynchronous -- locking run lock " ) ;
if ( ! m_public_run_lock . TrySetRunning ( ) )
{
Error error ( " Resume request failed - process still running. " ) ;
if ( log )
log - > Printf ( " Process::Resume: -- TrySetRunning failed, not resuming. " ) ;
return error ;
}
ListenerSP listener_sp ( new Listener ( " lldb.Process.ResumeSynchronous.hijack " ) ) ;
HijackProcessEvents ( listener_sp . get ( ) ) ;
Error error = PrivateResume ( ) ;
2015-07-03 12:57:06 -04:00
if ( error . Success ( ) )
{
StateType state = WaitForProcessToStop ( NULL , NULL , true , listener_sp . get ( ) , stream ) ;
const bool must_be_alive = false ; // eStateExited is ok, so this must be false
if ( ! StateIsStoppedState ( state , must_be_alive ) )
error . SetErrorStringWithFormat ( " process not in stopped state after synchronous resume: %s " , StateAsCString ( state ) ) ;
}
2015-02-06 16:38:51 -05:00
// Undo the hijacking of process events...
RestoreProcessEvents ( ) ;
return error ;
}
2013-08-23 13:46:38 -04:00
StateType
Process : : GetPrivateState ( )
{
return m_private_state . GetValue ( ) ;
}
void
Process : : SetPrivateState ( StateType new_state )
{
2014-11-25 16:00:58 -05:00
if ( m_finalize_called )
return ;
2013-08-23 13:46:38 -04:00
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS ) ) ;
bool state_changed = false ;
if ( log )
log - > Printf ( " Process::SetPrivateState (%s) " , StateAsCString ( new_state ) ) ;
Mutex : : Locker thread_locker ( m_thread_list . GetMutex ( ) ) ;
Mutex : : Locker locker ( m_private_state . GetMutex ( ) ) ;
const StateType old_state = m_private_state . GetValueNoLock ( ) ;
state_changed = old_state ! = new_state ;
const bool old_state_is_stopped = StateIsStoppedState ( old_state , false ) ;
const bool new_state_is_stopped = StateIsStoppedState ( new_state , false ) ;
if ( old_state_is_stopped ! = new_state_is_stopped )
{
if ( new_state_is_stopped )
m_private_run_lock . SetStopped ( ) ;
else
m_private_run_lock . SetRunning ( ) ;
}
if ( state_changed )
{
m_private_state . SetValueNoLock ( new_state ) ;
2015-07-03 12:57:06 -04:00
EventSP event_sp ( new Event ( eBroadcastBitStateChanged , new ProcessEventData ( shared_from_this ( ) , new_state ) ) ) ;
2013-08-23 13:46:38 -04:00
if ( StateIsStoppedState ( new_state , false ) )
{
// Note, this currently assumes that all threads in the list
// stop when the process stops. In the future we will want to
// support a debugging model where some threads continue to run
// while others are stopped. When that happens we will either need
// a way for the thread list to identify which threads are stopping
// or create a special thread list containing only threads which
// actually stopped.
//
// The process plugin is responsible for managing the actual
// behavior of the threads and should have stopped any threads
// that are going to stop before we get here.
m_thread_list . DidStop ( ) ;
m_mod_id . BumpStopID ( ) ;
2015-07-03 12:57:06 -04:00
if ( ! m_mod_id . IsLastResumeForUserExpression ( ) )
m_mod_id . SetStopEventForLastNaturalStopID ( event_sp ) ;
2013-08-23 13:46:38 -04:00
m_memory_cache . Clear ( ) ;
if ( log )
log - > Printf ( " Process::SetPrivateState (%s) stop_id = %u " , StateAsCString ( new_state ) , m_mod_id . GetStopID ( ) ) ;
}
2015-07-03 12:57:06 -04:00
2013-08-23 13:46:38 -04:00
// Use our target to get a shared pointer to ourselves...
if ( m_finalize_called & & PrivateStateThreadIsValid ( ) = = false )
2015-07-03 12:57:06 -04:00
BroadcastEvent ( event_sp ) ;
2013-08-23 13:46:38 -04:00
else
2015-07-03 12:57:06 -04:00
m_private_state_broadcaster . BroadcastEvent ( event_sp ) ;
2013-08-23 13:46:38 -04:00
}
else
{
if ( log )
log - > Printf ( " Process::SetPrivateState (%s) state didn't change. Ignoring... " , StateAsCString ( new_state ) ) ;
}
}
void
Process : : SetRunningUserExpression ( bool on )
{
m_mod_id . SetRunningUserExpression ( on ) ;
}
addr_t
Process : : GetImageInfoAddress ( )
{
return LLDB_INVALID_ADDRESS ;
}
//----------------------------------------------------------------------
// LoadImage
//
// This function provides a default implementation that works for most
// unix variants. Any Process subclasses that need to do shared library
// loading differently should override LoadImage and UnloadImage and
// do what is needed.
//----------------------------------------------------------------------
uint32_t
Process : : LoadImage ( const FileSpec & image_spec , Error & error )
{
2015-07-03 12:57:06 -04:00
if ( m_finalizing )
{
error . SetErrorString ( " process is tearing itself down " ) ;
return LLDB_INVALID_IMAGE_TOKEN ;
}
2013-08-23 13:46:38 -04:00
char path [ PATH_MAX ] ;
image_spec . GetPath ( path , sizeof ( path ) ) ;
DynamicLoader * loader = GetDynamicLoader ( ) ;
if ( loader )
{
error = loader - > CanLoadImage ( ) ;
if ( error . Fail ( ) )
return LLDB_INVALID_IMAGE_TOKEN ;
}
if ( error . Success ( ) )
{
ThreadSP thread_sp ( GetThreadList ( ) . GetSelectedThread ( ) ) ;
if ( thread_sp )
{
StackFrameSP frame_sp ( thread_sp - > GetStackFrameAtIndex ( 0 ) ) ;
if ( frame_sp )
{
ExecutionContext exe_ctx ;
frame_sp - > CalculateExecutionContext ( exe_ctx ) ;
2013-11-06 11:48:53 -05:00
EvaluateExpressionOptions expr_options ;
expr_options . SetUnwindOnError ( true ) ;
expr_options . SetIgnoreBreakpoints ( true ) ;
expr_options . SetExecutionPolicy ( eExecutionPolicyAlways ) ;
2014-11-25 16:00:58 -05:00
expr_options . SetResultIsInternal ( true ) ;
2013-08-23 13:46:38 -04:00
StreamString expr ;
2014-11-25 16:00:58 -05:00
expr . Printf ( R " (
struct __lldb_dlopen_result { void * image_ptr ; const char * error_str ; } the_result ;
the_result . image_ptr = dlopen ( " %s " , 2 ) ;
if ( the_result . image_ptr = = ( void * ) 0x0 )
{
the_result . error_str = dlerror ( ) ;
}
else
{
the_result . error_str = ( const char * ) 0x0 ;
}
the_result ;
) " ,
path ) ;
const char * prefix = R " (
extern " C " void * dlopen ( const char * path , int mode ) ;
extern " C " const char * dlerror ( void ) ;
) " ;
2013-08-23 13:46:38 -04:00
lldb : : ValueObjectSP result_valobj_sp ;
2013-11-06 11:48:53 -05:00
Error expr_error ;
2013-08-23 13:46:38 -04:00
ClangUserExpression : : Evaluate ( exe_ctx ,
2013-11-06 11:48:53 -05:00
expr_options ,
2013-08-23 13:46:38 -04:00
expr . GetData ( ) ,
prefix ,
result_valobj_sp ,
2013-11-06 11:48:53 -05:00
expr_error ) ;
if ( expr_error . Success ( ) )
2013-08-23 13:46:38 -04:00
{
2013-11-06 11:48:53 -05:00
error = result_valobj_sp - > GetError ( ) ;
if ( error . Success ( ) )
2013-08-23 13:46:38 -04:00
{
2013-11-06 11:48:53 -05:00
Scalar scalar ;
2014-11-25 16:00:58 -05:00
ValueObjectSP image_ptr_sp = result_valobj_sp - > GetChildAtIndex ( 0 , true ) ;
if ( image_ptr_sp & & image_ptr_sp - > ResolveValue ( scalar ) )
2013-08-23 13:46:38 -04:00
{
2013-11-06 11:48:53 -05:00
addr_t image_ptr = scalar . ULongLong ( LLDB_INVALID_ADDRESS ) ;
if ( image_ptr ! = 0 & & image_ptr ! = LLDB_INVALID_ADDRESS )
{
uint32_t image_token = m_image_tokens . size ( ) ;
m_image_tokens . push_back ( image_ptr ) ;
return image_token ;
}
2014-11-25 16:00:58 -05:00
else if ( image_ptr = = 0 )
{
ValueObjectSP error_str_sp = result_valobj_sp - > GetChildAtIndex ( 1 , true ) ;
if ( error_str_sp )
{
if ( error_str_sp - > IsCStringContainer ( true ) )
{
2015-02-06 16:38:51 -05:00
DataBufferSP buffer_sp ( new DataBufferHeap ( 10240 , 0 ) ) ;
size_t num_chars = error_str_sp - > ReadPointedString ( buffer_sp , error , 10240 ) ;
2014-11-25 16:00:58 -05:00
if ( error . Success ( ) & & num_chars > 0 )
{
error . Clear ( ) ;
2015-02-06 16:38:51 -05:00
error . SetErrorStringWithFormat ( " dlopen error: %s " , buffer_sp - > GetBytes ( ) ) ;
}
else
{
error . Clear ( ) ;
error . SetErrorStringWithFormat ( " dlopen failed for unknown reasons. " ) ;
2014-11-25 16:00:58 -05:00
}
}
}
}
2013-08-23 13:46:38 -04:00
}
}
}
2014-11-25 16:00:58 -05:00
else
error = expr_error ;
2013-08-23 13:46:38 -04:00
}
}
}
if ( ! error . AsCString ( ) )
error . SetErrorStringWithFormat ( " unable to load '%s' " , path ) ;
return LLDB_INVALID_IMAGE_TOKEN ;
}
//----------------------------------------------------------------------
// UnloadImage
//
// This function provides a default implementation that works for most
// unix variants. Any Process subclasses that need to do shared library
// loading differently should override LoadImage and UnloadImage and
// do what is needed.
//----------------------------------------------------------------------
Error
Process : : UnloadImage ( uint32_t image_token )
{
Error error ;
2015-07-03 12:57:06 -04:00
if ( m_finalizing )
{
error . SetErrorString ( " process is tearing itself down " ) ;
return error ;
}
2013-08-23 13:46:38 -04:00
if ( image_token < m_image_tokens . size ( ) )
{
const addr_t image_addr = m_image_tokens [ image_token ] ;
if ( image_addr = = LLDB_INVALID_ADDRESS )
{
error . SetErrorString ( " image already unloaded " ) ;
}
else
{
DynamicLoader * loader = GetDynamicLoader ( ) ;
if ( loader )
error = loader - > CanLoadImage ( ) ;
if ( error . Success ( ) )
{
ThreadSP thread_sp ( GetThreadList ( ) . GetSelectedThread ( ) ) ;
if ( thread_sp )
{
StackFrameSP frame_sp ( thread_sp - > GetStackFrameAtIndex ( 0 ) ) ;
if ( frame_sp )
{
ExecutionContext exe_ctx ;
frame_sp - > CalculateExecutionContext ( exe_ctx ) ;
2013-11-06 11:48:53 -05:00
EvaluateExpressionOptions expr_options ;
expr_options . SetUnwindOnError ( true ) ;
expr_options . SetIgnoreBreakpoints ( true ) ;
expr_options . SetExecutionPolicy ( eExecutionPolicyAlways ) ;
2013-08-23 13:46:38 -04:00
StreamString expr ;
expr . Printf ( " dlclose ((void *)0x% " PRIx64 " ) " , image_addr ) ;
const char * prefix = " extern \" C \" int dlclose(void* handle); \n " ;
lldb : : ValueObjectSP result_valobj_sp ;
2013-11-06 11:48:53 -05:00
Error expr_error ;
2013-08-23 13:46:38 -04:00
ClangUserExpression : : Evaluate ( exe_ctx ,
2013-11-06 11:48:53 -05:00
expr_options ,
2013-08-23 13:46:38 -04:00
expr . GetData ( ) ,
prefix ,
result_valobj_sp ,
2013-11-06 11:48:53 -05:00
expr_error ) ;
2013-08-23 13:46:38 -04:00
if ( result_valobj_sp - > GetError ( ) . Success ( ) )
{
Scalar scalar ;
if ( result_valobj_sp - > ResolveValue ( scalar ) )
{
if ( scalar . UInt ( 1 ) )
{
error . SetErrorStringWithFormat ( " expression failed: \" %s \" " , expr . GetData ( ) ) ;
}
else
{
m_image_tokens [ image_token ] = LLDB_INVALID_ADDRESS ;
}
}
}
else
{
error = result_valobj_sp - > GetError ( ) ;
}
}
}
}
}
}
else
{
error . SetErrorString ( " invalid image token " ) ;
}
return error ;
}
const lldb : : ABISP &
Process : : GetABI ( )
{
if ( ! m_abi_sp )
m_abi_sp = ABI : : FindPlugin ( m_target . GetArchitecture ( ) ) ;
return m_abi_sp ;
}
LanguageRuntime *
Process : : GetLanguageRuntime ( lldb : : LanguageType language , bool retry_if_null )
{
2015-07-03 12:57:06 -04:00
if ( m_finalizing )
return nullptr ;
2013-08-23 13:46:38 -04:00
LanguageRuntimeCollection : : iterator pos ;
pos = m_language_runtimes . find ( language ) ;
if ( pos = = m_language_runtimes . end ( ) | | ( retry_if_null & & ! ( * pos ) . second ) )
{
lldb : : LanguageRuntimeSP runtime_sp ( LanguageRuntime : : FindPlugin ( this , language ) ) ;
m_language_runtimes [ language ] = runtime_sp ;
return runtime_sp . get ( ) ;
}
else
return ( * pos ) . second . get ( ) ;
}
CPPLanguageRuntime *
Process : : GetCPPLanguageRuntime ( bool retry_if_null )
{
LanguageRuntime * runtime = GetLanguageRuntime ( eLanguageTypeC_plus_plus , retry_if_null ) ;
if ( runtime ! = NULL & & runtime - > GetLanguageType ( ) = = eLanguageTypeC_plus_plus )
return static_cast < CPPLanguageRuntime * > ( runtime ) ;
return NULL ;
}
ObjCLanguageRuntime *
Process : : GetObjCLanguageRuntime ( bool retry_if_null )
{
LanguageRuntime * runtime = GetLanguageRuntime ( eLanguageTypeObjC , retry_if_null ) ;
if ( runtime ! = NULL & & runtime - > GetLanguageType ( ) = = eLanguageTypeObjC )
return static_cast < ObjCLanguageRuntime * > ( runtime ) ;
return NULL ;
}
bool
Process : : IsPossibleDynamicValue ( ValueObject & in_value )
{
2015-07-03 12:57:06 -04:00
if ( m_finalizing )
return false ;
2013-08-23 13:46:38 -04:00
if ( in_value . IsDynamic ( ) )
return false ;
LanguageType known_type = in_value . GetObjectRuntimeLanguage ( ) ;
if ( known_type ! = eLanguageTypeUnknown & & known_type ! = eLanguageTypeC )
{
LanguageRuntime * runtime = GetLanguageRuntime ( known_type ) ;
return runtime ? runtime - > CouldHaveDynamicValue ( in_value ) : false ;
}
LanguageRuntime * cpp_runtime = GetLanguageRuntime ( eLanguageTypeC_plus_plus ) ;
if ( cpp_runtime & & cpp_runtime - > CouldHaveDynamicValue ( in_value ) )
return true ;
LanguageRuntime * objc_runtime = GetLanguageRuntime ( eLanguageTypeObjC ) ;
return objc_runtime ? objc_runtime - > CouldHaveDynamicValue ( in_value ) : false ;
}
2015-07-03 12:57:06 -04:00
void
Process : : SetDynamicCheckers ( DynamicCheckerFunctions * dynamic_checkers )
{
m_dynamic_checkers_ap . reset ( dynamic_checkers ) ;
}
2013-08-23 13:46:38 -04:00
BreakpointSiteList &
Process : : GetBreakpointSiteList ( )
{
return m_breakpoint_site_list ;
}
const BreakpointSiteList &
Process : : GetBreakpointSiteList ( ) const
{
return m_breakpoint_site_list ;
}
void
Process : : DisableAllBreakpointSites ( )
{
m_breakpoint_site_list . ForEach ( [ this ] ( BreakpointSite * bp_site ) - > void {
// bp_site->SetEnabled(true);
DisableBreakpointSite ( bp_site ) ;
} ) ;
}
Error
Process : : ClearBreakpointSiteByID ( lldb : : user_id_t break_id )
{
Error error ( DisableBreakpointSiteByID ( break_id ) ) ;
if ( error . Success ( ) )
m_breakpoint_site_list . Remove ( break_id ) ;
return error ;
}
Error
Process : : DisableBreakpointSiteByID ( lldb : : user_id_t break_id )
{
Error error ;
BreakpointSiteSP bp_site_sp = m_breakpoint_site_list . FindByID ( break_id ) ;
if ( bp_site_sp )
{
if ( bp_site_sp - > IsEnabled ( ) )
error = DisableBreakpointSite ( bp_site_sp . get ( ) ) ;
}
else
{
error . SetErrorStringWithFormat ( " invalid breakpoint site ID: % " PRIu64 , break_id ) ;
}
return error ;
}
Error
Process : : EnableBreakpointSiteByID ( lldb : : user_id_t break_id )
{
Error error ;
BreakpointSiteSP bp_site_sp = m_breakpoint_site_list . FindByID ( break_id ) ;
if ( bp_site_sp )
{
if ( ! bp_site_sp - > IsEnabled ( ) )
error = EnableBreakpointSite ( bp_site_sp . get ( ) ) ;
}
else
{
error . SetErrorStringWithFormat ( " invalid breakpoint site ID: % " PRIu64 , break_id ) ;
}
return error ;
}
lldb : : break_id_t
Process : : CreateBreakpointSite ( const BreakpointLocationSP & owner , bool use_hardware )
{
2014-02-18 11:23:10 -05:00
addr_t load_addr = LLDB_INVALID_ADDRESS ;
bool show_error = true ;
switch ( GetState ( ) )
{
case eStateInvalid :
case eStateUnloaded :
case eStateConnected :
case eStateAttaching :
case eStateLaunching :
case eStateDetached :
case eStateExited :
show_error = false ;
break ;
case eStateStopped :
case eStateRunning :
case eStateStepping :
case eStateCrashed :
case eStateSuspended :
show_error = IsAlive ( ) ;
break ;
}
// Reset the IsIndirect flag here, in case the location changes from
// pointing to a indirect symbol to a regular symbol.
owner - > SetIsIndirect ( false ) ;
if ( owner - > ShouldResolveIndirectFunctions ( ) )
{
Symbol * symbol = owner - > GetAddress ( ) . CalculateSymbolContextSymbol ( ) ;
if ( symbol & & symbol - > IsIndirect ( ) )
{
Error error ;
2015-07-03 12:57:06 -04:00
Address symbol_address = symbol - > GetAddress ( ) ;
load_addr = ResolveIndirectFunction ( & symbol_address , error ) ;
2014-02-18 11:23:10 -05:00
if ( ! error . Success ( ) & & show_error )
{
m_target . GetDebugger ( ) . GetErrorFile ( ) - > Printf ( " warning: failed to resolve indirect function at 0x% " PRIx64 " for breakpoint %i.%i: %s \n " ,
2015-07-03 12:57:06 -04:00
symbol - > GetLoadAddress ( & m_target ) ,
2014-02-18 11:23:10 -05:00
owner - > GetBreakpoint ( ) . GetID ( ) ,
owner - > GetID ( ) ,
2014-11-25 16:00:58 -05:00
error . AsCString ( ) ? error . AsCString ( ) : " unknown error " ) ;
2014-02-18 11:23:10 -05:00
return LLDB_INVALID_BREAK_ID ;
}
Address resolved_address ( load_addr ) ;
load_addr = resolved_address . GetOpcodeLoadAddress ( & m_target ) ;
owner - > SetIsIndirect ( true ) ;
}
else
load_addr = owner - > GetAddress ( ) . GetOpcodeLoadAddress ( & m_target ) ;
}
else
load_addr = owner - > GetAddress ( ) . GetOpcodeLoadAddress ( & m_target ) ;
2013-08-23 13:46:38 -04:00
if ( load_addr ! = LLDB_INVALID_ADDRESS )
{
BreakpointSiteSP bp_site_sp ;
// Look up this breakpoint site. If it exists, then add this new owner, otherwise
// create a new breakpoint site and add it.
bp_site_sp = m_breakpoint_site_list . FindByAddress ( load_addr ) ;
if ( bp_site_sp )
{
bp_site_sp - > AddOwner ( owner ) ;
owner - > SetBreakpointSite ( bp_site_sp ) ;
return bp_site_sp - > GetID ( ) ;
}
else
{
bp_site_sp . reset ( new BreakpointSite ( & m_breakpoint_site_list , owner , load_addr , use_hardware ) ) ;
if ( bp_site_sp )
{
2013-11-06 11:48:53 -05:00
Error error = EnableBreakpointSite ( bp_site_sp . get ( ) ) ;
if ( error . Success ( ) )
2013-08-23 13:46:38 -04:00
{
owner - > SetBreakpointSite ( bp_site_sp ) ;
return m_breakpoint_site_list . Add ( bp_site_sp ) ;
}
2013-11-06 11:48:53 -05:00
else
{
2013-12-03 13:51:59 -05:00
if ( show_error )
{
// Report error for setting breakpoint...
2014-02-18 11:23:10 -05:00
m_target . GetDebugger ( ) . GetErrorFile ( ) - > Printf ( " warning: failed to set breakpoint site at 0x% " PRIx64 " for breakpoint %i.%i: %s \n " ,
load_addr ,
owner - > GetBreakpoint ( ) . GetID ( ) ,
owner - > GetID ( ) ,
2014-11-25 16:00:58 -05:00
error . AsCString ( ) ? error . AsCString ( ) : " unknown error " ) ;
2013-12-03 13:51:59 -05:00
}
2013-11-06 11:48:53 -05:00
}
2013-08-23 13:46:38 -04:00
}
}
}
// We failed to enable the breakpoint
return LLDB_INVALID_BREAK_ID ;
}
void
Process : : RemoveOwnerFromBreakpointSite ( lldb : : user_id_t owner_id , lldb : : user_id_t owner_loc_id , BreakpointSiteSP & bp_site_sp )
{
uint32_t num_owners = bp_site_sp - > RemoveOwner ( owner_id , owner_loc_id ) ;
if ( num_owners = = 0 )
{
// Don't try to disable the site if we don't have a live process anymore.
if ( IsAlive ( ) )
DisableBreakpointSite ( bp_site_sp . get ( ) ) ;
m_breakpoint_site_list . RemoveByAddress ( bp_site_sp - > GetLoadAddress ( ) ) ;
}
}
size_t
Process : : RemoveBreakpointOpcodesFromBuffer ( addr_t bp_addr , size_t size , uint8_t * buf ) const
{
size_t bytes_removed = 0 ;
BreakpointSiteList bp_sites_in_range ;
if ( m_breakpoint_site_list . FindInRange ( bp_addr , bp_addr + size , bp_sites_in_range ) )
{
bp_sites_in_range . ForEach ( [ bp_addr , size , buf , & bytes_removed ] ( BreakpointSite * bp_site ) - > void {
if ( bp_site - > GetType ( ) = = BreakpointSite : : eSoftware )
{
addr_t intersect_addr ;
size_t intersect_size ;
size_t opcode_offset ;
if ( bp_site - > IntersectsRange ( bp_addr , size , & intersect_addr , & intersect_size , & opcode_offset ) )
{
assert ( bp_addr < = intersect_addr & & intersect_addr < bp_addr + size ) ;
assert ( bp_addr < intersect_addr + intersect_size & & intersect_addr + intersect_size < = bp_addr + size ) ;
assert ( opcode_offset + intersect_size < = bp_site - > GetByteSize ( ) ) ;
size_t buf_offset = intersect_addr - bp_addr ;
: : memcpy ( buf + buf_offset , bp_site - > GetSavedOpcodeBytes ( ) + opcode_offset , intersect_size ) ;
}
}
} ) ;
}
return bytes_removed ;
}
size_t
Process : : GetSoftwareBreakpointTrapOpcode ( BreakpointSite * bp_site )
{
PlatformSP platform_sp ( m_target . GetPlatform ( ) ) ;
if ( platform_sp )
return platform_sp - > GetSoftwareBreakpointTrapOpcode ( m_target , bp_site ) ;
return 0 ;
}
Error
Process : : EnableSoftwareBreakpoint ( BreakpointSite * bp_site )
{
Error error ;
assert ( bp_site ! = NULL ) ;
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_BREAKPOINTS ) ) ;
const addr_t bp_addr = bp_site - > GetLoadAddress ( ) ;
if ( log )
log - > Printf ( " Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x% " PRIx64 , bp_site - > GetID ( ) , ( uint64_t ) bp_addr ) ;
if ( bp_site - > IsEnabled ( ) )
{
if ( log )
log - > Printf ( " Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x% " PRIx64 " -- already enabled " , bp_site - > GetID ( ) , ( uint64_t ) bp_addr ) ;
return error ;
}
if ( bp_addr = = LLDB_INVALID_ADDRESS )
{
error . SetErrorString ( " BreakpointSite contains an invalid load address. " ) ;
return error ;
}
// Ask the lldb::Process subclass to fill in the correct software breakpoint
// trap for the breakpoint site
const size_t bp_opcode_size = GetSoftwareBreakpointTrapOpcode ( bp_site ) ;
if ( bp_opcode_size = = 0 )
{
error . SetErrorStringWithFormat ( " Process::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x% " PRIx64 , bp_addr ) ;
}
else
{
const uint8_t * const bp_opcode_bytes = bp_site - > GetTrapOpcodeBytes ( ) ;
if ( bp_opcode_bytes = = NULL )
{
error . SetErrorString ( " BreakpointSite doesn't contain a valid breakpoint trap opcode. " ) ;
return error ;
}
// Save the original opcode by reading it
if ( DoReadMemory ( bp_addr , bp_site - > GetSavedOpcodeBytes ( ) , bp_opcode_size , error ) = = bp_opcode_size )
{
// Write a software breakpoint in place of the original opcode
if ( DoWriteMemory ( bp_addr , bp_opcode_bytes , bp_opcode_size , error ) = = bp_opcode_size )
{
uint8_t verify_bp_opcode_bytes [ 64 ] ;
if ( DoReadMemory ( bp_addr , verify_bp_opcode_bytes , bp_opcode_size , error ) = = bp_opcode_size )
{
if ( : : memcmp ( bp_opcode_bytes , verify_bp_opcode_bytes , bp_opcode_size ) = = 0 )
{
bp_site - > SetEnabled ( true ) ;
bp_site - > SetType ( BreakpointSite : : eSoftware ) ;
if ( log )
log - > Printf ( " Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x% " PRIx64 " -- SUCCESS " ,
bp_site - > GetID ( ) ,
( uint64_t ) bp_addr ) ;
}
else
error . SetErrorString ( " failed to verify the breakpoint trap in memory. " ) ;
}
else
error . SetErrorString ( " Unable to read memory to verify breakpoint trap. " ) ;
}
else
error . SetErrorString ( " Unable to write breakpoint trap to memory. " ) ;
}
else
error . SetErrorString ( " Unable to read memory at breakpoint address. " ) ;
}
if ( log & & error . Fail ( ) )
log - > Printf ( " Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x% " PRIx64 " -- FAILED: %s " ,
bp_site - > GetID ( ) ,
( uint64_t ) bp_addr ,
error . AsCString ( ) ) ;
return error ;
}
Error
Process : : DisableSoftwareBreakpoint ( BreakpointSite * bp_site )
{
Error error ;
assert ( bp_site ! = NULL ) ;
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_BREAKPOINTS ) ) ;
addr_t bp_addr = bp_site - > GetLoadAddress ( ) ;
lldb : : user_id_t breakID = bp_site - > GetID ( ) ;
if ( log )
log - > Printf ( " Process::DisableSoftwareBreakpoint (breakID = % " PRIu64 " ) addr = 0x% " PRIx64 , breakID , ( uint64_t ) bp_addr ) ;
if ( bp_site - > IsHardware ( ) )
{
error . SetErrorString ( " Breakpoint site is a hardware breakpoint. " ) ;
}
else if ( bp_site - > IsEnabled ( ) )
{
const size_t break_op_size = bp_site - > GetByteSize ( ) ;
const uint8_t * const break_op = bp_site - > GetTrapOpcodeBytes ( ) ;
if ( break_op_size > 0 )
{
2014-11-25 16:00:58 -05:00
// Clear a software breakpoint instruction
2013-08-23 13:46:38 -04:00
uint8_t curr_break_op [ 8 ] ;
assert ( break_op_size < = sizeof ( curr_break_op ) ) ;
bool break_op_found = false ;
// Read the breakpoint opcode
if ( DoReadMemory ( bp_addr , curr_break_op , break_op_size , error ) = = break_op_size )
{
bool verify = false ;
2015-07-03 12:57:06 -04:00
// Make sure the breakpoint opcode exists at this address
2013-08-23 13:46:38 -04:00
if ( : : memcmp ( curr_break_op , break_op , break_op_size ) = = 0 )
{
break_op_found = true ;
// We found a valid breakpoint opcode at this address, now restore
// the saved opcode.
if ( DoWriteMemory ( bp_addr , bp_site - > GetSavedOpcodeBytes ( ) , break_op_size , error ) = = break_op_size )
{
verify = true ;
}
else
error . SetErrorString ( " Memory write failed when restoring original opcode. " ) ;
}
else
{
error . SetErrorString ( " Original breakpoint trap is no longer in memory. " ) ;
// Set verify to true and so we can check if the original opcode has already been restored
verify = true ;
}
if ( verify )
{
uint8_t verify_opcode [ 8 ] ;
assert ( break_op_size < sizeof ( verify_opcode ) ) ;
// Verify that our original opcode made it back to the inferior
if ( DoReadMemory ( bp_addr , verify_opcode , break_op_size , error ) = = break_op_size )
{
// compare the memory we just read with the original opcode
if ( : : memcmp ( bp_site - > GetSavedOpcodeBytes ( ) , verify_opcode , break_op_size ) = = 0 )
{
// SUCCESS
bp_site - > SetEnabled ( false ) ;
if ( log )
log - > Printf ( " Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x% " PRIx64 " -- SUCCESS " , bp_site - > GetID ( ) , ( uint64_t ) bp_addr ) ;
return error ;
}
else
{
if ( break_op_found )
error . SetErrorString ( " Failed to restore original opcode. " ) ;
}
}
else
error . SetErrorString ( " Failed to read memory to verify that breakpoint trap was restored. " ) ;
}
}
else
error . SetErrorString ( " Unable to read memory that should contain the breakpoint trap. " ) ;
}
}
else
{
if ( log )
log - > Printf ( " Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x% " PRIx64 " -- already disabled " , bp_site - > GetID ( ) , ( uint64_t ) bp_addr ) ;
return error ;
}
if ( log )
log - > Printf ( " Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x% " PRIx64 " -- FAILED: %s " ,
bp_site - > GetID ( ) ,
( uint64_t ) bp_addr ,
error . AsCString ( ) ) ;
return error ;
}
// Uncomment to verify memory caching works after making changes to caching code
//#define VERIFY_MEMORY_READS
size_t
Process : : ReadMemory ( addr_t addr , void * buf , size_t size , Error & error )
{
2013-12-03 13:51:59 -05:00
error . Clear ( ) ;
2013-08-23 13:46:38 -04:00
if ( ! GetDisableMemoryCache ( ) )
{
# if defined (VERIFY_MEMORY_READS)
// Memory caching is enabled, with debug verification
if ( buf & & size )
{
// Uncomment the line below to make sure memory caching is working.
// I ran this through the test suite and got no assertions, so I am
// pretty confident this is working well. If any changes are made to
// memory caching, uncomment the line below and test your changes!
// Verify all memory reads by using the cache first, then redundantly
// reading the same memory from the inferior and comparing to make sure
// everything is exactly the same.
std : : string verify_buf ( size , ' \0 ' ) ;
assert ( verify_buf . size ( ) = = size ) ;
const size_t cache_bytes_read = m_memory_cache . Read ( this , addr , buf , size , error ) ;
Error verify_error ;
const size_t verify_bytes_read = ReadMemoryFromInferior ( addr , const_cast < char * > ( verify_buf . data ( ) ) , verify_buf . size ( ) , verify_error ) ;
assert ( cache_bytes_read = = verify_bytes_read ) ;
assert ( memcmp ( buf , verify_buf . data ( ) , verify_buf . size ( ) ) = = 0 ) ;
assert ( verify_error . Success ( ) = = error . Success ( ) ) ;
return cache_bytes_read ;
}
return 0 ;
# else // !defined(VERIFY_MEMORY_READS)
// Memory caching is enabled, without debug verification
return m_memory_cache . Read ( addr , buf , size , error ) ;
# endif // defined (VERIFY_MEMORY_READS)
}
else
{
// Memory caching is disabled
return ReadMemoryFromInferior ( addr , buf , size , error ) ;
}
}
size_t
Process : : ReadCStringFromMemory ( addr_t addr , std : : string & out_str , Error & error )
{
char buf [ 256 ] ;
out_str . clear ( ) ;
addr_t curr_addr = addr ;
while ( 1 )
{
size_t length = ReadCStringFromMemory ( curr_addr , buf , sizeof ( buf ) , error ) ;
if ( length = = 0 )
break ;
out_str . append ( buf , length ) ;
// If we got "length - 1" bytes, we didn't get the whole C string, we
// need to read some more characters
if ( length = = sizeof ( buf ) - 1 )
curr_addr + = length ;
else
break ;
}
return out_str . size ( ) ;
}
size_t
Process : : ReadStringFromMemory ( addr_t addr , char * dst , size_t max_bytes , Error & error ,
size_t type_width )
{
size_t total_bytes_read = 0 ;
if ( dst & & max_bytes & & type_width & & max_bytes > = type_width )
{
// Ensure a null terminator independent of the number of bytes that is read.
memset ( dst , 0 , max_bytes ) ;
size_t bytes_left = max_bytes - type_width ;
const char terminator [ 4 ] = { ' \0 ' , ' \0 ' , ' \0 ' , ' \0 ' } ;
assert ( sizeof ( terminator ) > = type_width & &
" Attempting to validate a string with more than 4 bytes per character! " ) ;
addr_t curr_addr = addr ;
const size_t cache_line_size = m_memory_cache . GetMemoryCacheLineSize ( ) ;
char * curr_dst = dst ;
error . Clear ( ) ;
while ( bytes_left > 0 & & error . Success ( ) )
{
addr_t cache_line_bytes_left = cache_line_size - ( curr_addr % cache_line_size ) ;
addr_t bytes_to_read = std : : min < addr_t > ( bytes_left , cache_line_bytes_left ) ;
size_t bytes_read = ReadMemory ( curr_addr , curr_dst , bytes_to_read , error ) ;
if ( bytes_read = = 0 )
break ;
// Search for a null terminator of correct size and alignment in bytes_read
size_t aligned_start = total_bytes_read - total_bytes_read % type_width ;
for ( size_t i = aligned_start ; i + type_width < = total_bytes_read + bytes_read ; i + = type_width )
if ( : : strncmp ( & dst [ i ] , terminator , type_width ) = = 0 )
{
error . Clear ( ) ;
return i ;
}
total_bytes_read + = bytes_read ;
curr_dst + = bytes_read ;
curr_addr + = bytes_read ;
bytes_left - = bytes_read ;
}
}
else
{
if ( max_bytes )
error . SetErrorString ( " invalid arguments " ) ;
}
return total_bytes_read ;
}
// Deprecated in favor of ReadStringFromMemory which has wchar support and correct code to find
// null terminators.
size_t
Process : : ReadCStringFromMemory ( addr_t addr , char * dst , size_t dst_max_len , Error & result_error )
{
size_t total_cstr_len = 0 ;
if ( dst & & dst_max_len )
{
result_error . Clear ( ) ;
// NULL out everything just to be safe
memset ( dst , 0 , dst_max_len ) ;
Error error ;
addr_t curr_addr = addr ;
const size_t cache_line_size = m_memory_cache . GetMemoryCacheLineSize ( ) ;
size_t bytes_left = dst_max_len - 1 ;
char * curr_dst = dst ;
while ( bytes_left > 0 )
{
addr_t cache_line_bytes_left = cache_line_size - ( curr_addr % cache_line_size ) ;
addr_t bytes_to_read = std : : min < addr_t > ( bytes_left , cache_line_bytes_left ) ;
size_t bytes_read = ReadMemory ( curr_addr , curr_dst , bytes_to_read , error ) ;
if ( bytes_read = = 0 )
{
result_error = error ;
dst [ total_cstr_len ] = ' \0 ' ;
break ;
}
const size_t len = strlen ( curr_dst ) ;
total_cstr_len + = len ;
if ( len < bytes_to_read )
break ;
curr_dst + = bytes_read ;
curr_addr + = bytes_read ;
bytes_left - = bytes_read ;
}
}
else
{
if ( dst = = NULL )
result_error . SetErrorString ( " invalid arguments " ) ;
else
result_error . Clear ( ) ;
}
return total_cstr_len ;
}
size_t
Process : : ReadMemoryFromInferior ( addr_t addr , void * buf , size_t size , Error & error )
{
if ( buf = = NULL | | size = = 0 )
return 0 ;
size_t bytes_read = 0 ;
uint8_t * bytes = ( uint8_t * ) buf ;
while ( bytes_read < size )
{
const size_t curr_size = size - bytes_read ;
const size_t curr_bytes_read = DoReadMemory ( addr + bytes_read ,
bytes + bytes_read ,
curr_size ,
error ) ;
bytes_read + = curr_bytes_read ;
if ( curr_bytes_read = = curr_size | | curr_bytes_read = = 0 )
break ;
}
// Replace any software breakpoint opcodes that fall into this range back
// into "buf" before we return
if ( bytes_read > 0 )
RemoveBreakpointOpcodesFromBuffer ( addr , bytes_read , ( uint8_t * ) buf ) ;
return bytes_read ;
}
uint64_t
Process : : ReadUnsignedIntegerFromMemory ( lldb : : addr_t vm_addr , size_t integer_byte_size , uint64_t fail_value , Error & error )
{
Scalar scalar ;
if ( ReadScalarIntegerFromMemory ( vm_addr , integer_byte_size , false , scalar , error ) )
return scalar . ULongLong ( fail_value ) ;
return fail_value ;
}
addr_t
Process : : ReadPointerFromMemory ( lldb : : addr_t vm_addr , Error & error )
{
Scalar scalar ;
if ( ReadScalarIntegerFromMemory ( vm_addr , GetAddressByteSize ( ) , false , scalar , error ) )
return scalar . ULongLong ( LLDB_INVALID_ADDRESS ) ;
return LLDB_INVALID_ADDRESS ;
}
bool
Process : : WritePointerToMemory ( lldb : : addr_t vm_addr ,
lldb : : addr_t ptr_value ,
Error & error )
{
Scalar scalar ;
const uint32_t addr_byte_size = GetAddressByteSize ( ) ;
if ( addr_byte_size < = 4 )
scalar = ( uint32_t ) ptr_value ;
else
scalar = ptr_value ;
return WriteScalarToMemory ( vm_addr , scalar , addr_byte_size , error ) = = addr_byte_size ;
}
size_t
Process : : WriteMemoryPrivate ( addr_t addr , const void * buf , size_t size , Error & error )
{
size_t bytes_written = 0 ;
const uint8_t * bytes = ( const uint8_t * ) buf ;
while ( bytes_written < size )
{
const size_t curr_size = size - bytes_written ;
const size_t curr_bytes_written = DoWriteMemory ( addr + bytes_written ,
bytes + bytes_written ,
curr_size ,
error ) ;
bytes_written + = curr_bytes_written ;
if ( curr_bytes_written = = curr_size | | curr_bytes_written = = 0 )
break ;
}
return bytes_written ;
}
size_t
Process : : WriteMemory ( addr_t addr , const void * buf , size_t size , Error & error )
{
# if defined (ENABLE_MEMORY_CACHING)
m_memory_cache . Flush ( addr , size ) ;
# endif
if ( buf = = NULL | | size = = 0 )
return 0 ;
m_mod_id . BumpMemoryID ( ) ;
// We need to write any data that would go where any current software traps
// (enabled software breakpoints) any software traps (breakpoints) that we
// may have placed in our tasks memory.
BreakpointSiteList bp_sites_in_range ;
if ( m_breakpoint_site_list . FindInRange ( addr , addr + size , bp_sites_in_range ) )
{
// No breakpoint sites overlap
if ( bp_sites_in_range . IsEmpty ( ) )
return WriteMemoryPrivate ( addr , buf , size , error ) ;
else
{
const uint8_t * ubuf = ( const uint8_t * ) buf ;
uint64_t bytes_written = 0 ;
bp_sites_in_range . ForEach ( [ this , addr , size , & bytes_written , & ubuf , & error ] ( BreakpointSite * bp ) - > void {
if ( error . Success ( ) )
{
addr_t intersect_addr ;
size_t intersect_size ;
size_t opcode_offset ;
const bool intersects = bp - > IntersectsRange ( addr , size , & intersect_addr , & intersect_size , & opcode_offset ) ;
assert ( intersects ) ;
assert ( addr < = intersect_addr & & intersect_addr < addr + size ) ;
assert ( addr < intersect_addr + intersect_size & & intersect_addr + intersect_size < = addr + size ) ;
assert ( opcode_offset + intersect_size < = bp - > GetByteSize ( ) ) ;
// Check for bytes before this breakpoint
const addr_t curr_addr = addr + bytes_written ;
if ( intersect_addr > curr_addr )
{
// There are some bytes before this breakpoint that we need to
// just write to memory
size_t curr_size = intersect_addr - curr_addr ;
size_t curr_bytes_written = WriteMemoryPrivate ( curr_addr ,
ubuf + bytes_written ,
curr_size ,
error ) ;
bytes_written + = curr_bytes_written ;
if ( curr_bytes_written ! = curr_size )
{
// We weren't able to write all of the requested bytes, we
// are done looping and will return the number of bytes that
// we have written so far.
if ( error . Success ( ) )
error . SetErrorToGenericError ( ) ;
}
}
// Now write any bytes that would cover up any software breakpoints
// directly into the breakpoint opcode buffer
: : memcpy ( bp - > GetSavedOpcodeBytes ( ) + opcode_offset , ubuf + bytes_written , intersect_size ) ;
bytes_written + = intersect_size ;
}
} ) ;
if ( bytes_written < size )
2015-02-06 16:38:51 -05:00
WriteMemoryPrivate ( addr + bytes_written ,
ubuf + bytes_written ,
size - bytes_written ,
error ) ;
2013-08-23 13:46:38 -04:00
}
}
else
{
return WriteMemoryPrivate ( addr , buf , size , error ) ;
}
// Write any remaining bytes after the last breakpoint if we have any left
return 0 ; //bytes_written;
}
size_t
Process : : WriteScalarToMemory ( addr_t addr , const Scalar & scalar , size_t byte_size , Error & error )
{
if ( byte_size = = UINT32_MAX )
byte_size = scalar . GetByteSize ( ) ;
if ( byte_size > 0 )
{
uint8_t buf [ 32 ] ;
const size_t mem_size = scalar . GetAsMemoryData ( buf , byte_size , GetByteOrder ( ) , error ) ;
if ( mem_size > 0 )
return WriteMemory ( addr , buf , mem_size , error ) ;
else
error . SetErrorString ( " failed to get scalar as memory data " ) ;
}
else
{
error . SetErrorString ( " invalid scalar value " ) ;
}
return 0 ;
}
size_t
Process : : ReadScalarIntegerFromMemory ( addr_t addr ,
uint32_t byte_size ,
bool is_signed ,
Scalar & scalar ,
Error & error )
{
uint64_t uval = 0 ;
if ( byte_size = = 0 )
{
error . SetErrorString ( " byte size is zero " ) ;
}
else if ( byte_size & ( byte_size - 1 ) )
{
error . SetErrorStringWithFormat ( " byte size %u is not a power of 2 " , byte_size ) ;
}
else if ( byte_size < = sizeof ( uval ) )
{
const size_t bytes_read = ReadMemory ( addr , & uval , byte_size , error ) ;
if ( bytes_read = = byte_size )
{
DataExtractor data ( & uval , sizeof ( uval ) , GetByteOrder ( ) , GetAddressByteSize ( ) ) ;
lldb : : offset_t offset = 0 ;
if ( byte_size < = 4 )
scalar = data . GetMaxU32 ( & offset , byte_size ) ;
else
scalar = data . GetMaxU64 ( & offset , byte_size ) ;
if ( is_signed )
scalar . SignExtend ( byte_size * 8 ) ;
return bytes_read ;
}
}
else
{
error . SetErrorStringWithFormat ( " byte size of %u is too large for integer scalar type " , byte_size ) ;
}
return 0 ;
}
# define USE_ALLOCATE_MEMORY_CACHE 1
addr_t
Process : : AllocateMemory ( size_t size , uint32_t permissions , Error & error )
{
if ( GetPrivateState ( ) ! = eStateStopped )
return LLDB_INVALID_ADDRESS ;
# if defined (USE_ALLOCATE_MEMORY_CACHE)
return m_allocated_memory_cache . AllocateMemory ( size , permissions , error ) ;
# else
addr_t allocated_addr = DoAllocateMemory ( size , permissions , error ) ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2013-11-06 11:48:53 -05:00
log - > Printf ( " Process::AllocateMemory(size=% " PRIu64 " , permissions=%s) => 0x%16.16 " PRIx64 " (m_stop_id = %u m_memory_id = %u) " ,
( uint64_t ) size ,
2013-08-23 13:46:38 -04:00
GetPermissionsAsCString ( permissions ) ,
( uint64_t ) allocated_addr ,
m_mod_id . GetStopID ( ) ,
m_mod_id . GetMemoryID ( ) ) ;
return allocated_addr ;
# endif
}
bool
Process : : CanJIT ( )
{
if ( m_can_jit = = eCanJITDontKnow )
{
2014-11-25 16:00:58 -05:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2013-08-23 13:46:38 -04:00
Error err ;
uint64_t allocated_memory = AllocateMemory ( 8 ,
ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable ,
err ) ;
if ( err . Success ( ) )
2014-11-25 16:00:58 -05:00
{
2013-08-23 13:46:38 -04:00
m_can_jit = eCanJITYes ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Process::%s pid % " PRIu64 " allocation test passed, CanJIT () is true " , __FUNCTION__ , GetID ( ) ) ;
}
2013-08-23 13:46:38 -04:00
else
2014-11-25 16:00:58 -05:00
{
2013-08-23 13:46:38 -04:00
m_can_jit = eCanJITNo ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Process::%s pid % " PRIu64 " allocation test failed, CanJIT () is false: %s " , __FUNCTION__ , GetID ( ) , err . AsCString ( ) ) ;
}
2013-08-23 13:46:38 -04:00
DeallocateMemory ( allocated_memory ) ;
}
return m_can_jit = = eCanJITYes ;
}
void
Process : : SetCanJIT ( bool can_jit )
{
m_can_jit = ( can_jit ? eCanJITYes : eCanJITNo ) ;
}
Error
Process : : DeallocateMemory ( addr_t ptr )
{
Error error ;
# if defined (USE_ALLOCATE_MEMORY_CACHE)
if ( ! m_allocated_memory_cache . DeallocateMemory ( ptr ) )
{
error . SetErrorStringWithFormat ( " deallocation of memory at 0x% " PRIx64 " failed. " , ( uint64_t ) ptr ) ;
}
# else
error = DoDeallocateMemory ( ptr ) ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::DeallocateMemory(addr=0x%16.16 " PRIx64 " ) => err = %s (m_stop_id = %u, m_memory_id = %u) " ,
ptr ,
error . AsCString ( " SUCCESS " ) ,
m_mod_id . GetStopID ( ) ,
m_mod_id . GetMemoryID ( ) ) ;
# endif
return error ;
}
ModuleSP
Process : : ReadModuleFromMemory ( const FileSpec & file_spec ,
2014-11-25 16:00:58 -05:00
lldb : : addr_t header_addr ,
size_t size_to_read )
2013-08-23 13:46:38 -04:00
{
ModuleSP module_sp ( new Module ( file_spec , ArchSpec ( ) ) ) ;
if ( module_sp )
{
Error error ;
2014-11-25 16:00:58 -05:00
ObjectFile * objfile = module_sp - > GetMemoryObjectFile ( shared_from_this ( ) , header_addr , error , size_to_read ) ;
2013-08-23 13:46:38 -04:00
if ( objfile )
return module_sp ;
}
return ModuleSP ( ) ;
}
2015-07-03 12:57:06 -04:00
bool
Process : : GetLoadAddressPermissions ( lldb : : addr_t load_addr , uint32_t & permissions )
{
MemoryRegionInfo range_info ;
permissions = 0 ;
Error error ( GetMemoryRegionInfo ( load_addr , range_info ) ) ;
if ( ! error . Success ( ) )
return false ;
if ( range_info . GetReadable ( ) = = MemoryRegionInfo : : eDontKnow
| | range_info . GetWritable ( ) = = MemoryRegionInfo : : eDontKnow
| | range_info . GetExecutable ( ) = = MemoryRegionInfo : : eDontKnow )
{
return false ;
}
if ( range_info . GetReadable ( ) = = MemoryRegionInfo : : eYes )
permissions | = lldb : : ePermissionsReadable ;
if ( range_info . GetWritable ( ) = = MemoryRegionInfo : : eYes )
permissions | = lldb : : ePermissionsWritable ;
if ( range_info . GetExecutable ( ) = = MemoryRegionInfo : : eYes )
permissions | = lldb : : ePermissionsExecutable ;
return true ;
}
2013-08-23 13:46:38 -04:00
Error
Process : : EnableWatchpoint ( Watchpoint * watchpoint , bool notify )
{
Error error ;
error . SetErrorString ( " watchpoints are not supported " ) ;
return error ;
}
Error
Process : : DisableWatchpoint ( Watchpoint * watchpoint , bool notify )
{
Error error ;
error . SetErrorString ( " watchpoints are not supported " ) ;
return error ;
}
StateType
Process : : WaitForProcessStopPrivate ( const TimeValue * timeout , EventSP & event_sp )
{
StateType state ;
// Now wait for the process to launch and return control to us, and then
// call DidLaunch:
while ( 1 )
{
event_sp . reset ( ) ;
state = WaitForStateChangedEventsPrivate ( timeout , event_sp ) ;
if ( StateIsStoppedState ( state , false ) )
break ;
// If state is invalid, then we timed out
if ( state = = eStateInvalid )
break ;
if ( event_sp )
HandlePrivateEvent ( event_sp ) ;
}
return state ;
}
2015-02-06 16:38:51 -05:00
void
Process : : LoadOperatingSystemPlugin ( bool flush )
{
if ( flush )
m_thread_list . Clear ( ) ;
m_os_ap . reset ( OperatingSystem : : FindPlugin ( this , NULL ) ) ;
if ( flush )
Flush ( ) ;
}
2013-08-23 13:46:38 -04:00
Error
2013-12-03 13:51:59 -05:00
Process : : Launch ( ProcessLaunchInfo & launch_info )
2013-08-23 13:46:38 -04:00
{
Error error ;
m_abi_sp . reset ( ) ;
m_dyld_ap . reset ( ) ;
2014-11-25 16:00:58 -05:00
m_jit_loaders_ap . reset ( ) ;
2013-11-06 11:48:53 -05:00
m_system_runtime_ap . reset ( ) ;
2013-08-23 13:46:38 -04:00
m_os_ap . reset ( ) ;
m_process_input_reader . reset ( ) ;
2015-02-06 16:38:51 -05:00
m_stop_info_override_callback = NULL ;
2013-08-23 13:46:38 -04:00
Module * exe_module = m_target . GetExecutableModulePointer ( ) ;
if ( exe_module )
{
char local_exec_file_path [ PATH_MAX ] ;
char platform_exec_file_path [ PATH_MAX ] ;
exe_module - > GetFileSpec ( ) . GetPath ( local_exec_file_path , sizeof ( local_exec_file_path ) ) ;
exe_module - > GetPlatformFileSpec ( ) . GetPath ( platform_exec_file_path , sizeof ( platform_exec_file_path ) ) ;
if ( exe_module - > GetFileSpec ( ) . Exists ( ) )
{
2013-12-03 13:51:59 -05:00
// Install anything that might need to be installed prior to launching.
// For host systems, this will do nothing, but if we are connected to a
// remote platform it will install any needed binaries
error = GetTarget ( ) . Install ( & launch_info ) ;
if ( error . Fail ( ) )
return error ;
2013-08-23 13:46:38 -04:00
if ( PrivateStateThreadIsValid ( ) )
PausePrivateStateThread ( ) ;
error = WillLaunch ( exe_module ) ;
if ( error . Success ( ) )
{
const bool restarted = false ;
SetPublicState ( eStateLaunching , restarted ) ;
m_should_detach = false ;
if ( m_public_run_lock . TrySetRunning ( ) )
{
// Now launch using these arguments.
error = DoLaunch ( exe_module , launch_info ) ;
}
else
{
// This shouldn't happen
error . SetErrorString ( " failed to acquire process run lock " ) ;
}
if ( error . Fail ( ) )
{
if ( GetID ( ) ! = LLDB_INVALID_PROCESS_ID )
{
SetID ( LLDB_INVALID_PROCESS_ID ) ;
const char * error_string = error . AsCString ( ) ;
if ( error_string = = NULL )
error_string = " launch failed " ;
SetExitStatus ( - 1 , error_string ) ;
}
}
else
{
EventSP event_sp ;
TimeValue timeout_time ;
timeout_time = TimeValue : : Now ( ) ;
timeout_time . OffsetWithSeconds ( 10 ) ;
StateType state = WaitForProcessStopPrivate ( & timeout_time , event_sp ) ;
if ( state = = eStateInvalid | | event_sp . get ( ) = = NULL )
{
// We were able to launch the process, but we failed to
// catch the initial stop.
2015-07-03 12:57:06 -04:00
error . SetErrorString ( " failed to catch stop after launch " ) ;
2013-08-23 13:46:38 -04:00
SetExitStatus ( 0 , " failed to catch stop after launch " ) ;
2015-07-03 12:57:06 -04:00
Destroy ( false ) ;
2013-08-23 13:46:38 -04:00
}
else if ( state = = eStateStopped | | state = = eStateCrashed )
{
DidLaunch ( ) ;
DynamicLoader * dyld = GetDynamicLoader ( ) ;
if ( dyld )
dyld - > DidLaunch ( ) ;
2014-11-25 16:00:58 -05:00
GetJITLoaders ( ) . DidLaunch ( ) ;
2013-11-06 11:48:53 -05:00
SystemRuntime * system_runtime = GetSystemRuntime ( ) ;
if ( system_runtime )
system_runtime - > DidLaunch ( ) ;
2015-02-06 16:38:51 -05:00
LoadOperatingSystemPlugin ( false ) ;
// Note, the stop event was consumed above, but not handled. This was done
// to give DidLaunch a chance to run. The target is either stopped or crashed.
// Directly set the state. This is done to prevent a stop message with a bunch
// of spurious output on thread status, as well as not pop a ProcessIOHandler.
SetPublicState ( state , false ) ;
2013-08-23 13:46:38 -04:00
if ( PrivateStateThreadIsValid ( ) )
ResumePrivateStateThread ( ) ;
else
StartPrivateStateThread ( ) ;
2015-02-06 16:38:51 -05:00
m_stop_info_override_callback = GetTarget ( ) . GetArchitecture ( ) . GetStopInfoOverrideCallback ( ) ;
2015-02-08 20:44:09 -05:00
// Target was stopped at entry as was intended. Need to notify the listeners
// about it.
2015-07-03 12:57:06 -04:00
if ( state = = eStateStopped & & launch_info . GetFlags ( ) . Test ( eLaunchFlagStopAtEntry ) )
2015-02-08 20:44:09 -05:00
HandlePrivateEvent ( event_sp ) ;
2013-08-23 13:46:38 -04:00
}
else if ( state = = eStateExited )
{
// We exited while trying to launch somehow. Don't call DidLaunch as that's
// not likely to work, and return an invalid pid.
HandlePrivateEvent ( event_sp ) ;
}
}
}
}
else
{
error . SetErrorStringWithFormat ( " file doesn't exist: '%s' " , local_exec_file_path ) ;
}
}
return error ;
}
Error
Process : : LoadCore ( )
{
Error error = DoLoadCore ( ) ;
if ( error . Success ( ) )
{
2015-07-03 12:57:06 -04:00
Listener listener ( " lldb.process.load_core_listener " ) ;
HijackProcessEvents ( & listener ) ;
2013-08-23 13:46:38 -04:00
if ( PrivateStateThreadIsValid ( ) )
ResumePrivateStateThread ( ) ;
else
StartPrivateStateThread ( ) ;
DynamicLoader * dyld = GetDynamicLoader ( ) ;
if ( dyld )
dyld - > DidAttach ( ) ;
2014-11-25 16:00:58 -05:00
GetJITLoaders ( ) . DidAttach ( ) ;
2013-08-23 13:46:38 -04:00
2013-11-06 11:48:53 -05:00
SystemRuntime * system_runtime = GetSystemRuntime ( ) ;
if ( system_runtime )
system_runtime - > DidAttach ( ) ;
2013-08-23 13:46:38 -04:00
m_os_ap . reset ( OperatingSystem : : FindPlugin ( this , NULL ) ) ;
// We successfully loaded a core file, now pretend we stopped so we can
// show all of the threads in the core file and explore the crashed
// state.
SetPrivateState ( eStateStopped ) ;
2015-07-03 12:57:06 -04:00
// Wait indefinitely for a stopped event since we just posted one above...
lldb : : EventSP event_sp ;
listener . WaitForEvent ( NULL , event_sp ) ;
StateType state = ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( ! StateIsStoppedState ( state , false ) )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::Halt() failed to stop, state is: %s " , StateAsCString ( state ) ) ;
error . SetErrorString ( " Did not get stopped event after loading the core file. " ) ;
}
RestoreProcessEvents ( ) ;
2013-08-23 13:46:38 -04:00
}
return error ;
}
DynamicLoader *
Process : : GetDynamicLoader ( )
{
if ( m_dyld_ap . get ( ) = = NULL )
m_dyld_ap . reset ( DynamicLoader : : FindPlugin ( this , NULL ) ) ;
return m_dyld_ap . get ( ) ;
}
2014-11-25 16:00:58 -05:00
const lldb : : DataBufferSP
Process : : GetAuxvData ( )
{
return DataBufferSP ( ) ;
}
JITLoaderList &
Process : : GetJITLoaders ( )
{
if ( ! m_jit_loaders_ap )
{
m_jit_loaders_ap . reset ( new JITLoaderList ( ) ) ;
JITLoader : : LoadPlugins ( this , * m_jit_loaders_ap ) ;
}
return * m_jit_loaders_ap ;
}
2013-11-06 11:48:53 -05:00
SystemRuntime *
Process : : GetSystemRuntime ( )
{
if ( m_system_runtime_ap . get ( ) = = NULL )
m_system_runtime_ap . reset ( SystemRuntime : : FindPlugin ( this ) ) ;
return m_system_runtime_ap . get ( ) ;
}
2014-11-25 16:00:58 -05:00
Process : : AttachCompletionHandler : : AttachCompletionHandler ( Process * process , uint32_t exec_count ) :
NextEventAction ( process ) ,
m_exec_count ( exec_count )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::AttachCompletionHandler::%s process=%p, exec_count=% " PRIu32 , __FUNCTION__ , static_cast < void * > ( process ) , exec_count ) ;
}
2013-08-23 13:46:38 -04:00
Process : : NextEventAction : : EventActionResult
Process : : AttachCompletionHandler : : PerformAction ( lldb : : EventSP & event_sp )
{
2014-11-25 16:00:58 -05:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
2013-08-23 13:46:38 -04:00
StateType state = ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Process::AttachCompletionHandler::%s called with state %s (%d) " , __FUNCTION__ , StateAsCString ( state ) , static_cast < int > ( state ) ) ;
switch ( state )
2013-08-23 13:46:38 -04:00
{
2015-07-03 12:57:06 -04:00
case eStateAttaching :
return eEventActionSuccess ;
2013-08-23 13:46:38 -04:00
case eStateRunning :
case eStateConnected :
return eEventActionRetry ;
case eStateStopped :
case eStateCrashed :
{
// During attach, prior to sending the eStateStopped event,
// lldb_private::Process subclasses must set the new process ID.
assert ( m_process - > GetID ( ) ! = LLDB_INVALID_PROCESS_ID ) ;
// We don't want these events to be reported, so go set the ShouldReportStop here:
m_process - > GetThreadList ( ) . SetShouldReportStop ( eVoteNo ) ;
if ( m_exec_count > 0 )
{
- - m_exec_count ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Process::AttachCompletionHandler::%s state %s: reduced remaining exec count to % " PRIu32 " , requesting resume " , __FUNCTION__ , StateAsCString ( state ) , m_exec_count ) ;
2013-08-23 13:46:38 -04:00
RequestResume ( ) ;
return eEventActionRetry ;
}
else
{
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Process::AttachCompletionHandler::%s state %s: no more execs expected to start, continuing with attach " , __FUNCTION__ , StateAsCString ( state ) ) ;
2013-08-23 13:46:38 -04:00
m_process - > CompleteAttach ( ) ;
return eEventActionSuccess ;
}
}
break ;
default :
case eStateExited :
case eStateInvalid :
break ;
}
m_exit_string . assign ( " No valid Process " ) ;
return eEventActionExit ;
}
Process : : NextEventAction : : EventActionResult
Process : : AttachCompletionHandler : : HandleBeingInterrupted ( )
{
return eEventActionSuccess ;
}
const char *
Process : : AttachCompletionHandler : : GetExitString ( )
{
return m_exit_string . c_str ( ) ;
}
2015-02-06 16:38:51 -05:00
Listener &
ProcessAttachInfo : : GetListenerForProcess ( Debugger & debugger )
{
if ( m_listener_sp )
return * m_listener_sp ;
else
return debugger . GetListener ( ) ;
}
2013-08-23 13:46:38 -04:00
Error
Process : : Attach ( ProcessAttachInfo & attach_info )
{
m_abi_sp . reset ( ) ;
m_process_input_reader . reset ( ) ;
m_dyld_ap . reset ( ) ;
2014-11-25 16:00:58 -05:00
m_jit_loaders_ap . reset ( ) ;
2013-11-06 11:48:53 -05:00
m_system_runtime_ap . reset ( ) ;
2013-08-23 13:46:38 -04:00
m_os_ap . reset ( ) ;
2015-02-06 16:38:51 -05:00
m_stop_info_override_callback = NULL ;
2013-08-23 13:46:38 -04:00
lldb : : pid_t attach_pid = attach_info . GetProcessID ( ) ;
Error error ;
if ( attach_pid = = LLDB_INVALID_PROCESS_ID )
{
char process_name [ PATH_MAX ] ;
if ( attach_info . GetExecutableFile ( ) . GetPath ( process_name , sizeof ( process_name ) ) )
{
const bool wait_for_launch = attach_info . GetWaitForLaunch ( ) ;
if ( wait_for_launch )
{
error = WillAttachToProcessWithName ( process_name , wait_for_launch ) ;
if ( error . Success ( ) )
{
if ( m_public_run_lock . TrySetRunning ( ) )
{
m_should_detach = true ;
const bool restarted = false ;
SetPublicState ( eStateAttaching , restarted ) ;
// Now attach using these arguments.
2014-02-18 11:23:10 -05:00
error = DoAttachToProcessWithName ( process_name , attach_info ) ;
2013-08-23 13:46:38 -04:00
}
else
{
// This shouldn't happen
error . SetErrorString ( " failed to acquire process run lock " ) ;
}
if ( error . Fail ( ) )
{
if ( GetID ( ) ! = LLDB_INVALID_PROCESS_ID )
{
SetID ( LLDB_INVALID_PROCESS_ID ) ;
if ( error . AsCString ( ) = = NULL )
error . SetErrorString ( " attach failed " ) ;
SetExitStatus ( - 1 , error . AsCString ( ) ) ;
}
}
else
{
SetNextEventAction ( new Process : : AttachCompletionHandler ( this , attach_info . GetResumeCount ( ) ) ) ;
StartPrivateStateThread ( ) ;
}
return error ;
}
}
else
{
ProcessInstanceInfoList process_infos ;
PlatformSP platform_sp ( m_target . GetPlatform ( ) ) ;
if ( platform_sp )
{
ProcessInstanceInfoMatch match_info ;
match_info . GetProcessInfo ( ) = attach_info ;
match_info . SetNameMatchType ( eNameMatchEquals ) ;
platform_sp - > FindProcesses ( match_info , process_infos ) ;
const uint32_t num_matches = process_infos . GetSize ( ) ;
if ( num_matches = = 1 )
{
attach_pid = process_infos . GetProcessIDAtIndex ( 0 ) ;
// Fall through and attach using the above process ID
}
else
{
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . GetPath ( process_name , sizeof ( process_name ) ) ;
if ( num_matches > 1 )
2014-11-25 16:00:58 -05:00
{
StreamString s ;
ProcessInstanceInfo : : DumpTableHeader ( s , platform_sp . get ( ) , true , false ) ;
for ( size_t i = 0 ; i < num_matches ; i + + )
{
process_infos . GetProcessInfoAtIndex ( i ) . DumpAsTableRow ( s , platform_sp . get ( ) , true , false ) ;
}
error . SetErrorStringWithFormat ( " more than one process named %s: \n %s " ,
process_name ,
s . GetData ( ) ) ;
}
2013-08-23 13:46:38 -04:00
else
error . SetErrorStringWithFormat ( " could not find a process named %s " , process_name ) ;
}
}
else
{
error . SetErrorString ( " invalid platform, can't find processes by name " ) ;
return error ;
}
}
}
else
{
error . SetErrorString ( " invalid process name " ) ;
}
}
if ( attach_pid ! = LLDB_INVALID_PROCESS_ID )
{
error = WillAttachToProcessWithID ( attach_pid ) ;
if ( error . Success ( ) )
{
if ( m_public_run_lock . TrySetRunning ( ) )
{
// Now attach using these arguments.
m_should_detach = true ;
const bool restarted = false ;
SetPublicState ( eStateAttaching , restarted ) ;
error = DoAttachToProcessWithID ( attach_pid , attach_info ) ;
}
else
{
// This shouldn't happen
error . SetErrorString ( " failed to acquire process run lock " ) ;
}
if ( error . Success ( ) )
{
SetNextEventAction ( new Process : : AttachCompletionHandler ( this , attach_info . GetResumeCount ( ) ) ) ;
StartPrivateStateThread ( ) ;
}
else
{
if ( GetID ( ) ! = LLDB_INVALID_PROCESS_ID )
SetID ( LLDB_INVALID_PROCESS_ID ) ;
2015-02-06 16:38:51 -05:00
const char * error_string = error . AsCString ( ) ;
if ( error_string = = NULL )
error_string = " attach failed " ;
SetExitStatus ( - 1 , error_string ) ;
2013-08-23 13:46:38 -04:00
}
}
}
return error ;
}
void
Process : : CompleteAttach ( )
{
2014-11-25 16:00:58 -05:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::%s() " , __FUNCTION__ ) ;
2013-08-23 13:46:38 -04:00
// Let the process subclass figure out at much as it can about the process
// before we go looking for a dynamic loader plug-in.
2014-11-25 16:00:58 -05:00
ArchSpec process_arch ;
DidAttach ( process_arch ) ;
if ( process_arch . IsValid ( ) )
{
m_target . SetArchitecture ( process_arch ) ;
if ( log )
{
const char * triple_str = process_arch . GetTriple ( ) . getTriple ( ) . c_str ( ) ;
log - > Printf ( " Process::%s replacing process architecture with DidAttach() architecture: %s " ,
__FUNCTION__ ,
triple_str ? triple_str : " <null> " ) ;
}
}
2013-08-23 13:46:38 -04:00
// We just attached. If we have a platform, ask it for the process architecture, and if it isn't
// the same as the one we've already set, switch architectures.
PlatformSP platform_sp ( m_target . GetPlatform ( ) ) ;
assert ( platform_sp . get ( ) ) ;
if ( platform_sp )
{
const ArchSpec & target_arch = m_target . GetArchitecture ( ) ;
if ( target_arch . IsValid ( ) & & ! platform_sp - > IsCompatibleArchitecture ( target_arch , false , NULL ) )
{
ArchSpec platform_arch ;
platform_sp = platform_sp - > GetPlatformForArchitecture ( target_arch , & platform_arch ) ;
if ( platform_sp )
{
m_target . SetPlatform ( platform_sp ) ;
m_target . SetArchitecture ( platform_arch ) ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Process::%s switching platform to %s and architecture to %s based on info from attach " , __FUNCTION__ , platform_sp - > GetName ( ) . AsCString ( " " ) , platform_arch . GetTriple ( ) . getTriple ( ) . c_str ( ) ) ;
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
else if ( ! process_arch . IsValid ( ) )
2013-08-23 13:46:38 -04:00
{
ProcessInstanceInfo process_info ;
platform_sp - > GetProcessInfo ( GetID ( ) , process_info ) ;
const ArchSpec & process_arch = process_info . GetArchitecture ( ) ;
if ( process_arch . IsValid ( ) & & ! m_target . GetArchitecture ( ) . IsExactMatch ( process_arch ) )
2014-11-25 16:00:58 -05:00
{
2013-08-23 13:46:38 -04:00
m_target . SetArchitecture ( process_arch ) ;
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Process::%s switching architecture to %s based on info the platform retrieved for pid % " PRIu64 , __FUNCTION__ , process_arch . GetTriple ( ) . getTriple ( ) . c_str ( ) , GetID ( ) ) ;
}
2013-08-23 13:46:38 -04:00
}
}
// We have completed the attach, now it is time to find the dynamic loader
// plug-in
DynamicLoader * dyld = GetDynamicLoader ( ) ;
if ( dyld )
2014-11-25 16:00:58 -05:00
{
2013-08-23 13:46:38 -04:00
dyld - > DidAttach ( ) ;
2014-11-25 16:00:58 -05:00
if ( log )
{
ModuleSP exe_module_sp = m_target . GetExecutableModule ( ) ;
log - > Printf ( " Process::%s after DynamicLoader::DidAttach(), target executable is %s (using %s plugin) " ,
__FUNCTION__ ,
exe_module_sp ? exe_module_sp - > GetFileSpec ( ) . GetPath ( ) . c_str ( ) : " <none> " ,
dyld - > GetPluginName ( ) . AsCString ( " <unnamed> " ) ) ;
}
}
GetJITLoaders ( ) . DidAttach ( ) ;
2013-08-23 13:46:38 -04:00
2013-11-06 11:48:53 -05:00
SystemRuntime * system_runtime = GetSystemRuntime ( ) ;
if ( system_runtime )
2014-11-25 16:00:58 -05:00
{
2013-11-06 11:48:53 -05:00
system_runtime - > DidAttach ( ) ;
2014-11-25 16:00:58 -05:00
if ( log )
{
ModuleSP exe_module_sp = m_target . GetExecutableModule ( ) ;
log - > Printf ( " Process::%s after SystemRuntime::DidAttach(), target executable is %s (using %s plugin) " ,
__FUNCTION__ ,
exe_module_sp ? exe_module_sp - > GetFileSpec ( ) . GetPath ( ) . c_str ( ) : " <none> " ,
system_runtime - > GetPluginName ( ) . AsCString ( " <unnamed> " ) ) ;
}
}
2013-11-06 11:48:53 -05:00
2013-08-23 13:46:38 -04:00
m_os_ap . reset ( OperatingSystem : : FindPlugin ( this , NULL ) ) ;
// Figure out which one is the executable, and set that in our target:
const ModuleList & target_modules = m_target . GetImages ( ) ;
Mutex : : Locker modules_locker ( target_modules . GetMutex ( ) ) ;
size_t num_modules = target_modules . GetSize ( ) ;
ModuleSP new_executable_module_sp ;
for ( size_t i = 0 ; i < num_modules ; i + + )
{
ModuleSP module_sp ( target_modules . GetModuleAtIndexUnlocked ( i ) ) ;
if ( module_sp & & module_sp - > IsExecutable ( ) )
{
if ( m_target . GetExecutableModulePointer ( ) ! = module_sp . get ( ) )
new_executable_module_sp = module_sp ;
break ;
}
}
if ( new_executable_module_sp )
2014-11-25 16:00:58 -05:00
{
2013-08-23 13:46:38 -04:00
m_target . SetExecutableModule ( new_executable_module_sp , false ) ;
2014-11-25 16:00:58 -05:00
if ( log )
{
ModuleSP exe_module_sp = m_target . GetExecutableModule ( ) ;
log - > Printf ( " Process::%s after looping through modules, target executable is %s " ,
__FUNCTION__ ,
exe_module_sp ? exe_module_sp - > GetFileSpec ( ) . GetPath ( ) . c_str ( ) : " <none> " ) ;
}
}
2015-02-06 16:38:51 -05:00
m_stop_info_override_callback = process_arch . GetStopInfoOverrideCallback ( ) ;
2013-08-23 13:46:38 -04:00
}
Error
Process : : ConnectRemote ( Stream * strm , const char * remote_url )
{
m_abi_sp . reset ( ) ;
m_process_input_reader . reset ( ) ;
// Find the process and its architecture. Make sure it matches the architecture
// of the current Target, and if not adjust it.
Error error ( DoConnectRemote ( strm , remote_url ) ) ;
if ( error . Success ( ) )
{
if ( GetID ( ) ! = LLDB_INVALID_PROCESS_ID )
{
EventSP event_sp ;
StateType state = WaitForProcessStopPrivate ( NULL , event_sp ) ;
if ( state = = eStateStopped | | state = = eStateCrashed )
{
// If we attached and actually have a process on the other end, then
// this ended up being the equivalent of an attach.
CompleteAttach ( ) ;
// This delays passing the stopped event to listeners till
// CompleteAttach gets a chance to complete...
HandlePrivateEvent ( event_sp ) ;
}
}
if ( PrivateStateThreadIsValid ( ) )
ResumePrivateStateThread ( ) ;
else
StartPrivateStateThread ( ) ;
}
return error ;
}
Error
Process : : PrivateResume ( )
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_STEP ) ) ;
if ( log )
log - > Printf ( " Process::PrivateResume() m_stop_id = %u, public state: %s private state: %s " ,
m_mod_id . GetStopID ( ) ,
StateAsCString ( m_public_state . GetValue ( ) ) ,
StateAsCString ( m_private_state . GetValue ( ) ) ) ;
Error error ( WillResume ( ) ) ;
// Tell the process it is about to resume before the thread list
if ( error . Success ( ) )
{
// Now let the thread list know we are about to resume so it
// can let all of our threads know that they are about to be
// resumed. Threads will each be called with
// Thread::WillResume(StateType) where StateType contains the state
// that they are supposed to have when the process is resumed
// (suspended/running/stepping). Threads should also check
// their resume signal in lldb::Thread::GetResumeSignal()
// to see if they are supposed to start back up with a signal.
if ( m_thread_list . WillResume ( ) )
{
// Last thing, do the PreResumeActions.
if ( ! RunPreResumeActions ( ) )
{
error . SetErrorStringWithFormat ( " Process::PrivateResume PreResumeActions failed, not resuming. " ) ;
}
else
{
m_mod_id . BumpResumeID ( ) ;
error = DoResume ( ) ;
if ( error . Success ( ) )
{
DidResume ( ) ;
m_thread_list . DidResume ( ) ;
if ( log )
log - > Printf ( " Process thinks the process has resumed. " ) ;
}
}
}
else
{
2015-02-08 20:44:09 -05:00
// Somebody wanted to run without running (e.g. we were faking a step from one frame of a set of inlined
// frames that share the same PC to another.) So generate a continue & a stopped event,
2013-08-23 13:46:38 -04:00
// and let the world handle them.
if ( log )
log - > Printf ( " Process::PrivateResume() asked to simulate a start & stop. " ) ;
SetPrivateState ( eStateRunning ) ;
SetPrivateState ( eStateStopped ) ;
}
}
else if ( log )
log - > Printf ( " Process::PrivateResume() got an error \" %s \" . " , error . AsCString ( " <unknown error> " ) ) ;
return error ;
}
Error
Process : : Halt ( bool clear_thread_plans )
{
// Don't clear the m_clear_thread_plans_on_stop, only set it to true if
// in case it was already set and some thread plan logic calls halt on its
// own.
m_clear_thread_plans_on_stop | = clear_thread_plans ;
// First make sure we aren't in the middle of handling an event, or we might restart. This is pretty weak, since
// we could just straightaway get another event. It just narrows the window...
m_currently_handling_event . WaitForValueEqualTo ( false ) ;
// Pause our private state thread so we can ensure no one else eats
// the stop event out from under us.
Listener halt_listener ( " lldb.process.halt_listener " ) ;
HijackPrivateProcessEvents ( & halt_listener ) ;
EventSP event_sp ;
Error error ( WillHalt ( ) ) ;
2014-11-25 16:00:58 -05:00
bool restored_process_events = false ;
2013-08-23 13:46:38 -04:00
if ( error . Success ( ) )
{
bool caused_stop = false ;
// Ask the process subclass to actually halt our process
error = DoHalt ( caused_stop ) ;
if ( error . Success ( ) )
{
if ( m_public_state . GetValue ( ) = = eStateAttaching )
{
2014-11-25 16:00:58 -05:00
// Don't hijack and eat the eStateExited as the code that was doing
// the attach will be waiting for this event...
RestorePrivateProcessEvents ( ) ;
restored_process_events = true ;
2013-08-23 13:46:38 -04:00
SetExitStatus ( SIGKILL , " Cancelled async attach. " ) ;
2015-07-03 12:57:06 -04:00
Destroy ( false ) ;
2013-08-23 13:46:38 -04:00
}
else
{
// If "caused_stop" is true, then DoHalt stopped the process. If
// "caused_stop" is false, the process was already stopped.
// If the DoHalt caused the process to stop, then we want to catch
// this event and set the interrupted bool to true before we pass
// this along so clients know that the process was interrupted by
// a halt command.
if ( caused_stop )
{
// Wait for 1 second for the process to stop.
TimeValue timeout_time ;
timeout_time = TimeValue : : Now ( ) ;
2014-11-25 16:00:58 -05:00
timeout_time . OffsetWithSeconds ( 10 ) ;
2013-08-23 13:46:38 -04:00
bool got_event = halt_listener . WaitForEvent ( & timeout_time , event_sp ) ;
StateType state = ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( ! got_event | | state = = eStateInvalid )
{
// We timeout out and didn't get a stop event...
error . SetErrorStringWithFormat ( " Halt timed out. State = %s " , StateAsCString ( GetState ( ) ) ) ;
}
else
{
if ( StateIsStoppedState ( state , false ) )
{
// We caused the process to interrupt itself, so mark this
// as such in the stop event so clients can tell an interrupted
// process from a natural stop
ProcessEventData : : SetInterruptedInEvent ( event_sp . get ( ) , true ) ;
}
else
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::Halt() failed to stop, state is: %s " , StateAsCString ( state ) ) ;
error . SetErrorString ( " Did not get stopped event after halt. " ) ;
}
}
}
DidHalt ( ) ;
}
}
}
// Resume our private state thread before we post the event (if any)
2014-11-25 16:00:58 -05:00
if ( ! restored_process_events )
RestorePrivateProcessEvents ( ) ;
2013-08-23 13:46:38 -04:00
// Post any event we might have consumed. If all goes well, we will have
// stopped the process, intercepted the event and set the interrupted
// bool in the event. Post it to the private event queue and that will end up
// correctly setting the state.
if ( event_sp )
m_private_state_broadcaster . BroadcastEvent ( event_sp ) ;
return error ;
}
Error
Process : : HaltForDestroyOrDetach ( lldb : : EventSP & exit_event_sp )
{
Error error ;
if ( m_public_state . GetValue ( ) = = eStateRunning )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::Destroy() About to halt. " ) ;
error = Halt ( ) ;
if ( error . Success ( ) )
{
// Consume the halt event.
TimeValue timeout ( TimeValue : : Now ( ) ) ;
timeout . OffsetWithSeconds ( 1 ) ;
StateType state = WaitForProcessToStop ( & timeout , & exit_event_sp ) ;
// If the process exited while we were waiting for it to stop, put the exited event into
// the shared pointer passed in and return. Our caller doesn't need to do anything else, since
// they don't have a process anymore...
if ( state = = eStateExited | | m_private_state . GetValue ( ) = = eStateExited )
{
if ( log )
log - > Printf ( " Process::HaltForDestroyOrDetach() Process exited while waiting to Halt. " ) ;
return error ;
}
else
exit_event_sp . reset ( ) ; // It is ok to consume any non-exit stop events
if ( state ! = eStateStopped )
{
if ( log )
log - > Printf ( " Process::HaltForDestroyOrDetach() Halt failed to stop, state is: %s " , StateAsCString ( state ) ) ;
// If we really couldn't stop the process then we should just error out here, but if the
// lower levels just bobbled sending the event and we really are stopped, then continue on.
StateType private_state = m_private_state . GetValue ( ) ;
if ( private_state ! = eStateStopped )
{
return error ;
}
}
}
else
{
if ( log )
log - > Printf ( " Process::HaltForDestroyOrDetach() Halt got error: %s " , error . AsCString ( ) ) ;
}
}
return error ;
}
Error
Process : : Detach ( bool keep_stopped )
{
EventSP exit_event_sp ;
Error error ;
m_destroy_in_process = true ;
error = WillDetach ( ) ;
if ( error . Success ( ) )
{
if ( DetachRequiresHalt ( ) )
{
error = HaltForDestroyOrDetach ( exit_event_sp ) ;
if ( ! error . Success ( ) )
{
m_destroy_in_process = false ;
return error ;
}
else if ( exit_event_sp )
{
// We shouldn't need to do anything else here. There's no process left to detach from...
StopPrivateStateThread ( ) ;
m_destroy_in_process = false ;
return error ;
}
}
2014-11-25 16:00:58 -05:00
m_thread_list . DiscardThreadPlans ( ) ;
DisableAllBreakpointSites ( ) ;
2013-08-23 13:46:38 -04:00
error = DoDetach ( keep_stopped ) ;
if ( error . Success ( ) )
{
DidDetach ( ) ;
StopPrivateStateThread ( ) ;
}
else
{
return error ;
}
}
m_destroy_in_process = false ;
// If we exited when we were waiting for a process to stop, then
// forward the event here so we don't lose the event
if ( exit_event_sp )
{
// Directly broadcast our exited event because we shut down our
// private state thread above
BroadcastEvent ( exit_event_sp ) ;
}
// If we have been interrupted (to kill us) in the middle of running, we may not end up propagating
// the last events through the event system, in which case we might strand the write lock. Unlock
// it here so when we do to tear down the process we don't get an error destroying the lock.
m_public_run_lock . SetStopped ( ) ;
return error ;
}
Error
2015-07-03 12:57:06 -04:00
Process : : Destroy ( bool force_kill )
2013-08-23 13:46:38 -04:00
{
// Tell ourselves we are in the process of destroying the process, so that we don't do any unnecessary work
// that might hinder the destruction. Remember to set this back to false when we are done. That way if the attempt
// failed and the process stays around for some reason it won't be in a confused state.
2015-07-03 12:57:06 -04:00
if ( force_kill )
m_should_detach = false ;
2013-08-23 13:46:38 -04:00
2015-07-03 12:57:06 -04:00
if ( GetShouldDetach ( ) )
{
// FIXME: This will have to be a process setting:
bool keep_stopped = false ;
Detach ( keep_stopped ) ;
}
2013-08-23 13:46:38 -04:00
m_destroy_in_process = true ;
Error error ( WillDestroy ( ) ) ;
if ( error . Success ( ) )
{
EventSP exit_event_sp ;
if ( DestroyRequiresHalt ( ) )
{
error = HaltForDestroyOrDetach ( exit_event_sp ) ;
}
if ( m_public_state . GetValue ( ) ! = eStateRunning )
{
// Ditch all thread plans, and remove all our breakpoints: in case we have to restart the target to
// kill it, we don't want it hitting a breakpoint...
// Only do this if we've stopped, however, since if we didn't manage to halt it above, then
// we're not going to have much luck doing this now.
m_thread_list . DiscardThreadPlans ( ) ;
DisableAllBreakpointSites ( ) ;
}
error = DoDestroy ( ) ;
if ( error . Success ( ) )
{
DidDestroy ( ) ;
StopPrivateStateThread ( ) ;
}
m_stdio_communication . Disconnect ( ) ;
2015-07-03 12:57:06 -04:00
m_stdio_communication . StopReadThread ( ) ;
m_stdin_forward = false ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( m_process_input_reader )
2014-11-25 16:00:58 -05:00
{
m_process_input_reader - > SetIsDone ( true ) ;
m_process_input_reader - > Cancel ( ) ;
2013-08-23 13:46:38 -04:00
m_process_input_reader . reset ( ) ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
// If we exited when we were waiting for a process to stop, then
// forward the event here so we don't lose the event
if ( exit_event_sp )
{
// Directly broadcast our exited event because we shut down our
// private state thread above
BroadcastEvent ( exit_event_sp ) ;
}
// If we have been interrupted (to kill us) in the middle of running, we may not end up propagating
// the last events through the event system, in which case we might strand the write lock. Unlock
// it here so when we do to tear down the process we don't get an error destroying the lock.
m_public_run_lock . SetStopped ( ) ;
}
m_destroy_in_process = false ;
return error ;
}
Error
Process : : Signal ( int signal )
{
Error error ( WillSignal ( ) ) ;
if ( error . Success ( ) )
{
error = DoSignal ( signal ) ;
if ( error . Success ( ) )
DidSignal ( ) ;
}
return error ;
}
2015-07-03 12:57:06 -04:00
void
Process : : SetUnixSignals ( const UnixSignalsSP & signals_sp )
{
assert ( signals_sp & & " null signals_sp " ) ;
m_unix_signals_sp = signals_sp ;
}
UnixSignals &
Process : : GetUnixSignals ( )
{
assert ( m_unix_signals_sp & & " null m_unix_signals_sp " ) ;
return * m_unix_signals_sp ;
}
2013-08-23 13:46:38 -04:00
lldb : : ByteOrder
Process : : GetByteOrder ( ) const
{
return m_target . GetArchitecture ( ) . GetByteOrder ( ) ;
}
uint32_t
Process : : GetAddressByteSize ( ) const
{
return m_target . GetArchitecture ( ) . GetAddressByteSize ( ) ;
}
bool
Process : : ShouldBroadcastEvent ( Event * event_ptr )
{
const StateType state = Process : : ProcessEventData : : GetStateFromEvent ( event_ptr ) ;
bool return_value = true ;
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_EVENTS | LIBLLDB_LOG_PROCESS ) ) ;
switch ( state )
{
case eStateDetached :
case eStateExited :
case eStateUnloaded :
2015-07-03 12:57:06 -04:00
m_stdio_communication . SynchronizeWithReadThread ( ) ;
// fall-through
case eStateConnected :
case eStateAttaching :
case eStateLaunching :
2013-08-23 13:46:38 -04:00
// These events indicate changes in the state of the debugging session, always report them.
return_value = true ;
break ;
case eStateInvalid :
// We stopped for no apparent reason, don't report it.
return_value = false ;
break ;
case eStateRunning :
case eStateStepping :
// If we've started the target running, we handle the cases where we
// are already running and where there is a transition from stopped to
// running differently.
// running -> running: Automatically suppress extra running events
// stopped -> running: Report except when there is one or more no votes
// and no yes votes.
SynchronouslyNotifyStateChanged ( state ) ;
2014-02-18 11:23:10 -05:00
if ( m_force_next_event_delivery )
return_value = true ;
else
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
switch ( m_last_broadcast_state )
{
case eStateRunning :
case eStateStepping :
// We always suppress multiple runnings with no PUBLIC stop in between.
return_value = false ;
break ;
default :
// TODO: make this work correctly. For now always report
2014-11-25 16:00:58 -05:00
// run if we aren't running so we don't miss any running
2014-02-18 11:23:10 -05:00
// events. If I run the lldb/test/thread/a.out file and
// break at main.cpp:58, run and hit the breakpoints on
// multiple threads, then somehow during the stepping over
// of all breakpoints no run gets reported.
// This is a transition from stop to run.
switch ( m_thread_list . ShouldReportRun ( event_ptr ) )
{
case eVoteYes :
case eVoteNoOpinion :
return_value = true ;
break ;
case eVoteNo :
return_value = false ;
break ;
}
break ;
}
2013-08-23 13:46:38 -04:00
}
break ;
case eStateStopped :
case eStateCrashed :
case eStateSuspended :
{
// We've stopped. First see if we're going to restart the target.
// If we are going to stop, then we always broadcast the event.
// If we aren't going to stop, let the thread plans decide if we're going to report this event.
// If no thread has an opinion, we don't report it.
2015-07-03 12:57:06 -04:00
m_stdio_communication . SynchronizeWithReadThread ( ) ;
2013-08-23 13:46:38 -04:00
RefreshStateAfterStop ( ) ;
if ( ProcessEventData : : GetInterruptedFromEvent ( event_ptr ) )
{
if ( log )
log - > Printf ( " Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s " ,
2014-11-25 16:00:58 -05:00
static_cast < void * > ( event_ptr ) ,
2013-08-23 13:46:38 -04:00
StateAsCString ( state ) ) ;
2014-11-25 16:00:58 -05:00
// Even though we know we are going to stop, we should let the threads have a look at the stop,
// so they can properly set their state.
m_thread_list . ShouldStop ( event_ptr ) ;
2013-08-23 13:46:38 -04:00
return_value = true ;
}
else
{
bool was_restarted = ProcessEventData : : GetRestartedFromEvent ( event_ptr ) ;
bool should_resume = false ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// It makes no sense to ask "ShouldStop" if we've already been restarted...
// Asking the thread list is also not likely to go well, since we are running again.
// So in that case just report the event.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( ! was_restarted )
should_resume = m_thread_list . ShouldStop ( event_ptr ) = = false ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( was_restarted | | should_resume | | m_resume_requested )
{
Vote stop_vote = m_thread_list . ShouldReportStop ( event_ptr ) ;
if ( log )
log - > Printf ( " Process::ShouldBroadcastEvent: should_stop: %i state: %s was_restarted: %i stop_vote: %d. " ,
2014-11-25 16:00:58 -05:00
should_resume , StateAsCString ( state ) ,
was_restarted , stop_vote ) ;
2013-08-23 13:46:38 -04:00
switch ( stop_vote )
{
case eVoteYes :
return_value = true ;
break ;
case eVoteNoOpinion :
case eVoteNo :
return_value = false ;
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( ! was_restarted )
{
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::ShouldBroadcastEvent (%p) Restarting process from state: %s " ,
static_cast < void * > ( event_ptr ) ,
StateAsCString ( state ) ) ;
2013-08-23 13:46:38 -04:00
ProcessEventData : : SetRestartedInEvent ( event_ptr , true ) ;
PrivateResume ( ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
}
else
{
return_value = true ;
SynchronouslyNotifyStateChanged ( state ) ;
}
}
}
break ;
}
2014-11-25 16:00:58 -05:00
2014-02-18 11:23:10 -05:00
// Forcing the next event delivery is a one shot deal. So reset it here.
m_force_next_event_delivery = false ;
2013-08-23 13:46:38 -04:00
// We do some coalescing of events (for instance two consecutive running events get coalesced.)
// But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state
// to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done,
// because the PublicState reflects the last event pulled off the queue, and there may be several
// events stacked up on the queue unserviced. So the PublicState may not reflect the last broadcasted event
// yet. m_last_broadcast_state gets updated here.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( return_value )
m_last_broadcast_state = state ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( log )
log - > Printf ( " Process::ShouldBroadcastEvent (%p) => new state: %s, last broadcast state: %s - %s " ,
2014-11-25 16:00:58 -05:00
static_cast < void * > ( event_ptr ) , StateAsCString ( state ) ,
2013-08-23 13:46:38 -04:00
StateAsCString ( m_last_broadcast_state ) ,
return_value ? " YES " : " NO " ) ;
return return_value ;
}
bool
2015-07-03 12:57:06 -04:00
Process : : StartPrivateStateThread ( bool is_secondary_thread )
2013-08-23 13:46:38 -04:00
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_EVENTS ) ) ;
bool already_running = PrivateStateThreadIsValid ( ) ;
if ( log )
log - > Printf ( " Process::%s()%s " , __FUNCTION__ , already_running ? " already running " : " starting private state thread " ) ;
2015-07-03 12:57:06 -04:00
if ( ! is_secondary_thread & & already_running )
2013-08-23 13:46:38 -04:00
return true ;
// Create a thread that watches our internal state and controls which
// events make it to clients (into the DCProcess event queue).
char thread_name [ 1024 ] ;
2014-11-25 16:00:58 -05:00
2015-02-06 16:38:51 -05:00
if ( HostInfo : : GetMaxThreadNameLength ( ) < = 30 )
2014-11-25 16:00:58 -05:00
{
2015-02-06 16:38:51 -05:00
// On platforms with abbreviated thread name lengths, choose thread names that fit within the limit.
if ( already_running )
snprintf ( thread_name , sizeof ( thread_name ) , " intern-state-OV " ) ;
else
snprintf ( thread_name , sizeof ( thread_name ) , " intern-state " ) ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
else
2014-11-25 16:00:58 -05:00
{
if ( already_running )
2015-02-06 16:38:51 -05:00
snprintf ( thread_name , sizeof ( thread_name ) , " <lldb.process.internal-state-override(pid=% " PRIu64 " )> " , GetID ( ) ) ;
2014-11-25 16:00:58 -05:00
else
2015-02-06 16:38:51 -05:00
snprintf ( thread_name , sizeof ( thread_name ) , " <lldb.process.internal-state(pid=% " PRIu64 " )> " , GetID ( ) ) ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
// Create the private state thread, and start it running.
2015-07-03 12:57:06 -04:00
PrivateStateThreadArgs args = { this , is_secondary_thread } ;
m_private_state_thread = ThreadLauncher : : LaunchThread ( thread_name , Process : : PrivateStateThread , ( void * ) & args , NULL ) ;
2015-02-06 16:38:51 -05:00
if ( m_private_state_thread . IsJoinable ( ) )
2013-08-23 13:46:38 -04:00
{
ResumePrivateStateThread ( ) ;
return true ;
}
else
return false ;
}
void
Process : : PausePrivateStateThread ( )
{
ControlPrivateStateThread ( eBroadcastInternalStateControlPause ) ;
}
void
Process : : ResumePrivateStateThread ( )
{
ControlPrivateStateThread ( eBroadcastInternalStateControlResume ) ;
}
void
Process : : StopPrivateStateThread ( )
{
if ( PrivateStateThreadIsValid ( ) )
ControlPrivateStateThread ( eBroadcastInternalStateControlStop ) ;
else
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Went to stop the private state thread, but it was already invalid. " ) ;
}
}
void
Process : : ControlPrivateStateThread ( uint32_t signal )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
assert ( signal = = eBroadcastInternalStateControlStop | |
signal = = eBroadcastInternalStateControlPause | |
signal = = eBroadcastInternalStateControlResume ) ;
if ( log )
log - > Printf ( " Process::%s (signal = %d) " , __FUNCTION__ , signal ) ;
// Signal the private state thread. First we should copy this is case the
// thread starts exiting since the private state thread will NULL this out
// when it exits
2015-02-06 16:38:51 -05:00
HostThread private_state_thread ( m_private_state_thread ) ;
if ( private_state_thread . IsJoinable ( ) )
2013-08-23 13:46:38 -04:00
{
TimeValue timeout_time ;
bool timed_out ;
m_private_state_control_broadcaster . BroadcastEvent ( signal , NULL ) ;
timeout_time = TimeValue : : Now ( ) ;
timeout_time . OffsetWithSeconds ( 2 ) ;
if ( log )
log - > Printf ( " Sending control event of type: %d. " , signal ) ;
m_private_state_control_wait . WaitForValueEqualTo ( true , & timeout_time , & timed_out ) ;
m_private_state_control_wait . SetValue ( false , eBroadcastNever ) ;
if ( signal = = eBroadcastInternalStateControlStop )
{
if ( timed_out )
{
2015-02-06 16:38:51 -05:00
Error error = private_state_thread . Cancel ( ) ;
2013-08-23 13:46:38 -04:00
if ( log )
log - > Printf ( " Timed out responding to the control event, cancel got error: \" %s \" . " , error . AsCString ( ) ) ;
}
else
{
if ( log )
log - > Printf ( " The control event killed the private state thread without having to cancel. " ) ;
}
thread_result_t result = NULL ;
2015-02-06 16:38:51 -05:00
private_state_thread . Join ( & result ) ;
m_private_state_thread . Reset ( ) ;
2013-08-23 13:46:38 -04:00
}
}
else
{
if ( log )
log - > Printf ( " Private state thread already dead, no need to signal it to stop. " ) ;
}
}
void
Process : : SendAsyncInterrupt ( )
{
if ( PrivateStateThreadIsValid ( ) )
m_private_state_broadcaster . BroadcastEvent ( Process : : eBroadcastBitInterrupt , NULL ) ;
else
BroadcastEvent ( Process : : eBroadcastBitInterrupt , NULL ) ;
}
void
Process : : HandlePrivateEvent ( EventSP & event_sp )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
m_resume_requested = false ;
m_currently_handling_event . SetValue ( true , eBroadcastNever ) ;
const StateType new_state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
// First check to see if anybody wants a shot at this event:
if ( m_next_event_action_ap . get ( ) ! = NULL )
{
NextEventAction : : EventActionResult action_result = m_next_event_action_ap - > PerformAction ( event_sp ) ;
if ( log )
log - > Printf ( " Ran next event action, result was %d. " , action_result ) ;
switch ( action_result )
{
case NextEventAction : : eEventActionSuccess :
SetNextEventAction ( NULL ) ;
break ;
case NextEventAction : : eEventActionRetry :
break ;
case NextEventAction : : eEventActionExit :
// Handle Exiting Here. If we already got an exited event,
// we should just propagate it. Otherwise, swallow this event,
// and set our state to exit so the next event will kill us.
if ( new_state ! = eStateExited )
{
// FIXME: should cons up an exited event, and discard this one.
SetExitStatus ( 0 , m_next_event_action_ap - > GetExitString ( ) ) ;
m_currently_handling_event . SetValue ( false , eBroadcastAlways ) ;
SetNextEventAction ( NULL ) ;
return ;
}
SetNextEventAction ( NULL ) ;
break ;
}
}
// See if we should broadcast this state to external clients?
const bool should_broadcast = ShouldBroadcastEvent ( event_sp . get ( ) ) ;
if ( should_broadcast )
{
2014-11-25 16:00:58 -05:00
const bool is_hijacked = IsHijackedForEvent ( eBroadcastBitStateChanged ) ;
2013-08-23 13:46:38 -04:00
if ( log )
{
log - > Printf ( " Process::%s (pid = % " PRIu64 " ) broadcasting new state %s (old state %s) to %s " ,
__FUNCTION__ ,
GetID ( ) ,
StateAsCString ( new_state ) ,
StateAsCString ( GetState ( ) ) ,
2014-11-25 16:00:58 -05:00
is_hijacked ? " hijacked " : " public " ) ;
2013-08-23 13:46:38 -04:00
}
Process : : ProcessEventData : : SetUpdateStateOnRemoval ( event_sp . get ( ) ) ;
if ( StateIsRunningState ( new_state ) )
2014-02-18 11:23:10 -05:00
{
// Only push the input handler if we aren't fowarding events,
// as this means the curses GUI is in use...
2015-02-06 16:38:51 -05:00
// Or don't push it if we are launching since it will come up stopped.
2015-07-03 12:57:06 -04:00
if ( ! GetTarget ( ) . GetDebugger ( ) . IsForwardingEvents ( ) & & new_state ! = eStateLaunching & &
new_state ! = eStateAttaching )
{
2014-02-18 11:23:10 -05:00
PushProcessIOHandler ( ) ;
2015-07-03 12:57:06 -04:00
m_iohandler_sync . SetValue ( m_iohandler_sync . GetValue ( ) + 1 , eBroadcastAlways ) ;
if ( log )
log - > Printf ( " Process::%s updated m_iohandler_sync to %d " , __FUNCTION__ , m_iohandler_sync . GetValue ( ) ) ;
}
2014-11-25 16:00:58 -05:00
}
else if ( StateIsStoppedState ( new_state , false ) )
{
if ( ! Process : : ProcessEventData : : GetRestartedFromEvent ( event_sp . get ( ) ) )
{
// If the lldb_private::Debugger is handling the events, we don't
// want to pop the process IOHandler here, we want to do it when
// we receive the stopped event so we can carefully control when
// the process IOHandler is popped because when we stop we want to
// display some text stating how and why we stopped, then maybe some
// process/thread/frame info, and then we want the "(lldb) " prompt
// to show up. If we pop the process IOHandler here, then we will
// cause the command interpreter to become the top IOHandler after
// the process pops off and it will update its prompt right away...
// See the Debugger.cpp file where it calls the function as
// "process_sp->PopProcessIOHandler()" to see where I am talking about.
// Otherwise we end up getting overlapping "(lldb) " prompts and
// garbled output.
//
// If we aren't handling the events in the debugger (which is indicated
// by "m_target.GetDebugger().IsHandlingEvents()" returning false) or we
// are hijacked, then we always pop the process IO handler manually.
// Hijacking happens when the internal process state thread is running
// thread plans, or when commands want to run in synchronous mode
// and they call "process->WaitForProcessToStop()". An example of something
// that will hijack the events is a simple expression:
//
// (lldb) expr (int)puts("hello")
//
// This will cause the internal process state thread to resume and halt
// the process (and _it_ will hijack the eBroadcastBitStateChanged
// events) and we do need the IO handler to be pushed and popped
// correctly.
if ( is_hijacked | | m_target . GetDebugger ( ) . IsHandlingEvents ( ) = = false )
PopProcessIOHandler ( ) ;
}
2014-02-18 11:23:10 -05:00
}
2013-08-23 13:46:38 -04:00
BroadcastEvent ( event_sp ) ;
}
else
{
if ( log )
{
log - > Printf ( " Process::%s (pid = % " PRIu64 " ) suppressing state %s (old state %s): should_broadcast == false " ,
__FUNCTION__ ,
GetID ( ) ,
StateAsCString ( new_state ) ,
StateAsCString ( GetState ( ) ) ) ;
}
}
m_currently_handling_event . SetValue ( false , eBroadcastAlways ) ;
}
2013-11-06 11:48:53 -05:00
thread_result_t
2013-08-23 13:46:38 -04:00
Process : : PrivateStateThread ( void * arg )
{
2015-07-03 12:57:06 -04:00
PrivateStateThreadArgs * real_args = static_cast < PrivateStateThreadArgs * > ( arg ) ;
thread_result_t result = real_args - > process - > RunPrivateStateThread ( real_args - > is_secondary_thread ) ;
2013-08-23 13:46:38 -04:00
return result ;
}
2013-11-06 11:48:53 -05:00
thread_result_t
2015-07-03 12:57:06 -04:00
Process : : RunPrivateStateThread ( bool is_secondary_thread )
2013-08-23 13:46:38 -04:00
{
bool control_only = true ;
m_private_state_control_wait . SetValue ( false , eBroadcastNever ) ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (arg = %p, pid = % " PRIu64 " ) thread starting... " ,
__FUNCTION__ , static_cast < void * > ( this ) , GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
bool exit_now = false ;
while ( ! exit_now )
{
EventSP event_sp ;
WaitForEventsPrivate ( NULL , event_sp , control_only ) ;
if ( event_sp - > BroadcasterIs ( & m_private_state_control_broadcaster ) )
{
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (arg = %p, pid = % " PRIu64 " ) got a control event: %d " ,
__FUNCTION__ , static_cast < void * > ( this ) , GetID ( ) ,
event_sp - > GetType ( ) ) ;
2013-08-23 13:46:38 -04:00
switch ( event_sp - > GetType ( ) )
{
case eBroadcastInternalStateControlStop :
exit_now = true ;
2014-11-25 16:00:58 -05:00
break ; // doing any internal state management below
2013-08-23 13:46:38 -04:00
case eBroadcastInternalStateControlPause :
control_only = true ;
break ;
case eBroadcastInternalStateControlResume :
control_only = false ;
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
m_private_state_control_wait . SetValue ( true , eBroadcastAlways ) ;
continue ;
}
else if ( event_sp - > GetType ( ) = = eBroadcastBitInterrupt )
{
if ( m_public_state . GetValue ( ) = = eStateAttaching )
{
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (arg = %p, pid = % " PRIu64 " ) woke up with an interrupt while attaching - forwarding interrupt. " ,
__FUNCTION__ , static_cast < void * > ( this ) ,
GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
BroadcastEvent ( eBroadcastBitInterrupt , NULL ) ;
}
else
{
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (arg = %p, pid = % " PRIu64 " ) woke up with an interrupt - Halting. " ,
__FUNCTION__ , static_cast < void * > ( this ) ,
GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
Halt ( ) ;
}
continue ;
}
const StateType internal_state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( internal_state ! = eStateInvalid )
{
if ( m_clear_thread_plans_on_stop & &
StateIsStoppedState ( internal_state , true ) )
{
m_clear_thread_plans_on_stop = false ;
m_thread_list . DiscardThreadPlans ( ) ;
}
HandlePrivateEvent ( event_sp ) ;
}
if ( internal_state = = eStateInvalid | |
internal_state = = eStateExited | |
internal_state = = eStateDetached )
{
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (arg = %p, pid = % " PRIu64 " ) about to exit with internal state %s... " ,
__FUNCTION__ , static_cast < void * > ( this ) , GetID ( ) ,
StateAsCString ( internal_state ) ) ;
2013-08-23 13:46:38 -04:00
break ;
}
}
// Verify log is still enabled before attempting to write to it...
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::%s (arg = %p, pid = % " PRIu64 " ) thread exiting... " ,
__FUNCTION__ , static_cast < void * > ( this ) , GetID ( ) ) ;
2013-08-23 13:46:38 -04:00
2015-07-03 12:57:06 -04:00
// If we are a secondary thread, then the primary thread we are working for will have already
// acquired the public_run_lock, and isn't done with what it was doing yet, so don't
// try to change it on the way out.
if ( ! is_secondary_thread )
m_public_run_lock . SetStopped ( ) ;
2013-08-23 13:46:38 -04:00
m_private_state_control_wait . SetValue ( true , eBroadcastAlways ) ;
2015-02-06 16:38:51 -05:00
m_private_state_thread . Reset ( ) ;
2013-08-23 13:46:38 -04:00
return NULL ;
}
//------------------------------------------------------------------
// Process Event Data
//------------------------------------------------------------------
Process : : ProcessEventData : : ProcessEventData ( ) :
EventData ( ) ,
2015-07-03 12:57:06 -04:00
m_process_wp ( ) ,
2013-08-23 13:46:38 -04:00
m_state ( eStateInvalid ) ,
m_restarted ( false ) ,
m_update_state ( 0 ) ,
m_interrupted ( false )
{
}
Process : : ProcessEventData : : ProcessEventData ( const ProcessSP & process_sp , StateType state ) :
EventData ( ) ,
2015-07-03 12:57:06 -04:00
m_process_wp ( ) ,
2013-08-23 13:46:38 -04:00
m_state ( state ) ,
m_restarted ( false ) ,
m_update_state ( 0 ) ,
m_interrupted ( false )
{
2015-07-03 12:57:06 -04:00
if ( process_sp )
m_process_wp = process_sp ;
2013-08-23 13:46:38 -04:00
}
Process : : ProcessEventData : : ~ ProcessEventData ( )
{
}
const ConstString &
Process : : ProcessEventData : : GetFlavorString ( )
{
static ConstString g_flavor ( " Process::ProcessEventData " ) ;
return g_flavor ;
}
const ConstString &
Process : : ProcessEventData : : GetFlavor ( ) const
{
return ProcessEventData : : GetFlavorString ( ) ;
}
void
Process : : ProcessEventData : : DoOnRemoval ( Event * event_ptr )
{
2015-07-03 12:57:06 -04:00
ProcessSP process_sp ( m_process_wp . lock ( ) ) ;
if ( ! process_sp )
return ;
2013-08-23 13:46:38 -04:00
// This function gets called twice for each event, once when the event gets pulled
// off of the private process event queue, and then any number of times, first when it gets pulled off of
// the public event queue, then other times when we're pretending that this is where we stopped at the
// end of expression evaluation. m_update_state is used to distinguish these
// three cases; it is 0 when we're just pulling it off for private handling,
// and > 1 for expression evaluation, and we don't want to do the breakpoint command handling then.
if ( m_update_state ! = 1 )
return ;
2015-07-03 12:57:06 -04:00
process_sp - > SetPublicState ( m_state , Process : : ProcessEventData : : GetRestartedFromEvent ( event_ptr ) ) ;
2014-11-25 16:00:58 -05:00
// If this is a halt event, even if the halt stopped with some reason other than a plain interrupt (e.g. we had
// already stopped for a breakpoint when the halt request came through) don't do the StopInfo actions, as they may
// end up restarting the process.
if ( m_interrupted )
return ;
// If we're stopped and haven't restarted, then do the StopInfo actions here:
2013-08-23 13:46:38 -04:00
if ( m_state = = eStateStopped & & ! m_restarted )
{
2015-07-03 12:57:06 -04:00
ThreadList & curr_thread_list = process_sp - > GetThreadList ( ) ;
2013-08-23 13:46:38 -04:00
uint32_t num_threads = curr_thread_list . GetSize ( ) ;
uint32_t idx ;
// The actions might change one of the thread's stop_info's opinions about whether we should
// stop the process, so we need to query that as we go.
// One other complication here, is that we try to catch any case where the target has run (except for expressions)
// and immediately exit, but if we get that wrong (which is possible) then the thread list might have changed, and
// that would cause our iteration here to crash. We could make a copy of the thread list, but we'd really like
// to also know if it has changed at all, so we make up a vector of the thread ID's and check what we get back
// against this list & bag out if anything differs.
std : : vector < uint32_t > thread_index_array ( num_threads ) ;
for ( idx = 0 ; idx < num_threads ; + + idx )
thread_index_array [ idx ] = curr_thread_list . GetThreadAtIndex ( idx ) - > GetIndexID ( ) ;
// Use this to track whether we should continue from here. We will only continue the target running if
// no thread says we should stop. Of course if some thread's PerformAction actually sets the target running,
// then it doesn't matter what the other threads say...
bool still_should_stop = false ;
// Sometimes - for instance if we have a bug in the stub we are talking to, we stop but no thread has a
// valid stop reason. In that case we should just stop, because we have no way of telling what the right
// thing to do is, and it's better to let the user decide than continue behind their backs.
bool does_anybody_have_an_opinion = false ;
for ( idx = 0 ; idx < num_threads ; + + idx )
{
2015-07-03 12:57:06 -04:00
curr_thread_list = process_sp - > GetThreadList ( ) ;
2013-08-23 13:46:38 -04:00
if ( curr_thread_list . GetSize ( ) ! = num_threads )
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Number of threads changed from %u to %u while processing event. " , num_threads , curr_thread_list . GetSize ( ) ) ;
break ;
}
lldb : : ThreadSP thread_sp = curr_thread_list . GetThreadAtIndex ( idx ) ;
if ( thread_sp - > GetIndexID ( ) ! = thread_index_array [ idx ] )
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " The thread at position %u changed from %u to %u while processing event. " ,
idx ,
thread_index_array [ idx ] ,
thread_sp - > GetIndexID ( ) ) ;
break ;
}
StopInfoSP stop_info_sp = thread_sp - > GetStopInfo ( ) ;
if ( stop_info_sp & & stop_info_sp - > IsValid ( ) )
{
does_anybody_have_an_opinion = true ;
bool this_thread_wants_to_stop ;
if ( stop_info_sp - > GetOverrideShouldStop ( ) )
{
this_thread_wants_to_stop = stop_info_sp - > GetOverriddenShouldStopValue ( ) ;
}
else
{
stop_info_sp - > PerformAction ( event_ptr ) ;
// The stop action might restart the target. If it does, then we want to mark that in the
// event so that whoever is receiving it will know to wait for the running event and reflect
// that state appropriately.
// We also need to stop processing actions, since they aren't expecting the target to be running.
// FIXME: we might have run.
if ( stop_info_sp - > HasTargetRunSinceMe ( ) )
{
SetRestarted ( true ) ;
break ;
}
this_thread_wants_to_stop = stop_info_sp - > ShouldStop ( event_ptr ) ;
}
if ( still_should_stop = = false )
still_should_stop = this_thread_wants_to_stop ;
}
}
if ( ! GetRestarted ( ) )
{
if ( ! still_should_stop & & does_anybody_have_an_opinion )
{
// We've been asked to continue, so do that here.
SetRestarted ( true ) ;
// Use the public resume method here, since this is just
// extending a public resume.
2015-07-03 12:57:06 -04:00
process_sp - > PrivateResume ( ) ;
2013-08-23 13:46:38 -04:00
}
else
{
// If we didn't restart, run the Stop Hooks here:
// They might also restart the target, so watch for that.
2015-07-03 12:57:06 -04:00
process_sp - > GetTarget ( ) . RunStopHooks ( ) ;
if ( process_sp - > GetPrivateState ( ) = = eStateRunning )
2013-08-23 13:46:38 -04:00
SetRestarted ( true ) ;
}
}
}
}
void
Process : : ProcessEventData : : Dump ( Stream * s ) const
{
2015-07-03 12:57:06 -04:00
ProcessSP process_sp ( m_process_wp . lock ( ) ) ;
if ( process_sp )
2014-11-25 16:00:58 -05:00
s - > Printf ( " process = %p (pid = % " PRIu64 " ), " ,
2015-07-03 12:57:06 -04:00
static_cast < void * > ( process_sp . get ( ) ) , process_sp - > GetID ( ) ) ;
else
s - > PutCString ( " process = NULL, " ) ;
2013-08-23 13:46:38 -04:00
s - > Printf ( " state = %s " , StateAsCString ( GetState ( ) ) ) ;
}
const Process : : ProcessEventData *
Process : : ProcessEventData : : GetEventDataFromEvent ( const Event * event_ptr )
{
if ( event_ptr )
{
const EventData * event_data = event_ptr - > GetData ( ) ;
if ( event_data & & event_data - > GetFlavor ( ) = = ProcessEventData : : GetFlavorString ( ) )
return static_cast < const ProcessEventData * > ( event_ptr - > GetData ( ) ) ;
}
return NULL ;
}
ProcessSP
Process : : ProcessEventData : : GetProcessFromEvent ( const Event * event_ptr )
{
ProcessSP process_sp ;
const ProcessEventData * data = GetEventDataFromEvent ( event_ptr ) ;
if ( data )
process_sp = data - > GetProcessSP ( ) ;
return process_sp ;
}
StateType
Process : : ProcessEventData : : GetStateFromEvent ( const Event * event_ptr )
{
const ProcessEventData * data = GetEventDataFromEvent ( event_ptr ) ;
if ( data = = NULL )
return eStateInvalid ;
else
return data - > GetState ( ) ;
}
bool
Process : : ProcessEventData : : GetRestartedFromEvent ( const Event * event_ptr )
{
const ProcessEventData * data = GetEventDataFromEvent ( event_ptr ) ;
if ( data = = NULL )
return false ;
else
return data - > GetRestarted ( ) ;
}
void
Process : : ProcessEventData : : SetRestartedInEvent ( Event * event_ptr , bool new_value )
{
ProcessEventData * data = const_cast < ProcessEventData * > ( GetEventDataFromEvent ( event_ptr ) ) ;
if ( data ! = NULL )
data - > SetRestarted ( new_value ) ;
}
size_t
Process : : ProcessEventData : : GetNumRestartedReasons ( const Event * event_ptr )
{
ProcessEventData * data = const_cast < ProcessEventData * > ( GetEventDataFromEvent ( event_ptr ) ) ;
if ( data ! = NULL )
return data - > GetNumRestartedReasons ( ) ;
else
return 0 ;
}
const char *
Process : : ProcessEventData : : GetRestartedReasonAtIndex ( const Event * event_ptr , size_t idx )
{
ProcessEventData * data = const_cast < ProcessEventData * > ( GetEventDataFromEvent ( event_ptr ) ) ;
if ( data ! = NULL )
return data - > GetRestartedReasonAtIndex ( idx ) ;
else
return NULL ;
}
void
Process : : ProcessEventData : : AddRestartedReason ( Event * event_ptr , const char * reason )
{
ProcessEventData * data = const_cast < ProcessEventData * > ( GetEventDataFromEvent ( event_ptr ) ) ;
if ( data ! = NULL )
data - > AddRestartedReason ( reason ) ;
}
bool
Process : : ProcessEventData : : GetInterruptedFromEvent ( const Event * event_ptr )
{
const ProcessEventData * data = GetEventDataFromEvent ( event_ptr ) ;
if ( data = = NULL )
return false ;
else
return data - > GetInterrupted ( ) ;
}
void
Process : : ProcessEventData : : SetInterruptedInEvent ( Event * event_ptr , bool new_value )
{
ProcessEventData * data = const_cast < ProcessEventData * > ( GetEventDataFromEvent ( event_ptr ) ) ;
if ( data ! = NULL )
data - > SetInterrupted ( new_value ) ;
}
bool
Process : : ProcessEventData : : SetUpdateStateOnRemoval ( Event * event_ptr )
{
ProcessEventData * data = const_cast < ProcessEventData * > ( GetEventDataFromEvent ( event_ptr ) ) ;
if ( data )
{
data - > SetUpdateStateOnRemoval ( ) ;
return true ;
}
return false ;
}
lldb : : TargetSP
Process : : CalculateTarget ( )
{
return m_target . shared_from_this ( ) ;
}
void
Process : : CalculateExecutionContext ( ExecutionContext & exe_ctx )
{
exe_ctx . SetTargetPtr ( & m_target ) ;
exe_ctx . SetProcessPtr ( this ) ;
exe_ctx . SetThreadPtr ( NULL ) ;
exe_ctx . SetFramePtr ( NULL ) ;
}
//uint32_t
//Process::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids)
//{
// return 0;
//}
//
//ArchSpec
//Process::GetArchSpecForExistingProcess (lldb::pid_t pid)
//{
// return Host::GetArchSpecForExistingProcess (pid);
//}
//
//ArchSpec
//Process::GetArchSpecForExistingProcess (const char *process_name)
//{
// return Host::GetArchSpecForExistingProcess (process_name);
//}
//
void
Process : : AppendSTDOUT ( const char * s , size_t len )
{
Mutex : : Locker locker ( m_stdio_communication_mutex ) ;
m_stdout_data . append ( s , len ) ;
BroadcastEventIfUnique ( eBroadcastBitSTDOUT , new ProcessEventData ( shared_from_this ( ) , GetState ( ) ) ) ;
}
void
Process : : AppendSTDERR ( const char * s , size_t len )
{
Mutex : : Locker locker ( m_stdio_communication_mutex ) ;
m_stderr_data . append ( s , len ) ;
BroadcastEventIfUnique ( eBroadcastBitSTDERR , new ProcessEventData ( shared_from_this ( ) , GetState ( ) ) ) ;
}
void
Process : : BroadcastAsyncProfileData ( const std : : string & one_profile_data )
{
Mutex : : Locker locker ( m_profile_data_comm_mutex ) ;
m_profile_data . push_back ( one_profile_data ) ;
BroadcastEventIfUnique ( eBroadcastBitProfileData , new ProcessEventData ( shared_from_this ( ) , GetState ( ) ) ) ;
}
size_t
Process : : GetAsyncProfileData ( char * buf , size_t buf_size , Error & error )
{
Mutex : : Locker locker ( m_profile_data_comm_mutex ) ;
if ( m_profile_data . empty ( ) )
return 0 ;
std : : string & one_profile_data = m_profile_data . front ( ) ;
size_t bytes_available = one_profile_data . size ( ) ;
if ( bytes_available > 0 )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::GetProfileData (buf = %p, size = % " PRIu64 " ) " ,
static_cast < void * > ( buf ) ,
static_cast < uint64_t > ( buf_size ) ) ;
2013-08-23 13:46:38 -04:00
if ( bytes_available > buf_size )
{
memcpy ( buf , one_profile_data . c_str ( ) , buf_size ) ;
one_profile_data . erase ( 0 , buf_size ) ;
bytes_available = buf_size ;
}
else
{
memcpy ( buf , one_profile_data . c_str ( ) , bytes_available ) ;
m_profile_data . erase ( m_profile_data . begin ( ) ) ;
}
}
return bytes_available ;
}
//------------------------------------------------------------------
// Process STDIO
//------------------------------------------------------------------
size_t
Process : : GetSTDOUT ( char * buf , size_t buf_size , Error & error )
{
Mutex : : Locker locker ( m_stdio_communication_mutex ) ;
size_t bytes_available = m_stdout_data . size ( ) ;
if ( bytes_available > 0 )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::GetSTDOUT (buf = %p, size = % " PRIu64 " ) " ,
static_cast < void * > ( buf ) ,
static_cast < uint64_t > ( buf_size ) ) ;
2013-08-23 13:46:38 -04:00
if ( bytes_available > buf_size )
{
memcpy ( buf , m_stdout_data . c_str ( ) , buf_size ) ;
m_stdout_data . erase ( 0 , buf_size ) ;
bytes_available = buf_size ;
}
else
{
memcpy ( buf , m_stdout_data . c_str ( ) , bytes_available ) ;
m_stdout_data . clear ( ) ;
}
}
return bytes_available ;
}
size_t
Process : : GetSTDERR ( char * buf , size_t buf_size , Error & error )
{
Mutex : : Locker locker ( m_stdio_communication_mutex ) ;
size_t bytes_available = m_stderr_data . size ( ) ;
if ( bytes_available > 0 )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::GetSTDERR (buf = %p, size = % " PRIu64 " ) " ,
static_cast < void * > ( buf ) ,
static_cast < uint64_t > ( buf_size ) ) ;
2013-08-23 13:46:38 -04:00
if ( bytes_available > buf_size )
{
memcpy ( buf , m_stderr_data . c_str ( ) , buf_size ) ;
m_stderr_data . erase ( 0 , buf_size ) ;
bytes_available = buf_size ;
}
else
{
memcpy ( buf , m_stderr_data . c_str ( ) , bytes_available ) ;
m_stderr_data . clear ( ) ;
}
}
return bytes_available ;
}
void
Process : : STDIOReadThreadBytesReceived ( void * baton , const void * src , size_t src_len )
{
Process * process = ( Process * ) baton ;
process - > AppendSTDOUT ( static_cast < const char * > ( src ) , src_len ) ;
}
2014-02-18 11:23:10 -05:00
class IOHandlerProcessSTDIO :
public IOHandler
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
public :
IOHandlerProcessSTDIO ( Process * process ,
int write_fd ) :
2015-02-06 16:38:51 -05:00
IOHandler ( process - > GetTarget ( ) . GetDebugger ( ) , IOHandler : : Type : : ProcessIO ) ,
2014-02-18 11:23:10 -05:00
m_process ( process ) ,
m_read_file ( ) ,
m_write_file ( write_fd , false ) ,
2014-11-25 16:00:58 -05:00
m_pipe ( )
2014-02-18 11:23:10 -05:00
{
2015-07-03 12:57:06 -04:00
m_pipe . CreateNew ( false ) ;
2014-02-18 11:23:10 -05:00
m_read_file . SetDescriptor ( GetInputFD ( ) , false ) ;
}
virtual
~ IOHandlerProcessSTDIO ( )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
}
// Each IOHandler gets to run until it is done. It should read data
// from the "in" and place output into "out" and "err and return
// when done.
2015-07-03 12:57:06 -04:00
void
Run ( ) override
2014-02-18 11:23:10 -05:00
{
2015-07-03 12:57:06 -04:00
if ( ! m_read_file . IsValid ( ) | | ! m_write_file . IsValid ( ) | | ! m_pipe . CanRead ( ) | | ! m_pipe . CanWrite ( ) )
2014-02-18 11:23:10 -05:00
{
2015-07-03 12:57:06 -04:00
SetIsDone ( true ) ;
return ;
}
SetIsDone ( false ) ;
const int read_fd = m_read_file . GetDescriptor ( ) ;
TerminalState terminal_state ;
terminal_state . Save ( read_fd , false ) ;
Terminal terminal ( read_fd ) ;
terminal . SetCanonical ( false ) ;
terminal . SetEcho ( false ) ;
2014-02-18 11:23:10 -05:00
// FD_ZERO, FD_SET are not supported on windows
2014-11-25 16:00:58 -05:00
# ifndef _WIN32
2015-07-03 12:57:06 -04:00
const int pipe_read_fd = m_pipe . GetReadFileDescriptor ( ) ;
while ( ! GetIsDone ( ) )
{
fd_set read_fdset ;
FD_ZERO ( & read_fdset ) ;
FD_SET ( read_fd , & read_fdset ) ;
FD_SET ( pipe_read_fd , & read_fdset ) ;
const int nfds = std : : max < int > ( read_fd , pipe_read_fd ) + 1 ;
int num_set_fds = select ( nfds , & read_fdset , NULL , NULL , NULL ) ;
if ( num_set_fds < 0 )
{
const int select_errno = errno ;
if ( select_errno ! = EINTR )
SetIsDone ( true ) ;
}
else if ( num_set_fds > 0 )
{
char ch = 0 ;
size_t n ;
if ( FD_ISSET ( read_fd , & read_fdset ) )
2014-02-18 11:23:10 -05:00
{
2015-07-03 12:57:06 -04:00
n = 1 ;
if ( m_read_file . Read ( & ch , n ) . Success ( ) & & n = = 1 )
2014-02-18 11:23:10 -05:00
{
2015-07-03 12:57:06 -04:00
if ( m_write_file . Write ( & ch , n ) . Fail ( ) | | n ! = 1 )
2014-02-18 11:23:10 -05:00
SetIsDone ( true ) ;
}
2015-07-03 12:57:06 -04:00
else
SetIsDone ( true ) ;
}
if ( FD_ISSET ( pipe_read_fd , & read_fdset ) )
{
size_t bytes_read ;
// Consume the interrupt byte
Error error = m_pipe . Read ( & ch , 1 , bytes_read ) ;
if ( error . Success ( ) )
2014-02-18 11:23:10 -05:00
{
2015-07-03 12:57:06 -04:00
switch ( ch )
2014-02-18 11:23:10 -05:00
{
2015-07-03 12:57:06 -04:00
case ' q ' :
2014-02-18 11:23:10 -05:00
SetIsDone ( true ) ;
2015-07-03 12:57:06 -04:00
break ;
case ' i ' :
if ( StateIsRunningState ( m_process - > GetState ( ) ) )
m_process - > Halt ( ) ;
break ;
2014-02-18 11:23:10 -05:00
}
}
}
}
}
2015-07-03 12:57:06 -04:00
# endif
terminal_state . Restore ( ) ;
2014-02-18 11:23:10 -05:00
}
2014-02-25 16:42:16 -05:00
2015-07-03 12:57:06 -04:00
void
Cancel ( ) override
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
char ch = ' q ' ; // Send 'q' for quit
2015-02-06 16:38:51 -05:00
size_t bytes_written = 0 ;
m_pipe . Write ( & ch , 1 , bytes_written ) ;
2014-02-18 11:23:10 -05:00
}
2014-02-25 16:42:16 -05:00
2015-07-03 12:57:06 -04:00
bool
Interrupt ( ) override
2014-02-25 16:42:16 -05:00
{
2014-11-25 16:00:58 -05:00
// Do only things that are safe to do in an interrupt context (like in
// a SIGINT handler), like write 1 byte to a file descriptor. This will
// interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte
// that was written to the pipe and then call m_process->Halt() from a
// much safer location in code.
if ( m_active )
{
char ch = ' i ' ; // Send 'i' for interrupt
2015-02-06 16:38:51 -05:00
size_t bytes_written = 0 ;
Error result = m_pipe . Write ( & ch , 1 , bytes_written ) ;
return result . Success ( ) ;
2014-11-25 16:00:58 -05:00
}
else
{
// This IOHandler might be pushed on the stack, but not being run currently
// so do the right thing if we aren't actively watching for STDIN by sending
// the interrupt to the process. Otherwise the write to the pipe above would
// do nothing. This can happen when the command interpreter is running and
// gets a "expression ...". It will be on the IOHandler thread and sending
// the input is complete to the delegate which will cause the expression to
// run, which will push the process IO handler, but not run it.
if ( StateIsRunningState ( m_process - > GetState ( ) ) )
{
m_process - > SendAsyncInterrupt ( ) ;
return true ;
}
}
return false ;
2014-02-25 16:42:16 -05:00
}
2014-02-18 11:23:10 -05:00
2015-07-03 12:57:06 -04:00
void
GotEOF ( ) override
2014-02-18 11:23:10 -05:00
{
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
protected :
Process * m_process ;
File m_read_file ; // Read from this file (usually actual STDIN for LLDB
File m_write_file ; // Write to this file (usually the master pty for getting io to debuggee)
2014-11-25 16:00:58 -05:00
Pipe m_pipe ;
2014-02-18 11:23:10 -05:00
} ;
2013-08-23 13:46:38 -04:00
void
2014-02-18 11:23:10 -05:00
Process : : SetSTDIOFileDescriptor ( int fd )
2013-08-23 13:46:38 -04:00
{
// First set up the Read Thread for reading/handling process I/O
2014-02-18 11:23:10 -05:00
std : : unique_ptr < ConnectionFileDescriptor > conn_ap ( new ConnectionFileDescriptor ( fd , true ) ) ;
2013-08-23 13:46:38 -04:00
if ( conn_ap . get ( ) )
{
m_stdio_communication . SetConnection ( conn_ap . release ( ) ) ;
if ( m_stdio_communication . IsConnected ( ) )
{
m_stdio_communication . SetReadThreadBytesReceivedCallback ( STDIOReadThreadBytesReceived , this ) ;
m_stdio_communication . StartReadThread ( ) ;
// Now read thread is set up, set up input reader.
if ( ! m_process_input_reader . get ( ) )
2014-02-18 11:23:10 -05:00
m_process_input_reader . reset ( new IOHandlerProcessSTDIO ( this , fd ) ) ;
2013-08-23 13:46:38 -04:00
}
}
}
2014-11-25 16:00:58 -05:00
bool
Process : : ProcessIOHandlerIsActive ( )
{
IOHandlerSP io_handler_sp ( m_process_input_reader ) ;
if ( io_handler_sp )
return m_target . GetDebugger ( ) . IsTopIOHandler ( io_handler_sp ) ;
return false ;
}
bool
2014-02-18 11:23:10 -05:00
Process : : PushProcessIOHandler ( )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
IOHandlerSP io_handler_sp ( m_process_input_reader ) ;
if ( io_handler_sp )
{
2015-07-03 12:57:06 -04:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::%s pushing IO handler " , __FUNCTION__ ) ;
2014-02-18 11:23:10 -05:00
io_handler_sp - > SetIsDone ( false ) ;
m_target . GetDebugger ( ) . PushIOHandler ( io_handler_sp ) ;
2014-11-25 16:00:58 -05:00
return true ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
return false ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
bool
2014-02-18 11:23:10 -05:00
Process : : PopProcessIOHandler ( )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
IOHandlerSP io_handler_sp ( m_process_input_reader ) ;
if ( io_handler_sp )
2014-11-25 16:00:58 -05:00
return m_target . GetDebugger ( ) . PopIOHandler ( io_handler_sp ) ;
return false ;
2013-08-23 13:46:38 -04:00
}
// The process needs to know about installed plug-ins
void
Process : : SettingsInitialize ( )
{
Thread : : SettingsInitialize ( ) ;
}
void
Process : : SettingsTerminate ( )
{
Thread : : SettingsTerminate ( ) ;
}
2014-11-25 16:00:58 -05:00
ExpressionResults
2013-08-23 13:46:38 -04:00
Process : : RunThreadPlan ( ExecutionContext & exe_ctx ,
lldb : : ThreadPlanSP & thread_plan_sp ,
2013-12-03 13:51:59 -05:00
const EvaluateExpressionOptions & options ,
2013-08-23 13:46:38 -04:00
Stream & errors )
{
2014-11-25 16:00:58 -05:00
ExpressionResults return_value = eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
if ( thread_plan_sp . get ( ) = = NULL )
{
errors . Printf ( " RunThreadPlan called with empty thread plan. " ) ;
2014-11-25 16:00:58 -05:00
return eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( ! thread_plan_sp - > ValidatePlan ( NULL ) )
{
errors . Printf ( " RunThreadPlan called with an invalid thread plan. " ) ;
2014-11-25 16:00:58 -05:00
return eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( exe_ctx . GetProcessPtr ( ) ! = this )
{
errors . Printf ( " RunThreadPlan called on wrong process. " ) ;
2014-11-25 16:00:58 -05:00
return eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
}
Thread * thread = exe_ctx . GetThreadPtr ( ) ;
if ( thread = = NULL )
{
errors . Printf ( " RunThreadPlan called with invalid thread. " ) ;
2014-11-25 16:00:58 -05:00
return eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// We rely on the thread plan we are running returning "PlanCompleted" if when it successfully completes.
// For that to be true the plan can't be private - since private plans suppress themselves in the
// GetCompletedPlan call.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
bool orig_plan_private = thread_plan_sp - > GetPrivate ( ) ;
thread_plan_sp - > SetPrivate ( false ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( m_private_state . GetValue ( ) ! = eStateStopped )
{
errors . Printf ( " RunThreadPlan called while the private state was not stopped. " ) ;
2014-11-25 16:00:58 -05:00
return eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Save the thread & frame from the exe_ctx for restoration after we run
const uint32_t thread_idx_id = thread - > GetIndexID ( ) ;
StackFrameSP selected_frame_sp = thread - > GetSelectedFrame ( ) ;
if ( ! selected_frame_sp )
{
thread - > SetSelectedFrame ( 0 ) ;
selected_frame_sp = thread - > GetSelectedFrame ( ) ;
if ( ! selected_frame_sp )
{
errors . Printf ( " RunThreadPlan called without a selected frame on thread %d " , thread_idx_id ) ;
2014-11-25 16:00:58 -05:00
return eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
StackID ctx_frame_id = selected_frame_sp - > GetStackID ( ) ;
// N.B. Running the target may unset the currently selected thread and frame. We don't want to do that either,
// so we should arrange to reset them as well.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
lldb : : ThreadSP selected_thread_sp = GetThreadList ( ) . GetSelectedThread ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
uint32_t selected_tid ;
StackID selected_stack_id ;
if ( selected_thread_sp )
{
selected_tid = selected_thread_sp - > GetIndexID ( ) ;
selected_stack_id = selected_thread_sp - > GetSelectedFrame ( ) - > GetStackID ( ) ;
}
else
{
selected_tid = LLDB_INVALID_THREAD_ID ;
}
2015-02-06 16:38:51 -05:00
HostThread backup_private_state_thread ;
lldb : : StateType old_state = eStateInvalid ;
2013-08-23 13:46:38 -04:00
lldb : : ThreadPlanSP stopper_base_plan_sp ;
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS ) ) ;
2015-02-06 16:38:51 -05:00
if ( m_private_state_thread . EqualsThread ( Host : : GetCurrentThread ( ) ) )
2013-08-23 13:46:38 -04:00
{
// Yikes, we are running on the private state thread! So we can't wait for public events on this thread, since
// we are the thread that is generating public events.
// The simplest thing to do is to spin up a temporary thread to handle private state thread events while
// we are fielding public events here.
if ( log )
log - > Printf ( " Running thread plan on private state thread, spinning up another state thread to handle the events. " ) ;
backup_private_state_thread = m_private_state_thread ;
// One other bit of business: we want to run just this thread plan and anything it pushes, and then stop,
// returning control here.
// But in the normal course of things, the plan above us on the stack would be given a shot at the stop
// event before deciding to stop, and we don't want that. So we insert a "stopper" base plan on the stack
// before the plan we want to run. Since base plans always stop and return control to the user, that will
// do just what we want.
stopper_base_plan_sp . reset ( new ThreadPlanBase ( * thread ) ) ;
thread - > QueueThreadPlan ( stopper_base_plan_sp , false ) ;
// Have to make sure our public state is stopped, since otherwise the reporting logic below doesn't work correctly.
old_state = m_public_state . GetValue ( ) ;
m_public_state . SetValueNoLock ( eStateStopped ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Now spin up the private state thread:
StartPrivateStateThread ( true ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
thread - > QueueThreadPlan ( thread_plan_sp , false ) ; // This used to pass "true" does that make sense?
2014-11-25 16:00:58 -05:00
2013-12-03 13:51:59 -05:00
if ( options . GetDebug ( ) )
{
// In this case, we aren't actually going to run, we just want to stop right away.
// Flush this thread so we will refetch the stacks and show the correct backtrace.
// FIXME: To make this prettier we should invent some stop reason for this, but that
// is only cosmetic, and this functionality is only of use to lldb developers who can
// live with not pretty...
thread - > Flush ( ) ;
2014-11-25 16:00:58 -05:00
return eExpressionStoppedForDebug ;
2013-12-03 13:51:59 -05:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
Listener listener ( " lldb.process.listener.run-thread-plan " ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
lldb : : EventSP event_to_broadcast_sp ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
{
// This process event hijacker Hijacks the Public events and its destructor makes sure that the process events get
// restored on exit to the function.
//
// If the event needs to propagate beyond the hijacker (e.g., the process exits during execution), then the event
// is put into event_to_broadcast_sp for rebroadcasting.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
ProcessEventHijacker run_thread_plan_hijacker ( * this , & listener ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( log )
{
StreamString s ;
thread_plan_sp - > GetDescription ( & s , lldb : : eDescriptionLevelVerbose ) ;
log - > Printf ( " Process::RunThreadPlan(): Resuming thread %u - 0x%4.4 " PRIx64 " to run thread plan \" %s \" . " ,
thread - > GetIndexID ( ) ,
thread - > GetID ( ) ,
s . GetData ( ) ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
bool got_event ;
lldb : : EventSP event_sp ;
lldb : : StateType stop_state = lldb : : eStateInvalid ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
TimeValue * timeout_ptr = NULL ;
TimeValue real_timeout ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
bool before_first_timeout = true ; // This is set to false the first time that we have to halt the target.
bool do_resume = true ;
bool handle_running_event = true ;
const uint64_t default_one_thread_timeout_usec = 250000 ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// This is just for accounting:
uint32_t num_resumes = 0 ;
2014-11-25 16:00:58 -05:00
uint32_t timeout_usec = options . GetTimeoutUsec ( ) ;
uint32_t one_thread_timeout_usec ;
uint32_t all_threads_timeout_usec = 0 ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
// If we are going to run all threads the whole time, or if we are only going to run one thread,
// then we don't need the first timeout. So we set the final timeout, and pretend we are after the
// first timeout already.
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
if ( ! options . GetStopOthers ( ) | | ! options . GetTryAllThreads ( ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
before_first_timeout = false ;
one_thread_timeout_usec = 0 ;
all_threads_timeout_usec = timeout_usec ;
2013-08-23 13:46:38 -04:00
}
else
{
2014-11-25 16:00:58 -05:00
uint32_t option_one_thread_timeout = options . GetOneThreadTimeoutUsec ( ) ;
// If the overall wait is forever, then we only need to set the one thread timeout:
if ( timeout_usec = = 0 )
{
if ( option_one_thread_timeout ! = 0 )
one_thread_timeout_usec = option_one_thread_timeout ;
else
one_thread_timeout_usec = default_one_thread_timeout_usec ;
}
else
{
// Otherwise, if the one thread timeout is set, make sure it isn't longer than the overall timeout,
// and use it, otherwise use half the total timeout, bounded by the default_one_thread_timeout_usec.
uint64_t computed_one_thread_timeout ;
if ( option_one_thread_timeout ! = 0 )
{
if ( timeout_usec < option_one_thread_timeout )
{
errors . Printf ( " RunThreadPlan called without one thread timeout greater than total timeout " ) ;
return eExpressionSetupError ;
}
computed_one_thread_timeout = option_one_thread_timeout ;
}
else
{
computed_one_thread_timeout = timeout_usec / 2 ;
if ( computed_one_thread_timeout > default_one_thread_timeout_usec )
computed_one_thread_timeout = default_one_thread_timeout_usec ;
}
one_thread_timeout_usec = computed_one_thread_timeout ;
all_threads_timeout_usec = timeout_usec - one_thread_timeout_usec ;
}
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
if ( log )
log - > Printf ( " Stop others: %u, try all: %u, before_first: %u, one thread: % " PRIu32 " - all threads: % " PRIu32 " . \n " ,
options . GetStopOthers ( ) ,
options . GetTryAllThreads ( ) ,
before_first_timeout ,
one_thread_timeout_usec ,
all_threads_timeout_usec ) ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
// This isn't going to work if there are unfetched events on the queue.
// Are there cases where we might want to run the remaining events here, and then try to
// call the function? That's probably being too tricky for our own good.
2014-11-25 16:00:58 -05:00
2014-02-18 11:23:10 -05:00
Event * other_events = listener . PeekAtNextEvent ( ) ;
if ( other_events ! = NULL )
{
errors . Printf ( " Calling RunThreadPlan with pending events on the queue. " ) ;
2014-11-25 16:00:58 -05:00
return eExpressionSetupError ;
2014-02-18 11:23:10 -05:00
}
2014-11-25 16:00:58 -05:00
2014-02-18 11:23:10 -05:00
// We also need to make sure that the next event is delivered. We might be calling a function as part of
// a thread plan, in which case the last delivered event could be the running event, and we don't want
// event coalescing to cause us to lose OUR running event...
ForceNextEventDelivery ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// This while loop must exit out the bottom, there's cleanup that we need to do when we are done.
// So don't call return anywhere within it.
2014-11-25 16:00:58 -05:00
# ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
// It's pretty much impossible to write test cases for things like:
// One thread timeout expires, I go to halt, but the process already stopped
// on the function call stop breakpoint. Turning on this define will make us not
// fetch the first event till after the halt. So if you run a quick function, it will have
// completed, and the completion event will be waiting, when you interrupt for halt.
// The expression evaluation should still succeed.
bool miss_first_event = true ;
# endif
TimeValue one_thread_timeout ;
TimeValue final_timeout ;
2013-08-23 13:46:38 -04:00
while ( 1 )
{
// We usually want to resume the process if we get to the top of the loop.
// The only exception is if we get two running events with no intervening
// stop, which can happen, we will just wait for then next stop event.
if ( log )
log - > Printf ( " Top of while loop: do_resume: %i handle_running_event: %i before_first_timeout: %i. " ,
do_resume ,
handle_running_event ,
before_first_timeout ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( do_resume | | handle_running_event )
{
// Do the initial resume and wait for the running event before going further.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( do_resume )
{
num_resumes + + ;
Error resume_error = PrivateResume ( ) ;
if ( ! resume_error . Success ( ) )
{
errors . Printf ( " Error resuming inferior the %d time: \" %s \" . \n " ,
num_resumes ,
resume_error . AsCString ( ) ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
break ;
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
TimeValue resume_timeout = TimeValue : : Now ( ) ;
resume_timeout . OffsetWithMicroSeconds ( 500000 ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
got_event = listener . WaitForEvent ( & resume_timeout , event_sp ) ;
if ( ! got_event )
{
if ( log )
log - > Printf ( " Process::RunThreadPlan(): didn't get any event after resume %d, exiting. " ,
num_resumes ) ;
errors . Printf ( " Didn't get any event after resume %d, exiting. " , num_resumes ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
stop_state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( stop_state ! = eStateRunning )
{
bool restarted = false ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( stop_state = = eStateStopped )
{
restarted = Process : : ProcessEventData : : GetRestartedFromEvent ( event_sp . get ( ) ) ;
if ( log )
log - > Printf ( " Process::RunThreadPlan(): didn't get running event after "
" resume %d, got %s instead (restarted: %i, do_resume: %i, handle_running_event: %i). " ,
num_resumes ,
StateAsCString ( stop_state ) ,
restarted ,
do_resume ,
handle_running_event ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( restarted )
{
// This is probably an overabundance of caution, I don't think I should ever get a stopped & restarted
// event here. But if I do, the best thing is to Halt and then get out of here.
Halt ( ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
errors . Printf ( " Didn't get running event after initial resume, got %s instead. " ,
StateAsCString ( stop_state ) ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionSetupError ;
2013-08-23 13:46:38 -04:00
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): resuming succeeded. " ) ;
// We need to call the function synchronously, so spin waiting for it to return.
// If we get interrupted while executing, we're going to lose our context, and
// won't be able to gather the result at this point.
// We set the timeout AFTER the resume, since the resume takes some time and we
// don't want to charge that to the timeout.
}
else
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): waiting for next event. " ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( before_first_timeout )
{
2013-12-03 13:51:59 -05:00
if ( options . GetTryAllThreads ( ) )
2014-11-25 16:00:58 -05:00
{
one_thread_timeout = TimeValue : : Now ( ) ;
one_thread_timeout . OffsetWithMicroSeconds ( one_thread_timeout_usec ) ;
2013-08-23 13:46:38 -04:00
timeout_ptr = & one_thread_timeout ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
else
{
if ( timeout_usec = = 0 )
timeout_ptr = NULL ;
else
2014-11-25 16:00:58 -05:00
{
final_timeout = TimeValue : : Now ( ) ;
final_timeout . OffsetWithMicroSeconds ( timeout_usec ) ;
2013-08-23 13:46:38 -04:00
timeout_ptr = & final_timeout ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
}
}
else
{
if ( timeout_usec = = 0 )
timeout_ptr = NULL ;
else
2014-11-25 16:00:58 -05:00
{
final_timeout = TimeValue : : Now ( ) ;
final_timeout . OffsetWithMicroSeconds ( all_threads_timeout_usec ) ;
2013-08-23 13:46:38 -04:00
timeout_ptr = & final_timeout ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
do_resume = true ;
handle_running_event = true ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Now wait for the process to stop again:
event_sp . reset ( ) ;
if ( log )
{
if ( timeout_ptr )
{
log - > Printf ( " Process::RunThreadPlan(): about to wait - now is % " PRIu64 " - endpoint is % " PRIu64 ,
TimeValue : : Now ( ) . GetAsMicroSecondsSinceJan1_1970 ( ) ,
timeout_ptr - > GetAsMicroSecondsSinceJan1_1970 ( ) ) ;
}
else
{
log - > Printf ( " Process::RunThreadPlan(): about to wait forever. " ) ;
}
}
2014-11-25 16:00:58 -05:00
# ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
// See comment above...
if ( miss_first_event )
{
usleep ( 1000 ) ;
miss_first_event = false ;
got_event = false ;
}
else
# endif
2013-08-23 13:46:38 -04:00
got_event = listener . WaitForEvent ( timeout_ptr , event_sp ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( got_event )
{
if ( event_sp . get ( ) )
{
bool keep_going = false ;
if ( event_sp - > GetType ( ) = = eBroadcastBitInterrupt )
{
Halt ( ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
errors . Printf ( " Execution halted by user interrupt. " ) ;
if ( log )
log - > Printf ( " Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting. " ) ;
break ;
}
else
{
stop_state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( log )
log - > Printf ( " Process::RunThreadPlan(): in while loop, got event: %s. " , StateAsCString ( stop_state ) ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
switch ( stop_state )
{
case lldb : : eStateStopped :
{
// We stopped, figure out what we are going to do now.
ThreadSP thread_sp = GetThreadList ( ) . FindThreadByIndexID ( thread_idx_id ) ;
if ( ! thread_sp )
{
// Ooh, our thread has vanished. Unlikely that this was successful execution...
if ( log )
log - > Printf ( " Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished. " , thread_idx_id ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
}
else
{
// If we were restarted, we just need to go back up to fetch another event.
if ( Process : : ProcessEventData : : GetRestartedFromEvent ( event_sp . get ( ) ) )
{
if ( log )
{
log - > Printf ( " Process::RunThreadPlan(): Got a stop and restart, so we'll continue waiting. " ) ;
}
keep_going = true ;
do_resume = false ;
handle_running_event = true ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
}
else
{
StopInfoSP stop_info_sp ( thread_sp - > GetStopInfo ( ) ) ;
StopReason stop_reason = eStopReasonInvalid ;
if ( stop_info_sp )
stop_reason = stop_info_sp - > GetStopReason ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// FIXME: We only check if the stop reason is plan complete, should we make sure that
// it is OUR plan that is complete?
if ( stop_reason = = eStopReasonPlanComplete )
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): execution completed successfully. " ) ;
// Now mark this plan as private so it doesn't get reported as the stop reason
// after this point.
if ( thread_plan_sp )
thread_plan_sp - > SetPrivate ( orig_plan_private ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionCompleted ;
2013-08-23 13:46:38 -04:00
}
else
{
// Something restarted the target, so just wait for it to stop for real.
if ( stop_reason = = eStopReasonBreakpoint )
{
if ( log )
log - > Printf ( " Process::RunThreadPlan() stopped for breakpoint: %s. " , stop_info_sp - > GetDescription ( ) ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionHitBreakpoint ;
2013-12-03 13:51:59 -05:00
if ( ! options . DoesIgnoreBreakpoints ( ) )
2013-08-23 13:46:38 -04:00
{
event_to_broadcast_sp = event_sp ;
}
}
else
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): thread plan didn't successfully complete. " ) ;
2013-12-03 13:51:59 -05:00
if ( ! options . DoesUnwindOnError ( ) )
2013-08-23 13:46:38 -04:00
event_to_broadcast_sp = event_sp ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
}
}
}
}
}
break ;
case lldb : : eStateRunning :
// This shouldn't really happen, but sometimes we do get two running events without an
// intervening stop, and in that case we should just go back to waiting for the stop.
do_resume = false ;
keep_going = true ;
handle_running_event = false ;
break ;
default :
if ( log )
log - > Printf ( " Process::RunThreadPlan(): execution stopped with unexpected state: %s. " , StateAsCString ( stop_state ) ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( stop_state = = eStateExited )
event_to_broadcast_sp = event_sp ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
errors . Printf ( " Execution stopped with unexpected state. \n " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
break ;
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( keep_going )
continue ;
else
break ;
}
else
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): got_event was true, but the event pointer was null. How odd... " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
break ;
}
}
else
{
// If we didn't get an event that means we've timed out...
// We will interrupt the process here. Depending on what we were asked to do we will
// either exit, or try with all threads running for the same timeout.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( log ) {
2013-12-03 13:51:59 -05:00
if ( options . GetTryAllThreads ( ) )
2013-08-23 13:46:38 -04:00
{
if ( before_first_timeout )
2014-11-25 16:00:58 -05:00
{
if ( timeout_usec ! = 0 )
{
log - > Printf ( " Process::RunThreadPlan(): Running function with one thread timeout timed out, "
" running for % " PRIu32 " usec with all threads enabled. " ,
all_threads_timeout_usec ) ;
}
else
{
log - > Printf ( " Process::RunThreadPlan(): Running function with one thread timeout timed out, "
" running forever with all threads enabled. " ) ;
}
}
2013-08-23 13:46:38 -04:00
else
log - > Printf ( " Process::RunThreadPlan(): Restarting function with all threads enabled "
2013-11-06 11:48:53 -05:00
" and timeout: %u timed out, abandoning execution. " ,
2013-08-23 13:46:38 -04:00
timeout_usec ) ;
}
else
2013-11-06 11:48:53 -05:00
log - > Printf ( " Process::RunThreadPlan(): Running function with timeout: %u timed out, "
2013-08-23 13:46:38 -04:00
" abandoning execution. " ,
timeout_usec ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// It is possible that between the time we issued the Halt, and we get around to calling Halt the target
// could have stopped. That's fine, Halt will figure that out and send the appropriate Stopped event.
// BUT it is also possible that we stopped & restarted (e.g. hit a signal with "stop" set to false.) In
// that case, we'll get the stopped & restarted event, and we should go back to waiting for the Halt's
// stopped event. That's what this while loop does.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
bool back_to_top = true ;
uint32_t try_halt_again = 0 ;
bool do_halt = true ;
const uint32_t num_retries = 5 ;
while ( try_halt_again < num_retries )
{
Error halt_error ;
if ( do_halt )
{
if ( log )
log - > Printf ( " Process::RunThreadPlan(): Running Halt. " ) ;
halt_error = Halt ( ) ;
}
if ( halt_error . Success ( ) )
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): Halt succeeded. " ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
real_timeout = TimeValue : : Now ( ) ;
real_timeout . OffsetWithMicroSeconds ( 500000 ) ;
got_event = listener . WaitForEvent ( & real_timeout , event_sp ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( got_event )
{
stop_state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( log )
{
log - > Printf ( " Process::RunThreadPlan(): Stopped with event: %s " , StateAsCString ( stop_state ) ) ;
if ( stop_state = = lldb : : eStateStopped
& & Process : : ProcessEventData : : GetInterruptedFromEvent ( event_sp . get ( ) ) )
log - > PutCString ( " Event was the Halt interruption event. " ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( stop_state = = lldb : : eStateStopped )
{
// Between the time we initiated the Halt and the time we delivered it, the process could have
// already finished its job. Check that here:
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( thread - > IsThreadPlanDone ( thread_plan_sp . get ( ) ) )
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): Even though we timed out, the call plan was done. "
" Exiting wait loop. " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionCompleted ;
2013-08-23 13:46:38 -04:00
back_to_top = false ;
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( Process : : ProcessEventData : : GetRestartedFromEvent ( event_sp . get ( ) ) )
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): Went to halt but got a restarted event, there must be an un-restarted stopped event so try again... "
" Exiting wait loop. " ) ;
try_halt_again + + ;
do_halt = false ;
continue ;
}
2013-12-03 13:51:59 -05:00
if ( ! options . GetTryAllThreads ( ) )
2013-08-23 13:46:38 -04:00
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting. " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
back_to_top = false ;
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( before_first_timeout )
{
// Set all the other threads to run, and return to the top of the loop, which will continue;
before_first_timeout = false ;
thread_plan_sp - > SetStopOthers ( false ) ;
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): about to resume. " ) ;
back_to_top = true ;
break ;
}
else
{
// Running all threads failed, so return Interrupted.
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): running all threads timed out. " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
back_to_top = false ;
break ;
}
}
}
else
{ if ( log )
log - > PutCString ( " Process::RunThreadPlan(): halt said it succeeded, but I got no event. "
" I'm getting out of here passing Interrupted. " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionInterrupted ;
2013-08-23 13:46:38 -04:00
back_to_top = false ;
break ;
}
}
else
{
try_halt_again + + ;
continue ;
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( ! back_to_top | | try_halt_again > num_retries )
break ;
else
continue ;
}
} // END WAIT LOOP
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// If we had to start up a temporary private state thread to run this thread plan, shut it down now.
2015-02-06 16:38:51 -05:00
if ( backup_private_state_thread . IsJoinable ( ) )
2013-08-23 13:46:38 -04:00
{
StopPrivateStateThread ( ) ;
Error error ;
m_private_state_thread = backup_private_state_thread ;
if ( stopper_base_plan_sp )
{
thread - > DiscardThreadPlansUpToPlan ( stopper_base_plan_sp ) ;
}
2015-02-06 16:38:51 -05:00
if ( old_state ! = eStateInvalid )
m_public_state . SetValueNoLock ( old_state ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Restore the thread state if we are going to discard the plan execution. There are three cases where this
// could happen:
// 1) The execution successfully completed
// 2) We hit a breakpoint, and ignore_breakpoints was true
// 3) We got some other error, and discard_on_error was true
2014-11-25 16:00:58 -05:00
bool should_unwind = ( return_value = = eExpressionInterrupted & & options . DoesUnwindOnError ( ) )
| | ( return_value = = eExpressionHitBreakpoint & & options . DoesIgnoreBreakpoints ( ) ) ;
if ( return_value = = eExpressionCompleted
2013-08-23 13:46:38 -04:00
| | should_unwind )
{
thread_plan_sp - > RestoreThreadState ( ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Now do some processing on the results of the run:
2014-11-25 16:00:58 -05:00
if ( return_value = = eExpressionInterrupted | | return_value = = eExpressionHitBreakpoint )
2013-08-23 13:46:38 -04:00
{
if ( log )
{
StreamString s ;
if ( event_sp )
event_sp - > Dump ( & s ) ;
else
{
log - > PutCString ( " Process::RunThreadPlan(): Stop event that interrupted us is NULL. " ) ;
}
StreamString ts ;
const char * event_explanation = NULL ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
do
{
if ( ! event_sp )
{
event_explanation = " <no event> " ;
break ;
}
else if ( event_sp - > GetType ( ) = = eBroadcastBitInterrupt )
{
event_explanation = " <user interrupt> " ;
break ;
}
else
{
const Process : : ProcessEventData * event_data = Process : : ProcessEventData : : GetEventDataFromEvent ( event_sp . get ( ) ) ;
if ( ! event_data )
{
event_explanation = " <no event data> " ;
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
Process * process = event_data - > GetProcessSP ( ) . get ( ) ;
if ( ! process )
{
event_explanation = " <no process> " ;
break ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
ThreadList & thread_list = process - > GetThreadList ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
uint32_t num_threads = thread_list . GetSize ( ) ;
uint32_t thread_index ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
ts . Printf ( " <%u threads> " , num_threads ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
for ( thread_index = 0 ;
thread_index < num_threads ;
+ + thread_index )
{
Thread * thread = thread_list . GetThreadAtIndex ( thread_index ) . get ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( ! thread )
{
ts . Printf ( " <?> " ) ;
continue ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
ts . Printf ( " <0x%4.4 " PRIx64 " " , thread - > GetID ( ) ) ;
RegisterContext * register_context = thread - > GetRegisterContext ( ) . get ( ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( register_context )
ts . Printf ( " [ip 0x% " PRIx64 " ] " , register_context - > GetPC ( ) ) ;
else
ts . Printf ( " [ip unknown] " ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
lldb : : StopInfoSP stop_info_sp = thread - > GetStopInfo ( ) ;
if ( stop_info_sp )
{
const char * stop_desc = stop_info_sp - > GetDescription ( ) ;
if ( stop_desc )
ts . PutCString ( stop_desc ) ;
}
ts . Printf ( " > " ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
event_explanation = ts . GetData ( ) ;
}
} while ( 0 ) ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( event_explanation )
log - > Printf ( " Process::RunThreadPlan(): execution interrupted: %s %s " , s . GetData ( ) , event_explanation ) ;
else
log - > Printf ( " Process::RunThreadPlan(): execution interrupted: %s " , s . GetData ( ) ) ;
}
2014-11-25 16:00:58 -05:00
2013-11-06 11:48:53 -05:00
if ( should_unwind )
2013-08-23 13:46:38 -04:00
{
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p. " ,
static_cast < void * > ( thread_plan_sp . get ( ) ) ) ;
2013-08-23 13:46:38 -04:00
thread - > DiscardThreadPlansUpToPlan ( thread_plan_sp ) ;
thread_plan_sp - > SetPrivate ( orig_plan_private ) ;
}
else
{
if ( log )
2014-11-25 16:00:58 -05:00
log - > Printf ( " Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding. " ,
static_cast < void * > ( thread_plan_sp . get ( ) ) ) ;
2013-08-23 13:46:38 -04:00
}
}
2014-11-25 16:00:58 -05:00
else if ( return_value = = eExpressionSetupError )
2013-08-23 13:46:38 -04:00
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): execution set up error. " ) ;
2014-11-25 16:00:58 -05:00
2013-12-03 13:51:59 -05:00
if ( options . DoesUnwindOnError ( ) )
2013-08-23 13:46:38 -04:00
{
thread - > DiscardThreadPlansUpToPlan ( thread_plan_sp ) ;
thread_plan_sp - > SetPrivate ( orig_plan_private ) ;
}
}
else
{
if ( thread - > IsThreadPlanDone ( thread_plan_sp . get ( ) ) )
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): thread plan is done " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionCompleted ;
2013-08-23 13:46:38 -04:00
}
else if ( thread - > WasThreadPlanDiscarded ( thread_plan_sp . get ( ) ) )
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): thread plan was discarded " ) ;
2014-11-25 16:00:58 -05:00
return_value = eExpressionDiscarded ;
2013-08-23 13:46:38 -04:00
}
else
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): thread plan stopped in mid course " ) ;
2013-12-03 13:51:59 -05:00
if ( options . DoesUnwindOnError ( ) & & thread_plan_sp )
2013-08-23 13:46:38 -04:00
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set. " ) ;
thread - > DiscardThreadPlansUpToPlan ( thread_plan_sp ) ;
thread_plan_sp - > SetPrivate ( orig_plan_private ) ;
}
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Thread we ran the function in may have gone away because we ran the target
// Check that it's still there, and if it is put it back in the context. Also restore the
// frame in the context if it is still present.
thread = GetThreadList ( ) . FindThreadByIndexID ( thread_idx_id , true ) . get ( ) ;
if ( thread )
{
exe_ctx . SetFrameSP ( thread - > GetFrameWithStackID ( ctx_frame_id ) ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// Also restore the current process'es selected frame & thread, since this function calling may
// be done behind the user's back.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( selected_tid ! = LLDB_INVALID_THREAD_ID )
{
if ( GetThreadList ( ) . SetSelectedThreadByIndexID ( selected_tid ) & & selected_stack_id . IsValid ( ) )
{
// We were able to restore the selected thread, now restore the frame:
Mutex : : Locker lock ( GetThreadList ( ) . GetMutex ( ) ) ;
StackFrameSP old_frame_sp = GetThreadList ( ) . GetSelectedThread ( ) - > GetFrameWithStackID ( selected_stack_id ) ;
if ( old_frame_sp )
GetThreadList ( ) . GetSelectedThread ( ) - > SetSelectedFrame ( old_frame_sp . get ( ) ) ;
}
}
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
// If the process exited during the run of the thread plan, notify everyone.
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( event_to_broadcast_sp )
{
if ( log )
log - > PutCString ( " Process::RunThreadPlan(): rebroadcasting event. " ) ;
BroadcastEvent ( event_to_broadcast_sp ) ;
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
return return_value ;
}
const char *
2014-11-25 16:00:58 -05:00
Process : : ExecutionResultAsCString ( ExpressionResults result )
2013-08-23 13:46:38 -04:00
{
const char * result_name ;
switch ( result )
{
2014-11-25 16:00:58 -05:00
case eExpressionCompleted :
result_name = " eExpressionCompleted " ;
break ;
case eExpressionDiscarded :
result_name = " eExpressionDiscarded " ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
case eExpressionInterrupted :
result_name = " eExpressionInterrupted " ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
case eExpressionHitBreakpoint :
result_name = " eExpressionHitBreakpoint " ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
case eExpressionSetupError :
result_name = " eExpressionSetupError " ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
case eExpressionParseError :
result_name = " eExpressionParseError " ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
case eExpressionResultUnavailable :
result_name = " eExpressionResultUnavailable " ;
2013-08-23 13:46:38 -04:00
break ;
2014-11-25 16:00:58 -05:00
case eExpressionTimedOut :
result_name = " eExpressionTimedOut " ;
break ;
case eExpressionStoppedForDebug :
result_name = " eExpressionStoppedForDebug " ;
2013-12-03 13:51:59 -05:00
break ;
2013-08-23 13:46:38 -04:00
}
return result_name ;
}
void
Process : : GetStatus ( Stream & strm )
{
const StateType state = GetState ( ) ;
if ( StateIsStoppedState ( state , false ) )
{
if ( state = = eStateExited )
{
int exit_status = GetExitStatus ( ) ;
const char * exit_description = GetExitDescription ( ) ;
strm . Printf ( " Process % " PRIu64 " exited with status = %i (0x%8.8x) %s \n " ,
GetID ( ) ,
exit_status ,
exit_status ,
exit_description ? exit_description : " " ) ;
}
else
{
if ( state = = eStateConnected )
strm . Printf ( " Connected to remote target. \n " ) ;
else
strm . Printf ( " Process % " PRIu64 " %s \n " , GetID ( ) , StateAsCString ( state ) ) ;
}
}
else
{
strm . Printf ( " Process % " PRIu64 " is running. \n " , GetID ( ) ) ;
}
}
size_t
Process : : GetThreadStatus ( Stream & strm ,
bool only_threads_with_stop_reason ,
uint32_t start_frame ,
uint32_t num_frames ,
uint32_t num_frames_with_source )
{
size_t num_thread_infos_dumped = 0 ;
2014-11-25 16:00:58 -05:00
// You can't hold the thread list lock while calling Thread::GetStatus. That very well might run code (e.g. if we need it
// to get return values or arguments.) For that to work the process has to be able to acquire it. So instead copy the thread
// ID's, and look them up one by one:
uint32_t num_threads ;
2015-02-06 16:38:51 -05:00
std : : vector < lldb : : tid_t > thread_id_array ;
2014-11-25 16:00:58 -05:00
//Scope for thread list locker;
{
Mutex : : Locker locker ( GetThreadList ( ) . GetMutex ( ) ) ;
ThreadList & curr_thread_list = GetThreadList ( ) ;
num_threads = curr_thread_list . GetSize ( ) ;
uint32_t idx ;
2015-02-06 16:38:51 -05:00
thread_id_array . resize ( num_threads ) ;
2014-11-25 16:00:58 -05:00
for ( idx = 0 ; idx < num_threads ; + + idx )
2015-02-06 16:38:51 -05:00
thread_id_array [ idx ] = curr_thread_list . GetThreadAtIndex ( idx ) - > GetID ( ) ;
2014-11-25 16:00:58 -05:00
}
2013-08-23 13:46:38 -04:00
for ( uint32_t i = 0 ; i < num_threads ; i + + )
{
2015-02-06 16:38:51 -05:00
ThreadSP thread_sp ( GetThreadList ( ) . FindThreadByID ( thread_id_array [ i ] ) ) ;
2014-11-25 16:00:58 -05:00
if ( thread_sp )
2013-08-23 13:46:38 -04:00
{
if ( only_threads_with_stop_reason )
{
2014-11-25 16:00:58 -05:00
StopInfoSP stop_info_sp = thread_sp - > GetStopInfo ( ) ;
2013-08-23 13:46:38 -04:00
if ( stop_info_sp . get ( ) = = NULL | | ! stop_info_sp - > IsValid ( ) )
continue ;
}
2014-11-25 16:00:58 -05:00
thread_sp - > GetStatus ( strm ,
2013-08-23 13:46:38 -04:00
start_frame ,
num_frames ,
num_frames_with_source ) ;
+ + num_thread_infos_dumped ;
}
2014-11-25 16:00:58 -05:00
else
{
Log * log ( lldb_private : : GetLogIfAnyCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::GetThreadStatus - thread 0x " PRIu64 " vanished while running Thread::GetStatus. " ) ;
}
2013-08-23 13:46:38 -04:00
}
return num_thread_infos_dumped ;
}
void
Process : : AddInvalidMemoryRegion ( const LoadRange & region )
{
m_memory_cache . AddInvalidRange ( region . GetRangeBase ( ) , region . GetByteSize ( ) ) ;
}
bool
Process : : RemoveInvalidMemoryRange ( const LoadRange & region )
{
return m_memory_cache . RemoveInvalidRange ( region . GetRangeBase ( ) , region . GetByteSize ( ) ) ;
}
void
Process : : AddPreResumeAction ( PreResumeActionCallback callback , void * baton )
{
m_pre_resume_actions . push_back ( PreResumeCallbackAndBaton ( callback , baton ) ) ;
}
bool
Process : : RunPreResumeActions ( )
{
bool result = true ;
while ( ! m_pre_resume_actions . empty ( ) )
{
struct PreResumeCallbackAndBaton action = m_pre_resume_actions . back ( ) ;
m_pre_resume_actions . pop_back ( ) ;
bool this_result = action . callback ( action . baton ) ;
2015-02-06 16:38:51 -05:00
if ( result = = true )
result = this_result ;
2013-08-23 13:46:38 -04:00
}
return result ;
}
void
Process : : ClearPreResumeActions ( )
{
m_pre_resume_actions . clear ( ) ;
}
2015-07-03 12:57:06 -04:00
ProcessRunLock &
Process : : GetRunLock ( )
{
if ( m_private_state_thread . EqualsThread ( Host : : GetCurrentThread ( ) ) )
return m_private_run_lock ;
else
return m_public_run_lock ;
}
2013-08-23 13:46:38 -04:00
void
Process : : Flush ( )
{
m_thread_list . Flush ( ) ;
2014-02-18 11:23:10 -05:00
m_extended_thread_list . Flush ( ) ;
m_extended_thread_stop_id = 0 ;
m_queue_list . Clear ( ) ;
m_queue_list_stop_id = 0 ;
2013-08-23 13:46:38 -04:00
}
void
Process : : DidExec ( )
{
2014-11-25 16:00:58 -05:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_PROCESS ) ) ;
if ( log )
log - > Printf ( " Process::%s() " , __FUNCTION__ ) ;
2013-08-23 13:46:38 -04:00
Target & target = GetTarget ( ) ;
target . CleanupProcess ( ) ;
2013-12-03 13:51:59 -05:00
target . ClearModules ( false ) ;
2013-08-23 13:46:38 -04:00
m_dynamic_checkers_ap . reset ( ) ;
m_abi_sp . reset ( ) ;
2013-11-06 11:48:53 -05:00
m_system_runtime_ap . reset ( ) ;
2013-08-23 13:46:38 -04:00
m_os_ap . reset ( ) ;
m_dyld_ap . reset ( ) ;
2014-11-25 16:00:58 -05:00
m_jit_loaders_ap . reset ( ) ;
2013-08-23 13:46:38 -04:00
m_image_tokens . clear ( ) ;
m_allocated_memory_cache . Clear ( ) ;
m_language_runtimes . clear ( ) ;
2015-02-06 16:38:51 -05:00
m_instrumentation_runtimes . clear ( ) ;
2013-08-23 13:46:38 -04:00
m_thread_list . DiscardThreadPlans ( ) ;
m_memory_cache . Clear ( true ) ;
2015-02-06 16:38:51 -05:00
m_stop_info_override_callback = NULL ;
2013-08-23 13:46:38 -04:00
DoDidExec ( ) ;
CompleteAttach ( ) ;
2013-11-06 11:48:53 -05:00
// Flush the process (threads and all stack frames) after running CompleteAttach()
// in case the dynamic loader loaded things in new locations.
Flush ( ) ;
2013-12-03 13:51:59 -05:00
// After we figure out what was loaded/unloaded in CompleteAttach,
// we need to let the target know so it can do any cleanup it needs to.
target . DidExec ( ) ;
2013-08-23 13:46:38 -04:00
}
2013-11-06 11:48:53 -05:00
2014-02-18 11:23:10 -05:00
addr_t
Process : : ResolveIndirectFunction ( const Address * address , Error & error )
{
if ( address = = nullptr )
{
error . SetErrorString ( " Invalid address argument " ) ;
return LLDB_INVALID_ADDRESS ;
}
addr_t function_addr = LLDB_INVALID_ADDRESS ;
addr_t addr = address - > GetLoadAddress ( & GetTarget ( ) ) ;
std : : map < addr_t , addr_t > : : const_iterator iter = m_resolved_indirect_addresses . find ( addr ) ;
if ( iter ! = m_resolved_indirect_addresses . end ( ) )
{
function_addr = ( * iter ) . second ;
}
else
{
if ( ! InferiorCall ( this , address , function_addr ) )
{
Symbol * symbol = address - > CalculateSymbolContextSymbol ( ) ;
error . SetErrorStringWithFormat ( " Unable to call resolver for indirect function %s " ,
symbol ? symbol - > GetName ( ) . AsCString ( ) : " <UNKNOWN> " ) ;
function_addr = LLDB_INVALID_ADDRESS ;
}
else
{
m_resolved_indirect_addresses . insert ( std : : pair < addr_t , addr_t > ( addr , function_addr ) ) ;
}
}
return function_addr ;
}
2014-11-25 16:00:58 -05:00
void
Process : : ModulesDidLoad ( ModuleList & module_list )
{
2015-02-06 16:38:51 -05:00
SystemRuntime * sys_runtime = GetSystemRuntime ( ) ;
if ( sys_runtime )
{
sys_runtime - > ModulesDidLoad ( module_list ) ;
}
GetJITLoaders ( ) . ModulesDidLoad ( module_list ) ;
// Give runtimes a chance to be created.
InstrumentationRuntime : : ModulesDidLoad ( module_list , this , m_instrumentation_runtimes ) ;
// Tell runtimes about new modules.
for ( auto pos = m_instrumentation_runtimes . begin ( ) ; pos ! = m_instrumentation_runtimes . end ( ) ; + + pos )
{
InstrumentationRuntimeSP runtime = pos - > second ;
runtime - > ModulesDidLoad ( module_list ) ;
}
2015-07-03 12:57:06 -04:00
// Let any language runtimes we have already created know
// about the modules that loaded.
// Iterate over a copy of this language runtime list in case
// the language runtime ModulesDidLoad somehow causes the language
// riuntime to be unloaded.
LanguageRuntimeCollection language_runtimes ( m_language_runtimes ) ;
for ( const auto & pair : language_runtimes )
{
// We must check language_runtime_sp to make sure it is not
// NULL as we might cache the fact that we didn't have a
// language runtime for a language.
LanguageRuntimeSP language_runtime_sp = pair . second ;
if ( language_runtime_sp )
language_runtime_sp - > ModulesDidLoad ( module_list ) ;
}
2015-02-06 16:38:51 -05:00
}
ThreadCollectionSP
Process : : GetHistoryThreads ( lldb : : addr_t addr )
{
ThreadCollectionSP threads ;
2015-07-03 12:57:06 -04:00
2015-02-06 16:38:51 -05:00
const MemoryHistorySP & memory_history = MemoryHistory : : FindPlugin ( shared_from_this ( ) ) ;
if ( ! memory_history . get ( ) ) {
return threads ;
}
threads . reset ( new ThreadCollection ( memory_history - > GetHistoryThreads ( addr ) ) ) ;
return threads ;
}
2014-11-25 16:00:58 -05:00
2015-02-06 16:38:51 -05:00
InstrumentationRuntimeSP
Process : : GetInstrumentationRuntime ( lldb : : InstrumentationRuntimeType type )
{
InstrumentationRuntimeCollection : : iterator pos ;
pos = m_instrumentation_runtimes . find ( type ) ;
if ( pos = = m_instrumentation_runtimes . end ( ) )
{
return InstrumentationRuntimeSP ( ) ;
}
else
return ( * pos ) . second ;
2014-11-25 16:00:58 -05:00
}
2015-07-03 12:57:06 -04:00
bool
Process : : GetModuleSpec ( const FileSpec & module_file_spec ,
const ArchSpec & arch ,
ModuleSpec & module_spec )
{
module_spec . Clear ( ) ;
return false ;
}