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