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 : m_status(0), m_signo(0) { 53 if (!shell_interpreter.empty()) 54 m_shell = shell_interpreter.str(); 55 56 if (!m_shell.empty() && !shell_command.empty()) 57 m_command = shell_command.str(); 58 } 59 60 PlatformShellCommand(llvm::StringRef shell_command = llvm::StringRef()) { 61 if (!shell_command.empty()) 62 m_command = shell_command.str(); 63 } 64 65 ~PlatformShellCommand() = default; 66 67 std::string m_shell; 68 std::string m_command; 69 std::string m_working_dir; 70 std::string m_output; 71 int m_status = 0; 72 int m_signo = 0; 73 Timeout<std::ratio<1>> m_timeout = llvm::None; 74 }; 75 // SBPlatformConnectOptions 76 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url) 77 : m_opaque_ptr(new PlatformConnectOptions(url)) { 78 LLDB_INSTRUMENT_VA(this, url); 79 } 80 81 SBPlatformConnectOptions::SBPlatformConnectOptions( 82 const SBPlatformConnectOptions &rhs) 83 : m_opaque_ptr(new PlatformConnectOptions()) { 84 LLDB_INSTRUMENT_VA(this, rhs); 85 86 *m_opaque_ptr = *rhs.m_opaque_ptr; 87 } 88 89 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; } 90 91 SBPlatformConnectOptions & 92 SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) { 93 LLDB_INSTRUMENT_VA(this, rhs); 94 95 *m_opaque_ptr = *rhs.m_opaque_ptr; 96 return *this; 97 } 98 99 const char *SBPlatformConnectOptions::GetURL() { 100 LLDB_INSTRUMENT_VA(this); 101 102 if (m_opaque_ptr->m_url.empty()) 103 return nullptr; 104 return m_opaque_ptr->m_url.c_str(); 105 } 106 107 void SBPlatformConnectOptions::SetURL(const char *url) { 108 LLDB_INSTRUMENT_VA(this, url); 109 110 if (url && url[0]) 111 m_opaque_ptr->m_url = url; 112 else 113 m_opaque_ptr->m_url.clear(); 114 } 115 116 bool SBPlatformConnectOptions::GetRsyncEnabled() { 117 LLDB_INSTRUMENT_VA(this); 118 119 return m_opaque_ptr->m_rsync_enabled; 120 } 121 122 void SBPlatformConnectOptions::EnableRsync( 123 const char *options, const char *remote_path_prefix, 124 bool omit_hostname_from_remote_path) { 125 LLDB_INSTRUMENT_VA(this, options, remote_path_prefix, 126 omit_hostname_from_remote_path); 127 128 m_opaque_ptr->m_rsync_enabled = true; 129 m_opaque_ptr->m_rsync_omit_hostname_from_remote_path = 130 omit_hostname_from_remote_path; 131 if (remote_path_prefix && remote_path_prefix[0]) 132 m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix; 133 else 134 m_opaque_ptr->m_rsync_remote_path_prefix.clear(); 135 136 if (options && options[0]) 137 m_opaque_ptr->m_rsync_options = options; 138 else 139 m_opaque_ptr->m_rsync_options.clear(); 140 } 141 142 void SBPlatformConnectOptions::DisableRsync() { 143 LLDB_INSTRUMENT_VA(this); 144 145 m_opaque_ptr->m_rsync_enabled = false; 146 } 147 148 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() { 149 LLDB_INSTRUMENT_VA(this); 150 151 return m_opaque_ptr->m_local_cache_directory.GetCString(); 152 } 153 154 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) { 155 LLDB_INSTRUMENT_VA(this, path); 156 157 if (path && path[0]) 158 m_opaque_ptr->m_local_cache_directory.SetCString(path); 159 else 160 m_opaque_ptr->m_local_cache_directory = ConstString(); 161 } 162 163 // SBPlatformShellCommand 164 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_interpreter, 165 const char *shell_command) 166 : m_opaque_ptr(new PlatformShellCommand(shell_interpreter, shell_command)) { 167 LLDB_INSTRUMENT_VA(this, shell_interpreter, shell_command); 168 } 169 170 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command) 171 : m_opaque_ptr(new PlatformShellCommand(shell_command)) { 172 LLDB_INSTRUMENT_VA(this, shell_command); 173 } 174 175 SBPlatformShellCommand::SBPlatformShellCommand( 176 const SBPlatformShellCommand &rhs) 177 : m_opaque_ptr(new PlatformShellCommand()) { 178 LLDB_INSTRUMENT_VA(this, rhs); 179 180 *m_opaque_ptr = *rhs.m_opaque_ptr; 181 } 182 183 SBPlatformShellCommand & 184 SBPlatformShellCommand::operator=(const SBPlatformShellCommand &rhs) { 185 186 LLDB_INSTRUMENT_VA(this, rhs); 187 188 *m_opaque_ptr = *rhs.m_opaque_ptr; 189 return *this; 190 } 191 192 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; } 193 194 void SBPlatformShellCommand::Clear() { 195 LLDB_INSTRUMENT_VA(this); 196 197 m_opaque_ptr->m_output = std::string(); 198 m_opaque_ptr->m_status = 0; 199 m_opaque_ptr->m_signo = 0; 200 } 201 202 const char *SBPlatformShellCommand::GetShell() { 203 LLDB_INSTRUMENT_VA(this); 204 205 if (m_opaque_ptr->m_shell.empty()) 206 return nullptr; 207 return m_opaque_ptr->m_shell.c_str(); 208 } 209 210 void SBPlatformShellCommand::SetShell(const char *shell_interpreter) { 211 LLDB_INSTRUMENT_VA(this, shell_interpreter); 212 213 if (shell_interpreter && shell_interpreter[0]) 214 m_opaque_ptr->m_shell = shell_interpreter; 215 else 216 m_opaque_ptr->m_shell.clear(); 217 } 218 219 const char *SBPlatformShellCommand::GetCommand() { 220 LLDB_INSTRUMENT_VA(this); 221 222 if (m_opaque_ptr->m_command.empty()) 223 return nullptr; 224 return m_opaque_ptr->m_command.c_str(); 225 } 226 227 void SBPlatformShellCommand::SetCommand(const char *shell_command) { 228 LLDB_INSTRUMENT_VA(this, shell_command); 229 230 if (shell_command && shell_command[0]) 231 m_opaque_ptr->m_command = shell_command; 232 else 233 m_opaque_ptr->m_command.clear(); 234 } 235 236 const char *SBPlatformShellCommand::GetWorkingDirectory() { 237 LLDB_INSTRUMENT_VA(this); 238 239 if (m_opaque_ptr->m_working_dir.empty()) 240 return nullptr; 241 return m_opaque_ptr->m_working_dir.c_str(); 242 } 243 244 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) { 245 LLDB_INSTRUMENT_VA(this, path); 246 247 if (path && path[0]) 248 m_opaque_ptr->m_working_dir = path; 249 else 250 m_opaque_ptr->m_working_dir.clear(); 251 } 252 253 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() { 254 LLDB_INSTRUMENT_VA(this); 255 256 if (m_opaque_ptr->m_timeout) 257 return m_opaque_ptr->m_timeout->count(); 258 return UINT32_MAX; 259 } 260 261 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) { 262 LLDB_INSTRUMENT_VA(this, sec); 263 264 if (sec == UINT32_MAX) 265 m_opaque_ptr->m_timeout = llvm::None; 266 else 267 m_opaque_ptr->m_timeout = std::chrono::seconds(sec); 268 } 269 270 int SBPlatformShellCommand::GetSignal() { 271 LLDB_INSTRUMENT_VA(this); 272 273 return m_opaque_ptr->m_signo; 274 } 275 276 int SBPlatformShellCommand::GetStatus() { 277 LLDB_INSTRUMENT_VA(this); 278 279 return m_opaque_ptr->m_status; 280 } 281 282 const char *SBPlatformShellCommand::GetOutput() { 283 LLDB_INSTRUMENT_VA(this); 284 285 if (m_opaque_ptr->m_output.empty()) 286 return nullptr; 287 return m_opaque_ptr->m_output.c_str(); 288 } 289 290 // SBPlatform 291 SBPlatform::SBPlatform() { LLDB_INSTRUMENT_VA(this); } 292 293 SBPlatform::SBPlatform(const char *platform_name) { 294 LLDB_INSTRUMENT_VA(this, platform_name); 295 296 m_opaque_sp = Platform::Create(platform_name); 297 } 298 299 SBPlatform::SBPlatform(const SBPlatform &rhs) { 300 LLDB_INSTRUMENT_VA(this, rhs); 301 302 m_opaque_sp = rhs.m_opaque_sp; 303 } 304 305 SBPlatform &SBPlatform::operator=(const SBPlatform &rhs) { 306 LLDB_INSTRUMENT_VA(this, rhs); 307 308 m_opaque_sp = rhs.m_opaque_sp; 309 return *this; 310 } 311 312 SBPlatform::~SBPlatform() = default; 313 314 SBPlatform SBPlatform::GetHostPlatform() { 315 LLDB_INSTRUMENT(); 316 317 SBPlatform host_platform; 318 host_platform.m_opaque_sp = Platform::GetHostPlatform(); 319 return host_platform; 320 } 321 322 bool SBPlatform::IsValid() const { 323 LLDB_INSTRUMENT_VA(this); 324 return this->operator bool(); 325 } 326 SBPlatform::operator bool() const { 327 LLDB_INSTRUMENT_VA(this); 328 329 return m_opaque_sp.get() != nullptr; 330 } 331 332 void SBPlatform::Clear() { 333 LLDB_INSTRUMENT_VA(this); 334 335 m_opaque_sp.reset(); 336 } 337 338 const char *SBPlatform::GetName() { 339 LLDB_INSTRUMENT_VA(this); 340 341 PlatformSP platform_sp(GetSP()); 342 if (platform_sp) 343 return ConstString(platform_sp->GetName()).AsCString(); 344 return nullptr; 345 } 346 347 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; } 348 349 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) { 350 m_opaque_sp = platform_sp; 351 } 352 353 const char *SBPlatform::GetWorkingDirectory() { 354 LLDB_INSTRUMENT_VA(this); 355 356 PlatformSP platform_sp(GetSP()); 357 if (platform_sp) 358 return platform_sp->GetWorkingDirectory().GetCString(); 359 return nullptr; 360 } 361 362 bool SBPlatform::SetWorkingDirectory(const char *path) { 363 LLDB_INSTRUMENT_VA(this, path); 364 365 PlatformSP platform_sp(GetSP()); 366 if (platform_sp) { 367 if (path) 368 platform_sp->SetWorkingDirectory(FileSpec(path)); 369 else 370 platform_sp->SetWorkingDirectory(FileSpec()); 371 return true; 372 } 373 return false; 374 } 375 376 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) { 377 LLDB_INSTRUMENT_VA(this, connect_options); 378 379 SBError sb_error; 380 PlatformSP platform_sp(GetSP()); 381 if (platform_sp && connect_options.GetURL()) { 382 Args args; 383 args.AppendArgument(connect_options.GetURL()); 384 sb_error.ref() = platform_sp->ConnectRemote(args); 385 } else { 386 sb_error.SetErrorString("invalid platform"); 387 } 388 return sb_error; 389 } 390 391 void SBPlatform::DisconnectRemote() { 392 LLDB_INSTRUMENT_VA(this); 393 394 PlatformSP platform_sp(GetSP()); 395 if (platform_sp) 396 platform_sp->DisconnectRemote(); 397 } 398 399 bool SBPlatform::IsConnected() { 400 LLDB_INSTRUMENT_VA(this); 401 402 PlatformSP platform_sp(GetSP()); 403 if (platform_sp) 404 return platform_sp->IsConnected(); 405 return false; 406 } 407 408 const char *SBPlatform::GetTriple() { 409 LLDB_INSTRUMENT_VA(this); 410 411 PlatformSP platform_sp(GetSP()); 412 if (platform_sp) { 413 ArchSpec arch(platform_sp->GetSystemArchitecture()); 414 if (arch.IsValid()) { 415 // Const-ify the string so we don't need to worry about the lifetime of 416 // the string 417 return ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); 418 } 419 } 420 return nullptr; 421 } 422 423 const char *SBPlatform::GetOSBuild() { 424 LLDB_INSTRUMENT_VA(this); 425 426 PlatformSP platform_sp(GetSP()); 427 if (platform_sp) { 428 std::string s = platform_sp->GetOSBuildString().getValueOr(""); 429 if (!s.empty()) { 430 // Const-ify the string so we don't need to worry about the lifetime of 431 // the string 432 return ConstString(s).GetCString(); 433 } 434 } 435 return nullptr; 436 } 437 438 const char *SBPlatform::GetOSDescription() { 439 LLDB_INSTRUMENT_VA(this); 440 441 PlatformSP platform_sp(GetSP()); 442 if (platform_sp) { 443 std::string s = platform_sp->GetOSKernelDescription().getValueOr(""); 444 if (!s.empty()) { 445 // Const-ify the string so we don't need to worry about the lifetime of 446 // the string 447 return ConstString(s.c_str()).GetCString(); 448 } 449 } 450 return nullptr; 451 } 452 453 const char *SBPlatform::GetHostname() { 454 LLDB_INSTRUMENT_VA(this); 455 456 PlatformSP platform_sp(GetSP()); 457 if (platform_sp) 458 return platform_sp->GetHostname(); 459 return nullptr; 460 } 461 462 uint32_t SBPlatform::GetOSMajorVersion() { 463 LLDB_INSTRUMENT_VA(this); 464 465 llvm::VersionTuple version; 466 if (PlatformSP platform_sp = GetSP()) 467 version = platform_sp->GetOSVersion(); 468 return version.empty() ? UINT32_MAX : version.getMajor(); 469 } 470 471 uint32_t SBPlatform::GetOSMinorVersion() { 472 LLDB_INSTRUMENT_VA(this); 473 474 llvm::VersionTuple version; 475 if (PlatformSP platform_sp = GetSP()) 476 version = platform_sp->GetOSVersion(); 477 return version.getMinor().getValueOr(UINT32_MAX); 478 } 479 480 uint32_t SBPlatform::GetOSUpdateVersion() { 481 LLDB_INSTRUMENT_VA(this); 482 483 llvm::VersionTuple version; 484 if (PlatformSP platform_sp = GetSP()) 485 version = platform_sp->GetOSVersion(); 486 return version.getSubminor().getValueOr(UINT32_MAX); 487 } 488 489 void SBPlatform::SetSDKRoot(const char *sysroot) { 490 LLDB_INSTRUMENT_VA(this, sysroot); 491 if (PlatformSP platform_sp = GetSP()) 492 platform_sp->SetSDKRootDirectory(ConstString(sysroot)); 493 } 494 495 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) { 496 LLDB_INSTRUMENT_VA(this, src, dst); 497 498 SBError sb_error; 499 PlatformSP platform_sp(GetSP()); 500 if (platform_sp) { 501 sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref()); 502 } else { 503 sb_error.SetErrorString("invalid platform"); 504 } 505 return sb_error; 506 } 507 508 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) { 509 LLDB_INSTRUMENT_VA(this, src, dst); 510 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 511 if (src.Exists()) { 512 uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref()); 513 if (permissions == 0) { 514 if (FileSystem::Instance().IsDirectory(src.ref())) 515 permissions = eFilePermissionsDirectoryDefault; 516 else 517 permissions = eFilePermissionsFileDefault; 518 } 519 520 return platform_sp->PutFile(src.ref(), dst.ref(), permissions); 521 } 522 523 Status error; 524 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 525 src.ref().GetPath().c_str()); 526 return error; 527 }); 528 } 529 530 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) { 531 LLDB_INSTRUMENT_VA(this, src, dst); 532 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 533 if (src.Exists()) 534 return platform_sp->Install(src.ref(), dst.ref()); 535 536 Status error; 537 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 538 src.ref().GetPath().c_str()); 539 return error; 540 }); 541 } 542 543 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) { 544 LLDB_INSTRUMENT_VA(this, shell_command); 545 return ExecuteConnected( 546 [&](const lldb::PlatformSP &platform_sp) { 547 const char *command = shell_command.GetCommand(); 548 if (!command) 549 return Status("invalid shell command (empty)"); 550 551 const char *working_dir = shell_command.GetWorkingDirectory(); 552 if (working_dir == nullptr) { 553 working_dir = platform_sp->GetWorkingDirectory().GetCString(); 554 if (working_dir) 555 shell_command.SetWorkingDirectory(working_dir); 556 } 557 return platform_sp->RunShellCommand( 558 shell_command.m_opaque_ptr->m_shell, command, FileSpec(working_dir), 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