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