1 //===-- PlatformPOSIX.cpp -------------------------------------------------===// 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 "Plugins/TypeSystem/Clang/TypeSystemClang.h" 12 #include "lldb/Core/Debugger.h" 13 #include "lldb/Core/Module.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/Target/DynamicLoader.h" 26 #include "lldb/Target/ExecutionContext.h" 27 #include "lldb/Target/Process.h" 28 #include "lldb/Target/Thread.h" 29 #include "lldb/Utility/DataBufferHeap.h" 30 #include "lldb/Utility/FileSpec.h" 31 #include "lldb/Utility/LLDBLog.h" 32 #include "lldb/Utility/Log.h" 33 #include "lldb/Utility/StreamString.h" 34 #include "llvm/ADT/ScopeExit.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() = default; 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 static uint32_t chown_file(Platform *platform, const char *path, 68 uint32_t uid = UINT32_MAX, 69 uint32_t gid = UINT32_MAX) { 70 if (!platform || !path || *path == 0) 71 return UINT32_MAX; 72 73 if (uid == UINT32_MAX && gid == UINT32_MAX) 74 return 0; // pretend I did chown correctly - actually I just didn't care 75 76 StreamString command; 77 command.PutCString("chown "); 78 if (uid != UINT32_MAX) 79 command.Printf("%d", uid); 80 if (gid != UINT32_MAX) 81 command.Printf(":%d", gid); 82 command.Printf("%s", path); 83 int status; 84 platform->RunShellCommand(command.GetData(), FileSpec(), &status, nullptr, 85 nullptr, std::chrono::seconds(10)); 86 return status; 87 } 88 89 lldb_private::Status 90 PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, 91 const lldb_private::FileSpec &destination, uint32_t uid, 92 uint32_t gid) { 93 Log *log = GetLog(LLDBLog::Platform); 94 95 if (IsHost()) { 96 if (source == destination) 97 return Status(); 98 // cp src dst 99 // chown uid:gid dst 100 std::string src_path(source.GetPath()); 101 if (src_path.empty()) 102 return Status("unable to get file path for source"); 103 std::string dst_path(destination.GetPath()); 104 if (dst_path.empty()) 105 return Status("unable to get file path for destination"); 106 StreamString command; 107 command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 108 int status; 109 RunShellCommand(command.GetData(), FileSpec(), &status, nullptr, nullptr, 110 std::chrono::seconds(10)); 111 if (status != 0) 112 return Status("unable to perform copy"); 113 if (uid == UINT32_MAX && gid == UINT32_MAX) 114 return Status(); 115 if (chown_file(this, dst_path.c_str(), uid, gid) != 0) 116 return Status("unable to perform chown"); 117 return Status(); 118 } else if (m_remote_platform_sp) { 119 if (GetSupportsRSync()) { 120 std::string src_path(source.GetPath()); 121 if (src_path.empty()) 122 return Status("unable to get file path for source"); 123 std::string dst_path(destination.GetPath()); 124 if (dst_path.empty()) 125 return Status("unable to get file path for destination"); 126 StreamString command; 127 if (GetIgnoresRemoteHostname()) { 128 if (!GetRSyncPrefix()) 129 command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 130 dst_path.c_str()); 131 else 132 command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(), 133 GetRSyncPrefix(), dst_path.c_str()); 134 } else 135 command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(), 136 GetHostname(), dst_path.c_str()); 137 LLDB_LOGF(log, "[PutFile] Running command: %s\n", command.GetData()); 138 int retcode; 139 Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr, 140 nullptr, std::chrono::minutes(1)); 141 if (retcode == 0) { 142 // Don't chown a local file for a remote system 143 // if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 144 // return Status("unable to perform chown"); 145 return Status(); 146 } 147 // if we are still here rsync has failed - let's try the slow way before 148 // giving up 149 } 150 } 151 return Platform::PutFile(source, destination, uid, gid); 152 } 153 154 lldb_private::Status PlatformPOSIX::GetFile( 155 const lldb_private::FileSpec &source, // remote file path 156 const lldb_private::FileSpec &destination) // local file path 157 { 158 Log *log = GetLog(LLDBLog::Platform); 159 160 // Check the args, first. 161 std::string src_path(source.GetPath()); 162 if (src_path.empty()) 163 return Status("unable to get file path for source"); 164 std::string dst_path(destination.GetPath()); 165 if (dst_path.empty()) 166 return Status("unable to get file path for destination"); 167 if (IsHost()) { 168 if (source == destination) 169 return Status("local scenario->source and destination are the same file " 170 "path: no operation performed"); 171 // cp src dst 172 StreamString cp_command; 173 cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 174 int status; 175 RunShellCommand(cp_command.GetData(), FileSpec(), &status, nullptr, nullptr, 176 std::chrono::seconds(10)); 177 if (status != 0) 178 return Status("unable to perform copy"); 179 return Status(); 180 } else if (m_remote_platform_sp) { 181 if (GetSupportsRSync()) { 182 StreamString command; 183 if (GetIgnoresRemoteHostname()) { 184 if (!GetRSyncPrefix()) 185 command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 186 dst_path.c_str()); 187 else 188 command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(), 189 src_path.c_str(), dst_path.c_str()); 190 } else 191 command.Printf("rsync %s %s:%s %s", GetRSyncOpts(), 192 m_remote_platform_sp->GetHostname(), src_path.c_str(), 193 dst_path.c_str()); 194 LLDB_LOGF(log, "[GetFile] Running command: %s\n", command.GetData()); 195 int retcode; 196 Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr, 197 nullptr, std::chrono::minutes(1)); 198 if (retcode == 0) 199 return Status(); 200 // If we are here, rsync has failed - let's try the slow way before 201 // giving up 202 } 203 // open src and dst 204 // read/write, read/write, read/write, ... 205 // close src 206 // close dst 207 LLDB_LOGF(log, "[GetFile] Using block by block transfer....\n"); 208 Status error; 209 user_id_t fd_src = OpenFile(source, File::eOpenOptionReadOnly, 210 lldb::eFilePermissionsFileDefault, error); 211 212 if (fd_src == UINT64_MAX) 213 return Status("unable to open source file"); 214 215 uint32_t permissions = 0; 216 error = GetFilePermissions(source, permissions); 217 218 if (permissions == 0) 219 permissions = lldb::eFilePermissionsFileDefault; 220 221 user_id_t fd_dst = FileCache::GetInstance().OpenFile( 222 destination, File::eOpenOptionCanCreate | File::eOpenOptionWriteOnly | 223 File::eOpenOptionTruncate, 224 permissions, error); 225 226 if (fd_dst == UINT64_MAX) { 227 if (error.Success()) 228 error.SetErrorString("unable to open destination file"); 229 } 230 231 if (error.Success()) { 232 lldb::WritableDataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 233 uint64_t offset = 0; 234 error.Clear(); 235 while (error.Success()) { 236 const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(), 237 buffer_sp->GetByteSize(), error); 238 if (error.Fail()) 239 break; 240 if (n_read == 0) 241 break; 242 if (FileCache::GetInstance().WriteFile(fd_dst, offset, 243 buffer_sp->GetBytes(), n_read, 244 error) != n_read) { 245 if (!error.Fail()) 246 error.SetErrorString("unable to write to destination file"); 247 break; 248 } 249 offset += n_read; 250 } 251 } 252 // Ignore the close error of src. 253 if (fd_src != UINT64_MAX) 254 CloseFile(fd_src, error); 255 // And close the dst file descriptot. 256 if (fd_dst != UINT64_MAX && 257 !FileCache::GetInstance().CloseFile(fd_dst, error)) { 258 if (!error.Fail()) 259 error.SetErrorString("unable to close destination file"); 260 } 261 return error; 262 } 263 return Platform::GetFile(source, destination); 264 } 265 266 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() { 267 StreamString stream; 268 if (GetSupportsRSync()) { 269 stream.PutCString("rsync"); 270 if ((GetRSyncOpts() && *GetRSyncOpts()) || 271 (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) { 272 stream.Printf(", options: "); 273 if (GetRSyncOpts() && *GetRSyncOpts()) 274 stream.Printf("'%s' ", GetRSyncOpts()); 275 stream.Printf(", prefix: "); 276 if (GetRSyncPrefix() && *GetRSyncPrefix()) 277 stream.Printf("'%s' ", GetRSyncPrefix()); 278 if (GetIgnoresRemoteHostname()) 279 stream.Printf("ignore remote-hostname "); 280 } 281 } 282 if (GetSupportsSSH()) { 283 stream.PutCString("ssh"); 284 if (GetSSHOpts() && *GetSSHOpts()) 285 stream.Printf(", options: '%s' ", GetSSHOpts()); 286 } 287 if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) 288 stream.Printf("cache dir: %s", GetLocalCacheDirectory()); 289 if (stream.GetSize()) 290 return std::string(stream.GetString()); 291 else 292 return ""; 293 } 294 295 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() { 296 if (IsRemote() && m_remote_platform_sp) 297 return m_remote_platform_sp->GetRemoteUnixSignals(); 298 return Platform::GetRemoteUnixSignals(); 299 } 300 301 Status PlatformPOSIX::ConnectRemote(Args &args) { 302 Status error; 303 if (IsHost()) { 304 error.SetErrorStringWithFormatv( 305 "can't connect to the host platform '{0}', always connected", 306 GetPluginName()); 307 } else { 308 if (!m_remote_platform_sp) 309 m_remote_platform_sp = 310 Platform::Create(ConstString("remote-gdb-server"), error); 311 312 if (m_remote_platform_sp && error.Success()) 313 error = m_remote_platform_sp->ConnectRemote(args); 314 else 315 error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 316 317 if (error.Fail()) 318 m_remote_platform_sp.reset(); 319 } 320 321 if (error.Success() && m_remote_platform_sp) { 322 if (m_option_group_platform_rsync.get() && 323 m_option_group_platform_ssh.get() && 324 m_option_group_platform_caching.get()) { 325 if (m_option_group_platform_rsync->m_rsync) { 326 SetSupportsRSync(true); 327 SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str()); 328 SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str()); 329 SetIgnoresRemoteHostname( 330 m_option_group_platform_rsync->m_ignores_remote_hostname); 331 } 332 if (m_option_group_platform_ssh->m_ssh) { 333 SetSupportsSSH(true); 334 SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str()); 335 } 336 SetLocalCacheDirectory( 337 m_option_group_platform_caching->m_cache_dir.c_str()); 338 } 339 } 340 341 return error; 342 } 343 344 Status PlatformPOSIX::DisconnectRemote() { 345 Status error; 346 347 if (IsHost()) { 348 error.SetErrorStringWithFormatv( 349 "can't disconnect from the host platform '{0}', always connected", 350 GetPluginName()); 351 } else { 352 if (m_remote_platform_sp) 353 error = m_remote_platform_sp->DisconnectRemote(); 354 else 355 error.SetErrorString("the platform is not currently connected"); 356 } 357 return error; 358 } 359 360 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, 361 Debugger &debugger, Target *target, 362 Status &error) { 363 lldb::ProcessSP process_sp; 364 Log *log = GetLog(LLDBLog::Platform); 365 366 if (IsHost()) { 367 if (target == nullptr) { 368 TargetSP new_target_sp; 369 370 error = debugger.GetTargetList().CreateTarget( 371 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 372 target = new_target_sp.get(); 373 LLDB_LOGF(log, "PlatformPOSIX::%s created new target", __FUNCTION__); 374 } else { 375 error.Clear(); 376 LLDB_LOGF(log, "PlatformPOSIX::%s target already existed, setting target", 377 __FUNCTION__); 378 } 379 380 if (target && error.Success()) { 381 if (log) { 382 ModuleSP exe_module_sp = target->GetExecutableModule(); 383 LLDB_LOGF(log, "PlatformPOSIX::%s set selected target to %p %s", 384 __FUNCTION__, (void *)target, 385 exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() 386 : "<null>"); 387 } 388 389 process_sp = 390 target->CreateProcess(attach_info.GetListenerForProcess(debugger), 391 "gdb-remote", nullptr, true); 392 393 if (process_sp) { 394 ListenerSP listener_sp = attach_info.GetHijackListener(); 395 if (listener_sp == nullptr) { 396 listener_sp = 397 Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack"); 398 attach_info.SetHijackListener(listener_sp); 399 } 400 process_sp->HijackProcessEvents(listener_sp); 401 error = process_sp->Attach(attach_info); 402 } 403 } 404 } else { 405 if (m_remote_platform_sp) 406 process_sp = 407 m_remote_platform_sp->Attach(attach_info, debugger, target, error); 408 else 409 error.SetErrorString("the platform is not currently connected"); 410 } 411 return process_sp; 412 } 413 414 lldb::ProcessSP PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, 415 Debugger &debugger, Target &target, 416 Status &error) { 417 Log *log = GetLog(LLDBLog::Platform); 418 LLDB_LOG(log, "target {0}", &target); 419 420 ProcessSP process_sp; 421 422 if (!IsHost()) { 423 if (m_remote_platform_sp) 424 process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, 425 target, error); 426 else 427 error.SetErrorString("the platform is not currently connected"); 428 return process_sp; 429 } 430 431 // 432 // For local debugging, we'll insist on having ProcessGDBRemote create the 433 // process. 434 // 435 436 // Make sure we stop at the entry point 437 launch_info.GetFlags().Set(eLaunchFlagDebug); 438 439 // We always launch the process we are going to debug in a separate process 440 // group, since then we can handle ^C interrupts ourselves w/o having to 441 // worry about the target getting them as well. 442 launch_info.SetLaunchInSeparateProcessGroup(true); 443 444 // Now create the gdb-remote process. 445 LLDB_LOG(log, "having target create process with gdb-remote plugin"); 446 process_sp = target.CreateProcess(launch_info.GetListener(), "gdb-remote", 447 nullptr, true); 448 449 if (!process_sp) { 450 error.SetErrorString("CreateProcess() failed for gdb-remote process"); 451 LLDB_LOG(log, "error: {0}", error); 452 return process_sp; 453 } 454 455 LLDB_LOG(log, "successfully created process"); 456 457 process_sp->HijackProcessEvents(launch_info.GetHijackListener()); 458 459 // Log file actions. 460 if (log) { 461 LLDB_LOG(log, "launching process with the following file actions:"); 462 StreamString stream; 463 size_t i = 0; 464 const FileAction *file_action; 465 while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) { 466 file_action->Dump(stream); 467 LLDB_LOG(log, "{0}", stream.GetData()); 468 stream.Clear(); 469 } 470 } 471 472 // Do the launch. 473 error = process_sp->Launch(launch_info); 474 if (error.Success()) { 475 // Hook up process PTY if we have one (which we should for local debugging 476 // with llgs). 477 int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); 478 if (pty_fd != PseudoTerminal::invalid_fd) { 479 process_sp->SetSTDIOFileDescriptor(pty_fd); 480 LLDB_LOG(log, "hooked up STDIO pty to process"); 481 } else 482 LLDB_LOG(log, "not using process STDIO pty"); 483 } else { 484 LLDB_LOG(log, "{0}", error); 485 // FIXME figure out appropriate cleanup here. Do we delete the process? 486 // Does our caller do that? 487 } 488 489 return process_sp; 490 } 491 492 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() { 493 m_trap_handlers.push_back(ConstString("_sigtramp")); 494 } 495 496 Status PlatformPOSIX::EvaluateLibdlExpression( 497 lldb_private::Process *process, const char *expr_cstr, 498 llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) { 499 DynamicLoader *loader = process->GetDynamicLoader(); 500 if (loader) { 501 Status error = loader->CanLoadImage(); 502 if (error.Fail()) 503 return error; 504 } 505 506 ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread()); 507 if (!thread_sp) 508 return Status("Selected thread isn't valid"); 509 510 StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); 511 if (!frame_sp) 512 return Status("Frame 0 isn't valid"); 513 514 ExecutionContext exe_ctx; 515 frame_sp->CalculateExecutionContext(exe_ctx); 516 EvaluateExpressionOptions expr_options; 517 expr_options.SetUnwindOnError(true); 518 expr_options.SetIgnoreBreakpoints(true); 519 expr_options.SetExecutionPolicy(eExecutionPolicyAlways); 520 expr_options.SetLanguage(eLanguageTypeC_plus_plus); 521 expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 522 // don't do the work to trap them. 523 expr_options.SetTimeout(process->GetUtilityExpressionTimeout()); 524 525 Status expr_error; 526 ExpressionResults result = 527 UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix, 528 result_valobj_sp, expr_error); 529 if (result != eExpressionCompleted) 530 return expr_error; 531 532 if (result_valobj_sp->GetError().Fail()) 533 return result_valobj_sp->GetError(); 534 return Status(); 535 } 536 537 std::unique_ptr<UtilityFunction> 538 PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, 539 Status &error) { 540 // Remember to prepend this with the prefix from 541 // GetLibdlFunctionDeclarations. The returned values are all in 542 // __lldb_dlopen_result for consistency. The wrapper returns a void * but 543 // doesn't use it because UtilityFunctions don't work with void returns at 544 // present. 545 // 546 // Use lazy binding so as to not make dlopen()'s success conditional on 547 // forcing every symbol in the library. 548 // 549 // In general, the debugger should allow programs to load & run with 550 // libraries as far as they can, instead of defaulting to being super-picky 551 // about unavailable symbols. 552 // 553 // The value "1" appears to imply lazy binding (RTLD_LAZY) on both Darwin 554 // and other POSIX OSes. 555 static const char *dlopen_wrapper_code = R"( 556 const int RTLD_LAZY = 1; 557 558 struct __lldb_dlopen_result { 559 void *image_ptr; 560 const char *error_str; 561 }; 562 563 extern "C" void *memcpy(void *, const void *, size_t size); 564 extern "C" size_t strlen(const char *); 565 566 567 void * __lldb_dlopen_wrapper (const char *name, 568 const char *path_strings, 569 char *buffer, 570 __lldb_dlopen_result *result_ptr) 571 { 572 // This is the case where the name is the full path: 573 if (!path_strings) { 574 result_ptr->image_ptr = dlopen(name, RTLD_LAZY); 575 if (result_ptr->image_ptr) 576 result_ptr->error_str = nullptr; 577 else 578 result_ptr->error_str = dlerror(); 579 return nullptr; 580 } 581 582 // This is the case where we have a list of paths: 583 size_t name_len = strlen(name); 584 while (path_strings && path_strings[0] != '\0') { 585 size_t path_len = strlen(path_strings); 586 memcpy((void *) buffer, (void *) path_strings, path_len); 587 buffer[path_len] = '/'; 588 char *target_ptr = buffer+path_len+1; 589 memcpy((void *) target_ptr, (void *) name, name_len + 1); 590 result_ptr->image_ptr = dlopen(buffer, RTLD_LAZY); 591 if (result_ptr->image_ptr) { 592 result_ptr->error_str = nullptr; 593 break; 594 } 595 result_ptr->error_str = dlerror(); 596 path_strings = path_strings + path_len + 1; 597 } 598 return nullptr; 599 } 600 )"; 601 602 static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper"; 603 Process *process = exe_ctx.GetProcessSP().get(); 604 // Insert the dlopen shim defines into our generic expression: 605 std::string expr(std::string(GetLibdlFunctionDeclarations(process))); 606 expr.append(dlopen_wrapper_code); 607 Status utility_error; 608 DiagnosticManager diagnostics; 609 610 auto utility_fn_or_error = process->GetTarget().CreateUtilityFunction( 611 std::move(expr), dlopen_wrapper_name, eLanguageTypeC_plus_plus, exe_ctx); 612 if (!utility_fn_or_error) { 613 std::string error_str = llvm::toString(utility_fn_or_error.takeError()); 614 error.SetErrorStringWithFormat("dlopen error: could not create utility" 615 "function: %s", 616 error_str.c_str()); 617 return nullptr; 618 } 619 std::unique_ptr<UtilityFunction> dlopen_utility_func_up = 620 std::move(*utility_fn_or_error); 621 622 Value value; 623 ValueList arguments; 624 FunctionCaller *do_dlopen_function = nullptr; 625 626 // Fetch the clang types we will need: 627 TypeSystemClang *ast = 628 ScratchTypeSystemClang::GetForTarget(process->GetTarget()); 629 if (!ast) 630 return nullptr; 631 632 CompilerType clang_void_pointer_type 633 = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 634 CompilerType clang_char_pointer_type 635 = ast->GetBasicType(eBasicTypeChar).GetPointerType(); 636 637 // We are passing four arguments, the basename, the list of places to look, 638 // a buffer big enough for all the path + name combos, and 639 // a pointer to the storage we've made for the result: 640 value.SetValueType(Value::ValueType::Scalar); 641 value.SetCompilerType(clang_void_pointer_type); 642 arguments.PushValue(value); 643 value.SetCompilerType(clang_char_pointer_type); 644 arguments.PushValue(value); 645 arguments.PushValue(value); 646 arguments.PushValue(value); 647 648 do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller( 649 clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error); 650 if (utility_error.Fail()) { 651 error.SetErrorStringWithFormat("dlopen error: could not make function" 652 "caller: %s", utility_error.AsCString()); 653 return nullptr; 654 } 655 656 do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller(); 657 if (!do_dlopen_function) { 658 error.SetErrorString("dlopen error: could not get function caller."); 659 return nullptr; 660 } 661 662 // We made a good utility function, so cache it in the process: 663 return dlopen_utility_func_up; 664 } 665 666 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, 667 const lldb_private::FileSpec &remote_file, 668 const std::vector<std::string> *paths, 669 lldb_private::Status &error, 670 lldb_private::FileSpec *loaded_image) { 671 if (loaded_image) 672 loaded_image->Clear(); 673 674 std::string path; 675 path = remote_file.GetPath(); 676 677 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); 678 if (!thread_sp) { 679 error.SetErrorString("dlopen error: no thread available to call dlopen."); 680 return LLDB_INVALID_IMAGE_TOKEN; 681 } 682 683 DiagnosticManager diagnostics; 684 685 ExecutionContext exe_ctx; 686 thread_sp->CalculateExecutionContext(exe_ctx); 687 688 Status utility_error; 689 UtilityFunction *dlopen_utility_func; 690 ValueList arguments; 691 FunctionCaller *do_dlopen_function = nullptr; 692 693 // The UtilityFunction is held in the Process. Platforms don't track the 694 // lifespan of the Targets that use them, we can't put this in the Platform. 695 dlopen_utility_func = process->GetLoadImageUtilityFunction( 696 this, [&]() -> std::unique_ptr<UtilityFunction> { 697 return MakeLoadImageUtilityFunction(exe_ctx, error); 698 }); 699 // If we couldn't make it, the error will be in error, so we can exit here. 700 if (!dlopen_utility_func) 701 return LLDB_INVALID_IMAGE_TOKEN; 702 703 do_dlopen_function = dlopen_utility_func->GetFunctionCaller(); 704 if (!do_dlopen_function) { 705 error.SetErrorString("dlopen error: could not get function caller."); 706 return LLDB_INVALID_IMAGE_TOKEN; 707 } 708 arguments = do_dlopen_function->GetArgumentValues(); 709 710 // Now insert the path we are searching for and the result structure into the 711 // target. 712 uint32_t permissions = ePermissionsReadable|ePermissionsWritable; 713 size_t path_len = path.size() + 1; 714 lldb::addr_t path_addr = process->AllocateMemory(path_len, 715 permissions, 716 utility_error); 717 if (path_addr == LLDB_INVALID_ADDRESS) { 718 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 719 "for path: %s", utility_error.AsCString()); 720 return LLDB_INVALID_IMAGE_TOKEN; 721 } 722 723 // Make sure we deallocate the input string memory: 724 auto path_cleanup = llvm::make_scope_exit([process, path_addr] { 725 // Deallocate the buffer. 726 process->DeallocateMemory(path_addr); 727 }); 728 729 process->WriteMemory(path_addr, path.c_str(), path_len, utility_error); 730 if (utility_error.Fail()) { 731 error.SetErrorStringWithFormat("dlopen error: could not write path string:" 732 " %s", utility_error.AsCString()); 733 return LLDB_INVALID_IMAGE_TOKEN; 734 } 735 736 // Make space for our return structure. It is two pointers big: the token 737 // and the error string. 738 const uint32_t addr_size = process->GetAddressByteSize(); 739 lldb::addr_t return_addr = process->CallocateMemory(2*addr_size, 740 permissions, 741 utility_error); 742 if (utility_error.Fail()) { 743 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 744 "for path: %s", utility_error.AsCString()); 745 return LLDB_INVALID_IMAGE_TOKEN; 746 } 747 748 // Make sure we deallocate the result structure memory 749 auto return_cleanup = llvm::make_scope_exit([process, return_addr] { 750 // Deallocate the buffer 751 process->DeallocateMemory(return_addr); 752 }); 753 754 // This will be the address of the storage for paths, if we are using them, 755 // or nullptr to signal we aren't. 756 lldb::addr_t path_array_addr = 0x0; 757 llvm::Optional<llvm::detail::scope_exit<std::function<void()>>> 758 path_array_cleanup; 759 760 // This is the address to a buffer large enough to hold the largest path 761 // conjoined with the library name we're passing in. This is a convenience 762 // to avoid having to call malloc in the dlopen function. 763 lldb::addr_t buffer_addr = 0x0; 764 llvm::Optional<llvm::detail::scope_exit<std::function<void()>>> 765 buffer_cleanup; 766 767 // Set the values into our args and write them to the target: 768 if (paths != nullptr) { 769 // First insert the paths into the target. This is expected to be a 770 // continuous buffer with the strings laid out null terminated and 771 // end to end with an empty string terminating the buffer. 772 // We also compute the buffer's required size as we go. 773 size_t buffer_size = 0; 774 std::string path_array; 775 for (auto path : *paths) { 776 // Don't insert empty paths, they will make us abort the path 777 // search prematurely. 778 if (path.empty()) 779 continue; 780 size_t path_size = path.size(); 781 path_array.append(path); 782 path_array.push_back('\0'); 783 if (path_size > buffer_size) 784 buffer_size = path_size; 785 } 786 path_array.push_back('\0'); 787 788 path_array_addr = process->AllocateMemory(path_array.size(), 789 permissions, 790 utility_error); 791 if (path_array_addr == LLDB_INVALID_ADDRESS) { 792 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 793 "for path array: %s", 794 utility_error.AsCString()); 795 return LLDB_INVALID_IMAGE_TOKEN; 796 } 797 798 // Make sure we deallocate the paths array. 799 path_array_cleanup.emplace([process, path_array_addr]() { 800 // Deallocate the path array. 801 process->DeallocateMemory(path_array_addr); 802 }); 803 804 process->WriteMemory(path_array_addr, path_array.data(), 805 path_array.size(), utility_error); 806 807 if (utility_error.Fail()) { 808 error.SetErrorStringWithFormat("dlopen error: could not write path array:" 809 " %s", utility_error.AsCString()); 810 return LLDB_INVALID_IMAGE_TOKEN; 811 } 812 // Now make spaces in the target for the buffer. We need to add one for 813 // the '/' that the utility function will insert and one for the '\0': 814 buffer_size += path.size() + 2; 815 816 buffer_addr = process->AllocateMemory(buffer_size, 817 permissions, 818 utility_error); 819 if (buffer_addr == LLDB_INVALID_ADDRESS) { 820 error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 821 "for buffer: %s", 822 utility_error.AsCString()); 823 return LLDB_INVALID_IMAGE_TOKEN; 824 } 825 826 // Make sure we deallocate the buffer memory: 827 buffer_cleanup.emplace([process, buffer_addr]() { 828 // Deallocate the buffer. 829 process->DeallocateMemory(buffer_addr); 830 }); 831 } 832 833 arguments.GetValueAtIndex(0)->GetScalar() = path_addr; 834 arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr; 835 arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr; 836 arguments.GetValueAtIndex(3)->GetScalar() = return_addr; 837 838 lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS; 839 840 diagnostics.Clear(); 841 if (!do_dlopen_function->WriteFunctionArguments(exe_ctx, 842 func_args_addr, 843 arguments, 844 diagnostics)) { 845 error.SetErrorStringWithFormat("dlopen error: could not write function " 846 "arguments: %s", 847 diagnostics.GetString().c_str()); 848 return LLDB_INVALID_IMAGE_TOKEN; 849 } 850 851 // Make sure we clean up the args structure. We can't reuse it because the 852 // Platform lives longer than the process and the Platforms don't get a 853 // signal to clean up cached data when a process goes away. 854 auto args_cleanup = 855 llvm::make_scope_exit([do_dlopen_function, &exe_ctx, func_args_addr] { 856 do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr); 857 }); 858 859 // Now run the caller: 860 EvaluateExpressionOptions options; 861 options.SetExecutionPolicy(eExecutionPolicyAlways); 862 options.SetLanguage(eLanguageTypeC_plus_plus); 863 options.SetIgnoreBreakpoints(true); 864 options.SetUnwindOnError(true); 865 options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 866 // don't do the work to trap them. 867 options.SetTimeout(process->GetUtilityExpressionTimeout()); 868 options.SetIsForUtilityExpr(true); 869 870 Value return_value; 871 // Fetch the clang types we will need: 872 TypeSystemClang *ast = 873 ScratchTypeSystemClang::GetForTarget(process->GetTarget()); 874 if (!ast) { 875 error.SetErrorString("dlopen error: Unable to get TypeSystemClang"); 876 return LLDB_INVALID_IMAGE_TOKEN; 877 } 878 879 CompilerType clang_void_pointer_type 880 = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 881 882 return_value.SetCompilerType(clang_void_pointer_type); 883 884 ExpressionResults results = do_dlopen_function->ExecuteFunction( 885 exe_ctx, &func_args_addr, options, diagnostics, return_value); 886 if (results != eExpressionCompleted) { 887 error.SetErrorStringWithFormat("dlopen error: failed executing " 888 "dlopen wrapper function: %s", 889 diagnostics.GetString().c_str()); 890 return LLDB_INVALID_IMAGE_TOKEN; 891 } 892 893 // Read the dlopen token from the return area: 894 lldb::addr_t token = process->ReadPointerFromMemory(return_addr, 895 utility_error); 896 if (utility_error.Fail()) { 897 error.SetErrorStringWithFormat("dlopen error: could not read the return " 898 "struct: %s", utility_error.AsCString()); 899 return LLDB_INVALID_IMAGE_TOKEN; 900 } 901 902 // The dlopen succeeded! 903 if (token != 0x0) { 904 if (loaded_image && buffer_addr != 0x0) 905 { 906 // Capture the image which was loaded. We leave it in the buffer on 907 // exit from the dlopen function, so we can just read it from there: 908 std::string name_string; 909 process->ReadCStringFromMemory(buffer_addr, name_string, utility_error); 910 if (utility_error.Success()) 911 loaded_image->SetFile(name_string, llvm::sys::path::Style::posix); 912 } 913 return process->AddImageToken(token); 914 } 915 916 // We got an error, lets read in the error string: 917 std::string dlopen_error_str; 918 lldb::addr_t error_addr 919 = process->ReadPointerFromMemory(return_addr + addr_size, utility_error); 920 if (utility_error.Fail()) { 921 error.SetErrorStringWithFormat("dlopen error: could not read error string: " 922 "%s", utility_error.AsCString()); 923 return LLDB_INVALID_IMAGE_TOKEN; 924 } 925 926 size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size, 927 dlopen_error_str, 928 utility_error); 929 if (utility_error.Success() && num_chars > 0) 930 error.SetErrorStringWithFormat("dlopen error: %s", 931 dlopen_error_str.c_str()); 932 else 933 error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); 934 935 return LLDB_INVALID_IMAGE_TOKEN; 936 } 937 938 Status PlatformPOSIX::UnloadImage(lldb_private::Process *process, 939 uint32_t image_token) { 940 const addr_t image_addr = process->GetImagePtrFromToken(image_token); 941 if (image_addr == LLDB_INVALID_ADDRESS) 942 return Status("Invalid image token"); 943 944 StreamString expr; 945 expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr); 946 llvm::StringRef prefix = GetLibdlFunctionDeclarations(process); 947 lldb::ValueObjectSP result_valobj_sp; 948 Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix, 949 result_valobj_sp); 950 if (error.Fail()) 951 return error; 952 953 if (result_valobj_sp->GetError().Fail()) 954 return result_valobj_sp->GetError(); 955 956 Scalar scalar; 957 if (result_valobj_sp->ResolveValue(scalar)) { 958 if (scalar.UInt(1)) 959 return Status("expression failed: \"%s\"", expr.GetData()); 960 process->ResetImageToken(image_token); 961 } 962 return Status(); 963 } 964 965 llvm::StringRef 966 PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) { 967 return R"( 968 extern "C" void* dlopen(const char*, int); 969 extern "C" void* dlsym(void*, const char*); 970 extern "C" int dlclose(void*); 971 extern "C" char* dlerror(void); 972 )"; 973 } 974 975 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) { 976 if (basename.IsEmpty()) 977 return basename; 978 979 StreamString stream; 980 stream.Printf("lib%s.so", basename.GetCString()); 981 return ConstString(stream.GetString()); 982 } 983