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