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