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