1 //===-- SBPlatform.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 #include "lldb/API/SBPlatform.h" 11 #include "lldb/API/SBError.h" 12 #include "lldb/API/SBFileSpec.h" 13 #include "lldb/API/SBLaunchInfo.h" 14 #include "lldb/API/SBUnixSignals.h" 15 #include "lldb/Host/File.h" 16 #include "lldb/Target/Platform.h" 17 #include "lldb/Target/Target.h" 18 #include "lldb/Utility/ArchSpec.h" 19 #include "lldb/Utility/Args.h" 20 #include "lldb/Utility/Status.h" 21 22 #include "llvm/Support/FileSystem.h" 23 24 #include <functional> 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 //---------------------------------------------------------------------- 30 // PlatformConnectOptions 31 //---------------------------------------------------------------------- 32 struct PlatformConnectOptions { 33 PlatformConnectOptions(const char *url = NULL) 34 : m_url(), m_rsync_options(), m_rsync_remote_path_prefix(), 35 m_rsync_enabled(false), m_rsync_omit_hostname_from_remote_path(false), 36 m_local_cache_directory() { 37 if (url && url[0]) 38 m_url = url; 39 } 40 41 ~PlatformConnectOptions() {} 42 43 std::string m_url; 44 std::string m_rsync_options; 45 std::string m_rsync_remote_path_prefix; 46 bool m_rsync_enabled; 47 bool m_rsync_omit_hostname_from_remote_path; 48 ConstString m_local_cache_directory; 49 }; 50 51 //---------------------------------------------------------------------- 52 // PlatformShellCommand 53 //---------------------------------------------------------------------- 54 struct PlatformShellCommand { 55 PlatformShellCommand(const char *shell_command = NULL) 56 : m_command(), m_working_dir(), m_status(0), m_signo(0) { 57 if (shell_command && shell_command[0]) 58 m_command = shell_command; 59 } 60 61 ~PlatformShellCommand() {} 62 63 std::string m_command; 64 std::string m_working_dir; 65 std::string m_output; 66 int m_status; 67 int m_signo; 68 Timeout<std::ratio<1>> m_timeout = llvm::None; 69 }; 70 //---------------------------------------------------------------------- 71 // SBPlatformConnectOptions 72 //---------------------------------------------------------------------- 73 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url) 74 : m_opaque_ptr(new PlatformConnectOptions(url)) {} 75 76 SBPlatformConnectOptions::SBPlatformConnectOptions( 77 const SBPlatformConnectOptions &rhs) 78 : m_opaque_ptr(new PlatformConnectOptions()) { 79 *m_opaque_ptr = *rhs.m_opaque_ptr; 80 } 81 82 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; } 83 84 void SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) { 85 *m_opaque_ptr = *rhs.m_opaque_ptr; 86 } 87 88 const char *SBPlatformConnectOptions::GetURL() { 89 if (m_opaque_ptr->m_url.empty()) 90 return NULL; 91 return m_opaque_ptr->m_url.c_str(); 92 } 93 94 void SBPlatformConnectOptions::SetURL(const char *url) { 95 if (url && url[0]) 96 m_opaque_ptr->m_url = url; 97 else 98 m_opaque_ptr->m_url.clear(); 99 } 100 101 bool SBPlatformConnectOptions::GetRsyncEnabled() { 102 return m_opaque_ptr->m_rsync_enabled; 103 } 104 105 void SBPlatformConnectOptions::EnableRsync( 106 const char *options, const char *remote_path_prefix, 107 bool omit_hostname_from_remote_path) { 108 m_opaque_ptr->m_rsync_enabled = true; 109 m_opaque_ptr->m_rsync_omit_hostname_from_remote_path = 110 omit_hostname_from_remote_path; 111 if (remote_path_prefix && remote_path_prefix[0]) 112 m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix; 113 else 114 m_opaque_ptr->m_rsync_remote_path_prefix.clear(); 115 116 if (options && options[0]) 117 m_opaque_ptr->m_rsync_options = options; 118 else 119 m_opaque_ptr->m_rsync_options.clear(); 120 } 121 122 void SBPlatformConnectOptions::DisableRsync() { 123 m_opaque_ptr->m_rsync_enabled = false; 124 } 125 126 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() { 127 return m_opaque_ptr->m_local_cache_directory.GetCString(); 128 } 129 130 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) { 131 if (path && path[0]) 132 m_opaque_ptr->m_local_cache_directory.SetCString(path); 133 else 134 m_opaque_ptr->m_local_cache_directory = ConstString(); 135 } 136 137 //---------------------------------------------------------------------- 138 // SBPlatformShellCommand 139 //---------------------------------------------------------------------- 140 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command) 141 : m_opaque_ptr(new PlatformShellCommand(shell_command)) {} 142 143 SBPlatformShellCommand::SBPlatformShellCommand( 144 const SBPlatformShellCommand &rhs) 145 : m_opaque_ptr(new PlatformShellCommand()) { 146 *m_opaque_ptr = *rhs.m_opaque_ptr; 147 } 148 149 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; } 150 151 void SBPlatformShellCommand::Clear() { 152 m_opaque_ptr->m_output = std::string(); 153 m_opaque_ptr->m_status = 0; 154 m_opaque_ptr->m_signo = 0; 155 } 156 157 const char *SBPlatformShellCommand::GetCommand() { 158 if (m_opaque_ptr->m_command.empty()) 159 return NULL; 160 return m_opaque_ptr->m_command.c_str(); 161 } 162 163 void SBPlatformShellCommand::SetCommand(const char *shell_command) { 164 if (shell_command && shell_command[0]) 165 m_opaque_ptr->m_command = shell_command; 166 else 167 m_opaque_ptr->m_command.clear(); 168 } 169 170 const char *SBPlatformShellCommand::GetWorkingDirectory() { 171 if (m_opaque_ptr->m_working_dir.empty()) 172 return NULL; 173 return m_opaque_ptr->m_working_dir.c_str(); 174 } 175 176 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) { 177 if (path && path[0]) 178 m_opaque_ptr->m_working_dir = path; 179 else 180 m_opaque_ptr->m_working_dir.clear(); 181 } 182 183 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() { 184 if (m_opaque_ptr->m_timeout) 185 return m_opaque_ptr->m_timeout->count(); 186 return UINT32_MAX; 187 } 188 189 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) { 190 if (sec == UINT32_MAX) 191 m_opaque_ptr->m_timeout = llvm::None; 192 else 193 m_opaque_ptr->m_timeout = std::chrono::seconds(sec); 194 } 195 196 int SBPlatformShellCommand::GetSignal() { return m_opaque_ptr->m_signo; } 197 198 int SBPlatformShellCommand::GetStatus() { return m_opaque_ptr->m_status; } 199 200 const char *SBPlatformShellCommand::GetOutput() { 201 if (m_opaque_ptr->m_output.empty()) 202 return NULL; 203 return m_opaque_ptr->m_output.c_str(); 204 } 205 206 //---------------------------------------------------------------------- 207 // SBPlatform 208 //---------------------------------------------------------------------- 209 SBPlatform::SBPlatform() : m_opaque_sp() {} 210 211 SBPlatform::SBPlatform(const char *platform_name) : m_opaque_sp() { 212 Status error; 213 if (platform_name && platform_name[0]) 214 m_opaque_sp = Platform::Create(ConstString(platform_name), error); 215 } 216 217 SBPlatform::~SBPlatform() {} 218 219 bool SBPlatform::IsValid() const { return m_opaque_sp.get() != NULL; } 220 221 void SBPlatform::Clear() { m_opaque_sp.reset(); } 222 223 const char *SBPlatform::GetName() { 224 PlatformSP platform_sp(GetSP()); 225 if (platform_sp) 226 return platform_sp->GetName().GetCString(); 227 return NULL; 228 } 229 230 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; } 231 232 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) { 233 m_opaque_sp = platform_sp; 234 } 235 236 const char *SBPlatform::GetWorkingDirectory() { 237 PlatformSP platform_sp(GetSP()); 238 if (platform_sp) 239 return platform_sp->GetWorkingDirectory().GetCString(); 240 return NULL; 241 } 242 243 bool SBPlatform::SetWorkingDirectory(const char *path) { 244 PlatformSP platform_sp(GetSP()); 245 if (platform_sp) { 246 if (path) 247 platform_sp->SetWorkingDirectory(FileSpec(path)); 248 else 249 platform_sp->SetWorkingDirectory(FileSpec()); 250 return true; 251 } 252 return false; 253 } 254 255 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) { 256 SBError sb_error; 257 PlatformSP platform_sp(GetSP()); 258 if (platform_sp && connect_options.GetURL()) { 259 Args args; 260 args.AppendArgument( 261 llvm::StringRef::withNullAsEmpty(connect_options.GetURL())); 262 sb_error.ref() = platform_sp->ConnectRemote(args); 263 } else { 264 sb_error.SetErrorString("invalid platform"); 265 } 266 return sb_error; 267 } 268 269 void SBPlatform::DisconnectRemote() { 270 PlatformSP platform_sp(GetSP()); 271 if (platform_sp) 272 platform_sp->DisconnectRemote(); 273 } 274 275 bool SBPlatform::IsConnected() { 276 PlatformSP platform_sp(GetSP()); 277 if (platform_sp) 278 return platform_sp->IsConnected(); 279 return false; 280 } 281 282 const char *SBPlatform::GetTriple() { 283 PlatformSP platform_sp(GetSP()); 284 if (platform_sp) { 285 ArchSpec arch(platform_sp->GetSystemArchitecture()); 286 if (arch.IsValid()) { 287 // Const-ify the string so we don't need to worry about the lifetime of 288 // the string 289 return ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); 290 } 291 } 292 return NULL; 293 } 294 295 const char *SBPlatform::GetOSBuild() { 296 PlatformSP platform_sp(GetSP()); 297 if (platform_sp) { 298 std::string s; 299 if (platform_sp->GetOSBuildString(s)) { 300 if (!s.empty()) { 301 // Const-ify the string so we don't need to worry about the lifetime of 302 // the string 303 return ConstString(s.c_str()).GetCString(); 304 } 305 } 306 } 307 return NULL; 308 } 309 310 const char *SBPlatform::GetOSDescription() { 311 PlatformSP platform_sp(GetSP()); 312 if (platform_sp) { 313 std::string s; 314 if (platform_sp->GetOSKernelDescription(s)) { 315 if (!s.empty()) { 316 // Const-ify the string so we don't need to worry about the lifetime of 317 // the string 318 return ConstString(s.c_str()).GetCString(); 319 } 320 } 321 } 322 return NULL; 323 } 324 325 const char *SBPlatform::GetHostname() { 326 PlatformSP platform_sp(GetSP()); 327 if (platform_sp) 328 return platform_sp->GetHostname(); 329 return NULL; 330 } 331 332 uint32_t SBPlatform::GetOSMajorVersion() { 333 llvm::VersionTuple version; 334 if (PlatformSP platform_sp = GetSP()) 335 version = platform_sp->GetOSVersion(); 336 return version.empty() ? UINT32_MAX : version.getMajor(); 337 } 338 339 uint32_t SBPlatform::GetOSMinorVersion() { 340 llvm::VersionTuple version; 341 if (PlatformSP platform_sp = GetSP()) 342 version = platform_sp->GetOSVersion(); 343 return version.getMinor().getValueOr(UINT32_MAX); 344 } 345 346 uint32_t SBPlatform::GetOSUpdateVersion() { 347 llvm::VersionTuple version; 348 if (PlatformSP platform_sp = GetSP()) 349 version = platform_sp->GetOSVersion(); 350 return version.getSubminor().getValueOr(UINT32_MAX); 351 } 352 353 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) { 354 SBError sb_error; 355 PlatformSP platform_sp(GetSP()); 356 if (platform_sp) { 357 sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref()); 358 } else { 359 sb_error.SetErrorString("invalid platform"); 360 } 361 return sb_error; 362 } 363 364 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) { 365 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 366 if (src.Exists()) { 367 uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref()); 368 if (permissions == 0) { 369 if (FileSystem::Instance().IsDirectory(src.ref())) 370 permissions = eFilePermissionsDirectoryDefault; 371 else 372 permissions = eFilePermissionsFileDefault; 373 } 374 375 return platform_sp->PutFile(src.ref(), dst.ref(), permissions); 376 } 377 378 Status error; 379 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 380 src.ref().GetPath().c_str()); 381 return error; 382 }); 383 } 384 385 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) { 386 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 387 if (src.Exists()) 388 return platform_sp->Install(src.ref(), dst.ref()); 389 390 Status error; 391 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 392 src.ref().GetPath().c_str()); 393 return error; 394 }); 395 } 396 397 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) { 398 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 399 const char *command = shell_command.GetCommand(); 400 if (!command) 401 return Status("invalid shell command (empty)"); 402 403 const char *working_dir = shell_command.GetWorkingDirectory(); 404 if (working_dir == NULL) { 405 working_dir = platform_sp->GetWorkingDirectory().GetCString(); 406 if (working_dir) 407 shell_command.SetWorkingDirectory(working_dir); 408 } 409 return platform_sp->RunShellCommand(command, FileSpec(working_dir), 410 &shell_command.m_opaque_ptr->m_status, 411 &shell_command.m_opaque_ptr->m_signo, 412 &shell_command.m_opaque_ptr->m_output, 413 shell_command.m_opaque_ptr->m_timeout); 414 }); 415 } 416 417 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) { 418 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 419 ProcessLaunchInfo info = launch_info.ref(); 420 Status error = platform_sp->LaunchProcess(info); 421 launch_info.set_ref(info); 422 return error; 423 }); 424 } 425 426 SBError SBPlatform::Kill(const lldb::pid_t pid) { 427 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 428 return platform_sp->KillProcess(pid); 429 }); 430 } 431 432 SBError SBPlatform::ExecuteConnected( 433 const std::function<Status(const lldb::PlatformSP &)> &func) { 434 SBError sb_error; 435 const auto platform_sp(GetSP()); 436 if (platform_sp) { 437 if (platform_sp->IsConnected()) 438 sb_error.ref() = func(platform_sp); 439 else 440 sb_error.SetErrorString("not connected"); 441 } else 442 sb_error.SetErrorString("invalid platform"); 443 444 return sb_error; 445 } 446 447 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) { 448 SBError sb_error; 449 PlatformSP platform_sp(GetSP()); 450 if (platform_sp) { 451 sb_error.ref() = 452 platform_sp->MakeDirectory(FileSpec(path), file_permissions); 453 } else { 454 sb_error.SetErrorString("invalid platform"); 455 } 456 return sb_error; 457 } 458 459 uint32_t SBPlatform::GetFilePermissions(const char *path) { 460 PlatformSP platform_sp(GetSP()); 461 if (platform_sp) { 462 uint32_t file_permissions = 0; 463 platform_sp->GetFilePermissions(FileSpec(path), file_permissions); 464 return file_permissions; 465 } 466 return 0; 467 } 468 469 SBError SBPlatform::SetFilePermissions(const char *path, 470 uint32_t file_permissions) { 471 SBError sb_error; 472 PlatformSP platform_sp(GetSP()); 473 if (platform_sp) { 474 sb_error.ref() = 475 platform_sp->SetFilePermissions(FileSpec(path), file_permissions); 476 } else { 477 sb_error.SetErrorString("invalid platform"); 478 } 479 return sb_error; 480 } 481 482 SBUnixSignals SBPlatform::GetUnixSignals() const { 483 if (auto platform_sp = GetSP()) 484 return SBUnixSignals{platform_sp}; 485 486 return {}; 487 } 488