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