1257752Semaste//===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===// 2257752Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6257752Semaste// 7257752Semaste//===----------------------------------------------------------------------===// 8257752Semaste 9257752Semaste#include "PlatformPOSIX.h" 10257752Semaste 11280031Sdim#include "lldb/Core/Debugger.h" 12280031Sdim#include "lldb/Core/Module.h" 13321369Sdim#include "lldb/Core/ModuleSpec.h" 14296417Sdim#include "lldb/Core/ValueObject.h" 15341825Sdim#include "lldb/Expression/DiagnosticManager.h" 16341825Sdim#include "lldb/Expression/FunctionCaller.h" 17296417Sdim#include "lldb/Expression/UserExpression.h" 18341825Sdim#include "lldb/Expression/UtilityFunction.h" 19257752Semaste#include "lldb/Host/File.h" 20276479Sdim#include "lldb/Host/FileCache.h" 21276479Sdim#include "lldb/Host/FileSystem.h" 22257752Semaste#include "lldb/Host/Host.h" 23321369Sdim#include "lldb/Host/HostInfo.h" 24353358Sdim#include "lldb/Host/ProcessLaunchInfo.h" 25341825Sdim#include "lldb/Symbol/ClangASTContext.h" 26296417Sdim#include "lldb/Target/DynamicLoader.h" 27296417Sdim#include "lldb/Target/ExecutionContext.h" 28288943Sdim#include "lldb/Target/Process.h" 29296417Sdim#include "lldb/Target/Thread.h" 30321369Sdim#include "lldb/Utility/DataBufferHeap.h" 31321369Sdim#include "lldb/Utility/FileSpec.h" 32321369Sdim#include "lldb/Utility/Log.h" 33321369Sdim#include "lldb/Utility/StreamString.h" 34360784Sdim#include "llvm/ADT/ScopeExit.h" 35257752Semaste 36257752Semasteusing namespace lldb; 37257752Semasteusing namespace lldb_private; 38257752Semaste 39257752Semaste/// Default Constructor 40314564SdimPlatformPOSIX::PlatformPOSIX(bool is_host) 41353358Sdim : RemoteAwarePlatform(is_host), // This is the local host platform 42314564Sdim m_option_group_platform_rsync(new OptionGroupPlatformRSync()), 43314564Sdim m_option_group_platform_ssh(new OptionGroupPlatformSSH()), 44353358Sdim m_option_group_platform_caching(new OptionGroupPlatformCaching()) {} 45257752Semaste 46257752Semaste/// Destructor. 47257752Semaste/// 48257752Semaste/// The destructor is virtual since this class is designed to be 49257752Semaste/// inherited from by the plug-in instance. 50314564SdimPlatformPOSIX::~PlatformPOSIX() {} 51257752Semaste 52314564Sdimlldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions( 53314564Sdim lldb_private::CommandInterpreter &interpreter) { 54314564Sdim auto iter = m_options.find(&interpreter), end = m_options.end(); 55314564Sdim if (iter == end) { 56314564Sdim std::unique_ptr<lldb_private::OptionGroupOptions> options( 57314564Sdim new OptionGroupOptions()); 58314564Sdim options->Append(m_option_group_platform_rsync.get()); 59314564Sdim options->Append(m_option_group_platform_ssh.get()); 60314564Sdim options->Append(m_option_group_platform_caching.get()); 61314564Sdim m_options[&interpreter] = std::move(options); 62314564Sdim } 63257752Semaste 64314564Sdim return m_options.at(&interpreter).get(); 65276479Sdim} 66276479Sdim 67321369SdimStatus 68321369SdimPlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, 69321369Sdim lldb::ModuleSP &exe_module_sp, 70321369Sdim const FileSpecList *module_search_paths_ptr) { 71321369Sdim Status error; 72321369Sdim // Nothing special to do here, just use the actual file and architecture 73321369Sdim 74321369Sdim char exe_path[PATH_MAX]; 75321369Sdim ModuleSpec resolved_module_spec(module_spec); 76321369Sdim 77321369Sdim if (IsHost()) { 78341825Sdim // If we have "ls" as the exe_file, resolve the executable location based 79341825Sdim // on the current path variables 80344779Sdim if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { 81321369Sdim resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); 82344779Sdim resolved_module_spec.GetFileSpec().SetFile(exe_path, 83341825Sdim FileSpec::Style::native); 84344779Sdim FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); 85321369Sdim } 86321369Sdim 87344779Sdim if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 88344779Sdim FileSystem::Instance().ResolveExecutableLocation( 89344779Sdim resolved_module_spec.GetFileSpec()); 90321369Sdim 91321369Sdim // Resolve any executable within a bundle on MacOSX 92321369Sdim Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 93321369Sdim 94344779Sdim if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 95321369Sdim error.Clear(); 96321369Sdim else { 97344779Sdim const uint32_t permissions = FileSystem::Instance().GetPermissions( 98344779Sdim resolved_module_spec.GetFileSpec()); 99321369Sdim if (permissions && (permissions & eFilePermissionsEveryoneR) == 0) 100321369Sdim error.SetErrorStringWithFormat( 101321369Sdim "executable '%s' is not readable", 102321369Sdim resolved_module_spec.GetFileSpec().GetPath().c_str()); 103321369Sdim else 104321369Sdim error.SetErrorStringWithFormat( 105321369Sdim "unable to find executable for '%s'", 106321369Sdim resolved_module_spec.GetFileSpec().GetPath().c_str()); 107321369Sdim } 108321369Sdim } else { 109321369Sdim if (m_remote_platform_sp) { 110321369Sdim error = 111321369Sdim GetCachedExecutable(resolved_module_spec, exe_module_sp, 112321369Sdim module_search_paths_ptr, *m_remote_platform_sp); 113321369Sdim } else { 114321369Sdim // We may connect to a process and use the provided executable (Don't use 115321369Sdim // local $PATH). 116321369Sdim 117321369Sdim // Resolve any executable within a bundle on MacOSX 118321369Sdim Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 119321369Sdim 120344779Sdim if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) 121321369Sdim error.Clear(); 122321369Sdim else 123321369Sdim error.SetErrorStringWithFormat("the platform is not currently " 124321369Sdim "connected, and '%s' doesn't exist in " 125321369Sdim "the system root.", 126321369Sdim exe_path); 127321369Sdim } 128321369Sdim } 129321369Sdim 130321369Sdim if (error.Success()) { 131321369Sdim if (resolved_module_spec.GetArchitecture().IsValid()) { 132321369Sdim error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 133321369Sdim module_search_paths_ptr, nullptr, nullptr); 134321369Sdim if (error.Fail()) { 135321369Sdim // If we failed, it may be because the vendor and os aren't known. If 136321369Sdim // that is the case, try setting them to the host architecture and give 137321369Sdim // it another try. 138321369Sdim llvm::Triple &module_triple = 139321369Sdim resolved_module_spec.GetArchitecture().GetTriple(); 140321369Sdim bool is_vendor_specified = 141321369Sdim (module_triple.getVendor() != llvm::Triple::UnknownVendor); 142321369Sdim bool is_os_specified = 143321369Sdim (module_triple.getOS() != llvm::Triple::UnknownOS); 144321369Sdim if (!is_vendor_specified || !is_os_specified) { 145321369Sdim const llvm::Triple &host_triple = 146321369Sdim HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple(); 147321369Sdim 148321369Sdim if (!is_vendor_specified) 149321369Sdim module_triple.setVendorName(host_triple.getVendorName()); 150321369Sdim if (!is_os_specified) 151321369Sdim module_triple.setOSName(host_triple.getOSName()); 152321369Sdim 153321369Sdim error = ModuleList::GetSharedModule(resolved_module_spec, 154321369Sdim exe_module_sp, module_search_paths_ptr, nullptr, nullptr); 155321369Sdim } 156321369Sdim } 157321369Sdim 158321369Sdim // TODO find out why exe_module_sp might be NULL 159321369Sdim if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) { 160321369Sdim exe_module_sp.reset(); 161321369Sdim error.SetErrorStringWithFormat( 162321369Sdim "'%s' doesn't contain the architecture %s", 163321369Sdim resolved_module_spec.GetFileSpec().GetPath().c_str(), 164321369Sdim resolved_module_spec.GetArchitecture().GetArchitectureName()); 165321369Sdim } 166321369Sdim } else { 167341825Sdim // No valid architecture was specified, ask the platform for the 168341825Sdim // architectures that we should be using (in the correct order) and see 169341825Sdim // if we can find a match that way 170321369Sdim StreamString arch_names; 171321369Sdim for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( 172321369Sdim idx, resolved_module_spec.GetArchitecture()); 173321369Sdim ++idx) { 174321369Sdim error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 175321369Sdim module_search_paths_ptr, nullptr, nullptr); 176321369Sdim // Did we find an executable using one of the 177321369Sdim if (error.Success()) { 178321369Sdim if (exe_module_sp && exe_module_sp->GetObjectFile()) 179321369Sdim break; 180321369Sdim else 181321369Sdim error.SetErrorToGenericError(); 182321369Sdim } 183321369Sdim 184321369Sdim if (idx > 0) 185321369Sdim arch_names.PutCString(", "); 186321369Sdim arch_names.PutCString( 187321369Sdim resolved_module_spec.GetArchitecture().GetArchitectureName()); 188321369Sdim } 189321369Sdim 190321369Sdim if (error.Fail() || !exe_module_sp) { 191344779Sdim if (FileSystem::Instance().Readable( 192344779Sdim resolved_module_spec.GetFileSpec())) { 193321369Sdim error.SetErrorStringWithFormat( 194321369Sdim "'%s' doesn't contain any '%s' platform architectures: %s", 195321369Sdim resolved_module_spec.GetFileSpec().GetPath().c_str(), 196321369Sdim GetPluginName().GetCString(), arch_names.GetData()); 197321369Sdim } else { 198321369Sdim error.SetErrorStringWithFormat( 199321369Sdim "'%s' is not readable", 200321369Sdim resolved_module_spec.GetFileSpec().GetPath().c_str()); 201321369Sdim } 202321369Sdim } 203321369Sdim } 204321369Sdim } 205321369Sdim 206321369Sdim return error; 207321369Sdim} 208321369Sdim 209314564Sdimstatic uint32_t chown_file(Platform *platform, const char *path, 210314564Sdim uint32_t uid = UINT32_MAX, 211314564Sdim uint32_t gid = UINT32_MAX) { 212314564Sdim if (!platform || !path || *path == 0) 213314564Sdim return UINT32_MAX; 214314564Sdim 215314564Sdim if (uid == UINT32_MAX && gid == UINT32_MAX) 216314564Sdim return 0; // pretend I did chown correctly - actually I just didn't care 217314564Sdim 218314564Sdim StreamString command; 219314564Sdim command.PutCString("chown "); 220314564Sdim if (uid != UINT32_MAX) 221314564Sdim command.Printf("%d", uid); 222314564Sdim if (gid != UINT32_MAX) 223314564Sdim command.Printf(":%d", gid); 224314564Sdim command.Printf("%s", path); 225314564Sdim int status; 226360784Sdim platform->RunShellCommand(command.GetData(), FileSpec(), &status, nullptr, 227353358Sdim nullptr, std::chrono::seconds(10)); 228314564Sdim return status; 229314564Sdim} 230314564Sdim 231321369Sdimlldb_private::Status 232314564SdimPlatformPOSIX::PutFile(const lldb_private::FileSpec &source, 233314564Sdim const lldb_private::FileSpec &destination, uint32_t uid, 234314564Sdim uint32_t gid) { 235314564Sdim Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 236258884Semaste 237314564Sdim if (IsHost()) { 238360784Sdim if (source == destination) 239321369Sdim return Status(); 240314564Sdim // cp src dst 241314564Sdim // chown uid:gid dst 242314564Sdim std::string src_path(source.GetPath()); 243314564Sdim if (src_path.empty()) 244321369Sdim return Status("unable to get file path for source"); 245314564Sdim std::string dst_path(destination.GetPath()); 246314564Sdim if (dst_path.empty()) 247321369Sdim return Status("unable to get file path for destination"); 248314564Sdim StreamString command; 249314564Sdim command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 250314564Sdim int status; 251360784Sdim RunShellCommand(command.GetData(), FileSpec(), &status, nullptr, nullptr, 252341825Sdim std::chrono::seconds(10)); 253314564Sdim if (status != 0) 254321369Sdim return Status("unable to perform copy"); 255314564Sdim if (uid == UINT32_MAX && gid == UINT32_MAX) 256321369Sdim return Status(); 257314564Sdim if (chown_file(this, dst_path.c_str(), uid, gid) != 0) 258321369Sdim return Status("unable to perform chown"); 259321369Sdim return Status(); 260314564Sdim } else if (m_remote_platform_sp) { 261314564Sdim if (GetSupportsRSync()) { 262314564Sdim std::string src_path(source.GetPath()); 263314564Sdim if (src_path.empty()) 264321369Sdim return Status("unable to get file path for source"); 265314564Sdim std::string dst_path(destination.GetPath()); 266314564Sdim if (dst_path.empty()) 267321369Sdim return Status("unable to get file path for destination"); 268314564Sdim StreamString command; 269314564Sdim if (GetIgnoresRemoteHostname()) { 270314564Sdim if (!GetRSyncPrefix()) 271314564Sdim command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 272314564Sdim dst_path.c_str()); 273314564Sdim else 274314564Sdim command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(), 275314564Sdim GetRSyncPrefix(), dst_path.c_str()); 276314564Sdim } else 277314564Sdim command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(), 278314564Sdim GetHostname(), dst_path.c_str()); 279360784Sdim LLDB_LOGF(log, "[PutFile] Running command: %s\n", command.GetData()); 280314564Sdim int retcode; 281360784Sdim Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr, 282353358Sdim nullptr, std::chrono::minutes(1)); 283314564Sdim if (retcode == 0) { 284314564Sdim // Don't chown a local file for a remote system 285314564Sdim // if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 286321369Sdim // return Status("unable to perform chown"); 287321369Sdim return Status(); 288314564Sdim } 289314564Sdim // if we are still here rsync has failed - let's try the slow way before 290314564Sdim // giving up 291257752Semaste } 292314564Sdim } 293314564Sdim return Platform::PutFile(source, destination, uid, gid); 294257752Semaste} 295257752Semaste 296321369Sdimlldb_private::Status PlatformPOSIX::GetFile( 297314564Sdim const lldb_private::FileSpec &source, // remote file path 298314564Sdim const lldb_private::FileSpec &destination) // local file path 299257752Semaste{ 300314564Sdim Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 301258884Semaste 302314564Sdim // Check the args, first. 303314564Sdim std::string src_path(source.GetPath()); 304314564Sdim if (src_path.empty()) 305321369Sdim return Status("unable to get file path for source"); 306314564Sdim std::string dst_path(destination.GetPath()); 307314564Sdim if (dst_path.empty()) 308321369Sdim return Status("unable to get file path for destination"); 309314564Sdim if (IsHost()) { 310360784Sdim if (source == destination) 311321369Sdim return Status("local scenario->source and destination are the same file " 312321369Sdim "path: no operation performed"); 313314564Sdim // cp src dst 314314564Sdim StreamString cp_command; 315314564Sdim cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 316314564Sdim int status; 317360784Sdim RunShellCommand(cp_command.GetData(), FileSpec(), &status, nullptr, nullptr, 318341825Sdim std::chrono::seconds(10)); 319314564Sdim if (status != 0) 320321369Sdim return Status("unable to perform copy"); 321321369Sdim return Status(); 322314564Sdim } else if (m_remote_platform_sp) { 323314564Sdim if (GetSupportsRSync()) { 324314564Sdim StreamString command; 325314564Sdim if (GetIgnoresRemoteHostname()) { 326314564Sdim if (!GetRSyncPrefix()) 327314564Sdim command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), 328314564Sdim dst_path.c_str()); 329314564Sdim else 330314564Sdim command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(), 331314564Sdim src_path.c_str(), dst_path.c_str()); 332314564Sdim } else 333314564Sdim command.Printf("rsync %s %s:%s %s", GetRSyncOpts(), 334314564Sdim m_remote_platform_sp->GetHostname(), src_path.c_str(), 335314564Sdim dst_path.c_str()); 336360784Sdim LLDB_LOGF(log, "[GetFile] Running command: %s\n", command.GetData()); 337314564Sdim int retcode; 338360784Sdim Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr, 339353358Sdim nullptr, std::chrono::minutes(1)); 340314564Sdim if (retcode == 0) 341321369Sdim return Status(); 342341825Sdim // If we are here, rsync has failed - let's try the slow way before 343341825Sdim // giving up 344257752Semaste } 345314564Sdim // open src and dst 346314564Sdim // read/write, read/write, read/write, ... 347314564Sdim // close src 348314564Sdim // close dst 349360784Sdim LLDB_LOGF(log, "[GetFile] Using block by block transfer....\n"); 350321369Sdim Status error; 351314564Sdim user_id_t fd_src = OpenFile(source, File::eOpenOptionRead, 352314564Sdim lldb::eFilePermissionsFileDefault, error); 353257752Semaste 354314564Sdim if (fd_src == UINT64_MAX) 355321369Sdim return Status("unable to open source file"); 356257752Semaste 357314564Sdim uint32_t permissions = 0; 358314564Sdim error = GetFilePermissions(source, permissions); 359288943Sdim 360314564Sdim if (permissions == 0) 361314564Sdim permissions = lldb::eFilePermissionsFileDefault; 362257752Semaste 363314564Sdim user_id_t fd_dst = FileCache::GetInstance().OpenFile( 364314564Sdim destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | 365314564Sdim File::eOpenOptionTruncate, 366314564Sdim permissions, error); 367257752Semaste 368314564Sdim if (fd_dst == UINT64_MAX) { 369314564Sdim if (error.Success()) 370314564Sdim error.SetErrorString("unable to open destination file"); 371314564Sdim } 372257752Semaste 373314564Sdim if (error.Success()) { 374314564Sdim lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 375314564Sdim uint64_t offset = 0; 376314564Sdim error.Clear(); 377314564Sdim while (error.Success()) { 378314564Sdim const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(), 379314564Sdim buffer_sp->GetByteSize(), error); 380314564Sdim if (error.Fail()) 381314564Sdim break; 382314564Sdim if (n_read == 0) 383314564Sdim break; 384314564Sdim if (FileCache::GetInstance().WriteFile(fd_dst, offset, 385314564Sdim buffer_sp->GetBytes(), n_read, 386314564Sdim error) != n_read) { 387314564Sdim if (!error.Fail()) 388314564Sdim error.SetErrorString("unable to write to destination file"); 389314564Sdim break; 390257752Semaste } 391314564Sdim offset += n_read; 392314564Sdim } 393257752Semaste } 394314564Sdim // Ignore the close error of src. 395314564Sdim if (fd_src != UINT64_MAX) 396314564Sdim CloseFile(fd_src, error); 397314564Sdim // And close the dst file descriptot. 398314564Sdim if (fd_dst != UINT64_MAX && 399314564Sdim !FileCache::GetInstance().CloseFile(fd_dst, error)) { 400314564Sdim if (!error.Fail()) 401314564Sdim error.SetErrorString("unable to close destination file"); 402314564Sdim } 403314564Sdim return error; 404314564Sdim } 405314564Sdim return Platform::GetFile(source, destination); 406257752Semaste} 407257752Semaste 408314564Sdimstd::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() { 409314564Sdim StreamString stream; 410314564Sdim if (GetSupportsRSync()) { 411314564Sdim stream.PutCString("rsync"); 412314564Sdim if ((GetRSyncOpts() && *GetRSyncOpts()) || 413314564Sdim (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) { 414314564Sdim stream.Printf(", options: "); 415314564Sdim if (GetRSyncOpts() && *GetRSyncOpts()) 416314564Sdim stream.Printf("'%s' ", GetRSyncOpts()); 417314564Sdim stream.Printf(", prefix: "); 418314564Sdim if (GetRSyncPrefix() && *GetRSyncPrefix()) 419314564Sdim stream.Printf("'%s' ", GetRSyncPrefix()); 420314564Sdim if (GetIgnoresRemoteHostname()) 421314564Sdim stream.Printf("ignore remote-hostname "); 422257752Semaste } 423314564Sdim } 424314564Sdim if (GetSupportsSSH()) { 425314564Sdim stream.PutCString("ssh"); 426314564Sdim if (GetSSHOpts() && *GetSSHOpts()) 427314564Sdim stream.Printf(", options: '%s' ", GetSSHOpts()); 428314564Sdim } 429314564Sdim if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) 430314564Sdim stream.Printf("cache dir: %s", GetLocalCacheDirectory()); 431314564Sdim if (stream.GetSize()) 432314564Sdim return stream.GetString(); 433314564Sdim else 434314564Sdim return ""; 435257752Semaste} 436257752Semaste 437314564Sdimconst lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() { 438314564Sdim if (IsRemote() && m_remote_platform_sp) 439314564Sdim return m_remote_platform_sp->GetRemoteUnixSignals(); 440314564Sdim return Platform::GetRemoteUnixSignals(); 441288943Sdim} 442288943Sdim 443321369SdimStatus PlatformPOSIX::ConnectRemote(Args &args) { 444321369Sdim Status error; 445314564Sdim if (IsHost()) { 446314564Sdim error.SetErrorStringWithFormat( 447314564Sdim "can't connect to the host platform '%s', always connected", 448314564Sdim GetPluginName().GetCString()); 449314564Sdim } else { 450314564Sdim if (!m_remote_platform_sp) 451314564Sdim m_remote_platform_sp = 452314564Sdim Platform::Create(ConstString("remote-gdb-server"), error); 453314564Sdim 454314564Sdim if (m_remote_platform_sp && error.Success()) 455314564Sdim error = m_remote_platform_sp->ConnectRemote(args); 456276479Sdim else 457314564Sdim error.SetErrorString("failed to create a 'remote-gdb-server' platform"); 458276479Sdim 459314564Sdim if (error.Fail()) 460314564Sdim m_remote_platform_sp.reset(); 461314564Sdim } 462276479Sdim 463314564Sdim if (error.Success() && m_remote_platform_sp) { 464314564Sdim if (m_option_group_platform_rsync.get() && 465314564Sdim m_option_group_platform_ssh.get() && 466314564Sdim m_option_group_platform_caching.get()) { 467314564Sdim if (m_option_group_platform_rsync->m_rsync) { 468314564Sdim SetSupportsRSync(true); 469314564Sdim SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str()); 470314564Sdim SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str()); 471314564Sdim SetIgnoresRemoteHostname( 472314564Sdim m_option_group_platform_rsync->m_ignores_remote_hostname); 473314564Sdim } 474314564Sdim if (m_option_group_platform_ssh->m_ssh) { 475314564Sdim SetSupportsSSH(true); 476314564Sdim SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str()); 477314564Sdim } 478314564Sdim SetLocalCacheDirectory( 479314564Sdim m_option_group_platform_caching->m_cache_dir.c_str()); 480276479Sdim } 481314564Sdim } 482276479Sdim 483314564Sdim return error; 484276479Sdim} 485276479Sdim 486321369SdimStatus PlatformPOSIX::DisconnectRemote() { 487321369Sdim Status error; 488276479Sdim 489314564Sdim if (IsHost()) { 490314564Sdim error.SetErrorStringWithFormat( 491314564Sdim "can't disconnect from the host platform '%s', always connected", 492314564Sdim GetPluginName().GetCString()); 493314564Sdim } else { 494314564Sdim if (m_remote_platform_sp) 495314564Sdim error = m_remote_platform_sp->DisconnectRemote(); 496276479Sdim else 497314564Sdim error.SetErrorString("the platform is not currently connected"); 498314564Sdim } 499314564Sdim return error; 500276479Sdim} 501276479Sdim 502314564Sdimlldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, 503314564Sdim Debugger &debugger, Target *target, 504321369Sdim Status &error) { 505314564Sdim lldb::ProcessSP process_sp; 506314564Sdim Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 507280031Sdim 508314564Sdim if (IsHost()) { 509353358Sdim if (target == nullptr) { 510314564Sdim TargetSP new_target_sp; 511280031Sdim 512344779Sdim error = debugger.GetTargetList().CreateTarget( 513353358Sdim debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 514314564Sdim target = new_target_sp.get(); 515360784Sdim LLDB_LOGF(log, "PlatformPOSIX::%s created new target", __FUNCTION__); 516314564Sdim } else { 517314564Sdim error.Clear(); 518360784Sdim LLDB_LOGF(log, "PlatformPOSIX::%s target already existed, setting target", 519360784Sdim __FUNCTION__); 520314564Sdim } 521280031Sdim 522314564Sdim if (target && error.Success()) { 523314564Sdim debugger.GetTargetList().SetSelectedTarget(target); 524314564Sdim if (log) { 525314564Sdim ModuleSP exe_module_sp = target->GetExecutableModule(); 526360784Sdim LLDB_LOGF(log, "PlatformPOSIX::%s set selected target to %p %s", 527360784Sdim __FUNCTION__, (void *)target, 528360784Sdim exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() 529360784Sdim : "<null>"); 530314564Sdim } 531280031Sdim 532314564Sdim process_sp = 533314564Sdim target->CreateProcess(attach_info.GetListenerForProcess(debugger), 534353358Sdim attach_info.GetProcessPluginName(), nullptr); 535280031Sdim 536314564Sdim if (process_sp) { 537314564Sdim ListenerSP listener_sp = attach_info.GetHijackListener(); 538314564Sdim if (listener_sp == nullptr) { 539314564Sdim listener_sp = 540314564Sdim Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack"); 541314564Sdim attach_info.SetHijackListener(listener_sp); 542280031Sdim } 543314564Sdim process_sp->HijackProcessEvents(listener_sp); 544314564Sdim error = process_sp->Attach(attach_info); 545314564Sdim } 546280031Sdim } 547314564Sdim } else { 548314564Sdim if (m_remote_platform_sp) 549314564Sdim process_sp = 550314564Sdim m_remote_platform_sp->Attach(attach_info, debugger, target, error); 551280031Sdim else 552314564Sdim error.SetErrorString("the platform is not currently connected"); 553314564Sdim } 554314564Sdim return process_sp; 555280031Sdim} 556280031Sdim 557280031Sdimlldb::ProcessSP 558314564SdimPlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, 559314564Sdim Target *target, // Can be NULL, if NULL create a new 560314564Sdim // target, else use existing one 561321369Sdim Status &error) { 562314564Sdim ProcessSP process_sp; 563276479Sdim 564314564Sdim if (IsHost()) { 565314564Sdim // We are going to hand this process off to debugserver which will be in 566341825Sdim // charge of setting the exit status. However, we still need to reap it 567341825Sdim // from lldb. So, make sure we use a exit callback which does not set exit 568341825Sdim // status. 569341825Sdim const bool monitor_signals = false; 570341825Sdim launch_info.SetMonitorProcessCallback( 571341825Sdim &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals); 572314564Sdim process_sp = Platform::DebugProcess(launch_info, debugger, target, error); 573314564Sdim } else { 574314564Sdim if (m_remote_platform_sp) 575314564Sdim process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, 576314564Sdim target, error); 577276479Sdim else 578314564Sdim error.SetErrorString("the platform is not currently connected"); 579314564Sdim } 580314564Sdim return process_sp; 581276479Sdim} 582276479Sdim 583314564Sdimvoid PlatformPOSIX::CalculateTrapHandlerSymbolNames() { 584314564Sdim m_trap_handlers.push_back(ConstString("_sigtramp")); 585296417Sdim} 586296417Sdim 587321369SdimStatus PlatformPOSIX::EvaluateLibdlExpression( 588314564Sdim lldb_private::Process *process, const char *expr_cstr, 589321369Sdim llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) { 590314564Sdim DynamicLoader *loader = process->GetDynamicLoader(); 591314564Sdim if (loader) { 592321369Sdim Status error = loader->CanLoadImage(); 593314564Sdim if (error.Fail()) 594314564Sdim return error; 595314564Sdim } 596296417Sdim 597314564Sdim ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread()); 598314564Sdim if (!thread_sp) 599321369Sdim return Status("Selected thread isn't valid"); 600296417Sdim 601314564Sdim StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); 602314564Sdim if (!frame_sp) 603321369Sdim return Status("Frame 0 isn't valid"); 604296417Sdim 605314564Sdim ExecutionContext exe_ctx; 606314564Sdim frame_sp->CalculateExecutionContext(exe_ctx); 607314564Sdim EvaluateExpressionOptions expr_options; 608314564Sdim expr_options.SetUnwindOnError(true); 609314564Sdim expr_options.SetIgnoreBreakpoints(true); 610314564Sdim expr_options.SetExecutionPolicy(eExecutionPolicyAlways); 611314564Sdim expr_options.SetLanguage(eLanguageTypeC_plus_plus); 612314564Sdim expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 613314564Sdim // don't do the work to trap them. 614353358Sdim expr_options.SetTimeout(process->GetUtilityExpressionTimeout()); 615296417Sdim 616321369Sdim Status expr_error; 617314564Sdim ExpressionResults result = 618314564Sdim UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix, 619314564Sdim result_valobj_sp, expr_error); 620314564Sdim if (result != eExpressionCompleted) 621314564Sdim return expr_error; 622314564Sdim 623314564Sdim if (result_valobj_sp->GetError().Fail()) 624314564Sdim return result_valobj_sp->GetError(); 625321369Sdim return Status(); 626296417Sdim} 627296417Sdim 628341825Sdimstd::unique_ptr<UtilityFunction> 629341825SdimPlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, 630341825Sdim Status &error) { 631341825Sdim // Remember to prepend this with the prefix from 632341825Sdim // GetLibdlFunctionDeclarations. The returned values are all in 633341825Sdim // __lldb_dlopen_result for consistency. The wrapper returns a void * but 634341825Sdim // doesn't use it because UtilityFunctions don't work with void returns at 635341825Sdim // present. 636341825Sdim static const char *dlopen_wrapper_code = R"( 637341825Sdim struct __lldb_dlopen_result { 638341825Sdim void *image_ptr; 639341825Sdim const char *error_str; 640341825Sdim }; 641341825Sdim 642341825Sdim extern void *memcpy(void *, const void *, size_t size); 643341825Sdim extern size_t strlen(const char *); 644341825Sdim 645341825Sdim 646341825Sdim void * __lldb_dlopen_wrapper (const char *name, 647341825Sdim const char *path_strings, 648341825Sdim char *buffer, 649341825Sdim __lldb_dlopen_result *result_ptr) 650341825Sdim { 651341825Sdim // This is the case where the name is the full path: 652341825Sdim if (!path_strings) { 653341825Sdim result_ptr->image_ptr = dlopen(name, 2); 654341825Sdim if (result_ptr->image_ptr) 655341825Sdim result_ptr->error_str = nullptr; 656341825Sdim return nullptr; 657341825Sdim } 658341825Sdim 659341825Sdim // This is the case where we have a list of paths: 660341825Sdim size_t name_len = strlen(name); 661341825Sdim while (path_strings && path_strings[0] != '\0') { 662341825Sdim size_t path_len = strlen(path_strings); 663341825Sdim memcpy((void *) buffer, (void *) path_strings, path_len); 664341825Sdim buffer[path_len] = '/'; 665341825Sdim char *target_ptr = buffer+path_len+1; 666341825Sdim memcpy((void *) target_ptr, (void *) name, name_len + 1); 667341825Sdim result_ptr->image_ptr = dlopen(buffer, 2); 668341825Sdim if (result_ptr->image_ptr) { 669341825Sdim result_ptr->error_str = nullptr; 670341825Sdim break; 671341825Sdim } 672341825Sdim result_ptr->error_str = dlerror(); 673341825Sdim path_strings = path_strings + path_len + 1; 674341825Sdim } 675341825Sdim return nullptr; 676341825Sdim } 677341825Sdim )"; 678341825Sdim 679341825Sdim static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper"; 680341825Sdim Process *process = exe_ctx.GetProcessSP().get(); 681341825Sdim // Insert the dlopen shim defines into our generic expression: 682341825Sdim std::string expr(GetLibdlFunctionDeclarations(process)); 683341825Sdim expr.append(dlopen_wrapper_code); 684341825Sdim Status utility_error; 685341825Sdim DiagnosticManager diagnostics; 686341825Sdim 687341825Sdim std::unique_ptr<UtilityFunction> dlopen_utility_func_up(process 688341825Sdim ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(), 689341825Sdim eLanguageTypeObjC, 690341825Sdim dlopen_wrapper_name, 691341825Sdim utility_error)); 692341825Sdim if (utility_error.Fail()) { 693341825Sdim error.SetErrorStringWithFormat("dlopen error: could not make utility" 694341825Sdim "function: %s", utility_error.AsCString()); 695341825Sdim return nullptr; 696341825Sdim } 697341825Sdim if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) { 698341825Sdim error.SetErrorStringWithFormat("dlopen error: could not install utility" 699341825Sdim "function: %s", 700341825Sdim diagnostics.GetString().c_str()); 701341825Sdim return nullptr; 702341825Sdim } 703341825Sdim 704341825Sdim Value value; 705341825Sdim ValueList arguments; 706341825Sdim FunctionCaller *do_dlopen_function = nullptr; 707341825Sdim 708341825Sdim // Fetch the clang types we will need: 709360784Sdim ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); 710360784Sdim if (!ast) 711360784Sdim return nullptr; 712341825Sdim 713341825Sdim CompilerType clang_void_pointer_type 714341825Sdim = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 715341825Sdim CompilerType clang_char_pointer_type 716341825Sdim = ast->GetBasicType(eBasicTypeChar).GetPointerType(); 717341825Sdim 718341825Sdim // We are passing four arguments, the basename, the list of places to look, 719341825Sdim // a buffer big enough for all the path + name combos, and 720341825Sdim // a pointer to the storage we've made for the result: 721341825Sdim value.SetValueType(Value::eValueTypeScalar); 722341825Sdim value.SetCompilerType(clang_void_pointer_type); 723341825Sdim arguments.PushValue(value); 724341825Sdim value.SetCompilerType(clang_char_pointer_type); 725341825Sdim arguments.PushValue(value); 726341825Sdim arguments.PushValue(value); 727341825Sdim arguments.PushValue(value); 728341825Sdim 729341825Sdim do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller( 730341825Sdim clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error); 731341825Sdim if (utility_error.Fail()) { 732341825Sdim error.SetErrorStringWithFormat("dlopen error: could not make function" 733341825Sdim "caller: %s", utility_error.AsCString()); 734341825Sdim return nullptr; 735341825Sdim } 736341825Sdim 737341825Sdim do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller(); 738341825Sdim if (!do_dlopen_function) { 739341825Sdim error.SetErrorString("dlopen error: could not get function caller."); 740341825Sdim return nullptr; 741341825Sdim } 742341825Sdim 743341825Sdim // We made a good utility function, so cache it in the process: 744341825Sdim return dlopen_utility_func_up; 745341825Sdim} 746341825Sdim 747314564Sdimuint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, 748314564Sdim const lldb_private::FileSpec &remote_file, 749341825Sdim const std::vector<std::string> *paths, 750341825Sdim lldb_private::Status &error, 751341825Sdim lldb_private::FileSpec *loaded_image) { 752341825Sdim if (loaded_image) 753341825Sdim loaded_image->Clear(); 754296417Sdim 755341825Sdim std::string path; 756341825Sdim path = remote_file.GetPath(); 757341825Sdim 758341825Sdim ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); 759341825Sdim if (!thread_sp) { 760341825Sdim error.SetErrorString("dlopen error: no thread available to call dlopen."); 761314564Sdim return LLDB_INVALID_IMAGE_TOKEN; 762341825Sdim } 763341825Sdim 764341825Sdim DiagnosticManager diagnostics; 765341825Sdim 766341825Sdim ExecutionContext exe_ctx; 767341825Sdim thread_sp->CalculateExecutionContext(exe_ctx); 768296417Sdim 769341825Sdim Status utility_error; 770341825Sdim UtilityFunction *dlopen_utility_func; 771341825Sdim ValueList arguments; 772341825Sdim FunctionCaller *do_dlopen_function = nullptr; 773296417Sdim 774341825Sdim // The UtilityFunction is held in the Process. Platforms don't track the 775341825Sdim // lifespan of the Targets that use them, we can't put this in the Platform. 776341825Sdim dlopen_utility_func = process->GetLoadImageUtilityFunction( 777341825Sdim this, [&]() -> std::unique_ptr<UtilityFunction> { 778341825Sdim return MakeLoadImageUtilityFunction(exe_ctx, error); 779341825Sdim }); 780341825Sdim // If we couldn't make it, the error will be in error, so we can exit here. 781341825Sdim if (!dlopen_utility_func) 782314564Sdim return LLDB_INVALID_IMAGE_TOKEN; 783341825Sdim 784341825Sdim do_dlopen_function = dlopen_utility_func->GetFunctionCaller(); 785341825Sdim if (!do_dlopen_function) { 786341825Sdim error.SetErrorString("dlopen error: could not get function caller."); 787341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 788314564Sdim } 789341825Sdim arguments = do_dlopen_function->GetArgumentValues(); 790341825Sdim 791341825Sdim // Now insert the path we are searching for and the result structure into the 792341825Sdim // target. 793341825Sdim uint32_t permissions = ePermissionsReadable|ePermissionsWritable; 794341825Sdim size_t path_len = path.size() + 1; 795341825Sdim lldb::addr_t path_addr = process->AllocateMemory(path_len, 796341825Sdim permissions, 797341825Sdim utility_error); 798341825Sdim if (path_addr == LLDB_INVALID_ADDRESS) { 799341825Sdim error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 800341825Sdim "for path: %s", utility_error.AsCString()); 801341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 802341825Sdim } 803360784Sdim 804341825Sdim // Make sure we deallocate the input string memory: 805360784Sdim auto path_cleanup = llvm::make_scope_exit([process, path_addr] { 806360784Sdim // Deallocate the buffer. 807360784Sdim process->DeallocateMemory(path_addr); 808341825Sdim }); 809360784Sdim 810341825Sdim process->WriteMemory(path_addr, path.c_str(), path_len, utility_error); 811341825Sdim if (utility_error.Fail()) { 812341825Sdim error.SetErrorStringWithFormat("dlopen error: could not write path string:" 813341825Sdim " %s", utility_error.AsCString()); 814341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 815341825Sdim } 816341825Sdim 817341825Sdim // Make space for our return structure. It is two pointers big: the token 818341825Sdim // and the error string. 819341825Sdim const uint32_t addr_size = process->GetAddressByteSize(); 820341825Sdim lldb::addr_t return_addr = process->CallocateMemory(2*addr_size, 821341825Sdim permissions, 822341825Sdim utility_error); 823341825Sdim if (utility_error.Fail()) { 824341825Sdim error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 825341825Sdim "for path: %s", utility_error.AsCString()); 826341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 827341825Sdim } 828341825Sdim 829341825Sdim // Make sure we deallocate the result structure memory 830360784Sdim auto return_cleanup = llvm::make_scope_exit([process, return_addr] { 831360784Sdim // Deallocate the buffer 832360784Sdim process->DeallocateMemory(return_addr); 833341825Sdim }); 834360784Sdim 835341825Sdim // This will be the address of the storage for paths, if we are using them, 836341825Sdim // or nullptr to signal we aren't. 837341825Sdim lldb::addr_t path_array_addr = 0x0; 838360784Sdim llvm::Optional<llvm::detail::scope_exit<std::function<void()>>> 839360784Sdim path_array_cleanup; 840296417Sdim 841341825Sdim // This is the address to a buffer large enough to hold the largest path 842341825Sdim // conjoined with the library name we're passing in. This is a convenience 843341825Sdim // to avoid having to call malloc in the dlopen function. 844341825Sdim lldb::addr_t buffer_addr = 0x0; 845360784Sdim llvm::Optional<llvm::detail::scope_exit<std::function<void()>>> 846360784Sdim buffer_cleanup; 847360784Sdim 848341825Sdim // Set the values into our args and write them to the target: 849341825Sdim if (paths != nullptr) { 850341825Sdim // First insert the paths into the target. This is expected to be a 851341825Sdim // continuous buffer with the strings laid out null terminated and 852341825Sdim // end to end with an empty string terminating the buffer. 853341825Sdim // We also compute the buffer's required size as we go. 854341825Sdim size_t buffer_size = 0; 855341825Sdim std::string path_array; 856341825Sdim for (auto path : *paths) { 857341825Sdim // Don't insert empty paths, they will make us abort the path 858341825Sdim // search prematurely. 859341825Sdim if (path.empty()) 860341825Sdim continue; 861341825Sdim size_t path_size = path.size(); 862341825Sdim path_array.append(path); 863341825Sdim path_array.push_back('\0'); 864341825Sdim if (path_size > buffer_size) 865341825Sdim buffer_size = path_size; 866341825Sdim } 867341825Sdim path_array.push_back('\0'); 868341825Sdim 869341825Sdim path_array_addr = process->AllocateMemory(path_array.size(), 870341825Sdim permissions, 871341825Sdim utility_error); 872341825Sdim if (path_array_addr == LLDB_INVALID_ADDRESS) { 873341825Sdim error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 874341825Sdim "for path array: %s", 875341825Sdim utility_error.AsCString()); 876341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 877341825Sdim } 878341825Sdim 879341825Sdim // Make sure we deallocate the paths array. 880360784Sdim path_array_cleanup.emplace([process, path_array_addr]() { 881360784Sdim // Deallocate the path array. 882360784Sdim process->DeallocateMemory(path_array_addr); 883341825Sdim }); 884296417Sdim 885341825Sdim process->WriteMemory(path_array_addr, path_array.data(), 886341825Sdim path_array.size(), utility_error); 887341825Sdim 888341825Sdim if (utility_error.Fail()) { 889341825Sdim error.SetErrorStringWithFormat("dlopen error: could not write path array:" 890341825Sdim " %s", utility_error.AsCString()); 891314564Sdim return LLDB_INVALID_IMAGE_TOKEN; 892296417Sdim } 893341825Sdim // Now make spaces in the target for the buffer. We need to add one for 894341825Sdim // the '/' that the utility function will insert and one for the '\0': 895341825Sdim buffer_size += path.size() + 2; 896341825Sdim 897341825Sdim buffer_addr = process->AllocateMemory(buffer_size, 898341825Sdim permissions, 899341825Sdim utility_error); 900341825Sdim if (buffer_addr == LLDB_INVALID_ADDRESS) { 901341825Sdim error.SetErrorStringWithFormat("dlopen error: could not allocate memory" 902341825Sdim "for buffer: %s", 903341825Sdim utility_error.AsCString()); 904341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 905341825Sdim } 906341825Sdim 907341825Sdim // Make sure we deallocate the buffer memory: 908360784Sdim buffer_cleanup.emplace([process, buffer_addr]() { 909360784Sdim // Deallocate the buffer. 910360784Sdim process->DeallocateMemory(buffer_addr); 911341825Sdim }); 912314564Sdim } 913341825Sdim 914341825Sdim arguments.GetValueAtIndex(0)->GetScalar() = path_addr; 915341825Sdim arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr; 916341825Sdim arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr; 917341825Sdim arguments.GetValueAtIndex(3)->GetScalar() = return_addr; 918341825Sdim 919341825Sdim lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS; 920341825Sdim 921341825Sdim diagnostics.Clear(); 922341825Sdim if (!do_dlopen_function->WriteFunctionArguments(exe_ctx, 923341825Sdim func_args_addr, 924341825Sdim arguments, 925341825Sdim diagnostics)) { 926341825Sdim error.SetErrorStringWithFormat("dlopen error: could not write function " 927341825Sdim "arguments: %s", 928341825Sdim diagnostics.GetString().c_str()); 929341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 930341825Sdim } 931341825Sdim 932341825Sdim // Make sure we clean up the args structure. We can't reuse it because the 933341825Sdim // Platform lives longer than the process and the Platforms don't get a 934341825Sdim // signal to clean up cached data when a process goes away. 935360784Sdim auto args_cleanup = 936360784Sdim llvm::make_scope_exit([do_dlopen_function, &exe_ctx, func_args_addr] { 937360784Sdim do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr); 938360784Sdim }); 939360784Sdim 940341825Sdim // Now run the caller: 941341825Sdim EvaluateExpressionOptions options; 942341825Sdim options.SetExecutionPolicy(eExecutionPolicyAlways); 943341825Sdim options.SetLanguage(eLanguageTypeC_plus_plus); 944341825Sdim options.SetIgnoreBreakpoints(true); 945341825Sdim options.SetUnwindOnError(true); 946341825Sdim options.SetTrapExceptions(false); // dlopen can't throw exceptions, so 947341825Sdim // don't do the work to trap them. 948353358Sdim options.SetTimeout(process->GetUtilityExpressionTimeout()); 949344779Sdim options.SetIsForUtilityExpr(true); 950344779Sdim 951341825Sdim Value return_value; 952341825Sdim // Fetch the clang types we will need: 953360784Sdim ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); 954360784Sdim if (!ast) { 955360784Sdim error.SetErrorString("dlopen error: Unable to get ClangASTContext"); 956360784Sdim return LLDB_INVALID_IMAGE_TOKEN; 957360784Sdim } 958341825Sdim 959341825Sdim CompilerType clang_void_pointer_type 960341825Sdim = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 961341825Sdim 962341825Sdim return_value.SetCompilerType(clang_void_pointer_type); 963341825Sdim 964341825Sdim ExpressionResults results = do_dlopen_function->ExecuteFunction( 965341825Sdim exe_ctx, &func_args_addr, options, diagnostics, return_value); 966341825Sdim if (results != eExpressionCompleted) { 967341825Sdim error.SetErrorStringWithFormat("dlopen error: failed executing " 968341825Sdim "dlopen wrapper function: %s", 969341825Sdim diagnostics.GetString().c_str()); 970341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 971341825Sdim } 972341825Sdim 973341825Sdim // Read the dlopen token from the return area: 974341825Sdim lldb::addr_t token = process->ReadPointerFromMemory(return_addr, 975341825Sdim utility_error); 976341825Sdim if (utility_error.Fail()) { 977341825Sdim error.SetErrorStringWithFormat("dlopen error: could not read the return " 978341825Sdim "struct: %s", utility_error.AsCString()); 979341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 980341825Sdim } 981341825Sdim 982341825Sdim // The dlopen succeeded! 983341825Sdim if (token != 0x0) { 984341825Sdim if (loaded_image && buffer_addr != 0x0) 985341825Sdim { 986341825Sdim // Capture the image which was loaded. We leave it in the buffer on 987341825Sdim // exit from the dlopen function, so we can just read it from there: 988341825Sdim std::string name_string; 989341825Sdim process->ReadCStringFromMemory(buffer_addr, name_string, utility_error); 990341825Sdim if (utility_error.Success()) 991344779Sdim loaded_image->SetFile(name_string, llvm::sys::path::Style::posix); 992341825Sdim } 993341825Sdim return process->AddImageToken(token); 994341825Sdim } 995341825Sdim 996341825Sdim // We got an error, lets read in the error string: 997341825Sdim std::string dlopen_error_str; 998341825Sdim lldb::addr_t error_addr 999341825Sdim = process->ReadPointerFromMemory(return_addr + addr_size, utility_error); 1000341825Sdim if (utility_error.Fail()) { 1001341825Sdim error.SetErrorStringWithFormat("dlopen error: could not read error string: " 1002341825Sdim "%s", utility_error.AsCString()); 1003341825Sdim return LLDB_INVALID_IMAGE_TOKEN; 1004341825Sdim } 1005341825Sdim 1006341825Sdim size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size, 1007341825Sdim dlopen_error_str, 1008341825Sdim utility_error); 1009341825Sdim if (utility_error.Success() && num_chars > 0) 1010341825Sdim error.SetErrorStringWithFormat("dlopen error: %s", 1011341825Sdim dlopen_error_str.c_str()); 1012341825Sdim else 1013341825Sdim error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); 1014341825Sdim 1015314564Sdim return LLDB_INVALID_IMAGE_TOKEN; 1016296417Sdim} 1017296417Sdim 1018321369SdimStatus PlatformPOSIX::UnloadImage(lldb_private::Process *process, 1019321369Sdim uint32_t image_token) { 1020314564Sdim const addr_t image_addr = process->GetImagePtrFromToken(image_token); 1021314564Sdim if (image_addr == LLDB_INVALID_ADDRESS) 1022321369Sdim return Status("Invalid image token"); 1023296417Sdim 1024314564Sdim StreamString expr; 1025314564Sdim expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr); 1026327952Sdim llvm::StringRef prefix = GetLibdlFunctionDeclarations(process); 1027314564Sdim lldb::ValueObjectSP result_valobj_sp; 1028321369Sdim Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix, 1029321369Sdim result_valobj_sp); 1030314564Sdim if (error.Fail()) 1031314564Sdim return error; 1032296417Sdim 1033314564Sdim if (result_valobj_sp->GetError().Fail()) 1034314564Sdim return result_valobj_sp->GetError(); 1035296417Sdim 1036314564Sdim Scalar scalar; 1037314564Sdim if (result_valobj_sp->ResolveValue(scalar)) { 1038314564Sdim if (scalar.UInt(1)) 1039321369Sdim return Status("expression failed: \"%s\"", expr.GetData()); 1040314564Sdim process->ResetImageToken(image_token); 1041314564Sdim } 1042321369Sdim return Status(); 1043314564Sdim} 1044296417Sdim 1045327952Sdimllvm::StringRef 1046327952SdimPlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) { 1047314564Sdim return R"( 1048296417Sdim extern "C" void* dlopen(const char*, int); 1049296417Sdim extern "C" void* dlsym(void*, const char*); 1050296417Sdim extern "C" int dlclose(void*); 1051296417Sdim extern "C" char* dlerror(void); 1052296417Sdim )"; 1053296417Sdim} 1054296417Sdim 1055314564Sdimsize_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger, 1056321369Sdim Status &error) { 1057314564Sdim if (m_remote_platform_sp) 1058314564Sdim return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); 1059314564Sdim return Platform::ConnectToWaitingProcesses(debugger, error); 1060296417Sdim} 1061321369Sdim 1062321369SdimConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) { 1063321369Sdim if (basename.IsEmpty()) 1064321369Sdim return basename; 1065321369Sdim 1066321369Sdim StreamString stream; 1067321369Sdim stream.Printf("lib%s.so", basename.GetCString()); 1068321369Sdim return ConstString(stream.GetString()); 1069321369Sdim} 1070