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