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/DataBufferHeap.h" 18 #include "lldb/Core/Debugger.h" 19 #include "lldb/Core/Log.h" 20 #include "lldb/Core/Module.h" 21 #include "lldb/Core/StreamString.h" 22 #include "lldb/Core/ValueObject.h" 23 #include "lldb/Expression/UserExpression.h" 24 #include "lldb/Host/File.h" 25 #include "lldb/Host/FileCache.h" 26 #include "lldb/Host/FileSpec.h" 27 #include "lldb/Host/FileSystem.h" 28 #include "lldb/Host/Host.h" 29 #include "lldb/Target/DynamicLoader.h" 30 #include "lldb/Target/ExecutionContext.h" 31 #include "lldb/Target/Process.h" 32 #include "lldb/Target/ProcessLaunchInfo.h" 33 #include "lldb/Target/Thread.h" 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 //------------------------------------------------------------------ 39 /// Default Constructor 40 //------------------------------------------------------------------ 41 PlatformPOSIX::PlatformPOSIX(bool is_host) 42 : Platform(is_host), // This is the local host platform 43 m_option_group_platform_rsync(new OptionGroupPlatformRSync()), 44 m_option_group_platform_ssh(new OptionGroupPlatformSSH()), 45 m_option_group_platform_caching(new OptionGroupPlatformCaching()), 46 m_remote_platform_sp() {} 47 48 //------------------------------------------------------------------ 49 /// Destructor. 50 /// 51 /// The destructor is virtual since this class is designed to be 52 /// inherited from by the plug-in instance. 53 //------------------------------------------------------------------ 54 PlatformPOSIX::~PlatformPOSIX() {} 55 56 bool PlatformPOSIX::GetModuleSpec(const FileSpec &module_file_spec, 57 const ArchSpec &arch, 58 ModuleSpec &module_spec) { 59 if (m_remote_platform_sp) 60 return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch, 61 module_spec); 62 63 return Platform::GetModuleSpec(module_file_spec, arch, module_spec); 64 } 65 66 lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions( 67 lldb_private::CommandInterpreter &interpreter) { 68 auto iter = m_options.find(&interpreter), end = m_options.end(); 69 if (iter == end) { 70 std::unique_ptr<lldb_private::OptionGroupOptions> options( 71 new OptionGroupOptions()); 72 options->Append(m_option_group_platform_rsync.get()); 73 options->Append(m_option_group_platform_ssh.get()); 74 options->Append(m_option_group_platform_caching.get()); 75 m_options[&interpreter] = std::move(options); 76 } 77 78 return m_options.at(&interpreter).get(); 79 } 80 81 bool PlatformPOSIX::IsConnected() const { 82 if (IsHost()) 83 return true; 84 else if (m_remote_platform_sp) 85 return m_remote_platform_sp->IsConnected(); 86 return false; 87 } 88 89 lldb_private::Error PlatformPOSIX::RunShellCommand( 90 const char *command, // Shouldn't be NULL 91 const FileSpec & 92 working_dir, // Pass empty FileSpec to use the current working directory 93 int *status_ptr, // Pass NULL if you don't want the process exit status 94 int *signo_ptr, // Pass NULL if you don't want the signal that caused the 95 // process to exit 96 std::string 97 *command_output, // Pass NULL if you don't want the command output 98 uint32_t 99 timeout_sec) // Timeout in seconds to wait for shell program to finish 100 { 101 if (IsHost()) 102 return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, 103 command_output, timeout_sec); 104 else { 105 if (m_remote_platform_sp) 106 return m_remote_platform_sp->RunShellCommand(command, working_dir, 107 status_ptr, signo_ptr, 108 command_output, timeout_sec); 109 else 110 return Error("unable to run a remote command without a platform"); 111 } 112 } 113 114 Error PlatformPOSIX::MakeDirectory(const FileSpec &file_spec, 115 uint32_t file_permissions) { 116 if (m_remote_platform_sp) 117 return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions); 118 else 119 return Platform::MakeDirectory(file_spec, file_permissions); 120 } 121 122 Error PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec, 123 uint32_t &file_permissions) { 124 if (m_remote_platform_sp) 125 return m_remote_platform_sp->GetFilePermissions(file_spec, 126 file_permissions); 127 else 128 return Platform::GetFilePermissions(file_spec, file_permissions); 129 } 130 131 Error PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec, 132 uint32_t file_permissions) { 133 if (m_remote_platform_sp) 134 return m_remote_platform_sp->SetFilePermissions(file_spec, 135 file_permissions); 136 else 137 return Platform::SetFilePermissions(file_spec, file_permissions); 138 } 139 140 lldb::user_id_t PlatformPOSIX::OpenFile(const FileSpec &file_spec, 141 uint32_t flags, uint32_t mode, 142 Error &error) { 143 if (IsHost()) 144 return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error); 145 else if (m_remote_platform_sp) 146 return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); 147 else 148 return Platform::OpenFile(file_spec, flags, mode, error); 149 } 150 151 bool PlatformPOSIX::CloseFile(lldb::user_id_t fd, Error &error) { 152 if (IsHost()) 153 return FileCache::GetInstance().CloseFile(fd, error); 154 else if (m_remote_platform_sp) 155 return m_remote_platform_sp->CloseFile(fd, error); 156 else 157 return Platform::CloseFile(fd, error); 158 } 159 160 uint64_t PlatformPOSIX::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, 161 uint64_t dst_len, Error &error) { 162 if (IsHost()) 163 return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error); 164 else if (m_remote_platform_sp) 165 return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); 166 else 167 return Platform::ReadFile(fd, offset, dst, dst_len, error); 168 } 169 170 uint64_t PlatformPOSIX::WriteFile(lldb::user_id_t fd, uint64_t offset, 171 const void *src, uint64_t src_len, 172 Error &error) { 173 if (IsHost()) 174 return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error); 175 else if (m_remote_platform_sp) 176 return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); 177 else 178 return Platform::WriteFile(fd, offset, src, src_len, error); 179 } 180 181 static uint32_t chown_file(Platform *platform, const char *path, 182 uint32_t uid = UINT32_MAX, 183 uint32_t gid = UINT32_MAX) { 184 if (!platform || !path || *path == 0) 185 return UINT32_MAX; 186 187 if (uid == UINT32_MAX && gid == UINT32_MAX) 188 return 0; // pretend I did chown correctly - actually I just didn't care 189 190 StreamString command; 191 command.PutCString("chown "); 192 if (uid != UINT32_MAX) 193 command.Printf("%d", uid); 194 if (gid != UINT32_MAX) 195 command.Printf(":%d", gid); 196 command.Printf("%s", path); 197 int status; 198 platform->RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 10); 199 return status; 200 } 201 202 lldb_private::Error 203 PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, 204 const lldb_private::FileSpec &destination, uint32_t uid, 205 uint32_t gid) { 206 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 207 208 if (IsHost()) { 209 if (FileSpec::Equal(source, destination, true)) 210 return Error(); 211 // cp src dst 212 // chown uid:gid dst 213 std::string src_path(source.GetPath()); 214 if (src_path.empty()) 215 return Error("unable to get file path for source"); 216 std::string dst_path(destination.GetPath()); 217 if (dst_path.empty()) 218 return Error("unable to get file path for destination"); 219 StreamString command; 220 command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 221 int status; 222 RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 10); 223 if (status != 0) 224 return Error("unable to perform copy"); 225 if (uid == UINT32_MAX && gid == UINT32_MAX) 226 return Error(); 227 if (chown_file(this, dst_path.c_str(), uid, gid) != 0) 228 return Error("unable to perform chown"); 229 return Error(); 230 } else if (m_remote_platform_sp) { 231 if (GetSupportsRSync()) { 232 std::string src_path(source.GetPath()); 233 if (src_path.empty()) 234 return Error("unable to get file path for source"); 235 std::string dst_path(destination.GetPath()); 236 if (dst_path.empty()) 237 return Error("unable to get file path for destination"); 238 StreamString command; 239 if (GetIgnoresRemoteHostname()) { 240 if (!GetRSyncPrefix()) 241 command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 242 dst_path.c_str()); 243 else 244 command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(), 245 GetRSyncPrefix(), dst_path.c_str()); 246 } else 247 command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(), 248 GetHostname(), dst_path.c_str()); 249 if (log) 250 log->Printf("[PutFile] Running command: %s\n", command.GetData()); 251 int retcode; 252 Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60); 253 if (retcode == 0) { 254 // Don't chown a local file for a remote system 255 // if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 256 // return Error("unable to perform chown"); 257 return Error(); 258 } 259 // if we are still here rsync has failed - let's try the slow way before 260 // giving up 261 } 262 } 263 return Platform::PutFile(source, destination, uid, gid); 264 } 265 266 lldb::user_id_t PlatformPOSIX::GetFileSize(const FileSpec &file_spec) { 267 if (IsHost()) 268 return FileSystem::GetFileSize(file_spec); 269 else if (m_remote_platform_sp) 270 return m_remote_platform_sp->GetFileSize(file_spec); 271 else 272 return Platform::GetFileSize(file_spec); 273 } 274 275 Error PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) { 276 if (IsHost()) 277 return FileSystem::Symlink(src, dst); 278 else if (m_remote_platform_sp) 279 return m_remote_platform_sp->CreateSymlink(src, dst); 280 else 281 return Platform::CreateSymlink(src, dst); 282 } 283 284 bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) { 285 if (IsHost()) 286 return file_spec.Exists(); 287 else if (m_remote_platform_sp) 288 return m_remote_platform_sp->GetFileExists(file_spec); 289 else 290 return Platform::GetFileExists(file_spec); 291 } 292 293 Error PlatformPOSIX::Unlink(const FileSpec &file_spec) { 294 if (IsHost()) 295 return FileSystem::Unlink(file_spec); 296 else if (m_remote_platform_sp) 297 return m_remote_platform_sp->Unlink(file_spec); 298 else 299 return Platform::Unlink(file_spec); 300 } 301 302 lldb_private::Error PlatformPOSIX::GetFile( 303 const lldb_private::FileSpec &source, // remote file path 304 const lldb_private::FileSpec &destination) // local file path 305 { 306 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 307 308 // Check the args, first. 309 std::string src_path(source.GetPath()); 310 if (src_path.empty()) 311 return Error("unable to get file path for source"); 312 std::string dst_path(destination.GetPath()); 313 if (dst_path.empty()) 314 return Error("unable to get file path for destination"); 315 if (IsHost()) { 316 if (FileSpec::Equal(source, destination, true)) 317 return Error("local scenario->source and destination are the same file " 318 "path: no operation performed"); 319 // cp src dst 320 StreamString cp_command; 321 cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 322 int status; 323 RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 10); 324 if (status != 0) 325 return Error("unable to perform copy"); 326 return Error(); 327 } else if (m_remote_platform_sp) { 328 if (GetSupportsRSync()) { 329 StreamString command; 330 if (GetIgnoresRemoteHostname()) { 331 if (!GetRSyncPrefix()) 332 command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 333 dst_path.c_str()); 334 else 335 command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(), 336 src_path.c_str(), dst_path.c_str()); 337 } else 338 command.Printf("rsync %s %s:%s %s", GetRSyncOpts(), 339 m_remote_platform_sp->GetHostname(), src_path.c_str(), 340 dst_path.c_str()); 341 if (log) 342 log->Printf("[GetFile] Running command: %s\n", command.GetData()); 343 int retcode; 344 Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60); 345 if (retcode == 0) 346 return Error(); 347 // If we are here, rsync has failed - let's try the slow way before giving 348 // up 349 } 350 // open src and dst 351 // read/write, read/write, read/write, ... 352 // close src 353 // close dst 354 if (log) 355 log->Printf("[GetFile] Using block by block transfer....\n"); 356 Error error; 357 user_id_t fd_src = OpenFile(source, File::eOpenOptionRead, 358 lldb::eFilePermissionsFileDefault, error); 359 360 if (fd_src == UINT64_MAX) 361 return Error("unable to open source file"); 362 363 uint32_t permissions = 0; 364 error = GetFilePermissions(source, permissions); 365 366 if (permissions == 0) 367 permissions = lldb::eFilePermissionsFileDefault; 368 369 user_id_t fd_dst = FileCache::GetInstance().OpenFile( 370 destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | 371 File::eOpenOptionTruncate, 372 permissions, error); 373 374 if (fd_dst == UINT64_MAX) { 375 if (error.Success()) 376 error.SetErrorString("unable to open destination file"); 377 } 378 379 if (error.Success()) { 380 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 381 uint64_t offset = 0; 382 error.Clear(); 383 while (error.Success()) { 384 const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(), 385 buffer_sp->GetByteSize(), error); 386 if (error.Fail()) 387 break; 388 if (n_read == 0) 389 break; 390 if (FileCache::GetInstance().WriteFile(fd_dst, offset, 391 buffer_sp->GetBytes(), n_read, 392 error) != n_read) { 393 if (!error.Fail()) 394 error.SetErrorString("unable to write to destination file"); 395 break; 396 } 397 offset += n_read; 398 } 399 } 400 // Ignore the close error of src. 401 if (fd_src != UINT64_MAX) 402 CloseFile(fd_src, error); 403 // And close the dst file descriptot. 404 if (fd_dst != UINT64_MAX && 405 !FileCache::GetInstance().CloseFile(fd_dst, error)) { 406 if (!error.Fail()) 407 error.SetErrorString("unable to close destination file"); 408 } 409 return error; 410 } 411 return Platform::GetFile(source, destination); 412 } 413 414 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() { 415 StreamString stream; 416 if (GetSupportsRSync()) { 417 stream.PutCString("rsync"); 418 if ((GetRSyncOpts() && *GetRSyncOpts()) || 419 (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) { 420 stream.Printf(", options: "); 421 if (GetRSyncOpts() && *GetRSyncOpts()) 422 stream.Printf("'%s' ", GetRSyncOpts()); 423 stream.Printf(", prefix: "); 424 if (GetRSyncPrefix() && *GetRSyncPrefix()) 425 stream.Printf("'%s' ", GetRSyncPrefix()); 426 if (GetIgnoresRemoteHostname()) 427 stream.Printf("ignore remote-hostname "); 428 } 429 } 430 if (GetSupportsSSH()) { 431 stream.PutCString("ssh"); 432 if (GetSSHOpts() && *GetSSHOpts()) 433 stream.Printf(", options: '%s' ", GetSSHOpts()); 434 } 435 if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) 436 stream.Printf("cache dir: %s", GetLocalCacheDirectory()); 437 if (stream.GetSize()) 438 return stream.GetData(); 439 else 440 return ""; 441 } 442 443 bool PlatformPOSIX::CalculateMD5(const FileSpec &file_spec, uint64_t &low, 444 uint64_t &high) { 445 if (IsHost()) 446 return Platform::CalculateMD5(file_spec, low, high); 447 if (m_remote_platform_sp) 448 return m_remote_platform_sp->CalculateMD5(file_spec, low, high); 449 return false; 450 } 451 452 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() { 453 if (IsRemote() && m_remote_platform_sp) 454 return m_remote_platform_sp->GetRemoteUnixSignals(); 455 return Platform::GetRemoteUnixSignals(); 456 } 457 458 FileSpec PlatformPOSIX::GetRemoteWorkingDirectory() { 459 if (IsRemote() && m_remote_platform_sp) 460 return m_remote_platform_sp->GetRemoteWorkingDirectory(); 461 else 462 return Platform::GetRemoteWorkingDirectory(); 463 } 464 465 bool PlatformPOSIX::SetRemoteWorkingDirectory(const FileSpec &working_dir) { 466 if (IsRemote() && m_remote_platform_sp) 467 return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir); 468 else 469 return Platform::SetRemoteWorkingDirectory(working_dir); 470 } 471 472 bool PlatformPOSIX::GetRemoteOSVersion() { 473 if (m_remote_platform_sp) 474 return m_remote_platform_sp->GetOSVersion( 475 m_major_os_version, m_minor_os_version, m_update_os_version); 476 return false; 477 } 478 479 bool PlatformPOSIX::GetRemoteOSBuildString(std::string &s) { 480 if (m_remote_platform_sp) 481 return m_remote_platform_sp->GetRemoteOSBuildString(s); 482 s.clear(); 483 return false; 484 } 485 486 size_t PlatformPOSIX::GetEnvironment(StringList &env) { 487 if (IsRemote()) { 488 if (m_remote_platform_sp) 489 return m_remote_platform_sp->GetEnvironment(env); 490 return 0; 491 } 492 return Host::GetEnvironment(env); 493 } 494 495 bool PlatformPOSIX::GetRemoteOSKernelDescription(std::string &s) { 496 if (m_remote_platform_sp) 497 return m_remote_platform_sp->GetRemoteOSKernelDescription(s); 498 s.clear(); 499 return false; 500 } 501 502 // Remote Platform subclasses need to override this function 503 ArchSpec PlatformPOSIX::GetRemoteSystemArchitecture() { 504 if (m_remote_platform_sp) 505 return m_remote_platform_sp->GetRemoteSystemArchitecture(); 506 return ArchSpec(); 507 } 508 509 const char *PlatformPOSIX::GetHostname() { 510 if (IsHost()) 511 return Platform::GetHostname(); 512 513 if (m_remote_platform_sp) 514 return m_remote_platform_sp->GetHostname(); 515 return NULL; 516 } 517 518 const char *PlatformPOSIX::GetUserName(uint32_t uid) { 519 // Check the cache in Platform in case we have already looked this uid up 520 const char *user_name = Platform::GetUserName(uid); 521 if (user_name) 522 return user_name; 523 524 if (IsRemote() && m_remote_platform_sp) 525 return m_remote_platform_sp->GetUserName(uid); 526 return NULL; 527 } 528 529 const char *PlatformPOSIX::GetGroupName(uint32_t gid) { 530 const char *group_name = Platform::GetGroupName(gid); 531 if (group_name) 532 return group_name; 533 534 if (IsRemote() && m_remote_platform_sp) 535 return m_remote_platform_sp->GetGroupName(gid); 536 return NULL; 537 } 538 539 Error PlatformPOSIX::ConnectRemote(Args &args) { 540 Error error; 541 if (IsHost()) { 542 error.SetErrorStringWithFormat( 543 "can't connect to the host platform '%s', always connected", 544 GetPluginName().GetCString()); 545 } else { 546 if (!m_remote_platform_sp) 547 m_remote_platform_sp = 548 Platform::Create(ConstString("remote-gdb-server"), error); 549 550 if (m_remote_platform_sp && error.Success()) 551 error = m_remote_platform_sp->ConnectRemote(args); 552 else 553 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 554 555 if (error.Fail()) 556 m_remote_platform_sp.reset(); 557 } 558 559 if (error.Success() && m_remote_platform_sp) { 560 if (m_option_group_platform_rsync.get() && 561 m_option_group_platform_ssh.get() && 562 m_option_group_platform_caching.get()) { 563 if (m_option_group_platform_rsync->m_rsync) { 564 SetSupportsRSync(true); 565 SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str()); 566 SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str()); 567 SetIgnoresRemoteHostname( 568 m_option_group_platform_rsync->m_ignores_remote_hostname); 569 } 570 if (m_option_group_platform_ssh->m_ssh) { 571 SetSupportsSSH(true); 572 SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str()); 573 } 574 SetLocalCacheDirectory( 575 m_option_group_platform_caching->m_cache_dir.c_str()); 576 } 577 } 578 579 return error; 580 } 581 582 Error PlatformPOSIX::DisconnectRemote() { 583 Error error; 584 585 if (IsHost()) { 586 error.SetErrorStringWithFormat( 587 "can't disconnect from the host platform '%s', always connected", 588 GetPluginName().GetCString()); 589 } else { 590 if (m_remote_platform_sp) 591 error = m_remote_platform_sp->DisconnectRemote(); 592 else 593 error.SetErrorString("the platform is not currently connected"); 594 } 595 return error; 596 } 597 598 Error PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) { 599 Error error; 600 601 if (IsHost()) { 602 error = Platform::LaunchProcess(launch_info); 603 } else { 604 if (m_remote_platform_sp) 605 error = m_remote_platform_sp->LaunchProcess(launch_info); 606 else 607 error.SetErrorString("the platform is not currently connected"); 608 } 609 return error; 610 } 611 612 lldb_private::Error PlatformPOSIX::KillProcess(const lldb::pid_t pid) { 613 if (IsHost()) 614 return Platform::KillProcess(pid); 615 616 if (m_remote_platform_sp) 617 return m_remote_platform_sp->KillProcess(pid); 618 619 return Error("the platform is not currently connected"); 620 } 621 622 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, 623 Debugger &debugger, Target *target, 624 Error &error) { 625 lldb::ProcessSP process_sp; 626 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 627 628 if (IsHost()) { 629 if (target == NULL) { 630 TargetSP new_target_sp; 631 632 error = debugger.GetTargetList().CreateTarget(debugger, NULL, NULL, false, 633 NULL, new_target_sp); 634 target = new_target_sp.get(); 635 if (log) 636 log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__); 637 } else { 638 error.Clear(); 639 if (log) 640 log->Printf("PlatformPOSIX::%s target already existed, setting target", 641 __FUNCTION__); 642 } 643 644 if (target && error.Success()) { 645 debugger.GetTargetList().SetSelectedTarget(target); 646 if (log) { 647 ModuleSP exe_module_sp = target->GetExecutableModule(); 648 log->Printf("PlatformPOSIX::%s set selected target to %p %s", 649 __FUNCTION__, (void *)target, 650 exe_module_sp 651 ? exe_module_sp->GetFileSpec().GetPath().c_str() 652 : "<null>"); 653 } 654 655 process_sp = 656 target->CreateProcess(attach_info.GetListenerForProcess(debugger), 657 attach_info.GetProcessPluginName(), NULL); 658 659 if (process_sp) { 660 ListenerSP listener_sp = attach_info.GetHijackListener(); 661 if (listener_sp == nullptr) { 662 listener_sp = 663 Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack"); 664 attach_info.SetHijackListener(listener_sp); 665 } 666 process_sp->HijackProcessEvents(listener_sp); 667 error = process_sp->Attach(attach_info); 668 } 669 } 670 } else { 671 if (m_remote_platform_sp) 672 process_sp = 673 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 674 else 675 error.SetErrorString("the platform is not currently connected"); 676 } 677 return process_sp; 678 } 679 680 lldb::ProcessSP 681 PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, 682 Target *target, // Can be NULL, if NULL create a new 683 // target, else use existing one 684 Error &error) { 685 ProcessSP process_sp; 686 687 if (IsHost()) { 688 // We are going to hand this process off to debugserver which will be in 689 // charge of setting the exit status. 690 // We still need to reap it from lldb but if we let the monitor thread also 691 // set the exit status, we set up a 692 // race between debugserver & us for who will find out about the debugged 693 // process's death. 694 launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus); 695 process_sp = Platform::DebugProcess(launch_info, debugger, target, error); 696 } else { 697 if (m_remote_platform_sp) 698 process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, 699 target, error); 700 else 701 error.SetErrorString("the platform is not currently connected"); 702 } 703 return process_sp; 704 } 705 706 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() { 707 m_trap_handlers.push_back(ConstString("_sigtramp")); 708 } 709 710 Error PlatformPOSIX::EvaluateLibdlExpression( 711 lldb_private::Process *process, const char *expr_cstr, 712 const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp) { 713 DynamicLoader *loader = process->GetDynamicLoader(); 714 if (loader) { 715 Error error = loader->CanLoadImage(); 716 if (error.Fail()) 717 return error; 718 } 719 720 ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread()); 721 if (!thread_sp) 722 return Error("Selected thread isn't valid"); 723 724 StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); 725 if (!frame_sp) 726 return Error("Frame 0 isn't valid"); 727 728 ExecutionContext exe_ctx; 729 frame_sp->CalculateExecutionContext(exe_ctx); 730 EvaluateExpressionOptions expr_options; 731 expr_options.SetUnwindOnError(true); 732 expr_options.SetIgnoreBreakpoints(true); 733 expr_options.SetExecutionPolicy(eExecutionPolicyAlways); 734 expr_options.SetLanguage(eLanguageTypeC_plus_plus); 735 expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 736 // don't do the work to trap them. 737 expr_options.SetTimeoutUsec(2000000); // 2 seconds 738 739 Error expr_error; 740 UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix, 741 result_valobj_sp, expr_error); 742 if (result_valobj_sp->GetError().Fail()) 743 return result_valobj_sp->GetError(); 744 return Error(); 745 } 746 747 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, 748 const lldb_private::FileSpec &remote_file, 749 lldb_private::Error &error) { 750 char path[PATH_MAX]; 751 remote_file.GetPath(path, sizeof(path)); 752 753 StreamString expr; 754 expr.Printf(R"( 755 struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result; 756 the_result.image_ptr = dlopen ("%s", 2); 757 if (the_result.image_ptr == (void *) 0x0) 758 { 759 the_result.error_str = dlerror(); 760 } 761 else 762 { 763 the_result.error_str = (const char *) 0x0; 764 } 765 the_result; 766 )", 767 path); 768 const char *prefix = GetLibdlFunctionDeclarations(); 769 lldb::ValueObjectSP result_valobj_sp; 770 error = EvaluateLibdlExpression(process, expr.GetData(), prefix, 771 result_valobj_sp); 772 if (error.Fail()) 773 return LLDB_INVALID_IMAGE_TOKEN; 774 775 error = result_valobj_sp->GetError(); 776 if (error.Fail()) 777 return LLDB_INVALID_IMAGE_TOKEN; 778 779 Scalar scalar; 780 ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true); 781 if (!image_ptr_sp || !image_ptr_sp->ResolveValue(scalar)) { 782 error.SetErrorStringWithFormat("unable to load '%s'", path); 783 return LLDB_INVALID_IMAGE_TOKEN; 784 } 785 786 addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS); 787 if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS) 788 return process->AddImageToken(image_ptr); 789 790 if (image_ptr == 0) { 791 ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true); 792 if (error_str_sp) { 793 DataBufferSP buffer_sp(new DataBufferHeap(10240, 0)); 794 size_t num_chars = 795 error_str_sp->ReadPointedString(buffer_sp, error, 10240).first; 796 if (error.Success() && num_chars > 0) 797 error.SetErrorStringWithFormat("dlopen error: %s", 798 buffer_sp->GetBytes()); 799 else 800 error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); 801 return LLDB_INVALID_IMAGE_TOKEN; 802 } 803 } 804 error.SetErrorStringWithFormat("unable to load '%s'", path); 805 return LLDB_INVALID_IMAGE_TOKEN; 806 } 807 808 Error PlatformPOSIX::UnloadImage(lldb_private::Process *process, 809 uint32_t image_token) { 810 const addr_t image_addr = process->GetImagePtrFromToken(image_token); 811 if (image_addr == LLDB_INVALID_ADDRESS) 812 return Error("Invalid image token"); 813 814 StreamString expr; 815 expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr); 816 const char *prefix = GetLibdlFunctionDeclarations(); 817 lldb::ValueObjectSP result_valobj_sp; 818 Error error = EvaluateLibdlExpression(process, expr.GetData(), prefix, 819 result_valobj_sp); 820 if (error.Fail()) 821 return error; 822 823 if (result_valobj_sp->GetError().Fail()) 824 return result_valobj_sp->GetError(); 825 826 Scalar scalar; 827 if (result_valobj_sp->ResolveValue(scalar)) { 828 if (scalar.UInt(1)) 829 return Error("expression failed: \"%s\"", expr.GetData()); 830 process->ResetImageToken(image_token); 831 } 832 return Error(); 833 } 834 835 lldb::ProcessSP PlatformPOSIX::ConnectProcess(const char *connect_url, 836 const char *plugin_name, 837 lldb_private::Debugger &debugger, 838 lldb_private::Target *target, 839 lldb_private::Error &error) { 840 if (m_remote_platform_sp) 841 return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name, 842 debugger, target, error); 843 844 return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, 845 error); 846 } 847 848 const char *PlatformPOSIX::GetLibdlFunctionDeclarations() const { 849 return R"( 850 extern "C" void* dlopen(const char*, int); 851 extern "C" void* dlsym(void*, const char*); 852 extern "C" int dlclose(void*); 853 extern "C" char* dlerror(void); 854 )"; 855 } 856 857 size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger, 858 Error &error) { 859 if (m_remote_platform_sp) 860 return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); 861 return Platform::ConnectToWaitingProcesses(debugger, error); 862 } 863