2011-03-19 09:12:21 +08:00
//===-- CommandObjectPlatform.cpp -------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
2016-03-25 05:49:22 +08:00
# include <mutex>
2016-02-23 03:02:01 +08:00
# include "CommandObjectPlatform.h"
2011-03-19 09:12:21 +08:00
# include "lldb/Core/Debugger.h"
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-30 05:13:06 +08:00
# include "lldb/Core/Module.h"
2011-03-19 09:12:21 +08:00
# include "lldb/Core/PluginManager.h"
2017-03-23 07:33:16 +08:00
# include "lldb/Host/OptionParser.h"
2015-01-16 04:08:35 +08:00
# include "lldb/Host/StringConvert.h"
2011-03-19 09:12:21 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
2014-07-10 00:31:49 +08:00
# include "lldb/Interpreter/CommandOptionValidators.h"
2011-03-19 09:12:21 +08:00
# include "lldb/Interpreter/CommandReturnObject.h"
2013-11-21 05:07:01 +08:00
# include "lldb/Interpreter/OptionGroupFile.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/Interpreter/OptionGroupPlatform.h"
2011-03-19 09:12:21 +08:00
# include "lldb/Target/ExecutionContext.h"
# include "lldb/Target/Platform.h"
2011-04-08 06:46:35 +08:00
# include "lldb/Target/Process.h"
2018-04-18 02:53:35 +08:00
# include "lldb/Utility/Args.h"
2017-03-04 09:30:05 +08:00
# include "lldb/Utility/DataExtractor.h"
2011-03-19 09:12:21 +08:00
2016-09-20 01:54:06 +08:00
# include "llvm/ADT/SmallString.h"
2017-02-07 01:55:02 +08:00
# include "llvm/Support/Threading.h"
2016-09-20 01:54:06 +08:00
2011-03-19 09:12:21 +08:00
using namespace lldb ;
using namespace lldb_private ;
2016-09-24 01:48:13 +08:00
static mode_t ParsePermissionString ( const char * ) = delete ;
static mode_t ParsePermissionString ( llvm : : StringRef permissions ) {
if ( permissions . size ( ) ! = 9 )
2016-09-07 04:57:50 +08:00
return ( mode_t ) ( - 1 ) ;
bool user_r , user_w , user_x , group_r , group_w , group_x , world_r , world_w ,
world_x ;
user_r = ( permissions [ 0 ] = = ' r ' ) ;
user_w = ( permissions [ 1 ] = = ' w ' ) ;
user_x = ( permissions [ 2 ] = = ' x ' ) ;
group_r = ( permissions [ 3 ] = = ' r ' ) ;
group_w = ( permissions [ 4 ] = = ' w ' ) ;
group_x = ( permissions [ 5 ] = = ' x ' ) ;
world_r = ( permissions [ 6 ] = = ' r ' ) ;
world_w = ( permissions [ 7 ] = = ' w ' ) ;
world_x = ( permissions [ 8 ] = = ' x ' ) ;
mode_t user , group , world ;
user = ( user_r ? 4 : 0 ) | ( user_w ? 2 : 0 ) | ( user_x ? 1 : 0 ) ;
group = ( group_r ? 4 : 0 ) | ( group_w ? 2 : 0 ) | ( group_x ? 1 : 0 ) ;
world = ( world_r ? 4 : 0 ) | ( world_w ? 2 : 0 ) | ( world_x ? 1 : 0 ) ;
return user | group | world ;
2013-08-27 07:57:52 +08:00
}
2018-09-27 02:50:19 +08:00
static constexpr OptionDefinition g_permissions_options [ ] = {
2016-09-07 04:57:50 +08:00
// clang-format off
2018-09-27 02:50:19 +08:00
{ LLDB_OPT_SET_ALL , false , " permissions-value " , ' v ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypePermissionsNumber , " Give out the numeric value for permissions (e.g. 757) " } ,
{ LLDB_OPT_SET_ALL , false , " permissions-string " , ' s ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypePermissionsString , " Give out the string value for permissions (e.g. rwxr-xr--). " } ,
{ LLDB_OPT_SET_ALL , false , " user-read " , ' r ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow user to read. " } ,
{ LLDB_OPT_SET_ALL , false , " user-write " , ' w ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow user to write. " } ,
{ LLDB_OPT_SET_ALL , false , " user-exec " , ' x ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow user to execute. " } ,
{ LLDB_OPT_SET_ALL , false , " group-read " , ' R ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow group to read. " } ,
{ LLDB_OPT_SET_ALL , false , " group-write " , ' W ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow group to write. " } ,
{ LLDB_OPT_SET_ALL , false , " group-exec " , ' X ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow group to execute. " } ,
{ LLDB_OPT_SET_ALL , false , " world-read " , ' d ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow world to read. " } ,
{ LLDB_OPT_SET_ALL , false , " world-write " , ' t ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow world to write. " } ,
{ LLDB_OPT_SET_ALL , false , " world-exec " , ' e ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Allow world to execute. " } ,
2016-09-07 04:57:50 +08:00
// clang-format on
2013-08-27 07:57:52 +08:00
} ;
2016-09-24 01:48:13 +08:00
class OptionPermissions : public OptionGroup {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
OptionPermissions ( ) { }
~ OptionPermissions ( ) override = default ;
2017-05-12 12:51:55 +08:00
lldb_private : : Status
2016-09-24 01:48:13 +08:00
SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_arg ,
2016-09-07 04:57:50 +08:00
ExecutionContext * execution_context ) override {
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
char short_option = ( char ) GetDefinitions ( ) [ option_idx ] . short_option ;
switch ( short_option ) {
case ' v ' : {
2016-09-24 01:48:13 +08:00
if ( option_arg . getAsInteger ( 8 , m_permissions ) ) {
m_permissions = 0777 ;
2016-09-07 04:57:50 +08:00
error . SetErrorStringWithFormat ( " invalid value for permissions: %s " ,
2016-09-24 01:48:13 +08:00
option_arg . str ( ) . c_str ( ) ) ;
}
2016-09-07 04:57:50 +08:00
} break ;
case ' s ' : {
mode_t perms = ParsePermissionString ( option_arg ) ;
if ( perms = = ( mode_t ) - 1 )
error . SetErrorStringWithFormat ( " invalid value for permissions: %s " ,
2016-09-24 01:48:13 +08:00
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
else
m_permissions = perms ;
} break ;
case ' r ' :
m_permissions | = lldb : : eFilePermissionsUserRead ;
break ;
case ' w ' :
m_permissions | = lldb : : eFilePermissionsUserWrite ;
break ;
case ' x ' :
m_permissions | = lldb : : eFilePermissionsUserExecute ;
break ;
case ' R ' :
m_permissions | = lldb : : eFilePermissionsGroupRead ;
break ;
case ' W ' :
m_permissions | = lldb : : eFilePermissionsGroupWrite ;
break ;
case ' X ' :
m_permissions | = lldb : : eFilePermissionsGroupExecute ;
break ;
case ' d ' :
m_permissions | = lldb : : eFilePermissionsWorldRead ;
break ;
case ' t ' :
m_permissions | = lldb : : eFilePermissionsWorldWrite ;
break ;
case ' e ' :
m_permissions | = lldb : : eFilePermissionsWorldExecute ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " , short_option ) ;
break ;
2013-08-27 07:57:52 +08:00
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
return error ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
m_permissions = 0 ;
}
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
2016-09-23 05:06:13 +08:00
return llvm : : makeArrayRef ( g_permissions_options ) ;
2016-09-07 04:57:50 +08:00
}
// Instance variables to hold the values for command options.
uint32_t m_permissions ;
2016-02-23 03:02:01 +08:00
2013-08-27 07:57:52 +08:00
private :
2016-09-07 04:57:50 +08:00
DISALLOW_COPY_AND_ASSIGN ( OptionPermissions ) ;
2013-08-27 07:57:52 +08:00
} ;
2011-04-13 08:18:08 +08:00
2011-03-19 09:12:21 +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
// "platform select <platform-name>"
2011-03-19 09:12:21 +08:00
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformSelect : public CommandObjectParsed {
2011-03-19 09:12:21 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformSelect ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform select " ,
" Create a platform if needed and select it as the "
" current platform. " ,
" platform select <platform-name> " , 0 ) ,
m_option_group ( ) ,
m_platform_options (
false ) // Don't include the "--platform" option by passing false
{
m_option_group . Append ( & m_platform_options , LLDB_OPT_SET_ALL , 1 ) ;
m_option_group . Finalize ( ) ;
}
~ CommandObjectPlatformSelect ( ) override = default ;
Refactoring for for the internal command line completion API (NFC)
Summary:
This patch refactors the internal completion API. It now takes (as far as possible) a single
CompletionRequest object instead o half a dozen in/out/in-out parameters. The CompletionRequest
contains a common superset of the different parameters as far as it makes sense. This includes
the raw command line string and raw cursor position, which should make the `expr` command
possible to implement (at least without hacks that reconstruct the command line from the args).
This patch is not intended to change the observable behavior of lldb in any way. It's also as
minimal as possible and doesn't attempt to fix all the problems the API has.
Some Q&A:
Q: Why is this not fixing all the problems in the completion API?
A: Because is a blocker for the expr command completion which I want to get in ASAP. This is the
smallest patch that unblocks the expr completion patch and which allows trivial refactoring in the future.
The patch also doesn't really change the internal information flow in the API, so that hopefully
saves us from ever having to revert and resubmit this humongous patch.
Q: Can we merge all the copy-pasted code in the completion methods
(like computing the current incomplete arg) into CompletionRequest class?
A: Yes, but it's out of scope for this patch.
Q: Why the `word_complete = request.GetWordComplete(); ... ` pattern?
A: I don't want to add a getter that returns a reference to the internal integer. So we have
to use a temporary variable and the Getter/Setter instead. We don't throw exceptions
from what I can tell, so the behavior doesn't change.
Q: Why are we not owning the list of matches?
A: Because that's how the previous API works. But that should be fixed too (in another patch).
Q: Can we make the constructor simpler and compute some of the values from the plain command?
A: I think this works, but I rather want to have this in a follow up commit. Especially when making nested
request it's a bit awkward that the parsed arguments behave as both input/output (as we should in theory
propagate the changes on the nested request back to the parent request if we don't want to change the
behavior too much).
Q: Can't we pass one const request object and then just return another result object instead of mixing
them together in one in/out parameter?
A: It's hard to get keep the same behavior with that pattern, but I think we can also get a nice API with just
a single request object. If we make all input parameters read-only, we have a clear separation between what
is actually an input and what an output parameter (and hopefully we get rid of the in-out parameters).
Q: Can we throw out the 'match' variables that are not implemented according to the comment?
A: We currently just forward them as in the old code to the different methods, even though I think
they are really not used. We can easily remove and readd them once every single completion method just
takes a CompletionRequest, but for now I prefer NFC behavior from the perspective of the API user.
Reviewers: davide, jingham, labath
Reviewed By: jingham
Subscribers: mgorny, friss, lldb-commits
Differential Revision: https://reviews.llvm.org/D48796
llvm-svn: 336146
2018-07-03 05:29:56 +08:00
int HandleCompletion ( CompletionRequest & request ) override {
2018-07-14 02:28:14 +08:00
CommandCompletions : : PlatformPluginNames ( GetCommandInterpreter ( ) , request ,
nullptr ) ;
2018-07-28 02:42:46 +08:00
return request . GetNumberOfMatches ( ) ;
2016-09-07 04:57:50 +08:00
}
Options * GetOptions ( ) override { return & m_option_group ; }
2012-06-09 05:56:10 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
if ( args . GetArgumentCount ( ) = = 1 ) {
const char * platform_name = args . GetArgumentAtIndex ( 0 ) ;
if ( platform_name & & platform_name [ 0 ] ) {
const bool select = true ;
m_platform_options . SetPlatformName ( platform_name ) ;
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
ArchSpec platform_arch ;
PlatformSP platform_sp ( m_platform_options . CreatePlatformWithOptions (
m_interpreter , ArchSpec ( ) , select , error , platform_arch ) ) ;
if ( platform_sp ) {
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . SetSelectedPlatform (
platform_sp ) ;
platform_sp - > GetStatus ( result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " invalid platform name " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError (
" platform create takes a platform name as an argument \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2011-03-19 09:12:21 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
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
2016-09-07 04:57:50 +08:00
OptionGroupOptions m_option_group ;
OptionGroupPlatform m_platform_options ;
2011-03-19 09:12:21 +08:00
} ;
//----------------------------------------------------------------------
// "platform list"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformList : public CommandObjectParsed {
2011-03-19 09:12:21 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformList ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform list " ,
" List all platforms that are available. " , nullptr ,
0 ) { }
2011-03-19 09:12:21 +08:00
2016-09-07 04:57:50 +08:00
~ CommandObjectPlatformList ( ) override = default ;
2011-03-19 09:12:21 +08:00
2012-06-09 05:56:10 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
Stream & ostrm = result . GetOutputStream ( ) ;
ostrm . Printf ( " Available platforms: \n " ) ;
PlatformSP host_platform_sp ( Platform : : GetHostPlatform ( ) ) ;
ostrm . Printf ( " %s: %s \n " , host_platform_sp - > GetPluginName ( ) . GetCString ( ) ,
host_platform_sp - > GetDescription ( ) ) ;
uint32_t idx ;
for ( idx = 0 ; 1 ; + + idx ) {
const char * plugin_name =
PluginManager : : GetPlatformPluginNameAtIndex ( idx ) ;
if ( plugin_name = = nullptr )
break ;
const char * plugin_desc =
PluginManager : : GetPlatformPluginDescriptionAtIndex ( idx ) ;
if ( plugin_desc = = nullptr )
break ;
ostrm . Printf ( " %s: %s \n " , plugin_name , plugin_desc ) ;
2011-03-19 09:12:21 +08:00
}
2016-09-07 04:57:50 +08:00
if ( idx = = 0 ) {
result . AppendError ( " no platforms are available \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
} else
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return result . Succeeded ( ) ;
}
2011-03-19 09:12:21 +08:00
} ;
//----------------------------------------------------------------------
// "platform status"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformStatus : public CommandObjectParsed {
2011-03-19 09:12:21 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformStatus ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform status " ,
" Display status for the current platform. " , nullptr ,
0 ) { }
2011-03-19 09:12:21 +08:00
2016-09-07 04:57:50 +08:00
~ CommandObjectPlatformStatus ( ) override = default ;
2011-03-19 09:12:21 +08:00
2012-06-09 05:56:10 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
Stream & ostrm = result . GetOutputStream ( ) ;
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
PlatformSP platform_sp ;
if ( target ) {
platform_sp = target - > GetPlatform ( ) ;
2011-03-19 09:12:21 +08:00
}
2016-09-07 04:57:50 +08:00
if ( ! platform_sp ) {
platform_sp =
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ;
}
if ( platform_sp ) {
platform_sp - > GetStatus ( ostrm ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
2017-07-21 15:08:20 +08:00
result . AppendError ( " no platform is currently selected \n " ) ;
2016-09-07 04:57:50 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
2011-03-19 09:12:21 +08:00
} ;
2011-03-23 08:09:55 +08:00
//----------------------------------------------------------------------
// "platform connect <connect-url>"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformConnect : public CommandObjectParsed {
2011-03-23 08:09:55 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformConnect ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " platform connect " ,
" Select the current platform by providing a connection URL. " ,
" platform connect <connect-url> " , 0 ) { }
2011-03-23 08:09:55 +08:00
2016-09-07 04:57:50 +08:00
~ CommandObjectPlatformConnect ( ) override = default ;
2011-03-23 08:09:55 +08:00
2012-06-09 05:56:10 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
Stream & ostrm = result . GetOutputStream ( ) ;
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
2017-05-12 12:51:55 +08:00
Status error ( platform_sp - > ConnectRemote ( args ) ) ;
2016-09-07 04:57:50 +08:00
if ( error . Success ( ) ) {
platform_sp - > GetStatus ( ostrm ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
platform_sp - > ConnectToWaitingProcesses ( m_interpreter . GetDebugger ( ) ,
error ) ;
if ( error . Fail ( ) ) {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendErrorWithFormat ( " %s \n " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform is currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2011-03-23 08:09:55 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
Options * GetOptions ( ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
OptionGroupOptions * m_platform_options = nullptr ;
if ( platform_sp ) {
m_platform_options = platform_sp - > GetConnectionOptions ( m_interpreter ) ;
if ( m_platform_options ! = nullptr & & ! m_platform_options - > m_did_finalize )
m_platform_options - > Finalize ( ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return m_platform_options ;
}
2011-03-23 08:09:55 +08:00
} ;
//----------------------------------------------------------------------
// "platform disconnect"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformDisconnect : public CommandObjectParsed {
2011-03-23 08:09:55 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformDisconnect ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform disconnect " ,
" Disconnect from the current platform. " ,
" platform disconnect " , 0 ) { }
2011-03-23 08:09:55 +08:00
2016-09-07 04:57:50 +08:00
~ CommandObjectPlatformDisconnect ( ) override = default ;
2011-03-23 08:09:55 +08:00
2012-06-09 05:56:10 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
if ( args . GetArgumentCount ( ) = = 0 ) {
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
if ( platform_sp - > IsConnected ( ) ) {
2018-05-01 00:49:04 +08:00
// Cache the instance name if there is one since we are about to
// disconnect and the name might go with it.
2016-09-07 04:57:50 +08:00
const char * hostname_cstr = platform_sp - > GetHostname ( ) ;
std : : string hostname ;
if ( hostname_cstr )
hostname . assign ( hostname_cstr ) ;
error = platform_sp - > DisconnectRemote ( ) ;
if ( error . Success ( ) ) {
Stream & ostrm = result . GetOutputStream ( ) ;
if ( hostname . empty ( ) )
ostrm . Printf ( " Disconnected from \" %s \" \n " ,
platform_sp - > GetPluginName ( ) . GetCString ( ) ) ;
2011-03-23 08:09:55 +08:00
else
2016-09-07 04:57:50 +08:00
ostrm . Printf ( " Disconnected from \" %s \" \n " , hostname . c_str ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendErrorWithFormat ( " %s " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
// Not connected...
result . AppendErrorWithFormat (
" not connected to '%s' " ,
platform_sp - > GetPluginName ( ) . GetCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
// Bad args
result . AppendError (
" \" platform disconnect \" doesn't take any arguments " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform is currently selected " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2011-03-23 08:09:55 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2011-03-23 08:09:55 +08:00
} ;
2013-08-27 07:57:52 +08:00
2013-11-21 05:07:01 +08:00
//----------------------------------------------------------------------
// "platform settings"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformSettings : public CommandObjectParsed {
2013-11-21 05:07:01 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformSettings ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform settings " ,
" Set settings for the current target's platform, "
" or for a platform by name. " ,
" platform settings " , 0 ) ,
2016-08-12 07:51:28 +08:00
m_options ( ) ,
2016-09-07 04:57:50 +08:00
m_option_working_dir ( LLDB_OPT_SET_1 , false , " working-dir " , ' w ' , 0 ,
eArgTypePath ,
" The working directory for the platform. " ) {
m_options . Append ( & m_option_working_dir , LLDB_OPT_SET_ALL , LLDB_OPT_SET_1 ) ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
~ CommandObjectPlatformSettings ( ) override = default ;
2016-02-23 03:02:01 +08:00
2013-11-21 05:07:01 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
if ( m_option_working_dir . GetOptionValue ( ) . OptionWasSet ( ) )
platform_sp - > SetWorkingDirectory (
m_option_working_dir . GetOptionValue ( ) . GetCurrentValue ( ) ) ;
} else {
result . AppendError ( " no platform is currently selected " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-11-21 05:07:01 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
Options * GetOptions ( ) override {
if ( ! m_options . DidFinalize ( ) )
m_options . Finalize ( ) ;
return & m_options ;
}
2016-02-23 03:02:01 +08:00
2013-11-21 05:07:01 +08:00
protected :
2016-09-07 04:57:50 +08:00
OptionGroupOptions m_options ;
OptionGroupFile m_option_working_dir ;
2013-11-21 05:07:01 +08:00
} ;
2011-04-12 13:54:46 +08:00
//----------------------------------------------------------------------
2013-08-27 07:57:52 +08:00
// "platform mkdir"
2011-04-12 13:54:46 +08:00
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformMkDir : public CommandObjectParsed {
2011-04-12 13:54:46 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformMkDir ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform mkdir " ,
" Make a new directory on the remote end. " , nullptr ,
2016-02-23 03:02:01 +08:00
0 ) ,
2016-09-07 04:57:50 +08:00
m_options ( ) { }
~ CommandObjectPlatformMkDir ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
std : : string cmd_line ;
args . GetCommandString ( cmd_line ) ;
uint32_t mode ;
const OptionPermissions * options_permissions =
( const OptionPermissions * ) m_options . GetGroupWithOption ( ' r ' ) ;
if ( options_permissions )
mode = options_permissions - > m_permissions ;
else
mode = lldb : : eFilePermissionsUserRWX | lldb : : eFilePermissionsGroupRWX |
lldb : : eFilePermissionsWorldRX ;
2018-11-02 05:05:36 +08:00
Status error = platform_sp - > MakeDirectory ( FileSpec ( cmd_line ) , mode ) ;
2016-09-07 04:57:50 +08:00
if ( error . Success ( ) ) {
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2011-04-12 13:54:46 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
Options * GetOptions ( ) override {
if ( ! m_options . DidFinalize ( ) ) {
m_options . Append ( new OptionPermissions ( ) ) ;
m_options . Finalize ( ) ;
2012-06-09 05:56:10 +08:00
}
2016-09-07 04:57:50 +08:00
return & m_options ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
OptionGroupOptions m_options ;
2013-08-27 07:57:52 +08:00
} ;
//----------------------------------------------------------------------
// "platform fopen"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformFOpen : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformFOpen ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform file open " ,
" Open a file on the remote end. " , nullptr , 0 ) ,
m_options ( ) { }
~ CommandObjectPlatformFOpen ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
std : : string cmd_line ;
args . GetCommandString ( cmd_line ) ;
mode_t perms ;
const OptionPermissions * options_permissions =
( const OptionPermissions * ) m_options . GetGroupWithOption ( ' r ' ) ;
if ( options_permissions )
perms = options_permissions - > m_permissions ;
else
perms = lldb : : eFilePermissionsUserRW | lldb : : eFilePermissionsGroupRW |
lldb : : eFilePermissionsWorldRead ;
lldb : : user_id_t fd = platform_sp - > OpenFile (
2018-11-02 05:05:36 +08:00
FileSpec ( cmd_line ) ,
2016-09-07 04:57:50 +08:00
File : : eOpenOptionRead | File : : eOpenOptionWrite |
File : : eOpenOptionAppend | File : : eOpenOptionCanCreate ,
perms , error ) ;
if ( error . Success ( ) ) {
result . AppendMessageWithFormat ( " File Descriptor = % " PRIu64 " \n " , fd ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
Options * GetOptions ( ) override {
if ( ! m_options . DidFinalize ( ) ) {
m_options . Append ( new OptionPermissions ( ) ) ;
m_options . Finalize ( ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return & m_options ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
OptionGroupOptions m_options ;
2013-08-27 07:57:52 +08:00
} ;
2011-04-12 13:54:46 +08:00
2013-08-27 07:57:52 +08:00
//----------------------------------------------------------------------
// "platform fclose"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformFClose : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformFClose ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform file close " ,
" Close a file on the remote end. " , nullptr , 0 ) { }
~ CommandObjectPlatformFClose ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
std : : string cmd_line ;
args . GetCommandString ( cmd_line ) ;
const lldb : : user_id_t fd =
StringConvert : : ToUInt64 ( cmd_line . c_str ( ) , UINT64_MAX ) ;
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
bool success = platform_sp - > CloseFile ( fd , error ) ;
if ( success ) {
result . AppendMessageWithFormat ( " file % " PRIu64 " closed. \n " , fd ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2011-04-12 13:54:46 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2011-04-12 13:54:46 +08:00
} ;
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
//----------------------------------------------------------------------
2013-08-27 07:57:52 +08:00
// "platform fread"
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
//----------------------------------------------------------------------
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
2018-09-27 02:50:19 +08:00
static constexpr OptionDefinition g_platform_fread_options [ ] = {
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format off
2018-09-27 02:50:19 +08:00
{ LLDB_OPT_SET_1 , false , " offset " , ' o ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeIndex , " Offset into the file at which to start reading. " } ,
{ LLDB_OPT_SET_1 , false , " count " , ' c ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeCount , " Number of bytes to read from the file. " } ,
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format on
} ;
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformFRead : public CommandObjectParsed {
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
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformFRead ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform file read " ,
" Read data from a file on the remote end. " , nullptr ,
2016-02-23 03:02:01 +08:00
0 ) ,
2016-09-07 04:57:50 +08:00
m_options ( ) { }
~ CommandObjectPlatformFRead ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
std : : string cmd_line ;
args . GetCommandString ( cmd_line ) ;
const lldb : : user_id_t fd =
StringConvert : : ToUInt64 ( cmd_line . c_str ( ) , UINT64_MAX ) ;
std : : string buffer ( m_options . m_count , 0 ) ;
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
uint32_t retcode = platform_sp - > ReadFile (
fd , m_options . m_offset , & buffer [ 0 ] , m_options . m_count , error ) ;
result . AppendMessageWithFormat ( " Return = %d \n " , retcode ) ;
result . AppendMessageWithFormat ( " Data = \" %s \" \n " , buffer . c_str ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
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
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
Options * GetOptions ( ) override { return & m_options ; }
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
protected :
class CommandOptions : public Options {
public :
CommandOptions ( ) : Options ( ) { }
~ CommandOptions ( ) override = default ;
2017-05-12 12:51:55 +08:00
Status SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_arg ,
ExecutionContext * execution_context ) override {
Status error ;
2016-09-07 04:57:50 +08:00
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option ) {
case ' o ' :
2016-11-13 00:56:47 +08:00
if ( option_arg . getAsInteger ( 0 , m_offset ) )
error . SetErrorStringWithFormat ( " invalid offset: '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' c ' :
2016-11-13 00:56:47 +08:00
if ( option_arg . getAsInteger ( 0 , m_count ) )
error . SetErrorStringWithFormat ( " invalid offset: '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " ,
short_option ) ;
break ;
}
return error ;
2013-08-27 07:57:52 +08:00
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
m_offset = 0 ;
m_count = 1 ;
2012-06-09 05:56:10 +08:00
}
2016-02-23 03:02:01 +08:00
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
2016-09-23 05:06:13 +08:00
return llvm : : makeArrayRef ( g_platform_fread_options ) ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
}
2016-09-07 04:57:50 +08:00
// Instance variables to hold the values for command options.
uint32_t m_offset ;
uint32_t m_count ;
} ;
CommandOptions m_options ;
2013-08-27 07:57:52 +08:00
} ;
2016-02-23 03:02:01 +08:00
2013-08-27 07:57:52 +08:00
//----------------------------------------------------------------------
// "platform fwrite"
//----------------------------------------------------------------------
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
2018-09-27 02:50:19 +08:00
static constexpr OptionDefinition g_platform_fwrite_options [ ] = {
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format off
2018-09-27 02:50:19 +08:00
{ LLDB_OPT_SET_1 , false , " offset " , ' o ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeIndex , " Offset into the file at which to start reading. " } ,
{ LLDB_OPT_SET_1 , false , " data " , ' d ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeValue , " Text to write to the file. " } ,
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format on
} ;
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformFWrite : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformFWrite ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform file write " ,
" Write data to a file on the remote end. " , nullptr ,
2016-02-23 03:02:01 +08:00
0 ) ,
2016-09-07 04:57:50 +08:00
m_options ( ) { }
~ CommandObjectPlatformFWrite ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
std : : string cmd_line ;
args . GetCommandString ( cmd_line ) ;
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
const lldb : : user_id_t fd =
StringConvert : : ToUInt64 ( cmd_line . c_str ( ) , UINT64_MAX ) ;
uint32_t retcode =
platform_sp - > WriteFile ( fd , m_options . m_offset , & m_options . m_data [ 0 ] ,
m_options . m_data . size ( ) , error ) ;
result . AppendMessageWithFormat ( " Return = %d \n " , retcode ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
Options * GetOptions ( ) override { return & m_options ; }
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
protected :
class CommandOptions : public Options {
public :
CommandOptions ( ) : Options ( ) { }
~ CommandOptions ( ) override = default ;
2017-05-12 12:51:55 +08:00
Status SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_arg ,
ExecutionContext * execution_context ) override {
Status error ;
2016-09-07 04:57:50 +08:00
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option ) {
case ' o ' :
2016-11-13 00:56:47 +08:00
if ( option_arg . getAsInteger ( 0 , m_offset ) )
error . SetErrorStringWithFormat ( " invalid offset: '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' d ' :
m_data . assign ( option_arg ) ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " ,
short_option ) ;
break ;
}
return error ;
2013-08-27 07:57:52 +08:00
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
m_offset = 0 ;
m_data . clear ( ) ;
2013-08-27 07:57:52 +08:00
}
2016-02-23 03:02:01 +08:00
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
2016-09-23 05:06:13 +08:00
return llvm : : makeArrayRef ( g_platform_fwrite_options ) ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
}
2016-09-07 04:57:50 +08:00
// Instance variables to hold the values for command options.
uint32_t m_offset ;
std : : string m_data ;
} ;
CommandOptions m_options ;
2013-08-27 07:57:52 +08:00
} ;
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformFile : public CommandObjectMultiword {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
CommandObjectPlatformFile ( CommandInterpreter & interpreter )
: CommandObjectMultiword (
interpreter , " platform file " ,
" Commands to access files on the current platform. " ,
" platform file [open|close|read|write] ... " ) {
LoadSubCommand (
" open " , CommandObjectSP ( new CommandObjectPlatformFOpen ( interpreter ) ) ) ;
LoadSubCommand (
" close " , CommandObjectSP ( new CommandObjectPlatformFClose ( interpreter ) ) ) ;
LoadSubCommand (
" read " , CommandObjectSP ( new CommandObjectPlatformFRead ( interpreter ) ) ) ;
LoadSubCommand (
" write " , CommandObjectSP ( new CommandObjectPlatformFWrite ( interpreter ) ) ) ;
}
~ CommandObjectPlatformFile ( ) override = default ;
2016-02-23 03:02:01 +08:00
2013-08-27 07:57:52 +08:00
private :
2016-09-07 04:57:50 +08:00
//------------------------------------------------------------------
// For CommandObjectPlatform only
//------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN ( CommandObjectPlatformFile ) ;
2013-08-27 07:57:52 +08:00
} ;
//----------------------------------------------------------------------
// "platform get-file remote-file-path host-file-path"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformGetFile : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformGetFile ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " platform get-file " ,
" Transfer a file from the remote end to the local host. " ,
" platform get-file <remote-file-spec> <local-file-spec> " , 0 ) {
SetHelpLong (
R " (Examples:
2015-07-14 13:48:36 +08:00
( lldb ) platform get - file / the / remote / file / path / the / local / file / path
2016-09-07 04:57:50 +08:00
Transfer a file from the remote end with file path / the / remote / file / path to the local host . ) " );
CommandArgumentEntry arg1 , arg2 ;
CommandArgumentData file_arg_remote , file_arg_host ;
// Define the first (and only) variant of this arg.
file_arg_remote . arg_type = eArgTypeFilename ;
file_arg_remote . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the
// argument entry.
arg1 . push_back ( file_arg_remote ) ;
// Define the second (and only) variant of this arg.
file_arg_host . arg_type = eArgTypeFilename ;
file_arg_host . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the
// argument entry.
arg2 . push_back ( file_arg_host ) ;
2018-05-01 00:49:04 +08:00
// Push the data for the first and the second arguments into the
// m_arguments vector.
2016-09-07 04:57:50 +08:00
m_arguments . push_back ( arg1 ) ;
m_arguments . push_back ( arg2 ) ;
}
~ CommandObjectPlatformGetFile ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
// If the number of arguments is incorrect, issue an error message.
if ( args . GetArgumentCount ( ) ! = 2 ) {
result . GetErrorStream ( ) . Printf ( " error: required arguments missing; "
" specify both the source and destination "
" file paths \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-27 07:57:52 +08:00
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
const char * remote_file_path = args . GetArgumentAtIndex ( 0 ) ;
const char * local_file_path = args . GetArgumentAtIndex ( 1 ) ;
2018-11-02 05:05:36 +08:00
Status error = platform_sp - > GetFile ( FileSpec ( remote_file_path ) ,
FileSpec ( local_file_path ) ) ;
2016-09-07 04:57:50 +08:00
if ( error . Success ( ) ) {
result . AppendMessageWithFormat (
" successfully get-file from %s (remote) to %s (host) \n " ,
remote_file_path , local_file_path ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendMessageWithFormat ( " get-file failed: %s \n " ,
error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2013-08-27 07:57:52 +08:00
} ;
//----------------------------------------------------------------------
// "platform get-size remote-file-path"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformGetSize : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformGetSize ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform get-size " ,
" Get the file size from the remote end. " ,
" platform get-size <remote-file-spec> " , 0 ) {
SetHelpLong (
R " (Examples:
2015-07-14 13:48:36 +08:00
( lldb ) platform get - size / the / remote / file / path
2016-09-07 04:57:50 +08:00
Get the file size from the remote end with path / the / remote / file / path . ) " );
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
CommandArgumentEntry arg1 ;
CommandArgumentData file_arg_remote ;
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
// Define the first (and only) variant of this arg.
file_arg_remote . arg_type = eArgTypeFilename ;
file_arg_remote . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the
// argument entry.
arg1 . push_back ( file_arg_remote ) ;
2013-08-27 07:57:52 +08:00
2016-09-07 04:57:50 +08:00
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg1 ) ;
}
~ CommandObjectPlatformGetSize ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
// If the number of arguments is incorrect, issue an error message.
if ( args . GetArgumentCount ( ) ! = 1 ) {
result . GetErrorStream ( ) . Printf ( " error: required argument missing; "
" specify the source file path as the only "
" argument \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
std : : string remote_file_path ( args . GetArgumentAtIndex ( 0 ) ) ;
2018-11-02 05:05:36 +08:00
user_id_t size = platform_sp - > GetFileSize ( FileSpec ( remote_file_path ) ) ;
2016-09-07 04:57:50 +08:00
if ( size ! = UINT64_MAX ) {
result . AppendMessageWithFormat ( " File size of %s (remote): % " PRIu64
" \n " ,
remote_file_path . c_str ( ) , size ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendMessageWithFormat (
" Error getting file size of %s (remote) \n " ,
remote_file_path . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
2013-08-27 07:57:52 +08:00
} ;
//----------------------------------------------------------------------
// "platform put-file"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformPutFile : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformPutFile ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " platform put-file " ,
" Transfer a file from this system to the remote end. " , nullptr , 0 ) {
}
~ CommandObjectPlatformPutFile ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
const char * src = args . GetArgumentAtIndex ( 0 ) ;
const char * dst = args . GetArgumentAtIndex ( 1 ) ;
2018-11-02 05:05:36 +08:00
FileSpec src_fs ( src ) ;
FileSystem : : Instance ( ) . Resolve ( src_fs ) ;
FileSpec dst_fs ( dst ? dst : src_fs . GetFilename ( ) . GetCString ( ) ) ;
2016-09-07 04:57:50 +08:00
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
2017-05-12 12:51:55 +08:00
Status error ( platform_sp - > PutFile ( src_fs , dst_fs ) ) ;
2016-09-07 04:57:50 +08:00
if ( error . Success ( ) ) {
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
} else {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform currently selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2013-08-27 07:57:52 +08:00
} ;
//----------------------------------------------------------------------
// "platform process launch"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformProcessLaunch ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform process launch " ,
" Launch a new process on a remote platform. " ,
" platform process launch program " ,
eCommandRequiresTarget | eCommandTryTargetAPILock ) ,
m_options ( ) { }
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
~ CommandObjectPlatformProcessLaunch ( ) override = default ;
Options * GetOptions ( ) override { return & m_options ; }
2016-02-23 03:02:01 +08:00
2013-08-27 07:57:52 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
PlatformSP platform_sp ;
if ( target ) {
platform_sp = target - > GetPlatform ( ) ;
}
if ( ! platform_sp ) {
platform_sp =
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ;
}
2013-08-27 07:57:52 +08:00
2016-09-07 04:57:50 +08:00
if ( platform_sp ) {
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
const size_t argc = args . GetArgumentCount ( ) ;
Target * target = m_exe_ctx . GetTargetPtr ( ) ;
Module * exe_module = target - > GetExecutableModulePointer ( ) ;
if ( exe_module ) {
m_options . launch_info . GetExecutableFile ( ) = exe_module - > GetFileSpec ( ) ;
2018-12-11 01:23:28 +08:00
llvm : : SmallString < 128 > exe_path ;
2016-09-20 01:54:06 +08:00
m_options . launch_info . GetExecutableFile ( ) . GetPath ( exe_path ) ;
if ( ! exe_path . empty ( ) )
2016-09-07 04:57:50 +08:00
m_options . launch_info . GetArguments ( ) . AppendArgument ( exe_path ) ;
m_options . launch_info . GetArchitecture ( ) = exe_module - > GetArchitecture ( ) ;
}
if ( argc > 0 ) {
if ( m_options . launch_info . GetExecutableFile ( ) ) {
2018-05-01 00:49:04 +08:00
// We already have an executable file, so we will use this and all
// arguments to this function are extra arguments
2016-09-07 04:57:50 +08:00
m_options . launch_info . GetArguments ( ) . AppendArguments ( args ) ;
} else {
// We don't have any file yet, so the first argument is our
// executable, and the rest are program arguments
const bool first_arg_is_executable = true ;
m_options . launch_info . SetArguments ( args , first_arg_is_executable ) ;
}
}
if ( m_options . launch_info . GetExecutableFile ( ) ) {
Debugger & debugger = m_interpreter . GetDebugger ( ) ;
if ( argc = = 0 )
target - > GetRunArguments ( m_options . launch_info . GetArguments ( ) ) ;
ProcessSP process_sp ( platform_sp - > DebugProcess (
m_options . launch_info , debugger , target , error ) ) ;
if ( process_sp & & process_sp - > IsAlive ( ) ) {
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
return true ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
if ( error . Success ( ) )
result . AppendError ( " process launch failed " ) ;
2013-08-27 07:57:52 +08:00
else
2016-09-07 04:57:50 +08:00
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
} else {
result . AppendError ( " 'platform process launch' uses the current target "
" file and arguments, or the executable and its "
" arguments can be specified in this command " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
} else {
result . AppendError ( " no platform is selected \n " ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2013-08-27 07:57:52 +08:00
protected :
2016-09-07 04:57:50 +08:00
ProcessLaunchCommandOptions m_options ;
2013-08-27 07:57:52 +08:00
} ;
//----------------------------------------------------------------------
// "platform process list"
//----------------------------------------------------------------------
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
2018-09-27 02:50:19 +08:00
static OptionDefinition g_platform_process_list_options [ ] = {
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format off
2018-09-27 02:50:19 +08:00
{ LLDB_OPT_SET_1 , false , " pid " , ' p ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypePid , " List the process info for a specific process ID. " } ,
{ LLDB_OPT_SET_2 , true , " name " , ' n ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeProcessName , " Find processes with executable basenames that match a string. " } ,
{ LLDB_OPT_SET_3 , true , " ends-with " , ' e ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeProcessName , " Find processes with executable basenames that end with a string. " } ,
{ LLDB_OPT_SET_4 , true , " starts-with " , ' s ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeProcessName , " Find processes with executable basenames that start with a string. " } ,
{ LLDB_OPT_SET_5 , true , " contains " , ' c ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeProcessName , " Find processes with executable basenames that contain a string. " } ,
{ LLDB_OPT_SET_6 , true , " regex " , ' r ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeRegularExpression , " Find processes with executable basenames that match a regular expression. " } ,
{ LLDB_OPT_SET_FROM_TO ( 2 , 6 ) , false , " parent " , ' P ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypePid , " Find processes that have a matching parent process ID. " } ,
{ LLDB_OPT_SET_FROM_TO ( 2 , 6 ) , false , " uid " , ' u ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeUnsignedInteger , " Find processes that have a matching user ID. " } ,
{ LLDB_OPT_SET_FROM_TO ( 2 , 6 ) , false , " euid " , ' U ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeUnsignedInteger , " Find processes that have a matching effective user ID. " } ,
{ LLDB_OPT_SET_FROM_TO ( 2 , 6 ) , false , " gid " , ' g ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeUnsignedInteger , " Find processes that have a matching group ID. " } ,
{ LLDB_OPT_SET_FROM_TO ( 2 , 6 ) , false , " egid " , ' G ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeUnsignedInteger , " Find processes that have a matching effective group ID. " } ,
{ LLDB_OPT_SET_FROM_TO ( 2 , 6 ) , false , " arch " , ' a ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeArchitecture , " Find processes that have a matching architecture. " } ,
{ LLDB_OPT_SET_FROM_TO ( 1 , 6 ) , false , " show-args " , ' A ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Show process arguments instead of the process executable basename. " } ,
{ LLDB_OPT_SET_FROM_TO ( 1 , 6 ) , false , " verbose " , ' v ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Enable verbose output. " } ,
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format on
} ;
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformProcessList : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformProcessList ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform process list " ,
" List processes on a remote platform by name, pid, "
" or many other matching attributes. " ,
" platform process list " , 0 ) ,
m_options ( ) { }
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
~ CommandObjectPlatformProcessList ( ) override = default ;
Options * GetOptions ( ) override { return & m_options ; }
2016-02-23 03:02:01 +08:00
2013-08-27 07:57:52 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
PlatformSP platform_sp ;
if ( target ) {
platform_sp = target - > GetPlatform ( ) ;
}
if ( ! platform_sp ) {
platform_sp =
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ;
}
if ( platform_sp ) {
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
if ( args . GetArgumentCount ( ) = = 0 ) {
if ( platform_sp ) {
Stream & ostrm = result . GetOutputStream ( ) ;
lldb : : pid_t pid =
m_options . match_info . GetProcessInfo ( ) . GetProcessID ( ) ;
if ( pid ! = LLDB_INVALID_PROCESS_ID ) {
ProcessInstanceInfo proc_info ;
if ( platform_sp - > GetProcessInfo ( pid , proc_info ) ) {
ProcessInstanceInfo : : DumpTableHeader ( ostrm , platform_sp . get ( ) ,
m_options . show_args ,
m_options . verbose ) ;
proc_info . DumpAsTableRow ( ostrm , platform_sp . get ( ) ,
m_options . show_args , m_options . verbose ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendErrorWithFormat (
" no process found with pid = % " PRIu64 " \n " , pid ) ;
result . SetStatus ( eReturnStatusFailed ) ;
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
}
2016-09-07 04:57:50 +08:00
} else {
ProcessInstanceInfoList proc_infos ;
const uint32_t matches =
platform_sp - > FindProcesses ( m_options . match_info , proc_infos ) ;
const char * match_desc = nullptr ;
const char * match_name =
m_options . match_info . GetProcessInfo ( ) . GetName ( ) ;
if ( match_name & & match_name [ 0 ] ) {
switch ( m_options . match_info . GetNameMatchType ( ) ) {
2017-02-20 19:35:33 +08:00
case NameMatch : : Ignore :
2016-09-07 04:57:50 +08:00
break ;
2017-02-20 19:35:33 +08:00
case NameMatch : : Equals :
2016-09-07 04:57:50 +08:00
match_desc = " matched " ;
break ;
2017-02-20 19:35:33 +08:00
case NameMatch : : Contains :
2016-09-07 04:57:50 +08:00
match_desc = " contained " ;
break ;
2017-02-20 19:35:33 +08:00
case NameMatch : : StartsWith :
2016-09-07 04:57:50 +08:00
match_desc = " started with " ;
break ;
2017-02-20 19:35:33 +08:00
case NameMatch : : EndsWith :
2016-09-07 04:57:50 +08:00
match_desc = " ended with " ;
break ;
2017-02-20 19:35:33 +08:00
case NameMatch : : RegularExpression :
2016-09-07 04:57:50 +08:00
match_desc = " matched the regular expression " ;
break ;
}
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
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
if ( matches = = 0 ) {
if ( match_desc )
result . AppendErrorWithFormat (
" no processes were found that %s \" %s \" on the \" %s \" "
" platform \n " ,
match_desc , match_name ,
platform_sp - > GetPluginName ( ) . GetCString ( ) ) ;
else
result . AppendErrorWithFormat (
" no processes were found on the \" %s \" platform \n " ,
platform_sp - > GetPluginName ( ) . GetCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
} else {
result . AppendMessageWithFormat (
" %u matching process%s found on \" %s \" " , matches ,
matches > 1 ? " es were " : " was " ,
platform_sp - > GetName ( ) . GetCString ( ) ) ;
if ( match_desc )
result . AppendMessageWithFormat ( " whose name %s \" %s \" " ,
match_desc , match_name ) ;
result . AppendMessageWithFormat ( " \n " ) ;
ProcessInstanceInfo : : DumpTableHeader ( ostrm , platform_sp . get ( ) ,
m_options . show_args ,
m_options . verbose ) ;
for ( uint32_t i = 0 ; i < matches ; + + i ) {
proc_infos . GetProcessInfoAtIndex ( i ) . DumpAsTableRow (
ostrm , platform_sp . get ( ) , m_options . show_args ,
m_options . verbose ) ;
}
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
}
2016-09-07 04:57:50 +08:00
}
}
} else {
result . AppendError ( " invalid args: process list takes only options \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform is selected \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
class CommandOptions : public Options {
public :
CommandOptions ( )
: Options ( ) , match_info ( ) , show_args ( false ) , verbose ( false ) {
2017-02-07 01:55:02 +08:00
static llvm : : once_flag g_once_flag ;
llvm : : call_once ( g_once_flag , [ ] ( ) {
2016-09-07 04:57:50 +08:00
PosixPlatformCommandOptionValidator * posix_validator =
new PosixPlatformCommandOptionValidator ( ) ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
for ( auto & Option : g_platform_process_list_options ) {
switch ( Option . short_option ) {
2016-09-07 04:57:50 +08:00
case ' u ' :
case ' U ' :
case ' g ' :
case ' G ' :
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
Option . validator = posix_validator ;
2016-09-07 04:57:50 +08:00
break ;
default :
break ;
}
}
} ) ;
}
~ CommandOptions ( ) override = default ;
2017-05-12 12:51:55 +08:00
Status SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_arg ,
ExecutionContext * execution_context ) override {
Status error ;
2016-09-07 04:57:50 +08:00
const int short_option = m_getopt_table [ option_idx ] . val ;
bool success = false ;
2016-11-13 00:56:47 +08:00
uint32_t id = LLDB_INVALID_PROCESS_ID ;
success = ! option_arg . getAsInteger ( 0 , id ) ;
2016-09-07 04:57:50 +08:00
switch ( short_option ) {
2016-11-13 00:56:47 +08:00
case ' p ' : {
match_info . GetProcessInfo ( ) . SetProcessID ( id ) ;
2016-09-07 04:57:50 +08:00
if ( ! success )
error . SetErrorStringWithFormat ( " invalid process ID string: '%s' " ,
2016-11-13 00:56:47 +08:00
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
2016-11-13 00:56:47 +08:00
}
2016-09-07 04:57:50 +08:00
case ' P ' :
2016-11-13 00:56:47 +08:00
match_info . GetProcessInfo ( ) . SetParentProcessID ( id ) ;
2016-09-07 04:57:50 +08:00
if ( ! success )
error . SetErrorStringWithFormat (
2016-11-13 00:56:47 +08:00
" invalid parent process ID string: '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' u ' :
2016-11-13 00:56:47 +08:00
match_info . GetProcessInfo ( ) . SetUserID ( success ? id : UINT32_MAX ) ;
2016-09-07 04:57:50 +08:00
if ( ! success )
error . SetErrorStringWithFormat ( " invalid user ID string: '%s' " ,
2016-11-13 00:56:47 +08:00
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' U ' :
2016-11-13 00:56:47 +08:00
match_info . GetProcessInfo ( ) . SetEffectiveUserID ( success ? id
: UINT32_MAX ) ;
2016-09-07 04:57:50 +08:00
if ( ! success )
error . SetErrorStringWithFormat (
2016-11-13 00:56:47 +08:00
" invalid effective user ID string: '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' g ' :
2016-11-13 00:56:47 +08:00
match_info . GetProcessInfo ( ) . SetGroupID ( success ? id : UINT32_MAX ) ;
2016-09-07 04:57:50 +08:00
if ( ! success )
error . SetErrorStringWithFormat ( " invalid group ID string: '%s' " ,
2016-11-13 00:56:47 +08:00
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' G ' :
2016-11-13 00:56:47 +08:00
match_info . GetProcessInfo ( ) . SetEffectiveGroupID ( success ? id
: UINT32_MAX ) ;
2016-09-07 04:57:50 +08:00
if ( ! success )
error . SetErrorStringWithFormat (
2016-11-13 00:56:47 +08:00
" invalid effective group ID string: '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' a ' : {
TargetSP target_sp =
execution_context ? execution_context - > GetTargetSP ( ) : TargetSP ( ) ;
DebuggerSP debugger_sp =
target_sp ? target_sp - > GetDebugger ( ) . shared_from_this ( )
: DebuggerSP ( ) ;
PlatformSP platform_sp =
debugger_sp ? debugger_sp - > GetPlatformList ( ) . GetSelectedPlatform ( )
: PlatformSP ( ) ;
2017-10-31 18:56:03 +08:00
match_info . GetProcessInfo ( ) . GetArchitecture ( ) =
Platform : : GetAugmentedArchSpec ( platform_sp . get ( ) , option_arg ) ;
2016-09-07 04:57:50 +08:00
} break ;
case ' n ' :
2018-06-14 06:08:14 +08:00
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . SetFile (
2018-11-02 05:05:36 +08:00
option_arg , FileSpec : : Style : : native ) ;
2017-02-20 19:35:33 +08:00
match_info . SetNameMatchType ( NameMatch : : Equals ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' e ' :
2018-06-14 06:08:14 +08:00
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . SetFile (
2018-11-02 05:05:36 +08:00
option_arg , FileSpec : : Style : : native ) ;
2017-02-20 19:35:33 +08:00
match_info . SetNameMatchType ( NameMatch : : EndsWith ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' s ' :
2018-06-14 06:08:14 +08:00
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . SetFile (
2018-11-02 05:05:36 +08:00
option_arg , FileSpec : : Style : : native ) ;
2017-02-20 19:35:33 +08:00
match_info . SetNameMatchType ( NameMatch : : StartsWith ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' c ' :
2018-06-14 06:08:14 +08:00
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . SetFile (
2018-11-02 05:05:36 +08:00
option_arg , FileSpec : : Style : : native ) ;
2017-02-20 19:35:33 +08:00
match_info . SetNameMatchType ( NameMatch : : Contains ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' r ' :
2018-06-14 06:08:14 +08:00
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . SetFile (
2018-11-02 05:05:36 +08:00
option_arg , FileSpec : : Style : : native ) ;
2017-02-20 19:35:33 +08:00
match_info . SetNameMatchType ( NameMatch : : RegularExpression ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' A ' :
show_args = true ;
break ;
case ' v ' :
verbose = true ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized option '%c' " ,
short_option ) ;
break ;
}
return error ;
}
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
match_info . Clear ( ) ;
show_args = false ;
verbose = false ;
}
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
2016-09-23 05:06:13 +08:00
return llvm : : makeArrayRef ( g_platform_process_list_options ) ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
}
2016-09-07 04:57:50 +08:00
// Instance variables to hold the values for command options.
ProcessInstanceInfoMatch match_info ;
bool show_args ;
bool verbose ;
} ;
CommandOptions m_options ;
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
} ;
2011-04-01 08:29:43 +08:00
//----------------------------------------------------------------------
// "platform process info"
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformProcessInfo : public CommandObjectParsed {
2011-04-01 08:29:43 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformProcessInfo ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " platform process info " ,
" Get detailed information for one or more process by process ID. " ,
" platform process info <pid> [<pid> <pid> ...] " , 0 ) {
CommandArgumentEntry arg ;
CommandArgumentData pid_args ;
// Define the first (and only) variant of this arg.
pid_args . arg_type = eArgTypePid ;
pid_args . arg_repetition = eArgRepeatStar ;
// There is only one variant this argument could be; put it into the
// argument entry.
arg . push_back ( pid_args ) ;
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
}
~ CommandObjectPlatformProcessInfo ( ) override = default ;
2016-02-23 03:02:01 +08:00
2013-08-27 07:57:52 +08:00
protected :
2016-09-07 04:57:50 +08:00
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
PlatformSP platform_sp ;
if ( target ) {
platform_sp = target - > GetPlatform ( ) ;
}
if ( ! platform_sp ) {
platform_sp =
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ;
}
if ( platform_sp ) {
const size_t argc = args . GetArgumentCount ( ) ;
if ( argc > 0 ) {
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
if ( platform_sp - > IsConnected ( ) ) {
Stream & ostrm = result . GetOutputStream ( ) ;
2016-10-06 07:40:23 +08:00
for ( auto & entry : args . entries ( ) ) {
lldb : : pid_t pid ;
if ( entry . ref . getAsInteger ( 0 , pid ) ) {
result . AppendErrorWithFormat ( " invalid process ID argument '%s' " ,
entry . ref . str ( ) . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
break ;
} else {
2016-09-07 04:57:50 +08:00
ProcessInstanceInfo proc_info ;
if ( platform_sp - > GetProcessInfo ( pid , proc_info ) ) {
ostrm . Printf ( " Process information for process % " PRIu64 " : \n " ,
pid ) ;
proc_info . Dump ( ostrm , platform_sp . get ( ) ) ;
} else {
ostrm . Printf ( " error: no process information is available for "
" process % " PRIu64 " \n " ,
pid ) ;
}
ostrm . EOL ( ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
}
} else {
// Not connected...
result . AppendErrorWithFormat (
" not connected to '%s' " ,
platform_sp - > GetPluginName ( ) . GetCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
// No args
result . AppendError ( " one or more process id(s) must be specified " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
} else {
result . AppendError ( " no platform is currently selected " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2013-08-27 07:57:52 +08:00
} ;
2018-09-27 02:50:19 +08:00
static constexpr OptionDefinition g_platform_process_attach_options [ ] = {
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format off
2018-09-27 02:50:19 +08:00
{ LLDB_OPT_SET_ALL , false , " plugin " , ' P ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypePlugin , " Name of the process plugin you want to use. " } ,
{ LLDB_OPT_SET_1 , false , " pid " , ' p ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypePid , " The process ID of an existing process to attach to. " } ,
{ LLDB_OPT_SET_2 , false , " name " , ' n ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeProcessName , " The name of the process to attach to. " } ,
{ LLDB_OPT_SET_2 , false , " waitfor " , ' w ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Wait for the process with <process-name> to launch. " } ,
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format on
} ;
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformProcessAttach : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
class CommandOptions : public Options {
public :
CommandOptions ( ) : Options ( ) {
// Keep default values of all options in one place: OptionParsingStarting
// ()
OptionParsingStarting ( nullptr ) ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
~ CommandOptions ( ) override = default ;
2017-05-12 12:51:55 +08:00
Status SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_arg ,
ExecutionContext * execution_context ) override {
Status error ;
2016-09-07 04:57:50 +08:00
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option ) {
case ' p ' : {
2016-11-13 00:56:47 +08:00
lldb : : pid_t pid = LLDB_INVALID_PROCESS_ID ;
if ( option_arg . getAsInteger ( 0 , pid ) ) {
error . SetErrorStringWithFormat ( " invalid process ID '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
} else {
attach_info . SetProcessID ( pid ) ;
}
} break ;
case ' P ' :
attach_info . SetProcessPluginName ( option_arg ) ;
break ;
case ' n ' :
2018-11-02 05:05:36 +08:00
attach_info . GetExecutableFile ( ) . SetFile ( option_arg ,
2018-06-14 06:08:14 +08:00
FileSpec : : Style : : native ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' w ' :
attach_info . SetWaitForLaunch ( true ) ;
break ;
default :
error . SetErrorStringWithFormat ( " invalid short option character '%c' " ,
short_option ) ;
break ;
}
return error ;
2011-04-01 08:29:43 +08:00
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
attach_info . Clear ( ) ;
}
2016-02-23 03:02:01 +08:00
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
2016-09-23 05:06:13 +08:00
return llvm : : makeArrayRef ( g_platform_process_attach_options ) ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
}
2016-09-07 04:57:50 +08:00
bool HandleOptionArgumentCompletion (
2018-07-14 02:28:14 +08:00
CompletionRequest & request , OptionElementVector & opt_element_vector ,
int opt_element_index , CommandInterpreter & interpreter ) override {
2016-09-07 04:57:50 +08:00
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...
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
if ( GetDefinitions ( ) [ opt_defs_index ] . short_option = = ' n ' ) {
2016-09-07 04:57:50 +08:00
// Are we in the name?
// Look to see if there is a -P argument provided, and if so use that
2018-05-01 00:49:04 +08:00
// plugin, otherwise use the default plugin.
2016-09-07 04:57:50 +08:00
const char * partial_name = nullptr ;
2018-07-14 02:28:14 +08:00
partial_name = request . GetParsedLine ( ) . GetArgumentAtIndex ( opt_arg_pos ) ;
2016-09-07 04:57:50 +08:00
PlatformSP platform_sp ( interpreter . GetPlatform ( true ) ) ;
if ( platform_sp ) {
ProcessInstanceInfoList process_infos ;
ProcessInstanceInfoMatch match_info ;
if ( partial_name ) {
match_info . GetProcessInfo ( ) . GetExecutableFile ( ) . SetFile (
2018-11-02 05:05:36 +08:00
partial_name , FileSpec : : Style : : native ) ;
2017-02-20 19:35:33 +08:00
match_info . SetNameMatchType ( NameMatch : : StartsWith ) ;
2016-09-07 04:57:50 +08:00
}
platform_sp - > FindProcesses ( match_info , process_infos ) ;
const uint32_t num_matches = process_infos . GetSize ( ) ;
if ( num_matches > 0 ) {
for ( uint32_t i = 0 ; i < num_matches ; + + i ) {
2018-07-28 02:42:46 +08:00
request . AddCompletion ( llvm : : StringRef (
2016-09-07 04:57:50 +08:00
process_infos . GetProcessNameAtIndex ( i ) ,
2018-07-28 02:42:46 +08:00
process_infos . GetProcessNameLengthAtIndex ( i ) ) ) ;
2011-04-01 08:29:43 +08:00
}
2016-09-07 04:57:50 +08:00
}
2011-04-01 08:29:43 +08:00
}
2016-09-07 04:57:50 +08:00
}
return false ;
2011-04-01 08:29:43 +08:00
}
2016-09-07 04:57:50 +08:00
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
ProcessAttachInfo attach_info ;
} ;
CommandObjectPlatformProcessAttach ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " platform process attach " ,
" Attach to a process. " ,
" platform process attach <cmd-options> " ) ,
m_options ( ) { }
~ CommandObjectPlatformProcessAttach ( ) override = default ;
bool DoExecute ( Args & command , CommandReturnObject & result ) override {
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( platform_sp ) {
2017-05-12 12:51:55 +08:00
Status err ;
2016-09-07 04:57:50 +08:00
ProcessSP remote_process_sp = platform_sp - > Attach (
m_options . attach_info , m_interpreter . GetDebugger ( ) , nullptr , err ) ;
if ( err . Fail ( ) ) {
result . AppendError ( err . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
} else if ( ! remote_process_sp ) {
result . AppendError ( " could not attach: unknown reason " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
} else
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendError ( " no platform is currently selected " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
Options * GetOptions ( ) override { return & m_options ; }
2013-08-27 07:57:52 +08:00
protected :
2016-09-07 04:57:50 +08:00
CommandOptions m_options ;
2011-04-01 08:29:43 +08:00
} ;
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformProcess : public CommandObjectMultiword {
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
public :
2016-09-07 04:57:50 +08:00
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
CommandObjectPlatformProcess ( CommandInterpreter & interpreter )
: CommandObjectMultiword ( interpreter , " platform process " ,
" Commands to query, launch and attach to "
" processes on the current platform. " ,
" platform process [attach|launch|list] ... " ) {
LoadSubCommand (
" attach " ,
CommandObjectSP ( new CommandObjectPlatformProcessAttach ( interpreter ) ) ) ;
LoadSubCommand (
" launch " ,
CommandObjectSP ( new CommandObjectPlatformProcessLaunch ( interpreter ) ) ) ;
LoadSubCommand ( " info " , CommandObjectSP ( new CommandObjectPlatformProcessInfo (
interpreter ) ) ) ;
LoadSubCommand ( " list " , CommandObjectSP ( new CommandObjectPlatformProcessList (
interpreter ) ) ) ;
}
~ CommandObjectPlatformProcess ( ) override = default ;
2016-02-23 03:02:01 +08:00
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
private :
2016-09-07 04:57:50 +08:00
//------------------------------------------------------------------
// For CommandObjectPlatform only
//------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN ( CommandObjectPlatformProcess ) ;
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
} ;
2011-03-19 09:12:21 +08:00
2013-08-27 07:57:52 +08:00
//----------------------------------------------------------------------
// "platform shell"
//----------------------------------------------------------------------
2018-09-27 02:50:19 +08:00
static constexpr OptionDefinition g_platform_shell_options [ ] = {
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format off
2018-09-27 02:50:19 +08:00
{ LLDB_OPT_SET_ALL , false , " timeout " , ' t ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeValue , " Seconds to wait for the remote host to finish running the command. " } ,
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
// clang-format on
} ;
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformShell : public CommandObjectRaw {
2012-04-14 09:42:46 +08:00
public :
2016-09-07 04:57:50 +08:00
class CommandOptions : public Options {
public :
2018-05-10 18:46:03 +08:00
CommandOptions ( ) : Options ( ) { }
2016-09-07 04:57:50 +08:00
~ CommandOptions ( ) override = default ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
2016-09-23 05:06:13 +08:00
return llvm : : makeArrayRef ( g_platform_shell_options ) ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
}
2016-09-07 04:57:50 +08:00
2017-05-12 12:51:55 +08:00
Status SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_arg ,
ExecutionContext * execution_context ) override {
Status error ;
2016-09-07 04:57:50 +08:00
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
const char short_option = ( char ) GetDefinitions ( ) [ option_idx ] . short_option ;
2016-09-07 04:57:50 +08:00
switch ( short_option ) {
2016-11-13 00:56:47 +08:00
case ' t ' :
2018-05-10 18:46:03 +08:00
uint32_t timeout_sec ;
if ( option_arg . getAsInteger ( 10 , timeout_sec ) )
2016-09-07 04:57:50 +08:00
error . SetErrorStringWithFormat (
2016-11-13 00:56:47 +08:00
" could not convert \" %s \" to a numeric value. " ,
option_arg . str ( ) . c_str ( ) ) ;
2018-05-10 18:46:03 +08:00
else
timeout = std : : chrono : : seconds ( timeout_sec ) ;
2016-09-07 04:57:50 +08:00
break ;
default :
error . SetErrorStringWithFormat ( " invalid short option character '%c' " ,
short_option ) ;
break ;
}
return error ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
void OptionParsingStarting ( ExecutionContext * execution_context ) override { }
2016-02-23 03:02:01 +08:00
2018-05-10 18:46:03 +08:00
Timeout < std : : micro > timeout = std : : chrono : : seconds ( 10 ) ;
2016-09-07 04:57:50 +08:00
} ;
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
CommandObjectPlatformShell ( CommandInterpreter & interpreter )
: CommandObjectRaw ( interpreter , " platform shell " ,
" Run a shell command on the current platform. " ,
" platform shell <shell-command> " , 0 ) ,
m_options ( ) { }
~ CommandObjectPlatformShell ( ) override = default ;
Options * GetOptions ( ) override { return & m_options ; }
2018-07-13 06:28:52 +08:00
bool DoExecute ( llvm : : StringRef raw_command_line ,
2016-09-07 04:57:50 +08:00
CommandReturnObject & result ) override {
ExecutionContext exe_ctx = GetCommandInterpreter ( ) . GetExecutionContext ( ) ;
m_options . NotifyOptionParsingStarting ( & exe_ctx ) ;
// Print out an usage syntax on an empty command line.
2018-07-13 06:28:52 +08:00
if ( raw_command_line . empty ( ) ) {
2016-11-15 08:45:18 +08:00
result . GetOutputStream ( ) . Printf ( " %s \n " , this - > GetSyntax ( ) . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
return true ;
2013-09-10 06:35:18 +08:00
}
2013-08-27 07:57:52 +08:00
2018-07-11 04:17:38 +08:00
OptionsWithRaw args ( raw_command_line ) ;
const char * expr = args . GetRawPart ( ) . c_str ( ) ;
2016-09-07 04:57:50 +08:00
2018-07-11 04:17:38 +08:00
if ( args . HasArgs ( ) )
if ( ! ParseOptions ( args . GetArgs ( ) , result ) )
return false ;
2016-09-07 04:57:50 +08:00
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
if ( platform_sp ) {
FileSpec working_dir { } ;
std : : string output ;
int status = - 1 ;
int signo = - 1 ;
error = ( platform_sp - > RunShellCommand ( expr , working_dir , & status , & signo ,
& output , m_options . timeout ) ) ;
if ( ! output . empty ( ) )
2016-11-03 04:34:10 +08:00
result . GetOutputStream ( ) . PutCString ( output ) ;
2016-09-07 04:57:50 +08:00
if ( status > 0 ) {
if ( signo > 0 ) {
const char * signo_cstr = Host : : GetSignalAsCString ( signo ) ;
if ( signo_cstr )
result . GetOutputStream ( ) . Printf (
" error: command returned with status %i and signal %s \n " ,
status , signo_cstr ) ;
else
result . GetOutputStream ( ) . Printf (
" error: command returned with status %i and signal %i \n " ,
status , signo ) ;
} else
result . GetOutputStream ( ) . Printf (
" error: command returned with status %i \n " , status ) ;
}
} else {
result . GetOutputStream ( ) . Printf (
" error: cannot run remote shell commands without a platform \n " ) ;
error . SetErrorString (
" error: cannot run remote shell commands without a platform " ) ;
}
if ( error . Fail ( ) ) {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
} else {
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
2012-04-14 09:42:46 +08:00
}
2016-09-07 04:57:50 +08:00
return true ;
}
2016-02-23 03:02:01 +08:00
2016-09-07 04:57:50 +08:00
CommandOptions m_options ;
2013-08-27 07:57:52 +08:00
} ;
//----------------------------------------------------------------------
// "platform install" - install a target to a remote end
//----------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
class CommandObjectPlatformInstall : public CommandObjectParsed {
2013-08-27 07:57:52 +08:00
public :
2016-09-07 04:57:50 +08:00
CommandObjectPlatformInstall ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " platform target-install " ,
" Install a target (bundle or executable file) to the remote end. " ,
" platform target-install <local-thing> <remote-sandbox> " , 0 ) { }
~ CommandObjectPlatformInstall ( ) override = default ;
bool DoExecute ( Args & args , CommandReturnObject & result ) override {
if ( args . GetArgumentCount ( ) ! = 2 ) {
result . AppendError ( " platform target-install takes two arguments " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
// TODO: move the bulk of this code over to the platform itself
2018-11-02 05:05:36 +08:00
FileSpec src ( args . GetArgumentAtIndex ( 0 ) ) ;
FileSystem : : Instance ( ) . Resolve ( src ) ;
FileSpec dst ( args . GetArgumentAtIndex ( 1 ) ) ;
2018-11-02 01:09:25 +08:00
if ( ! FileSystem : : Instance ( ) . Exists ( src ) ) {
2016-09-07 04:57:50 +08:00
result . AppendError ( " source location does not exist or is not accessible " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
PlatformSP platform_sp (
m_interpreter . GetDebugger ( ) . GetPlatformList ( ) . GetSelectedPlatform ( ) ) ;
if ( ! platform_sp ) {
result . AppendError ( " no platform currently selected " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-27 07:57:52 +08:00
}
2016-02-23 03:02:01 +08:00
2017-05-12 12:51:55 +08:00
Status error = platform_sp - > Install ( src , dst ) ;
2016-09-07 04:57:50 +08:00
if ( error . Success ( ) ) {
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
} else {
result . AppendErrorWithFormat ( " install failed: %s " , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2013-08-27 07:57:52 +08:00
}
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
}
2012-04-14 09:42:46 +08:00
} ;
2016-07-15 06:03:10 +08:00
CommandObjectPlatform : : CommandObjectPlatform ( CommandInterpreter & interpreter )
2016-09-07 04:57:50 +08:00
: CommandObjectMultiword (
interpreter , " platform " , " Commands to manage and create platforms. " ,
" platform [connect|disconnect|info|list|status|select] ... " ) {
LoadSubCommand ( " select " ,
CommandObjectSP ( new CommandObjectPlatformSelect ( interpreter ) ) ) ;
LoadSubCommand ( " list " ,
CommandObjectSP ( new CommandObjectPlatformList ( interpreter ) ) ) ;
LoadSubCommand ( " status " ,
CommandObjectSP ( new CommandObjectPlatformStatus ( interpreter ) ) ) ;
LoadSubCommand ( " connect " , CommandObjectSP (
new CommandObjectPlatformConnect ( interpreter ) ) ) ;
LoadSubCommand (
" disconnect " ,
CommandObjectSP ( new CommandObjectPlatformDisconnect ( interpreter ) ) ) ;
LoadSubCommand ( " settings " , CommandObjectSP ( new CommandObjectPlatformSettings (
interpreter ) ) ) ;
LoadSubCommand ( " mkdir " ,
CommandObjectSP ( new CommandObjectPlatformMkDir ( interpreter ) ) ) ;
LoadSubCommand ( " file " ,
CommandObjectSP ( new CommandObjectPlatformFile ( interpreter ) ) ) ;
LoadSubCommand ( " get-file " , CommandObjectSP ( new CommandObjectPlatformGetFile (
interpreter ) ) ) ;
LoadSubCommand ( " get-size " , CommandObjectSP ( new CommandObjectPlatformGetSize (
interpreter ) ) ) ;
LoadSubCommand ( " put-file " , CommandObjectSP ( new CommandObjectPlatformPutFile (
interpreter ) ) ) ;
LoadSubCommand ( " process " , CommandObjectSP (
new CommandObjectPlatformProcess ( interpreter ) ) ) ;
LoadSubCommand ( " shell " ,
CommandObjectSP ( new CommandObjectPlatformShell ( interpreter ) ) ) ;
LoadSubCommand (
" target-install " ,
CommandObjectSP ( new CommandObjectPlatformInstall ( interpreter ) ) ) ;
2011-03-19 09:12:21 +08:00
}
2016-02-23 03:02:01 +08:00
CommandObjectPlatform : : ~ CommandObjectPlatform ( ) = default ;