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