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