1 //===-- CommandObjectPlatform.cpp -----------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectPlatform.h"
10 #include "CommandOptionsProcessAttach.h"
11 #include "CommandOptionsProcessLaunch.h"
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/PluginManager.h"
15 #include "lldb/Host/OptionParser.h"
16 #include "lldb/Interpreter/CommandInterpreter.h"
17 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
18 #include "lldb/Interpreter/CommandOptionValidators.h"
19 #include "lldb/Interpreter/CommandReturnObject.h"
20 #include "lldb/Interpreter/OptionGroupFile.h"
21 #include "lldb/Interpreter/OptionGroupPlatform.h"
22 #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
23 #include "lldb/Target/ExecutionContext.h"
24 #include "lldb/Target/Platform.h"
25 #include "lldb/Target/Process.h"
26 #include "lldb/Utility/Args.h"
27 #include "lldb/Utility/ScriptedMetadata.h"
28 #include "lldb/Utility/State.h"
30 #include "llvm/ADT/SmallString.h"
33 using namespace lldb_private
;
35 static mode_t
ParsePermissionString(const char *) = delete;
37 static mode_t
ParsePermissionString(llvm::StringRef permissions
) {
38 if (permissions
.size() != 9)
40 bool user_r
, user_w
, user_x
, group_r
, group_w
, group_x
, world_r
, world_w
,
43 user_r
= (permissions
[0] == 'r');
44 user_w
= (permissions
[1] == 'w');
45 user_x
= (permissions
[2] == 'x');
47 group_r
= (permissions
[3] == 'r');
48 group_w
= (permissions
[4] == 'w');
49 group_x
= (permissions
[5] == 'x');
51 world_r
= (permissions
[6] == 'r');
52 world_w
= (permissions
[7] == 'w');
53 world_x
= (permissions
[8] == 'x');
55 mode_t user
, group
, world
;
56 user
= (user_r
? 4 : 0) | (user_w
? 2 : 0) | (user_x
? 1 : 0);
57 group
= (group_r
? 4 : 0) | (group_w
? 2 : 0) | (group_x
? 1 : 0);
58 world
= (world_r
? 4 : 0) | (world_w
? 2 : 0) | (world_x
? 1 : 0);
60 return user
| group
| world
;
63 #define LLDB_OPTIONS_permissions
64 #include "CommandOptions.inc"
66 class OptionPermissions
: public OptionGroup
{
68 OptionPermissions() = default;
70 ~OptionPermissions() override
= default;
73 SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
74 ExecutionContext
*execution_context
) override
{
76 char short_option
= (char)GetDefinitions()[option_idx
].short_option
;
77 switch (short_option
) {
79 if (option_arg
.getAsInteger(8, m_permissions
)) {
81 error
.SetErrorStringWithFormat("invalid value for permissions: %s",
82 option_arg
.str().c_str());
87 mode_t perms
= ParsePermissionString(option_arg
);
88 if (perms
== (mode_t
)-1)
89 error
.SetErrorStringWithFormat("invalid value for permissions: %s",
90 option_arg
.str().c_str());
92 m_permissions
= perms
;
95 m_permissions
|= lldb::eFilePermissionsUserRead
;
98 m_permissions
|= lldb::eFilePermissionsUserWrite
;
101 m_permissions
|= lldb::eFilePermissionsUserExecute
;
104 m_permissions
|= lldb::eFilePermissionsGroupRead
;
107 m_permissions
|= lldb::eFilePermissionsGroupWrite
;
110 m_permissions
|= lldb::eFilePermissionsGroupExecute
;
113 m_permissions
|= lldb::eFilePermissionsWorldRead
;
116 m_permissions
|= lldb::eFilePermissionsWorldWrite
;
119 m_permissions
|= lldb::eFilePermissionsWorldExecute
;
122 llvm_unreachable("Unimplemented option");
128 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
132 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
133 return llvm::ArrayRef(g_permissions_options
);
136 // Instance variables to hold the values for command options.
138 uint32_t m_permissions
;
141 OptionPermissions(const OptionPermissions
&) = delete;
142 const OptionPermissions
&operator=(const OptionPermissions
&) = delete;
145 // "platform select <platform-name>"
146 class CommandObjectPlatformSelect
: public CommandObjectParsed
{
148 CommandObjectPlatformSelect(CommandInterpreter
&interpreter
)
149 : CommandObjectParsed(interpreter
, "platform select",
150 "Create a platform if needed and select it as the "
152 "platform select <platform-name>", 0),
154 false) // Don't include the "--platform" option by passing false
156 m_option_group
.Append(&m_platform_options
, LLDB_OPT_SET_ALL
, 1);
157 m_option_group
.Finalize();
158 CommandArgumentData platform_arg
{eArgTypePlatform
, eArgRepeatPlain
};
159 m_arguments
.push_back({platform_arg
});
162 ~CommandObjectPlatformSelect() override
= default;
164 void HandleCompletion(CompletionRequest
&request
) override
{
165 lldb_private::CommandCompletions::PlatformPluginNames(
166 GetCommandInterpreter(), request
, nullptr);
169 Options
*GetOptions() override
{ return &m_option_group
; }
172 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
173 if (args
.GetArgumentCount() == 1) {
174 const char *platform_name
= args
.GetArgumentAtIndex(0);
175 if (platform_name
&& platform_name
[0]) {
176 const bool select
= true;
177 m_platform_options
.SetPlatformName(platform_name
);
179 ArchSpec platform_arch
;
180 PlatformSP
platform_sp(m_platform_options
.CreatePlatformWithOptions(
181 m_interpreter
, ArchSpec(), select
, error
, platform_arch
));
183 GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp
);
185 platform_sp
->GetStatus(result
.GetOutputStream());
186 result
.SetStatus(eReturnStatusSuccessFinishResult
);
188 result
.AppendError(error
.AsCString());
191 result
.AppendError("invalid platform name");
195 "platform create takes a platform name as an argument\n");
199 OptionGroupOptions m_option_group
;
200 OptionGroupPlatform m_platform_options
;
204 class CommandObjectPlatformList
: public CommandObjectParsed
{
206 CommandObjectPlatformList(CommandInterpreter
&interpreter
)
207 : CommandObjectParsed(interpreter
, "platform list",
208 "List all platforms that are available.", nullptr,
211 ~CommandObjectPlatformList() override
= default;
214 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
215 Stream
&ostrm
= result
.GetOutputStream();
216 ostrm
.Printf("Available platforms:\n");
218 PlatformSP
host_platform_sp(Platform::GetHostPlatform());
219 ostrm
.Format("{0}: {1}\n", host_platform_sp
->GetPluginName(),
220 host_platform_sp
->GetDescription());
223 for (idx
= 0; true; ++idx
) {
224 llvm::StringRef plugin_name
=
225 PluginManager::GetPlatformPluginNameAtIndex(idx
);
226 if (plugin_name
.empty())
228 llvm::StringRef plugin_desc
=
229 PluginManager::GetPlatformPluginDescriptionAtIndex(idx
);
230 ostrm
.Format("{0}: {1}\n", plugin_name
, plugin_desc
);
234 result
.AppendError("no platforms are available\n");
236 result
.SetStatus(eReturnStatusSuccessFinishResult
);
241 class CommandObjectPlatformStatus
: public CommandObjectParsed
{
243 CommandObjectPlatformStatus(CommandInterpreter
&interpreter
)
244 : CommandObjectParsed(interpreter
, "platform status",
245 "Display status for the current platform.", nullptr,
248 ~CommandObjectPlatformStatus() override
= default;
251 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
252 Stream
&ostrm
= result
.GetOutputStream();
254 Target
*target
= GetDebugger().GetSelectedTarget().get();
255 PlatformSP platform_sp
;
257 platform_sp
= target
->GetPlatform();
260 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
263 platform_sp
->GetStatus(ostrm
);
264 result
.SetStatus(eReturnStatusSuccessFinishResult
);
266 result
.AppendError("no platform is currently selected\n");
271 // "platform connect <connect-url>"
272 class CommandObjectPlatformConnect
: public CommandObjectParsed
{
274 CommandObjectPlatformConnect(CommandInterpreter
&interpreter
)
275 : CommandObjectParsed(
276 interpreter
, "platform connect",
277 "Select the current platform by providing a connection URL.",
278 "platform connect <connect-url>", 0) {
279 CommandArgumentData platform_arg
{eArgTypeConnectURL
, eArgRepeatPlain
};
280 m_arguments
.push_back({platform_arg
});
283 ~CommandObjectPlatformConnect() override
= default;
286 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
287 Stream
&ostrm
= result
.GetOutputStream();
289 PlatformSP
platform_sp(
290 GetDebugger().GetPlatformList().GetSelectedPlatform());
292 Status
error(platform_sp
->ConnectRemote(args
));
293 if (error
.Success()) {
294 platform_sp
->GetStatus(ostrm
);
295 result
.SetStatus(eReturnStatusSuccessFinishResult
);
297 platform_sp
->ConnectToWaitingProcesses(GetDebugger(), error
);
299 result
.AppendError(error
.AsCString());
302 result
.AppendErrorWithFormat("%s\n", error
.AsCString());
305 result
.AppendError("no platform is currently selected\n");
309 Options
*GetOptions() override
{
310 PlatformSP
platform_sp(
311 GetDebugger().GetPlatformList().GetSelectedPlatform());
312 OptionGroupOptions
*m_platform_options
= nullptr;
314 m_platform_options
= platform_sp
->GetConnectionOptions(m_interpreter
);
315 if (m_platform_options
!= nullptr && !m_platform_options
->m_did_finalize
)
316 m_platform_options
->Finalize();
318 return m_platform_options
;
322 // "platform disconnect"
323 class CommandObjectPlatformDisconnect
: public CommandObjectParsed
{
325 CommandObjectPlatformDisconnect(CommandInterpreter
&interpreter
)
326 : CommandObjectParsed(interpreter
, "platform disconnect",
327 "Disconnect from the current platform.",
328 "platform disconnect", 0) {}
330 ~CommandObjectPlatformDisconnect() override
= default;
333 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
334 PlatformSP
platform_sp(
335 GetDebugger().GetPlatformList().GetSelectedPlatform());
337 if (args
.GetArgumentCount() == 0) {
340 if (platform_sp
->IsConnected()) {
341 // Cache the instance name if there is one since we are about to
342 // disconnect and the name might go with it.
343 const char *hostname_cstr
= platform_sp
->GetHostname();
344 std::string hostname
;
346 hostname
.assign(hostname_cstr
);
348 error
= platform_sp
->DisconnectRemote();
349 if (error
.Success()) {
350 Stream
&ostrm
= result
.GetOutputStream();
351 if (hostname
.empty())
352 ostrm
.Format("Disconnected from \"{0}\"\n",
353 platform_sp
->GetPluginName());
355 ostrm
.Printf("Disconnected from \"%s\"\n", hostname
.c_str());
356 result
.SetStatus(eReturnStatusSuccessFinishResult
);
358 result
.AppendErrorWithFormat("%s", error
.AsCString());
362 result
.AppendErrorWithFormatv("not connected to '{0}'",
363 platform_sp
->GetPluginName());
368 "\"platform disconnect\" doesn't take any arguments");
371 result
.AppendError("no platform is currently selected");
376 // "platform settings"
377 class CommandObjectPlatformSettings
: public CommandObjectParsed
{
379 CommandObjectPlatformSettings(CommandInterpreter
&interpreter
)
380 : CommandObjectParsed(interpreter
, "platform settings",
381 "Set settings for the current target's platform.",
382 "platform settings", 0),
383 m_option_working_dir(LLDB_OPT_SET_1
, false, "working-dir", 'w',
384 lldb::eRemoteDiskDirectoryCompletion
, eArgTypePath
,
385 "The working directory for the platform.") {
386 m_options
.Append(&m_option_working_dir
, LLDB_OPT_SET_ALL
, LLDB_OPT_SET_1
);
389 ~CommandObjectPlatformSettings() override
= default;
392 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
393 PlatformSP
platform_sp(
394 GetDebugger().GetPlatformList().GetSelectedPlatform());
396 if (m_option_working_dir
.GetOptionValue().OptionWasSet())
397 platform_sp
->SetWorkingDirectory(
398 m_option_working_dir
.GetOptionValue().GetCurrentValue());
400 result
.AppendError("no platform is currently selected");
404 Options
*GetOptions() override
{
405 if (!m_options
.DidFinalize())
406 m_options
.Finalize();
410 OptionGroupOptions m_options
;
411 OptionGroupFile m_option_working_dir
;
415 class CommandObjectPlatformMkDir
: public CommandObjectParsed
{
417 CommandObjectPlatformMkDir(CommandInterpreter
&interpreter
)
418 : CommandObjectParsed(interpreter
, "platform mkdir",
419 "Make a new directory on the remote end.", nullptr,
421 CommandArgumentData thread_arg
{eArgTypePath
, eArgRepeatPlain
};
422 m_arguments
.push_back({thread_arg
});
425 ~CommandObjectPlatformMkDir() override
= default;
427 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
428 PlatformSP
platform_sp(
429 GetDebugger().GetPlatformList().GetSelectedPlatform());
431 std::string cmd_line
;
432 args
.GetCommandString(cmd_line
);
434 const OptionPermissions
*options_permissions
=
435 (const OptionPermissions
*)m_options
.GetGroupWithOption('r');
436 if (options_permissions
)
437 mode
= options_permissions
->m_permissions
;
439 mode
= lldb::eFilePermissionsUserRWX
| lldb::eFilePermissionsGroupRWX
|
440 lldb::eFilePermissionsWorldRX
;
441 Status error
= platform_sp
->MakeDirectory(FileSpec(cmd_line
), mode
);
442 if (error
.Success()) {
443 result
.SetStatus(eReturnStatusSuccessFinishResult
);
445 result
.AppendError(error
.AsCString());
448 result
.AppendError("no platform currently selected\n");
452 Options
*GetOptions() override
{
453 if (!m_options
.DidFinalize()) {
454 m_options
.Append(&m_option_permissions
);
455 m_options
.Finalize();
460 OptionPermissions m_option_permissions
;
461 OptionGroupOptions m_options
;
465 class CommandObjectPlatformFOpen
: public CommandObjectParsed
{
467 CommandObjectPlatformFOpen(CommandInterpreter
&interpreter
)
468 : CommandObjectParsed(interpreter
, "platform file open",
469 "Open a file on the remote end.", nullptr, 0) {
470 CommandArgumentData path_arg
{eArgTypePath
, eArgRepeatPlain
};
471 m_arguments
.push_back({path_arg
});
474 ~CommandObjectPlatformFOpen() override
= default;
477 HandleArgumentCompletion(CompletionRequest
&request
,
478 OptionElementVector
&opt_element_vector
) override
{
479 if (request
.GetCursorIndex() == 0)
480 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
481 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
485 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
486 PlatformSP
platform_sp(
487 GetDebugger().GetPlatformList().GetSelectedPlatform());
490 std::string cmd_line
;
491 args
.GetCommandString(cmd_line
);
493 const OptionPermissions
*options_permissions
=
494 (const OptionPermissions
*)m_options
.GetGroupWithOption('r');
495 if (options_permissions
)
496 perms
= options_permissions
->m_permissions
;
498 perms
= lldb::eFilePermissionsUserRW
| lldb::eFilePermissionsGroupRW
|
499 lldb::eFilePermissionsWorldRead
;
500 lldb::user_id_t fd
= platform_sp
->OpenFile(
502 File::eOpenOptionReadWrite
| File::eOpenOptionCanCreate
,
504 if (error
.Success()) {
505 result
.AppendMessageWithFormat("File Descriptor = %" PRIu64
"\n", fd
);
506 result
.SetStatus(eReturnStatusSuccessFinishResult
);
508 result
.AppendError(error
.AsCString());
511 result
.AppendError("no platform currently selected\n");
515 Options
*GetOptions() override
{
516 if (!m_options
.DidFinalize()) {
517 m_options
.Append(&m_option_permissions
);
518 m_options
.Finalize();
523 OptionPermissions m_option_permissions
;
524 OptionGroupOptions m_options
;
528 class CommandObjectPlatformFClose
: public CommandObjectParsed
{
530 CommandObjectPlatformFClose(CommandInterpreter
&interpreter
)
531 : CommandObjectParsed(interpreter
, "platform file close",
532 "Close a file on the remote end.", nullptr, 0) {
533 CommandArgumentData path_arg
{eArgTypeUnsignedInteger
, eArgRepeatPlain
};
534 m_arguments
.push_back({path_arg
});
537 ~CommandObjectPlatformFClose() override
= default;
539 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
540 PlatformSP
platform_sp(
541 GetDebugger().GetPlatformList().GetSelectedPlatform());
543 std::string cmd_line
;
544 args
.GetCommandString(cmd_line
);
546 if (!llvm::to_integer(cmd_line
, fd
)) {
547 result
.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
552 bool success
= platform_sp
->CloseFile(fd
, error
);
554 result
.AppendMessageWithFormat("file %" PRIu64
" closed.\n", fd
);
555 result
.SetStatus(eReturnStatusSuccessFinishResult
);
557 result
.AppendError(error
.AsCString());
560 result
.AppendError("no platform currently selected\n");
567 #define LLDB_OPTIONS_platform_fread
568 #include "CommandOptions.inc"
570 class CommandObjectPlatformFRead
: public CommandObjectParsed
{
572 CommandObjectPlatformFRead(CommandInterpreter
&interpreter
)
573 : CommandObjectParsed(interpreter
, "platform file read",
574 "Read data from a file on the remote end.", nullptr,
576 CommandArgumentData path_arg
{eArgTypeUnsignedInteger
, eArgRepeatPlain
};
577 m_arguments
.push_back({path_arg
});
580 ~CommandObjectPlatformFRead() override
= default;
582 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
583 PlatformSP
platform_sp(
584 GetDebugger().GetPlatformList().GetSelectedPlatform());
586 std::string cmd_line
;
587 args
.GetCommandString(cmd_line
);
589 if (!llvm::to_integer(cmd_line
, fd
)) {
590 result
.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
594 std::string
buffer(m_options
.m_count
, 0);
596 uint64_t retcode
= platform_sp
->ReadFile(
597 fd
, m_options
.m_offset
, &buffer
[0], m_options
.m_count
, error
);
598 if (retcode
!= UINT64_MAX
) {
599 result
.AppendMessageWithFormat("Return = %" PRIu64
"\n", retcode
);
600 result
.AppendMessageWithFormat("Data = \"%s\"\n", buffer
.c_str());
601 result
.SetStatus(eReturnStatusSuccessFinishResult
);
603 result
.AppendError(error
.AsCString());
606 result
.AppendError("no platform currently selected\n");
610 Options
*GetOptions() override
{ return &m_options
; }
613 class CommandOptions
: public Options
{
615 CommandOptions() = default;
617 ~CommandOptions() override
= default;
619 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
620 ExecutionContext
*execution_context
) override
{
622 char short_option
= (char)m_getopt_table
[option_idx
].val
;
624 switch (short_option
) {
626 if (option_arg
.getAsInteger(0, m_offset
))
627 error
.SetErrorStringWithFormat("invalid offset: '%s'",
628 option_arg
.str().c_str());
631 if (option_arg
.getAsInteger(0, m_count
))
632 error
.SetErrorStringWithFormat("invalid offset: '%s'",
633 option_arg
.str().c_str());
636 llvm_unreachable("Unimplemented option");
642 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
647 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
648 return llvm::ArrayRef(g_platform_fread_options
);
651 // Instance variables to hold the values for command options.
657 CommandOptions m_options
;
662 #define LLDB_OPTIONS_platform_fwrite
663 #include "CommandOptions.inc"
665 class CommandObjectPlatformFWrite
: public CommandObjectParsed
{
667 CommandObjectPlatformFWrite(CommandInterpreter
&interpreter
)
668 : CommandObjectParsed(interpreter
, "platform file write",
669 "Write data to a file on the remote end.", nullptr,
671 CommandArgumentData path_arg
{eArgTypeUnsignedInteger
, eArgRepeatPlain
};
672 m_arguments
.push_back({path_arg
});
675 ~CommandObjectPlatformFWrite() override
= default;
677 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
678 PlatformSP
platform_sp(
679 GetDebugger().GetPlatformList().GetSelectedPlatform());
681 std::string cmd_line
;
682 args
.GetCommandString(cmd_line
);
685 if (!llvm::to_integer(cmd_line
, fd
)) {
686 result
.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.",
691 platform_sp
->WriteFile(fd
, m_options
.m_offset
, &m_options
.m_data
[0],
692 m_options
.m_data
.size(), error
);
693 if (retcode
!= UINT64_MAX
) {
694 result
.AppendMessageWithFormat("Return = %" PRIu64
"\n", retcode
);
695 result
.SetStatus(eReturnStatusSuccessFinishResult
);
697 result
.AppendError(error
.AsCString());
700 result
.AppendError("no platform currently selected\n");
704 Options
*GetOptions() override
{ return &m_options
; }
707 class CommandOptions
: public Options
{
709 CommandOptions() = default;
711 ~CommandOptions() override
= default;
713 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
714 ExecutionContext
*execution_context
) override
{
716 char short_option
= (char)m_getopt_table
[option_idx
].val
;
718 switch (short_option
) {
720 if (option_arg
.getAsInteger(0, m_offset
))
721 error
.SetErrorStringWithFormat("invalid offset: '%s'",
722 option_arg
.str().c_str());
725 m_data
.assign(std::string(option_arg
));
728 llvm_unreachable("Unimplemented option");
734 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
739 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
740 return llvm::ArrayRef(g_platform_fwrite_options
);
743 // Instance variables to hold the values for command options.
749 CommandOptions m_options
;
752 class CommandObjectPlatformFile
: public CommandObjectMultiword
{
754 // Constructors and Destructors
755 CommandObjectPlatformFile(CommandInterpreter
&interpreter
)
756 : CommandObjectMultiword(
757 interpreter
, "platform file",
758 "Commands to access files on the current platform.",
759 "platform file [open|close|read|write] ...") {
761 "open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter
)));
763 "close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter
)));
765 "read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter
)));
767 "write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter
)));
770 ~CommandObjectPlatformFile() override
= default;
773 // For CommandObjectPlatform only
774 CommandObjectPlatformFile(const CommandObjectPlatformFile
&) = delete;
775 const CommandObjectPlatformFile
&
776 operator=(const CommandObjectPlatformFile
&) = delete;
779 // "platform get-file remote-file-path host-file-path"
780 class CommandObjectPlatformGetFile
: public CommandObjectParsed
{
782 CommandObjectPlatformGetFile(CommandInterpreter
&interpreter
)
783 : CommandObjectParsed(
784 interpreter
, "platform get-file",
785 "Transfer a file from the remote end to the local host.",
786 "platform get-file <remote-file-spec> <local-file-spec>", 0) {
790 (lldb) platform get-file /the/remote/file/path /the/local/file/path
792 Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");
794 CommandArgumentEntry arg1
, arg2
;
795 CommandArgumentData file_arg_remote
, file_arg_host
;
797 // Define the first (and only) variant of this arg.
798 file_arg_remote
.arg_type
= eArgTypeFilename
;
799 file_arg_remote
.arg_repetition
= eArgRepeatPlain
;
800 // There is only one variant this argument could be; put it into the
802 arg1
.push_back(file_arg_remote
);
804 // Define the second (and only) variant of this arg.
805 file_arg_host
.arg_type
= eArgTypeFilename
;
806 file_arg_host
.arg_repetition
= eArgRepeatPlain
;
807 // There is only one variant this argument could be; put it into the
809 arg2
.push_back(file_arg_host
);
811 // Push the data for the first and the second arguments into the
812 // m_arguments vector.
813 m_arguments
.push_back(arg1
);
814 m_arguments
.push_back(arg2
);
817 ~CommandObjectPlatformGetFile() override
= default;
820 HandleArgumentCompletion(CompletionRequest
&request
,
821 OptionElementVector
&opt_element_vector
) override
{
822 if (request
.GetCursorIndex() == 0)
823 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
824 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
826 else if (request
.GetCursorIndex() == 1)
827 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
828 GetCommandInterpreter(), lldb::eDiskFileCompletion
, request
, nullptr);
831 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
832 // If the number of arguments is incorrect, issue an error message.
833 if (args
.GetArgumentCount() != 2) {
834 result
.AppendError("required arguments missing; specify both the "
835 "source and destination file paths");
839 PlatformSP
platform_sp(
840 GetDebugger().GetPlatformList().GetSelectedPlatform());
842 const char *remote_file_path
= args
.GetArgumentAtIndex(0);
843 const char *local_file_path
= args
.GetArgumentAtIndex(1);
844 Status error
= platform_sp
->GetFile(FileSpec(remote_file_path
),
845 FileSpec(local_file_path
));
846 if (error
.Success()) {
847 result
.AppendMessageWithFormat(
848 "successfully get-file from %s (remote) to %s (host)\n",
849 remote_file_path
, local_file_path
);
850 result
.SetStatus(eReturnStatusSuccessFinishResult
);
852 result
.AppendMessageWithFormat("get-file failed: %s\n",
856 result
.AppendError("no platform currently selected\n");
861 // "platform get-size remote-file-path"
862 class CommandObjectPlatformGetSize
: public CommandObjectParsed
{
864 CommandObjectPlatformGetSize(CommandInterpreter
&interpreter
)
865 : CommandObjectParsed(interpreter
, "platform get-size",
866 "Get the file size from the remote end.",
867 "platform get-size <remote-file-spec>", 0) {
871 (lldb) platform get-size /the/remote/file/path
873 Get the file size from the remote end with path /the/remote/file/path.)");
875 CommandArgumentEntry arg1
;
876 CommandArgumentData file_arg_remote
;
878 // Define the first (and only) variant of this arg.
879 file_arg_remote
.arg_type
= eArgTypeFilename
;
880 file_arg_remote
.arg_repetition
= eArgRepeatPlain
;
881 // There is only one variant this argument could be; put it into the
883 arg1
.push_back(file_arg_remote
);
885 // Push the data for the first argument into the m_arguments vector.
886 m_arguments
.push_back(arg1
);
889 ~CommandObjectPlatformGetSize() override
= default;
892 HandleArgumentCompletion(CompletionRequest
&request
,
893 OptionElementVector
&opt_element_vector
) override
{
894 if (request
.GetCursorIndex() != 0)
897 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
898 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
902 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
903 // If the number of arguments is incorrect, issue an error message.
904 if (args
.GetArgumentCount() != 1) {
905 result
.AppendError("required argument missing; specify the source file "
906 "path as the only argument");
910 PlatformSP
platform_sp(
911 GetDebugger().GetPlatformList().GetSelectedPlatform());
913 std::string
remote_file_path(args
.GetArgumentAtIndex(0));
914 user_id_t size
= platform_sp
->GetFileSize(FileSpec(remote_file_path
));
915 if (size
!= UINT64_MAX
) {
916 result
.AppendMessageWithFormat("File size of %s (remote): %" PRIu64
918 remote_file_path
.c_str(), size
);
919 result
.SetStatus(eReturnStatusSuccessFinishResult
);
921 result
.AppendMessageWithFormat(
922 "Error getting file size of %s (remote)\n",
923 remote_file_path
.c_str());
926 result
.AppendError("no platform currently selected\n");
931 // "platform get-permissions remote-file-path"
932 class CommandObjectPlatformGetPermissions
: public CommandObjectParsed
{
934 CommandObjectPlatformGetPermissions(CommandInterpreter
&interpreter
)
935 : CommandObjectParsed(interpreter
, "platform get-permissions",
936 "Get the file permission bits from the remote end.",
937 "platform get-permissions <remote-file-spec>", 0) {
941 (lldb) platform get-permissions /the/remote/file/path
943 Get the file permissions from the remote end with path /the/remote/file/path.)");
945 CommandArgumentEntry arg1
;
946 CommandArgumentData file_arg_remote
;
948 // Define the first (and only) variant of this arg.
949 file_arg_remote
.arg_type
= eArgTypeFilename
;
950 file_arg_remote
.arg_repetition
= eArgRepeatPlain
;
951 // There is only one variant this argument could be; put it into the
953 arg1
.push_back(file_arg_remote
);
955 // Push the data for the first argument into the m_arguments vector.
956 m_arguments
.push_back(arg1
);
959 ~CommandObjectPlatformGetPermissions() override
= default;
962 HandleArgumentCompletion(CompletionRequest
&request
,
963 OptionElementVector
&opt_element_vector
) override
{
964 if (request
.GetCursorIndex() != 0)
967 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
968 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
972 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
973 // If the number of arguments is incorrect, issue an error message.
974 if (args
.GetArgumentCount() != 1) {
975 result
.AppendError("required argument missing; specify the source file "
976 "path as the only argument");
980 PlatformSP
platform_sp(
981 GetDebugger().GetPlatformList().GetSelectedPlatform());
983 std::string
remote_file_path(args
.GetArgumentAtIndex(0));
984 uint32_t permissions
;
985 Status error
= platform_sp
->GetFilePermissions(FileSpec(remote_file_path
),
987 if (error
.Success()) {
988 result
.AppendMessageWithFormat(
989 "File permissions of %s (remote): 0o%04" PRIo32
"\n",
990 remote_file_path
.c_str(), permissions
);
991 result
.SetStatus(eReturnStatusSuccessFinishResult
);
993 result
.AppendError(error
.AsCString());
995 result
.AppendError("no platform currently selected\n");
1000 // "platform file-exists remote-file-path"
1001 class CommandObjectPlatformFileExists
: public CommandObjectParsed
{
1003 CommandObjectPlatformFileExists(CommandInterpreter
&interpreter
)
1004 : CommandObjectParsed(interpreter
, "platform file-exists",
1005 "Check if the file exists on the remote end.",
1006 "platform file-exists <remote-file-spec>", 0) {
1010 (lldb) platform file-exists /the/remote/file/path
1012 Check if /the/remote/file/path exists on the remote end.)");
1014 CommandArgumentEntry arg1
;
1015 CommandArgumentData file_arg_remote
;
1017 // Define the first (and only) variant of this arg.
1018 file_arg_remote
.arg_type
= eArgTypeFilename
;
1019 file_arg_remote
.arg_repetition
= eArgRepeatPlain
;
1020 // There is only one variant this argument could be; put it into the
1022 arg1
.push_back(file_arg_remote
);
1024 // Push the data for the first argument into the m_arguments vector.
1025 m_arguments
.push_back(arg1
);
1028 ~CommandObjectPlatformFileExists() override
= default;
1031 HandleArgumentCompletion(CompletionRequest
&request
,
1032 OptionElementVector
&opt_element_vector
) override
{
1033 if (request
.GetCursorIndex() != 0)
1036 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1037 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
1041 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1042 // If the number of arguments is incorrect, issue an error message.
1043 if (args
.GetArgumentCount() != 1) {
1044 result
.AppendError("required argument missing; specify the source file "
1045 "path as the only argument");
1049 PlatformSP
platform_sp(
1050 GetDebugger().GetPlatformList().GetSelectedPlatform());
1052 std::string
remote_file_path(args
.GetArgumentAtIndex(0));
1053 bool exists
= platform_sp
->GetFileExists(FileSpec(remote_file_path
));
1054 result
.AppendMessageWithFormat(
1055 "File %s (remote) %s\n",
1056 remote_file_path
.c_str(), exists
? "exists" : "does not exist");
1057 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1059 result
.AppendError("no platform currently selected\n");
1064 // "platform put-file"
1065 class CommandObjectPlatformPutFile
: public CommandObjectParsed
{
1067 CommandObjectPlatformPutFile(CommandInterpreter
&interpreter
)
1068 : CommandObjectParsed(
1069 interpreter
, "platform put-file",
1070 "Transfer a file from this system to the remote end.",
1071 "platform put-file <source> [<destination>]", 0) {
1075 (lldb) platform put-file /source/foo.txt /destination/bar.txt
1077 (lldb) platform put-file /source/foo.txt
1079 Relative source file paths are resolved against lldb's local working directory.
1081 Omitting the destination places the file in the platform working directory.)");
1082 CommandArgumentData source_arg
{eArgTypePath
, eArgRepeatPlain
};
1083 CommandArgumentData path_arg
{eArgTypePath
, eArgRepeatOptional
};
1084 m_arguments
.push_back({source_arg
});
1085 m_arguments
.push_back({path_arg
});
1088 ~CommandObjectPlatformPutFile() override
= default;
1091 HandleArgumentCompletion(CompletionRequest
&request
,
1092 OptionElementVector
&opt_element_vector
) override
{
1093 if (request
.GetCursorIndex() == 0)
1094 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1095 GetCommandInterpreter(), lldb::eDiskFileCompletion
, request
, nullptr);
1096 else if (request
.GetCursorIndex() == 1)
1097 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1098 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
1102 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1103 const char *src
= args
.GetArgumentAtIndex(0);
1104 const char *dst
= args
.GetArgumentAtIndex(1);
1106 FileSpec
src_fs(src
);
1107 FileSystem::Instance().Resolve(src_fs
);
1108 FileSpec
dst_fs(dst
? dst
: src_fs
.GetFilename().GetCString());
1110 PlatformSP
platform_sp(
1111 GetDebugger().GetPlatformList().GetSelectedPlatform());
1113 Status
error(platform_sp
->PutFile(src_fs
, dst_fs
));
1114 if (error
.Success()) {
1115 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1117 result
.AppendError(error
.AsCString());
1120 result
.AppendError("no platform currently selected\n");
1125 // "platform process launch"
1126 class CommandObjectPlatformProcessLaunch
: public CommandObjectParsed
{
1128 CommandObjectPlatformProcessLaunch(CommandInterpreter
&interpreter
)
1129 : CommandObjectParsed(interpreter
, "platform process launch",
1130 "Launch a new process on a remote platform.",
1131 "platform process launch program",
1132 eCommandRequiresTarget
| eCommandTryTargetAPILock
),
1133 m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
1134 m_all_options
.Append(&m_options
);
1135 m_all_options
.Append(&m_class_options
, LLDB_OPT_SET_1
| LLDB_OPT_SET_2
,
1137 m_all_options
.Finalize();
1138 CommandArgumentData run_arg_arg
{eArgTypeRunArgs
, eArgRepeatStar
};
1139 m_arguments
.push_back({run_arg_arg
});
1142 ~CommandObjectPlatformProcessLaunch() override
= default;
1144 Options
*GetOptions() override
{ return &m_all_options
; }
1147 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1148 Target
*target
= GetDebugger().GetSelectedTarget().get();
1149 PlatformSP platform_sp
;
1151 platform_sp
= target
->GetPlatform();
1154 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
1159 const size_t argc
= args
.GetArgumentCount();
1160 Target
*target
= m_exe_ctx
.GetTargetPtr();
1161 Module
*exe_module
= target
->GetExecutableModulePointer();
1163 m_options
.launch_info
.GetExecutableFile() = exe_module
->GetFileSpec();
1164 llvm::SmallString
<128> exe_path
;
1165 m_options
.launch_info
.GetExecutableFile().GetPath(exe_path
);
1166 if (!exe_path
.empty())
1167 m_options
.launch_info
.GetArguments().AppendArgument(exe_path
);
1168 m_options
.launch_info
.GetArchitecture() = exe_module
->GetArchitecture();
1171 if (!m_class_options
.GetName().empty()) {
1172 m_options
.launch_info
.SetProcessPluginName("ScriptedProcess");
1173 ScriptedMetadataSP metadata_sp
= std::make_shared
<ScriptedMetadata
>(
1174 m_class_options
.GetName(), m_class_options
.GetStructuredData());
1175 m_options
.launch_info
.SetScriptedMetadata(metadata_sp
);
1176 target
->SetProcessLaunchInfo(m_options
.launch_info
);
1180 if (m_options
.launch_info
.GetExecutableFile()) {
1181 // We already have an executable file, so we will use this and all
1182 // arguments to this function are extra arguments
1183 m_options
.launch_info
.GetArguments().AppendArguments(args
);
1185 // We don't have any file yet, so the first argument is our
1186 // executable, and the rest are program arguments
1187 const bool first_arg_is_executable
= true;
1188 m_options
.launch_info
.SetArguments(args
, first_arg_is_executable
);
1192 if (m_options
.launch_info
.GetExecutableFile()) {
1193 Debugger
&debugger
= GetDebugger();
1196 // If no arguments were given to the command, use target.run-args.
1197 Args target_run_args
;
1198 target
->GetRunArguments(target_run_args
);
1199 m_options
.launch_info
.GetArguments().AppendArguments(target_run_args
);
1202 ProcessSP
process_sp(platform_sp
->DebugProcess(
1203 m_options
.launch_info
, debugger
, *target
, error
));
1205 if (!process_sp
&& error
.Success()) {
1206 result
.AppendError("failed to launch or debug process");
1208 } else if (!error
.Success()) {
1209 result
.AppendError(error
.AsCString());
1213 const bool synchronous_execution
=
1214 debugger
.GetCommandInterpreter().GetSynchronous();
1215 auto launch_info
= m_options
.launch_info
;
1216 bool rebroadcast_first_stop
=
1217 !synchronous_execution
&&
1218 launch_info
.GetFlags().Test(eLaunchFlagStopAtEntry
);
1220 EventSP first_stop_event_sp
;
1221 StateType state
= process_sp
->WaitForProcessToStop(
1222 std::nullopt
, &first_stop_event_sp
, rebroadcast_first_stop
,
1223 launch_info
.GetHijackListener());
1224 process_sp
->RestoreProcessEvents();
1226 if (rebroadcast_first_stop
) {
1227 assert(first_stop_event_sp
);
1228 process_sp
->BroadcastEvent(first_stop_event_sp
);
1233 case eStateStopped
: {
1234 if (launch_info
.GetFlags().Test(eLaunchFlagStopAtEntry
))
1236 if (synchronous_execution
) {
1237 // Now we have handled the stop-from-attach, and we are just
1238 // switching to a synchronous resume. So we should switch to the
1239 // SyncResume hijacker.
1240 process_sp
->ResumeSynchronous(&result
.GetOutputStream());
1242 error
= process_sp
->Resume();
1243 if (!error
.Success()) {
1244 result
.AppendErrorWithFormat(
1245 "process resume at entry point failed: %s",
1251 result
.AppendErrorWithFormat(
1252 "initial process state wasn't stopped: %s",
1253 StateAsCString(state
));
1257 if (process_sp
&& process_sp
->IsAlive()) {
1258 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1262 result
.AppendError("'platform process launch' uses the current target "
1263 "file and arguments, or the executable and its "
1264 "arguments can be specified in this command");
1268 result
.AppendError("no platform is selected\n");
1272 CommandOptionsProcessLaunch m_options
;
1273 OptionGroupPythonClassWithDict m_class_options
;
1274 OptionGroupOptions m_all_options
;
1277 // "platform process list"
1279 static PosixPlatformCommandOptionValidator posix_validator
;
1280 #define LLDB_OPTIONS_platform_process_list
1281 #include "CommandOptions.inc"
1283 class CommandObjectPlatformProcessList
: public CommandObjectParsed
{
1285 CommandObjectPlatformProcessList(CommandInterpreter
&interpreter
)
1286 : CommandObjectParsed(interpreter
, "platform process list",
1287 "List processes on a remote platform by name, pid, "
1288 "or many other matching attributes.",
1289 "platform process list", 0) {}
1291 ~CommandObjectPlatformProcessList() override
= default;
1293 Options
*GetOptions() override
{ return &m_options
; }
1296 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1297 Target
*target
= GetDebugger().GetSelectedTarget().get();
1298 PlatformSP platform_sp
;
1300 platform_sp
= target
->GetPlatform();
1303 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
1309 Stream
&ostrm
= result
.GetOutputStream();
1311 lldb::pid_t pid
= m_options
.match_info
.GetProcessInfo().GetProcessID();
1312 if (pid
!= LLDB_INVALID_PROCESS_ID
) {
1313 ProcessInstanceInfo proc_info
;
1314 if (platform_sp
->GetProcessInfo(pid
, proc_info
)) {
1315 ProcessInstanceInfo::DumpTableHeader(ostrm
, m_options
.show_args
,
1317 proc_info
.DumpAsTableRow(ostrm
, platform_sp
->GetUserIDResolver(),
1318 m_options
.show_args
, m_options
.verbose
);
1319 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1321 result
.AppendErrorWithFormat(
1322 "no process found with pid = %" PRIu64
"\n", pid
);
1325 ProcessInstanceInfoList proc_infos
;
1326 const uint32_t matches
=
1327 platform_sp
->FindProcesses(m_options
.match_info
, proc_infos
);
1328 const char *match_desc
= nullptr;
1329 const char *match_name
=
1330 m_options
.match_info
.GetProcessInfo().GetName();
1331 if (match_name
&& match_name
[0]) {
1332 switch (m_options
.match_info
.GetNameMatchType()) {
1333 case NameMatch::Ignore
:
1335 case NameMatch::Equals
:
1336 match_desc
= "matched";
1338 case NameMatch::Contains
:
1339 match_desc
= "contained";
1341 case NameMatch::StartsWith
:
1342 match_desc
= "started with";
1344 case NameMatch::EndsWith
:
1345 match_desc
= "ended with";
1347 case NameMatch::RegularExpression
:
1348 match_desc
= "matched the regular expression";
1355 result
.AppendErrorWithFormatv(
1356 "no processes were found that {0} \"{1}\" on the \"{2}\" "
1358 match_desc
, match_name
, platform_sp
->GetName());
1360 result
.AppendErrorWithFormatv(
1361 "no processes were found on the \"{0}\" platform\n",
1362 platform_sp
->GetName());
1364 result
.AppendMessageWithFormatv(
1365 "{0} matching process{1} found on \"{2}\"", matches
,
1366 matches
> 1 ? "es were" : " was", platform_sp
->GetName());
1368 result
.AppendMessageWithFormat(" whose name %s \"%s\"",
1369 match_desc
, match_name
);
1370 result
.AppendMessageWithFormat("\n");
1371 ProcessInstanceInfo::DumpTableHeader(ostrm
, m_options
.show_args
,
1373 for (uint32_t i
= 0; i
< matches
; ++i
) {
1374 proc_infos
[i
].DumpAsTableRow(
1375 ostrm
, platform_sp
->GetUserIDResolver(), m_options
.show_args
,
1382 result
.AppendError("no platform is selected\n");
1386 class CommandOptions
: public Options
{
1388 CommandOptions() = default;
1390 ~CommandOptions() override
= default;
1392 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
1393 ExecutionContext
*execution_context
) override
{
1395 const int short_option
= m_getopt_table
[option_idx
].val
;
1396 bool success
= false;
1398 uint32_t id
= LLDB_INVALID_PROCESS_ID
;
1399 success
= !option_arg
.getAsInteger(0, id
);
1400 switch (short_option
) {
1402 match_info
.GetProcessInfo().SetProcessID(id
);
1404 error
.SetErrorStringWithFormat("invalid process ID string: '%s'",
1405 option_arg
.str().c_str());
1409 match_info
.GetProcessInfo().SetParentProcessID(id
);
1411 error
.SetErrorStringWithFormat(
1412 "invalid parent process ID string: '%s'",
1413 option_arg
.str().c_str());
1417 match_info
.GetProcessInfo().SetUserID(success
? id
: UINT32_MAX
);
1419 error
.SetErrorStringWithFormat("invalid user ID string: '%s'",
1420 option_arg
.str().c_str());
1424 match_info
.GetProcessInfo().SetEffectiveUserID(success
? id
1427 error
.SetErrorStringWithFormat(
1428 "invalid effective user ID string: '%s'",
1429 option_arg
.str().c_str());
1433 match_info
.GetProcessInfo().SetGroupID(success
? id
: UINT32_MAX
);
1435 error
.SetErrorStringWithFormat("invalid group ID string: '%s'",
1436 option_arg
.str().c_str());
1440 match_info
.GetProcessInfo().SetEffectiveGroupID(success
? id
1443 error
.SetErrorStringWithFormat(
1444 "invalid effective group ID string: '%s'",
1445 option_arg
.str().c_str());
1449 TargetSP target_sp
=
1450 execution_context
? execution_context
->GetTargetSP() : TargetSP();
1451 DebuggerSP debugger_sp
=
1452 target_sp
? target_sp
->GetDebugger().shared_from_this()
1454 PlatformSP platform_sp
=
1455 debugger_sp
? debugger_sp
->GetPlatformList().GetSelectedPlatform()
1457 match_info
.GetProcessInfo().GetArchitecture() =
1458 Platform::GetAugmentedArchSpec(platform_sp
.get(), option_arg
);
1462 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1463 option_arg
, FileSpec::Style::native
);
1464 match_info
.SetNameMatchType(NameMatch::Equals
);
1468 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1469 option_arg
, FileSpec::Style::native
);
1470 match_info
.SetNameMatchType(NameMatch::EndsWith
);
1474 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1475 option_arg
, FileSpec::Style::native
);
1476 match_info
.SetNameMatchType(NameMatch::StartsWith
);
1480 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1481 option_arg
, FileSpec::Style::native
);
1482 match_info
.SetNameMatchType(NameMatch::Contains
);
1486 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1487 option_arg
, FileSpec::Style::native
);
1488 match_info
.SetNameMatchType(NameMatch::RegularExpression
);
1500 match_info
.SetMatchAllUsers(true);
1504 llvm_unreachable("Unimplemented option");
1510 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
1516 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
1517 return llvm::ArrayRef(g_platform_process_list_options
);
1520 // Instance variables to hold the values for command options.
1522 ProcessInstanceInfoMatch match_info
;
1523 bool show_args
= false;
1524 bool verbose
= false;
1527 CommandOptions m_options
;
1530 // "platform process info"
1531 class CommandObjectPlatformProcessInfo
: public CommandObjectParsed
{
1533 CommandObjectPlatformProcessInfo(CommandInterpreter
&interpreter
)
1534 : CommandObjectParsed(
1535 interpreter
, "platform process info",
1536 "Get detailed information for one or more process by process ID.",
1537 "platform process info <pid> [<pid> <pid> ...]", 0) {
1538 CommandArgumentEntry arg
;
1539 CommandArgumentData pid_args
;
1541 // Define the first (and only) variant of this arg.
1542 pid_args
.arg_type
= eArgTypePid
;
1543 pid_args
.arg_repetition
= eArgRepeatStar
;
1545 // There is only one variant this argument could be; put it into the
1547 arg
.push_back(pid_args
);
1549 // Push the data for the first argument into the m_arguments vector.
1550 m_arguments
.push_back(arg
);
1553 ~CommandObjectPlatformProcessInfo() override
= default;
1556 HandleArgumentCompletion(CompletionRequest
&request
,
1557 OptionElementVector
&opt_element_vector
) override
{
1558 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1559 GetCommandInterpreter(), lldb::eProcessIDCompletion
, request
, nullptr);
1563 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1564 Target
*target
= GetDebugger().GetSelectedTarget().get();
1565 PlatformSP platform_sp
;
1567 platform_sp
= target
->GetPlatform();
1570 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
1574 const size_t argc
= args
.GetArgumentCount();
1578 if (platform_sp
->IsConnected()) {
1579 Stream
&ostrm
= result
.GetOutputStream();
1580 for (auto &entry
: args
.entries()) {
1582 if (entry
.ref().getAsInteger(0, pid
)) {
1583 result
.AppendErrorWithFormat("invalid process ID argument '%s'",
1584 entry
.ref().str().c_str());
1587 ProcessInstanceInfo proc_info
;
1588 if (platform_sp
->GetProcessInfo(pid
, proc_info
)) {
1589 ostrm
.Printf("Process information for process %" PRIu64
":\n",
1591 proc_info
.Dump(ostrm
, platform_sp
->GetUserIDResolver());
1593 ostrm
.Printf("error: no process information is available for "
1594 "process %" PRIu64
"\n",
1602 result
.AppendErrorWithFormatv("not connected to '{0}'",
1603 platform_sp
->GetPluginName());
1607 result
.AppendError("one or more process id(s) must be specified");
1610 result
.AppendError("no platform is currently selected");
1615 #define LLDB_OPTIONS_platform_process_attach
1616 #include "CommandOptions.inc"
1618 class CommandObjectPlatformProcessAttach
: public CommandObjectParsed
{
1620 CommandObjectPlatformProcessAttach(CommandInterpreter
&interpreter
)
1621 : CommandObjectParsed(interpreter
, "platform process attach",
1622 "Attach to a process.",
1623 "platform process attach <cmd-options>"),
1624 m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
1625 m_all_options
.Append(&m_options
);
1626 m_all_options
.Append(&m_class_options
, LLDB_OPT_SET_1
| LLDB_OPT_SET_2
,
1628 m_all_options
.Finalize();
1631 ~CommandObjectPlatformProcessAttach() override
= default;
1633 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1634 PlatformSP
platform_sp(
1635 GetDebugger().GetPlatformList().GetSelectedPlatform());
1638 if (!m_class_options
.GetName().empty()) {
1639 m_options
.attach_info
.SetProcessPluginName("ScriptedProcess");
1640 ScriptedMetadataSP metadata_sp
= std::make_shared
<ScriptedMetadata
>(
1641 m_class_options
.GetName(), m_class_options
.GetStructuredData());
1642 m_options
.attach_info
.SetScriptedMetadata(metadata_sp
);
1646 ProcessSP remote_process_sp
= platform_sp
->Attach(
1647 m_options
.attach_info
, GetDebugger(), nullptr, err
);
1649 result
.AppendError(err
.AsCString());
1650 } else if (!remote_process_sp
) {
1651 result
.AppendError("could not attach: unknown reason");
1653 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1655 result
.AppendError("no platform is currently selected");
1659 Options
*GetOptions() override
{ return &m_all_options
; }
1662 CommandOptionsProcessAttach m_options
;
1663 OptionGroupPythonClassWithDict m_class_options
;
1664 OptionGroupOptions m_all_options
;
1667 class CommandObjectPlatformProcess
: public CommandObjectMultiword
{
1669 // Constructors and Destructors
1670 CommandObjectPlatformProcess(CommandInterpreter
&interpreter
)
1671 : CommandObjectMultiword(interpreter
, "platform process",
1672 "Commands to query, launch and attach to "
1673 "processes on the current platform.",
1674 "platform process [attach|launch|list] ...") {
1677 CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter
)));
1680 CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter
)));
1681 LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(
1683 LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
1687 ~CommandObjectPlatformProcess() override
= default;
1690 // For CommandObjectPlatform only
1691 CommandObjectPlatformProcess(const CommandObjectPlatformProcess
&) = delete;
1692 const CommandObjectPlatformProcess
&
1693 operator=(const CommandObjectPlatformProcess
&) = delete;
1697 #define LLDB_OPTIONS_platform_shell
1698 #include "CommandOptions.inc"
1700 class CommandObjectPlatformShell
: public CommandObjectRaw
{
1702 class CommandOptions
: public Options
{
1704 CommandOptions() = default;
1706 ~CommandOptions() override
= default;
1708 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
1709 return llvm::ArrayRef(g_platform_shell_options
);
1712 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
1713 ExecutionContext
*execution_context
) override
{
1716 const char short_option
= (char)GetDefinitions()[option_idx
].short_option
;
1718 switch (short_option
) {
1720 m_use_host_platform
= true;
1723 uint32_t timeout_sec
;
1724 if (option_arg
.getAsInteger(10, timeout_sec
))
1725 error
.SetErrorStringWithFormat(
1726 "could not convert \"%s\" to a numeric value.",
1727 option_arg
.str().c_str());
1729 m_timeout
= std::chrono::seconds(timeout_sec
);
1732 if (option_arg
.empty()) {
1733 error
.SetErrorStringWithFormat(
1734 "missing shell interpreter path for option -i|--interpreter.");
1738 m_shell_interpreter
= option_arg
.str();
1742 llvm_unreachable("Unimplemented option");
1748 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
1750 m_use_host_platform
= false;
1751 m_shell_interpreter
.clear();
1754 Timeout
<std::micro
> m_timeout
= std::chrono::seconds(10);
1755 bool m_use_host_platform
;
1756 std::string m_shell_interpreter
;
1759 CommandObjectPlatformShell(CommandInterpreter
&interpreter
)
1760 : CommandObjectRaw(interpreter
, "platform shell",
1761 "Run a shell command on the current platform.",
1762 "platform shell <shell-command>", 0) {
1763 CommandArgumentData thread_arg
{eArgTypeNone
, eArgRepeatStar
};
1764 m_arguments
.push_back({thread_arg
});
1767 ~CommandObjectPlatformShell() override
= default;
1769 Options
*GetOptions() override
{ return &m_options
; }
1771 void DoExecute(llvm::StringRef raw_command_line
,
1772 CommandReturnObject
&result
) override
{
1773 ExecutionContext exe_ctx
= GetCommandInterpreter().GetExecutionContext();
1774 m_options
.NotifyOptionParsingStarting(&exe_ctx
);
1776 // Print out an usage syntax on an empty command line.
1777 if (raw_command_line
.empty()) {
1778 result
.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());
1782 const bool is_alias
= !raw_command_line
.contains("platform");
1783 OptionsWithRaw
args(raw_command_line
);
1786 if (!ParseOptions(args
.GetArgs(), result
))
1789 if (args
.GetRawPart().empty()) {
1790 result
.GetOutputStream().Printf("%s <shell-command>\n",
1791 is_alias
? "shell" : "platform shell");
1795 llvm::StringRef cmd
= args
.GetRawPart();
1797 PlatformSP
platform_sp(
1798 m_options
.m_use_host_platform
1799 ? Platform::GetHostPlatform()
1800 : GetDebugger().GetPlatformList().GetSelectedPlatform());
1803 FileSpec working_dir
{};
1807 error
= (platform_sp
->RunShellCommand(m_options
.m_shell_interpreter
, cmd
,
1808 working_dir
, &status
, &signo
,
1809 &output
, m_options
.m_timeout
));
1810 if (!output
.empty())
1811 result
.GetOutputStream().PutCString(output
);
1814 const char *signo_cstr
= Host::GetSignalAsCString(signo
);
1816 result
.GetOutputStream().Printf(
1817 "error: command returned with status %i and signal %s\n",
1818 status
, signo_cstr
);
1820 result
.GetOutputStream().Printf(
1821 "error: command returned with status %i and signal %i\n",
1824 result
.GetOutputStream().Printf(
1825 "error: command returned with status %i\n", status
);
1828 result
.GetOutputStream().Printf(
1829 "error: cannot run remote shell commands without a platform\n");
1830 error
.SetErrorString(
1831 "error: cannot run remote shell commands without a platform");
1835 result
.AppendError(error
.AsCString());
1837 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1841 CommandOptions m_options
;
1844 // "platform install" - install a target to a remote end
1845 class CommandObjectPlatformInstall
: public CommandObjectParsed
{
1847 CommandObjectPlatformInstall(CommandInterpreter
&interpreter
)
1848 : CommandObjectParsed(
1849 interpreter
, "platform target-install",
1850 "Install a target (bundle or executable file) to the remote end.",
1851 "platform target-install <local-thing> <remote-sandbox>", 0) {
1852 CommandArgumentData local_arg
{eArgTypePath
, eArgRepeatPlain
};
1853 CommandArgumentData remote_arg
{eArgTypePath
, eArgRepeatPlain
};
1854 m_arguments
.push_back({local_arg
});
1855 m_arguments
.push_back({remote_arg
});
1858 ~CommandObjectPlatformInstall() override
= default;
1861 HandleArgumentCompletion(CompletionRequest
&request
,
1862 OptionElementVector
&opt_element_vector
) override
{
1863 if (request
.GetCursorIndex())
1865 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1866 GetCommandInterpreter(), lldb::eDiskFileCompletion
, request
, nullptr);
1869 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1870 if (args
.GetArgumentCount() != 2) {
1871 result
.AppendError("platform target-install takes two arguments");
1874 // TODO: move the bulk of this code over to the platform itself
1875 FileSpec
src(args
.GetArgumentAtIndex(0));
1876 FileSystem::Instance().Resolve(src
);
1877 FileSpec
dst(args
.GetArgumentAtIndex(1));
1878 if (!FileSystem::Instance().Exists(src
)) {
1879 result
.AppendError("source location does not exist or is not accessible");
1882 PlatformSP
platform_sp(
1883 GetDebugger().GetPlatformList().GetSelectedPlatform());
1885 result
.AppendError("no platform currently selected");
1889 Status error
= platform_sp
->Install(src
, dst
);
1890 if (error
.Success()) {
1891 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1893 result
.AppendErrorWithFormat("install failed: %s", error
.AsCString());
1898 CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter
&interpreter
)
1899 : CommandObjectMultiword(
1900 interpreter
, "platform", "Commands to manage and create platforms.",
1901 "platform [connect|disconnect|info|list|status|select] ...") {
1902 LoadSubCommand("select",
1903 CommandObjectSP(new CommandObjectPlatformSelect(interpreter
)));
1904 LoadSubCommand("list",
1905 CommandObjectSP(new CommandObjectPlatformList(interpreter
)));
1906 LoadSubCommand("status",
1907 CommandObjectSP(new CommandObjectPlatformStatus(interpreter
)));
1908 LoadSubCommand("connect", CommandObjectSP(
1909 new CommandObjectPlatformConnect(interpreter
)));
1912 CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter
)));
1913 LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(
1915 LoadSubCommand("mkdir",
1916 CommandObjectSP(new CommandObjectPlatformMkDir(interpreter
)));
1917 LoadSubCommand("file",
1918 CommandObjectSP(new CommandObjectPlatformFile(interpreter
)));
1919 LoadSubCommand("file-exists",
1920 CommandObjectSP(new CommandObjectPlatformFileExists(interpreter
)));
1921 LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
1923 LoadSubCommand("get-permissions",
1924 CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter
)));
1925 LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
1927 LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
1929 LoadSubCommand("process", CommandObjectSP(
1930 new CommandObjectPlatformProcess(interpreter
)));
1931 LoadSubCommand("shell",
1932 CommandObjectSP(new CommandObjectPlatformShell(interpreter
)));
1935 CommandObjectSP(new CommandObjectPlatformInstall(interpreter
)));
1938 CommandObjectPlatform::~CommandObjectPlatform() = default;