1 //===-- SBPlatform.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/API/SBPlatform.h" 10 #include "lldb/API/SBEnvironment.h" 11 #include "lldb/API/SBError.h" 12 #include "lldb/API/SBFileSpec.h" 13 #include "lldb/API/SBLaunchInfo.h" 14 #include "lldb/API/SBPlatform.h" 15 #include "lldb/API/SBUnixSignals.h" 16 #include "lldb/Host/File.h" 17 #include "lldb/Target/Platform.h" 18 #include "lldb/Target/Target.h" 19 #include "lldb/Utility/ArchSpec.h" 20 #include "lldb/Utility/Args.h" 21 #include "lldb/Utility/Instrumentation.h" 22 #include "lldb/Utility/Status.h" 23 24 #include "llvm/Support/FileSystem.h" 25 26 #include <functional> 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 // PlatformConnectOptions 32 struct PlatformConnectOptions { 33 PlatformConnectOptions(const char *url = nullptr) { 34 if (url && url[0]) 35 m_url = url; 36 } 37 38 ~PlatformConnectOptions() = default; 39 40 std::string m_url; 41 std::string m_rsync_options; 42 std::string m_rsync_remote_path_prefix; 43 bool m_rsync_enabled = false; 44 bool m_rsync_omit_hostname_from_remote_path = false; 45 ConstString m_local_cache_directory; 46 }; 47 48 // PlatformShellCommand 49 struct PlatformShellCommand { 50 PlatformShellCommand(llvm::StringRef shell_interpreter, 51 llvm::StringRef shell_command) { 52 if (!shell_interpreter.empty()) 53 m_shell = shell_interpreter.str(); 54 55 if (!m_shell.empty() && !shell_command.empty()) 56 m_command = shell_command.str(); 57 } 58 59 PlatformShellCommand(llvm::StringRef shell_command = llvm::StringRef()) { 60 if (!shell_command.empty()) 61 m_command = shell_command.str(); 62 } 63 64 ~PlatformShellCommand() = default; 65 66 std::string m_shell; 67 std::string m_command; 68 std::string m_working_dir; 69 std::string m_output; 70 int m_status = 0; 71 int m_signo = 0; 72 Timeout<std::ratio<1>> m_timeout = llvm::None; 73 }; 74 // SBPlatformConnectOptions 75 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url) 76 : m_opaque_ptr(new PlatformConnectOptions(url)) { 77 LLDB_INSTRUMENT_VA(this, url); 78 } 79 80 SBPlatformConnectOptions::SBPlatformConnectOptions( 81 const SBPlatformConnectOptions &rhs) 82 : m_opaque_ptr(new PlatformConnectOptions()) { 83 LLDB_INSTRUMENT_VA(this, rhs); 84 85 *m_opaque_ptr = *rhs.m_opaque_ptr; 86 } 87 88 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; } 89 90 SBPlatformConnectOptions & 91 SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) { 92 LLDB_INSTRUMENT_VA(this, rhs); 93 94 *m_opaque_ptr = *rhs.m_opaque_ptr; 95 return *this; 96 } 97 98 const char *SBPlatformConnectOptions::GetURL() { 99 LLDB_INSTRUMENT_VA(this); 100 101 if (m_opaque_ptr->m_url.empty()) 102 return nullptr; 103 return m_opaque_ptr->m_url.c_str(); 104 } 105 106 void SBPlatformConnectOptions::SetURL(const char *url) { 107 LLDB_INSTRUMENT_VA(this, url); 108 109 if (url && url[0]) 110 m_opaque_ptr->m_url = url; 111 else 112 m_opaque_ptr->m_url.clear(); 113 } 114 115 bool SBPlatformConnectOptions::GetRsyncEnabled() { 116 LLDB_INSTRUMENT_VA(this); 117 118 return m_opaque_ptr->m_rsync_enabled; 119 } 120 121 void SBPlatformConnectOptions::EnableRsync( 122 const char *options, const char *remote_path_prefix, 123 bool omit_hostname_from_remote_path) { 124 LLDB_INSTRUMENT_VA(this, options, remote_path_prefix, 125 omit_hostname_from_remote_path); 126 127 m_opaque_ptr->m_rsync_enabled = true; 128 m_opaque_ptr->m_rsync_omit_hostname_from_remote_path = 129 omit_hostname_from_remote_path; 130 if (remote_path_prefix && remote_path_prefix[0]) 131 m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix; 132 else 133 m_opaque_ptr->m_rsync_remote_path_prefix.clear(); 134 135 if (options && options[0]) 136 m_opaque_ptr->m_rsync_options = options; 137 else 138 m_opaque_ptr->m_rsync_options.clear(); 139 } 140 141 void SBPlatformConnectOptions::DisableRsync() { 142 LLDB_INSTRUMENT_VA(this); 143 144 m_opaque_ptr->m_rsync_enabled = false; 145 } 146 147 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() { 148 LLDB_INSTRUMENT_VA(this); 149 150 return m_opaque_ptr->m_local_cache_directory.GetCString(); 151 } 152 153 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) { 154 LLDB_INSTRUMENT_VA(this, path); 155 156 if (path && path[0]) 157 m_opaque_ptr->m_local_cache_directory.SetCString(path); 158 else 159 m_opaque_ptr->m_local_cache_directory = ConstString(); 160 } 161 162 // SBPlatformShellCommand 163 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_interpreter, 164 const char *shell_command) 165 : m_opaque_ptr(new PlatformShellCommand(shell_interpreter, shell_command)) { 166 LLDB_INSTRUMENT_VA(this, shell_interpreter, shell_command); 167 } 168 169 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command) 170 : m_opaque_ptr(new PlatformShellCommand(shell_command)) { 171 LLDB_INSTRUMENT_VA(this, shell_command); 172 } 173 174 SBPlatformShellCommand::SBPlatformShellCommand( 175 const SBPlatformShellCommand &rhs) 176 : m_opaque_ptr(new PlatformShellCommand()) { 177 LLDB_INSTRUMENT_VA(this, rhs); 178 179 *m_opaque_ptr = *rhs.m_opaque_ptr; 180 } 181 182 SBPlatformShellCommand & 183 SBPlatformShellCommand::operator=(const SBPlatformShellCommand &rhs) { 184 185 LLDB_INSTRUMENT_VA(this, rhs); 186 187 *m_opaque_ptr = *rhs.m_opaque_ptr; 188 return *this; 189 } 190 191 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; } 192 193 void SBPlatformShellCommand::Clear() { 194 LLDB_INSTRUMENT_VA(this); 195 196 m_opaque_ptr->m_output = std::string(); 197 m_opaque_ptr->m_status = 0; 198 m_opaque_ptr->m_signo = 0; 199 } 200 201 const char *SBPlatformShellCommand::GetShell() { 202 LLDB_INSTRUMENT_VA(this); 203 204 if (m_opaque_ptr->m_shell.empty()) 205 return nullptr; 206 return m_opaque_ptr->m_shell.c_str(); 207 } 208 209 void SBPlatformShellCommand::SetShell(const char *shell_interpreter) { 210 LLDB_INSTRUMENT_VA(this, shell_interpreter); 211 212 if (shell_interpreter && shell_interpreter[0]) 213 m_opaque_ptr->m_shell = shell_interpreter; 214 else 215 m_opaque_ptr->m_shell.clear(); 216 } 217 218 const char *SBPlatformShellCommand::GetCommand() { 219 LLDB_INSTRUMENT_VA(this); 220 221 if (m_opaque_ptr->m_command.empty()) 222 return nullptr; 223 return m_opaque_ptr->m_command.c_str(); 224 } 225 226 void SBPlatformShellCommand::SetCommand(const char *shell_command) { 227 LLDB_INSTRUMENT_VA(this, shell_command); 228 229 if (shell_command && shell_command[0]) 230 m_opaque_ptr->m_command = shell_command; 231 else 232 m_opaque_ptr->m_command.clear(); 233 } 234 235 const char *SBPlatformShellCommand::GetWorkingDirectory() { 236 LLDB_INSTRUMENT_VA(this); 237 238 if (m_opaque_ptr->m_working_dir.empty()) 239 return nullptr; 240 return m_opaque_ptr->m_working_dir.c_str(); 241 } 242 243 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) { 244 LLDB_INSTRUMENT_VA(this, path); 245 246 if (path && path[0]) 247 m_opaque_ptr->m_working_dir = path; 248 else 249 m_opaque_ptr->m_working_dir.clear(); 250 } 251 252 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() { 253 LLDB_INSTRUMENT_VA(this); 254 255 if (m_opaque_ptr->m_timeout) 256 return m_opaque_ptr->m_timeout->count(); 257 return UINT32_MAX; 258 } 259 260 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) { 261 LLDB_INSTRUMENT_VA(this, sec); 262 263 if (sec == UINT32_MAX) 264 m_opaque_ptr->m_timeout = llvm::None; 265 else 266 m_opaque_ptr->m_timeout = std::chrono::seconds(sec); 267 } 268 269 int SBPlatformShellCommand::GetSignal() { 270 LLDB_INSTRUMENT_VA(this); 271 272 return m_opaque_ptr->m_signo; 273 } 274 275 int SBPlatformShellCommand::GetStatus() { 276 LLDB_INSTRUMENT_VA(this); 277 278 return m_opaque_ptr->m_status; 279 } 280 281 const char *SBPlatformShellCommand::GetOutput() { 282 LLDB_INSTRUMENT_VA(this); 283 284 if (m_opaque_ptr->m_output.empty()) 285 return nullptr; 286 return m_opaque_ptr->m_output.c_str(); 287 } 288 289 // SBPlatform 290 SBPlatform::SBPlatform() { LLDB_INSTRUMENT_VA(this); } 291 292 SBPlatform::SBPlatform(const char *platform_name) { 293 LLDB_INSTRUMENT_VA(this, platform_name); 294 295 Status error; 296 if (platform_name && platform_name[0]) 297 m_opaque_sp = Platform::Create(ConstString(platform_name), error); 298 } 299 300 SBPlatform::SBPlatform(const SBPlatform &rhs) { 301 LLDB_INSTRUMENT_VA(this, rhs); 302 303 m_opaque_sp = rhs.m_opaque_sp; 304 } 305 306 SBPlatform &SBPlatform::operator=(const SBPlatform &rhs) { 307 LLDB_INSTRUMENT_VA(this, rhs); 308 309 m_opaque_sp = rhs.m_opaque_sp; 310 return *this; 311 } 312 313 SBPlatform::~SBPlatform() = default; 314 315 SBPlatform SBPlatform::GetHostPlatform() { 316 LLDB_INSTRUMENT(); 317 318 SBPlatform host_platform; 319 host_platform.m_opaque_sp = Platform::GetHostPlatform(); 320 return host_platform; 321 } 322 323 bool SBPlatform::IsValid() const { 324 LLDB_INSTRUMENT_VA(this); 325 return this->operator bool(); 326 } 327 SBPlatform::operator bool() const { 328 LLDB_INSTRUMENT_VA(this); 329 330 return m_opaque_sp.get() != nullptr; 331 } 332 333 void SBPlatform::Clear() { 334 LLDB_INSTRUMENT_VA(this); 335 336 m_opaque_sp.reset(); 337 } 338 339 const char *SBPlatform::GetName() { 340 LLDB_INSTRUMENT_VA(this); 341 342 PlatformSP platform_sp(GetSP()); 343 if (platform_sp) 344 return ConstString(platform_sp->GetName()).AsCString(); 345 return nullptr; 346 } 347 348 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; } 349 350 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) { 351 m_opaque_sp = platform_sp; 352 } 353 354 const char *SBPlatform::GetWorkingDirectory() { 355 LLDB_INSTRUMENT_VA(this); 356 357 PlatformSP platform_sp(GetSP()); 358 if (platform_sp) 359 return platform_sp->GetWorkingDirectory().GetCString(); 360 return nullptr; 361 } 362 363 bool SBPlatform::SetWorkingDirectory(const char *path) { 364 LLDB_INSTRUMENT_VA(this, path); 365 366 PlatformSP platform_sp(GetSP()); 367 if (platform_sp) { 368 if (path) 369 platform_sp->SetWorkingDirectory(FileSpec(path)); 370 else 371 platform_sp->SetWorkingDirectory(FileSpec()); 372 return true; 373 } 374 return false; 375 } 376 377 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) { 378 LLDB_INSTRUMENT_VA(this, connect_options); 379 380 SBError sb_error; 381 PlatformSP platform_sp(GetSP()); 382 if (platform_sp && connect_options.GetURL()) { 383 Args args; 384 args.AppendArgument(connect_options.GetURL()); 385 sb_error.ref() = platform_sp->ConnectRemote(args); 386 } else { 387 sb_error.SetErrorString("invalid platform"); 388 } 389 return sb_error; 390 } 391 392 void SBPlatform::DisconnectRemote() { 393 LLDB_INSTRUMENT_VA(this); 394 395 PlatformSP platform_sp(GetSP()); 396 if (platform_sp) 397 platform_sp->DisconnectRemote(); 398 } 399 400 bool SBPlatform::IsConnected() { 401 LLDB_INSTRUMENT_VA(this); 402 403 PlatformSP platform_sp(GetSP()); 404 if (platform_sp) 405 return platform_sp->IsConnected(); 406 return false; 407 } 408 409 const char *SBPlatform::GetTriple() { 410 LLDB_INSTRUMENT_VA(this); 411 412 PlatformSP platform_sp(GetSP()); 413 if (platform_sp) { 414 ArchSpec arch(platform_sp->GetSystemArchitecture()); 415 if (arch.IsValid()) { 416 // Const-ify the string so we don't need to worry about the lifetime of 417 // the string 418 return ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); 419 } 420 } 421 return nullptr; 422 } 423 424 const char *SBPlatform::GetOSBuild() { 425 LLDB_INSTRUMENT_VA(this); 426 427 PlatformSP platform_sp(GetSP()); 428 if (platform_sp) { 429 std::string s = platform_sp->GetOSBuildString().getValueOr(""); 430 if (!s.empty()) { 431 // Const-ify the string so we don't need to worry about the lifetime of 432 // the string 433 return ConstString(s).GetCString(); 434 } 435 } 436 return nullptr; 437 } 438 439 const char *SBPlatform::GetOSDescription() { 440 LLDB_INSTRUMENT_VA(this); 441 442 PlatformSP platform_sp(GetSP()); 443 if (platform_sp) { 444 std::string s = platform_sp->GetOSKernelDescription().getValueOr(""); 445 if (!s.empty()) { 446 // Const-ify the string so we don't need to worry about the lifetime of 447 // the string 448 return ConstString(s.c_str()).GetCString(); 449 } 450 } 451 return nullptr; 452 } 453 454 const char *SBPlatform::GetHostname() { 455 LLDB_INSTRUMENT_VA(this); 456 457 PlatformSP platform_sp(GetSP()); 458 if (platform_sp) 459 return platform_sp->GetHostname(); 460 return nullptr; 461 } 462 463 uint32_t SBPlatform::GetOSMajorVersion() { 464 LLDB_INSTRUMENT_VA(this); 465 466 llvm::VersionTuple version; 467 if (PlatformSP platform_sp = GetSP()) 468 version = platform_sp->GetOSVersion(); 469 return version.empty() ? UINT32_MAX : version.getMajor(); 470 } 471 472 uint32_t SBPlatform::GetOSMinorVersion() { 473 LLDB_INSTRUMENT_VA(this); 474 475 llvm::VersionTuple version; 476 if (PlatformSP platform_sp = GetSP()) 477 version = platform_sp->GetOSVersion(); 478 return version.getMinor().getValueOr(UINT32_MAX); 479 } 480 481 uint32_t SBPlatform::GetOSUpdateVersion() { 482 LLDB_INSTRUMENT_VA(this); 483 484 llvm::VersionTuple version; 485 if (PlatformSP platform_sp = GetSP()) 486 version = platform_sp->GetOSVersion(); 487 return version.getSubminor().getValueOr(UINT32_MAX); 488 } 489 490 void SBPlatform::SetSDKRoot(const char *sysroot) { 491 LLDB_INSTRUMENT_VA(this, sysroot); 492 if (PlatformSP platform_sp = GetSP()) 493 platform_sp->SetSDKRootDirectory(ConstString(sysroot)); 494 } 495 496 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) { 497 LLDB_INSTRUMENT_VA(this, src, dst); 498 499 SBError sb_error; 500 PlatformSP platform_sp(GetSP()); 501 if (platform_sp) { 502 sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref()); 503 } else { 504 sb_error.SetErrorString("invalid platform"); 505 } 506 return sb_error; 507 } 508 509 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) { 510 LLDB_INSTRUMENT_VA(this, src, dst); 511 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 512 if (src.Exists()) { 513 uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref()); 514 if (permissions == 0) { 515 if (FileSystem::Instance().IsDirectory(src.ref())) 516 permissions = eFilePermissionsDirectoryDefault; 517 else 518 permissions = eFilePermissionsFileDefault; 519 } 520 521 return platform_sp->PutFile(src.ref(), dst.ref(), permissions); 522 } 523 524 Status error; 525 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 526 src.ref().GetPath().c_str()); 527 return error; 528 }); 529 } 530 531 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) { 532 LLDB_INSTRUMENT_VA(this, src, dst); 533 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 534 if (src.Exists()) 535 return platform_sp->Install(src.ref(), dst.ref()); 536 537 Status error; 538 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 539 src.ref().GetPath().c_str()); 540 return error; 541 }); 542 } 543 544 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) { 545 LLDB_INSTRUMENT_VA(this, shell_command); 546 return ExecuteConnected( 547 [&](const lldb::PlatformSP &platform_sp) { 548 const char *command = shell_command.GetCommand(); 549 if (!command) 550 return Status("invalid shell command (empty)"); 551 552 const char *working_dir = shell_command.GetWorkingDirectory(); 553 if (working_dir == nullptr) { 554 working_dir = platform_sp->GetWorkingDirectory().GetCString(); 555 if (working_dir) 556 shell_command.SetWorkingDirectory(working_dir); 557 } 558 return platform_sp->RunShellCommand( 559 shell_command.m_opaque_ptr->m_shell, command, FileSpec(working_dir), 560 &shell_command.m_opaque_ptr->m_status, 561 &shell_command.m_opaque_ptr->m_signo, 562 &shell_command.m_opaque_ptr->m_output, 563 shell_command.m_opaque_ptr->m_timeout); 564 }); 565 } 566 567 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) { 568 LLDB_INSTRUMENT_VA(this, launch_info); 569 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 570 ProcessLaunchInfo info = launch_info.ref(); 571 Status error = platform_sp->LaunchProcess(info); 572 launch_info.set_ref(info); 573 return error; 574 }); 575 } 576 577 SBError SBPlatform::Kill(const lldb::pid_t pid) { 578 LLDB_INSTRUMENT_VA(this, pid); 579 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 580 return platform_sp->KillProcess(pid); 581 }); 582 } 583 584 SBError SBPlatform::ExecuteConnected( 585 const std::function<Status(const lldb::PlatformSP &)> &func) { 586 SBError sb_error; 587 const auto platform_sp(GetSP()); 588 if (platform_sp) { 589 if (platform_sp->IsConnected()) 590 sb_error.ref() = func(platform_sp); 591 else 592 sb_error.SetErrorString("not connected"); 593 } else 594 sb_error.SetErrorString("invalid platform"); 595 596 return sb_error; 597 } 598 599 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) { 600 LLDB_INSTRUMENT_VA(this, path, file_permissions); 601 602 SBError sb_error; 603 PlatformSP platform_sp(GetSP()); 604 if (platform_sp) { 605 sb_error.ref() = 606 platform_sp->MakeDirectory(FileSpec(path), file_permissions); 607 } else { 608 sb_error.SetErrorString("invalid platform"); 609 } 610 return sb_error; 611 } 612 613 uint32_t SBPlatform::GetFilePermissions(const char *path) { 614 LLDB_INSTRUMENT_VA(this, path); 615 616 PlatformSP platform_sp(GetSP()); 617 if (platform_sp) { 618 uint32_t file_permissions = 0; 619 platform_sp->GetFilePermissions(FileSpec(path), file_permissions); 620 return file_permissions; 621 } 622 return 0; 623 } 624 625 SBError SBPlatform::SetFilePermissions(const char *path, 626 uint32_t file_permissions) { 627 LLDB_INSTRUMENT_VA(this, path, file_permissions); 628 629 SBError sb_error; 630 PlatformSP platform_sp(GetSP()); 631 if (platform_sp) { 632 sb_error.ref() = 633 platform_sp->SetFilePermissions(FileSpec(path), file_permissions); 634 } else { 635 sb_error.SetErrorString("invalid platform"); 636 } 637 return sb_error; 638 } 639 640 SBUnixSignals SBPlatform::GetUnixSignals() const { 641 LLDB_INSTRUMENT_VA(this); 642 643 if (auto platform_sp = GetSP()) 644 return SBUnixSignals{platform_sp}; 645 646 return SBUnixSignals(); 647 } 648 649 SBEnvironment SBPlatform::GetEnvironment() { 650 LLDB_INSTRUMENT_VA(this); 651 PlatformSP platform_sp(GetSP()); 652 653 if (platform_sp) { 654 return SBEnvironment(platform_sp->GetEnvironment()); 655 } 656 657 return SBEnvironment(); 658 } 659