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