1 //===-- CommandObjectPlatform.cpp -----------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "CommandObjectPlatform.h"
10 #include "CommandOptionsProcessLaunch.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/PluginManager.h"
14 #include "lldb/Host/OptionParser.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17 #include "lldb/Interpreter/CommandOptionValidators.h"
18 #include "lldb/Interpreter/CommandReturnObject.h"
19 #include "lldb/Interpreter/OptionGroupFile.h"
20 #include "lldb/Interpreter/OptionGroupPlatform.h"
21 #include "lldb/Target/ExecutionContext.h"
22 #include "lldb/Target/Platform.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Utility/Args.h"
25
26 #include "llvm/ADT/SmallString.h"
27
28 using namespace lldb;
29 using namespace lldb_private;
30
31 static mode_t ParsePermissionString(const char *) = delete;
32
ParsePermissionString(llvm::StringRef permissions)33 static mode_t ParsePermissionString(llvm::StringRef permissions) {
34 if (permissions.size() != 9)
35 return (mode_t)(-1);
36 bool user_r, user_w, user_x, group_r, group_w, group_x, world_r, world_w,
37 world_x;
38
39 user_r = (permissions[0] == 'r');
40 user_w = (permissions[1] == 'w');
41 user_x = (permissions[2] == 'x');
42
43 group_r = (permissions[3] == 'r');
44 group_w = (permissions[4] == 'w');
45 group_x = (permissions[5] == 'x');
46
47 world_r = (permissions[6] == 'r');
48 world_w = (permissions[7] == 'w');
49 world_x = (permissions[8] == 'x');
50
51 mode_t user, group, world;
52 user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
53 group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
54 world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
55
56 return user | group | world;
57 }
58
59 #define LLDB_OPTIONS_permissions
60 #include "CommandOptions.inc"
61
62 class OptionPermissions : public OptionGroup {
63 public:
64 OptionPermissions() = default;
65
66 ~OptionPermissions() override = default;
67
68 lldb_private::Status
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)69 SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
70 ExecutionContext *execution_context) override {
71 Status error;
72 char short_option = (char)GetDefinitions()[option_idx].short_option;
73 switch (short_option) {
74 case 'v': {
75 if (option_arg.getAsInteger(8, m_permissions)) {
76 m_permissions = 0777;
77 error.SetErrorStringWithFormat("invalid value for permissions: %s",
78 option_arg.str().c_str());
79 }
80
81 } break;
82 case 's': {
83 mode_t perms = ParsePermissionString(option_arg);
84 if (perms == (mode_t)-1)
85 error.SetErrorStringWithFormat("invalid value for permissions: %s",
86 option_arg.str().c_str());
87 else
88 m_permissions = perms;
89 } break;
90 case 'r':
91 m_permissions |= lldb::eFilePermissionsUserRead;
92 break;
93 case 'w':
94 m_permissions |= lldb::eFilePermissionsUserWrite;
95 break;
96 case 'x':
97 m_permissions |= lldb::eFilePermissionsUserExecute;
98 break;
99 case 'R':
100 m_permissions |= lldb::eFilePermissionsGroupRead;
101 break;
102 case 'W':
103 m_permissions |= lldb::eFilePermissionsGroupWrite;
104 break;
105 case 'X':
106 m_permissions |= lldb::eFilePermissionsGroupExecute;
107 break;
108 case 'd':
109 m_permissions |= lldb::eFilePermissionsWorldRead;
110 break;
111 case 't':
112 m_permissions |= lldb::eFilePermissionsWorldWrite;
113 break;
114 case 'e':
115 m_permissions |= lldb::eFilePermissionsWorldExecute;
116 break;
117 default:
118 llvm_unreachable("Unimplemented option");
119 }
120
121 return error;
122 }
123
OptionParsingStarting(ExecutionContext * execution_context)124 void OptionParsingStarting(ExecutionContext *execution_context) override {
125 m_permissions = 0;
126 }
127
GetDefinitions()128 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
129 return llvm::ArrayRef(g_permissions_options);
130 }
131
132 // Instance variables to hold the values for command options.
133
134 uint32_t m_permissions;
135
136 private:
137 OptionPermissions(const OptionPermissions &) = delete;
138 const OptionPermissions &operator=(const OptionPermissions &) = delete;
139 };
140
141 // "platform select <platform-name>"
142 class CommandObjectPlatformSelect : public CommandObjectParsed {
143 public:
CommandObjectPlatformSelect(CommandInterpreter & interpreter)144 CommandObjectPlatformSelect(CommandInterpreter &interpreter)
145 : CommandObjectParsed(interpreter, "platform select",
146 "Create a platform if needed and select it as the "
147 "current platform.",
148 "platform select <platform-name>", 0),
149 m_platform_options(
150 false) // Don't include the "--platform" option by passing false
151 {
152 m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
153 m_option_group.Finalize();
154 CommandArgumentData platform_arg{eArgTypePlatform, eArgRepeatPlain};
155 m_arguments.push_back({platform_arg});
156 }
157
158 ~CommandObjectPlatformSelect() override = default;
159
HandleCompletion(CompletionRequest & request)160 void HandleCompletion(CompletionRequest &request) override {
161 CommandCompletions::PlatformPluginNames(GetCommandInterpreter(), request,
162 nullptr);
163 }
164
GetOptions()165 Options *GetOptions() override { return &m_option_group; }
166
167 protected:
DoExecute(Args & args,CommandReturnObject & result)168 bool DoExecute(Args &args, CommandReturnObject &result) override {
169 if (args.GetArgumentCount() == 1) {
170 const char *platform_name = args.GetArgumentAtIndex(0);
171 if (platform_name && platform_name[0]) {
172 const bool select = true;
173 m_platform_options.SetPlatformName(platform_name);
174 Status error;
175 ArchSpec platform_arch;
176 PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(
177 m_interpreter, ArchSpec(), select, error, platform_arch));
178 if (platform_sp) {
179 GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp);
180
181 platform_sp->GetStatus(result.GetOutputStream());
182 result.SetStatus(eReturnStatusSuccessFinishResult);
183 } else {
184 result.AppendError(error.AsCString());
185 }
186 } else {
187 result.AppendError("invalid platform name");
188 }
189 } else {
190 result.AppendError(
191 "platform create takes a platform name as an argument\n");
192 }
193 return result.Succeeded();
194 }
195
196 OptionGroupOptions m_option_group;
197 OptionGroupPlatform m_platform_options;
198 };
199
200 // "platform list"
201 class CommandObjectPlatformList : public CommandObjectParsed {
202 public:
CommandObjectPlatformList(CommandInterpreter & interpreter)203 CommandObjectPlatformList(CommandInterpreter &interpreter)
204 : CommandObjectParsed(interpreter, "platform list",
205 "List all platforms that are available.", nullptr,
206 0) {}
207
208 ~CommandObjectPlatformList() override = default;
209
210 protected:
DoExecute(Args & args,CommandReturnObject & result)211 bool DoExecute(Args &args, CommandReturnObject &result) override {
212 Stream &ostrm = result.GetOutputStream();
213 ostrm.Printf("Available platforms:\n");
214
215 PlatformSP host_platform_sp(Platform::GetHostPlatform());
216 ostrm.Format("{0}: {1}\n", host_platform_sp->GetPluginName(),
217 host_platform_sp->GetDescription());
218
219 uint32_t idx;
220 for (idx = 0; true; ++idx) {
221 llvm::StringRef plugin_name =
222 PluginManager::GetPlatformPluginNameAtIndex(idx);
223 if (plugin_name.empty())
224 break;
225 llvm::StringRef plugin_desc =
226 PluginManager::GetPlatformPluginDescriptionAtIndex(idx);
227 ostrm.Format("{0}: {1}\n", plugin_name, plugin_desc);
228 }
229
230 if (idx == 0) {
231 result.AppendError("no platforms are available\n");
232 } else
233 result.SetStatus(eReturnStatusSuccessFinishResult);
234 return result.Succeeded();
235 }
236 };
237
238 // "platform status"
239 class CommandObjectPlatformStatus : public CommandObjectParsed {
240 public:
CommandObjectPlatformStatus(CommandInterpreter & interpreter)241 CommandObjectPlatformStatus(CommandInterpreter &interpreter)
242 : CommandObjectParsed(interpreter, "platform status",
243 "Display status for the current platform.", nullptr,
244 0) {}
245
246 ~CommandObjectPlatformStatus() override = default;
247
248 protected:
DoExecute(Args & args,CommandReturnObject & result)249 bool DoExecute(Args &args, CommandReturnObject &result) override {
250 Stream &ostrm = result.GetOutputStream();
251
252 Target *target = GetDebugger().GetSelectedTarget().get();
253 PlatformSP platform_sp;
254 if (target) {
255 platform_sp = target->GetPlatform();
256 }
257 if (!platform_sp) {
258 platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
259 }
260 if (platform_sp) {
261 platform_sp->GetStatus(ostrm);
262 result.SetStatus(eReturnStatusSuccessFinishResult);
263 } else {
264 result.AppendError("no platform is currently selected\n");
265 }
266 return result.Succeeded();
267 }
268 };
269
270 // "platform connect <connect-url>"
271 class CommandObjectPlatformConnect : public CommandObjectParsed {
272 public:
CommandObjectPlatformConnect(CommandInterpreter & interpreter)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 CommandArgumentData platform_arg{eArgTypeConnectURL, eArgRepeatPlain};
279 m_arguments.push_back({platform_arg});
280 }
281
282 ~CommandObjectPlatformConnect() override = default;
283
284 protected:
DoExecute(Args & args,CommandReturnObject & result)285 bool DoExecute(Args &args, CommandReturnObject &result) override {
286 Stream &ostrm = result.GetOutputStream();
287
288 PlatformSP platform_sp(
289 GetDebugger().GetPlatformList().GetSelectedPlatform());
290 if (platform_sp) {
291 Status error(platform_sp->ConnectRemote(args));
292 if (error.Success()) {
293 platform_sp->GetStatus(ostrm);
294 result.SetStatus(eReturnStatusSuccessFinishResult);
295
296 platform_sp->ConnectToWaitingProcesses(GetDebugger(), error);
297 if (error.Fail()) {
298 result.AppendError(error.AsCString());
299 }
300 } else {
301 result.AppendErrorWithFormat("%s\n", error.AsCString());
302 }
303 } else {
304 result.AppendError("no platform is currently selected\n");
305 }
306 return result.Succeeded();
307 }
308
GetOptions()309 Options *GetOptions() override {
310 PlatformSP platform_sp(
311 GetDebugger().GetPlatformList().GetSelectedPlatform());
312 OptionGroupOptions *m_platform_options = nullptr;
313 if (platform_sp) {
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();
317 }
318 return m_platform_options;
319 }
320 };
321
322 // "platform disconnect"
323 class CommandObjectPlatformDisconnect : public CommandObjectParsed {
324 public:
CommandObjectPlatformDisconnect(CommandInterpreter & interpreter)325 CommandObjectPlatformDisconnect(CommandInterpreter &interpreter)
326 : CommandObjectParsed(interpreter, "platform disconnect",
327 "Disconnect from the current platform.",
328 "platform disconnect", 0) {}
329
330 ~CommandObjectPlatformDisconnect() override = default;
331
332 protected:
DoExecute(Args & args,CommandReturnObject & result)333 bool DoExecute(Args &args, CommandReturnObject &result) override {
334 PlatformSP platform_sp(
335 GetDebugger().GetPlatformList().GetSelectedPlatform());
336 if (platform_sp) {
337 if (args.GetArgumentCount() == 0) {
338 Status error;
339
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;
345 if (hostname_cstr)
346 hostname.assign(hostname_cstr);
347
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());
354 else
355 ostrm.Printf("Disconnected from \"%s\"\n", hostname.c_str());
356 result.SetStatus(eReturnStatusSuccessFinishResult);
357 } else {
358 result.AppendErrorWithFormat("%s", error.AsCString());
359 }
360 } else {
361 // Not connected...
362 result.AppendErrorWithFormatv("not connected to '{0}'",
363 platform_sp->GetPluginName());
364 }
365 } else {
366 // Bad args
367 result.AppendError(
368 "\"platform disconnect\" doesn't take any arguments");
369 }
370 } else {
371 result.AppendError("no platform is currently selected");
372 }
373 return result.Succeeded();
374 }
375 };
376
377 // "platform settings"
378 class CommandObjectPlatformSettings : public CommandObjectParsed {
379 public:
CommandObjectPlatformSettings(CommandInterpreter & interpreter)380 CommandObjectPlatformSettings(CommandInterpreter &interpreter)
381 : CommandObjectParsed(interpreter, "platform settings",
382 "Set settings for the current target's platform.",
383 "platform settings", 0),
384 m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w',
385 CommandCompletions::eRemoteDiskDirectoryCompletion,
386 eArgTypePath,
387 "The working directory for the platform.") {
388 m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
389 }
390
391 ~CommandObjectPlatformSettings() override = default;
392
393 protected:
DoExecute(Args & args,CommandReturnObject & result)394 bool DoExecute(Args &args, CommandReturnObject &result) override {
395 PlatformSP platform_sp(
396 GetDebugger().GetPlatformList().GetSelectedPlatform());
397 if (platform_sp) {
398 if (m_option_working_dir.GetOptionValue().OptionWasSet())
399 platform_sp->SetWorkingDirectory(
400 m_option_working_dir.GetOptionValue().GetCurrentValue());
401 } else {
402 result.AppendError("no platform is currently selected");
403 }
404 return result.Succeeded();
405 }
406
GetOptions()407 Options *GetOptions() override {
408 if (!m_options.DidFinalize())
409 m_options.Finalize();
410 return &m_options;
411 }
412
413 OptionGroupOptions m_options;
414 OptionGroupFile m_option_working_dir;
415 };
416
417 // "platform mkdir"
418 class CommandObjectPlatformMkDir : public CommandObjectParsed {
419 public:
CommandObjectPlatformMkDir(CommandInterpreter & interpreter)420 CommandObjectPlatformMkDir(CommandInterpreter &interpreter)
421 : CommandObjectParsed(interpreter, "platform mkdir",
422 "Make a new directory on the remote end.", nullptr,
423 0) {
424 CommandArgumentData thread_arg{eArgTypePath, eArgRepeatPlain};
425 m_arguments.push_back({thread_arg});
426 }
427
428 ~CommandObjectPlatformMkDir() override = default;
429
DoExecute(Args & args,CommandReturnObject & result)430 bool DoExecute(Args &args, CommandReturnObject &result) override {
431 PlatformSP platform_sp(
432 GetDebugger().GetPlatformList().GetSelectedPlatform());
433 if (platform_sp) {
434 std::string cmd_line;
435 args.GetCommandString(cmd_line);
436 uint32_t mode;
437 const OptionPermissions *options_permissions =
438 (const OptionPermissions *)m_options.GetGroupWithOption('r');
439 if (options_permissions)
440 mode = options_permissions->m_permissions;
441 else
442 mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |
443 lldb::eFilePermissionsWorldRX;
444 Status error = platform_sp->MakeDirectory(FileSpec(cmd_line), mode);
445 if (error.Success()) {
446 result.SetStatus(eReturnStatusSuccessFinishResult);
447 } else {
448 result.AppendError(error.AsCString());
449 }
450 } else {
451 result.AppendError("no platform currently selected\n");
452 }
453 return result.Succeeded();
454 }
455
GetOptions()456 Options *GetOptions() override {
457 if (!m_options.DidFinalize()) {
458 m_options.Append(&m_option_permissions);
459 m_options.Finalize();
460 }
461 return &m_options;
462 }
463
464 OptionPermissions m_option_permissions;
465 OptionGroupOptions m_options;
466 };
467
468 // "platform fopen"
469 class CommandObjectPlatformFOpen : public CommandObjectParsed {
470 public:
CommandObjectPlatformFOpen(CommandInterpreter & interpreter)471 CommandObjectPlatformFOpen(CommandInterpreter &interpreter)
472 : CommandObjectParsed(interpreter, "platform file open",
473 "Open a file on the remote end.", nullptr, 0) {
474 CommandArgumentData path_arg{eArgTypePath, eArgRepeatPlain};
475 m_arguments.push_back({path_arg});
476 }
477
478 ~CommandObjectPlatformFOpen() override = default;
479
480 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)481 HandleArgumentCompletion(CompletionRequest &request,
482 OptionElementVector &opt_element_vector) override {
483 if (request.GetCursorIndex() == 0)
484 CommandCompletions::InvokeCommonCompletionCallbacks(
485 GetCommandInterpreter(),
486 CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
487 }
488
DoExecute(Args & args,CommandReturnObject & result)489 bool DoExecute(Args &args, CommandReturnObject &result) override {
490 PlatformSP platform_sp(
491 GetDebugger().GetPlatformList().GetSelectedPlatform());
492 if (platform_sp) {
493 Status error;
494 std::string cmd_line;
495 args.GetCommandString(cmd_line);
496 mode_t perms;
497 const OptionPermissions *options_permissions =
498 (const OptionPermissions *)m_options.GetGroupWithOption('r');
499 if (options_permissions)
500 perms = options_permissions->m_permissions;
501 else
502 perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW |
503 lldb::eFilePermissionsWorldRead;
504 lldb::user_id_t fd = platform_sp->OpenFile(
505 FileSpec(cmd_line),
506 File::eOpenOptionReadWrite | File::eOpenOptionCanCreate,
507 perms, error);
508 if (error.Success()) {
509 result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n", fd);
510 result.SetStatus(eReturnStatusSuccessFinishResult);
511 } else {
512 result.AppendError(error.AsCString());
513 }
514 } else {
515 result.AppendError("no platform currently selected\n");
516 }
517 return result.Succeeded();
518 }
519
GetOptions()520 Options *GetOptions() override {
521 if (!m_options.DidFinalize()) {
522 m_options.Append(&m_option_permissions);
523 m_options.Finalize();
524 }
525 return &m_options;
526 }
527
528 OptionPermissions m_option_permissions;
529 OptionGroupOptions m_options;
530 };
531
532 // "platform fclose"
533 class CommandObjectPlatformFClose : public CommandObjectParsed {
534 public:
CommandObjectPlatformFClose(CommandInterpreter & interpreter)535 CommandObjectPlatformFClose(CommandInterpreter &interpreter)
536 : CommandObjectParsed(interpreter, "platform file close",
537 "Close a file on the remote end.", nullptr, 0) {
538 CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
539 m_arguments.push_back({path_arg});
540 }
541
542 ~CommandObjectPlatformFClose() override = default;
543
DoExecute(Args & args,CommandReturnObject & result)544 bool DoExecute(Args &args, CommandReturnObject &result) override {
545 PlatformSP platform_sp(
546 GetDebugger().GetPlatformList().GetSelectedPlatform());
547 if (platform_sp) {
548 std::string cmd_line;
549 args.GetCommandString(cmd_line);
550 lldb::user_id_t fd;
551 if (!llvm::to_integer(cmd_line, fd)) {
552 result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
553 cmd_line);
554 return result.Succeeded();
555 }
556 Status error;
557 bool success = platform_sp->CloseFile(fd, error);
558 if (success) {
559 result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
560 result.SetStatus(eReturnStatusSuccessFinishResult);
561 } else {
562 result.AppendError(error.AsCString());
563 }
564 } else {
565 result.AppendError("no platform currently selected\n");
566 }
567 return result.Succeeded();
568 }
569 };
570
571 // "platform fread"
572
573 #define LLDB_OPTIONS_platform_fread
574 #include "CommandOptions.inc"
575
576 class CommandObjectPlatformFRead : public CommandObjectParsed {
577 public:
CommandObjectPlatformFRead(CommandInterpreter & interpreter)578 CommandObjectPlatformFRead(CommandInterpreter &interpreter)
579 : CommandObjectParsed(interpreter, "platform file read",
580 "Read data from a file on the remote end.", nullptr,
581 0) {
582 CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
583 m_arguments.push_back({path_arg});
584 }
585
586 ~CommandObjectPlatformFRead() override = default;
587
DoExecute(Args & args,CommandReturnObject & result)588 bool DoExecute(Args &args, CommandReturnObject &result) override {
589 PlatformSP platform_sp(
590 GetDebugger().GetPlatformList().GetSelectedPlatform());
591 if (platform_sp) {
592 std::string cmd_line;
593 args.GetCommandString(cmd_line);
594 lldb::user_id_t fd;
595 if (!llvm::to_integer(cmd_line, fd)) {
596 result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
597 cmd_line);
598 return result.Succeeded();
599 }
600 std::string buffer(m_options.m_count, 0);
601 Status error;
602 uint64_t retcode = platform_sp->ReadFile(
603 fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
604 if (retcode != UINT64_MAX) {
605 result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);
606 result.AppendMessageWithFormat("Data = \"%s\"\n", buffer.c_str());
607 result.SetStatus(eReturnStatusSuccessFinishResult);
608 } else {
609 result.AppendError(error.AsCString());
610 }
611 } else {
612 result.AppendError("no platform currently selected\n");
613 }
614 return result.Succeeded();
615 }
616
GetOptions()617 Options *GetOptions() override { return &m_options; }
618
619 protected:
620 class CommandOptions : public Options {
621 public:
622 CommandOptions() = default;
623
624 ~CommandOptions() override = default;
625
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)626 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
627 ExecutionContext *execution_context) override {
628 Status error;
629 char short_option = (char)m_getopt_table[option_idx].val;
630
631 switch (short_option) {
632 case 'o':
633 if (option_arg.getAsInteger(0, m_offset))
634 error.SetErrorStringWithFormat("invalid offset: '%s'",
635 option_arg.str().c_str());
636 break;
637 case 'c':
638 if (option_arg.getAsInteger(0, m_count))
639 error.SetErrorStringWithFormat("invalid offset: '%s'",
640 option_arg.str().c_str());
641 break;
642 default:
643 llvm_unreachable("Unimplemented option");
644 }
645
646 return error;
647 }
648
OptionParsingStarting(ExecutionContext * execution_context)649 void OptionParsingStarting(ExecutionContext *execution_context) override {
650 m_offset = 0;
651 m_count = 1;
652 }
653
GetDefinitions()654 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
655 return llvm::ArrayRef(g_platform_fread_options);
656 }
657
658 // Instance variables to hold the values for command options.
659
660 uint32_t m_offset;
661 uint32_t m_count;
662 };
663
664 CommandOptions m_options;
665 };
666
667 // "platform fwrite"
668
669 #define LLDB_OPTIONS_platform_fwrite
670 #include "CommandOptions.inc"
671
672 class CommandObjectPlatformFWrite : public CommandObjectParsed {
673 public:
CommandObjectPlatformFWrite(CommandInterpreter & interpreter)674 CommandObjectPlatformFWrite(CommandInterpreter &interpreter)
675 : CommandObjectParsed(interpreter, "platform file write",
676 "Write data to a file on the remote end.", nullptr,
677 0) {
678 CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
679 m_arguments.push_back({path_arg});
680 }
681
682 ~CommandObjectPlatformFWrite() override = default;
683
DoExecute(Args & args,CommandReturnObject & result)684 bool DoExecute(Args &args, CommandReturnObject &result) override {
685 PlatformSP platform_sp(
686 GetDebugger().GetPlatformList().GetSelectedPlatform());
687 if (platform_sp) {
688 std::string cmd_line;
689 args.GetCommandString(cmd_line);
690 Status error;
691 lldb::user_id_t fd;
692 if (!llvm::to_integer(cmd_line, fd)) {
693 result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.",
694 cmd_line);
695 return result.Succeeded();
696 }
697 uint64_t retcode =
698 platform_sp->WriteFile(fd, m_options.m_offset, &m_options.m_data[0],
699 m_options.m_data.size(), error);
700 if (retcode != UINT64_MAX) {
701 result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);
702 result.SetStatus(eReturnStatusSuccessFinishResult);
703 } else {
704 result.AppendError(error.AsCString());
705 }
706 } else {
707 result.AppendError("no platform currently selected\n");
708 }
709 return result.Succeeded();
710 }
711
GetOptions()712 Options *GetOptions() override { return &m_options; }
713
714 protected:
715 class CommandOptions : public Options {
716 public:
717 CommandOptions() = default;
718
719 ~CommandOptions() override = default;
720
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)721 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
722 ExecutionContext *execution_context) override {
723 Status error;
724 char short_option = (char)m_getopt_table[option_idx].val;
725
726 switch (short_option) {
727 case 'o':
728 if (option_arg.getAsInteger(0, m_offset))
729 error.SetErrorStringWithFormat("invalid offset: '%s'",
730 option_arg.str().c_str());
731 break;
732 case 'd':
733 m_data.assign(std::string(option_arg));
734 break;
735 default:
736 llvm_unreachable("Unimplemented option");
737 }
738
739 return error;
740 }
741
OptionParsingStarting(ExecutionContext * execution_context)742 void OptionParsingStarting(ExecutionContext *execution_context) override {
743 m_offset = 0;
744 m_data.clear();
745 }
746
GetDefinitions()747 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
748 return llvm::ArrayRef(g_platform_fwrite_options);
749 }
750
751 // Instance variables to hold the values for command options.
752
753 uint32_t m_offset;
754 std::string m_data;
755 };
756
757 CommandOptions m_options;
758 };
759
760 class CommandObjectPlatformFile : public CommandObjectMultiword {
761 public:
762 // Constructors and Destructors
CommandObjectPlatformFile(CommandInterpreter & interpreter)763 CommandObjectPlatformFile(CommandInterpreter &interpreter)
764 : CommandObjectMultiword(
765 interpreter, "platform file",
766 "Commands to access files on the current platform.",
767 "platform file [open|close|read|write] ...") {
768 LoadSubCommand(
769 "open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter)));
770 LoadSubCommand(
771 "close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter)));
772 LoadSubCommand(
773 "read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter)));
774 LoadSubCommand(
775 "write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter)));
776 }
777
778 ~CommandObjectPlatformFile() override = default;
779
780 private:
781 // For CommandObjectPlatform only
782 CommandObjectPlatformFile(const CommandObjectPlatformFile &) = delete;
783 const CommandObjectPlatformFile &
784 operator=(const CommandObjectPlatformFile &) = delete;
785 };
786
787 // "platform get-file remote-file-path host-file-path"
788 class CommandObjectPlatformGetFile : public CommandObjectParsed {
789 public:
CommandObjectPlatformGetFile(CommandInterpreter & interpreter)790 CommandObjectPlatformGetFile(CommandInterpreter &interpreter)
791 : CommandObjectParsed(
792 interpreter, "platform get-file",
793 "Transfer a file from the remote end to the local host.",
794 "platform get-file <remote-file-spec> <local-file-spec>", 0) {
795 SetHelpLong(
796 R"(Examples:
797
798 (lldb) platform get-file /the/remote/file/path /the/local/file/path
799
800 Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");
801
802 CommandArgumentEntry arg1, arg2;
803 CommandArgumentData file_arg_remote, file_arg_host;
804
805 // Define the first (and only) variant of this arg.
806 file_arg_remote.arg_type = eArgTypeFilename;
807 file_arg_remote.arg_repetition = eArgRepeatPlain;
808 // There is only one variant this argument could be; put it into the
809 // argument entry.
810 arg1.push_back(file_arg_remote);
811
812 // Define the second (and only) variant of this arg.
813 file_arg_host.arg_type = eArgTypeFilename;
814 file_arg_host.arg_repetition = eArgRepeatPlain;
815 // There is only one variant this argument could be; put it into the
816 // argument entry.
817 arg2.push_back(file_arg_host);
818
819 // Push the data for the first and the second arguments into the
820 // m_arguments vector.
821 m_arguments.push_back(arg1);
822 m_arguments.push_back(arg2);
823 }
824
825 ~CommandObjectPlatformGetFile() override = default;
826
827 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)828 HandleArgumentCompletion(CompletionRequest &request,
829 OptionElementVector &opt_element_vector) override {
830 if (request.GetCursorIndex() == 0)
831 CommandCompletions::InvokeCommonCompletionCallbacks(
832 GetCommandInterpreter(),
833 CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
834 else if (request.GetCursorIndex() == 1)
835 CommandCompletions::InvokeCommonCompletionCallbacks(
836 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
837 request, nullptr);
838 }
839
DoExecute(Args & args,CommandReturnObject & result)840 bool DoExecute(Args &args, CommandReturnObject &result) override {
841 // If the number of arguments is incorrect, issue an error message.
842 if (args.GetArgumentCount() != 2) {
843 result.AppendError("required arguments missing; specify both the "
844 "source and destination file paths");
845 return false;
846 }
847
848 PlatformSP platform_sp(
849 GetDebugger().GetPlatformList().GetSelectedPlatform());
850 if (platform_sp) {
851 const char *remote_file_path = args.GetArgumentAtIndex(0);
852 const char *local_file_path = args.GetArgumentAtIndex(1);
853 Status error = platform_sp->GetFile(FileSpec(remote_file_path),
854 FileSpec(local_file_path));
855 if (error.Success()) {
856 result.AppendMessageWithFormat(
857 "successfully get-file from %s (remote) to %s (host)\n",
858 remote_file_path, local_file_path);
859 result.SetStatus(eReturnStatusSuccessFinishResult);
860 } else {
861 result.AppendMessageWithFormat("get-file failed: %s\n",
862 error.AsCString());
863 }
864 } else {
865 result.AppendError("no platform currently selected\n");
866 }
867 return result.Succeeded();
868 }
869 };
870
871 // "platform get-size remote-file-path"
872 class CommandObjectPlatformGetSize : public CommandObjectParsed {
873 public:
CommandObjectPlatformGetSize(CommandInterpreter & interpreter)874 CommandObjectPlatformGetSize(CommandInterpreter &interpreter)
875 : CommandObjectParsed(interpreter, "platform get-size",
876 "Get the file size from the remote end.",
877 "platform get-size <remote-file-spec>", 0) {
878 SetHelpLong(
879 R"(Examples:
880
881 (lldb) platform get-size /the/remote/file/path
882
883 Get the file size from the remote end with path /the/remote/file/path.)");
884
885 CommandArgumentEntry arg1;
886 CommandArgumentData file_arg_remote;
887
888 // Define the first (and only) variant of this arg.
889 file_arg_remote.arg_type = eArgTypeFilename;
890 file_arg_remote.arg_repetition = eArgRepeatPlain;
891 // There is only one variant this argument could be; put it into the
892 // argument entry.
893 arg1.push_back(file_arg_remote);
894
895 // Push the data for the first argument into the m_arguments vector.
896 m_arguments.push_back(arg1);
897 }
898
899 ~CommandObjectPlatformGetSize() override = default;
900
901 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)902 HandleArgumentCompletion(CompletionRequest &request,
903 OptionElementVector &opt_element_vector) override {
904 if (request.GetCursorIndex() != 0)
905 return;
906
907 CommandCompletions::InvokeCommonCompletionCallbacks(
908 GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
909 request, nullptr);
910 }
911
DoExecute(Args & args,CommandReturnObject & result)912 bool 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");
917 return false;
918 }
919
920 PlatformSP platform_sp(
921 GetDebugger().GetPlatformList().GetSelectedPlatform());
922 if (platform_sp) {
923 std::string remote_file_path(args.GetArgumentAtIndex(0));
924 user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path));
925 if (size != UINT64_MAX) {
926 result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64
927 "\n",
928 remote_file_path.c_str(), size);
929 result.SetStatus(eReturnStatusSuccessFinishResult);
930 } else {
931 result.AppendMessageWithFormat(
932 "Error getting file size of %s (remote)\n",
933 remote_file_path.c_str());
934 }
935 } else {
936 result.AppendError("no platform currently selected\n");
937 }
938 return result.Succeeded();
939 }
940 };
941
942 // "platform get-permissions remote-file-path"
943 class CommandObjectPlatformGetPermissions : public CommandObjectParsed {
944 public:
CommandObjectPlatformGetPermissions(CommandInterpreter & interpreter)945 CommandObjectPlatformGetPermissions(CommandInterpreter &interpreter)
946 : CommandObjectParsed(interpreter, "platform get-permissions",
947 "Get the file permission bits from the remote end.",
948 "platform get-permissions <remote-file-spec>", 0) {
949 SetHelpLong(
950 R"(Examples:
951
952 (lldb) platform get-permissions /the/remote/file/path
953
954 Get the file permissions from the remote end with path /the/remote/file/path.)");
955
956 CommandArgumentEntry arg1;
957 CommandArgumentData file_arg_remote;
958
959 // Define the first (and only) variant of this arg.
960 file_arg_remote.arg_type = eArgTypeFilename;
961 file_arg_remote.arg_repetition = eArgRepeatPlain;
962 // There is only one variant this argument could be; put it into the
963 // argument entry.
964 arg1.push_back(file_arg_remote);
965
966 // Push the data for the first argument into the m_arguments vector.
967 m_arguments.push_back(arg1);
968 }
969
970 ~CommandObjectPlatformGetPermissions() override = default;
971
972 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)973 HandleArgumentCompletion(CompletionRequest &request,
974 OptionElementVector &opt_element_vector) override {
975 if (request.GetCursorIndex() != 0)
976 return;
977
978 CommandCompletions::InvokeCommonCompletionCallbacks(
979 GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
980 request, nullptr);
981 }
982
DoExecute(Args & args,CommandReturnObject & result)983 bool DoExecute(Args &args, CommandReturnObject &result) override {
984 // If the number of arguments is incorrect, issue an error message.
985 if (args.GetArgumentCount() != 1) {
986 result.AppendError("required argument missing; specify the source file "
987 "path as the only argument");
988 return false;
989 }
990
991 PlatformSP platform_sp(
992 GetDebugger().GetPlatformList().GetSelectedPlatform());
993 if (platform_sp) {
994 std::string remote_file_path(args.GetArgumentAtIndex(0));
995 uint32_t permissions;
996 Status error = platform_sp->GetFilePermissions(FileSpec(remote_file_path),
997 permissions);
998 if (error.Success()) {
999 result.AppendMessageWithFormat(
1000 "File permissions of %s (remote): 0o%04" PRIo32 "\n",
1001 remote_file_path.c_str(), permissions);
1002 result.SetStatus(eReturnStatusSuccessFinishResult);
1003 } else
1004 result.AppendError(error.AsCString());
1005 } else {
1006 result.AppendError("no platform currently selected\n");
1007 }
1008 return result.Succeeded();
1009 }
1010 };
1011
1012 // "platform file-exists remote-file-path"
1013 class CommandObjectPlatformFileExists : public CommandObjectParsed {
1014 public:
CommandObjectPlatformFileExists(CommandInterpreter & interpreter)1015 CommandObjectPlatformFileExists(CommandInterpreter &interpreter)
1016 : CommandObjectParsed(interpreter, "platform file-exists",
1017 "Check if the file exists on the remote end.",
1018 "platform file-exists <remote-file-spec>", 0) {
1019 SetHelpLong(
1020 R"(Examples:
1021
1022 (lldb) platform file-exists /the/remote/file/path
1023
1024 Check if /the/remote/file/path exists on the remote end.)");
1025
1026 CommandArgumentEntry arg1;
1027 CommandArgumentData file_arg_remote;
1028
1029 // Define the first (and only) variant of this arg.
1030 file_arg_remote.arg_type = eArgTypeFilename;
1031 file_arg_remote.arg_repetition = eArgRepeatPlain;
1032 // There is only one variant this argument could be; put it into the
1033 // argument entry.
1034 arg1.push_back(file_arg_remote);
1035
1036 // Push the data for the first argument into the m_arguments vector.
1037 m_arguments.push_back(arg1);
1038 }
1039
1040 ~CommandObjectPlatformFileExists() override = default;
1041
1042 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1043 HandleArgumentCompletion(CompletionRequest &request,
1044 OptionElementVector &opt_element_vector) override {
1045 if (request.GetCursorIndex() != 0)
1046 return;
1047
1048 CommandCompletions::InvokeCommonCompletionCallbacks(
1049 GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion,
1050 request, nullptr);
1051 }
1052
DoExecute(Args & args,CommandReturnObject & result)1053 bool DoExecute(Args &args, CommandReturnObject &result) override {
1054 // If the number of arguments is incorrect, issue an error message.
1055 if (args.GetArgumentCount() != 1) {
1056 result.AppendError("required argument missing; specify the source file "
1057 "path as the only argument");
1058 return false;
1059 }
1060
1061 PlatformSP platform_sp(
1062 GetDebugger().GetPlatformList().GetSelectedPlatform());
1063 if (platform_sp) {
1064 std::string remote_file_path(args.GetArgumentAtIndex(0));
1065 bool exists = platform_sp->GetFileExists(FileSpec(remote_file_path));
1066 result.AppendMessageWithFormat(
1067 "File %s (remote) %s\n",
1068 remote_file_path.c_str(), exists ? "exists" : "does not exist");
1069 result.SetStatus(eReturnStatusSuccessFinishResult);
1070 } else {
1071 result.AppendError("no platform currently selected\n");
1072 }
1073 return result.Succeeded();
1074 }
1075 };
1076
1077 // "platform put-file"
1078 class CommandObjectPlatformPutFile : public CommandObjectParsed {
1079 public:
CommandObjectPlatformPutFile(CommandInterpreter & interpreter)1080 CommandObjectPlatformPutFile(CommandInterpreter &interpreter)
1081 : CommandObjectParsed(
1082 interpreter, "platform put-file",
1083 "Transfer a file from this system to the remote end.",
1084 "platform put-file <source> [<destination>]", 0) {
1085 SetHelpLong(
1086 R"(Examples:
1087
1088 (lldb) platform put-file /source/foo.txt /destination/bar.txt
1089
1090 (lldb) platform put-file /source/foo.txt
1091
1092 Relative source file paths are resolved against lldb's local working directory.
1093
1094 Omitting the destination places the file in the platform working directory.)");
1095 CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain};
1096 CommandArgumentData path_arg{eArgTypePath, eArgRepeatOptional};
1097 m_arguments.push_back({source_arg});
1098 m_arguments.push_back({path_arg});
1099 }
1100
1101 ~CommandObjectPlatformPutFile() override = default;
1102
1103 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1104 HandleArgumentCompletion(CompletionRequest &request,
1105 OptionElementVector &opt_element_vector) override {
1106 if (request.GetCursorIndex() == 0)
1107 CommandCompletions::InvokeCommonCompletionCallbacks(
1108 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1109 request, nullptr);
1110 else if (request.GetCursorIndex() == 1)
1111 CommandCompletions::InvokeCommonCompletionCallbacks(
1112 GetCommandInterpreter(),
1113 CommandCompletions::eRemoteDiskFileCompletion, request, nullptr);
1114 }
1115
DoExecute(Args & args,CommandReturnObject & result)1116 bool DoExecute(Args &args, CommandReturnObject &result) override {
1117 const char *src = args.GetArgumentAtIndex(0);
1118 const char *dst = args.GetArgumentAtIndex(1);
1119
1120 FileSpec src_fs(src);
1121 FileSystem::Instance().Resolve(src_fs);
1122 FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString());
1123
1124 PlatformSP platform_sp(
1125 GetDebugger().GetPlatformList().GetSelectedPlatform());
1126 if (platform_sp) {
1127 Status error(platform_sp->PutFile(src_fs, dst_fs));
1128 if (error.Success()) {
1129 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1130 } else {
1131 result.AppendError(error.AsCString());
1132 }
1133 } else {
1134 result.AppendError("no platform currently selected\n");
1135 }
1136 return result.Succeeded();
1137 }
1138 };
1139
1140 // "platform process launch"
1141 class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {
1142 public:
CommandObjectPlatformProcessLaunch(CommandInterpreter & interpreter)1143 CommandObjectPlatformProcessLaunch(CommandInterpreter &interpreter)
1144 : CommandObjectParsed(interpreter, "platform process launch",
1145 "Launch a new process on a remote platform.",
1146 "platform process launch program",
1147 eCommandRequiresTarget | eCommandTryTargetAPILock) {
1148 m_all_options.Append(&m_options);
1149 m_all_options.Finalize();
1150 CommandArgumentData run_arg_arg{eArgTypeRunArgs, eArgRepeatStar};
1151 m_arguments.push_back({run_arg_arg});
1152 }
1153
1154 ~CommandObjectPlatformProcessLaunch() override = default;
1155
GetOptions()1156 Options *GetOptions() override { return &m_all_options; }
1157
1158 protected:
DoExecute(Args & args,CommandReturnObject & result)1159 bool DoExecute(Args &args, CommandReturnObject &result) override {
1160 Target *target = GetDebugger().GetSelectedTarget().get();
1161 PlatformSP platform_sp;
1162 if (target) {
1163 platform_sp = target->GetPlatform();
1164 }
1165 if (!platform_sp) {
1166 platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1167 }
1168
1169 if (platform_sp) {
1170 Status error;
1171 const size_t argc = args.GetArgumentCount();
1172 Target *target = m_exe_ctx.GetTargetPtr();
1173 Module *exe_module = target->GetExecutableModulePointer();
1174 if (exe_module) {
1175 m_options.launch_info.GetExecutableFile() = exe_module->GetFileSpec();
1176 llvm::SmallString<128> exe_path;
1177 m_options.launch_info.GetExecutableFile().GetPath(exe_path);
1178 if (!exe_path.empty())
1179 m_options.launch_info.GetArguments().AppendArgument(exe_path);
1180 m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
1181 }
1182
1183 if (argc > 0) {
1184 if (m_options.launch_info.GetExecutableFile()) {
1185 // We already have an executable file, so we will use this and all
1186 // arguments to this function are extra arguments
1187 m_options.launch_info.GetArguments().AppendArguments(args);
1188 } else {
1189 // We don't have any file yet, so the first argument is our
1190 // executable, and the rest are program arguments
1191 const bool first_arg_is_executable = true;
1192 m_options.launch_info.SetArguments(args, first_arg_is_executable);
1193 }
1194 }
1195
1196 if (m_options.launch_info.GetExecutableFile()) {
1197 Debugger &debugger = GetDebugger();
1198
1199 if (argc == 0)
1200 target->GetRunArguments(m_options.launch_info.GetArguments());
1201
1202 ProcessSP process_sp(platform_sp->DebugProcess(
1203 m_options.launch_info, debugger, *target, error));
1204 if (process_sp && process_sp->IsAlive()) {
1205 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1206 return true;
1207 }
1208
1209 if (error.Success())
1210 result.AppendError("process launch failed");
1211 else
1212 result.AppendError(error.AsCString());
1213 } else {
1214 result.AppendError("'platform process launch' uses the current target "
1215 "file and arguments, or the executable and its "
1216 "arguments can be specified in this command");
1217 return false;
1218 }
1219 } else {
1220 result.AppendError("no platform is selected\n");
1221 }
1222 return result.Succeeded();
1223 }
1224
1225 CommandOptionsProcessLaunch m_options;
1226 OptionGroupOptions m_all_options;
1227 };
1228
1229 // "platform process list"
1230
1231 static PosixPlatformCommandOptionValidator posix_validator;
1232 #define LLDB_OPTIONS_platform_process_list
1233 #include "CommandOptions.inc"
1234
1235 class CommandObjectPlatformProcessList : public CommandObjectParsed {
1236 public:
CommandObjectPlatformProcessList(CommandInterpreter & interpreter)1237 CommandObjectPlatformProcessList(CommandInterpreter &interpreter)
1238 : CommandObjectParsed(interpreter, "platform process list",
1239 "List processes on a remote platform by name, pid, "
1240 "or many other matching attributes.",
1241 "platform process list", 0) {}
1242
1243 ~CommandObjectPlatformProcessList() override = default;
1244
GetOptions()1245 Options *GetOptions() override { return &m_options; }
1246
1247 protected:
DoExecute(Args & args,CommandReturnObject & result)1248 bool DoExecute(Args &args, CommandReturnObject &result) override {
1249 Target *target = GetDebugger().GetSelectedTarget().get();
1250 PlatformSP platform_sp;
1251 if (target) {
1252 platform_sp = target->GetPlatform();
1253 }
1254 if (!platform_sp) {
1255 platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1256 }
1257
1258 if (platform_sp) {
1259 Status error;
1260 if (platform_sp) {
1261 Stream &ostrm = result.GetOutputStream();
1262
1263 lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
1264 if (pid != LLDB_INVALID_PROCESS_ID) {
1265 ProcessInstanceInfo proc_info;
1266 if (platform_sp->GetProcessInfo(pid, proc_info)) {
1267 ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1268 m_options.verbose);
1269 proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
1270 m_options.show_args, m_options.verbose);
1271 result.SetStatus(eReturnStatusSuccessFinishResult);
1272 } else {
1273 result.AppendErrorWithFormat(
1274 "no process found with pid = %" PRIu64 "\n", pid);
1275 }
1276 } else {
1277 ProcessInstanceInfoList proc_infos;
1278 const uint32_t matches =
1279 platform_sp->FindProcesses(m_options.match_info, proc_infos);
1280 const char *match_desc = nullptr;
1281 const char *match_name =
1282 m_options.match_info.GetProcessInfo().GetName();
1283 if (match_name && match_name[0]) {
1284 switch (m_options.match_info.GetNameMatchType()) {
1285 case NameMatch::Ignore:
1286 break;
1287 case NameMatch::Equals:
1288 match_desc = "matched";
1289 break;
1290 case NameMatch::Contains:
1291 match_desc = "contained";
1292 break;
1293 case NameMatch::StartsWith:
1294 match_desc = "started with";
1295 break;
1296 case NameMatch::EndsWith:
1297 match_desc = "ended with";
1298 break;
1299 case NameMatch::RegularExpression:
1300 match_desc = "matched the regular expression";
1301 break;
1302 }
1303 }
1304
1305 if (matches == 0) {
1306 if (match_desc)
1307 result.AppendErrorWithFormatv(
1308 "no processes were found that {0} \"{1}\" on the \"{2}\" "
1309 "platform\n",
1310 match_desc, match_name, platform_sp->GetName());
1311 else
1312 result.AppendErrorWithFormatv(
1313 "no processes were found on the \"{0}\" platform\n",
1314 platform_sp->GetName());
1315 } else {
1316 result.AppendMessageWithFormatv(
1317 "{0} matching process{1} found on \"{2}\"", matches,
1318 matches > 1 ? "es were" : " was", platform_sp->GetName());
1319 if (match_desc)
1320 result.AppendMessageWithFormat(" whose name %s \"%s\"",
1321 match_desc, match_name);
1322 result.AppendMessageWithFormat("\n");
1323 ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1324 m_options.verbose);
1325 for (uint32_t i = 0; i < matches; ++i) {
1326 proc_infos[i].DumpAsTableRow(
1327 ostrm, platform_sp->GetUserIDResolver(), m_options.show_args,
1328 m_options.verbose);
1329 }
1330 }
1331 }
1332 }
1333 } else {
1334 result.AppendError("no platform is selected\n");
1335 }
1336 return result.Succeeded();
1337 }
1338
1339 class CommandOptions : public Options {
1340 public:
1341 CommandOptions() = default;
1342
1343 ~CommandOptions() override = default;
1344
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1345 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1346 ExecutionContext *execution_context) override {
1347 Status error;
1348 const int short_option = m_getopt_table[option_idx].val;
1349 bool success = false;
1350
1351 uint32_t id = LLDB_INVALID_PROCESS_ID;
1352 success = !option_arg.getAsInteger(0, id);
1353 switch (short_option) {
1354 case 'p': {
1355 match_info.GetProcessInfo().SetProcessID(id);
1356 if (!success)
1357 error.SetErrorStringWithFormat("invalid process ID string: '%s'",
1358 option_arg.str().c_str());
1359 break;
1360 }
1361 case 'P':
1362 match_info.GetProcessInfo().SetParentProcessID(id);
1363 if (!success)
1364 error.SetErrorStringWithFormat(
1365 "invalid parent process ID string: '%s'",
1366 option_arg.str().c_str());
1367 break;
1368
1369 case 'u':
1370 match_info.GetProcessInfo().SetUserID(success ? id : UINT32_MAX);
1371 if (!success)
1372 error.SetErrorStringWithFormat("invalid user ID string: '%s'",
1373 option_arg.str().c_str());
1374 break;
1375
1376 case 'U':
1377 match_info.GetProcessInfo().SetEffectiveUserID(success ? id
1378 : UINT32_MAX);
1379 if (!success)
1380 error.SetErrorStringWithFormat(
1381 "invalid effective user ID string: '%s'",
1382 option_arg.str().c_str());
1383 break;
1384
1385 case 'g':
1386 match_info.GetProcessInfo().SetGroupID(success ? id : UINT32_MAX);
1387 if (!success)
1388 error.SetErrorStringWithFormat("invalid group ID string: '%s'",
1389 option_arg.str().c_str());
1390 break;
1391
1392 case 'G':
1393 match_info.GetProcessInfo().SetEffectiveGroupID(success ? id
1394 : UINT32_MAX);
1395 if (!success)
1396 error.SetErrorStringWithFormat(
1397 "invalid effective group ID string: '%s'",
1398 option_arg.str().c_str());
1399 break;
1400
1401 case 'a': {
1402 TargetSP target_sp =
1403 execution_context ? execution_context->GetTargetSP() : TargetSP();
1404 DebuggerSP debugger_sp =
1405 target_sp ? target_sp->GetDebugger().shared_from_this()
1406 : DebuggerSP();
1407 PlatformSP platform_sp =
1408 debugger_sp ? debugger_sp->GetPlatformList().GetSelectedPlatform()
1409 : PlatformSP();
1410 match_info.GetProcessInfo().GetArchitecture() =
1411 Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg);
1412 } break;
1413
1414 case 'n':
1415 match_info.GetProcessInfo().GetExecutableFile().SetFile(
1416 option_arg, FileSpec::Style::native);
1417 match_info.SetNameMatchType(NameMatch::Equals);
1418 break;
1419
1420 case 'e':
1421 match_info.GetProcessInfo().GetExecutableFile().SetFile(
1422 option_arg, FileSpec::Style::native);
1423 match_info.SetNameMatchType(NameMatch::EndsWith);
1424 break;
1425
1426 case 's':
1427 match_info.GetProcessInfo().GetExecutableFile().SetFile(
1428 option_arg, FileSpec::Style::native);
1429 match_info.SetNameMatchType(NameMatch::StartsWith);
1430 break;
1431
1432 case 'c':
1433 match_info.GetProcessInfo().GetExecutableFile().SetFile(
1434 option_arg, FileSpec::Style::native);
1435 match_info.SetNameMatchType(NameMatch::Contains);
1436 break;
1437
1438 case 'r':
1439 match_info.GetProcessInfo().GetExecutableFile().SetFile(
1440 option_arg, FileSpec::Style::native);
1441 match_info.SetNameMatchType(NameMatch::RegularExpression);
1442 break;
1443
1444 case 'A':
1445 show_args = true;
1446 break;
1447
1448 case 'v':
1449 verbose = true;
1450 break;
1451
1452 case 'x':
1453 match_info.SetMatchAllUsers(true);
1454 break;
1455
1456 default:
1457 llvm_unreachable("Unimplemented option");
1458 }
1459
1460 return error;
1461 }
1462
OptionParsingStarting(ExecutionContext * execution_context)1463 void OptionParsingStarting(ExecutionContext *execution_context) override {
1464 match_info.Clear();
1465 show_args = false;
1466 verbose = false;
1467 }
1468
GetDefinitions()1469 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1470 return llvm::ArrayRef(g_platform_process_list_options);
1471 }
1472
1473 // Instance variables to hold the values for command options.
1474
1475 ProcessInstanceInfoMatch match_info;
1476 bool show_args = false;
1477 bool verbose = false;
1478 };
1479
1480 CommandOptions m_options;
1481 };
1482
1483 // "platform process info"
1484 class CommandObjectPlatformProcessInfo : public CommandObjectParsed {
1485 public:
CommandObjectPlatformProcessInfo(CommandInterpreter & interpreter)1486 CommandObjectPlatformProcessInfo(CommandInterpreter &interpreter)
1487 : CommandObjectParsed(
1488 interpreter, "platform process info",
1489 "Get detailed information for one or more process by process ID.",
1490 "platform process info <pid> [<pid> <pid> ...]", 0) {
1491 CommandArgumentEntry arg;
1492 CommandArgumentData pid_args;
1493
1494 // Define the first (and only) variant of this arg.
1495 pid_args.arg_type = eArgTypePid;
1496 pid_args.arg_repetition = eArgRepeatStar;
1497
1498 // There is only one variant this argument could be; put it into the
1499 // argument entry.
1500 arg.push_back(pid_args);
1501
1502 // Push the data for the first argument into the m_arguments vector.
1503 m_arguments.push_back(arg);
1504 }
1505
1506 ~CommandObjectPlatformProcessInfo() override = default;
1507
1508 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1509 HandleArgumentCompletion(CompletionRequest &request,
1510 OptionElementVector &opt_element_vector) override {
1511 CommandCompletions::InvokeCommonCompletionCallbacks(
1512 GetCommandInterpreter(), CommandCompletions::eProcessIDCompletion,
1513 request, nullptr);
1514 }
1515
1516 protected:
DoExecute(Args & args,CommandReturnObject & result)1517 bool DoExecute(Args &args, CommandReturnObject &result) override {
1518 Target *target = GetDebugger().GetSelectedTarget().get();
1519 PlatformSP platform_sp;
1520 if (target) {
1521 platform_sp = target->GetPlatform();
1522 }
1523 if (!platform_sp) {
1524 platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1525 }
1526
1527 if (platform_sp) {
1528 const size_t argc = args.GetArgumentCount();
1529 if (argc > 0) {
1530 Status error;
1531
1532 if (platform_sp->IsConnected()) {
1533 Stream &ostrm = result.GetOutputStream();
1534 for (auto &entry : args.entries()) {
1535 lldb::pid_t pid;
1536 if (entry.ref().getAsInteger(0, pid)) {
1537 result.AppendErrorWithFormat("invalid process ID argument '%s'",
1538 entry.ref().str().c_str());
1539 break;
1540 } else {
1541 ProcessInstanceInfo proc_info;
1542 if (platform_sp->GetProcessInfo(pid, proc_info)) {
1543 ostrm.Printf("Process information for process %" PRIu64 ":\n",
1544 pid);
1545 proc_info.Dump(ostrm, platform_sp->GetUserIDResolver());
1546 } else {
1547 ostrm.Printf("error: no process information is available for "
1548 "process %" PRIu64 "\n",
1549 pid);
1550 }
1551 ostrm.EOL();
1552 }
1553 }
1554 } else {
1555 // Not connected...
1556 result.AppendErrorWithFormatv("not connected to '{0}'",
1557 platform_sp->GetPluginName());
1558 }
1559 } else {
1560 // No args
1561 result.AppendError("one or more process id(s) must be specified");
1562 }
1563 } else {
1564 result.AppendError("no platform is currently selected");
1565 }
1566 return result.Succeeded();
1567 }
1568 };
1569
1570 #define LLDB_OPTIONS_platform_process_attach
1571 #include "CommandOptions.inc"
1572
1573 class CommandObjectPlatformProcessAttach : public CommandObjectParsed {
1574 public:
1575 class CommandOptions : public Options {
1576 public:
CommandOptions()1577 CommandOptions() {
1578 // Keep default values of all options in one place: OptionParsingStarting
1579 // ()
1580 OptionParsingStarting(nullptr);
1581 }
1582
1583 ~CommandOptions() override = default;
1584
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1585 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1586 ExecutionContext *execution_context) override {
1587 Status error;
1588 char short_option = (char)m_getopt_table[option_idx].val;
1589 switch (short_option) {
1590 case 'p': {
1591 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
1592 if (option_arg.getAsInteger(0, pid)) {
1593 error.SetErrorStringWithFormat("invalid process ID '%s'",
1594 option_arg.str().c_str());
1595 } else {
1596 attach_info.SetProcessID(pid);
1597 }
1598 } break;
1599
1600 case 'P':
1601 attach_info.SetProcessPluginName(option_arg);
1602 break;
1603
1604 case 'n':
1605 attach_info.GetExecutableFile().SetFile(option_arg,
1606 FileSpec::Style::native);
1607 break;
1608
1609 case 'w':
1610 attach_info.SetWaitForLaunch(true);
1611 break;
1612
1613 default:
1614 llvm_unreachable("Unimplemented option");
1615 }
1616 return error;
1617 }
1618
OptionParsingStarting(ExecutionContext * execution_context)1619 void OptionParsingStarting(ExecutionContext *execution_context) override {
1620 attach_info.Clear();
1621 }
1622
GetDefinitions()1623 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1624 return llvm::ArrayRef(g_platform_process_attach_options);
1625 }
1626
1627 // Options table: Required for subclasses of Options.
1628
1629 static OptionDefinition g_option_table[];
1630
1631 // Instance variables to hold the values for command options.
1632
1633 ProcessAttachInfo attach_info;
1634 };
1635
CommandObjectPlatformProcessAttach(CommandInterpreter & interpreter)1636 CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter)
1637 : CommandObjectParsed(interpreter, "platform process attach",
1638 "Attach to a process.",
1639 "platform process attach <cmd-options>") {}
1640
1641 ~CommandObjectPlatformProcessAttach() override = default;
1642
DoExecute(Args & command,CommandReturnObject & result)1643 bool DoExecute(Args &command, CommandReturnObject &result) override {
1644 PlatformSP platform_sp(
1645 GetDebugger().GetPlatformList().GetSelectedPlatform());
1646 if (platform_sp) {
1647 Status err;
1648 ProcessSP remote_process_sp = platform_sp->Attach(
1649 m_options.attach_info, GetDebugger(), nullptr, err);
1650 if (err.Fail()) {
1651 result.AppendError(err.AsCString());
1652 } else if (!remote_process_sp) {
1653 result.AppendError("could not attach: unknown reason");
1654 } else
1655 result.SetStatus(eReturnStatusSuccessFinishResult);
1656 } else {
1657 result.AppendError("no platform is currently selected");
1658 }
1659 return result.Succeeded();
1660 }
1661
GetOptions()1662 Options *GetOptions() override { return &m_options; }
1663
1664 protected:
1665 CommandOptions m_options;
1666 };
1667
1668 class CommandObjectPlatformProcess : public CommandObjectMultiword {
1669 public:
1670 // Constructors and Destructors
CommandObjectPlatformProcess(CommandInterpreter & interpreter)1671 CommandObjectPlatformProcess(CommandInterpreter &interpreter)
1672 : CommandObjectMultiword(interpreter, "platform process",
1673 "Commands to query, launch and attach to "
1674 "processes on the current platform.",
1675 "platform process [attach|launch|list] ...") {
1676 LoadSubCommand(
1677 "attach",
1678 CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));
1679 LoadSubCommand(
1680 "launch",
1681 CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter)));
1682 LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(
1683 interpreter)));
1684 LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
1685 interpreter)));
1686 }
1687
1688 ~CommandObjectPlatformProcess() override = default;
1689
1690 private:
1691 // For CommandObjectPlatform only
1692 CommandObjectPlatformProcess(const CommandObjectPlatformProcess &) = delete;
1693 const CommandObjectPlatformProcess &
1694 operator=(const CommandObjectPlatformProcess &) = delete;
1695 };
1696
1697 // "platform shell"
1698 #define LLDB_OPTIONS_platform_shell
1699 #include "CommandOptions.inc"
1700
1701 class CommandObjectPlatformShell : public CommandObjectRaw {
1702 public:
1703 class CommandOptions : public Options {
1704 public:
1705 CommandOptions() = default;
1706
1707 ~CommandOptions() override = default;
1708
GetDefinitions()1709 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1710 return llvm::ArrayRef(g_platform_shell_options);
1711 }
1712
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1713 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1714 ExecutionContext *execution_context) override {
1715 Status error;
1716
1717 const char short_option = (char)GetDefinitions()[option_idx].short_option;
1718
1719 switch (short_option) {
1720 case 'h':
1721 m_use_host_platform = true;
1722 break;
1723 case 't':
1724 uint32_t timeout_sec;
1725 if (option_arg.getAsInteger(10, timeout_sec))
1726 error.SetErrorStringWithFormat(
1727 "could not convert \"%s\" to a numeric value.",
1728 option_arg.str().c_str());
1729 else
1730 m_timeout = std::chrono::seconds(timeout_sec);
1731 break;
1732 case 's': {
1733 if (option_arg.empty()) {
1734 error.SetErrorStringWithFormat(
1735 "missing shell interpreter path for option -i|--interpreter.");
1736 return error;
1737 }
1738
1739 m_shell_interpreter = option_arg.str();
1740 break;
1741 }
1742 default:
1743 llvm_unreachable("Unimplemented option");
1744 }
1745
1746 return error;
1747 }
1748
OptionParsingStarting(ExecutionContext * execution_context)1749 void OptionParsingStarting(ExecutionContext *execution_context) override {
1750 m_timeout.reset();
1751 m_use_host_platform = false;
1752 m_shell_interpreter.clear();
1753 }
1754
1755 Timeout<std::micro> m_timeout = std::chrono::seconds(10);
1756 bool m_use_host_platform;
1757 std::string m_shell_interpreter;
1758 };
1759
CommandObjectPlatformShell(CommandInterpreter & interpreter)1760 CommandObjectPlatformShell(CommandInterpreter &interpreter)
1761 : CommandObjectRaw(interpreter, "platform shell",
1762 "Run a shell command on the current platform.",
1763 "platform shell <shell-command>", 0) {
1764 CommandArgumentData thread_arg{eArgTypeNone, eArgRepeatStar};
1765 m_arguments.push_back({thread_arg});
1766 }
1767
1768 ~CommandObjectPlatformShell() override = default;
1769
GetOptions()1770 Options *GetOptions() override { return &m_options; }
1771
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1772 bool DoExecute(llvm::StringRef raw_command_line,
1773 CommandReturnObject &result) override {
1774 ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
1775 m_options.NotifyOptionParsingStarting(&exe_ctx);
1776
1777 // Print out an usage syntax on an empty command line.
1778 if (raw_command_line.empty()) {
1779 result.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());
1780 return true;
1781 }
1782
1783 const bool is_alias = !raw_command_line.contains("platform");
1784 OptionsWithRaw args(raw_command_line);
1785
1786 if (args.HasArgs())
1787 if (!ParseOptions(args.GetArgs(), result))
1788 return false;
1789
1790 if (args.GetRawPart().empty()) {
1791 result.GetOutputStream().Printf("%s <shell-command>\n",
1792 is_alias ? "shell" : "platform shell");
1793 return false;
1794 }
1795
1796 llvm::StringRef cmd = args.GetRawPart();
1797
1798 PlatformSP platform_sp(
1799 m_options.m_use_host_platform
1800 ? Platform::GetHostPlatform()
1801 : GetDebugger().GetPlatformList().GetSelectedPlatform());
1802 Status error;
1803 if (platform_sp) {
1804 FileSpec working_dir{};
1805 std::string output;
1806 int status = -1;
1807 int signo = -1;
1808 error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd,
1809 working_dir, &status, &signo,
1810 &output, m_options.m_timeout));
1811 if (!output.empty())
1812 result.GetOutputStream().PutCString(output);
1813 if (status > 0) {
1814 if (signo > 0) {
1815 const char *signo_cstr = Host::GetSignalAsCString(signo);
1816 if (signo_cstr)
1817 result.GetOutputStream().Printf(
1818 "error: command returned with status %i and signal %s\n",
1819 status, signo_cstr);
1820 else
1821 result.GetOutputStream().Printf(
1822 "error: command returned with status %i and signal %i\n",
1823 status, signo);
1824 } else
1825 result.GetOutputStream().Printf(
1826 "error: command returned with status %i\n", status);
1827 }
1828 } else {
1829 result.GetOutputStream().Printf(
1830 "error: cannot run remote shell commands without a platform\n");
1831 error.SetErrorString(
1832 "error: cannot run remote shell commands without a platform");
1833 }
1834
1835 if (error.Fail()) {
1836 result.AppendError(error.AsCString());
1837 } else {
1838 result.SetStatus(eReturnStatusSuccessFinishResult);
1839 }
1840 return true;
1841 }
1842
1843 CommandOptions m_options;
1844 };
1845
1846 // "platform install" - install a target to a remote end
1847 class CommandObjectPlatformInstall : public CommandObjectParsed {
1848 public:
CommandObjectPlatformInstall(CommandInterpreter & interpreter)1849 CommandObjectPlatformInstall(CommandInterpreter &interpreter)
1850 : CommandObjectParsed(
1851 interpreter, "platform target-install",
1852 "Install a target (bundle or executable file) to the remote end.",
1853 "platform target-install <local-thing> <remote-sandbox>", 0) {
1854 CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain};
1855 CommandArgumentData remote_arg{eArgTypePath, eArgRepeatPlain};
1856 m_arguments.push_back({local_arg});
1857 m_arguments.push_back({remote_arg});
1858 }
1859
1860 ~CommandObjectPlatformInstall() override = default;
1861
1862 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1863 HandleArgumentCompletion(CompletionRequest &request,
1864 OptionElementVector &opt_element_vector) override {
1865 if (request.GetCursorIndex())
1866 return;
1867 CommandCompletions::InvokeCommonCompletionCallbacks(
1868 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1869 request, nullptr);
1870 }
1871
DoExecute(Args & args,CommandReturnObject & result)1872 bool DoExecute(Args &args, CommandReturnObject &result) override {
1873 if (args.GetArgumentCount() != 2) {
1874 result.AppendError("platform target-install takes two arguments");
1875 return false;
1876 }
1877 // TODO: move the bulk of this code over to the platform itself
1878 FileSpec src(args.GetArgumentAtIndex(0));
1879 FileSystem::Instance().Resolve(src);
1880 FileSpec dst(args.GetArgumentAtIndex(1));
1881 if (!FileSystem::Instance().Exists(src)) {
1882 result.AppendError("source location does not exist or is not accessible");
1883 return false;
1884 }
1885 PlatformSP platform_sp(
1886 GetDebugger().GetPlatformList().GetSelectedPlatform());
1887 if (!platform_sp) {
1888 result.AppendError("no platform currently selected");
1889 return false;
1890 }
1891
1892 Status error = platform_sp->Install(src, dst);
1893 if (error.Success()) {
1894 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1895 } else {
1896 result.AppendErrorWithFormat("install failed: %s", error.AsCString());
1897 }
1898 return result.Succeeded();
1899 }
1900 };
1901
CommandObjectPlatform(CommandInterpreter & interpreter)1902 CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter)
1903 : CommandObjectMultiword(
1904 interpreter, "platform", "Commands to manage and create platforms.",
1905 "platform [connect|disconnect|info|list|status|select] ...") {
1906 LoadSubCommand("select",
1907 CommandObjectSP(new CommandObjectPlatformSelect(interpreter)));
1908 LoadSubCommand("list",
1909 CommandObjectSP(new CommandObjectPlatformList(interpreter)));
1910 LoadSubCommand("status",
1911 CommandObjectSP(new CommandObjectPlatformStatus(interpreter)));
1912 LoadSubCommand("connect", CommandObjectSP(
1913 new CommandObjectPlatformConnect(interpreter)));
1914 LoadSubCommand(
1915 "disconnect",
1916 CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter)));
1917 LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(
1918 interpreter)));
1919 LoadSubCommand("mkdir",
1920 CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));
1921 LoadSubCommand("file",
1922 CommandObjectSP(new CommandObjectPlatformFile(interpreter)));
1923 LoadSubCommand("file-exists",
1924 CommandObjectSP(new CommandObjectPlatformFileExists(interpreter)));
1925 LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
1926 interpreter)));
1927 LoadSubCommand("get-permissions",
1928 CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter)));
1929 LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
1930 interpreter)));
1931 LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
1932 interpreter)));
1933 LoadSubCommand("process", CommandObjectSP(
1934 new CommandObjectPlatformProcess(interpreter)));
1935 LoadSubCommand("shell",
1936 CommandObjectSP(new CommandObjectPlatformShell(interpreter)));
1937 LoadSubCommand(
1938 "target-install",
1939 CommandObjectSP(new CommandObjectPlatformInstall(interpreter)));
1940 }
1941
1942 CommandObjectPlatform::~CommandObjectPlatform() = default;
1943