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