1 //===-- CommandObjectPlatform.cpp -------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 #include <mutex> 13 // Other libraries and framework includes 14 // Project includes 15 #include "CommandObjectPlatform.h" 16 #include "lldb/Core/DataExtractor.h" 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/PluginManager.h" 20 #include "lldb/Host/StringConvert.h" 21 #include "lldb/Interpreter/Args.h" 22 #include "lldb/Interpreter/CommandInterpreter.h" 23 #include "lldb/Interpreter/CommandOptionValidators.h" 24 #include "lldb/Interpreter/CommandReturnObject.h" 25 #include "lldb/Interpreter/OptionGroupFile.h" 26 #include "lldb/Interpreter/OptionGroupPlatform.h" 27 #include "lldb/Target/ExecutionContext.h" 28 #include "lldb/Target/Platform.h" 29 #include "lldb/Target/Process.h" 30 #include "lldb/Utility/Utils.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 35 static mode_t 36 ParsePermissionString(const char* permissions) 37 { 38 if (strlen(permissions) != 9) 39 return (mode_t)(-1); 40 bool user_r,user_w,user_x, 41 group_r,group_w,group_x, 42 world_r,world_w,world_x; 43 44 user_r = (permissions[0] == 'r'); 45 user_w = (permissions[1] == 'w'); 46 user_x = (permissions[2] == 'x'); 47 48 group_r = (permissions[3] == 'r'); 49 group_w = (permissions[4] == 'w'); 50 group_x = (permissions[5] == 'x'); 51 52 world_r = (permissions[6] == 'r'); 53 world_w = (permissions[7] == 'w'); 54 world_x = (permissions[8] == 'x'); 55 56 mode_t user,group,world; 57 user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0); 58 group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0); 59 world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0); 60 61 return user | group | world; 62 } 63 64 static OptionDefinition 65 g_permissions_options[] = 66 { 67 // clang-format off 68 {LLDB_OPT_SET_ALL, false, "permissions-value", 'v', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePermissionsNumber, "Give out the numeric value for permissions (e.g. 757)"}, 69 {LLDB_OPT_SET_ALL, false, "permissions-string", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePermissionsString, "Give out the string value for permissions (e.g. rwxr-xr--)."}, 70 {LLDB_OPT_SET_ALL, false, "user-read", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow user to read."}, 71 {LLDB_OPT_SET_ALL, false, "user-write", 'w', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow user to write."}, 72 {LLDB_OPT_SET_ALL, false, "user-exec", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow user to execute."}, 73 {LLDB_OPT_SET_ALL, false, "group-read", 'R', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow group to read."}, 74 {LLDB_OPT_SET_ALL, false, "group-write", 'W', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow group to write."}, 75 {LLDB_OPT_SET_ALL, false, "group-exec", 'X', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow group to execute."}, 76 {LLDB_OPT_SET_ALL, false, "world-read", 'd', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow world to read."}, 77 {LLDB_OPT_SET_ALL, false, "world-write", 't', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow world to write."}, 78 {LLDB_OPT_SET_ALL, false, "world-exec", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow world to execute."}, 79 // clang-format on 80 }; 81 82 class OptionPermissions : public lldb_private::OptionGroup 83 { 84 public: 85 OptionPermissions () 86 { 87 } 88 89 ~OptionPermissions() override = default; 90 91 lldb_private::Error 92 SetOptionValue(uint32_t option_idx, 93 const char *option_arg, 94 ExecutionContext *execution_context) override 95 { 96 Error error; 97 char short_option = (char) GetDefinitions()[option_idx].short_option; 98 switch (short_option) 99 { 100 case 'v': 101 { 102 bool ok; 103 uint32_t perms = StringConvert::ToUInt32(option_arg, 777, 8, &ok); 104 if (!ok) 105 error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg); 106 else 107 m_permissions = perms; 108 } 109 break; 110 case 's': 111 { 112 mode_t perms = ParsePermissionString(option_arg); 113 if (perms == (mode_t)-1) 114 error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg); 115 else 116 m_permissions = perms; 117 } 118 break; 119 case 'r': 120 m_permissions |= lldb::eFilePermissionsUserRead; 121 break; 122 case 'w': 123 m_permissions |= lldb::eFilePermissionsUserWrite; 124 break; 125 case 'x': 126 m_permissions |= lldb::eFilePermissionsUserExecute; 127 break; 128 case 'R': 129 m_permissions |= lldb::eFilePermissionsGroupRead; 130 break; 131 case 'W': 132 m_permissions |= lldb::eFilePermissionsGroupWrite; 133 break; 134 case 'X': 135 m_permissions |= lldb::eFilePermissionsGroupExecute; 136 break; 137 case 'd': 138 m_permissions |= lldb::eFilePermissionsWorldRead; 139 break; 140 case 't': 141 m_permissions |= lldb::eFilePermissionsWorldWrite; 142 break; 143 case 'e': 144 m_permissions |= lldb::eFilePermissionsWorldExecute; 145 break; 146 default: 147 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 148 break; 149 } 150 151 return error; 152 } 153 154 void 155 OptionParsingStarting(ExecutionContext *execution_context) override 156 { 157 m_permissions = 0; 158 } 159 160 uint32_t 161 GetNumDefinitions () override 162 { 163 return llvm::array_lengthof(g_permissions_options); 164 } 165 166 const lldb_private::OptionDefinition* 167 GetDefinitions () override 168 { 169 return g_permissions_options; 170 } 171 172 // Instance variables to hold the values for command options. 173 174 uint32_t m_permissions; 175 176 private: 177 DISALLOW_COPY_AND_ASSIGN(OptionPermissions); 178 }; 179 180 //---------------------------------------------------------------------- 181 // "platform select <platform-name>" 182 //---------------------------------------------------------------------- 183 class CommandObjectPlatformSelect : public CommandObjectParsed 184 { 185 public: 186 CommandObjectPlatformSelect (CommandInterpreter &interpreter) : 187 CommandObjectParsed (interpreter, 188 "platform select", 189 "Create a platform if needed and select it as the current platform.", 190 "platform select <platform-name>", 191 0), 192 m_option_group (), 193 m_platform_options (false) // Don't include the "--platform" option by passing false 194 { 195 m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, 1); 196 m_option_group.Finalize(); 197 } 198 199 ~CommandObjectPlatformSelect() override = default; 200 201 int 202 HandleCompletion (Args &input, 203 int &cursor_index, 204 int &cursor_char_position, 205 int match_start_point, 206 int max_return_elements, 207 bool &word_complete, 208 StringList &matches) override 209 { 210 std::string completion_str (input.GetArgumentAtIndex(cursor_index)); 211 completion_str.erase (cursor_char_position); 212 213 CommandCompletions::PlatformPluginNames(GetCommandInterpreter(), 214 completion_str.c_str(), 215 match_start_point, 216 max_return_elements, 217 nullptr, 218 word_complete, 219 matches); 220 return matches.GetSize(); 221 } 222 223 Options * 224 GetOptions () override 225 { 226 return &m_option_group; 227 } 228 229 protected: 230 bool 231 DoExecute (Args& args, CommandReturnObject &result) override 232 { 233 if (args.GetArgumentCount() == 1) 234 { 235 const char *platform_name = args.GetArgumentAtIndex (0); 236 if (platform_name && platform_name[0]) 237 { 238 const bool select = true; 239 m_platform_options.SetPlatformName (platform_name); 240 Error error; 241 ArchSpec platform_arch; 242 PlatformSP platform_sp (m_platform_options.CreatePlatformWithOptions (m_interpreter, ArchSpec(), select, error, platform_arch)); 243 if (platform_sp) 244 { 245 m_interpreter.GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp); 246 247 platform_sp->GetStatus (result.GetOutputStream()); 248 result.SetStatus (eReturnStatusSuccessFinishResult); 249 } 250 else 251 { 252 result.AppendError(error.AsCString()); 253 result.SetStatus (eReturnStatusFailed); 254 } 255 } 256 else 257 { 258 result.AppendError ("invalid platform name"); 259 result.SetStatus (eReturnStatusFailed); 260 } 261 } 262 else 263 { 264 result.AppendError ("platform create takes a platform name as an argument\n"); 265 result.SetStatus (eReturnStatusFailed); 266 } 267 return result.Succeeded(); 268 } 269 270 OptionGroupOptions m_option_group; 271 OptionGroupPlatform m_platform_options; 272 }; 273 274 //---------------------------------------------------------------------- 275 // "platform list" 276 //---------------------------------------------------------------------- 277 class CommandObjectPlatformList : public CommandObjectParsed 278 { 279 public: 280 CommandObjectPlatformList (CommandInterpreter &interpreter) : 281 CommandObjectParsed(interpreter, 282 "platform list", 283 "List all platforms that are available.", 284 nullptr, 285 0) 286 { 287 } 288 289 ~CommandObjectPlatformList() override = default; 290 291 protected: 292 bool 293 DoExecute (Args& args, CommandReturnObject &result) override 294 { 295 Stream &ostrm = result.GetOutputStream(); 296 ostrm.Printf("Available platforms:\n"); 297 298 PlatformSP host_platform_sp (Platform::GetHostPlatform()); 299 ostrm.Printf ("%s: %s\n", 300 host_platform_sp->GetPluginName().GetCString(), 301 host_platform_sp->GetDescription()); 302 303 uint32_t idx; 304 for (idx = 0; 1; ++idx) 305 { 306 const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (idx); 307 if (plugin_name == nullptr) 308 break; 309 const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (idx); 310 if (plugin_desc == nullptr) 311 break; 312 ostrm.Printf("%s: %s\n", plugin_name, plugin_desc); 313 } 314 315 if (idx == 0) 316 { 317 result.AppendError ("no platforms are available\n"); 318 result.SetStatus (eReturnStatusFailed); 319 } 320 else 321 result.SetStatus (eReturnStatusSuccessFinishResult); 322 return result.Succeeded(); 323 } 324 }; 325 326 //---------------------------------------------------------------------- 327 // "platform status" 328 //---------------------------------------------------------------------- 329 class CommandObjectPlatformStatus : public CommandObjectParsed 330 { 331 public: 332 CommandObjectPlatformStatus(CommandInterpreter &interpreter) 333 : CommandObjectParsed(interpreter, "platform status", "Display status for the current platform.", nullptr, 0) 334 { 335 } 336 337 ~CommandObjectPlatformStatus() override = default; 338 339 protected: 340 bool 341 DoExecute (Args& args, CommandReturnObject &result) override 342 { 343 Stream &ostrm = result.GetOutputStream(); 344 345 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 346 PlatformSP platform_sp; 347 if (target) 348 { 349 platform_sp = target->GetPlatform(); 350 } 351 if (!platform_sp) 352 { 353 platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); 354 } 355 if (platform_sp) 356 { 357 platform_sp->GetStatus (ostrm); 358 result.SetStatus (eReturnStatusSuccessFinishResult); 359 } 360 else 361 { 362 result.AppendError ("no platform us currently selected\n"); 363 result.SetStatus (eReturnStatusFailed); 364 } 365 return result.Succeeded(); 366 } 367 }; 368 369 //---------------------------------------------------------------------- 370 // "platform connect <connect-url>" 371 //---------------------------------------------------------------------- 372 class CommandObjectPlatformConnect : public CommandObjectParsed 373 { 374 public: 375 CommandObjectPlatformConnect(CommandInterpreter &interpreter) 376 : CommandObjectParsed(interpreter, "platform connect", 377 "Select the current platform by providing a connection URL.", 378 "platform connect <connect-url>", 0) 379 { 380 } 381 382 ~CommandObjectPlatformConnect() override = default; 383 384 protected: 385 bool 386 DoExecute (Args& args, CommandReturnObject &result) override 387 { 388 Stream &ostrm = result.GetOutputStream(); 389 390 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 391 if (platform_sp) 392 { 393 Error error (platform_sp->ConnectRemote (args)); 394 if (error.Success()) 395 { 396 platform_sp->GetStatus (ostrm); 397 result.SetStatus (eReturnStatusSuccessFinishResult); 398 399 platform_sp->ConnectToWaitingProcesses(m_interpreter.GetDebugger(), error); 400 if (error.Fail()) 401 { 402 result.AppendError (error.AsCString()); 403 result.SetStatus (eReturnStatusFailed); 404 } 405 } 406 else 407 { 408 result.AppendErrorWithFormat ("%s\n", error.AsCString()); 409 result.SetStatus (eReturnStatusFailed); 410 } 411 } 412 else 413 { 414 result.AppendError ("no platform is currently selected\n"); 415 result.SetStatus (eReturnStatusFailed); 416 } 417 return result.Succeeded(); 418 } 419 420 Options * 421 GetOptions () override 422 { 423 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 424 OptionGroupOptions* m_platform_options = nullptr; 425 if (platform_sp) 426 { 427 m_platform_options = platform_sp->GetConnectionOptions(m_interpreter); 428 if (m_platform_options != nullptr && !m_platform_options->m_did_finalize) 429 m_platform_options->Finalize(); 430 } 431 return m_platform_options; 432 } 433 }; 434 435 //---------------------------------------------------------------------- 436 // "platform disconnect" 437 //---------------------------------------------------------------------- 438 class CommandObjectPlatformDisconnect : public CommandObjectParsed 439 { 440 public: 441 CommandObjectPlatformDisconnect(CommandInterpreter &interpreter) 442 : CommandObjectParsed(interpreter, "platform disconnect", "Disconnect from the current platform.", 443 "platform disconnect", 0) 444 { 445 } 446 447 ~CommandObjectPlatformDisconnect() override = default; 448 449 protected: 450 bool 451 DoExecute (Args& args, CommandReturnObject &result) override 452 { 453 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 454 if (platform_sp) 455 { 456 if (args.GetArgumentCount() == 0) 457 { 458 Error error; 459 460 if (platform_sp->IsConnected()) 461 { 462 // Cache the instance name if there is one since we are 463 // about to disconnect and the name might go with it. 464 const char *hostname_cstr = platform_sp->GetHostname(); 465 std::string hostname; 466 if (hostname_cstr) 467 hostname.assign (hostname_cstr); 468 469 error = platform_sp->DisconnectRemote (); 470 if (error.Success()) 471 { 472 Stream &ostrm = result.GetOutputStream(); 473 if (hostname.empty()) 474 ostrm.Printf ("Disconnected from \"%s\"\n", platform_sp->GetPluginName().GetCString()); 475 else 476 ostrm.Printf ("Disconnected from \"%s\"\n", hostname.c_str()); 477 result.SetStatus (eReturnStatusSuccessFinishResult); 478 } 479 else 480 { 481 result.AppendErrorWithFormat ("%s", error.AsCString()); 482 result.SetStatus (eReturnStatusFailed); 483 } 484 } 485 else 486 { 487 // Not connected... 488 result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString()); 489 result.SetStatus (eReturnStatusFailed); 490 } 491 } 492 else 493 { 494 // Bad args 495 result.AppendError ("\"platform disconnect\" doesn't take any arguments"); 496 result.SetStatus (eReturnStatusFailed); 497 } 498 } 499 else 500 { 501 result.AppendError ("no platform is currently selected"); 502 result.SetStatus (eReturnStatusFailed); 503 } 504 return result.Succeeded(); 505 } 506 }; 507 508 //---------------------------------------------------------------------- 509 // "platform settings" 510 //---------------------------------------------------------------------- 511 class CommandObjectPlatformSettings : public CommandObjectParsed 512 { 513 public: 514 CommandObjectPlatformSettings (CommandInterpreter &interpreter) : 515 CommandObjectParsed (interpreter, 516 "platform settings", 517 "Set settings for the current target's platform, or for a platform by name.", 518 "platform settings", 519 0), 520 m_options(), 521 m_option_working_dir (LLDB_OPT_SET_1, false, "working-dir", 'w', 0, eArgTypePath, "The working directory for the platform.") 522 { 523 m_options.Append (&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 524 } 525 526 ~CommandObjectPlatformSettings() override = default; 527 528 protected: 529 bool 530 DoExecute (Args& args, CommandReturnObject &result) override 531 { 532 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 533 if (platform_sp) 534 { 535 if (m_option_working_dir.GetOptionValue().OptionWasSet()) 536 platform_sp->SetWorkingDirectory(m_option_working_dir.GetOptionValue().GetCurrentValue()); 537 } 538 else 539 { 540 result.AppendError ("no platform is currently selected"); 541 result.SetStatus (eReturnStatusFailed); 542 } 543 return result.Succeeded(); 544 } 545 546 Options * 547 GetOptions () override 548 { 549 if (!m_options.DidFinalize()) 550 m_options.Finalize(); 551 return &m_options; 552 } 553 554 protected: 555 OptionGroupOptions m_options; 556 OptionGroupFile m_option_working_dir; 557 }; 558 559 //---------------------------------------------------------------------- 560 // "platform mkdir" 561 //---------------------------------------------------------------------- 562 class CommandObjectPlatformMkDir : public CommandObjectParsed 563 { 564 public: 565 CommandObjectPlatformMkDir (CommandInterpreter &interpreter) : 566 CommandObjectParsed(interpreter, 567 "platform mkdir", 568 "Make a new directory on the remote end.", 569 nullptr, 570 0), 571 m_options() 572 { 573 } 574 575 ~CommandObjectPlatformMkDir() override = default; 576 577 bool 578 DoExecute (Args& args, CommandReturnObject &result) override 579 { 580 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 581 if (platform_sp) 582 { 583 std::string cmd_line; 584 args.GetCommandString(cmd_line); 585 uint32_t mode; 586 const OptionPermissions* options_permissions = (const OptionPermissions*)m_options.GetGroupWithOption('r'); 587 if (options_permissions) 588 mode = options_permissions->m_permissions; 589 else 590 mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX | lldb::eFilePermissionsWorldRX; 591 Error error = platform_sp->MakeDirectory(FileSpec{cmd_line, false}, mode); 592 if (error.Success()) 593 { 594 result.SetStatus (eReturnStatusSuccessFinishResult); 595 } 596 else 597 { 598 result.AppendError(error.AsCString()); 599 result.SetStatus (eReturnStatusFailed); 600 } 601 } 602 else 603 { 604 result.AppendError ("no platform currently selected\n"); 605 result.SetStatus (eReturnStatusFailed); 606 } 607 return result.Succeeded(); 608 } 609 610 Options * 611 GetOptions () override 612 { 613 if (!m_options.DidFinalize()) 614 { 615 m_options.Append(new OptionPermissions()); 616 m_options.Finalize(); 617 } 618 return &m_options; 619 } 620 621 OptionGroupOptions m_options; 622 }; 623 624 //---------------------------------------------------------------------- 625 // "platform fopen" 626 //---------------------------------------------------------------------- 627 class CommandObjectPlatformFOpen : public CommandObjectParsed 628 { 629 public: 630 CommandObjectPlatformFOpen (CommandInterpreter &interpreter) : 631 CommandObjectParsed(interpreter, 632 "platform file open", 633 "Open a file on the remote end.", 634 nullptr, 635 0), 636 m_options() 637 { 638 } 639 640 ~CommandObjectPlatformFOpen() override = default; 641 642 bool 643 DoExecute (Args& args, CommandReturnObject &result) override 644 { 645 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 646 if (platform_sp) 647 { 648 Error error; 649 std::string cmd_line; 650 args.GetCommandString(cmd_line); 651 mode_t perms; 652 const OptionPermissions* options_permissions = (const OptionPermissions*)m_options.GetGroupWithOption('r'); 653 if (options_permissions) 654 perms = options_permissions->m_permissions; 655 else 656 perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW | lldb::eFilePermissionsWorldRead; 657 lldb::user_id_t fd = platform_sp->OpenFile(FileSpec(cmd_line.c_str(),false), 658 File::eOpenOptionRead | File::eOpenOptionWrite | 659 File::eOpenOptionAppend | File::eOpenOptionCanCreate, 660 perms, 661 error); 662 if (error.Success()) 663 { 664 result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n",fd); 665 result.SetStatus (eReturnStatusSuccessFinishResult); 666 } 667 else 668 { 669 result.AppendError(error.AsCString()); 670 result.SetStatus (eReturnStatusFailed); 671 } 672 } 673 else 674 { 675 result.AppendError ("no platform currently selected\n"); 676 result.SetStatus (eReturnStatusFailed); 677 } 678 return result.Succeeded(); 679 } 680 681 Options * 682 GetOptions () override 683 { 684 if (!m_options.DidFinalize()) 685 { 686 m_options.Append(new OptionPermissions()); 687 m_options.Finalize(); 688 } 689 return &m_options; 690 } 691 692 OptionGroupOptions m_options; 693 }; 694 695 //---------------------------------------------------------------------- 696 // "platform fclose" 697 //---------------------------------------------------------------------- 698 class CommandObjectPlatformFClose : public CommandObjectParsed 699 { 700 public: 701 CommandObjectPlatformFClose (CommandInterpreter &interpreter) : 702 CommandObjectParsed(interpreter, 703 "platform file close", 704 "Close a file on the remote end.", 705 nullptr, 706 0) 707 { 708 } 709 710 ~CommandObjectPlatformFClose() override = default; 711 712 bool 713 DoExecute (Args& args, CommandReturnObject &result) override 714 { 715 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 716 if (platform_sp) 717 { 718 std::string cmd_line; 719 args.GetCommandString(cmd_line); 720 const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX); 721 Error error; 722 bool success = platform_sp->CloseFile(fd, error); 723 if (success) 724 { 725 result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd); 726 result.SetStatus (eReturnStatusSuccessFinishResult); 727 } 728 else 729 { 730 result.AppendError(error.AsCString()); 731 result.SetStatus (eReturnStatusFailed); 732 } 733 } 734 else 735 { 736 result.AppendError ("no platform currently selected\n"); 737 result.SetStatus (eReturnStatusFailed); 738 } 739 return result.Succeeded(); 740 } 741 }; 742 743 //---------------------------------------------------------------------- 744 // "platform fread" 745 //---------------------------------------------------------------------- 746 class CommandObjectPlatformFRead : public CommandObjectParsed 747 { 748 public: 749 CommandObjectPlatformFRead (CommandInterpreter &interpreter) : 750 CommandObjectParsed(interpreter, 751 "platform file read", 752 "Read data from a file on the remote end.", 753 nullptr, 754 0), 755 m_options() 756 { 757 } 758 759 ~CommandObjectPlatformFRead() override = default; 760 761 bool 762 DoExecute (Args& args, CommandReturnObject &result) override 763 { 764 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 765 if (platform_sp) 766 { 767 std::string cmd_line; 768 args.GetCommandString(cmd_line); 769 const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX); 770 std::string buffer(m_options.m_count,0); 771 Error error; 772 uint32_t retcode = platform_sp->ReadFile(fd, m_options.m_offset, &buffer[0], m_options.m_count, error); 773 result.AppendMessageWithFormat("Return = %d\n",retcode); 774 result.AppendMessageWithFormat("Data = \"%s\"\n",buffer.c_str()); 775 result.SetStatus (eReturnStatusSuccessFinishResult); 776 } 777 else 778 { 779 result.AppendError ("no platform currently selected\n"); 780 result.SetStatus (eReturnStatusFailed); 781 } 782 return result.Succeeded(); 783 } 784 785 Options * 786 GetOptions () override 787 { 788 return &m_options; 789 } 790 791 protected: 792 class CommandOptions : public Options 793 { 794 public: 795 CommandOptions() : 796 Options() 797 { 798 } 799 800 ~CommandOptions() override = default; 801 802 Error 803 SetOptionValue (uint32_t option_idx, const char *option_arg, 804 ExecutionContext *execution_context) override 805 { 806 Error error; 807 char short_option = (char) m_getopt_table[option_idx].val; 808 bool success = false; 809 810 switch (short_option) 811 { 812 case 'o': 813 m_offset = StringConvert::ToUInt32(option_arg, 0, 0, &success); 814 if (!success) 815 error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg); 816 break; 817 case 'c': 818 m_count = StringConvert::ToUInt32(option_arg, 0, 0, &success); 819 if (!success) 820 error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg); 821 break; 822 default: 823 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 824 break; 825 } 826 827 return error; 828 } 829 830 void 831 OptionParsingStarting(ExecutionContext *execution_context) override 832 { 833 m_offset = 0; 834 m_count = 1; 835 } 836 837 const OptionDefinition* 838 GetDefinitions () override 839 { 840 return g_option_table; 841 } 842 843 // Options table: Required for subclasses of Options. 844 845 static OptionDefinition g_option_table[]; 846 847 // Instance variables to hold the values for command options. 848 849 uint32_t m_offset; 850 uint32_t m_count; 851 }; 852 853 CommandOptions m_options; 854 }; 855 856 OptionDefinition 857 CommandObjectPlatformFRead::CommandOptions::g_option_table[] = 858 { 859 // clang-format off 860 {LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeIndex, "Offset into the file at which to start reading."}, 861 {LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Number of bytes to read from the file."}, 862 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 863 // clang-format on 864 }; 865 866 //---------------------------------------------------------------------- 867 // "platform fwrite" 868 //---------------------------------------------------------------------- 869 class CommandObjectPlatformFWrite : public CommandObjectParsed 870 { 871 public: 872 CommandObjectPlatformFWrite (CommandInterpreter &interpreter) : 873 CommandObjectParsed(interpreter, 874 "platform file write", 875 "Write data to a file on the remote end.", 876 nullptr, 877 0), 878 m_options() 879 { 880 } 881 882 ~CommandObjectPlatformFWrite() override = default; 883 884 bool 885 DoExecute (Args& args, CommandReturnObject &result) override 886 { 887 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 888 if (platform_sp) 889 { 890 std::string cmd_line; 891 args.GetCommandString(cmd_line); 892 Error error; 893 const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX); 894 uint32_t retcode = platform_sp->WriteFile (fd, 895 m_options.m_offset, 896 &m_options.m_data[0], 897 m_options.m_data.size(), 898 error); 899 result.AppendMessageWithFormat("Return = %d\n",retcode); 900 result.SetStatus (eReturnStatusSuccessFinishResult); 901 } 902 else 903 { 904 result.AppendError ("no platform currently selected\n"); 905 result.SetStatus (eReturnStatusFailed); 906 } 907 return result.Succeeded(); 908 } 909 910 Options * 911 GetOptions () override 912 { 913 return &m_options; 914 } 915 916 protected: 917 class CommandOptions : public Options 918 { 919 public: 920 CommandOptions() : 921 Options() 922 { 923 } 924 925 ~CommandOptions() override = default; 926 927 Error 928 SetOptionValue (uint32_t option_idx, const char *option_arg, 929 ExecutionContext *execution_context) override 930 { 931 Error error; 932 char short_option = (char) m_getopt_table[option_idx].val; 933 bool success = false; 934 935 switch (short_option) 936 { 937 case 'o': 938 m_offset = StringConvert::ToUInt32(option_arg, 0, 0, &success); 939 if (!success) 940 error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg); 941 break; 942 case 'd': 943 m_data.assign(option_arg); 944 break; 945 default: 946 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 947 break; 948 } 949 950 return error; 951 } 952 953 void 954 OptionParsingStarting(ExecutionContext *execution_context) override 955 { 956 m_offset = 0; 957 m_data.clear(); 958 } 959 960 const OptionDefinition* 961 GetDefinitions () override 962 { 963 return g_option_table; 964 } 965 966 // Options table: Required for subclasses of Options. 967 968 static OptionDefinition g_option_table[]; 969 970 // Instance variables to hold the values for command options. 971 972 uint32_t m_offset; 973 std::string m_data; 974 }; 975 976 CommandOptions m_options; 977 }; 978 979 OptionDefinition 980 CommandObjectPlatformFWrite::CommandOptions::g_option_table[] = 981 { 982 // clang-format off 983 {LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeIndex, "Offset into the file at which to start reading."}, 984 {LLDB_OPT_SET_1, false, "data", 'd', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, "Text to write to the file."}, 985 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 986 // clang-format on 987 }; 988 989 class CommandObjectPlatformFile : public CommandObjectMultiword 990 { 991 public: 992 //------------------------------------------------------------------ 993 // Constructors and Destructors 994 //------------------------------------------------------------------ 995 CommandObjectPlatformFile(CommandInterpreter &interpreter) 996 : CommandObjectMultiword(interpreter, "platform file", "Commands to access files on the current platform.", 997 "platform file [open|close|read|write] ...") 998 { 999 LoadSubCommand ("open", CommandObjectSP (new CommandObjectPlatformFOpen (interpreter))); 1000 LoadSubCommand ("close", CommandObjectSP (new CommandObjectPlatformFClose (interpreter))); 1001 LoadSubCommand ("read", CommandObjectSP (new CommandObjectPlatformFRead (interpreter))); 1002 LoadSubCommand ("write", CommandObjectSP (new CommandObjectPlatformFWrite (interpreter))); 1003 } 1004 1005 ~CommandObjectPlatformFile() override = default; 1006 1007 private: 1008 //------------------------------------------------------------------ 1009 // For CommandObjectPlatform only 1010 //------------------------------------------------------------------ 1011 DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformFile); 1012 }; 1013 1014 //---------------------------------------------------------------------- 1015 // "platform get-file remote-file-path host-file-path" 1016 //---------------------------------------------------------------------- 1017 class CommandObjectPlatformGetFile : public CommandObjectParsed 1018 { 1019 public: 1020 CommandObjectPlatformGetFile (CommandInterpreter &interpreter) : 1021 CommandObjectParsed (interpreter, 1022 "platform get-file", 1023 "Transfer a file from the remote end to the local host.", 1024 "platform get-file <remote-file-spec> <local-file-spec>", 1025 0) 1026 { 1027 SetHelpLong( 1028 R"(Examples: 1029 1030 (lldb) platform get-file /the/remote/file/path /the/local/file/path 1031 1032 Transfer a file from the remote end with file path /the/remote/file/path to the local host.)" 1033 ); 1034 1035 CommandArgumentEntry arg1, arg2; 1036 CommandArgumentData file_arg_remote, file_arg_host; 1037 1038 // Define the first (and only) variant of this arg. 1039 file_arg_remote.arg_type = eArgTypeFilename; 1040 file_arg_remote.arg_repetition = eArgRepeatPlain; 1041 // There is only one variant this argument could be; put it into the argument entry. 1042 arg1.push_back (file_arg_remote); 1043 1044 // Define the second (and only) variant of this arg. 1045 file_arg_host.arg_type = eArgTypeFilename; 1046 file_arg_host.arg_repetition = eArgRepeatPlain; 1047 // There is only one variant this argument could be; put it into the argument entry. 1048 arg2.push_back (file_arg_host); 1049 1050 // Push the data for the first and the second arguments into the m_arguments vector. 1051 m_arguments.push_back (arg1); 1052 m_arguments.push_back (arg2); 1053 } 1054 1055 ~CommandObjectPlatformGetFile() override = default; 1056 1057 bool 1058 DoExecute (Args& args, CommandReturnObject &result) override 1059 { 1060 // If the number of arguments is incorrect, issue an error message. 1061 if (args.GetArgumentCount() != 2) 1062 { 1063 result.GetErrorStream().Printf("error: required arguments missing; specify both the source and destination file paths\n"); 1064 result.SetStatus(eReturnStatusFailed); 1065 return false; 1066 } 1067 1068 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 1069 if (platform_sp) 1070 { 1071 const char *remote_file_path = args.GetArgumentAtIndex(0); 1072 const char *local_file_path = args.GetArgumentAtIndex(1); 1073 Error error = platform_sp->GetFile(FileSpec(remote_file_path, false), 1074 FileSpec(local_file_path, false)); 1075 if (error.Success()) 1076 { 1077 result.AppendMessageWithFormat("successfully get-file from %s (remote) to %s (host)\n", 1078 remote_file_path, local_file_path); 1079 result.SetStatus (eReturnStatusSuccessFinishResult); 1080 } 1081 else 1082 { 1083 result.AppendMessageWithFormat("get-file failed: %s\n", error.AsCString()); 1084 result.SetStatus (eReturnStatusFailed); 1085 } 1086 } 1087 else 1088 { 1089 result.AppendError ("no platform currently selected\n"); 1090 result.SetStatus (eReturnStatusFailed); 1091 } 1092 return result.Succeeded(); 1093 } 1094 }; 1095 1096 //---------------------------------------------------------------------- 1097 // "platform get-size remote-file-path" 1098 //---------------------------------------------------------------------- 1099 class CommandObjectPlatformGetSize : public CommandObjectParsed 1100 { 1101 public: 1102 CommandObjectPlatformGetSize (CommandInterpreter &interpreter) : 1103 CommandObjectParsed (interpreter, 1104 "platform get-size", 1105 "Get the file size from the remote end.", 1106 "platform get-size <remote-file-spec>", 1107 0) 1108 { 1109 SetHelpLong( 1110 R"(Examples: 1111 1112 (lldb) platform get-size /the/remote/file/path 1113 1114 Get the file size from the remote end with path /the/remote/file/path.)" 1115 ); 1116 1117 CommandArgumentEntry arg1; 1118 CommandArgumentData file_arg_remote; 1119 1120 // Define the first (and only) variant of this arg. 1121 file_arg_remote.arg_type = eArgTypeFilename; 1122 file_arg_remote.arg_repetition = eArgRepeatPlain; 1123 // There is only one variant this argument could be; put it into the argument entry. 1124 arg1.push_back (file_arg_remote); 1125 1126 // Push the data for the first argument into the m_arguments vector. 1127 m_arguments.push_back (arg1); 1128 } 1129 1130 ~CommandObjectPlatformGetSize() override = default; 1131 1132 bool 1133 DoExecute (Args& args, CommandReturnObject &result) override 1134 { 1135 // If the number of arguments is incorrect, issue an error message. 1136 if (args.GetArgumentCount() != 1) 1137 { 1138 result.GetErrorStream().Printf("error: required argument missing; specify the source file path as the only argument\n"); 1139 result.SetStatus(eReturnStatusFailed); 1140 return false; 1141 } 1142 1143 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 1144 if (platform_sp) 1145 { 1146 std::string remote_file_path(args.GetArgumentAtIndex(0)); 1147 user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path.c_str(), false)); 1148 if (size != UINT64_MAX) 1149 { 1150 result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64 "\n", remote_file_path.c_str(), size); 1151 result.SetStatus (eReturnStatusSuccessFinishResult); 1152 } 1153 else 1154 { 1155 result.AppendMessageWithFormat("Error getting file size of %s (remote)\n", remote_file_path.c_str()); 1156 result.SetStatus (eReturnStatusFailed); 1157 } 1158 } 1159 else 1160 { 1161 result.AppendError ("no platform currently selected\n"); 1162 result.SetStatus (eReturnStatusFailed); 1163 } 1164 return result.Succeeded(); 1165 } 1166 }; 1167 1168 //---------------------------------------------------------------------- 1169 // "platform put-file" 1170 //---------------------------------------------------------------------- 1171 class CommandObjectPlatformPutFile : public CommandObjectParsed 1172 { 1173 public: 1174 CommandObjectPlatformPutFile (CommandInterpreter &interpreter) : 1175 CommandObjectParsed(interpreter, 1176 "platform put-file", 1177 "Transfer a file from this system to the remote end.", 1178 nullptr, 1179 0) 1180 { 1181 } 1182 1183 ~CommandObjectPlatformPutFile() override = default; 1184 1185 bool 1186 DoExecute (Args& args, CommandReturnObject &result) override 1187 { 1188 const char* src = args.GetArgumentAtIndex(0); 1189 const char* dst = args.GetArgumentAtIndex(1); 1190 1191 FileSpec src_fs(src, true); 1192 FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString(), false); 1193 1194 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 1195 if (platform_sp) 1196 { 1197 Error error (platform_sp->PutFile(src_fs, dst_fs)); 1198 if (error.Success()) 1199 { 1200 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1201 } 1202 else 1203 { 1204 result.AppendError (error.AsCString()); 1205 result.SetStatus (eReturnStatusFailed); 1206 } 1207 } 1208 else 1209 { 1210 result.AppendError ("no platform currently selected\n"); 1211 result.SetStatus (eReturnStatusFailed); 1212 } 1213 return result.Succeeded(); 1214 } 1215 }; 1216 1217 //---------------------------------------------------------------------- 1218 // "platform process launch" 1219 //---------------------------------------------------------------------- 1220 class CommandObjectPlatformProcessLaunch : public CommandObjectParsed 1221 { 1222 public: 1223 CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) : 1224 CommandObjectParsed (interpreter, 1225 "platform process launch", 1226 "Launch a new process on a remote platform.", 1227 "platform process launch program", 1228 eCommandRequiresTarget | eCommandTryTargetAPILock), 1229 m_options() 1230 { 1231 } 1232 1233 ~CommandObjectPlatformProcessLaunch() override = default; 1234 1235 Options * 1236 GetOptions () override 1237 { 1238 return &m_options; 1239 } 1240 1241 protected: 1242 bool 1243 DoExecute (Args& args, CommandReturnObject &result) override 1244 { 1245 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1246 PlatformSP platform_sp; 1247 if (target) 1248 { 1249 platform_sp = target->GetPlatform(); 1250 } 1251 if (!platform_sp) 1252 { 1253 platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); 1254 } 1255 1256 if (platform_sp) 1257 { 1258 Error error; 1259 const size_t argc = args.GetArgumentCount(); 1260 Target *target = m_exe_ctx.GetTargetPtr(); 1261 Module *exe_module = target->GetExecutableModulePointer(); 1262 if (exe_module) 1263 { 1264 m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec(); 1265 char exe_path[PATH_MAX]; 1266 if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path))) 1267 m_options.launch_info.GetArguments().AppendArgument (exe_path); 1268 m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture(); 1269 } 1270 1271 if (argc > 0) 1272 { 1273 if (m_options.launch_info.GetExecutableFile ()) 1274 { 1275 // We already have an executable file, so we will use this 1276 // and all arguments to this function are extra arguments 1277 m_options.launch_info.GetArguments().AppendArguments (args); 1278 } 1279 else 1280 { 1281 // We don't have any file yet, so the first argument is our 1282 // executable, and the rest are program arguments 1283 const bool first_arg_is_executable = true; 1284 m_options.launch_info.SetArguments (args, first_arg_is_executable); 1285 } 1286 } 1287 1288 if (m_options.launch_info.GetExecutableFile ()) 1289 { 1290 Debugger &debugger = m_interpreter.GetDebugger(); 1291 1292 if (argc == 0) 1293 target->GetRunArguments(m_options.launch_info.GetArguments()); 1294 1295 ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info, 1296 debugger, 1297 target, 1298 error)); 1299 if (process_sp && process_sp->IsAlive()) 1300 { 1301 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1302 return true; 1303 } 1304 1305 if (error.Success()) 1306 result.AppendError ("process launch failed"); 1307 else 1308 result.AppendError (error.AsCString()); 1309 result.SetStatus (eReturnStatusFailed); 1310 } 1311 else 1312 { 1313 result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command"); 1314 result.SetStatus (eReturnStatusFailed); 1315 return false; 1316 } 1317 } 1318 else 1319 { 1320 result.AppendError ("no platform is selected\n"); 1321 } 1322 return result.Succeeded(); 1323 } 1324 1325 protected: 1326 ProcessLaunchCommandOptions m_options; 1327 }; 1328 1329 //---------------------------------------------------------------------- 1330 // "platform process list" 1331 //---------------------------------------------------------------------- 1332 class CommandObjectPlatformProcessList : public CommandObjectParsed 1333 { 1334 public: 1335 CommandObjectPlatformProcessList (CommandInterpreter &interpreter) : 1336 CommandObjectParsed (interpreter, 1337 "platform process list", 1338 "List processes on a remote platform by name, pid, or many other matching attributes.", 1339 "platform process list", 1340 0), 1341 m_options() 1342 { 1343 } 1344 1345 ~CommandObjectPlatformProcessList() override = default; 1346 1347 Options * 1348 GetOptions () override 1349 { 1350 return &m_options; 1351 } 1352 1353 protected: 1354 bool 1355 DoExecute (Args& args, CommandReturnObject &result) override 1356 { 1357 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1358 PlatformSP platform_sp; 1359 if (target) 1360 { 1361 platform_sp = target->GetPlatform(); 1362 } 1363 if (!platform_sp) 1364 { 1365 platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); 1366 } 1367 1368 if (platform_sp) 1369 { 1370 Error error; 1371 if (args.GetArgumentCount() == 0) 1372 { 1373 if (platform_sp) 1374 { 1375 Stream &ostrm = result.GetOutputStream(); 1376 1377 lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID(); 1378 if (pid != LLDB_INVALID_PROCESS_ID) 1379 { 1380 ProcessInstanceInfo proc_info; 1381 if (platform_sp->GetProcessInfo (pid, proc_info)) 1382 { 1383 ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); 1384 proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); 1385 result.SetStatus (eReturnStatusSuccessFinishResult); 1386 } 1387 else 1388 { 1389 result.AppendErrorWithFormat ("no process found with pid = %" PRIu64 "\n", pid); 1390 result.SetStatus (eReturnStatusFailed); 1391 } 1392 } 1393 else 1394 { 1395 ProcessInstanceInfoList proc_infos; 1396 const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos); 1397 const char *match_desc = nullptr; 1398 const char *match_name = m_options.match_info.GetProcessInfo().GetName(); 1399 if (match_name && match_name[0]) 1400 { 1401 switch (m_options.match_info.GetNameMatchType()) 1402 { 1403 case eNameMatchIgnore: break; 1404 case eNameMatchEquals: match_desc = "matched"; break; 1405 case eNameMatchContains: match_desc = "contained"; break; 1406 case eNameMatchStartsWith: match_desc = "started with"; break; 1407 case eNameMatchEndsWith: match_desc = "ended with"; break; 1408 case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break; 1409 } 1410 } 1411 1412 if (matches == 0) 1413 { 1414 if (match_desc) 1415 result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n", 1416 match_desc, 1417 match_name, 1418 platform_sp->GetPluginName().GetCString()); 1419 else 1420 result.AppendErrorWithFormat ("no processes were found on the \"%s\" platform\n", platform_sp->GetPluginName().GetCString()); 1421 result.SetStatus (eReturnStatusFailed); 1422 } 1423 else 1424 { 1425 result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"", 1426 matches, 1427 matches > 1 ? "es were" : " was", 1428 platform_sp->GetName().GetCString()); 1429 if (match_desc) 1430 result.AppendMessageWithFormat (" whose name %s \"%s\"", 1431 match_desc, 1432 match_name); 1433 result.AppendMessageWithFormat ("\n"); 1434 ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); 1435 for (uint32_t i=0; i<matches; ++i) 1436 { 1437 proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); 1438 } 1439 } 1440 } 1441 } 1442 } 1443 else 1444 { 1445 result.AppendError ("invalid args: process list takes only options\n"); 1446 result.SetStatus (eReturnStatusFailed); 1447 } 1448 } 1449 else 1450 { 1451 result.AppendError ("no platform is selected\n"); 1452 result.SetStatus (eReturnStatusFailed); 1453 } 1454 return result.Succeeded(); 1455 } 1456 1457 class CommandOptions : public Options 1458 { 1459 public: 1460 CommandOptions() : 1461 Options(), 1462 match_info(), 1463 show_args(false), 1464 verbose(false) 1465 { 1466 static std::once_flag g_once_flag; 1467 std::call_once(g_once_flag, []() { 1468 PosixPlatformCommandOptionValidator *posix_validator = new PosixPlatformCommandOptionValidator(); 1469 for (size_t i=0; g_option_table[i].short_option != 0; ++i) 1470 { 1471 switch (g_option_table[i].short_option) 1472 { 1473 case 'u': 1474 case 'U': 1475 case 'g': 1476 case 'G': 1477 g_option_table[i].validator = posix_validator; 1478 break; 1479 default: 1480 break; 1481 } 1482 } 1483 }); 1484 } 1485 1486 ~CommandOptions() override = default; 1487 1488 Error 1489 SetOptionValue(uint32_t option_idx, const char *option_arg, 1490 ExecutionContext *execution_context) override 1491 { 1492 Error error; 1493 const int short_option = m_getopt_table[option_idx].val; 1494 bool success = false; 1495 1496 switch (short_option) 1497 { 1498 case 'p': 1499 match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success)); 1500 if (!success) 1501 error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg); 1502 break; 1503 1504 case 'P': 1505 match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success)); 1506 if (!success) 1507 error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg); 1508 break; 1509 1510 case 'u': 1511 match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); 1512 if (!success) 1513 error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg); 1514 break; 1515 1516 case 'U': 1517 match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); 1518 if (!success) 1519 error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg); 1520 break; 1521 1522 case 'g': 1523 match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); 1524 if (!success) 1525 error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg); 1526 break; 1527 1528 case 'G': 1529 match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); 1530 if (!success) 1531 error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg); 1532 break; 1533 1534 case 'a': 1535 { 1536 TargetSP target_sp = execution_context ? 1537 execution_context->GetTargetSP() : TargetSP(); 1538 DebuggerSP debugger_sp = target_sp ? 1539 target_sp->GetDebugger().shared_from_this() : 1540 DebuggerSP(); 1541 PlatformSP platform_sp = debugger_sp ? 1542 debugger_sp->GetPlatformList().GetSelectedPlatform() : 1543 PlatformSP(); 1544 match_info.GetProcessInfo().GetArchitecture().SetTriple( 1545 option_arg, platform_sp.get()); 1546 } 1547 break; 1548 1549 case 'n': 1550 match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false); 1551 match_info.SetNameMatchType (eNameMatchEquals); 1552 break; 1553 1554 case 'e': 1555 match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false); 1556 match_info.SetNameMatchType (eNameMatchEndsWith); 1557 break; 1558 1559 case 's': 1560 match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false); 1561 match_info.SetNameMatchType (eNameMatchStartsWith); 1562 break; 1563 1564 case 'c': 1565 match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false); 1566 match_info.SetNameMatchType (eNameMatchContains); 1567 break; 1568 1569 case 'r': 1570 match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false); 1571 match_info.SetNameMatchType (eNameMatchRegularExpression); 1572 break; 1573 1574 case 'A': 1575 show_args = true; 1576 break; 1577 1578 case 'v': 1579 verbose = true; 1580 break; 1581 1582 default: 1583 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1584 break; 1585 } 1586 1587 return error; 1588 } 1589 1590 void 1591 OptionParsingStarting(ExecutionContext *execution_context) override 1592 { 1593 match_info.Clear(); 1594 show_args = false; 1595 verbose = false; 1596 } 1597 1598 const OptionDefinition* 1599 GetDefinitions () override 1600 { 1601 return g_option_table; 1602 } 1603 1604 // Options table: Required for subclasses of Options. 1605 1606 static OptionDefinition g_option_table[]; 1607 1608 // Instance variables to hold the values for command options. 1609 1610 ProcessInstanceInfoMatch match_info; 1611 bool show_args; 1612 bool verbose; 1613 }; 1614 1615 CommandOptions m_options; 1616 }; 1617 1618 OptionDefinition 1619 CommandObjectPlatformProcessList::CommandOptions::g_option_table[] = 1620 { 1621 // clang-format off 1622 {LLDB_OPT_SET_1, false, "pid", 'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePid, "List the process info for a specific process ID."}, 1623 {LLDB_OPT_SET_2, true, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName, "Find processes with executable basenames that match a string."}, 1624 {LLDB_OPT_SET_3, true, "ends-with", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName, "Find processes with executable basenames that end with a string."}, 1625 {LLDB_OPT_SET_4, true, "starts-with", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName, "Find processes with executable basenames that start with a string."}, 1626 {LLDB_OPT_SET_5, true, "contains", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName, "Find processes with executable basenames that contain a string."}, 1627 {LLDB_OPT_SET_6, true, "regex", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression."}, 1628 {LLDB_OPT_SET_FROM_TO(2, 6), false, "parent", 'P', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePid, "Find processes that have a matching parent process ID."}, 1629 {LLDB_OPT_SET_FROM_TO(2, 6), false, "uid", 'u', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Find processes that have a matching user ID."}, 1630 {LLDB_OPT_SET_FROM_TO(2, 6), false, "euid", 'U', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Find processes that have a matching effective user ID."}, 1631 {LLDB_OPT_SET_FROM_TO(2, 6), false, "gid", 'g', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Find processes that have a matching group ID."}, 1632 {LLDB_OPT_SET_FROM_TO(2, 6), false, "egid", 'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Find processes that have a matching effective group ID."}, 1633 {LLDB_OPT_SET_FROM_TO(2, 6), false, "arch", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeArchitecture, "Find processes that have a matching architecture."}, 1634 {LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args", 'A', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show process arguments instead of the process executable basename."}, 1635 {LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable verbose output."}, 1636 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 1637 // clang-format on 1638 }; 1639 1640 //---------------------------------------------------------------------- 1641 // "platform process info" 1642 //---------------------------------------------------------------------- 1643 class CommandObjectPlatformProcessInfo : public CommandObjectParsed 1644 { 1645 public: 1646 CommandObjectPlatformProcessInfo (CommandInterpreter &interpreter) : 1647 CommandObjectParsed (interpreter, 1648 "platform process info", 1649 "Get detailed information for one or more process by process ID.", 1650 "platform process info <pid> [<pid> <pid> ...]", 1651 0) 1652 { 1653 CommandArgumentEntry arg; 1654 CommandArgumentData pid_args; 1655 1656 // Define the first (and only) variant of this arg. 1657 pid_args.arg_type = eArgTypePid; 1658 pid_args.arg_repetition = eArgRepeatStar; 1659 1660 // There is only one variant this argument could be; put it into the argument entry. 1661 arg.push_back (pid_args); 1662 1663 // Push the data for the first argument into the m_arguments vector. 1664 m_arguments.push_back (arg); 1665 } 1666 1667 ~CommandObjectPlatformProcessInfo() override = default; 1668 1669 protected: 1670 bool 1671 DoExecute (Args& args, CommandReturnObject &result) override 1672 { 1673 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1674 PlatformSP platform_sp; 1675 if (target) 1676 { 1677 platform_sp = target->GetPlatform(); 1678 } 1679 if (!platform_sp) 1680 { 1681 platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); 1682 } 1683 1684 if (platform_sp) 1685 { 1686 const size_t argc = args.GetArgumentCount(); 1687 if (argc > 0) 1688 { 1689 Error error; 1690 1691 if (platform_sp->IsConnected()) 1692 { 1693 Stream &ostrm = result.GetOutputStream(); 1694 bool success; 1695 for (size_t i=0; i<argc; ++ i) 1696 { 1697 const char *arg = args.GetArgumentAtIndex(i); 1698 lldb::pid_t pid = StringConvert::ToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success); 1699 if (success) 1700 { 1701 ProcessInstanceInfo proc_info; 1702 if (platform_sp->GetProcessInfo (pid, proc_info)) 1703 { 1704 ostrm.Printf ("Process information for process %" PRIu64 ":\n", pid); 1705 proc_info.Dump (ostrm, platform_sp.get()); 1706 } 1707 else 1708 { 1709 ostrm.Printf ("error: no process information is available for process %" PRIu64 "\n", pid); 1710 } 1711 ostrm.EOL(); 1712 } 1713 else 1714 { 1715 result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg); 1716 result.SetStatus (eReturnStatusFailed); 1717 break; 1718 } 1719 } 1720 } 1721 else 1722 { 1723 // Not connected... 1724 result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString()); 1725 result.SetStatus (eReturnStatusFailed); 1726 } 1727 } 1728 else 1729 { 1730 // No args 1731 result.AppendError ("one or more process id(s) must be specified"); 1732 result.SetStatus (eReturnStatusFailed); 1733 } 1734 } 1735 else 1736 { 1737 result.AppendError ("no platform is currently selected"); 1738 result.SetStatus (eReturnStatusFailed); 1739 } 1740 return result.Succeeded(); 1741 } 1742 }; 1743 1744 class CommandObjectPlatformProcessAttach : public CommandObjectParsed 1745 { 1746 public: 1747 class CommandOptions : public Options 1748 { 1749 public: 1750 CommandOptions() : 1751 Options() 1752 { 1753 // Keep default values of all options in one place: OptionParsingStarting () 1754 OptionParsingStarting(nullptr); 1755 } 1756 1757 ~CommandOptions() override = default; 1758 1759 Error 1760 SetOptionValue (uint32_t option_idx, const char *option_arg, 1761 ExecutionContext *execution_context) override 1762 { 1763 Error error; 1764 char short_option = (char) m_getopt_table[option_idx].val; 1765 bool success = false; 1766 switch (short_option) 1767 { 1768 case 'p': 1769 { 1770 lldb::pid_t pid = StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); 1771 if (!success || pid == LLDB_INVALID_PROCESS_ID) 1772 { 1773 error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg); 1774 } 1775 else 1776 { 1777 attach_info.SetProcessID (pid); 1778 } 1779 } 1780 break; 1781 1782 case 'P': 1783 attach_info.SetProcessPluginName (option_arg); 1784 break; 1785 1786 case 'n': 1787 attach_info.GetExecutableFile().SetFile(option_arg, false); 1788 break; 1789 1790 case 'w': 1791 attach_info.SetWaitForLaunch(true); 1792 break; 1793 1794 default: 1795 error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); 1796 break; 1797 } 1798 return error; 1799 } 1800 1801 void 1802 OptionParsingStarting(ExecutionContext *execution_context) override 1803 { 1804 attach_info.Clear(); 1805 } 1806 1807 const OptionDefinition* 1808 GetDefinitions () override 1809 { 1810 return g_option_table; 1811 } 1812 1813 bool 1814 HandleOptionArgumentCompletion (Args &input, 1815 int cursor_index, 1816 int char_pos, 1817 OptionElementVector &opt_element_vector, 1818 int opt_element_index, 1819 int match_start_point, 1820 int max_return_elements, 1821 CommandInterpreter &interpreter, 1822 bool &word_complete, 1823 StringList &matches) override 1824 { 1825 int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; 1826 int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; 1827 1828 // We are only completing the name option for now... 1829 1830 const OptionDefinition *opt_defs = GetDefinitions(); 1831 if (opt_defs[opt_defs_index].short_option == 'n') 1832 { 1833 // Are we in the name? 1834 1835 // Look to see if there is a -P argument provided, and if so use that plugin, otherwise 1836 // use the default plugin. 1837 1838 const char *partial_name = nullptr; 1839 partial_name = input.GetArgumentAtIndex(opt_arg_pos); 1840 1841 PlatformSP platform_sp(interpreter.GetPlatform(true)); 1842 if (platform_sp) 1843 { 1844 ProcessInstanceInfoList process_infos; 1845 ProcessInstanceInfoMatch match_info; 1846 if (partial_name) 1847 { 1848 match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false); 1849 match_info.SetNameMatchType(eNameMatchStartsWith); 1850 } 1851 platform_sp->FindProcesses (match_info, process_infos); 1852 const uint32_t num_matches = process_infos.GetSize(); 1853 if (num_matches > 0) 1854 { 1855 for (uint32_t i=0; i<num_matches; ++i) 1856 { 1857 matches.AppendString (process_infos.GetProcessNameAtIndex(i), 1858 process_infos.GetProcessNameLengthAtIndex(i)); 1859 } 1860 } 1861 } 1862 } 1863 1864 return false; 1865 } 1866 1867 // Options table: Required for subclasses of Options. 1868 1869 static OptionDefinition g_option_table[]; 1870 1871 // Instance variables to hold the values for command options. 1872 1873 ProcessAttachInfo attach_info; 1874 }; 1875 1876 CommandObjectPlatformProcessAttach (CommandInterpreter &interpreter) : 1877 CommandObjectParsed (interpreter, 1878 "platform process attach", 1879 "Attach to a process.", 1880 "platform process attach <cmd-options>"), 1881 m_options() 1882 { 1883 } 1884 1885 ~CommandObjectPlatformProcessAttach() override = default; 1886 1887 bool 1888 DoExecute (Args& command, 1889 CommandReturnObject &result) override 1890 { 1891 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 1892 if (platform_sp) 1893 { 1894 Error err; 1895 ProcessSP remote_process_sp = 1896 platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), nullptr, err); 1897 if (err.Fail()) 1898 { 1899 result.AppendError(err.AsCString()); 1900 result.SetStatus (eReturnStatusFailed); 1901 } 1902 else if (!remote_process_sp) 1903 { 1904 result.AppendError("could not attach: unknown reason"); 1905 result.SetStatus (eReturnStatusFailed); 1906 } 1907 else 1908 result.SetStatus (eReturnStatusSuccessFinishResult); 1909 } 1910 else 1911 { 1912 result.AppendError ("no platform is currently selected"); 1913 result.SetStatus (eReturnStatusFailed); 1914 } 1915 return result.Succeeded(); 1916 } 1917 1918 Options * 1919 GetOptions () override 1920 { 1921 return &m_options; 1922 } 1923 1924 protected: 1925 CommandOptions m_options; 1926 }; 1927 1928 OptionDefinition 1929 CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] = 1930 { 1931 // clang-format off 1932 {LLDB_OPT_SET_ALL, false, "plugin", 'P', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePlugin, "Name of the process plugin you want to use."}, 1933 {LLDB_OPT_SET_1, false, "pid", 'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePid, "The process ID of an existing process to attach to."}, 1934 {LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeProcessName, "The name of the process to attach to."}, 1935 {LLDB_OPT_SET_2, false, "waitfor", 'w', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."}, 1936 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 1937 // clang-format on 1938 }; 1939 1940 class CommandObjectPlatformProcess : public CommandObjectMultiword 1941 { 1942 public: 1943 //------------------------------------------------------------------ 1944 // Constructors and Destructors 1945 //------------------------------------------------------------------ 1946 CommandObjectPlatformProcess(CommandInterpreter &interpreter) 1947 : CommandObjectMultiword(interpreter, "platform process", 1948 "Commands to query, launch and attach to processes on the current platform.", 1949 "platform process [attach|launch|list] ...") 1950 { 1951 LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter))); 1952 LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter))); 1953 LoadSubCommand ("info" , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter))); 1954 LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter))); 1955 } 1956 1957 ~CommandObjectPlatformProcess() override = default; 1958 1959 private: 1960 //------------------------------------------------------------------ 1961 // For CommandObjectPlatform only 1962 //------------------------------------------------------------------ 1963 DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess); 1964 }; 1965 1966 //---------------------------------------------------------------------- 1967 // "platform shell" 1968 //---------------------------------------------------------------------- 1969 class CommandObjectPlatformShell : public CommandObjectRaw 1970 { 1971 public: 1972 class CommandOptions : public Options 1973 { 1974 public: 1975 CommandOptions() : 1976 Options(), 1977 timeout(10) 1978 { 1979 } 1980 1981 ~CommandOptions() override = default; 1982 1983 virtual uint32_t 1984 GetNumDefinitions () 1985 { 1986 return 1; 1987 } 1988 1989 const OptionDefinition* 1990 GetDefinitions () override 1991 { 1992 return g_option_table; 1993 } 1994 1995 Error 1996 SetOptionValue (uint32_t option_idx, 1997 const char *option_value, 1998 ExecutionContext *execution_context) override 1999 { 2000 Error error; 2001 2002 const char short_option = (char) g_option_table[option_idx].short_option; 2003 2004 switch (short_option) 2005 { 2006 case 't': 2007 { 2008 bool success; 2009 timeout = StringConvert::ToUInt32(option_value, 10, 10, &success); 2010 if (!success) 2011 error.SetErrorStringWithFormat("could not convert \"%s\" to a numeric value.", option_value); 2012 break; 2013 } 2014 default: 2015 error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); 2016 break; 2017 } 2018 2019 return error; 2020 } 2021 2022 void 2023 OptionParsingStarting(ExecutionContext *execution_context) override 2024 { 2025 } 2026 2027 // Options table: Required for subclasses of Options. 2028 2029 static OptionDefinition g_option_table[]; 2030 uint32_t timeout; 2031 }; 2032 2033 CommandObjectPlatformShell(CommandInterpreter &interpreter) 2034 : CommandObjectRaw(interpreter, "platform shell", "Run a shell command on the current platform.", 2035 "platform shell <shell-command>", 0), 2036 m_options() 2037 { 2038 } 2039 2040 ~CommandObjectPlatformShell() override = default; 2041 2042 Options * 2043 GetOptions () override 2044 { 2045 return &m_options; 2046 } 2047 2048 bool 2049 DoExecute (const char *raw_command_line, CommandReturnObject &result) override 2050 { 2051 ExecutionContext exe_ctx = 2052 GetCommandInterpreter().GetExecutionContext(); 2053 m_options.NotifyOptionParsingStarting(&exe_ctx); 2054 2055 const char* expr = nullptr; 2056 2057 // Print out an usage syntax on an empty command line. 2058 if (raw_command_line[0] == '\0') 2059 { 2060 result.GetOutputStream().Printf("%s\n", this->GetSyntax()); 2061 return true; 2062 } 2063 2064 if (raw_command_line[0] == '-') 2065 { 2066 // We have some options and these options MUST end with --. 2067 const char *end_options = nullptr; 2068 const char *s = raw_command_line; 2069 while (s && s[0]) 2070 { 2071 end_options = ::strstr (s, "--"); 2072 if (end_options) 2073 { 2074 end_options += 2; // Get past the "--" 2075 if (::isspace (end_options[0])) 2076 { 2077 expr = end_options; 2078 while (::isspace (*expr)) 2079 ++expr; 2080 break; 2081 } 2082 } 2083 s = end_options; 2084 } 2085 2086 if (end_options) 2087 { 2088 Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line)); 2089 if (!ParseOptions (args, result)) 2090 return false; 2091 } 2092 } 2093 2094 if (expr == nullptr) 2095 expr = raw_command_line; 2096 2097 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 2098 Error error; 2099 if (platform_sp) 2100 { 2101 FileSpec working_dir{}; 2102 std::string output; 2103 int status = -1; 2104 int signo = -1; 2105 error = (platform_sp->RunShellCommand (expr, working_dir, &status, &signo, &output, m_options.timeout)); 2106 if (!output.empty()) 2107 result.GetOutputStream().PutCString(output.c_str()); 2108 if (status > 0) 2109 { 2110 if (signo > 0) 2111 { 2112 const char *signo_cstr = Host::GetSignalAsCString(signo); 2113 if (signo_cstr) 2114 result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr); 2115 else 2116 result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo); 2117 } 2118 else 2119 result.GetOutputStream().Printf("error: command returned with status %i\n", status); 2120 } 2121 } 2122 else 2123 { 2124 result.GetOutputStream().Printf("error: cannot run remote shell commands without a platform\n"); 2125 error.SetErrorString("error: cannot run remote shell commands without a platform"); 2126 } 2127 2128 if (error.Fail()) 2129 { 2130 result.AppendError(error.AsCString()); 2131 result.SetStatus (eReturnStatusFailed); 2132 } 2133 else 2134 { 2135 result.SetStatus (eReturnStatusSuccessFinishResult); 2136 } 2137 return true; 2138 } 2139 2140 CommandOptions m_options; 2141 }; 2142 2143 OptionDefinition 2144 CommandObjectPlatformShell::CommandOptions::g_option_table[] = 2145 { 2146 // clang-format off 2147 {LLDB_OPT_SET_ALL, false, "timeout", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, "Seconds to wait for the remote host to finish running the command."}, 2148 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 2149 // clang-format on 2150 }; 2151 2152 //---------------------------------------------------------------------- 2153 // "platform install" - install a target to a remote end 2154 //---------------------------------------------------------------------- 2155 class CommandObjectPlatformInstall : public CommandObjectParsed 2156 { 2157 public: 2158 CommandObjectPlatformInstall (CommandInterpreter &interpreter) : 2159 CommandObjectParsed (interpreter, 2160 "platform target-install", 2161 "Install a target (bundle or executable file) to the remote end.", 2162 "platform target-install <local-thing> <remote-sandbox>", 2163 0) 2164 { 2165 } 2166 2167 ~CommandObjectPlatformInstall() override = default; 2168 2169 bool 2170 DoExecute (Args& args, CommandReturnObject &result) override 2171 { 2172 if (args.GetArgumentCount() != 2) 2173 { 2174 result.AppendError("platform target-install takes two arguments"); 2175 result.SetStatus(eReturnStatusFailed); 2176 return false; 2177 } 2178 // TODO: move the bulk of this code over to the platform itself 2179 FileSpec src(args.GetArgumentAtIndex(0), true); 2180 FileSpec dst(args.GetArgumentAtIndex(1), false); 2181 if (!src.Exists()) 2182 { 2183 result.AppendError("source location does not exist or is not accessible"); 2184 result.SetStatus(eReturnStatusFailed); 2185 return false; 2186 } 2187 PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); 2188 if (!platform_sp) 2189 { 2190 result.AppendError ("no platform currently selected"); 2191 result.SetStatus (eReturnStatusFailed); 2192 return false; 2193 } 2194 2195 Error error = platform_sp->Install(src, dst); 2196 if (error.Success()) 2197 { 2198 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2199 } 2200 else 2201 { 2202 result.AppendErrorWithFormat("install failed: %s", error.AsCString()); 2203 result.SetStatus(eReturnStatusFailed); 2204 } 2205 return result.Succeeded(); 2206 } 2207 }; 2208 2209 CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) 2210 : CommandObjectMultiword(interpreter, "platform", "Commands to manage and create platforms.", 2211 "platform [connect|disconnect|info|list|status|select] ...") 2212 { 2213 LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter))); 2214 LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter))); 2215 LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter))); 2216 LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter))); 2217 LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter))); 2218 LoadSubCommand ("settings", CommandObjectSP (new CommandObjectPlatformSettings (interpreter))); 2219 LoadSubCommand ("mkdir", CommandObjectSP (new CommandObjectPlatformMkDir (interpreter))); 2220 LoadSubCommand ("file", CommandObjectSP (new CommandObjectPlatformFile (interpreter))); 2221 LoadSubCommand ("get-file", CommandObjectSP (new CommandObjectPlatformGetFile (interpreter))); 2222 LoadSubCommand ("get-size", CommandObjectSP (new CommandObjectPlatformGetSize (interpreter))); 2223 LoadSubCommand ("put-file", CommandObjectSP (new CommandObjectPlatformPutFile (interpreter))); 2224 LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter))); 2225 LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter))); 2226 LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall (interpreter))); 2227 } 2228 2229 CommandObjectPlatform::~CommandObjectPlatform() = default; 2230