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
= Status::FromErrorStringWithFormat(
82 "invalid value for permissions: %s", option_arg
.str().c_str());
87 mode_t perms
= ParsePermissionString(option_arg
);
88 if (perms
== (mode_t
)-1)
89 error
= Status::FromErrorStringWithFormat(
90 "invalid value for permissions: %s", 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 AddSimpleArgumentList(eArgTypePlatform
);
161 ~CommandObjectPlatformSelect() override
= default;
163 void HandleCompletion(CompletionRequest
&request
) override
{
164 lldb_private::CommandCompletions::PlatformPluginNames(
165 GetCommandInterpreter(), request
, nullptr);
168 Options
*GetOptions() override
{ return &m_option_group
; }
171 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
172 if (args
.GetArgumentCount() == 1) {
173 const char *platform_name
= args
.GetArgumentAtIndex(0);
174 if (platform_name
&& platform_name
[0]) {
175 const bool select
= true;
176 m_platform_options
.SetPlatformName(platform_name
);
178 ArchSpec platform_arch
;
179 PlatformSP
platform_sp(m_platform_options
.CreatePlatformWithOptions(
180 m_interpreter
, ArchSpec(), select
, error
, platform_arch
));
182 GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp
);
184 platform_sp
->GetStatus(result
.GetOutputStream());
185 result
.SetStatus(eReturnStatusSuccessFinishResult
);
187 result
.AppendError(error
.AsCString());
190 result
.AppendError("invalid platform name");
194 "platform create takes a platform name as an argument\n");
198 OptionGroupOptions m_option_group
;
199 OptionGroupPlatform m_platform_options
;
203 class CommandObjectPlatformList
: public CommandObjectParsed
{
205 CommandObjectPlatformList(CommandInterpreter
&interpreter
)
206 : CommandObjectParsed(interpreter
, "platform list",
207 "List all platforms that are available.", nullptr,
210 ~CommandObjectPlatformList() override
= default;
213 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
214 Stream
&ostrm
= result
.GetOutputStream();
215 ostrm
.Printf("Available platforms:\n");
217 PlatformSP
host_platform_sp(Platform::GetHostPlatform());
218 ostrm
.Format("{0}: {1}\n", host_platform_sp
->GetPluginName(),
219 host_platform_sp
->GetDescription());
222 for (idx
= 0; true; ++idx
) {
223 llvm::StringRef plugin_name
=
224 PluginManager::GetPlatformPluginNameAtIndex(idx
);
225 if (plugin_name
.empty())
227 llvm::StringRef plugin_desc
=
228 PluginManager::GetPlatformPluginDescriptionAtIndex(idx
);
229 ostrm
.Format("{0}: {1}\n", plugin_name
, plugin_desc
);
233 result
.AppendError("no platforms are available\n");
235 result
.SetStatus(eReturnStatusSuccessFinishResult
);
240 class CommandObjectPlatformStatus
: public CommandObjectParsed
{
242 CommandObjectPlatformStatus(CommandInterpreter
&interpreter
)
243 : CommandObjectParsed(interpreter
, "platform status",
244 "Display status for the current platform.", nullptr,
247 ~CommandObjectPlatformStatus() override
= default;
250 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
251 Stream
&ostrm
= result
.GetOutputStream();
253 Target
*target
= GetDebugger().GetSelectedTarget().get();
254 PlatformSP platform_sp
;
256 platform_sp
= target
->GetPlatform();
259 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
262 platform_sp
->GetStatus(ostrm
);
263 result
.SetStatus(eReturnStatusSuccessFinishResult
);
265 result
.AppendError("no platform is currently selected\n");
270 // "platform connect <connect-url>"
271 class CommandObjectPlatformConnect
: public CommandObjectParsed
{
273 CommandObjectPlatformConnect(CommandInterpreter
&interpreter
)
274 : CommandObjectParsed(
275 interpreter
, "platform connect",
276 "Select the current platform by providing a connection URL.",
277 "platform connect <connect-url>", 0) {
278 AddSimpleArgumentList(eArgTypeConnectURL
);
281 ~CommandObjectPlatformConnect() override
= default;
284 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
285 Stream
&ostrm
= result
.GetOutputStream();
287 PlatformSP
platform_sp(
288 GetDebugger().GetPlatformList().GetSelectedPlatform());
290 Status
error(platform_sp
->ConnectRemote(args
));
291 if (error
.Success()) {
292 platform_sp
->GetStatus(ostrm
);
293 result
.SetStatus(eReturnStatusSuccessFinishResult
);
295 platform_sp
->ConnectToWaitingProcesses(GetDebugger(), error
);
297 result
.AppendError(error
.AsCString());
300 result
.AppendErrorWithFormat("%s\n", error
.AsCString());
303 result
.AppendError("no platform is currently selected\n");
307 Options
*GetOptions() override
{
308 PlatformSP
platform_sp(
309 GetDebugger().GetPlatformList().GetSelectedPlatform());
310 OptionGroupOptions
*m_platform_options
= nullptr;
312 m_platform_options
= platform_sp
->GetConnectionOptions(m_interpreter
);
313 if (m_platform_options
!= nullptr && !m_platform_options
->m_did_finalize
)
314 m_platform_options
->Finalize();
316 return m_platform_options
;
320 // "platform disconnect"
321 class CommandObjectPlatformDisconnect
: public CommandObjectParsed
{
323 CommandObjectPlatformDisconnect(CommandInterpreter
&interpreter
)
324 : CommandObjectParsed(interpreter
, "platform disconnect",
325 "Disconnect from the current platform.",
326 "platform disconnect", 0) {}
328 ~CommandObjectPlatformDisconnect() override
= default;
331 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
332 PlatformSP
platform_sp(
333 GetDebugger().GetPlatformList().GetSelectedPlatform());
335 if (args
.GetArgumentCount() == 0) {
338 if (platform_sp
->IsConnected()) {
339 // Cache the instance name if there is one since we are about to
340 // disconnect and the name might go with it.
341 const char *hostname_cstr
= platform_sp
->GetHostname();
342 std::string hostname
;
344 hostname
.assign(hostname_cstr
);
346 error
= platform_sp
->DisconnectRemote();
347 if (error
.Success()) {
348 Stream
&ostrm
= result
.GetOutputStream();
349 if (hostname
.empty())
350 ostrm
.Format("Disconnected from \"{0}\"\n",
351 platform_sp
->GetPluginName());
353 ostrm
.Printf("Disconnected from \"%s\"\n", hostname
.c_str());
354 result
.SetStatus(eReturnStatusSuccessFinishResult
);
356 result
.AppendErrorWithFormat("%s", error
.AsCString());
360 result
.AppendErrorWithFormatv("not connected to '{0}'",
361 platform_sp
->GetPluginName());
366 "\"platform disconnect\" doesn't take any arguments");
369 result
.AppendError("no platform is currently selected");
374 // "platform settings"
375 class CommandObjectPlatformSettings
: public CommandObjectParsed
{
377 CommandObjectPlatformSettings(CommandInterpreter
&interpreter
)
378 : CommandObjectParsed(interpreter
, "platform settings",
379 "Set settings for the current target's platform.",
380 "platform settings", 0),
381 m_option_working_dir(LLDB_OPT_SET_1
, false, "working-dir", 'w',
382 lldb::eRemoteDiskDirectoryCompletion
, eArgTypePath
,
383 "The working directory for the platform.") {
384 m_options
.Append(&m_option_working_dir
, LLDB_OPT_SET_ALL
, LLDB_OPT_SET_1
);
387 ~CommandObjectPlatformSettings() override
= default;
390 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
391 PlatformSP
platform_sp(
392 GetDebugger().GetPlatformList().GetSelectedPlatform());
394 if (m_option_working_dir
.GetOptionValue().OptionWasSet())
395 platform_sp
->SetWorkingDirectory(
396 m_option_working_dir
.GetOptionValue().GetCurrentValue());
398 result
.AppendError("no platform is currently selected");
402 Options
*GetOptions() override
{
403 if (!m_options
.DidFinalize())
404 m_options
.Finalize();
408 OptionGroupOptions m_options
;
409 OptionGroupFile m_option_working_dir
;
413 class CommandObjectPlatformMkDir
: public CommandObjectParsed
{
415 CommandObjectPlatformMkDir(CommandInterpreter
&interpreter
)
416 : CommandObjectParsed(interpreter
, "platform mkdir",
417 "Make a new directory on the remote end.", nullptr,
419 AddSimpleArgumentList(eArgTypeRemotePath
);
422 ~CommandObjectPlatformMkDir() override
= default;
424 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
425 PlatformSP
platform_sp(
426 GetDebugger().GetPlatformList().GetSelectedPlatform());
428 std::string cmd_line
;
429 args
.GetCommandString(cmd_line
);
431 const OptionPermissions
*options_permissions
=
432 (const OptionPermissions
*)m_options
.GetGroupWithOption('r');
433 if (options_permissions
)
434 mode
= options_permissions
->m_permissions
;
436 mode
= lldb::eFilePermissionsUserRWX
| lldb::eFilePermissionsGroupRWX
|
437 lldb::eFilePermissionsWorldRX
;
438 Status error
= platform_sp
->MakeDirectory(FileSpec(cmd_line
), mode
);
439 if (error
.Success()) {
440 result
.SetStatus(eReturnStatusSuccessFinishResult
);
442 result
.AppendError(error
.AsCString());
445 result
.AppendError("no platform currently selected\n");
449 Options
*GetOptions() override
{
450 if (!m_options
.DidFinalize()) {
451 m_options
.Append(&m_option_permissions
);
452 m_options
.Finalize();
457 OptionPermissions m_option_permissions
;
458 OptionGroupOptions m_options
;
462 class CommandObjectPlatformFOpen
: public CommandObjectParsed
{
464 CommandObjectPlatformFOpen(CommandInterpreter
&interpreter
)
465 : CommandObjectParsed(interpreter
, "platform file open",
466 "Open a file on the remote end.", nullptr, 0) {
467 AddSimpleArgumentList(eArgTypeRemotePath
);
470 ~CommandObjectPlatformFOpen() override
= default;
472 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
473 PlatformSP
platform_sp(
474 GetDebugger().GetPlatformList().GetSelectedPlatform());
477 std::string cmd_line
;
478 args
.GetCommandString(cmd_line
);
480 const OptionPermissions
*options_permissions
=
481 (const OptionPermissions
*)m_options
.GetGroupWithOption('r');
482 if (options_permissions
)
483 perms
= options_permissions
->m_permissions
;
485 perms
= lldb::eFilePermissionsUserRW
| lldb::eFilePermissionsGroupRW
|
486 lldb::eFilePermissionsWorldRead
;
487 lldb::user_id_t fd
= platform_sp
->OpenFile(
489 File::eOpenOptionReadWrite
| File::eOpenOptionCanCreate
,
491 if (error
.Success()) {
492 result
.AppendMessageWithFormat("File Descriptor = %" PRIu64
"\n", fd
);
493 result
.SetStatus(eReturnStatusSuccessFinishResult
);
495 result
.AppendError(error
.AsCString());
498 result
.AppendError("no platform currently selected\n");
502 Options
*GetOptions() override
{
503 if (!m_options
.DidFinalize()) {
504 m_options
.Append(&m_option_permissions
);
505 m_options
.Finalize();
510 OptionPermissions m_option_permissions
;
511 OptionGroupOptions m_options
;
515 class CommandObjectPlatformFClose
: public CommandObjectParsed
{
517 CommandObjectPlatformFClose(CommandInterpreter
&interpreter
)
518 : CommandObjectParsed(interpreter
, "platform file close",
519 "Close a file on the remote end.", nullptr, 0) {
520 AddSimpleArgumentList(eArgTypeUnsignedInteger
);
523 ~CommandObjectPlatformFClose() override
= default;
525 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
526 PlatformSP
platform_sp(
527 GetDebugger().GetPlatformList().GetSelectedPlatform());
529 std::string cmd_line
;
530 args
.GetCommandString(cmd_line
);
532 if (!llvm::to_integer(cmd_line
, fd
)) {
533 result
.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
538 bool success
= platform_sp
->CloseFile(fd
, error
);
540 result
.AppendMessageWithFormat("file %" PRIu64
" closed.\n", fd
);
541 result
.SetStatus(eReturnStatusSuccessFinishResult
);
543 result
.AppendError(error
.AsCString());
546 result
.AppendError("no platform currently selected\n");
553 #define LLDB_OPTIONS_platform_fread
554 #include "CommandOptions.inc"
556 class CommandObjectPlatformFRead
: public CommandObjectParsed
{
558 CommandObjectPlatformFRead(CommandInterpreter
&interpreter
)
559 : CommandObjectParsed(interpreter
, "platform file read",
560 "Read data from a file on the remote end.", nullptr,
562 AddSimpleArgumentList(eArgTypeUnsignedInteger
);
565 ~CommandObjectPlatformFRead() override
= default;
567 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
568 PlatformSP
platform_sp(
569 GetDebugger().GetPlatformList().GetSelectedPlatform());
571 std::string cmd_line
;
572 args
.GetCommandString(cmd_line
);
574 if (!llvm::to_integer(cmd_line
, fd
)) {
575 result
.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
579 std::string
buffer(m_options
.m_count
, 0);
581 uint64_t retcode
= platform_sp
->ReadFile(
582 fd
, m_options
.m_offset
, &buffer
[0], m_options
.m_count
, error
);
583 if (retcode
!= UINT64_MAX
) {
584 result
.AppendMessageWithFormat("Return = %" PRIu64
"\n", retcode
);
585 result
.AppendMessageWithFormat("Data = \"%s\"\n", buffer
.c_str());
586 result
.SetStatus(eReturnStatusSuccessFinishResult
);
588 result
.AppendError(error
.AsCString());
591 result
.AppendError("no platform currently selected\n");
595 Options
*GetOptions() override
{ return &m_options
; }
598 class CommandOptions
: public Options
{
600 CommandOptions() = default;
602 ~CommandOptions() override
= default;
604 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
605 ExecutionContext
*execution_context
) override
{
607 char short_option
= (char)m_getopt_table
[option_idx
].val
;
609 switch (short_option
) {
611 if (option_arg
.getAsInteger(0, m_offset
))
612 error
= Status::FromErrorStringWithFormat("invalid offset: '%s'",
613 option_arg
.str().c_str());
616 if (option_arg
.getAsInteger(0, m_count
))
617 error
= Status::FromErrorStringWithFormat("invalid offset: '%s'",
618 option_arg
.str().c_str());
621 llvm_unreachable("Unimplemented option");
627 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
632 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
633 return llvm::ArrayRef(g_platform_fread_options
);
636 // Instance variables to hold the values for command options.
642 CommandOptions m_options
;
647 #define LLDB_OPTIONS_platform_fwrite
648 #include "CommandOptions.inc"
650 class CommandObjectPlatformFWrite
: public CommandObjectParsed
{
652 CommandObjectPlatformFWrite(CommandInterpreter
&interpreter
)
653 : CommandObjectParsed(interpreter
, "platform file write",
654 "Write data to a file on the remote end.", nullptr,
656 AddSimpleArgumentList(eArgTypeUnsignedInteger
);
659 ~CommandObjectPlatformFWrite() override
= default;
661 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
662 PlatformSP
platform_sp(
663 GetDebugger().GetPlatformList().GetSelectedPlatform());
665 std::string cmd_line
;
666 args
.GetCommandString(cmd_line
);
669 if (!llvm::to_integer(cmd_line
, fd
)) {
670 result
.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.",
675 platform_sp
->WriteFile(fd
, m_options
.m_offset
, &m_options
.m_data
[0],
676 m_options
.m_data
.size(), error
);
677 if (retcode
!= UINT64_MAX
) {
678 result
.AppendMessageWithFormat("Return = %" PRIu64
"\n", retcode
);
679 result
.SetStatus(eReturnStatusSuccessFinishResult
);
681 result
.AppendError(error
.AsCString());
684 result
.AppendError("no platform currently selected\n");
688 Options
*GetOptions() override
{ return &m_options
; }
691 class CommandOptions
: public Options
{
693 CommandOptions() = default;
695 ~CommandOptions() override
= default;
697 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
698 ExecutionContext
*execution_context
) override
{
700 char short_option
= (char)m_getopt_table
[option_idx
].val
;
702 switch (short_option
) {
704 if (option_arg
.getAsInteger(0, m_offset
))
705 error
= Status::FromErrorStringWithFormat("invalid offset: '%s'",
706 option_arg
.str().c_str());
709 m_data
.assign(std::string(option_arg
));
712 llvm_unreachable("Unimplemented option");
718 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
723 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
724 return llvm::ArrayRef(g_platform_fwrite_options
);
727 // Instance variables to hold the values for command options.
733 CommandOptions m_options
;
736 class CommandObjectPlatformFile
: public CommandObjectMultiword
{
738 // Constructors and Destructors
739 CommandObjectPlatformFile(CommandInterpreter
&interpreter
)
740 : CommandObjectMultiword(
741 interpreter
, "platform file",
742 "Commands to access files on the current platform.",
743 "platform file [open|close|read|write] ...") {
745 "open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter
)));
747 "close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter
)));
749 "read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter
)));
751 "write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter
)));
754 ~CommandObjectPlatformFile() override
= default;
757 // For CommandObjectPlatform only
758 CommandObjectPlatformFile(const CommandObjectPlatformFile
&) = delete;
759 const CommandObjectPlatformFile
&
760 operator=(const CommandObjectPlatformFile
&) = delete;
763 // "platform get-file remote-file-path host-file-path"
764 class CommandObjectPlatformGetFile
: public CommandObjectParsed
{
766 CommandObjectPlatformGetFile(CommandInterpreter
&interpreter
)
767 : CommandObjectParsed(
768 interpreter
, "platform get-file",
769 "Transfer a file from the remote end to the local host.",
770 "platform get-file <remote-file-spec> <local-file-spec>", 0) {
774 (lldb) platform get-file /the/remote/file/path /the/local/file/path
776 Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");
778 CommandArgumentEntry arg1
, arg2
;
779 CommandArgumentData file_arg_remote
, file_arg_host
;
781 // Define the first (and only) variant of this arg.
782 file_arg_remote
.arg_type
= eArgTypeRemoteFilename
;
783 file_arg_remote
.arg_repetition
= eArgRepeatPlain
;
784 // There is only one variant this argument could be; put it into the
786 arg1
.push_back(file_arg_remote
);
788 // Define the second (and only) variant of this arg.
789 file_arg_host
.arg_type
= eArgTypeFilename
;
790 file_arg_host
.arg_repetition
= eArgRepeatPlain
;
791 // There is only one variant this argument could be; put it into the
793 arg2
.push_back(file_arg_host
);
795 // Push the data for the first and the second arguments into the
796 // m_arguments vector.
797 m_arguments
.push_back(arg1
);
798 m_arguments
.push_back(arg2
);
801 ~CommandObjectPlatformGetFile() override
= default;
804 HandleArgumentCompletion(CompletionRequest
&request
,
805 OptionElementVector
&opt_element_vector
) override
{
806 if (request
.GetCursorIndex() == 0)
807 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
808 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
810 else if (request
.GetCursorIndex() == 1)
811 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
812 GetCommandInterpreter(), lldb::eDiskFileCompletion
, request
, nullptr);
815 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
816 // If the number of arguments is incorrect, issue an error message.
817 if (args
.GetArgumentCount() != 2) {
818 result
.AppendError("required arguments missing; specify both the "
819 "source and destination file paths");
823 PlatformSP
platform_sp(
824 GetDebugger().GetPlatformList().GetSelectedPlatform());
826 const char *remote_file_path
= args
.GetArgumentAtIndex(0);
827 const char *local_file_path
= args
.GetArgumentAtIndex(1);
828 Status error
= platform_sp
->GetFile(FileSpec(remote_file_path
),
829 FileSpec(local_file_path
));
830 if (error
.Success()) {
831 result
.AppendMessageWithFormat(
832 "successfully get-file from %s (remote) to %s (host)\n",
833 remote_file_path
, local_file_path
);
834 result
.SetStatus(eReturnStatusSuccessFinishResult
);
836 result
.AppendMessageWithFormat("get-file failed: %s\n",
840 result
.AppendError("no platform currently selected\n");
845 // "platform get-size remote-file-path"
846 class CommandObjectPlatformGetSize
: public CommandObjectParsed
{
848 CommandObjectPlatformGetSize(CommandInterpreter
&interpreter
)
849 : CommandObjectParsed(interpreter
, "platform get-size",
850 "Get the file size from the remote end.",
851 "platform get-size <remote-file-spec>", 0) {
855 (lldb) platform get-size /the/remote/file/path
857 Get the file size from the remote end with path /the/remote/file/path.)");
859 AddSimpleArgumentList(eArgTypeRemoteFilename
);
862 ~CommandObjectPlatformGetSize() override
= default;
864 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
865 // If the number of arguments is incorrect, issue an error message.
866 if (args
.GetArgumentCount() != 1) {
867 result
.AppendError("required argument missing; specify the source file "
868 "path as the only argument");
872 PlatformSP
platform_sp(
873 GetDebugger().GetPlatformList().GetSelectedPlatform());
875 std::string
remote_file_path(args
.GetArgumentAtIndex(0));
876 user_id_t size
= platform_sp
->GetFileSize(FileSpec(remote_file_path
));
877 if (size
!= UINT64_MAX
) {
878 result
.AppendMessageWithFormat("File size of %s (remote): %" PRIu64
880 remote_file_path
.c_str(), size
);
881 result
.SetStatus(eReturnStatusSuccessFinishResult
);
883 result
.AppendMessageWithFormat(
884 "Error getting file size of %s (remote)\n",
885 remote_file_path
.c_str());
888 result
.AppendError("no platform currently selected\n");
893 // "platform get-permissions remote-file-path"
894 class CommandObjectPlatformGetPermissions
: public CommandObjectParsed
{
896 CommandObjectPlatformGetPermissions(CommandInterpreter
&interpreter
)
897 : CommandObjectParsed(interpreter
, "platform get-permissions",
898 "Get the file permission bits from the remote end.",
899 "platform get-permissions <remote-file-spec>", 0) {
903 (lldb) platform get-permissions /the/remote/file/path
905 Get the file permissions from the remote end with path /the/remote/file/path.)");
907 AddSimpleArgumentList(eArgTypeRemoteFilename
);
910 ~CommandObjectPlatformGetPermissions() override
= default;
912 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
913 // If the number of arguments is incorrect, issue an error message.
914 if (args
.GetArgumentCount() != 1) {
915 result
.AppendError("required argument missing; specify the source file "
916 "path as the only argument");
920 PlatformSP
platform_sp(
921 GetDebugger().GetPlatformList().GetSelectedPlatform());
923 std::string
remote_file_path(args
.GetArgumentAtIndex(0));
924 uint32_t permissions
;
925 Status error
= platform_sp
->GetFilePermissions(FileSpec(remote_file_path
),
927 if (error
.Success()) {
928 result
.AppendMessageWithFormat(
929 "File permissions of %s (remote): 0o%04" PRIo32
"\n",
930 remote_file_path
.c_str(), permissions
);
931 result
.SetStatus(eReturnStatusSuccessFinishResult
);
933 result
.AppendError(error
.AsCString());
935 result
.AppendError("no platform currently selected\n");
940 // "platform file-exists remote-file-path"
941 class CommandObjectPlatformFileExists
: public CommandObjectParsed
{
943 CommandObjectPlatformFileExists(CommandInterpreter
&interpreter
)
944 : CommandObjectParsed(interpreter
, "platform file-exists",
945 "Check if the file exists on the remote end.",
946 "platform file-exists <remote-file-spec>", 0) {
950 (lldb) platform file-exists /the/remote/file/path
952 Check if /the/remote/file/path exists on the remote end.)");
954 AddSimpleArgumentList(eArgTypeRemoteFilename
);
957 ~CommandObjectPlatformFileExists() override
= default;
959 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
960 // If the number of arguments is incorrect, issue an error message.
961 if (args
.GetArgumentCount() != 1) {
962 result
.AppendError("required argument missing; specify the source file "
963 "path as the only argument");
967 PlatformSP
platform_sp(
968 GetDebugger().GetPlatformList().GetSelectedPlatform());
970 std::string
remote_file_path(args
.GetArgumentAtIndex(0));
971 bool exists
= platform_sp
->GetFileExists(FileSpec(remote_file_path
));
972 result
.AppendMessageWithFormat(
973 "File %s (remote) %s\n",
974 remote_file_path
.c_str(), exists
? "exists" : "does not exist");
975 result
.SetStatus(eReturnStatusSuccessFinishResult
);
977 result
.AppendError("no platform currently selected\n");
982 // "platform put-file"
983 class CommandObjectPlatformPutFile
: public CommandObjectParsed
{
985 CommandObjectPlatformPutFile(CommandInterpreter
&interpreter
)
986 : CommandObjectParsed(
987 interpreter
, "platform put-file",
988 "Transfer a file from this system to the remote end.",
989 "platform put-file <source> [<destination>]", 0) {
993 (lldb) platform put-file /source/foo.txt /destination/bar.txt
995 (lldb) platform put-file /source/foo.txt
997 Relative source file paths are resolved against lldb's local working directory.
999 Omitting the destination places the file in the platform working directory.)");
1000 CommandArgumentData source_arg
{eArgTypePath
, eArgRepeatPlain
};
1001 CommandArgumentData path_arg
{eArgTypeRemotePath
, eArgRepeatOptional
};
1002 m_arguments
.push_back({source_arg
});
1003 m_arguments
.push_back({path_arg
});
1006 ~CommandObjectPlatformPutFile() override
= default;
1009 HandleArgumentCompletion(CompletionRequest
&request
,
1010 OptionElementVector
&opt_element_vector
) override
{
1011 if (request
.GetCursorIndex() == 0)
1012 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1013 GetCommandInterpreter(), lldb::eDiskFileCompletion
, request
, nullptr);
1014 else if (request
.GetCursorIndex() == 1)
1015 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1016 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
1020 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1021 const char *src
= args
.GetArgumentAtIndex(0);
1022 const char *dst
= args
.GetArgumentAtIndex(1);
1024 FileSpec
src_fs(src
);
1025 FileSystem::Instance().Resolve(src_fs
);
1026 FileSpec
dst_fs(dst
? dst
: src_fs
.GetFilename().GetCString());
1028 PlatformSP
platform_sp(
1029 GetDebugger().GetPlatformList().GetSelectedPlatform());
1031 Status
error(platform_sp
->PutFile(src_fs
, dst_fs
));
1032 if (error
.Success()) {
1033 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1035 result
.AppendError(error
.AsCString());
1038 result
.AppendError("no platform currently selected\n");
1043 // "platform process launch"
1044 class CommandObjectPlatformProcessLaunch
: public CommandObjectParsed
{
1046 CommandObjectPlatformProcessLaunch(CommandInterpreter
&interpreter
)
1047 : CommandObjectParsed(interpreter
, "platform process launch",
1048 "Launch a new process on a remote platform.",
1049 "platform process launch program",
1050 eCommandRequiresTarget
| eCommandTryTargetAPILock
),
1051 m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
1052 m_all_options
.Append(&m_options
);
1053 m_all_options
.Append(&m_class_options
, LLDB_OPT_SET_1
| LLDB_OPT_SET_2
,
1055 m_all_options
.Finalize();
1056 AddSimpleArgumentList(eArgTypeRunArgs
, eArgRepeatStar
);
1060 HandleArgumentCompletion(CompletionRequest
&request
,
1061 OptionElementVector
&opt_element_vector
) override
{
1062 // I didn't make a type for RemoteRunArgs, but since we're going to run
1063 // this on the remote system we should use the remote completer.
1064 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1065 GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion
, request
,
1069 ~CommandObjectPlatformProcessLaunch() override
= default;
1071 Options
*GetOptions() override
{ return &m_all_options
; }
1074 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1075 Target
*target
= GetDebugger().GetSelectedTarget().get();
1076 PlatformSP platform_sp
;
1078 platform_sp
= target
->GetPlatform();
1081 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
1086 const size_t argc
= args
.GetArgumentCount();
1087 Target
*target
= m_exe_ctx
.GetTargetPtr();
1088 Module
*exe_module
= target
->GetExecutableModulePointer();
1090 m_options
.launch_info
.GetExecutableFile() = exe_module
->GetFileSpec();
1091 llvm::SmallString
<128> exe_path
;
1092 m_options
.launch_info
.GetExecutableFile().GetPath(exe_path
);
1093 if (!exe_path
.empty())
1094 m_options
.launch_info
.GetArguments().AppendArgument(exe_path
);
1095 m_options
.launch_info
.GetArchitecture() = exe_module
->GetArchitecture();
1098 if (!m_class_options
.GetName().empty()) {
1099 m_options
.launch_info
.SetProcessPluginName("ScriptedProcess");
1100 ScriptedMetadataSP metadata_sp
= std::make_shared
<ScriptedMetadata
>(
1101 m_class_options
.GetName(), m_class_options
.GetStructuredData());
1102 m_options
.launch_info
.SetScriptedMetadata(metadata_sp
);
1103 target
->SetProcessLaunchInfo(m_options
.launch_info
);
1107 if (m_options
.launch_info
.GetExecutableFile()) {
1108 // We already have an executable file, so we will use this and all
1109 // arguments to this function are extra arguments
1110 m_options
.launch_info
.GetArguments().AppendArguments(args
);
1112 // We don't have any file yet, so the first argument is our
1113 // executable, and the rest are program arguments
1114 const bool first_arg_is_executable
= true;
1115 m_options
.launch_info
.SetArguments(args
, first_arg_is_executable
);
1119 if (m_options
.launch_info
.GetExecutableFile()) {
1120 Debugger
&debugger
= GetDebugger();
1123 // If no arguments were given to the command, use target.run-args.
1124 Args target_run_args
;
1125 target
->GetRunArguments(target_run_args
);
1126 m_options
.launch_info
.GetArguments().AppendArguments(target_run_args
);
1129 ProcessSP
process_sp(platform_sp
->DebugProcess(
1130 m_options
.launch_info
, debugger
, *target
, error
));
1132 if (!process_sp
&& error
.Success()) {
1133 result
.AppendError("failed to launch or debug process");
1135 } else if (!error
.Success()) {
1136 result
.AppendError(error
.AsCString());
1140 const bool synchronous_execution
=
1141 debugger
.GetCommandInterpreter().GetSynchronous();
1142 auto launch_info
= m_options
.launch_info
;
1143 bool rebroadcast_first_stop
=
1144 !synchronous_execution
&&
1145 launch_info
.GetFlags().Test(eLaunchFlagStopAtEntry
);
1147 EventSP first_stop_event_sp
;
1148 StateType state
= process_sp
->WaitForProcessToStop(
1149 std::nullopt
, &first_stop_event_sp
, rebroadcast_first_stop
,
1150 launch_info
.GetHijackListener());
1151 process_sp
->RestoreProcessEvents();
1153 if (rebroadcast_first_stop
) {
1154 assert(first_stop_event_sp
);
1155 process_sp
->BroadcastEvent(first_stop_event_sp
);
1160 case eStateStopped
: {
1161 if (launch_info
.GetFlags().Test(eLaunchFlagStopAtEntry
))
1163 if (synchronous_execution
) {
1164 // Now we have handled the stop-from-attach, and we are just
1165 // switching to a synchronous resume. So we should switch to the
1166 // SyncResume hijacker.
1167 process_sp
->ResumeSynchronous(&result
.GetOutputStream());
1169 error
= process_sp
->Resume();
1170 if (!error
.Success()) {
1171 result
.AppendErrorWithFormat(
1172 "process resume at entry point failed: %s",
1178 result
.AppendErrorWithFormat(
1179 "initial process state wasn't stopped: %s",
1180 StateAsCString(state
));
1184 if (process_sp
&& process_sp
->IsAlive()) {
1185 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1189 result
.AppendError("'platform process launch' uses the current target "
1190 "file and arguments, or the executable and its "
1191 "arguments can be specified in this command");
1195 result
.AppendError("no platform is selected\n");
1199 CommandOptionsProcessLaunch m_options
;
1200 OptionGroupPythonClassWithDict m_class_options
;
1201 OptionGroupOptions m_all_options
;
1204 // "platform process list"
1206 static PosixPlatformCommandOptionValidator posix_validator
;
1207 #define LLDB_OPTIONS_platform_process_list
1208 #include "CommandOptions.inc"
1210 class CommandObjectPlatformProcessList
: public CommandObjectParsed
{
1212 CommandObjectPlatformProcessList(CommandInterpreter
&interpreter
)
1213 : CommandObjectParsed(interpreter
, "platform process list",
1214 "List processes on a remote platform by name, pid, "
1215 "or many other matching attributes.",
1216 "platform process list", 0) {}
1218 ~CommandObjectPlatformProcessList() override
= default;
1220 Options
*GetOptions() override
{ return &m_options
; }
1223 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1224 Target
*target
= GetDebugger().GetSelectedTarget().get();
1225 PlatformSP platform_sp
;
1227 platform_sp
= target
->GetPlatform();
1230 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
1236 Stream
&ostrm
= result
.GetOutputStream();
1238 lldb::pid_t pid
= m_options
.match_info
.GetProcessInfo().GetProcessID();
1239 if (pid
!= LLDB_INVALID_PROCESS_ID
) {
1240 ProcessInstanceInfo proc_info
;
1241 if (platform_sp
->GetProcessInfo(pid
, proc_info
)) {
1242 ProcessInstanceInfo::DumpTableHeader(ostrm
, m_options
.show_args
,
1244 proc_info
.DumpAsTableRow(ostrm
, platform_sp
->GetUserIDResolver(),
1245 m_options
.show_args
, m_options
.verbose
);
1246 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1248 result
.AppendErrorWithFormat(
1249 "no process found with pid = %" PRIu64
"\n", pid
);
1252 ProcessInstanceInfoList proc_infos
;
1253 const uint32_t matches
=
1254 platform_sp
->FindProcesses(m_options
.match_info
, proc_infos
);
1255 const char *match_desc
= nullptr;
1256 const char *match_name
=
1257 m_options
.match_info
.GetProcessInfo().GetName();
1258 if (match_name
&& match_name
[0]) {
1259 switch (m_options
.match_info
.GetNameMatchType()) {
1260 case NameMatch::Ignore
:
1262 case NameMatch::Equals
:
1263 match_desc
= "matched";
1265 case NameMatch::Contains
:
1266 match_desc
= "contained";
1268 case NameMatch::StartsWith
:
1269 match_desc
= "started with";
1271 case NameMatch::EndsWith
:
1272 match_desc
= "ended with";
1274 case NameMatch::RegularExpression
:
1275 match_desc
= "matched the regular expression";
1282 result
.AppendErrorWithFormatv(
1283 "no processes were found that {0} \"{1}\" on the \"{2}\" "
1285 match_desc
, match_name
, platform_sp
->GetName());
1287 result
.AppendErrorWithFormatv(
1288 "no processes were found on the \"{0}\" platform\n",
1289 platform_sp
->GetName());
1291 result
.AppendMessageWithFormatv(
1292 "{0} matching process{1} found on \"{2}\"", matches
,
1293 matches
> 1 ? "es were" : " was", platform_sp
->GetName());
1295 result
.AppendMessageWithFormat(" whose name %s \"%s\"",
1296 match_desc
, match_name
);
1297 result
.AppendMessageWithFormat("\n");
1298 ProcessInstanceInfo::DumpTableHeader(ostrm
, m_options
.show_args
,
1300 for (uint32_t i
= 0; i
< matches
; ++i
) {
1301 proc_infos
[i
].DumpAsTableRow(
1302 ostrm
, platform_sp
->GetUserIDResolver(), m_options
.show_args
,
1309 result
.AppendError("no platform is selected\n");
1313 class CommandOptions
: public Options
{
1315 CommandOptions() = default;
1317 ~CommandOptions() override
= default;
1319 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
1320 ExecutionContext
*execution_context
) override
{
1322 const int short_option
= m_getopt_table
[option_idx
].val
;
1323 bool success
= false;
1325 uint32_t id
= LLDB_INVALID_PROCESS_ID
;
1326 success
= !option_arg
.getAsInteger(0, id
);
1327 switch (short_option
) {
1329 match_info
.GetProcessInfo().SetProcessID(id
);
1331 error
= Status::FromErrorStringWithFormat(
1332 "invalid process ID string: '%s'", option_arg
.str().c_str());
1336 match_info
.GetProcessInfo().SetParentProcessID(id
);
1338 error
= Status::FromErrorStringWithFormat(
1339 "invalid parent process ID string: '%s'",
1340 option_arg
.str().c_str());
1344 match_info
.GetProcessInfo().SetUserID(success
? id
: UINT32_MAX
);
1346 error
= Status::FromErrorStringWithFormat(
1347 "invalid user ID string: '%s'", option_arg
.str().c_str());
1351 match_info
.GetProcessInfo().SetEffectiveUserID(success
? id
1354 error
= Status::FromErrorStringWithFormat(
1355 "invalid effective user ID string: '%s'",
1356 option_arg
.str().c_str());
1360 match_info
.GetProcessInfo().SetGroupID(success
? id
: UINT32_MAX
);
1362 error
= Status::FromErrorStringWithFormat(
1363 "invalid group ID string: '%s'", option_arg
.str().c_str());
1367 match_info
.GetProcessInfo().SetEffectiveGroupID(success
? id
1370 error
= Status::FromErrorStringWithFormat(
1371 "invalid effective group ID string: '%s'",
1372 option_arg
.str().c_str());
1376 TargetSP target_sp
=
1377 execution_context
? execution_context
->GetTargetSP() : TargetSP();
1378 DebuggerSP debugger_sp
=
1379 target_sp
? target_sp
->GetDebugger().shared_from_this()
1381 PlatformSP platform_sp
=
1382 debugger_sp
? debugger_sp
->GetPlatformList().GetSelectedPlatform()
1384 match_info
.GetProcessInfo().GetArchitecture() =
1385 Platform::GetAugmentedArchSpec(platform_sp
.get(), option_arg
);
1389 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1390 option_arg
, FileSpec::Style::native
);
1391 match_info
.SetNameMatchType(NameMatch::Equals
);
1395 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1396 option_arg
, FileSpec::Style::native
);
1397 match_info
.SetNameMatchType(NameMatch::EndsWith
);
1401 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1402 option_arg
, FileSpec::Style::native
);
1403 match_info
.SetNameMatchType(NameMatch::StartsWith
);
1407 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1408 option_arg
, FileSpec::Style::native
);
1409 match_info
.SetNameMatchType(NameMatch::Contains
);
1413 match_info
.GetProcessInfo().GetExecutableFile().SetFile(
1414 option_arg
, FileSpec::Style::native
);
1415 match_info
.SetNameMatchType(NameMatch::RegularExpression
);
1427 match_info
.SetMatchAllUsers(true);
1431 llvm_unreachable("Unimplemented option");
1437 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
1443 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
1444 return llvm::ArrayRef(g_platform_process_list_options
);
1447 // Instance variables to hold the values for command options.
1449 ProcessInstanceInfoMatch match_info
;
1450 bool show_args
= false;
1451 bool verbose
= false;
1454 CommandOptions m_options
;
1457 // "platform process info"
1458 class CommandObjectPlatformProcessInfo
: public CommandObjectParsed
{
1460 CommandObjectPlatformProcessInfo(CommandInterpreter
&interpreter
)
1461 : CommandObjectParsed(
1462 interpreter
, "platform process info",
1463 "Get detailed information for one or more process by process ID.",
1464 "platform process info <pid> [<pid> <pid> ...]", 0) {
1465 AddSimpleArgumentList(eArgTypePid
, eArgRepeatStar
);
1468 ~CommandObjectPlatformProcessInfo() override
= default;
1471 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1472 Target
*target
= GetDebugger().GetSelectedTarget().get();
1473 PlatformSP platform_sp
;
1475 platform_sp
= target
->GetPlatform();
1478 platform_sp
= GetDebugger().GetPlatformList().GetSelectedPlatform();
1482 const size_t argc
= args
.GetArgumentCount();
1486 if (platform_sp
->IsConnected()) {
1487 Stream
&ostrm
= result
.GetOutputStream();
1488 for (auto &entry
: args
.entries()) {
1490 if (entry
.ref().getAsInteger(0, pid
)) {
1491 result
.AppendErrorWithFormat("invalid process ID argument '%s'",
1492 entry
.ref().str().c_str());
1495 ProcessInstanceInfo proc_info
;
1496 if (platform_sp
->GetProcessInfo(pid
, proc_info
)) {
1497 ostrm
.Printf("Process information for process %" PRIu64
":\n",
1499 proc_info
.Dump(ostrm
, platform_sp
->GetUserIDResolver());
1501 ostrm
.Printf("error: no process information is available for "
1502 "process %" PRIu64
"\n",
1510 result
.AppendErrorWithFormatv("not connected to '{0}'",
1511 platform_sp
->GetPluginName());
1515 result
.AppendError("one or more process id(s) must be specified");
1518 result
.AppendError("no platform is currently selected");
1523 #define LLDB_OPTIONS_platform_process_attach
1524 #include "CommandOptions.inc"
1526 class CommandObjectPlatformProcessAttach
: public CommandObjectParsed
{
1528 CommandObjectPlatformProcessAttach(CommandInterpreter
&interpreter
)
1529 : CommandObjectParsed(interpreter
, "platform process attach",
1530 "Attach to a process.",
1531 "platform process attach <cmd-options>"),
1532 m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
1533 m_all_options
.Append(&m_options
);
1534 m_all_options
.Append(&m_class_options
, LLDB_OPT_SET_1
| LLDB_OPT_SET_2
,
1536 m_all_options
.Finalize();
1539 ~CommandObjectPlatformProcessAttach() override
= default;
1541 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1542 PlatformSP
platform_sp(
1543 GetDebugger().GetPlatformList().GetSelectedPlatform());
1546 if (!m_class_options
.GetName().empty()) {
1547 m_options
.attach_info
.SetProcessPluginName("ScriptedProcess");
1548 ScriptedMetadataSP metadata_sp
= std::make_shared
<ScriptedMetadata
>(
1549 m_class_options
.GetName(), m_class_options
.GetStructuredData());
1550 m_options
.attach_info
.SetScriptedMetadata(metadata_sp
);
1554 ProcessSP remote_process_sp
= platform_sp
->Attach(
1555 m_options
.attach_info
, GetDebugger(), nullptr, err
);
1557 result
.AppendError(err
.AsCString());
1558 } else if (!remote_process_sp
) {
1559 result
.AppendError("could not attach: unknown reason");
1561 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1563 result
.AppendError("no platform is currently selected");
1567 Options
*GetOptions() override
{ return &m_all_options
; }
1570 CommandOptionsProcessAttach m_options
;
1571 OptionGroupPythonClassWithDict m_class_options
;
1572 OptionGroupOptions m_all_options
;
1575 class CommandObjectPlatformProcess
: public CommandObjectMultiword
{
1577 // Constructors and Destructors
1578 CommandObjectPlatformProcess(CommandInterpreter
&interpreter
)
1579 : CommandObjectMultiword(interpreter
, "platform process",
1580 "Commands to query, launch and attach to "
1581 "processes on the current platform.",
1582 "platform process [attach|launch|list] ...") {
1585 CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter
)));
1588 CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter
)));
1589 LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(
1591 LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
1595 ~CommandObjectPlatformProcess() override
= default;
1598 // For CommandObjectPlatform only
1599 CommandObjectPlatformProcess(const CommandObjectPlatformProcess
&) = delete;
1600 const CommandObjectPlatformProcess
&
1601 operator=(const CommandObjectPlatformProcess
&) = delete;
1605 #define LLDB_OPTIONS_platform_shell
1606 #include "CommandOptions.inc"
1608 class CommandObjectPlatformShell
: public CommandObjectRaw
{
1610 class CommandOptions
: public Options
{
1612 CommandOptions() = default;
1614 ~CommandOptions() override
= default;
1616 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
1617 return llvm::ArrayRef(g_platform_shell_options
);
1620 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_arg
,
1621 ExecutionContext
*execution_context
) override
{
1624 const char short_option
= (char)GetDefinitions()[option_idx
].short_option
;
1626 switch (short_option
) {
1628 m_use_host_platform
= true;
1631 uint32_t timeout_sec
;
1632 if (option_arg
.getAsInteger(10, timeout_sec
))
1633 error
= Status::FromErrorStringWithFormat(
1634 "could not convert \"%s\" to a numeric value.",
1635 option_arg
.str().c_str());
1637 m_timeout
= std::chrono::seconds(timeout_sec
);
1640 if (option_arg
.empty()) {
1641 error
= Status::FromErrorStringWithFormat(
1642 "missing shell interpreter path for option -i|--interpreter.");
1646 m_shell_interpreter
= option_arg
.str();
1650 llvm_unreachable("Unimplemented option");
1656 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
1658 m_use_host_platform
= false;
1659 m_shell_interpreter
.clear();
1662 Timeout
<std::micro
> m_timeout
= std::chrono::seconds(10);
1663 bool m_use_host_platform
;
1664 std::string m_shell_interpreter
;
1667 CommandObjectPlatformShell(CommandInterpreter
&interpreter
)
1668 : CommandObjectRaw(interpreter
, "platform shell",
1669 "Run a shell command on the current platform.",
1670 "platform shell <shell-command>", 0) {
1671 AddSimpleArgumentList(eArgTypeNone
, eArgRepeatStar
);
1674 ~CommandObjectPlatformShell() override
= default;
1676 Options
*GetOptions() override
{ return &m_options
; }
1678 void DoExecute(llvm::StringRef raw_command_line
,
1679 CommandReturnObject
&result
) override
{
1680 ExecutionContext exe_ctx
= GetCommandInterpreter().GetExecutionContext();
1681 m_options
.NotifyOptionParsingStarting(&exe_ctx
);
1683 // Print out an usage syntax on an empty command line.
1684 if (raw_command_line
.empty()) {
1685 result
.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());
1689 const bool is_alias
= !raw_command_line
.contains("platform");
1690 OptionsWithRaw
args(raw_command_line
);
1693 if (!ParseOptions(args
.GetArgs(), result
))
1696 if (args
.GetRawPart().empty()) {
1697 result
.GetOutputStream().Printf("%s <shell-command>\n",
1698 is_alias
? "shell" : "platform shell");
1702 llvm::StringRef cmd
= args
.GetRawPart();
1704 PlatformSP
platform_sp(
1705 m_options
.m_use_host_platform
1706 ? Platform::GetHostPlatform()
1707 : GetDebugger().GetPlatformList().GetSelectedPlatform());
1710 FileSpec working_dir
{};
1714 error
= (platform_sp
->RunShellCommand(m_options
.m_shell_interpreter
, cmd
,
1715 working_dir
, &status
, &signo
,
1716 &output
, m_options
.m_timeout
));
1717 if (!output
.empty())
1718 result
.GetOutputStream().PutCString(output
);
1721 const char *signo_cstr
= Host::GetSignalAsCString(signo
);
1723 result
.GetOutputStream().Printf(
1724 "error: command returned with status %i and signal %s\n",
1725 status
, signo_cstr
);
1727 result
.GetOutputStream().Printf(
1728 "error: command returned with status %i and signal %i\n",
1731 result
.GetOutputStream().Printf(
1732 "error: command returned with status %i\n", status
);
1735 result
.GetOutputStream().Printf(
1736 "error: cannot run remote shell commands without a platform\n");
1737 error
= Status::FromErrorString(
1738 "error: cannot run remote shell commands without a platform");
1742 result
.AppendError(error
.AsCString());
1744 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1748 CommandOptions m_options
;
1751 // "platform install" - install a target to a remote end
1752 class CommandObjectPlatformInstall
: public CommandObjectParsed
{
1754 CommandObjectPlatformInstall(CommandInterpreter
&interpreter
)
1755 : CommandObjectParsed(
1756 interpreter
, "platform target-install",
1757 "Install a target (bundle or executable file) to the remote end.",
1758 "platform target-install <local-thing> <remote-sandbox>", 0) {
1759 CommandArgumentData local_arg
{eArgTypePath
, eArgRepeatPlain
};
1760 CommandArgumentData remote_arg
{eArgTypeRemotePath
, eArgRepeatPlain
};
1761 m_arguments
.push_back({local_arg
});
1762 m_arguments
.push_back({remote_arg
});
1765 ~CommandObjectPlatformInstall() override
= default;
1768 HandleArgumentCompletion(CompletionRequest
&request
,
1769 OptionElementVector
&opt_element_vector
) override
{
1770 if (request
.GetCursorIndex())
1772 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1773 GetCommandInterpreter(), lldb::eDiskFileCompletion
, request
, nullptr);
1776 void DoExecute(Args
&args
, CommandReturnObject
&result
) override
{
1777 if (args
.GetArgumentCount() != 2) {
1778 result
.AppendError("platform target-install takes two arguments");
1781 // TODO: move the bulk of this code over to the platform itself
1782 FileSpec
src(args
.GetArgumentAtIndex(0));
1783 FileSystem::Instance().Resolve(src
);
1784 FileSpec
dst(args
.GetArgumentAtIndex(1));
1785 if (!FileSystem::Instance().Exists(src
)) {
1786 result
.AppendError("source location does not exist or is not accessible");
1789 PlatformSP
platform_sp(
1790 GetDebugger().GetPlatformList().GetSelectedPlatform());
1792 result
.AppendError("no platform currently selected");
1796 Status error
= platform_sp
->Install(src
, dst
);
1797 if (error
.Success()) {
1798 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
1800 result
.AppendErrorWithFormat("install failed: %s", error
.AsCString());
1805 CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter
&interpreter
)
1806 : CommandObjectMultiword(
1807 interpreter
, "platform", "Commands to manage and create platforms.",
1808 "platform [connect|disconnect|info|list|status|select] ...") {
1809 LoadSubCommand("select",
1810 CommandObjectSP(new CommandObjectPlatformSelect(interpreter
)));
1811 LoadSubCommand("list",
1812 CommandObjectSP(new CommandObjectPlatformList(interpreter
)));
1813 LoadSubCommand("status",
1814 CommandObjectSP(new CommandObjectPlatformStatus(interpreter
)));
1815 LoadSubCommand("connect", CommandObjectSP(
1816 new CommandObjectPlatformConnect(interpreter
)));
1819 CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter
)));
1820 LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(
1822 LoadSubCommand("mkdir",
1823 CommandObjectSP(new CommandObjectPlatformMkDir(interpreter
)));
1824 LoadSubCommand("file",
1825 CommandObjectSP(new CommandObjectPlatformFile(interpreter
)));
1826 LoadSubCommand("file-exists",
1827 CommandObjectSP(new CommandObjectPlatformFileExists(interpreter
)));
1828 LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
1830 LoadSubCommand("get-permissions",
1831 CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter
)));
1832 LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
1834 LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
1836 LoadSubCommand("process", CommandObjectSP(
1837 new CommandObjectPlatformProcess(interpreter
)));
1838 LoadSubCommand("shell",
1839 CommandObjectSP(new CommandObjectPlatformShell(interpreter
)));
1842 CommandObjectSP(new CommandObjectPlatformInstall(interpreter
)));
1845 CommandObjectPlatform::~CommandObjectPlatform() = default;