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