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