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