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