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