1 //===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "PlatformPOSIX.h" 10 11 #include "lldb/Core/Debugger.h" 12 #include "lldb/Core/Module.h" 13 #include "lldb/Core/ModuleSpec.h" 14 #include "lldb/Core/ValueObject.h" 15 #include "lldb/Expression/DiagnosticManager.h" 16 #include "lldb/Expression/FunctionCaller.h" 17 #include "lldb/Expression/UserExpression.h" 18 #include "lldb/Expression/UtilityFunction.h" 19 #include "lldb/Host/File.h" 20 #include "lldb/Host/FileCache.h" 21 #include "lldb/Host/FileSystem.h" 22 #include "lldb/Host/Host.h" 23 #include "lldb/Host/HostInfo.h" 24 #include "lldb/Host/ProcessLaunchInfo.h" 25 #include "lldb/Symbol/ClangASTContext.h" 26 #include "lldb/Target/DynamicLoader.h" 27 #include "lldb/Target/ExecutionContext.h" 28 #include "lldb/Target/Process.h" 29 #include "lldb/Target/Thread.h" 30 #include "lldb/Utility/CleanUp.h" 31 #include "lldb/Utility/DataBufferHeap.h" 32 #include "lldb/Utility/FileSpec.h" 33 #include "lldb/Utility/Log.h" 34 #include "lldb/Utility/StreamString.h" 35 36 using namespace lldb; 37 using namespace lldb_private; 38 39 //------------------------------------------------------------------ 40 /// Default Constructor 41 //------------------------------------------------------------------ 42 PlatformPOSIX::PlatformPOSIX(bool is_host) 43 : RemoteAwarePlatform(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 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 lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions( 57 lldb_private::CommandInterpreter &interpreter) { 58 auto iter = m_options.find(&interpreter), end = m_options.end(); 59 if (iter == end) { 60 std::unique_ptr<lldb_private::OptionGroupOptions> options( 61 new OptionGroupOptions()); 62 options->Append(m_option_group_platform_rsync.get()); 63 options->Append(m_option_group_platform_ssh.get()); 64 options->Append(m_option_group_platform_caching.get()); 65 m_options[&interpreter] = std::move(options); 66 } 67 68 return m_options.at(&interpreter).get(); 69 } 70 71 Status 72 PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, 73 lldb::ModuleSP &exe_module_sp, 74 const FileSpecList *module_search_paths_ptr) { 75 Status error; 76 // Nothing special to do here, just use the actual file and architecture 77 78 char exe_path[PATH_MAX]; 79 ModuleSpec resolved_module_spec(module_spec); 80 81 if (IsHost()) { 82 // If we have "ls" as the exe_file, resolve the executable location based 83 // on the current path variables 84 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { 85 resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 86 resolved_module_spec.GetFileSpec().SetFile(exe_path, 87 FileSpec::Style::native); 88 FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); 89 } 90 91 if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 92 FileSystem::Instance().ResolveExecutableLocation( 93 resolved_module_spec.GetFileSpec()); 94 95 // Resolve any executable within a bundle on MacOSX 96 Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 97 98 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 99 error.Clear(); 100 else { 101 const uint32_t permissions = FileSystem::Instance().GetPermissions( 102 resolved_module_spec.GetFileSpec()); 103 if (permissions && (permissions & eFilePermissionsEveryoneR) == 0) 104 error.SetErrorStringWithFormat( 105 "executable '%s' is not readable", 106 resolved_module_spec.GetFileSpec().GetPath().c_str()); 107 else 108 error.SetErrorStringWithFormat( 109 "unable to find executable for '%s'", 110 resolved_module_spec.GetFileSpec().GetPath().c_str()); 111 } 112 } else { 113 if (m_remote_platform_sp) { 114 error = 115 GetCachedExecutable(resolved_module_spec, exe_module_sp, 116 module_search_paths_ptr, *m_remote_platform_sp); 117 } else { 118 // We may connect to a process and use the provided executable (Don't use 119 // local $PATH). 120 121 // Resolve any executable within a bundle on MacOSX 122 Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 123 124 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 125 error.Clear(); 126 else 127 error.SetErrorStringWithFormat("the platform is not currently " 128 "connected, and '%s' doesn't exist in " 129 "the system root.", 130 exe_path); 131 } 132 } 133 134 if (error.Success()) { 135 if (resolved_module_spec.GetArchitecture().IsValid()) { 136 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 137 module_search_paths_ptr, nullptr, nullptr); 138 if (error.Fail()) { 139 // If we failed, it may be because the vendor and os aren't known. If 140 // that is the case, try setting them to the host architecture and give 141 // it another try. 142 llvm::Triple &module_triple = 143 resolved_module_spec.GetArchitecture().GetTriple(); 144 bool is_vendor_specified = 145 (module_triple.getVendor() != llvm::Triple::UnknownVendor); 146 bool is_os_specified = 147 (module_triple.getOS() != llvm::Triple::UnknownOS); 148 if (!is_vendor_specified || !is_os_specified) { 149 const llvm::Triple &host_triple = 150 HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple(); 151 152 if (!is_vendor_specified) 153 module_triple.setVendorName(host_triple.getVendorName()); 154 if (!is_os_specified) 155 module_triple.setOSName(host_triple.getOSName()); 156 157 error = ModuleList::GetSharedModule(resolved_module_spec, 158 exe_module_sp, module_search_paths_ptr, nullptr, nullptr); 159 } 160 } 161 162 // TODO find out why exe_module_sp might be NULL 163 if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) { 164 exe_module_sp.reset(); 165 error.SetErrorStringWithFormat( 166 "'%s' doesn't contain the architecture %s", 167 resolved_module_spec.GetFileSpec().GetPath().c_str(), 168 resolved_module_spec.GetArchitecture().GetArchitectureName()); 169 } 170 } else { 171 // No valid architecture was specified, ask the platform for the 172 // architectures that we should be using (in the correct order) and see 173 // if we can find a match that way 174 StreamString arch_names; 175 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( 176 idx, resolved_module_spec.GetArchitecture()); 177 ++idx) { 178 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 179 module_search_paths_ptr, nullptr, nullptr); 180 // Did we find an executable using one of the 181 if (error.Success()) { 182 if (exe_module_sp && exe_module_sp->GetObjectFile()) 183 break; 184 else 185 error.SetErrorToGenericError(); 186 } 187 188 if (idx > 0) 189 arch_names.PutCString(", "); 190 arch_names.PutCString( 191 resolved_module_spec.GetArchitecture().GetArchitectureName()); 192 } 193 194 if (error.Fail() || !exe_module_sp) { 195 if (FileSystem::Instance().Readable( 196 resolved_module_spec.GetFileSpec())) { 197 error.SetErrorStringWithFormat( 198 "'%s' doesn't contain any '%s' platform architectures: %s", 199 resolved_module_spec.GetFileSpec().GetPath().c_str(), 200 GetPluginName().GetCString(), arch_names.GetData()); 201 } else { 202 error.SetErrorStringWithFormat( 203 "'%s' is not readable", 204 resolved_module_spec.GetFileSpec().GetPath().c_str()); 205 } 206 } 207 } 208 } 209 210 return error; 211 } 212 213 static uint32_t chown_file(Platform *platform, const char *path, 214 uint32_t uid = UINT32_MAX, 215 uint32_t gid = UINT32_MAX) { 216 if (!platform || !path || *path == 0) 217 return UINT32_MAX; 218 219 if (uid == UINT32_MAX && gid == UINT32_MAX) 220 return 0; // pretend I did chown correctly - actually I just didn't care 221 222 StreamString command; 223 command.PutCString("chown "); 224 if (uid != UINT32_MAX) 225 command.Printf("%d", uid); 226 if (gid != UINT32_MAX) 227 command.Printf(":%d", gid); 228 command.Printf("%s", path); 229 int status; 230 platform->RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 231 std::chrono::seconds(10)); 232 return status; 233 } 234 235 lldb_private::Status 236 PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, 237 const lldb_private::FileSpec &destination, uint32_t uid, 238 uint32_t gid) { 239 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 240 241 if (IsHost()) { 242 if (FileSpec::Equal(source, destination, true)) 243 return Status(); 244 // cp src dst 245 // chown uid:gid dst 246 std::string src_path(source.GetPath()); 247 if (src_path.empty()) 248 return Status("unable to get file path for source"); 249 std::string dst_path(destination.GetPath()); 250 if (dst_path.empty()) 251 return Status("unable to get file path for destination"); 252 StreamString command; 253 command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 254 int status; 255 RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 256 std::chrono::seconds(10)); 257 if (status != 0) 258 return Status("unable to perform copy"); 259 if (uid == UINT32_MAX && gid == UINT32_MAX) 260 return Status(); 261 if (chown_file(this, dst_path.c_str(), uid, gid) != 0) 262 return Status("unable to perform chown"); 263 return Status(); 264 } else if (m_remote_platform_sp) { 265 if (GetSupportsRSync()) { 266 std::string src_path(source.GetPath()); 267 if (src_path.empty()) 268 return Status("unable to get file path for source"); 269 std::string dst_path(destination.GetPath()); 270 if (dst_path.empty()) 271 return Status("unable to get file path for destination"); 272 StreamString command; 273 if (GetIgnoresRemoteHostname()) { 274 if (!GetRSyncPrefix()) 275 command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 276 dst_path.c_str()); 277 else 278 command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(), 279 GetRSyncPrefix(), dst_path.c_str()); 280 } else 281 command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(), 282 GetHostname(), dst_path.c_str()); 283 if (log) 284 log->Printf("[PutFile] Running command: %s\n", command.GetData()); 285 int retcode; 286 Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 287 std::chrono::minutes(1)); 288 if (retcode == 0) { 289 // Don't chown a local file for a remote system 290 // if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 291 // return Status("unable to perform chown"); 292 return Status(); 293 } 294 // if we are still here rsync has failed - let's try the slow way before 295 // giving up 296 } 297 } 298 return Platform::PutFile(source, destination, uid, gid); 299 } 300 301 lldb_private::Status PlatformPOSIX::GetFile( 302 const lldb_private::FileSpec &source, // remote file path 303 const lldb_private::FileSpec &destination) // local file path 304 { 305 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 306 307 // Check the args, first. 308 std::string src_path(source.GetPath()); 309 if (src_path.empty()) 310 return Status("unable to get file path for source"); 311 std::string dst_path(destination.GetPath()); 312 if (dst_path.empty()) 313 return Status("unable to get file path for destination"); 314 if (IsHost()) { 315 if (FileSpec::Equal(source, destination, true)) 316 return Status("local scenario->source and destination are the same file " 317 "path: no operation performed"); 318 // cp src dst 319 StreamString cp_command; 320 cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 321 int status; 322 RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 323 std::chrono::seconds(10)); 324 if (status != 0) 325 return Status("unable to perform copy"); 326 return Status(); 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, 345 std::chrono::minutes(1)); 346 if (retcode == 0) 347 return Status(); 348 // If we are here, rsync has failed - let's try the slow way before 349 // giving up 350 } 351 // open src and dst 352 // read/write, read/write, read/write, ... 353 // close src 354 // close dst 355 if (log) 356 log->Printf("[GetFile] Using block by block transfer....\n"); 357 Status error; 358 user_id_t fd_src = OpenFile(source, File::eOpenOptionRead, 359 lldb::eFilePermissionsFileDefault, error); 360 361 if (fd_src == UINT64_MAX) 362 return Status("unable to open source file"); 363 364 uint32_t permissions = 0; 365 error = GetFilePermissions(source, permissions); 366 367 if (permissions == 0) 368 permissions = lldb::eFilePermissionsFileDefault; 369 370 user_id_t fd_dst = FileCache::GetInstance().OpenFile( 371 destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | 372 File::eOpenOptionTruncate, 373 permissions, error); 374 375 if (fd_dst == UINT64_MAX) { 376 if (error.Success()) 377 error.SetErrorString("unable to open destination file"); 378 } 379 380 if (error.Success()) { 381 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 382 uint64_t offset = 0; 383 error.Clear(); 384 while (error.Success()) { 385 const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(), 386 buffer_sp->GetByteSize(), error); 387 if (error.Fail()) 388 break; 389 if (n_read == 0) 390 break; 391 if (FileCache::GetInstance().WriteFile(fd_dst, offset, 392 buffer_sp->GetBytes(), n_read, 393 error) != n_read) { 394 if (!error.Fail()) 395 error.SetErrorString("unable to write to destination file"); 396 break; 397 } 398 offset += n_read; 399 } 400 } 401 // Ignore the close error of src. 402 if (fd_src != UINT64_MAX) 403 CloseFile(fd_src, error); 404 // And close the dst file descriptot. 405 if (fd_dst != UINT64_MAX && 406 !FileCache::GetInstance().CloseFile(fd_dst, error)) { 407 if (!error.Fail()) 408 error.SetErrorString("unable to close destination file"); 409 } 410 return error; 411 } 412 return Platform::GetFile(source, destination); 413 } 414 415 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() { 416 StreamString stream; 417 if (GetSupportsRSync()) { 418 stream.PutCString("rsync"); 419 if ((GetRSyncOpts() && *GetRSyncOpts()) || 420 (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) { 421 stream.Printf(", options: "); 422 if (GetRSyncOpts() && *GetRSyncOpts()) 423 stream.Printf("'%s' ", GetRSyncOpts()); 424 stream.Printf(", prefix: "); 425 if (GetRSyncPrefix() && *GetRSyncPrefix()) 426 stream.Printf("'%s' ", GetRSyncPrefix()); 427 if (GetIgnoresRemoteHostname()) 428 stream.Printf("ignore remote-hostname "); 429 } 430 } 431 if (GetSupportsSSH()) { 432 stream.PutCString("ssh"); 433 if (GetSSHOpts() && *GetSSHOpts()) 434 stream.Printf(", options: '%s' ", GetSSHOpts()); 435 } 436 if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) 437 stream.Printf("cache dir: %s", GetLocalCacheDirectory()); 438 if (stream.GetSize()) 439 return stream.GetString(); 440 else 441 return ""; 442 } 443 444 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() { 445 if (IsRemote() && m_remote_platform_sp) 446 return m_remote_platform_sp->GetRemoteUnixSignals(); 447 return Platform::GetRemoteUnixSignals(); 448 } 449 450 Status PlatformPOSIX::ConnectRemote(Args &args) { 451 Status error; 452 if (IsHost()) { 453 error.SetErrorStringWithFormat( 454 "can't connect to the host platform '%s', always connected", 455 GetPluginName().GetCString()); 456 } else { 457 if (!m_remote_platform_sp) 458 m_remote_platform_sp = 459 Platform::Create(ConstString("remote-gdb-server"), error); 460 461 if (m_remote_platform_sp && error.Success()) 462 error = m_remote_platform_sp->ConnectRemote(args); 463 else 464 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 465 466 if (error.Fail()) 467 m_remote_platform_sp.reset(); 468 } 469 470 if (error.Success() && m_remote_platform_sp) { 471 if (m_option_group_platform_rsync.get() && 472 m_option_group_platform_ssh.get() && 473 m_option_group_platform_caching.get()) { 474 if (m_option_group_platform_rsync->m_rsync) { 475 SetSupportsRSync(true); 476 SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str()); 477 SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str()); 478 SetIgnoresRemoteHostname( 479 m_option_group_platform_rsync->m_ignores_remote_hostname); 480 } 481 if (m_option_group_platform_ssh->m_ssh) { 482 SetSupportsSSH(true); 483 SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str()); 484 } 485 SetLocalCacheDirectory( 486 m_option_group_platform_caching->m_cache_dir.c_str()); 487 } 488 } 489 490 return error; 491 } 492 493 Status PlatformPOSIX::DisconnectRemote() { 494 Status error; 495 496 if (IsHost()) { 497 error.SetErrorStringWithFormat( 498 "can't disconnect from the host platform '%s', always connected", 499 GetPluginName().GetCString()); 500 } else { 501 if (m_remote_platform_sp) 502 error = m_remote_platform_sp->DisconnectRemote(); 503 else 504 error.SetErrorString("the platform is not currently connected"); 505 } 506 return error; 507 } 508 509 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, 510 Debugger &debugger, Target *target, 511 Status &error) { 512 lldb::ProcessSP process_sp; 513 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 514 515 if (IsHost()) { 516 if (target == NULL) { 517 TargetSP new_target_sp; 518 519 error = debugger.GetTargetList().CreateTarget( 520 debugger, "", "", eLoadDependentsNo, NULL, new_target_sp); 521 target = new_target_sp.get(); 522 if (log) 523 log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__); 524 } else { 525 error.Clear(); 526 if (log) 527 log->Printf("PlatformPOSIX::%s target already existed, setting target", 528 __FUNCTION__); 529 } 530 531 if (target && error.Success()) { 532 debugger.GetTargetList().SetSelectedTarget(target); 533 if (log) { 534 ModuleSP exe_module_sp = target->GetExecutableModule(); 535 log->Printf("PlatformPOSIX::%s set selected target to %p %s", 536 __FUNCTION__, (void *)target, 537 exe_module_sp 538 ? exe_module_sp->GetFileSpec().GetPath().c_str() 539 : "<null>"); 540 } 541 542 process_sp = 543 target->CreateProcess(attach_info.GetListenerForProcess(debugger), 544 attach_info.GetProcessPluginName(), NULL); 545 546 if (process_sp) { 547 ListenerSP listener_sp = attach_info.GetHijackListener(); 548 if (listener_sp == nullptr) { 549 listener_sp = 550 Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack"); 551 attach_info.SetHijackListener(listener_sp); 552 } 553 process_sp->HijackProcessEvents(listener_sp); 554 error = process_sp->Attach(attach_info); 555 } 556 } 557 } else { 558 if (m_remote_platform_sp) 559 process_sp = 560 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 561 else 562 error.SetErrorString("the platform is not currently connected"); 563 } 564 return process_sp; 565 } 566 567 lldb::ProcessSP 568 PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, 569 Target *target, // Can be NULL, if NULL create a new 570 // target, else use existing one 571 Status &error) { 572 ProcessSP process_sp; 573 574 if (IsHost()) { 575 // We are going to hand this process off to debugserver which will be in 576 // charge of setting the exit status. However, we still need to reap it 577 // from lldb. So, make sure we use a exit callback which does not set exit 578 // status. 579 const bool monitor_signals = false; 580 launch_info.SetMonitorProcessCallback( 581 &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals); 582 process_sp = Platform::DebugProcess(launch_info, debugger, target, error); 583 } else { 584 if (m_remote_platform_sp) 585 process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, 586 target, error); 587 else 588 error.SetErrorString("the platform is not currently connected"); 589 } 590 return process_sp; 591 } 592 593 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() { 594 m_trap_handlers.push_back(ConstString("_sigtramp")); 595 } 596 597 Status PlatformPOSIX::EvaluateLibdlExpression( 598 lldb_private::Process *process, const char *expr_cstr, 599 llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) { 600 DynamicLoader *loader = process->GetDynamicLoader(); 601 if (loader) { 602 Status error = loader->CanLoadImage(); 603 if (error.Fail()) 604 return error; 605 } 606 607 ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread()); 608 if (!thread_sp) 609 return Status("Selected thread isn't valid"); 610 611 StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); 612 if (!frame_sp) 613 return Status("Frame 0 isn't valid"); 614 615 ExecutionContext exe_ctx; 616 frame_sp->CalculateExecutionContext(exe_ctx); 617 EvaluateExpressionOptions expr_options; 618 expr_options.SetUnwindOnError(true); 619 expr_options.SetIgnoreBreakpoints(true); 620 expr_options.SetExecutionPolicy(eExecutionPolicyAlways); 621 expr_options.SetLanguage(eLanguageTypeC_plus_plus); 622 expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 623 // don't do the work to trap them. 624 expr_options.SetTimeout(std::chrono::seconds(2)); 625 626 Status expr_error; 627 ExpressionResults result = 628 UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix, 629 result_valobj_sp, expr_error); 630 if (result != eExpressionCompleted) 631 return expr_error; 632 633 if (result_valobj_sp->GetError().Fail()) 634 return result_valobj_sp->GetError(); 635 return Status(); 636 } 637 638 std::unique_ptr<UtilityFunction> 639 PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, 640 Status &error) { 641 // Remember to prepend this with the prefix from 642 // GetLibdlFunctionDeclarations. The returned values are all in 643 // __lldb_dlopen_result for consistency. The wrapper returns a void * but 644 // doesn't use it because UtilityFunctions don't work with void returns at 645 // present. 646 static const char *dlopen_wrapper_code = R"( 647 struct __lldb_dlopen_result { 648 void *image_ptr; 649 const char *error_str; 650 }; 651 652 extern void *memcpy(void *, const void *, size_t size); 653 extern size_t strlen(const char *); 654 655 656 void * __lldb_dlopen_wrapper (const char *name, 657 const char *path_strings, 658 char *buffer, 659 __lldb_dlopen_result *result_ptr) 660 { 661 // This is the case where the name is the full path: 662 if (!path_strings) { 663 result_ptr->image_ptr = dlopen(name, 2); 664 if (result_ptr->image_ptr) 665 result_ptr->error_str = nullptr; 666 return nullptr; 667 } 668 669 // This is the case where we have a list of paths: 670 size_t name_len = strlen(name); 671 while (path_strings && path_strings[0] != '\0') { 672 size_t path_len = strlen(path_strings); 673 memcpy((void *) buffer, (void *) path_strings, path_len); 674 buffer[path_len] = '/'; 675 char *target_ptr = buffer+path_len+1; 676 memcpy((void *) target_ptr, (void *) name, name_len + 1); 677 result_ptr->image_ptr = dlopen(buffer, 2); 678 if (result_ptr->image_ptr) { 679 result_ptr->error_str = nullptr; 680 break; 681 } 682 result_ptr->error_str = dlerror(); 683 path_strings = path_strings + path_len + 1; 684 } 685 return nullptr; 686 } 687 )"; 688 689 static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper"; 690 Process *process = exe_ctx.GetProcessSP().get(); 691 // Insert the dlopen shim defines into our generic expression: 692 std::string expr(GetLibdlFunctionDeclarations(process)); 693 expr.append(dlopen_wrapper_code); 694 Status utility_error; 695 DiagnosticManager diagnostics; 696 697 std::unique_ptr<UtilityFunction> dlopen_utility_func_up(process 698 ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(), 699 eLanguageTypeObjC, 700 dlopen_wrapper_name, 701 utility_error)); 702 if (utility_error.Fail()) { 703 error.SetErrorStringWithFormat("dlopen error: could not make utility" 704 "function: %s", utility_error.AsCString()); 705 return nullptr; 706 } 707 if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) { 708 error.SetErrorStringWithFormat("dlopen error: could not install utility" 709 "function: %s", 710 diagnostics.GetString().c_str()); 711 return nullptr; 712 } 713 714 Value value; 715 ValueList arguments; 716 FunctionCaller *do_dlopen_function = nullptr; 717 718 // Fetch the clang types we will need: 719 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 720 721 CompilerType clang_void_pointer_type 722 = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 723 CompilerType clang_char_pointer_type 724 = ast->GetBasicType(eBasicTypeChar).GetPointerType(); 725 726 // We are passing four arguments, the basename, the list of places to look, 727 // a buffer big enough for all the path + name combos, and 728 // a pointer to the storage we've made for the result: 729 value.SetValueType(Value::eValueTypeScalar); 730 value.SetCompilerType(clang_void_pointer_type); 731 arguments.PushValue(value); 732 value.SetCompilerType(clang_char_pointer_type); 733 arguments.PushValue(value); 734 arguments.PushValue(value); 735 arguments.PushValue(value); 736 737 do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller( 738 clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error); 739 if (utility_error.Fail()) { 740 error.SetErrorStringWithFormat("dlopen error: could not make function" 741 "caller: %s", utility_error.AsCString()); 742 return nullptr; 743 } 744 745 do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller(); 746 if (!do_dlopen_function) { 747 error.SetErrorString("dlopen error: could not get function caller."); 748 return nullptr; 749 } 750 751 // We made a good utility function, so cache it in the process: 752 return dlopen_utility_func_up; 753 } 754 755 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, 756 const lldb_private::FileSpec &remote_file, 757 const std::vector<std::string> *paths, 758 lldb_private::Status &error, 759 lldb_private::FileSpec *loaded_image) { 760 if (loaded_image) 761 loaded_image->Clear(); 762 763 std::string path; 764 path = remote_file.GetPath(); 765 766 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); 767 if (!thread_sp) { 768 error.SetErrorString("dlopen error: no thread available to call dlopen."); 769 return LLDB_INVALID_IMAGE_TOKEN; 770 } 771 772 DiagnosticManager diagnostics; 773 774 ExecutionContext exe_ctx; 775 thread_sp->CalculateExecutionContext(exe_ctx); 776 777 Status utility_error; 778 UtilityFunction *dlopen_utility_func; 779 ValueList arguments; 780 FunctionCaller *do_dlopen_function = nullptr; 781 782 // The UtilityFunction is held in the Process. Platforms don't track the 783 // lifespan of the Targets that use them, we can't put this in the Platform. 784 dlopen_utility_func = process->GetLoadImageUtilityFunction( 785 this, [&]() -> std::unique_ptr<UtilityFunction> { 786 return MakeLoadImageUtilityFunction(exe_ctx, error); 787 }); 788 // If we couldn't make it, the error will be in error, so we can exit here. 789 if (!dlopen_utility_func) 790 return LLDB_INVALID_IMAGE_TOKEN; 791 792 do_dlopen_function = dlopen_utility_func->GetFunctionCaller(); 793 if (!do_dlopen_function) { 794 error.SetErrorString("dlopen error: could not get function caller."); 795 return LLDB_INVALID_IMAGE_TOKEN; 796 } 797 arguments = do_dlopen_function->GetArgumentValues(); 798 799 // Now insert the path we are searching for and the result structure into the 800 // target. 801 uint32_t permissions = ePermissionsReadable|ePermissionsWritable; 802 size_t path_len = path.size() + 1; 803 lldb::addr_t path_addr = process->AllocateMemory(path_len, 804 permissions, 805 utility_error); 806 if (path_addr == LLDB_INVALID_ADDRESS) { 807 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 808 "for path: %s", utility_error.AsCString()); 809 return LLDB_INVALID_IMAGE_TOKEN; 810 } 811 812 // Make sure we deallocate the input string memory: 813 CleanUp path_cleanup([process, path_addr] { 814 process->DeallocateMemory(path_addr); 815 }); 816 817 process->WriteMemory(path_addr, path.c_str(), path_len, utility_error); 818 if (utility_error.Fail()) { 819 error.SetErrorStringWithFormat("dlopen error: could not write path string:" 820 " %s", utility_error.AsCString()); 821 return LLDB_INVALID_IMAGE_TOKEN; 822 } 823 824 // Make space for our return structure. It is two pointers big: the token 825 // and the error string. 826 const uint32_t addr_size = process->GetAddressByteSize(); 827 lldb::addr_t return_addr = process->CallocateMemory(2*addr_size, 828 permissions, 829 utility_error); 830 if (utility_error.Fail()) { 831 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 832 "for path: %s", utility_error.AsCString()); 833 return LLDB_INVALID_IMAGE_TOKEN; 834 } 835 836 // Make sure we deallocate the result structure memory 837 CleanUp return_cleanup([process, return_addr] { 838 process->DeallocateMemory(return_addr); 839 }); 840 841 // This will be the address of the storage for paths, if we are using them, 842 // or nullptr to signal we aren't. 843 lldb::addr_t path_array_addr = 0x0; 844 llvm::Optional<CleanUp> path_array_cleanup; 845 846 // This is the address to a buffer large enough to hold the largest path 847 // conjoined with the library name we're passing in. This is a convenience 848 // to avoid having to call malloc in the dlopen function. 849 lldb::addr_t buffer_addr = 0x0; 850 llvm::Optional<CleanUp> buffer_cleanup; 851 852 // Set the values into our args and write them to the target: 853 if (paths != nullptr) { 854 // First insert the paths into the target. This is expected to be a 855 // continuous buffer with the strings laid out null terminated and 856 // end to end with an empty string terminating the buffer. 857 // We also compute the buffer's required size as we go. 858 size_t buffer_size = 0; 859 std::string path_array; 860 for (auto path : *paths) { 861 // Don't insert empty paths, they will make us abort the path 862 // search prematurely. 863 if (path.empty()) 864 continue; 865 size_t path_size = path.size(); 866 path_array.append(path); 867 path_array.push_back('\0'); 868 if (path_size > buffer_size) 869 buffer_size = path_size; 870 } 871 path_array.push_back('\0'); 872 873 path_array_addr = process->AllocateMemory(path_array.size(), 874 permissions, 875 utility_error); 876 if (path_array_addr == LLDB_INVALID_ADDRESS) { 877 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 878 "for path array: %s", 879 utility_error.AsCString()); 880 return LLDB_INVALID_IMAGE_TOKEN; 881 } 882 883 // Make sure we deallocate the paths array. 884 path_array_cleanup.emplace([process, path_array_addr] { 885 process->DeallocateMemory(path_array_addr); 886 }); 887 888 process->WriteMemory(path_array_addr, path_array.data(), 889 path_array.size(), utility_error); 890 891 if (utility_error.Fail()) { 892 error.SetErrorStringWithFormat("dlopen error: could not write path array:" 893 " %s", utility_error.AsCString()); 894 return LLDB_INVALID_IMAGE_TOKEN; 895 } 896 // Now make spaces in the target for the buffer. We need to add one for 897 // the '/' that the utility function will insert and one for the '\0': 898 buffer_size += path.size() + 2; 899 900 buffer_addr = process->AllocateMemory(buffer_size, 901 permissions, 902 utility_error); 903 if (buffer_addr == LLDB_INVALID_ADDRESS) { 904 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 905 "for buffer: %s", 906 utility_error.AsCString()); 907 return LLDB_INVALID_IMAGE_TOKEN; 908 } 909 910 // Make sure we deallocate the buffer memory: 911 buffer_cleanup.emplace([process, buffer_addr] { 912 process->DeallocateMemory(buffer_addr); 913 }); 914 } 915 916 arguments.GetValueAtIndex(0)->GetScalar() = path_addr; 917 arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr; 918 arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr; 919 arguments.GetValueAtIndex(3)->GetScalar() = return_addr; 920 921 lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS; 922 923 diagnostics.Clear(); 924 if (!do_dlopen_function->WriteFunctionArguments(exe_ctx, 925 func_args_addr, 926 arguments, 927 diagnostics)) { 928 error.SetErrorStringWithFormat("dlopen error: could not write function " 929 "arguments: %s", 930 diagnostics.GetString().c_str()); 931 return LLDB_INVALID_IMAGE_TOKEN; 932 } 933 934 // Make sure we clean up the args structure. We can't reuse it because the 935 // Platform lives longer than the process and the Platforms don't get a 936 // signal to clean up cached data when a process goes away. 937 CleanUp args_cleanup([do_dlopen_function, &exe_ctx, func_args_addr] { 938 do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr); 939 }); 940 941 // Now run the caller: 942 EvaluateExpressionOptions options; 943 options.SetExecutionPolicy(eExecutionPolicyAlways); 944 options.SetLanguage(eLanguageTypeC_plus_plus); 945 options.SetIgnoreBreakpoints(true); 946 options.SetUnwindOnError(true); 947 options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 948 // don't do the work to trap them. 949 options.SetTimeout(std::chrono::seconds(2)); 950 options.SetIsForUtilityExpr(true); 951 952 Value return_value; 953 // Fetch the clang types we will need: 954 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 955 956 CompilerType clang_void_pointer_type 957 = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 958 959 return_value.SetCompilerType(clang_void_pointer_type); 960 961 ExpressionResults results = do_dlopen_function->ExecuteFunction( 962 exe_ctx, &func_args_addr, options, diagnostics, return_value); 963 if (results != eExpressionCompleted) { 964 error.SetErrorStringWithFormat("dlopen error: failed executing " 965 "dlopen wrapper function: %s", 966 diagnostics.GetString().c_str()); 967 return LLDB_INVALID_IMAGE_TOKEN; 968 } 969 970 // Read the dlopen token from the return area: 971 lldb::addr_t token = process->ReadPointerFromMemory(return_addr, 972 utility_error); 973 if (utility_error.Fail()) { 974 error.SetErrorStringWithFormat("dlopen error: could not read the return " 975 "struct: %s", utility_error.AsCString()); 976 return LLDB_INVALID_IMAGE_TOKEN; 977 } 978 979 // The dlopen succeeded! 980 if (token != 0x0) { 981 if (loaded_image && buffer_addr != 0x0) 982 { 983 // Capture the image which was loaded. We leave it in the buffer on 984 // exit from the dlopen function, so we can just read it from there: 985 std::string name_string; 986 process->ReadCStringFromMemory(buffer_addr, name_string, utility_error); 987 if (utility_error.Success()) 988 loaded_image->SetFile(name_string, llvm::sys::path::Style::posix); 989 } 990 return process->AddImageToken(token); 991 } 992 993 // We got an error, lets read in the error string: 994 std::string dlopen_error_str; 995 lldb::addr_t error_addr 996 = process->ReadPointerFromMemory(return_addr + addr_size, utility_error); 997 if (utility_error.Fail()) { 998 error.SetErrorStringWithFormat("dlopen error: could not read error string: " 999 "%s", utility_error.AsCString()); 1000 return LLDB_INVALID_IMAGE_TOKEN; 1001 } 1002 1003 size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size, 1004 dlopen_error_str, 1005 utility_error); 1006 if (utility_error.Success() && num_chars > 0) 1007 error.SetErrorStringWithFormat("dlopen error: %s", 1008 dlopen_error_str.c_str()); 1009 else 1010 error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); 1011 1012 return LLDB_INVALID_IMAGE_TOKEN; 1013 } 1014 1015 Status PlatformPOSIX::UnloadImage(lldb_private::Process *process, 1016 uint32_t image_token) { 1017 const addr_t image_addr = process->GetImagePtrFromToken(image_token); 1018 if (image_addr == LLDB_INVALID_ADDRESS) 1019 return Status("Invalid image token"); 1020 1021 StreamString expr; 1022 expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr); 1023 llvm::StringRef prefix = GetLibdlFunctionDeclarations(process); 1024 lldb::ValueObjectSP result_valobj_sp; 1025 Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix, 1026 result_valobj_sp); 1027 if (error.Fail()) 1028 return error; 1029 1030 if (result_valobj_sp->GetError().Fail()) 1031 return result_valobj_sp->GetError(); 1032 1033 Scalar scalar; 1034 if (result_valobj_sp->ResolveValue(scalar)) { 1035 if (scalar.UInt(1)) 1036 return Status("expression failed: \"%s\"", expr.GetData()); 1037 process->ResetImageToken(image_token); 1038 } 1039 return Status(); 1040 } 1041 1042 llvm::StringRef 1043 PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) { 1044 return R"( 1045 extern "C" void* dlopen(const char*, int); 1046 extern "C" void* dlsym(void*, const char*); 1047 extern "C" int dlclose(void*); 1048 extern "C" char* dlerror(void); 1049 )"; 1050 } 1051 1052 size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger, 1053 Status &error) { 1054 if (m_remote_platform_sp) 1055 return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); 1056 return Platform::ConnectToWaitingProcesses(debugger, error); 1057 } 1058 1059 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) { 1060 if (basename.IsEmpty()) 1061 return basename; 1062 1063 StreamString stream; 1064 stream.Printf("lib%s.so", basename.GetCString()); 1065 return ConstString(stream.GetString()); 1066 } 1067