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