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