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