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