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