2010-06-09 00:52:24 +08:00
//===-- CommandObjectProcess.cpp --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "CommandObjectProcess.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Args.h"
# include "lldb/Interpreter/Options.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/State.h"
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
# include "lldb/Host/Host.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
2011-03-09 06:40:15 +08:00
# include "lldb/Target/Platform.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Target/Process.h"
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
using namespace lldb ;
using namespace lldb_private ;
//-------------------------------------------------------------------------
// CommandObjectProcessLaunch
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProjectLaunch
2010-06-09 00:52:24 +08:00
class CommandObjectProcessLaunch : public CommandObject
{
public :
2011-11-04 05:22:33 +08:00
// class CommandOptions : public Options
// {
// public:
//
// CommandOptions (CommandInterpreter &interpreter) :
// Options(interpreter)
// {
// // Keep default values of all options in one place: OptionParsingStarting ()
// OptionParsingStarting ();
// }
//
// ~CommandOptions ()
// {
// }
//
// Error
// SetOptionValue (uint32_t option_idx, const char *option_arg)
// {
// Error error;
// char short_option = (char) m_getopt_table[option_idx].val;
//
// switch (short_option)
// {
// case 's': stop_at_entry = true; break;
// case 'e': stderr_path.assign (option_arg); break;
// case 'i': stdin_path.assign (option_arg); break;
// case 'o': stdout_path.assign (option_arg); break;
// case 'p': plugin_name.assign (option_arg); break;
// case 'n': no_stdio = true; break;
// case 'w': working_dir.assign (option_arg); break;
// case 't':
// if (option_arg && option_arg[0])
// tty_name.assign (option_arg);
// in_new_tty = true;
// break;
// default:
// error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
// break;
//
// }
// return error;
// }
//
// void
// OptionParsingStarting ()
// {
// stop_at_entry = false;
// in_new_tty = false;
// tty_name.clear();
// stdin_path.clear();
// stdout_path.clear();
// stderr_path.clear();
// plugin_name.clear();
// working_dir.clear();
// no_stdio = false;
// }
//
// const OptionDefinition*
// GetDefinitions ()
// {
// return g_option_table;
// }
//
// // Options table: Required for subclasses of Options.
//
// static OptionDefinition g_option_table[];
//
// // Instance variables to hold the values for command options.
//
// bool stop_at_entry;
// bool in_new_tty;
// bool no_stdio;
// std::string tty_name;
// std::string stderr_path;
// std::string stdin_path;
// std::string stdout_path;
// std::string plugin_name;
// std::string working_dir;
//
// };
2010-06-09 00:52:24 +08:00
2010-09-18 09:14:36 +08:00
CommandObjectProcessLaunch ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process launch " ,
2010-09-09 05:06:11 +08:00
" Launch the executable in the debugger. " ,
2011-04-08 06:46:35 +08:00
NULL ) ,
m_options ( interpreter )
2010-06-09 00:52:24 +08:00
{
2010-10-05 06:28:36 +08:00
CommandArgumentEntry arg ;
CommandArgumentData run_args_arg ;
// Define the first (and only) variant of this arg.
run_args_arg . arg_type = eArgTypeRunArgs ;
run_args_arg . arg_repetition = eArgRepeatOptional ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( run_args_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-09 00:52:24 +08:00
}
~ CommandObjectProcessLaunch ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
bool
2010-10-07 12:19:01 +08:00
Execute ( Args & launch_args , CommandReturnObject & result )
2010-06-09 00:52:24 +08:00
{
2011-11-08 10:43:13 +08:00
Debugger & debugger = m_interpreter . GetDebugger ( ) ;
Target * target = debugger . GetSelectedTarget ( ) . get ( ) ;
Error error ;
2010-06-09 00:52:24 +08:00
if ( target = = NULL )
{
2011-05-04 06:09:39 +08:00
result . AppendError ( " invalid target, create a debug target using the 'target create' command " ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
// If our listener is NULL, users aren't allows to launch
char filename [ PATH_MAX ] ;
2011-08-11 10:48:45 +08:00
const Module * exe_module = target - > GetExecutableModulePointer ( ) ;
2011-02-25 06:24:29 +08:00
if ( exe_module = = NULL )
{
2011-05-04 06:09:39 +08:00
result . AppendError ( " no file in target, create a debug target using the 'target create' command " ) ;
2011-02-25 06:24:29 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-11-04 05:22:33 +08:00
exe_module - > GetFileSpec ( ) . GetPath ( filename , sizeof ( filename ) ) ;
2010-06-09 00:52:24 +08:00
2011-11-04 05:22:33 +08:00
const bool add_exe_file_as_first_arg = true ;
m_options . launch_info . SetExecutableFile ( exe_module - > GetFileSpec ( ) , add_exe_file_as_first_arg ) ;
2011-02-25 06:24:29 +08:00
StateType state = eStateInvalid ;
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2011-02-25 06:24:29 +08:00
if ( process )
{
state = process - > GetState ( ) ;
if ( process - > IsAlive ( ) & & state ! = eStateConnected )
{
char message [ 1024 ] ;
if ( process - > GetState ( ) = = eStateAttaching )
: : strncpy ( message , " There is a pending attach, abort it and launch a new process? " , sizeof ( message ) ) ;
else
: : strncpy ( message , " There is a running process, kill it and restart? " , sizeof ( message ) ) ;
if ( ! m_interpreter . Confirm ( message , true ) )
2010-12-10 02:58:16 +08:00
{
2011-02-25 06:24:29 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2010-12-10 02:58:16 +08:00
}
else
{
2011-11-08 10:43:13 +08:00
Error destroy_error ( process - > Destroy ( ) ) ;
if ( destroy_error . Success ( ) )
2011-02-25 06:24:29 +08:00
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
2011-11-08 10:43:13 +08:00
result . AppendErrorWithFormat ( " Failed to kill process: %s \n " , destroy_error . AsCString ( ) ) ;
2011-02-25 06:24:29 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-12-10 02:58:16 +08:00
}
}
2010-06-09 00:52:24 +08:00
}
2010-12-10 02:58:16 +08:00
2011-11-15 11:53:30 +08:00
if ( launch_args . GetArgumentCount ( ) = = 0 )
{
const Args & process_args = target - > GetRunArguments ( ) ;
if ( process_args . GetArgumentCount ( ) > 0 )
m_options . launch_info . GetArguments ( ) . AppendArguments ( process_args ) ;
}
else
2010-09-04 08:03:46 +08:00
{
2011-11-04 05:22:33 +08:00
m_options . launch_info . GetArguments ( ) . AppendArguments ( launch_args ) ;
}
2011-11-08 10:43:13 +08:00
2011-11-15 11:53:30 +08:00
if ( target - > GetDisableASLR ( ) )
m_options . launch_info . GetFlags ( ) . Set ( eLaunchFlagDisableASLR ) ;
if ( target - > GetDisableSTDIO ( ) )
m_options . launch_info . GetFlags ( ) . Set ( eLaunchFlagDisableSTDIO ) ;
m_options . launch_info . GetFlags ( ) . Set ( eLaunchFlagDebug ) ;
Args environment ;
target - > GetEnvironmentAsArgs ( environment ) ;
if ( environment . GetArgumentCount ( ) > 0 )
m_options . launch_info . GetEnvironmentEntries ( ) . AppendArguments ( environment ) ;
m_options . launch_info . FinalizeFileActions ( target ) ;
2011-11-08 10:43:13 +08:00
if ( state = = eStateConnected )
2010-10-18 09:45:30 +08:00
{
2011-11-08 10:43:13 +08:00
if ( m_options . launch_info . GetFlags ( ) . Test ( eLaunchFlagLaunchInTTY ) )
2010-10-18 09:45:30 +08:00
{
2011-11-08 10:43:13 +08:00
result . AppendWarning ( " can't launch in tty when launching through a remote connection " ) ;
2011-11-04 05:22:33 +08:00
m_options . launch_info . GetFlags ( ) . Clear ( eLaunchFlagLaunchInTTY ) ;
2010-10-18 09:45:30 +08:00
}
}
2011-11-08 10:43:13 +08:00
else
2010-12-04 02:46:09 +08:00
{
2011-11-15 11:53:30 +08:00
if ( ! m_options . launch_info . GetArchitecture ( ) . IsValid ( ) )
2011-11-12 10:10:56 +08:00
m_options . launch_info . GetArchitecture ( ) = target - > GetArchitecture ( ) ;
2011-11-15 11:53:30 +08:00
process = target - > GetPlatform ( ) - > DebugProcess ( m_options . launch_info ,
debugger ,
target ,
debugger . GetListener ( ) ,
error ) . get ( ) ;
2011-11-08 10:43:13 +08:00
if ( process = = NULL )
2011-11-04 05:22:33 +08:00
{
2011-11-15 11:53:30 +08:00
result . SetError ( error , " failed to launch or debug process " ) ;
2011-11-08 10:43:13 +08:00
return false ;
2011-11-04 05:22:33 +08:00
}
2010-10-18 09:45:30 +08:00
}
2011-11-08 10:43:13 +08:00
2010-09-18 09:14:36 +08:00
if ( error . Success ( ) )
2010-06-09 00:52:24 +08:00
{
2011-02-23 08:35:02 +08:00
const char * archname = exe_module - > GetArchitecture ( ) . GetArchitectureName ( ) ;
2010-10-18 09:45:30 +08:00
2011-10-20 02:09:39 +08:00
result . AppendMessageWithFormat ( " Process %llu launched: '%s' (%s) \n " , process - > GetID ( ) , filename , archname ) ;
2010-10-07 12:19:01 +08:00
result . SetDidChangeProcessState ( true ) ;
2011-11-04 05:22:33 +08:00
if ( m_options . launch_info . GetFlags ( ) . Test ( eLaunchFlagStopAtEntry ) = = false )
2010-06-09 00:52:24 +08:00
{
2010-10-07 12:19:01 +08:00
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
2010-09-18 09:14:36 +08:00
StateType state = process - > WaitForProcessToStop ( NULL ) ;
2010-06-09 00:52:24 +08:00
2010-09-18 09:14:36 +08:00
if ( state = = eStateStopped )
2010-06-09 00:52:24 +08:00
{
2010-10-07 12:19:01 +08:00
error = process - > Resume ( ) ;
if ( error . Success ( ) )
{
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
if ( synchronous_execution )
{
state = process - > WaitForProcessToStop ( NULL ) ;
2011-02-23 08:35:02 +08:00
if ( ! StateIsStoppedState ( state ) )
2011-02-16 05:59:32 +08:00
{
2011-11-15 11:53:30 +08:00
result . AppendErrorWithFormat ( " process isn't stopped: %s " , StateAsCString ( state ) ) ;
2011-02-16 05:59:32 +08:00
}
2010-10-07 12:19:01 +08:00
result . SetDidChangeProcessState ( true ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
}
}
2011-02-16 05:59:32 +08:00
else
{
2011-11-15 11:53:30 +08:00
result . AppendErrorWithFormat ( " process resume at entry point failed: %s " , error . AsCString ( ) ) ;
2011-02-16 05:59:32 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-06-09 00:52:24 +08:00
}
2011-02-16 05:59:32 +08:00
else
{
2011-11-15 11:53:30 +08:00
result . AppendErrorWithFormat ( " initial process state wasn't stopped: %s " , StateAsCString ( state ) ) ;
2011-02-16 05:59:32 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-06-09 00:52:24 +08:00
}
}
2011-02-16 05:59:32 +08:00
else
{
2011-07-03 05:07:54 +08:00
result . AppendErrorWithFormat ( " process launch failed: %s " , error . AsCString ( ) ) ;
2011-02-16 05:59:32 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-06-09 00:52:24 +08:00
return result . Succeeded ( ) ;
}
2010-07-07 11:36:20 +08:00
virtual const char * GetRepeatCommand ( Args & current_command_args , uint32_t index )
{
// No repeat for "process launch"...
return " " ;
}
2010-06-09 00:52:24 +08:00
protected :
2011-11-04 05:22:33 +08:00
ProcessLaunchCommandOptions m_options ;
2010-06-09 00:52:24 +08:00
} ;
2011-11-04 05:22:33 +08:00
//#define SET1 LLDB_OPT_SET_1
//#define SET2 LLDB_OPT_SET_2
//#define SET3 LLDB_OPT_SET_3
//
//OptionDefinition
//CommandObjectProcessLaunch::CommandOptions::g_option_table[] =
//{
//{ SET1 | SET2 | SET3, false, "stop-at-entry", 's', no_argument, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
//{ SET1 , false, "stdin", 'i', required_argument, NULL, 0, eArgTypePath, "Redirect stdin for the process to <path>."},
//{ SET1 , false, "stdout", 'o', required_argument, NULL, 0, eArgTypePath, "Redirect stdout for the process to <path>."},
//{ SET1 , false, "stderr", 'e', required_argument, NULL, 0, eArgTypePath, "Redirect stderr for the process to <path>."},
//{ SET1 | SET2 | SET3, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
//{ SET2 , false, "tty", 't', optional_argument, NULL, 0, eArgTypePath, "Start the process in a terminal. If <path> is specified, look for a terminal whose name contains <path>, else start the process in a new terminal."},
//{ SET3, false, "no-stdio", 'n', no_argument, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
//{ SET1 | SET2 | SET3, false, "working-dir", 'w', required_argument, NULL, 0, eArgTypePath, "Set the current working directory to <path> when running the inferior."},
//{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
//};
//
//#undef SET1
//#undef SET2
//#undef SET3
2010-06-09 00:52:24 +08:00
//-------------------------------------------------------------------------
// CommandObjectProcessAttach
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessAttach
2010-06-09 00:52:24 +08:00
class CommandObjectProcessAttach : public CommandObject
{
public :
class CommandOptions : public Options
{
public :
2011-04-08 06:46:35 +08:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
2010-06-09 00:52:24 +08:00
{
2011-04-13 08:18:08 +08:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2010-06-09 00:52:24 +08:00
}
~ CommandOptions ( )
{
}
Error
2011-04-13 08:18:08 +08:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-06-09 00:52:24 +08:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
bool success = false ;
switch ( short_option )
{
case ' p ' :
{
2011-11-15 11:53:30 +08:00
lldb : : pid_t pid = Args : : StringToUInt32 ( option_arg , LLDB_INVALID_PROCESS_ID , 0 , & success ) ;
if ( ! success | | pid = = LLDB_INVALID_PROCESS_ID )
{
error . SetErrorStringWithFormat ( " invalid process ID '%s' " , option_arg ) ;
}
else
{
attach_info . SetProcessID ( pid ) ;
}
2010-06-09 00:52:24 +08:00
}
break ;
case ' P ' :
2011-11-15 11:53:30 +08:00
attach_info . SetProcessPluginName ( option_arg ) ;
2010-06-09 00:52:24 +08:00
break ;
case ' n ' :
2011-11-15 11:53:30 +08:00
attach_info . GetExecutableFile ( ) . SetFile ( option_arg , false ) ;
2010-06-09 00:52:24 +08:00
break ;
case ' w ' :
2011-11-15 11:53:30 +08:00
attach_info . SetWaitForLaunch ( true ) ;
2010-06-09 00:52:24 +08:00
break ;
default :
2011-10-26 08:56:27 +08:00
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
2010-06-09 00:52:24 +08:00
break ;
}
return error ;
}
void
2011-04-13 08:18:08 +08:00
OptionParsingStarting ( )
2010-06-09 00:52:24 +08:00
{
2011-11-15 11:53:30 +08:00
attach_info . Clear ( ) ;
2010-06-09 00:52:24 +08:00
}
2011-03-25 05:19:54 +08:00
const OptionDefinition *
2010-06-09 00:52:24 +08:00
GetDefinitions ( )
{
return g_option_table ;
}
2010-08-10 07:31:02 +08:00
virtual bool
2011-04-08 06:46:35 +08:00
HandleOptionArgumentCompletion ( Args & input ,
2010-08-10 07:31:02 +08:00
int cursor_index ,
int char_pos ,
OptionElementVector & opt_element_vector ,
int opt_element_index ,
int match_start_point ,
int max_return_elements ,
bool & word_complete ,
StringList & matches )
{
int opt_arg_pos = opt_element_vector [ opt_element_index ] . opt_arg_pos ;
int opt_defs_index = opt_element_vector [ opt_element_index ] . opt_defs_index ;
// We are only completing the name option for now...
2011-03-25 05:19:54 +08:00
const OptionDefinition * opt_defs = GetDefinitions ( ) ;
2010-08-10 07:31:02 +08:00
if ( opt_defs [ opt_defs_index ] . short_option = = ' n ' )
{
// Are we in the name?
// Look to see if there is a -P argument provided, and if so use that plugin, otherwise
// use the default plugin.
const char * partial_name = NULL ;
partial_name = input . GetArgumentAtIndex ( opt_arg_pos ) ;
2011-03-09 06:40:15 +08:00
2011-04-12 13:54:46 +08:00
PlatformSP platform_sp ( m_interpreter . GetPlatform ( true ) ) ;
2011-03-09 06:40:15 +08:00
if ( platform_sp )
2010-08-10 07:31:02 +08:00
{
2011-04-12 13:54:46 +08:00
ProcessInstanceInfoList process_infos ;
ProcessInstanceInfoMatch match_info ;
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-31 02:16:51 +08:00
if ( partial_name )
{
2011-11-15 11:53:30 +08:00
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . SetFile ( partial_name , false ) ;
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-31 02:16:51 +08:00
match_info . SetNameMatchType ( eNameMatchStartsWith ) ;
}
platform_sp - > FindProcesses ( match_info , process_infos ) ;
2011-03-09 06:40:15 +08:00
const uint32_t num_matches = process_infos . GetSize ( ) ;
if ( num_matches > 0 )
{
for ( uint32_t i = 0 ; i < num_matches ; + + i )
{
matches . AppendString ( process_infos . GetProcessNameAtIndex ( i ) ,
process_infos . GetProcessNameLengthAtIndex ( i ) ) ;
}
}
2010-08-10 07:31:02 +08:00
}
}
return false ;
}
2010-06-09 00:52:24 +08:00
// Options table: Required for subclasses of Options.
2011-03-25 05:19:54 +08:00
static OptionDefinition g_option_table [ ] ;
2010-06-09 00:52:24 +08:00
// Instance variables to hold the values for command options.
2011-11-15 11:53:30 +08:00
ProcessAttachInfo attach_info ;
2010-06-09 00:52:24 +08:00
} ;
2010-09-18 09:14:36 +08:00
CommandObjectProcessAttach ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process attach " ,
2010-09-09 05:06:11 +08:00
" Attach to a process. " ,
2011-04-08 06:46:35 +08:00
" process attach <cmd-options> " ) ,
m_options ( interpreter )
2010-08-10 07:31:02 +08:00
{
}
~ CommandObjectProcessAttach ( )
{
}
bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-08-10 07:31:02 +08:00
CommandReturnObject & result )
{
2010-09-18 09:14:36 +08:00
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
2011-09-15 09:08:57 +08:00
// N.B. The attach should be synchronous. It doesn't help much to get the prompt back between initiating the attach
// and the target actually stopping. So even if the interpreter is set to be asynchronous, we wait for the stop
// ourselves here.
2011-01-29 09:49:25 +08:00
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2011-02-25 06:24:29 +08:00
StateType state = eStateInvalid ;
2010-08-10 07:31:02 +08:00
if ( process )
{
2011-02-25 06:24:29 +08:00
state = process - > GetState ( ) ;
if ( process - > IsAlive ( ) & & state ! = eStateConnected )
2010-08-10 07:31:02 +08:00
{
2011-10-20 02:09:39 +08:00
result . AppendErrorWithFormat ( " Process %llu is currently being debugged, kill the process before attaching. \n " ,
2010-08-10 07:31:02 +08:00
process - > GetID ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
if ( target = = NULL )
{
// If there isn't a current target create one.
TargetSP new_target_sp ;
FileSpec emptyFileSpec ;
Error error ;
2010-09-18 09:14:36 +08:00
error = m_interpreter . GetDebugger ( ) . GetTargetList ( ) . CreateTarget ( m_interpreter . GetDebugger ( ) ,
emptyFileSpec ,
2011-09-24 08:52:29 +08:00
NULL ,
2010-09-18 09:14:36 +08:00
false ,
2011-09-24 08:52:29 +08:00
NULL , // No platform options
2010-09-18 09:14:36 +08:00
new_target_sp ) ;
2010-08-10 07:31:02 +08:00
target = new_target_sp . get ( ) ;
if ( target = = NULL | | error . Fail ( ) )
{
2011-02-04 09:58:07 +08:00
result . AppendError ( error . AsCString ( " Error creating target " ) ) ;
2010-08-10 07:31:02 +08:00
return false ;
}
2010-09-18 09:14:36 +08:00
m_interpreter . GetDebugger ( ) . GetTargetList ( ) . SetSelectedTarget ( target ) ;
2010-08-10 07:31:02 +08:00
}
// Record the old executable module, we want to issue a warning if the process of attaching changed the
// current executable (like somebody said "file foo" then attached to a PID whose executable was bar.)
ModuleSP old_exec_module_sp = target - > GetExecutableModule ( ) ;
ArchSpec old_arch_spec = target - > GetArchitecture ( ) ;
if ( command . GetArgumentCount ( ) )
{
2011-09-21 05:44:10 +08:00
result . AppendErrorWithFormat ( " Invalid arguments for '%s'. \n Usage: %s \n " , m_cmd_name . c_str ( ) , m_cmd_syntax . c_str ( ) ) ;
2010-08-10 07:31:02 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
else
{
2011-02-25 06:24:29 +08:00
if ( state ! = eStateConnected )
{
2011-11-15 11:53:30 +08:00
const char * plugin_name = m_options . attach_info . GetProcessPluginName ( ) ;
2011-02-25 06:24:29 +08:00
process = target - > CreateProcess ( m_interpreter . GetDebugger ( ) . GetListener ( ) , plugin_name ) . get ( ) ;
}
2010-08-10 07:31:02 +08:00
if ( process )
{
Error error ;
2011-11-15 11:53:30 +08:00
// If no process info was specified, then use the target executable
// name as the process to attach to by default
if ( ! m_options . attach_info . ProcessInfoSpecified ( ) )
2010-09-15 09:34:14 +08:00
{
if ( old_exec_module_sp )
2011-11-15 11:53:30 +08:00
m_options . attach_info . GetExecutableFile ( ) . GetFilename ( ) = old_exec_module_sp - > GetFileSpec ( ) . GetFilename ( ) ;
if ( ! m_options . attach_info . ProcessInfoSpecified ( ) )
2010-09-15 09:34:14 +08:00
{
2011-11-15 11:53:30 +08:00
error . SetErrorString ( " no process specified, create a target with a file, or specify the --pid or --name command option " ) ;
2010-09-15 09:34:14 +08:00
}
}
2011-11-15 11:53:30 +08:00
if ( error . Success ( ) )
{
error = process - > Attach ( m_options . attach_info ) ;
2010-09-15 09:34:14 +08:00
if ( error . Success ( ) )
{
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
}
2010-08-10 07:31:02 +08:00
else
{
2011-11-15 11:53:30 +08:00
result . AppendErrorWithFormat ( " attach failed: %s \n " , error . AsCString ( ) ) ;
2010-09-15 09:34:14 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2010-08-10 07:31:02 +08:00
}
2011-01-29 09:49:25 +08:00
// If we're synchronous, wait for the stopped event and report that.
// Otherwise just return.
// FIXME: in the async case it will now be possible to get to the command
// interpreter with a state eStateAttaching. Make sure we handle that correctly.
2011-09-15 09:08:57 +08:00
StateType state = process - > WaitForProcessToStop ( NULL ) ;
2011-11-15 11:53:30 +08:00
2011-09-15 09:08:57 +08:00
result . SetDidChangeProcessState ( true ) ;
2011-10-20 02:09:39 +08:00
result . AppendMessageWithFormat ( " Process %llu %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
2011-09-15 09:08:57 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2010-08-10 07:31:02 +08:00
}
}
}
if ( result . Succeeded ( ) )
{
// Okay, we're done. Last step is to warn if the executable module has changed:
2011-01-29 15:10:55 +08:00
char new_path [ PATH_MAX ] ;
2011-08-11 10:48:45 +08:00
ModuleSP new_exec_module_sp ( target - > GetExecutableModule ( ) ) ;
2010-08-10 07:31:02 +08:00
if ( ! old_exec_module_sp )
{
2011-01-29 15:10:55 +08:00
// We might not have a module if we attached to a raw pid...
2011-08-11 10:48:45 +08:00
if ( new_exec_module_sp )
2011-01-29 15:10:55 +08:00
{
2011-08-11 10:48:45 +08:00
new_exec_module_sp - > GetFileSpec ( ) . GetPath ( new_path , PATH_MAX ) ;
2011-01-29 15:10:55 +08:00
result . AppendMessageWithFormat ( " Executable module set to \" %s \" . \n " , new_path ) ;
}
2010-08-10 07:31:02 +08:00
}
2011-08-11 10:48:45 +08:00
else if ( old_exec_module_sp - > GetFileSpec ( ) ! = new_exec_module_sp - > GetFileSpec ( ) )
2010-08-10 07:31:02 +08:00
{
2011-01-29 15:10:55 +08:00
char old_path [ PATH_MAX ] ;
2010-08-10 07:31:02 +08:00
2011-08-11 10:48:45 +08:00
old_exec_module_sp - > GetFileSpec ( ) . GetPath ( old_path , PATH_MAX ) ;
new_exec_module_sp - > GetFileSpec ( ) . GetPath ( new_path , PATH_MAX ) ;
2010-08-10 07:31:02 +08:00
result . AppendWarningWithFormat ( " Executable module changed from \" %s \" to \" %s \" . \n " ,
old_path , new_path ) ;
}
if ( ! old_arch_spec . IsValid ( ) )
{
2011-02-23 08:35:02 +08:00
result . AppendMessageWithFormat ( " Architecture set to: %s. \n " , target - > GetArchitecture ( ) . GetArchitectureName ( ) ) ;
2010-08-10 07:31:02 +08:00
}
else if ( old_arch_spec ! = target - > GetArchitecture ( ) )
{
result . AppendWarningWithFormat ( " Architecture changed from %s to %s. \n " ,
2011-02-23 08:35:02 +08:00
old_arch_spec . GetArchitectureName ( ) , target - > GetArchitecture ( ) . GetArchitectureName ( ) ) ;
2010-08-10 07:31:02 +08:00
}
}
return result . Succeeded ( ) ;
}
Options *
GetOptions ( )
{
return & m_options ;
}
2010-06-09 00:52:24 +08:00
protected :
CommandOptions m_options ;
} ;
2011-03-25 05:19:54 +08:00
OptionDefinition
2010-06-09 00:52:24 +08:00
CommandObjectProcessAttach : : CommandOptions : : g_option_table [ ] =
{
2010-10-02 03:59:14 +08:00
{ LLDB_OPT_SET_ALL , false , " plugin " , ' P ' , required_argument , NULL , 0 , eArgTypePlugin , " Name of the process plugin you want to use. " } ,
{ LLDB_OPT_SET_1 , false , " pid " , ' p ' , required_argument , NULL , 0 , eArgTypePid , " The process ID of an existing process to attach to. " } ,
{ LLDB_OPT_SET_2 , false , " name " , ' n ' , required_argument , NULL , 0 , eArgTypeProcessName , " The name of the process to attach to. " } ,
{ LLDB_OPT_SET_2 , false , " waitfor " , ' w ' , no_argument , NULL , 0 , eArgTypeNone , " Wait for the the process with <process-name> to launch. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-06-09 00:52:24 +08:00
} ;
//-------------------------------------------------------------------------
// CommandObjectProcessContinue
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessContinue
2010-06-09 00:52:24 +08:00
class CommandObjectProcessContinue : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectProcessContinue ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process continue " ,
2010-09-09 05:06:11 +08:00
" Continue execution of all threads in the current process. " ,
2010-06-09 00:52:24 +08:00
" process continue " ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
{
}
~ CommandObjectProcessContinue ( )
{
}
bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-09-18 09:14:36 +08:00
bool synchronous_execution = m_interpreter . GetSynchronous ( ) ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " no process to continue " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
StateType state = process - > GetState ( ) ;
if ( state = = eStateStopped )
{
if ( command . GetArgumentCount ( ) ! = 0 )
{
result . AppendErrorWithFormat ( " The '%s' command does not take any arguments. \n " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
const uint32_t num_threads = process - > GetThreadList ( ) . GetSize ( ) ;
// Set the actions that the threads should each take when resuming
for ( uint32_t idx = 0 ; idx < num_threads ; + + idx )
{
process - > GetThreadList ( ) . GetThreadAtIndex ( idx ) - > SetResumeState ( eStateRunning ) ;
}
Error error ( process - > Resume ( ) ) ;
if ( error . Success ( ) )
{
2011-10-20 02:09:39 +08:00
result . AppendMessageWithFormat ( " Process %llu resuming \n " , process - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
if ( synchronous_execution )
{
2010-07-14 08:18:15 +08:00
state = process - > WaitForProcessToStop ( NULL ) ;
2010-06-09 00:52:24 +08:00
result . SetDidChangeProcessState ( true ) ;
2011-10-20 02:09:39 +08:00
result . AppendMessageWithFormat ( " Process %llu %s \n " , process - > GetID ( ) , StateAsCString ( state ) ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . SetStatus ( eReturnStatusSuccessContinuingNoResult ) ;
}
}
else
{
result . AppendErrorWithFormat ( " Failed to resume process: %s. \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
result . AppendErrorWithFormat ( " Process cannot be continued from its current state (%s). \n " ,
StateAsCString ( state ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectProcessDetach
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessDetach
2010-06-09 00:52:24 +08:00
class CommandObjectProcessDetach : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectProcessDetach ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process detach " ,
2010-09-09 05:06:11 +08:00
" Detach from the current process being debugged. " ,
2010-06-09 00:52:24 +08:00
" process detach " ,
eFlagProcessMustBeLaunched )
{
}
~ CommandObjectProcessDetach ( )
{
}
bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " must have a valid process in order to detach " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-10-20 02:09:39 +08:00
result . AppendMessageWithFormat ( " Detaching from process %llu \n " , process - > GetID ( ) ) ;
2010-06-09 00:52:24 +08:00
Error error ( process - > Detach ( ) ) ;
if ( error . Success ( ) )
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " Detach failed: %s \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
return result . Succeeded ( ) ;
}
} ;
2011-02-04 09:58:07 +08:00
//-------------------------------------------------------------------------
// CommandObjectProcessConnect
//-------------------------------------------------------------------------
# pragma mark CommandObjectProcessConnect
class CommandObjectProcessConnect : public CommandObject
{
public :
class CommandOptions : public Options
{
public :
2011-04-08 06:46:35 +08:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
2011-02-04 09:58:07 +08:00
{
2011-04-13 08:18:08 +08:00
// Keep default values of all options in one place: OptionParsingStarting ()
OptionParsingStarting ( ) ;
2011-02-04 09:58:07 +08:00
}
~ CommandOptions ( )
{
}
Error
2011-04-13 08:18:08 +08:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2011-02-04 09:58:07 +08:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' p ' :
plugin_name . assign ( option_arg ) ;
break ;
default :
2011-10-26 08:56:27 +08:00
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
2011-02-04 09:58:07 +08:00
break ;
}
return error ;
}
void
2011-04-13 08:18:08 +08:00
OptionParsingStarting ( )
2011-02-04 09:58:07 +08:00
{
plugin_name . clear ( ) ;
}
2011-03-25 05:19:54 +08:00
const OptionDefinition *
2011-02-04 09:58:07 +08:00
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
2011-03-25 05:19:54 +08:00
static OptionDefinition g_option_table [ ] ;
2011-02-04 09:58:07 +08:00
// Instance variables to hold the values for command options.
std : : string plugin_name ;
} ;
CommandObjectProcessConnect ( CommandInterpreter & interpreter ) :
2011-04-08 06:46:35 +08:00
CommandObject ( interpreter ,
" process connect " ,
" Connect to a remote debug service. " ,
" process connect <remote-url> " ,
0 ) ,
m_options ( interpreter )
2011-02-04 09:58:07 +08:00
{
}
~ CommandObjectProcessConnect ( )
{
}
bool
Execute ( Args & command ,
CommandReturnObject & result )
{
TargetSP target_sp ( m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) ) ;
Error error ;
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2011-02-04 09:58:07 +08:00
if ( process )
{
if ( process - > IsAlive ( ) )
{
2011-10-20 02:09:39 +08:00
result . AppendErrorWithFormat ( " Process %llu is currently being debugged, kill the process before connecting. \n " ,
2011-02-04 09:58:07 +08:00
process - > GetID ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
if ( ! target_sp )
{
// If there isn't a current target create one.
FileSpec emptyFileSpec ;
error = m_interpreter . GetDebugger ( ) . GetTargetList ( ) . CreateTarget ( m_interpreter . GetDebugger ( ) ,
emptyFileSpec ,
2011-09-24 08:52:29 +08:00
NULL ,
2011-02-04 09:58:07 +08:00
false ,
2011-09-24 08:52:29 +08:00
NULL , // No platform options
2011-02-04 09:58:07 +08:00
target_sp ) ;
if ( ! target_sp | | error . Fail ( ) )
{
result . AppendError ( error . AsCString ( " Error creating target " ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
m_interpreter . GetDebugger ( ) . GetTargetList ( ) . SetSelectedTarget ( target_sp . get ( ) ) ;
}
if ( command . GetArgumentCount ( ) = = 1 )
{
const char * plugin_name = NULL ;
if ( ! m_options . plugin_name . empty ( ) )
plugin_name = m_options . plugin_name . c_str ( ) ;
const char * remote_url = command . GetArgumentAtIndex ( 0 ) ;
process = target_sp - > CreateProcess ( m_interpreter . GetDebugger ( ) . GetListener ( ) , plugin_name ) . get ( ) ;
if ( process )
{
error = process - > ConnectRemote ( remote_url ) ;
if ( error . Fail ( ) )
{
result . AppendError ( error . AsCString ( " Remote connect failed " ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else
{
2011-09-21 05:44:10 +08:00
result . AppendErrorWithFormat ( " Unable to find process plug-in for remote URL '%s'. \n Please specify a process plug-in name with the --plugin option, or specify an object file using the \" file \" command. \n " ,
m_cmd_name . c_str ( ) ) ;
2011-02-04 09:58:07 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
2011-09-21 05:44:10 +08:00
result . AppendErrorWithFormat ( " '%s' takes exactly one argument: \n Usage: %s \n " ,
2011-02-04 09:58:07 +08:00
m_cmd_name . c_str ( ) ,
m_cmd_syntax . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
Options *
GetOptions ( )
{
return & m_options ;
}
protected :
CommandOptions m_options ;
} ;
2011-03-25 05:19:54 +08:00
OptionDefinition
2011-02-04 09:58:07 +08:00
CommandObjectProcessConnect : : CommandOptions : : g_option_table [ ] =
{
{ LLDB_OPT_SET_ALL , false , " plugin " , ' p ' , required_argument , NULL , 0 , eArgTypePlugin , " Name of the process plugin you want to use. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
} ;
2010-11-04 09:54:29 +08:00
//-------------------------------------------------------------------------
// CommandObjectProcessLoad
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessLoad
2010-11-04 09:54:29 +08:00
class CommandObjectProcessLoad : public CommandObject
{
public :
CommandObjectProcessLoad ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process load " ,
" Load a shared library into the current process. " ,
" process load <filename> [<filename> ...] " ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
{
}
~ CommandObjectProcessLoad ( )
{
}
bool
Execute ( Args & command ,
CommandReturnObject & result )
{
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-11-04 09:54:29 +08:00
if ( process = = NULL )
{
result . AppendError ( " must have a valid process in order to load a shared library " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
const uint32_t argc = command . GetArgumentCount ( ) ;
for ( uint32_t i = 0 ; i < argc ; + + i )
{
Error error ;
const char * image_path = command . GetArgumentAtIndex ( i ) ;
FileSpec image_spec ( image_path , false ) ;
2011-08-12 00:25:18 +08:00
process - > GetTarget ( ) . GetPlatform ( ) - > ResolveRemotePath ( image_spec , image_spec ) ;
2010-11-04 09:54:29 +08:00
uint32_t image_token = process - > LoadImage ( image_spec , error ) ;
if ( image_token ! = LLDB_INVALID_IMAGE_TOKEN )
{
result . AppendMessageWithFormat ( " Loading \" %s \" ...ok \n Image %u loaded. \n " , image_path , image_token ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " failed to load '%s': %s " , image_path , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectProcessUnload
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessUnload
2010-11-04 09:54:29 +08:00
class CommandObjectProcessUnload : public CommandObject
{
public :
CommandObjectProcessUnload ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process unload " ,
" Unload a shared library from the current process using the index returned by a previous call to \" process load \" . " ,
" process unload <index> " ,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused )
{
}
~ CommandObjectProcessUnload ( )
{
}
bool
Execute ( Args & command ,
CommandReturnObject & result )
{
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-11-04 09:54:29 +08:00
if ( process = = NULL )
{
result . AppendError ( " must have a valid process in order to load a shared library " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
const uint32_t argc = command . GetArgumentCount ( ) ;
for ( uint32_t i = 0 ; i < argc ; + + i )
{
const char * image_token_cstr = command . GetArgumentAtIndex ( i ) ;
uint32_t image_token = Args : : StringToUInt32 ( image_token_cstr , LLDB_INVALID_IMAGE_TOKEN , 0 ) ;
if ( image_token = = LLDB_INVALID_IMAGE_TOKEN )
{
result . AppendErrorWithFormat ( " invalid image index argument '%s' " , image_token_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
break ;
}
else
{
Error error ( process - > UnloadImage ( image_token ) ) ;
if ( error . Success ( ) )
{
result . AppendMessageWithFormat ( " Unloading shared library with index %u...ok \n " , image_token ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " failed to unload image: %s " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
break ;
}
}
}
return result . Succeeded ( ) ;
}
} ;
2010-06-09 00:52:24 +08:00
//-------------------------------------------------------------------------
// CommandObjectProcessSignal
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessSignal
2010-06-09 00:52:24 +08:00
class CommandObjectProcessSignal : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectProcessSignal ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process signal " ,
2010-09-09 05:06:11 +08:00
" Send a UNIX signal to the current process being debugged. " ,
2010-10-05 06:28:36 +08:00
NULL )
2010-06-09 00:52:24 +08:00
{
2010-10-05 06:28:36 +08:00
CommandArgumentEntry arg ;
CommandArgumentData signal_arg ;
// Define the first (and only) variant of this arg.
2010-10-19 06:56:57 +08:00
signal_arg . arg_type = eArgTypeUnixSignal ;
2010-10-05 06:28:36 +08:00
signal_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( signal_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-09 00:52:24 +08:00
}
~ CommandObjectProcessSignal ( )
{
}
bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " no process to signal " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( command . GetArgumentCount ( ) = = 1 )
{
2010-10-09 09:40:57 +08:00
int signo = LLDB_INVALID_SIGNAL_NUMBER ;
const char * signal_name = command . GetArgumentAtIndex ( 0 ) ;
if ( : : isxdigit ( signal_name [ 0 ] ) )
signo = Args : : StringToSInt32 ( signal_name , LLDB_INVALID_SIGNAL_NUMBER , 0 ) ;
else
signo = process - > GetUnixSignals ( ) . GetSignalNumberFromName ( signal_name ) ;
if ( signo = = LLDB_INVALID_SIGNAL_NUMBER )
2010-06-09 00:52:24 +08:00
{
result . AppendErrorWithFormat ( " Invalid signal argument '%s'. \n " , command . GetArgumentAtIndex ( 0 ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
else
{
Error error ( process - > Signal ( signo ) ) ;
if ( error . Success ( ) )
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " Failed to send signal %i: %s \n " , signo , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
}
else
{
2011-09-21 05:44:10 +08:00
result . AppendErrorWithFormat ( " '%s' takes exactly one signal number argument: \n Usage: %s \n " , m_cmd_name . c_str ( ) ,
2010-06-09 00:52:24 +08:00
m_cmd_syntax . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectProcessInterrupt
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessInterrupt
2010-06-09 00:52:24 +08:00
class CommandObjectProcessInterrupt : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectProcessInterrupt ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process interrupt " ,
2010-09-09 05:06:11 +08:00
" Interrupt the current process being debugged. " ,
2010-06-09 00:52:24 +08:00
" process interrupt " ,
eFlagProcessMustBeLaunched )
{
}
~ CommandObjectProcessInterrupt ( )
{
}
bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " no process to halt " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( command . GetArgumentCount ( ) = = 0 )
{
Error error ( process - > Halt ( ) ) ;
if ( error . Success ( ) )
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
// Maybe we should add a "SuspendThreadPlans so we
// can halt, and keep in place all the current thread plans.
process - > GetThreadList ( ) . DiscardThreadPlans ( ) ;
}
else
{
result . AppendErrorWithFormat ( " Failed to halt process: %s \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
2011-09-21 05:44:10 +08:00
result . AppendErrorWithFormat ( " '%s' takes no arguments: \n Usage: %s \n " ,
2010-06-09 00:52:24 +08:00
m_cmd_name . c_str ( ) ,
m_cmd_syntax . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
} ;
//-------------------------------------------------------------------------
// CommandObjectProcessKill
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessKill
2010-06-09 00:52:24 +08:00
class CommandObjectProcessKill : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectProcessKill ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process kill " ,
2010-09-09 05:06:11 +08:00
" Terminate the current process being debugged. " ,
2010-06-09 00:52:24 +08:00
" process kill " ,
eFlagProcessMustBeLaunched )
{
}
~ CommandObjectProcessKill ( )
{
}
bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2011-09-22 12:58:26 +08:00
Process * process = m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " no process to kill " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( command . GetArgumentCount ( ) = = 0 )
{
Error error ( process - > Destroy ( ) ) ;
if ( error . Success ( ) )
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " Failed to kill process: %s \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
2011-09-21 05:44:10 +08:00
result . AppendErrorWithFormat ( " '%s' takes no arguments: \n Usage: %s \n " ,
2010-06-09 00:52:24 +08:00
m_cmd_name . c_str ( ) ,
m_cmd_syntax . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
} ;
2010-06-18 09:23:09 +08:00
//-------------------------------------------------------------------------
// CommandObjectProcessStatus
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessStatus
2010-06-18 09:23:09 +08:00
class CommandObjectProcessStatus : public CommandObject
{
public :
2010-09-18 09:14:36 +08:00
CommandObjectProcessStatus ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process status " ,
2010-09-09 05:06:11 +08:00
" Show the current status and location of executing process. " ,
" process status " ,
2010-06-18 09:23:09 +08:00
0 )
{
}
~ CommandObjectProcessStatus ( )
{
}
bool
Execute
(
Args & command ,
CommandReturnObject & result
)
{
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
Stream & strm = result . GetOutputStream ( ) ;
2010-06-18 09:23:09 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2011-04-12 13:54:46 +08:00
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
2011-09-22 12:58:26 +08:00
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process )
2010-06-18 09:23:09 +08:00
{
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
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 ;
2011-09-22 12:58:26 +08:00
process - > GetStatus ( strm ) ;
process - > GetThreadStatus ( strm ,
only_threads_with_stop_reason ,
start_frame ,
num_frames ,
num_frames_with_source ) ;
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
2010-06-18 09:23:09 +08:00
}
else
{
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 16:33:37 +08:00
result . AppendError ( " No process. " ) ;
2010-06-18 09:23:09 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
} ;
2010-10-14 04:44:39 +08:00
//-------------------------------------------------------------------------
// CommandObjectProcessHandle
//-------------------------------------------------------------------------
2010-12-10 02:58:16 +08:00
# pragma mark CommandObjectProcessHandle
2010-10-14 04:44:39 +08:00
class CommandObjectProcessHandle : public CommandObject
{
public :
class CommandOptions : public Options
{
public :
2011-04-08 06:46:35 +08:00
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
2010-10-14 04:44:39 +08:00
{
2011-04-13 08:18:08 +08:00
OptionParsingStarting ( ) ;
2010-10-14 04:44:39 +08:00
}
~ CommandOptions ( )
{
}
Error
2011-04-13 08:18:08 +08:00
SetOptionValue ( uint32_t option_idx , const char * option_arg )
2010-10-14 04:44:39 +08:00
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' s ' :
stop = option_arg ;
break ;
case ' n ' :
notify = option_arg ;
break ;
case ' p ' :
pass = option_arg ;
break ;
default :
2011-10-26 08:56:27 +08:00
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
2010-10-14 04:44:39 +08:00
break ;
}
return error ;
}
void
2011-04-13 08:18:08 +08:00
OptionParsingStarting ( )
2010-10-14 04:44:39 +08:00
{
stop . clear ( ) ;
notify . clear ( ) ;
pass . clear ( ) ;
}
2011-03-25 05:19:54 +08:00
const OptionDefinition *
2010-10-14 04:44:39 +08:00
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
2011-03-25 05:19:54 +08:00
static OptionDefinition g_option_table [ ] ;
2010-10-14 04:44:39 +08:00
// Instance variables to hold the values for command options.
std : : string stop ;
std : : string notify ;
std : : string pass ;
} ;
CommandObjectProcessHandle ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" process handle " ,
2010-10-15 05:31:13 +08:00
" Show or update what the process and debugger should do with various signals received from the OS. " ,
2011-04-08 06:46:35 +08:00
NULL ) ,
m_options ( interpreter )
2010-10-14 04:44:39 +08:00
{
2010-10-15 05:31:13 +08:00
SetHelpLong ( " If no signals are specified, update them all. If no update option is specified, list the current values. \n " ) ;
2010-10-14 04:44:39 +08:00
CommandArgumentEntry arg ;
2010-10-19 06:56:57 +08:00
CommandArgumentData signal_arg ;
2010-10-14 04:44:39 +08:00
2010-10-19 06:56:57 +08:00
signal_arg . arg_type = eArgTypeUnixSignal ;
signal_arg . arg_repetition = eArgRepeatStar ;
2010-10-14 04:44:39 +08:00
2010-10-19 06:56:57 +08:00
arg . push_back ( signal_arg ) ;
2010-10-14 04:44:39 +08:00
m_arguments . push_back ( arg ) ;
}
~ CommandObjectProcessHandle ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
bool
2010-10-15 05:31:13 +08:00
VerifyCommandOptionValue ( const std : : string & option , int & real_value )
2010-10-14 04:44:39 +08:00
{
bool okay = true ;
2010-10-15 05:31:13 +08:00
bool success = false ;
bool tmp_value = Args : : StringToBoolean ( option . c_str ( ) , false , & success ) ;
if ( success & & tmp_value )
real_value = 1 ;
else if ( success & & ! tmp_value )
real_value = 0 ;
2010-10-14 04:44:39 +08:00
else
{
// If the value isn't 'true' or 'false', it had better be 0 or 1.
2010-10-15 05:31:13 +08:00
real_value = Args : : StringToUInt32 ( option . c_str ( ) , 3 ) ;
if ( real_value ! = 0 & & real_value ! = 1 )
2010-10-14 04:44:39 +08:00
okay = false ;
}
return okay ;
}
2010-10-15 05:31:13 +08:00
void
PrintSignalHeader ( Stream & str )
{
str . Printf ( " NAME PASS STOP NOTIFY \n " ) ;
str . Printf ( " ========== ===== ===== ====== \n " ) ;
}
void
PrintSignal ( Stream & str , int32_t signo , const char * sig_name , UnixSignals & signals )
{
bool stop ;
bool suppress ;
bool notify ;
str . Printf ( " %-10s " , sig_name ) ;
if ( signals . GetSignalInfo ( signo , suppress , stop , notify ) )
{
bool pass = ! suppress ;
str . Printf ( " %s %s %s " ,
( pass ? " true " : " false " ) ,
( stop ? " true " : " false " ) ,
( notify ? " true " : " false " ) ) ;
}
str . Printf ( " \n " ) ;
}
void
PrintSignalInformation ( Stream & str , Args & signal_args , int num_valid_signals , UnixSignals & signals )
{
PrintSignalHeader ( str ) ;
if ( num_valid_signals > 0 )
{
size_t num_args = signal_args . GetArgumentCount ( ) ;
for ( size_t i = 0 ; i < num_args ; + + i )
{
int32_t signo = signals . GetSignalNumberFromName ( signal_args . GetArgumentAtIndex ( i ) ) ;
if ( signo ! = LLDB_INVALID_SIGNAL_NUMBER )
PrintSignal ( str , signo , signal_args . GetArgumentAtIndex ( i ) , signals ) ;
}
}
else // Print info for ALL signals
{
int32_t signo = signals . GetFirstSignalNumber ( ) ;
while ( signo ! = LLDB_INVALID_SIGNAL_NUMBER )
{
PrintSignal ( str , signo , signals . GetSignalAsCString ( signo ) , signals ) ;
signo = signals . GetNextSignalNumber ( signo ) ;
}
}
}
2010-10-14 04:44:39 +08:00
bool
Execute ( Args & signal_args , CommandReturnObject & result )
{
TargetSP target_sp = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) ;
if ( ! target_sp )
{
result . AppendError ( " No current target; "
" cannot handle signals until you have a valid target and process. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
ProcessSP process_sp = target_sp - > GetProcessSP ( ) ;
if ( ! process_sp )
{
result . AppendError ( " No current process; cannot handle signals until you have a valid process. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
int stop_action = - 1 ; // -1 means leave the current setting alone
2010-10-15 05:31:13 +08:00
int pass_action = - 1 ; // -1 means leave the current setting alone
2010-10-14 04:44:39 +08:00
int notify_action = - 1 ; // -1 means leave the current setting alone
if ( ! m_options . stop . empty ( )
2010-10-15 05:31:13 +08:00
& & ! VerifyCommandOptionValue ( m_options . stop , stop_action ) )
2010-10-14 04:44:39 +08:00
{
result . AppendError ( " Invalid argument for command option --stop; must be true or false. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( ! m_options . notify . empty ( )
2010-10-15 05:31:13 +08:00
& & ! VerifyCommandOptionValue ( m_options . notify , notify_action ) )
2010-10-14 04:44:39 +08:00
{
result . AppendError ( " Invalid argument for command option --notify; must be true or false. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( ! m_options . pass . empty ( )
2010-10-15 05:31:13 +08:00
& & ! VerifyCommandOptionValue ( m_options . pass , pass_action ) )
2010-10-14 04:44:39 +08:00
{
result . AppendError ( " Invalid argument for command option --pass; must be true or false. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
size_t num_args = signal_args . GetArgumentCount ( ) ;
UnixSignals & signals = process_sp - > GetUnixSignals ( ) ;
int num_signals_set = 0 ;
2010-10-15 05:31:13 +08:00
if ( num_args > 0 )
2010-10-14 04:44:39 +08:00
{
2010-10-15 05:31:13 +08:00
for ( size_t i = 0 ; i < num_args ; + + i )
2010-10-14 04:44:39 +08:00
{
2010-10-15 05:31:13 +08:00
int32_t signo = signals . GetSignalNumberFromName ( signal_args . GetArgumentAtIndex ( i ) ) ;
if ( signo ! = LLDB_INVALID_SIGNAL_NUMBER )
{
// Casting the actions as bools here should be okay, because VerifyCommandOptionValue guarantees
// the value is either 0 or 1.
if ( stop_action ! = - 1 )
signals . SetShouldStop ( signo , ( bool ) stop_action ) ;
if ( pass_action ! = - 1 )
{
bool suppress = ! ( ( bool ) pass_action ) ;
signals . SetShouldSuppress ( signo , suppress ) ;
}
if ( notify_action ! = - 1 )
signals . SetShouldNotify ( signo , ( bool ) notify_action ) ;
+ + num_signals_set ;
}
else
2010-10-14 04:44:39 +08:00
{
2010-10-15 05:31:13 +08:00
result . AppendErrorWithFormat ( " Invalid signal name '%s' \n " , signal_args . GetArgumentAtIndex ( i ) ) ;
2010-10-14 04:44:39 +08:00
}
}
2010-10-15 05:31:13 +08:00
}
else
{
// No signal specified, if any command options were specified, update ALL signals.
if ( ( notify_action ! = - 1 ) | | ( stop_action ! = - 1 ) | | ( pass_action ! = - 1 ) )
2010-10-14 04:44:39 +08:00
{
2010-10-15 05:31:13 +08:00
if ( m_interpreter . Confirm ( " Do you really want to update all the signals? " , false ) )
{
int32_t signo = signals . GetFirstSignalNumber ( ) ;
while ( signo ! = LLDB_INVALID_SIGNAL_NUMBER )
{
if ( notify_action ! = - 1 )
signals . SetShouldNotify ( signo , ( bool ) notify_action ) ;
if ( stop_action ! = - 1 )
signals . SetShouldStop ( signo , ( bool ) stop_action ) ;
if ( pass_action ! = - 1 )
{
bool suppress = ! ( ( bool ) pass_action ) ;
signals . SetShouldSuppress ( signo , suppress ) ;
}
signo = signals . GetNextSignalNumber ( signo ) ;
}
}
2010-10-14 04:44:39 +08:00
}
}
2010-10-15 05:31:13 +08:00
PrintSignalInformation ( result . GetOutputStream ( ) , signal_args , num_signals_set , signals ) ;
2010-10-14 04:44:39 +08:00
if ( num_signals_set > 0 )
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
else
result . SetStatus ( eReturnStatusFailed ) ;
return result . Succeeded ( ) ;
}
protected :
CommandOptions m_options ;
} ;
2011-03-25 05:19:54 +08:00
OptionDefinition
2010-10-14 04:44:39 +08:00
CommandObjectProcessHandle : : CommandOptions : : g_option_table [ ] =
{
{ LLDB_OPT_SET_1 , false , " stop " , ' s ' , required_argument , NULL , 0 , eArgTypeBoolean , " Whether or not the process should be stopped if the signal is received. " } ,
{ LLDB_OPT_SET_1 , false , " notify " , ' n ' , required_argument , NULL , 0 , eArgTypeBoolean , " Whether or not the debugger should notify the user if the signal is received. " } ,
{ LLDB_OPT_SET_1 , false , " pass " , ' p ' , required_argument , NULL , 0 , eArgTypeBoolean , " Whether or not the signal should be passed to the process. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
} ;
2010-06-09 00:52:24 +08:00
//-------------------------------------------------------------------------
// CommandObjectMultiwordProcess
//-------------------------------------------------------------------------
2010-06-23 09:19:29 +08:00
CommandObjectMultiwordProcess : : CommandObjectMultiwordProcess ( CommandInterpreter & interpreter ) :
2010-09-18 09:14:36 +08:00
CommandObjectMultiword ( interpreter ,
" process " ,
" A set of commands for operating on a process. " ,
" process <subcommand> [<subcommand-options>] " )
2010-06-09 00:52:24 +08:00
{
2011-07-03 05:07:54 +08:00
LoadSubCommand ( " attach " , CommandObjectSP ( new CommandObjectProcessAttach ( interpreter ) ) ) ;
LoadSubCommand ( " launch " , CommandObjectSP ( new CommandObjectProcessLaunch ( interpreter ) ) ) ;
LoadSubCommand ( " continue " , CommandObjectSP ( new CommandObjectProcessContinue ( interpreter ) ) ) ;
LoadSubCommand ( " connect " , CommandObjectSP ( new CommandObjectProcessConnect ( interpreter ) ) ) ;
LoadSubCommand ( " detach " , CommandObjectSP ( new CommandObjectProcessDetach ( interpreter ) ) ) ;
LoadSubCommand ( " load " , CommandObjectSP ( new CommandObjectProcessLoad ( interpreter ) ) ) ;
LoadSubCommand ( " unload " , CommandObjectSP ( new CommandObjectProcessUnload ( interpreter ) ) ) ;
LoadSubCommand ( " signal " , CommandObjectSP ( new CommandObjectProcessSignal ( interpreter ) ) ) ;
LoadSubCommand ( " handle " , CommandObjectSP ( new CommandObjectProcessHandle ( interpreter ) ) ) ;
LoadSubCommand ( " status " , CommandObjectSP ( new CommandObjectProcessStatus ( interpreter ) ) ) ;
2010-09-18 09:14:36 +08:00
LoadSubCommand ( " interrupt " , CommandObjectSP ( new CommandObjectProcessInterrupt ( interpreter ) ) ) ;
2011-07-03 05:07:54 +08:00
LoadSubCommand ( " kill " , CommandObjectSP ( new CommandObjectProcessKill ( interpreter ) ) ) ;
2010-06-09 00:52:24 +08:00
}
CommandObjectMultiwordProcess : : ~ CommandObjectMultiwordProcess ( )
{
}