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 = std::nullopt; 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 = std::nullopt; 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 m_opaque_sp = Platform::Create(platform_name); 296 } 297 298 SBPlatform::SBPlatform(const SBPlatform &rhs) { 299 LLDB_INSTRUMENT_VA(this, rhs); 300 301 m_opaque_sp = rhs.m_opaque_sp; 302 } 303 304 SBPlatform &SBPlatform::operator=(const SBPlatform &rhs) { 305 LLDB_INSTRUMENT_VA(this, rhs); 306 307 m_opaque_sp = rhs.m_opaque_sp; 308 return *this; 309 } 310 311 SBPlatform::~SBPlatform() = default; 312 313 SBPlatform SBPlatform::GetHostPlatform() { 314 LLDB_INSTRUMENT(); 315 316 SBPlatform host_platform; 317 host_platform.m_opaque_sp = Platform::GetHostPlatform(); 318 return host_platform; 319 } 320 321 bool SBPlatform::IsValid() const { 322 LLDB_INSTRUMENT_VA(this); 323 return this->operator bool(); 324 } 325 SBPlatform::operator bool() const { 326 LLDB_INSTRUMENT_VA(this); 327 328 return m_opaque_sp.get() != nullptr; 329 } 330 331 void SBPlatform::Clear() { 332 LLDB_INSTRUMENT_VA(this); 333 334 m_opaque_sp.reset(); 335 } 336 337 const char *SBPlatform::GetName() { 338 LLDB_INSTRUMENT_VA(this); 339 340 PlatformSP platform_sp(GetSP()); 341 if (platform_sp) 342 return ConstString(platform_sp->GetName()).AsCString(); 343 return nullptr; 344 } 345 346 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; } 347 348 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) { 349 m_opaque_sp = platform_sp; 350 } 351 352 const char *SBPlatform::GetWorkingDirectory() { 353 LLDB_INSTRUMENT_VA(this); 354 355 PlatformSP platform_sp(GetSP()); 356 if (platform_sp) 357 return platform_sp->GetWorkingDirectory().GetPathAsConstString().AsCString(); 358 return nullptr; 359 } 360 361 bool SBPlatform::SetWorkingDirectory(const char *path) { 362 LLDB_INSTRUMENT_VA(this, path); 363 364 PlatformSP platform_sp(GetSP()); 365 if (platform_sp) { 366 if (path) 367 platform_sp->SetWorkingDirectory(FileSpec(path)); 368 else 369 platform_sp->SetWorkingDirectory(FileSpec()); 370 return true; 371 } 372 return false; 373 } 374 375 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) { 376 LLDB_INSTRUMENT_VA(this, connect_options); 377 378 SBError sb_error; 379 PlatformSP platform_sp(GetSP()); 380 if (platform_sp && connect_options.GetURL()) { 381 Args args; 382 args.AppendArgument(connect_options.GetURL()); 383 sb_error.ref() = platform_sp->ConnectRemote(args); 384 } else { 385 sb_error.SetErrorString("invalid platform"); 386 } 387 return sb_error; 388 } 389 390 void SBPlatform::DisconnectRemote() { 391 LLDB_INSTRUMENT_VA(this); 392 393 PlatformSP platform_sp(GetSP()); 394 if (platform_sp) 395 platform_sp->DisconnectRemote(); 396 } 397 398 bool SBPlatform::IsConnected() { 399 LLDB_INSTRUMENT_VA(this); 400 401 PlatformSP platform_sp(GetSP()); 402 if (platform_sp) 403 return platform_sp->IsConnected(); 404 return false; 405 } 406 407 const char *SBPlatform::GetTriple() { 408 LLDB_INSTRUMENT_VA(this); 409 410 PlatformSP platform_sp(GetSP()); 411 if (platform_sp) { 412 ArchSpec arch(platform_sp->GetSystemArchitecture()); 413 if (arch.IsValid()) { 414 // Const-ify the string so we don't need to worry about the lifetime of 415 // the string 416 return ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); 417 } 418 } 419 return nullptr; 420 } 421 422 const char *SBPlatform::GetOSBuild() { 423 LLDB_INSTRUMENT_VA(this); 424 425 PlatformSP platform_sp(GetSP()); 426 if (platform_sp) { 427 std::string s = platform_sp->GetOSBuildString().value_or(""); 428 if (!s.empty()) { 429 // Const-ify the string so we don't need to worry about the lifetime of 430 // the string 431 return ConstString(s).GetCString(); 432 } 433 } 434 return nullptr; 435 } 436 437 const char *SBPlatform::GetOSDescription() { 438 LLDB_INSTRUMENT_VA(this); 439 440 PlatformSP platform_sp(GetSP()); 441 if (platform_sp) { 442 std::string s = platform_sp->GetOSKernelDescription().value_or(""); 443 if (!s.empty()) { 444 // Const-ify the string so we don't need to worry about the lifetime of 445 // the string 446 return ConstString(s.c_str()).GetCString(); 447 } 448 } 449 return nullptr; 450 } 451 452 const char *SBPlatform::GetHostname() { 453 LLDB_INSTRUMENT_VA(this); 454 455 PlatformSP platform_sp(GetSP()); 456 if (platform_sp) 457 return platform_sp->GetHostname(); 458 return nullptr; 459 } 460 461 uint32_t SBPlatform::GetOSMajorVersion() { 462 LLDB_INSTRUMENT_VA(this); 463 464 llvm::VersionTuple version; 465 if (PlatformSP platform_sp = GetSP()) 466 version = platform_sp->GetOSVersion(); 467 return version.empty() ? UINT32_MAX : version.getMajor(); 468 } 469 470 uint32_t SBPlatform::GetOSMinorVersion() { 471 LLDB_INSTRUMENT_VA(this); 472 473 llvm::VersionTuple version; 474 if (PlatformSP platform_sp = GetSP()) 475 version = platform_sp->GetOSVersion(); 476 return version.getMinor().value_or(UINT32_MAX); 477 } 478 479 uint32_t SBPlatform::GetOSUpdateVersion() { 480 LLDB_INSTRUMENT_VA(this); 481 482 llvm::VersionTuple version; 483 if (PlatformSP platform_sp = GetSP()) 484 version = platform_sp->GetOSVersion(); 485 return version.getSubminor().value_or(UINT32_MAX); 486 } 487 488 void SBPlatform::SetSDKRoot(const char *sysroot) { 489 LLDB_INSTRUMENT_VA(this, sysroot); 490 if (PlatformSP platform_sp = GetSP()) 491 platform_sp->SetSDKRootDirectory(ConstString(sysroot)); 492 } 493 494 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) { 495 LLDB_INSTRUMENT_VA(this, src, dst); 496 497 SBError sb_error; 498 PlatformSP platform_sp(GetSP()); 499 if (platform_sp) { 500 sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref()); 501 } else { 502 sb_error.SetErrorString("invalid platform"); 503 } 504 return sb_error; 505 } 506 507 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) { 508 LLDB_INSTRUMENT_VA(this, src, dst); 509 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 510 if (src.Exists()) { 511 uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref()); 512 if (permissions == 0) { 513 if (FileSystem::Instance().IsDirectory(src.ref())) 514 permissions = eFilePermissionsDirectoryDefault; 515 else 516 permissions = eFilePermissionsFileDefault; 517 } 518 519 return platform_sp->PutFile(src.ref(), dst.ref(), permissions); 520 } 521 522 Status error; 523 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 524 src.ref().GetPath().c_str()); 525 return error; 526 }); 527 } 528 529 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) { 530 LLDB_INSTRUMENT_VA(this, src, dst); 531 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 532 if (src.Exists()) 533 return platform_sp->Install(src.ref(), dst.ref()); 534 535 Status error; 536 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 537 src.ref().GetPath().c_str()); 538 return error; 539 }); 540 } 541 542 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) { 543 LLDB_INSTRUMENT_VA(this, shell_command); 544 return ExecuteConnected( 545 [&](const lldb::PlatformSP &platform_sp) { 546 const char *command = shell_command.GetCommand(); 547 if (!command) 548 return Status("invalid shell command (empty)"); 549 550 if (shell_command.GetWorkingDirectory() == nullptr) { 551 std::string platform_working_dir = 552 platform_sp->GetWorkingDirectory().GetPath(); 553 if (!platform_working_dir.empty()) 554 shell_command.SetWorkingDirectory(platform_working_dir.c_str()); 555 } 556 return platform_sp->RunShellCommand( 557 shell_command.m_opaque_ptr->m_shell, command, 558 FileSpec(shell_command.GetWorkingDirectory()), 559 &shell_command.m_opaque_ptr->m_status, 560 &shell_command.m_opaque_ptr->m_signo, 561 &shell_command.m_opaque_ptr->m_output, 562 shell_command.m_opaque_ptr->m_timeout); 563 }); 564 } 565 566 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) { 567 LLDB_INSTRUMENT_VA(this, launch_info); 568 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 569 ProcessLaunchInfo info = launch_info.ref(); 570 Status error = platform_sp->LaunchProcess(info); 571 launch_info.set_ref(info); 572 return error; 573 }); 574 } 575 576 SBError SBPlatform::Kill(const lldb::pid_t pid) { 577 LLDB_INSTRUMENT_VA(this, pid); 578 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 579 return platform_sp->KillProcess(pid); 580 }); 581 } 582 583 SBError SBPlatform::ExecuteConnected( 584 const std::function<Status(const lldb::PlatformSP &)> &func) { 585 SBError sb_error; 586 const auto platform_sp(GetSP()); 587 if (platform_sp) { 588 if (platform_sp->IsConnected()) 589 sb_error.ref() = func(platform_sp); 590 else 591 sb_error.SetErrorString("not connected"); 592 } else 593 sb_error.SetErrorString("invalid platform"); 594 595 return sb_error; 596 } 597 598 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) { 599 LLDB_INSTRUMENT_VA(this, path, file_permissions); 600 601 SBError sb_error; 602 PlatformSP platform_sp(GetSP()); 603 if (platform_sp) { 604 sb_error.ref() = 605 platform_sp->MakeDirectory(FileSpec(path), file_permissions); 606 } else { 607 sb_error.SetErrorString("invalid platform"); 608 } 609 return sb_error; 610 } 611 612 uint32_t SBPlatform::GetFilePermissions(const char *path) { 613 LLDB_INSTRUMENT_VA(this, path); 614 615 PlatformSP platform_sp(GetSP()); 616 if (platform_sp) { 617 uint32_t file_permissions = 0; 618 platform_sp->GetFilePermissions(FileSpec(path), file_permissions); 619 return file_permissions; 620 } 621 return 0; 622 } 623 624 SBError SBPlatform::SetFilePermissions(const char *path, 625 uint32_t file_permissions) { 626 LLDB_INSTRUMENT_VA(this, path, file_permissions); 627 628 SBError sb_error; 629 PlatformSP platform_sp(GetSP()); 630 if (platform_sp) { 631 sb_error.ref() = 632 platform_sp->SetFilePermissions(FileSpec(path), file_permissions); 633 } else { 634 sb_error.SetErrorString("invalid platform"); 635 } 636 return sb_error; 637 } 638 639 SBUnixSignals SBPlatform::GetUnixSignals() const { 640 LLDB_INSTRUMENT_VA(this); 641 642 if (auto platform_sp = GetSP()) 643 return SBUnixSignals{platform_sp}; 644 645 return SBUnixSignals(); 646 } 647 648 SBEnvironment SBPlatform::GetEnvironment() { 649 LLDB_INSTRUMENT_VA(this); 650 PlatformSP platform_sp(GetSP()); 651 652 if (platform_sp) { 653 return SBEnvironment(platform_sp->GetEnvironment()); 654 } 655 656 return SBEnvironment(); 657 } 658