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