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