1 //===-- PlatformPOSIX.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 "PlatformPOSIX.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/ModuleSpec.h" 20 #include "lldb/Core/ValueObject.h" 21 #include "lldb/Expression/DiagnosticManager.h" 22 #include "lldb/Expression/FunctionCaller.h" 23 #include "lldb/Expression/UserExpression.h" 24 #include "lldb/Expression/UtilityFunction.h" 25 #include "lldb/Host/File.h" 26 #include "lldb/Host/FileCache.h" 27 #include "lldb/Host/FileSystem.h" 28 #include "lldb/Host/Host.h" 29 #include "lldb/Host/HostInfo.h" 30 #include "lldb/Symbol/ClangASTContext.h" 31 #include "lldb/Target/DynamicLoader.h" 32 #include "lldb/Target/ExecutionContext.h" 33 #include "lldb/Target/Process.h" 34 #include "lldb/Target/ProcessLaunchInfo.h" 35 #include "lldb/Target/Thread.h" 36 #include "lldb/Utility/CleanUp.h" 37 #include "lldb/Utility/DataBufferHeap.h" 38 #include "lldb/Utility/FileSpec.h" 39 #include "lldb/Utility/Log.h" 40 #include "lldb/Utility/StreamString.h" 41 42 using namespace lldb; 43 using namespace lldb_private; 44 45 //------------------------------------------------------------------ 46 /// Default Constructor 47 //------------------------------------------------------------------ 48 PlatformPOSIX::PlatformPOSIX(bool is_host) 49 : Platform(is_host), // This is the local host platform 50 m_option_group_platform_rsync(new OptionGroupPlatformRSync()), 51 m_option_group_platform_ssh(new OptionGroupPlatformSSH()), 52 m_option_group_platform_caching(new OptionGroupPlatformCaching()), 53 m_remote_platform_sp() {} 54 55 //------------------------------------------------------------------ 56 /// Destructor. 57 /// 58 /// The destructor is virtual since this class is designed to be 59 /// inherited from by the plug-in instance. 60 //------------------------------------------------------------------ 61 PlatformPOSIX::~PlatformPOSIX() {} 62 63 bool PlatformPOSIX::GetModuleSpec(const FileSpec &module_file_spec, 64 const ArchSpec &arch, 65 ModuleSpec &module_spec) { 66 if (m_remote_platform_sp) 67 return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch, 68 module_spec); 69 70 return Platform::GetModuleSpec(module_file_spec, arch, module_spec); 71 } 72 73 lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions( 74 lldb_private::CommandInterpreter &interpreter) { 75 auto iter = m_options.find(&interpreter), end = m_options.end(); 76 if (iter == end) { 77 std::unique_ptr<lldb_private::OptionGroupOptions> options( 78 new OptionGroupOptions()); 79 options->Append(m_option_group_platform_rsync.get()); 80 options->Append(m_option_group_platform_ssh.get()); 81 options->Append(m_option_group_platform_caching.get()); 82 m_options[&interpreter] = std::move(options); 83 } 84 85 return m_options.at(&interpreter).get(); 86 } 87 88 bool PlatformPOSIX::IsConnected() const { 89 if (IsHost()) 90 return true; 91 else if (m_remote_platform_sp) 92 return m_remote_platform_sp->IsConnected(); 93 return false; 94 } 95 96 lldb_private::Status PlatformPOSIX::RunShellCommand( 97 const char *command, // Shouldn't be NULL 98 const FileSpec & 99 working_dir, // Pass empty FileSpec to use the current working directory 100 int *status_ptr, // Pass NULL if you don't want the process exit status 101 int *signo_ptr, // Pass NULL if you don't want the signal that caused the 102 // process to exit 103 std::string 104 *command_output, // Pass NULL if you don't want the command output 105 const Timeout<std::micro> &timeout) { 106 if (IsHost()) 107 return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, 108 command_output, timeout); 109 else { 110 if (m_remote_platform_sp) 111 return m_remote_platform_sp->RunShellCommand( 112 command, working_dir, status_ptr, signo_ptr, command_output, timeout); 113 else 114 return Status("unable to run a remote command without a platform"); 115 } 116 } 117 118 Status 119 PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, 120 lldb::ModuleSP &exe_module_sp, 121 const FileSpecList *module_search_paths_ptr) { 122 Status error; 123 // Nothing special to do here, just use the actual file and architecture 124 125 char exe_path[PATH_MAX]; 126 ModuleSpec resolved_module_spec(module_spec); 127 128 if (IsHost()) { 129 // If we have "ls" as the exe_file, resolve the executable location based 130 // on the current path variables 131 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { 132 resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 133 resolved_module_spec.GetFileSpec().SetFile(exe_path, 134 FileSpec::Style::native); 135 FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); 136 } 137 138 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 139 FileSystem::Instance().ResolveExecutableLocation( 140 resolved_module_spec.GetFileSpec()); 141 142 // Resolve any executable within a bundle on MacOSX 143 Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 144 145 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 146 error.Clear(); 147 else { 148 const uint32_t permissions = FileSystem::Instance().GetPermissions( 149 resolved_module_spec.GetFileSpec()); 150 if (permissions && (permissions & eFilePermissionsEveryoneR) == 0) 151 error.SetErrorStringWithFormat( 152 "executable '%s' is not readable", 153 resolved_module_spec.GetFileSpec().GetPath().c_str()); 154 else 155 error.SetErrorStringWithFormat( 156 "unable to find executable for '%s'", 157 resolved_module_spec.GetFileSpec().GetPath().c_str()); 158 } 159 } else { 160 if (m_remote_platform_sp) { 161 error = 162 GetCachedExecutable(resolved_module_spec, exe_module_sp, 163 module_search_paths_ptr, *m_remote_platform_sp); 164 } else { 165 // We may connect to a process and use the provided executable (Don't use 166 // local $PATH). 167 168 // Resolve any executable within a bundle on MacOSX 169 Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 170 171 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 172 error.Clear(); 173 else 174 error.SetErrorStringWithFormat("the platform is not currently " 175 "connected, and '%s' doesn't exist in " 176 "the system root.", 177 exe_path); 178 } 179 } 180 181 if (error.Success()) { 182 if (resolved_module_spec.GetArchitecture().IsValid()) { 183 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 184 module_search_paths_ptr, nullptr, nullptr); 185 if (error.Fail()) { 186 // If we failed, it may be because the vendor and os aren't known. If 187 // that is the case, try setting them to the host architecture and give 188 // it another try. 189 llvm::Triple &module_triple = 190 resolved_module_spec.GetArchitecture().GetTriple(); 191 bool is_vendor_specified = 192 (module_triple.getVendor() != llvm::Triple::UnknownVendor); 193 bool is_os_specified = 194 (module_triple.getOS() != llvm::Triple::UnknownOS); 195 if (!is_vendor_specified || !is_os_specified) { 196 const llvm::Triple &host_triple = 197 HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple(); 198 199 if (!is_vendor_specified) 200 module_triple.setVendorName(host_triple.getVendorName()); 201 if (!is_os_specified) 202 module_triple.setOSName(host_triple.getOSName()); 203 204 error = ModuleList::GetSharedModule(resolved_module_spec, 205 exe_module_sp, module_search_paths_ptr, nullptr, nullptr); 206 } 207 } 208 209 // TODO find out why exe_module_sp might be NULL 210 if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) { 211 exe_module_sp.reset(); 212 error.SetErrorStringWithFormat( 213 "'%s' doesn't contain the architecture %s", 214 resolved_module_spec.GetFileSpec().GetPath().c_str(), 215 resolved_module_spec.GetArchitecture().GetArchitectureName()); 216 } 217 } else { 218 // No valid architecture was specified, ask the platform for the 219 // architectures that we should be using (in the correct order) and see 220 // if we can find a match that way 221 StreamString arch_names; 222 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( 223 idx, resolved_module_spec.GetArchitecture()); 224 ++idx) { 225 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 226 module_search_paths_ptr, nullptr, nullptr); 227 // Did we find an executable using one of the 228 if (error.Success()) { 229 if (exe_module_sp && exe_module_sp->GetObjectFile()) 230 break; 231 else 232 error.SetErrorToGenericError(); 233 } 234 235 if (idx > 0) 236 arch_names.PutCString(", "); 237 arch_names.PutCString( 238 resolved_module_spec.GetArchitecture().GetArchitectureName()); 239 } 240 241 if (error.Fail() || !exe_module_sp) { 242 if (FileSystem::Instance().Readable( 243 resolved_module_spec.GetFileSpec())) { 244 error.SetErrorStringWithFormat( 245 "'%s' doesn't contain any '%s' platform architectures: %s", 246 resolved_module_spec.GetFileSpec().GetPath().c_str(), 247 GetPluginName().GetCString(), arch_names.GetData()); 248 } else { 249 error.SetErrorStringWithFormat( 250 "'%s' is not readable", 251 resolved_module_spec.GetFileSpec().GetPath().c_str()); 252 } 253 } 254 } 255 } 256 257 return error; 258 } 259 260 Status PlatformPOSIX::GetFileWithUUID(const FileSpec &platform_file, 261 const UUID *uuid_ptr, 262 FileSpec &local_file) { 263 if (IsRemote() && m_remote_platform_sp) 264 return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr, 265 local_file); 266 267 // Default to the local case 268 local_file = platform_file; 269 return Status(); 270 } 271 272 bool PlatformPOSIX::GetProcessInfo(lldb::pid_t pid, 273 ProcessInstanceInfo &process_info) { 274 if (IsHost()) 275 return Platform::GetProcessInfo(pid, process_info); 276 if (m_remote_platform_sp) 277 return m_remote_platform_sp->GetProcessInfo(pid, process_info); 278 return false; 279 } 280 281 uint32_t 282 PlatformPOSIX::FindProcesses(const ProcessInstanceInfoMatch &match_info, 283 ProcessInstanceInfoList &process_infos) { 284 if (IsHost()) 285 return Platform::FindProcesses(match_info, process_infos); 286 if (m_remote_platform_sp) 287 return 288 m_remote_platform_sp->FindProcesses(match_info, process_infos); 289 return 0; 290 } 291 292 Status PlatformPOSIX::MakeDirectory(const FileSpec &file_spec, 293 uint32_t file_permissions) { 294 if (m_remote_platform_sp) 295 return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions); 296 else 297 return Platform::MakeDirectory(file_spec, file_permissions); 298 } 299 300 Status PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec, 301 uint32_t &file_permissions) { 302 if (m_remote_platform_sp) 303 return m_remote_platform_sp->GetFilePermissions(file_spec, 304 file_permissions); 305 else 306 return Platform::GetFilePermissions(file_spec, file_permissions); 307 } 308 309 Status PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec, 310 uint32_t file_permissions) { 311 if (m_remote_platform_sp) 312 return m_remote_platform_sp->SetFilePermissions(file_spec, 313 file_permissions); 314 else 315 return Platform::SetFilePermissions(file_spec, file_permissions); 316 } 317 318 lldb::user_id_t PlatformPOSIX::OpenFile(const FileSpec &file_spec, 319 uint32_t flags, uint32_t mode, 320 Status &error) { 321 if (IsHost()) 322 return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error); 323 else if (m_remote_platform_sp) 324 return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); 325 else 326 return Platform::OpenFile(file_spec, flags, mode, error); 327 } 328 329 bool PlatformPOSIX::CloseFile(lldb::user_id_t fd, Status &error) { 330 if (IsHost()) 331 return FileCache::GetInstance().CloseFile(fd, error); 332 else if (m_remote_platform_sp) 333 return m_remote_platform_sp->CloseFile(fd, error); 334 else 335 return Platform::CloseFile(fd, error); 336 } 337 338 uint64_t PlatformPOSIX::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, 339 uint64_t dst_len, Status &error) { 340 if (IsHost()) 341 return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error); 342 else if (m_remote_platform_sp) 343 return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); 344 else 345 return Platform::ReadFile(fd, offset, dst, dst_len, error); 346 } 347 348 uint64_t PlatformPOSIX::WriteFile(lldb::user_id_t fd, uint64_t offset, 349 const void *src, uint64_t src_len, 350 Status &error) { 351 if (IsHost()) 352 return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error); 353 else if (m_remote_platform_sp) 354 return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); 355 else 356 return Platform::WriteFile(fd, offset, src, src_len, error); 357 } 358 359 static uint32_t chown_file(Platform *platform, const char *path, 360 uint32_t uid = UINT32_MAX, 361 uint32_t gid = UINT32_MAX) { 362 if (!platform || !path || *path == 0) 363 return UINT32_MAX; 364 365 if (uid == UINT32_MAX && gid == UINT32_MAX) 366 return 0; // pretend I did chown correctly - actually I just didn't care 367 368 StreamString command; 369 command.PutCString("chown "); 370 if (uid != UINT32_MAX) 371 command.Printf("%d", uid); 372 if (gid != UINT32_MAX) 373 command.Printf(":%d", gid); 374 command.Printf("%s", path); 375 int status; 376 platform->RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 377 std::chrono::seconds(10)); 378 return status; 379 } 380 381 lldb_private::Status 382 PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, 383 const lldb_private::FileSpec &destination, uint32_t uid, 384 uint32_t gid) { 385 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 386 387 if (IsHost()) { 388 if (FileSpec::Equal(source, destination, true)) 389 return Status(); 390 // cp src dst 391 // chown uid:gid dst 392 std::string src_path(source.GetPath()); 393 if (src_path.empty()) 394 return Status("unable to get file path for source"); 395 std::string dst_path(destination.GetPath()); 396 if (dst_path.empty()) 397 return Status("unable to get file path for destination"); 398 StreamString command; 399 command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 400 int status; 401 RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 402 std::chrono::seconds(10)); 403 if (status != 0) 404 return Status("unable to perform copy"); 405 if (uid == UINT32_MAX && gid == UINT32_MAX) 406 return Status(); 407 if (chown_file(this, dst_path.c_str(), uid, gid) != 0) 408 return Status("unable to perform chown"); 409 return Status(); 410 } else if (m_remote_platform_sp) { 411 if (GetSupportsRSync()) { 412 std::string src_path(source.GetPath()); 413 if (src_path.empty()) 414 return Status("unable to get file path for source"); 415 std::string dst_path(destination.GetPath()); 416 if (dst_path.empty()) 417 return Status("unable to get file path for destination"); 418 StreamString command; 419 if (GetIgnoresRemoteHostname()) { 420 if (!GetRSyncPrefix()) 421 command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 422 dst_path.c_str()); 423 else 424 command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(), 425 GetRSyncPrefix(), dst_path.c_str()); 426 } else 427 command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(), 428 GetHostname(), dst_path.c_str()); 429 if (log) 430 log->Printf("[PutFile] Running command: %s\n", command.GetData()); 431 int retcode; 432 Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 433 std::chrono::minutes(1)); 434 if (retcode == 0) { 435 // Don't chown a local file for a remote system 436 // if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 437 // return Status("unable to perform chown"); 438 return Status(); 439 } 440 // if we are still here rsync has failed - let's try the slow way before 441 // giving up 442 } 443 } 444 return Platform::PutFile(source, destination, uid, gid); 445 } 446 447 lldb::user_id_t PlatformPOSIX::GetFileSize(const FileSpec &file_spec) { 448 if (IsHost()) { 449 uint64_t Size; 450 if (llvm::sys::fs::file_size(file_spec.GetPath(), Size)) 451 return 0; 452 return Size; 453 } else if (m_remote_platform_sp) 454 return m_remote_platform_sp->GetFileSize(file_spec); 455 else 456 return Platform::GetFileSize(file_spec); 457 } 458 459 Status PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) { 460 if (IsHost()) 461 return FileSystem::Instance().Symlink(src, dst); 462 else if (m_remote_platform_sp) 463 return m_remote_platform_sp->CreateSymlink(src, dst); 464 else 465 return Platform::CreateSymlink(src, dst); 466 } 467 468 bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) { 469 if (IsHost()) 470 return FileSystem::Instance().Exists(file_spec); 471 else if (m_remote_platform_sp) 472 return m_remote_platform_sp->GetFileExists(file_spec); 473 else 474 return Platform::GetFileExists(file_spec); 475 } 476 477 Status PlatformPOSIX::Unlink(const FileSpec &file_spec) { 478 if (IsHost()) 479 return llvm::sys::fs::remove(file_spec.GetPath()); 480 else if (m_remote_platform_sp) 481 return m_remote_platform_sp->Unlink(file_spec); 482 else 483 return Platform::Unlink(file_spec); 484 } 485 486 lldb_private::Status PlatformPOSIX::GetFile( 487 const lldb_private::FileSpec &source, // remote file path 488 const lldb_private::FileSpec &destination) // local file path 489 { 490 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 491 492 // Check the args, first. 493 std::string src_path(source.GetPath()); 494 if (src_path.empty()) 495 return Status("unable to get file path for source"); 496 std::string dst_path(destination.GetPath()); 497 if (dst_path.empty()) 498 return Status("unable to get file path for destination"); 499 if (IsHost()) { 500 if (FileSpec::Equal(source, destination, true)) 501 return Status("local scenario->source and destination are the same file " 502 "path: no operation performed"); 503 // cp src dst 504 StreamString cp_command; 505 cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 506 int status; 507 RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 508 std::chrono::seconds(10)); 509 if (status != 0) 510 return Status("unable to perform copy"); 511 return Status(); 512 } else if (m_remote_platform_sp) { 513 if (GetSupportsRSync()) { 514 StreamString command; 515 if (GetIgnoresRemoteHostname()) { 516 if (!GetRSyncPrefix()) 517 command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 518 dst_path.c_str()); 519 else 520 command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(), 521 src_path.c_str(), dst_path.c_str()); 522 } else 523 command.Printf("rsync %s %s:%s %s", GetRSyncOpts(), 524 m_remote_platform_sp->GetHostname(), src_path.c_str(), 525 dst_path.c_str()); 526 if (log) 527 log->Printf("[GetFile] Running command: %s\n", command.GetData()); 528 int retcode; 529 Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 530 std::chrono::minutes(1)); 531 if (retcode == 0) 532 return Status(); 533 // If we are here, rsync has failed - let's try the slow way before 534 // giving up 535 } 536 // open src and dst 537 // read/write, read/write, read/write, ... 538 // close src 539 // close dst 540 if (log) 541 log->Printf("[GetFile] Using block by block transfer....\n"); 542 Status error; 543 user_id_t fd_src = OpenFile(source, File::eOpenOptionRead, 544 lldb::eFilePermissionsFileDefault, error); 545 546 if (fd_src == UINT64_MAX) 547 return Status("unable to open source file"); 548 549 uint32_t permissions = 0; 550 error = GetFilePermissions(source, permissions); 551 552 if (permissions == 0) 553 permissions = lldb::eFilePermissionsFileDefault; 554 555 user_id_t fd_dst = FileCache::GetInstance().OpenFile( 556 destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | 557 File::eOpenOptionTruncate, 558 permissions, error); 559 560 if (fd_dst == UINT64_MAX) { 561 if (error.Success()) 562 error.SetErrorString("unable to open destination file"); 563 } 564 565 if (error.Success()) { 566 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 567 uint64_t offset = 0; 568 error.Clear(); 569 while (error.Success()) { 570 const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(), 571 buffer_sp->GetByteSize(), error); 572 if (error.Fail()) 573 break; 574 if (n_read == 0) 575 break; 576 if (FileCache::GetInstance().WriteFile(fd_dst, offset, 577 buffer_sp->GetBytes(), n_read, 578 error) != n_read) { 579 if (!error.Fail()) 580 error.SetErrorString("unable to write to destination file"); 581 break; 582 } 583 offset += n_read; 584 } 585 } 586 // Ignore the close error of src. 587 if (fd_src != UINT64_MAX) 588 CloseFile(fd_src, error); 589 // And close the dst file descriptot. 590 if (fd_dst != UINT64_MAX && 591 !FileCache::GetInstance().CloseFile(fd_dst, error)) { 592 if (!error.Fail()) 593 error.SetErrorString("unable to close destination file"); 594 } 595 return error; 596 } 597 return Platform::GetFile(source, destination); 598 } 599 600 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() { 601 StreamString stream; 602 if (GetSupportsRSync()) { 603 stream.PutCString("rsync"); 604 if ((GetRSyncOpts() && *GetRSyncOpts()) || 605 (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) { 606 stream.Printf(", options: "); 607 if (GetRSyncOpts() && *GetRSyncOpts()) 608 stream.Printf("'%s' ", GetRSyncOpts()); 609 stream.Printf(", prefix: "); 610 if (GetRSyncPrefix() && *GetRSyncPrefix()) 611 stream.Printf("'%s' ", GetRSyncPrefix()); 612 if (GetIgnoresRemoteHostname()) 613 stream.Printf("ignore remote-hostname "); 614 } 615 } 616 if (GetSupportsSSH()) { 617 stream.PutCString("ssh"); 618 if (GetSSHOpts() && *GetSSHOpts()) 619 stream.Printf(", options: '%s' ", GetSSHOpts()); 620 } 621 if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) 622 stream.Printf("cache dir: %s", GetLocalCacheDirectory()); 623 if (stream.GetSize()) 624 return stream.GetString(); 625 else 626 return ""; 627 } 628 629 bool PlatformPOSIX::CalculateMD5(const FileSpec &file_spec, uint64_t &low, 630 uint64_t &high) { 631 if (IsHost()) 632 return Platform::CalculateMD5(file_spec, low, high); 633 if (m_remote_platform_sp) 634 return m_remote_platform_sp->CalculateMD5(file_spec, low, high); 635 return false; 636 } 637 638 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() { 639 if (IsRemote() && m_remote_platform_sp) 640 return m_remote_platform_sp->GetRemoteUnixSignals(); 641 return Platform::GetRemoteUnixSignals(); 642 } 643 644 FileSpec PlatformPOSIX::GetRemoteWorkingDirectory() { 645 if (IsRemote() && m_remote_platform_sp) 646 return m_remote_platform_sp->GetRemoteWorkingDirectory(); 647 else 648 return Platform::GetRemoteWorkingDirectory(); 649 } 650 651 bool PlatformPOSIX::SetRemoteWorkingDirectory(const FileSpec &working_dir) { 652 if (IsRemote() && m_remote_platform_sp) 653 return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir); 654 else 655 return Platform::SetRemoteWorkingDirectory(working_dir); 656 } 657 658 bool PlatformPOSIX::GetRemoteOSVersion() { 659 if (m_remote_platform_sp) { 660 m_os_version = m_remote_platform_sp->GetOSVersion(); 661 return !m_os_version.empty(); 662 } 663 return false; 664 } 665 666 bool PlatformPOSIX::GetRemoteOSBuildString(std::string &s) { 667 if (m_remote_platform_sp) 668 return m_remote_platform_sp->GetRemoteOSBuildString(s); 669 s.clear(); 670 return false; 671 } 672 673 Environment PlatformPOSIX::GetEnvironment() { 674 if (IsRemote()) { 675 if (m_remote_platform_sp) 676 return m_remote_platform_sp->GetEnvironment(); 677 return Environment(); 678 } 679 return Host::GetEnvironment(); 680 } 681 682 bool PlatformPOSIX::GetRemoteOSKernelDescription(std::string &s) { 683 if (m_remote_platform_sp) 684 return m_remote_platform_sp->GetRemoteOSKernelDescription(s); 685 s.clear(); 686 return false; 687 } 688 689 // Remote Platform subclasses need to override this function 690 ArchSpec PlatformPOSIX::GetRemoteSystemArchitecture() { 691 if (m_remote_platform_sp) 692 return m_remote_platform_sp->GetRemoteSystemArchitecture(); 693 return ArchSpec(); 694 } 695 696 const char *PlatformPOSIX::GetHostname() { 697 if (IsHost()) 698 return Platform::GetHostname(); 699 700 if (m_remote_platform_sp) 701 return m_remote_platform_sp->GetHostname(); 702 return NULL; 703 } 704 705 const char *PlatformPOSIX::GetUserName(uint32_t uid) { 706 // Check the cache in Platform in case we have already looked this uid up 707 const char *user_name = Platform::GetUserName(uid); 708 if (user_name) 709 return user_name; 710 711 if (IsRemote() && m_remote_platform_sp) 712 return m_remote_platform_sp->GetUserName(uid); 713 return NULL; 714 } 715 716 const char *PlatformPOSIX::GetGroupName(uint32_t gid) { 717 const char *group_name = Platform::GetGroupName(gid); 718 if (group_name) 719 return group_name; 720 721 if (IsRemote() && m_remote_platform_sp) 722 return m_remote_platform_sp->GetGroupName(gid); 723 return NULL; 724 } 725 726 Status PlatformPOSIX::ConnectRemote(Args &args) { 727 Status error; 728 if (IsHost()) { 729 error.SetErrorStringWithFormat( 730 "can't connect to the host platform '%s', always connected", 731 GetPluginName().GetCString()); 732 } else { 733 if (!m_remote_platform_sp) 734 m_remote_platform_sp = 735 Platform::Create(ConstString("remote-gdb-server"), error); 736 737 if (m_remote_platform_sp && error.Success()) 738 error = m_remote_platform_sp->ConnectRemote(args); 739 else 740 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 741 742 if (error.Fail()) 743 m_remote_platform_sp.reset(); 744 } 745 746 if (error.Success() && m_remote_platform_sp) { 747 if (m_option_group_platform_rsync.get() && 748 m_option_group_platform_ssh.get() && 749 m_option_group_platform_caching.get()) { 750 if (m_option_group_platform_rsync->m_rsync) { 751 SetSupportsRSync(true); 752 SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str()); 753 SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str()); 754 SetIgnoresRemoteHostname( 755 m_option_group_platform_rsync->m_ignores_remote_hostname); 756 } 757 if (m_option_group_platform_ssh->m_ssh) { 758 SetSupportsSSH(true); 759 SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str()); 760 } 761 SetLocalCacheDirectory( 762 m_option_group_platform_caching->m_cache_dir.c_str()); 763 } 764 } 765 766 return error; 767 } 768 769 Status PlatformPOSIX::DisconnectRemote() { 770 Status error; 771 772 if (IsHost()) { 773 error.SetErrorStringWithFormat( 774 "can't disconnect from the host platform '%s', always connected", 775 GetPluginName().GetCString()); 776 } else { 777 if (m_remote_platform_sp) 778 error = m_remote_platform_sp->DisconnectRemote(); 779 else 780 error.SetErrorString("the platform is not currently connected"); 781 } 782 return error; 783 } 784 785 Status PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) { 786 Status error; 787 788 if (IsHost()) { 789 error = Platform::LaunchProcess(launch_info); 790 } else { 791 if (m_remote_platform_sp) 792 error = m_remote_platform_sp->LaunchProcess(launch_info); 793 else 794 error.SetErrorString("the platform is not currently connected"); 795 } 796 return error; 797 } 798 799 lldb_private::Status PlatformPOSIX::KillProcess(const lldb::pid_t pid) { 800 if (IsHost()) 801 return Platform::KillProcess(pid); 802 803 if (m_remote_platform_sp) 804 return m_remote_platform_sp->KillProcess(pid); 805 806 return Status("the platform is not currently connected"); 807 } 808 809 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, 810 Debugger &debugger, Target *target, 811 Status &error) { 812 lldb::ProcessSP process_sp; 813 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 814 815 if (IsHost()) { 816 if (target == NULL) { 817 TargetSP new_target_sp; 818 819 error = debugger.GetTargetList().CreateTarget( 820 debugger, "", "", eLoadDependentsNo, NULL, new_target_sp); 821 target = new_target_sp.get(); 822 if (log) 823 log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__); 824 } else { 825 error.Clear(); 826 if (log) 827 log->Printf("PlatformPOSIX::%s target already existed, setting target", 828 __FUNCTION__); 829 } 830 831 if (target && error.Success()) { 832 debugger.GetTargetList().SetSelectedTarget(target); 833 if (log) { 834 ModuleSP exe_module_sp = target->GetExecutableModule(); 835 log->Printf("PlatformPOSIX::%s set selected target to %p %s", 836 __FUNCTION__, (void *)target, 837 exe_module_sp 838 ? exe_module_sp->GetFileSpec().GetPath().c_str() 839 : "<null>"); 840 } 841 842 process_sp = 843 target->CreateProcess(attach_info.GetListenerForProcess(debugger), 844 attach_info.GetProcessPluginName(), NULL); 845 846 if (process_sp) { 847 ListenerSP listener_sp = attach_info.GetHijackListener(); 848 if (listener_sp == nullptr) { 849 listener_sp = 850 Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack"); 851 attach_info.SetHijackListener(listener_sp); 852 } 853 process_sp->HijackProcessEvents(listener_sp); 854 error = process_sp->Attach(attach_info); 855 } 856 } 857 } else { 858 if (m_remote_platform_sp) 859 process_sp = 860 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 861 else 862 error.SetErrorString("the platform is not currently connected"); 863 } 864 return process_sp; 865 } 866 867 lldb::ProcessSP 868 PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, 869 Target *target, // Can be NULL, if NULL create a new 870 // target, else use existing one 871 Status &error) { 872 ProcessSP process_sp; 873 874 if (IsHost()) { 875 // We are going to hand this process off to debugserver which will be in 876 // charge of setting the exit status. However, we still need to reap it 877 // from lldb. So, make sure we use a exit callback which does not set exit 878 // status. 879 const bool monitor_signals = false; 880 launch_info.SetMonitorProcessCallback( 881 &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals); 882 process_sp = Platform::DebugProcess(launch_info, debugger, target, error); 883 } else { 884 if (m_remote_platform_sp) 885 process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, 886 target, error); 887 else 888 error.SetErrorString("the platform is not currently connected"); 889 } 890 return process_sp; 891 } 892 893 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() { 894 m_trap_handlers.push_back(ConstString("_sigtramp")); 895 } 896 897 Status PlatformPOSIX::EvaluateLibdlExpression( 898 lldb_private::Process *process, const char *expr_cstr, 899 llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) { 900 DynamicLoader *loader = process->GetDynamicLoader(); 901 if (loader) { 902 Status error = loader->CanLoadImage(); 903 if (error.Fail()) 904 return error; 905 } 906 907 ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread()); 908 if (!thread_sp) 909 return Status("Selected thread isn't valid"); 910 911 StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); 912 if (!frame_sp) 913 return Status("Frame 0 isn't valid"); 914 915 ExecutionContext exe_ctx; 916 frame_sp->CalculateExecutionContext(exe_ctx); 917 EvaluateExpressionOptions expr_options; 918 expr_options.SetUnwindOnError(true); 919 expr_options.SetIgnoreBreakpoints(true); 920 expr_options.SetExecutionPolicy(eExecutionPolicyAlways); 921 expr_options.SetLanguage(eLanguageTypeC_plus_plus); 922 expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 923 // don't do the work to trap them. 924 expr_options.SetTimeout(std::chrono::seconds(2)); 925 926 Status expr_error; 927 ExpressionResults result = 928 UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix, 929 result_valobj_sp, expr_error); 930 if (result != eExpressionCompleted) 931 return expr_error; 932 933 if (result_valobj_sp->GetError().Fail()) 934 return result_valobj_sp->GetError(); 935 return Status(); 936 } 937 938 std::unique_ptr<UtilityFunction> 939 PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, 940 Status &error) { 941 // Remember to prepend this with the prefix from 942 // GetLibdlFunctionDeclarations. The returned values are all in 943 // __lldb_dlopen_result for consistency. The wrapper returns a void * but 944 // doesn't use it because UtilityFunctions don't work with void returns at 945 // present. 946 static const char *dlopen_wrapper_code = R"( 947 struct __lldb_dlopen_result { 948 void *image_ptr; 949 const char *error_str; 950 }; 951 952 extern void *memcpy(void *, const void *, size_t size); 953 extern size_t strlen(const char *); 954 955 956 void * __lldb_dlopen_wrapper (const char *name, 957 const char *path_strings, 958 char *buffer, 959 __lldb_dlopen_result *result_ptr) 960 { 961 // This is the case where the name is the full path: 962 if (!path_strings) { 963 result_ptr->image_ptr = dlopen(name, 2); 964 if (result_ptr->image_ptr) 965 result_ptr->error_str = nullptr; 966 return nullptr; 967 } 968 969 // This is the case where we have a list of paths: 970 size_t name_len = strlen(name); 971 while (path_strings && path_strings[0] != '\0') { 972 size_t path_len = strlen(path_strings); 973 memcpy((void *) buffer, (void *) path_strings, path_len); 974 buffer[path_len] = '/'; 975 char *target_ptr = buffer+path_len+1; 976 memcpy((void *) target_ptr, (void *) name, name_len + 1); 977 result_ptr->image_ptr = dlopen(buffer, 2); 978 if (result_ptr->image_ptr) { 979 result_ptr->error_str = nullptr; 980 break; 981 } 982 result_ptr->error_str = dlerror(); 983 path_strings = path_strings + path_len + 1; 984 } 985 return nullptr; 986 } 987 )"; 988 989 static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper"; 990 Process *process = exe_ctx.GetProcessSP().get(); 991 // Insert the dlopen shim defines into our generic expression: 992 std::string expr(GetLibdlFunctionDeclarations(process)); 993 expr.append(dlopen_wrapper_code); 994 Status utility_error; 995 DiagnosticManager diagnostics; 996 997 std::unique_ptr<UtilityFunction> dlopen_utility_func_up(process 998 ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(), 999 eLanguageTypeObjC, 1000 dlopen_wrapper_name, 1001 utility_error)); 1002 if (utility_error.Fail()) { 1003 error.SetErrorStringWithFormat("dlopen error: could not make utility" 1004 "function: %s", utility_error.AsCString()); 1005 return nullptr; 1006 } 1007 if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) { 1008 error.SetErrorStringWithFormat("dlopen error: could not install utility" 1009 "function: %s", 1010 diagnostics.GetString().c_str()); 1011 return nullptr; 1012 } 1013 1014 Value value; 1015 ValueList arguments; 1016 FunctionCaller *do_dlopen_function = nullptr; 1017 1018 // Fetch the clang types we will need: 1019 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 1020 1021 CompilerType clang_void_pointer_type 1022 = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 1023 CompilerType clang_char_pointer_type 1024 = ast->GetBasicType(eBasicTypeChar).GetPointerType(); 1025 1026 // We are passing four arguments, the basename, the list of places to look, 1027 // a buffer big enough for all the path + name combos, and 1028 // a pointer to the storage we've made for the result: 1029 value.SetValueType(Value::eValueTypeScalar); 1030 value.SetCompilerType(clang_void_pointer_type); 1031 arguments.PushValue(value); 1032 value.SetCompilerType(clang_char_pointer_type); 1033 arguments.PushValue(value); 1034 arguments.PushValue(value); 1035 arguments.PushValue(value); 1036 1037 do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller( 1038 clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error); 1039 if (utility_error.Fail()) { 1040 error.SetErrorStringWithFormat("dlopen error: could not make function" 1041 "caller: %s", utility_error.AsCString()); 1042 return nullptr; 1043 } 1044 1045 do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller(); 1046 if (!do_dlopen_function) { 1047 error.SetErrorString("dlopen error: could not get function caller."); 1048 return nullptr; 1049 } 1050 1051 // We made a good utility function, so cache it in the process: 1052 return dlopen_utility_func_up; 1053 } 1054 1055 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, 1056 const lldb_private::FileSpec &remote_file, 1057 const std::vector<std::string> *paths, 1058 lldb_private::Status &error, 1059 lldb_private::FileSpec *loaded_image) { 1060 if (loaded_image) 1061 loaded_image->Clear(); 1062 1063 std::string path; 1064 path = remote_file.GetPath(); 1065 1066 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); 1067 if (!thread_sp) { 1068 error.SetErrorString("dlopen error: no thread available to call dlopen."); 1069 return LLDB_INVALID_IMAGE_TOKEN; 1070 } 1071 1072 DiagnosticManager diagnostics; 1073 1074 ExecutionContext exe_ctx; 1075 thread_sp->CalculateExecutionContext(exe_ctx); 1076 1077 Status utility_error; 1078 UtilityFunction *dlopen_utility_func; 1079 ValueList arguments; 1080 FunctionCaller *do_dlopen_function = nullptr; 1081 1082 // The UtilityFunction is held in the Process. Platforms don't track the 1083 // lifespan of the Targets that use them, we can't put this in the Platform. 1084 dlopen_utility_func = process->GetLoadImageUtilityFunction( 1085 this, [&]() -> std::unique_ptr<UtilityFunction> { 1086 return MakeLoadImageUtilityFunction(exe_ctx, error); 1087 }); 1088 // If we couldn't make it, the error will be in error, so we can exit here. 1089 if (!dlopen_utility_func) 1090 return LLDB_INVALID_IMAGE_TOKEN; 1091 1092 do_dlopen_function = dlopen_utility_func->GetFunctionCaller(); 1093 if (!do_dlopen_function) { 1094 error.SetErrorString("dlopen error: could not get function caller."); 1095 return LLDB_INVALID_IMAGE_TOKEN; 1096 } 1097 arguments = do_dlopen_function->GetArgumentValues(); 1098 1099 // Now insert the path we are searching for and the result structure into the 1100 // target. 1101 uint32_t permissions = ePermissionsReadable|ePermissionsWritable; 1102 size_t path_len = path.size() + 1; 1103 lldb::addr_t path_addr = process->AllocateMemory(path_len, 1104 permissions, 1105 utility_error); 1106 if (path_addr == LLDB_INVALID_ADDRESS) { 1107 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 1108 "for path: %s", utility_error.AsCString()); 1109 return LLDB_INVALID_IMAGE_TOKEN; 1110 } 1111 1112 // Make sure we deallocate the input string memory: 1113 CleanUp path_cleanup([process, path_addr] { 1114 process->DeallocateMemory(path_addr); 1115 }); 1116 1117 process->WriteMemory(path_addr, path.c_str(), path_len, utility_error); 1118 if (utility_error.Fail()) { 1119 error.SetErrorStringWithFormat("dlopen error: could not write path string:" 1120 " %s", utility_error.AsCString()); 1121 return LLDB_INVALID_IMAGE_TOKEN; 1122 } 1123 1124 // Make space for our return structure. It is two pointers big: the token 1125 // and the error string. 1126 const uint32_t addr_size = process->GetAddressByteSize(); 1127 lldb::addr_t return_addr = process->CallocateMemory(2*addr_size, 1128 permissions, 1129 utility_error); 1130 if (utility_error.Fail()) { 1131 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 1132 "for path: %s", utility_error.AsCString()); 1133 return LLDB_INVALID_IMAGE_TOKEN; 1134 } 1135 1136 // Make sure we deallocate the result structure memory 1137 CleanUp return_cleanup([process, return_addr] { 1138 process->DeallocateMemory(return_addr); 1139 }); 1140 1141 // This will be the address of the storage for paths, if we are using them, 1142 // or nullptr to signal we aren't. 1143 lldb::addr_t path_array_addr = 0x0; 1144 llvm::Optional<CleanUp> path_array_cleanup; 1145 1146 // This is the address to a buffer large enough to hold the largest path 1147 // conjoined with the library name we're passing in. This is a convenience 1148 // to avoid having to call malloc in the dlopen function. 1149 lldb::addr_t buffer_addr = 0x0; 1150 llvm::Optional<CleanUp> buffer_cleanup; 1151 1152 // Set the values into our args and write them to the target: 1153 if (paths != nullptr) { 1154 // First insert the paths into the target. This is expected to be a 1155 // continuous buffer with the strings laid out null terminated and 1156 // end to end with an empty string terminating the buffer. 1157 // We also compute the buffer's required size as we go. 1158 size_t buffer_size = 0; 1159 std::string path_array; 1160 for (auto path : *paths) { 1161 // Don't insert empty paths, they will make us abort the path 1162 // search prematurely. 1163 if (path.empty()) 1164 continue; 1165 size_t path_size = path.size(); 1166 path_array.append(path); 1167 path_array.push_back('\0'); 1168 if (path_size > buffer_size) 1169 buffer_size = path_size; 1170 } 1171 path_array.push_back('\0'); 1172 1173 path_array_addr = process->AllocateMemory(path_array.size(), 1174 permissions, 1175 utility_error); 1176 if (path_array_addr == LLDB_INVALID_ADDRESS) { 1177 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 1178 "for path array: %s", 1179 utility_error.AsCString()); 1180 return LLDB_INVALID_IMAGE_TOKEN; 1181 } 1182 1183 // Make sure we deallocate the paths array. 1184 path_array_cleanup.emplace([process, path_array_addr] { 1185 process->DeallocateMemory(path_array_addr); 1186 }); 1187 1188 process->WriteMemory(path_array_addr, path_array.data(), 1189 path_array.size(), utility_error); 1190 1191 if (utility_error.Fail()) { 1192 error.SetErrorStringWithFormat("dlopen error: could not write path array:" 1193 " %s", utility_error.AsCString()); 1194 return LLDB_INVALID_IMAGE_TOKEN; 1195 } 1196 // Now make spaces in the target for the buffer. We need to add one for 1197 // the '/' that the utility function will insert and one for the '\0': 1198 buffer_size += path.size() + 2; 1199 1200 buffer_addr = process->AllocateMemory(buffer_size, 1201 permissions, 1202 utility_error); 1203 if (buffer_addr == LLDB_INVALID_ADDRESS) { 1204 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 1205 "for buffer: %s", 1206 utility_error.AsCString()); 1207 return LLDB_INVALID_IMAGE_TOKEN; 1208 } 1209 1210 // Make sure we deallocate the buffer memory: 1211 buffer_cleanup.emplace([process, buffer_addr] { 1212 process->DeallocateMemory(buffer_addr); 1213 }); 1214 } 1215 1216 arguments.GetValueAtIndex(0)->GetScalar() = path_addr; 1217 arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr; 1218 arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr; 1219 arguments.GetValueAtIndex(3)->GetScalar() = return_addr; 1220 1221 lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS; 1222 1223 diagnostics.Clear(); 1224 if (!do_dlopen_function->WriteFunctionArguments(exe_ctx, 1225 func_args_addr, 1226 arguments, 1227 diagnostics)) { 1228 error.SetErrorStringWithFormat("dlopen error: could not write function " 1229 "arguments: %s", 1230 diagnostics.GetString().c_str()); 1231 return LLDB_INVALID_IMAGE_TOKEN; 1232 } 1233 1234 // Make sure we clean up the args structure. We can't reuse it because the 1235 // Platform lives longer than the process and the Platforms don't get a 1236 // signal to clean up cached data when a process goes away. 1237 CleanUp args_cleanup([do_dlopen_function, &exe_ctx, func_args_addr] { 1238 do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr); 1239 }); 1240 1241 // Now run the caller: 1242 EvaluateExpressionOptions options; 1243 options.SetExecutionPolicy(eExecutionPolicyAlways); 1244 options.SetLanguage(eLanguageTypeC_plus_plus); 1245 options.SetIgnoreBreakpoints(true); 1246 options.SetUnwindOnError(true); 1247 options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 1248 // don't do the work to trap them. 1249 options.SetTimeout(std::chrono::seconds(2)); 1250 options.SetIsForUtilityExpr(true); 1251 1252 Value return_value; 1253 // Fetch the clang types we will need: 1254 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 1255 1256 CompilerType clang_void_pointer_type 1257 = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 1258 1259 return_value.SetCompilerType(clang_void_pointer_type); 1260 1261 ExpressionResults results = do_dlopen_function->ExecuteFunction( 1262 exe_ctx, &func_args_addr, options, diagnostics, return_value); 1263 if (results != eExpressionCompleted) { 1264 error.SetErrorStringWithFormat("dlopen error: failed executing " 1265 "dlopen wrapper function: %s", 1266 diagnostics.GetString().c_str()); 1267 return LLDB_INVALID_IMAGE_TOKEN; 1268 } 1269 1270 // Read the dlopen token from the return area: 1271 lldb::addr_t token = process->ReadPointerFromMemory(return_addr, 1272 utility_error); 1273 if (utility_error.Fail()) { 1274 error.SetErrorStringWithFormat("dlopen error: could not read the return " 1275 "struct: %s", utility_error.AsCString()); 1276 return LLDB_INVALID_IMAGE_TOKEN; 1277 } 1278 1279 // The dlopen succeeded! 1280 if (token != 0x0) { 1281 if (loaded_image && buffer_addr != 0x0) 1282 { 1283 // Capture the image which was loaded. We leave it in the buffer on 1284 // exit from the dlopen function, so we can just read it from there: 1285 std::string name_string; 1286 process->ReadCStringFromMemory(buffer_addr, name_string, utility_error); 1287 if (utility_error.Success()) 1288 loaded_image->SetFile(name_string, llvm::sys::path::Style::posix); 1289 } 1290 return process->AddImageToken(token); 1291 } 1292 1293 // We got an error, lets read in the error string: 1294 std::string dlopen_error_str; 1295 lldb::addr_t error_addr 1296 = process->ReadPointerFromMemory(return_addr + addr_size, utility_error); 1297 if (utility_error.Fail()) { 1298 error.SetErrorStringWithFormat("dlopen error: could not read error string: " 1299 "%s", utility_error.AsCString()); 1300 return LLDB_INVALID_IMAGE_TOKEN; 1301 } 1302 1303 size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size, 1304 dlopen_error_str, 1305 utility_error); 1306 if (utility_error.Success() && num_chars > 0) 1307 error.SetErrorStringWithFormat("dlopen error: %s", 1308 dlopen_error_str.c_str()); 1309 else 1310 error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); 1311 1312 return LLDB_INVALID_IMAGE_TOKEN; 1313 } 1314 1315 Status PlatformPOSIX::UnloadImage(lldb_private::Process *process, 1316 uint32_t image_token) { 1317 const addr_t image_addr = process->GetImagePtrFromToken(image_token); 1318 if (image_addr == LLDB_INVALID_ADDRESS) 1319 return Status("Invalid image token"); 1320 1321 StreamString expr; 1322 expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr); 1323 llvm::StringRef prefix = GetLibdlFunctionDeclarations(process); 1324 lldb::ValueObjectSP result_valobj_sp; 1325 Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix, 1326 result_valobj_sp); 1327 if (error.Fail()) 1328 return error; 1329 1330 if (result_valobj_sp->GetError().Fail()) 1331 return result_valobj_sp->GetError(); 1332 1333 Scalar scalar; 1334 if (result_valobj_sp->ResolveValue(scalar)) { 1335 if (scalar.UInt(1)) 1336 return Status("expression failed: \"%s\"", expr.GetData()); 1337 process->ResetImageToken(image_token); 1338 } 1339 return Status(); 1340 } 1341 1342 lldb::ProcessSP PlatformPOSIX::ConnectProcess(llvm::StringRef connect_url, 1343 llvm::StringRef plugin_name, 1344 lldb_private::Debugger &debugger, 1345 lldb_private::Target *target, 1346 lldb_private::Status &error) { 1347 if (m_remote_platform_sp) 1348 return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name, 1349 debugger, target, error); 1350 1351 return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, 1352 error); 1353 } 1354 1355 llvm::StringRef 1356 PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) { 1357 return R"( 1358 extern "C" void* dlopen(const char*, int); 1359 extern "C" void* dlsym(void*, const char*); 1360 extern "C" int dlclose(void*); 1361 extern "C" char* dlerror(void); 1362 )"; 1363 } 1364 1365 size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger, 1366 Status &error) { 1367 if (m_remote_platform_sp) 1368 return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); 1369 return Platform::ConnectToWaitingProcesses(debugger, error); 1370 } 1371 1372 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) { 1373 if (basename.IsEmpty()) 1374 return basename; 1375 1376 StreamString stream; 1377 stream.Printf("lib%s.so", basename.GetCString()); 1378 return ConstString(stream.GetString()); 1379 } 1380