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("dlopen error: could not create utility"
617                                    "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("dlopen error: could not make function"
654                                    "caller: %s", utility_error.AsCString());
655     return nullptr;
656   }
657 
658   do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller();
659   if (!do_dlopen_function) {
660     error.SetErrorString("dlopen error: could not get function caller.");
661     return nullptr;
662   }
663 
664   // We made a good utility function, so cache it in the process:
665   return dlopen_utility_func_up;
666 }
667 
668 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
669                                     const lldb_private::FileSpec &remote_file,
670                                     const std::vector<std::string> *paths,
671                                     lldb_private::Status &error,
672                                     lldb_private::FileSpec *loaded_image) {
673   if (loaded_image)
674     loaded_image->Clear();
675 
676   std::string path;
677   path = remote_file.GetPath();
678 
679   ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
680   if (!thread_sp) {
681     error.SetErrorString("dlopen error: no thread available to call dlopen.");
682     return LLDB_INVALID_IMAGE_TOKEN;
683   }
684 
685   DiagnosticManager diagnostics;
686 
687   ExecutionContext exe_ctx;
688   thread_sp->CalculateExecutionContext(exe_ctx);
689 
690   Status utility_error;
691   UtilityFunction *dlopen_utility_func;
692   ValueList arguments;
693   FunctionCaller *do_dlopen_function = nullptr;
694 
695   // The UtilityFunction is held in the Process.  Platforms don't track the
696   // lifespan of the Targets that use them, we can't put this in the Platform.
697   dlopen_utility_func = process->GetLoadImageUtilityFunction(
698       this, [&]() -> std::unique_ptr<UtilityFunction> {
699         return MakeLoadImageUtilityFunction(exe_ctx, error);
700       });
701   // If we couldn't make it, the error will be in error, so we can exit here.
702   if (!dlopen_utility_func)
703     return LLDB_INVALID_IMAGE_TOKEN;
704 
705   do_dlopen_function = dlopen_utility_func->GetFunctionCaller();
706   if (!do_dlopen_function) {
707     error.SetErrorString("dlopen error: could not get function caller.");
708     return LLDB_INVALID_IMAGE_TOKEN;
709   }
710   arguments = do_dlopen_function->GetArgumentValues();
711 
712   // Now insert the path we are searching for and the result structure into the
713   // target.
714   uint32_t permissions = ePermissionsReadable|ePermissionsWritable;
715   size_t path_len = path.size() + 1;
716   lldb::addr_t path_addr = process->AllocateMemory(path_len,
717                                                    permissions,
718                                                    utility_error);
719   if (path_addr == LLDB_INVALID_ADDRESS) {
720     error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
721                                     "for path: %s", utility_error.AsCString());
722     return LLDB_INVALID_IMAGE_TOKEN;
723   }
724 
725   // Make sure we deallocate the input string memory:
726   auto path_cleanup = llvm::make_scope_exit([process, path_addr] {
727     // Deallocate the buffer.
728     process->DeallocateMemory(path_addr);
729   });
730 
731   process->WriteMemory(path_addr, path.c_str(), path_len, utility_error);
732   if (utility_error.Fail()) {
733     error.SetErrorStringWithFormat("dlopen error: could not write path string:"
734                                     " %s", utility_error.AsCString());
735     return LLDB_INVALID_IMAGE_TOKEN;
736   }
737 
738   // Make space for our return structure.  It is two pointers big: the token
739   // and the error string.
740   const uint32_t addr_size = process->GetAddressByteSize();
741   lldb::addr_t return_addr = process->CallocateMemory(2*addr_size,
742                                                       permissions,
743                                                       utility_error);
744   if (utility_error.Fail()) {
745     error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
746                                     "for path: %s", utility_error.AsCString());
747     return LLDB_INVALID_IMAGE_TOKEN;
748   }
749 
750   // Make sure we deallocate the result structure memory
751   auto return_cleanup = llvm::make_scope_exit([process, return_addr] {
752     // Deallocate the buffer
753     process->DeallocateMemory(return_addr);
754   });
755 
756   // This will be the address of the storage for paths, if we are using them,
757   // or nullptr to signal we aren't.
758   lldb::addr_t path_array_addr = 0x0;
759   llvm::Optional<llvm::detail::scope_exit<std::function<void()>>>
760       path_array_cleanup;
761 
762   // This is the address to a buffer large enough to hold the largest path
763   // conjoined with the library name we're passing in.  This is a convenience
764   // to avoid having to call malloc in the dlopen function.
765   lldb::addr_t buffer_addr = 0x0;
766   llvm::Optional<llvm::detail::scope_exit<std::function<void()>>>
767       buffer_cleanup;
768 
769   // Set the values into our args and write them to the target:
770   if (paths != nullptr) {
771     // First insert the paths into the target.  This is expected to be a
772     // continuous buffer with the strings laid out null terminated and
773     // end to end with an empty string terminating the buffer.
774     // We also compute the buffer's required size as we go.
775     size_t buffer_size = 0;
776     std::string path_array;
777     for (auto path : *paths) {
778       // Don't insert empty paths, they will make us abort the path
779       // search prematurely.
780       if (path.empty())
781         continue;
782       size_t path_size = path.size();
783       path_array.append(path);
784       path_array.push_back('\0');
785       if (path_size > buffer_size)
786         buffer_size = path_size;
787     }
788     path_array.push_back('\0');
789 
790     path_array_addr = process->AllocateMemory(path_array.size(),
791                                               permissions,
792                                               utility_error);
793     if (path_array_addr == LLDB_INVALID_ADDRESS) {
794       error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
795                                       "for path array: %s",
796                                       utility_error.AsCString());
797       return LLDB_INVALID_IMAGE_TOKEN;
798     }
799 
800     // Make sure we deallocate the paths array.
801     path_array_cleanup.emplace([process, path_array_addr]() {
802       // Deallocate the path array.
803       process->DeallocateMemory(path_array_addr);
804     });
805 
806     process->WriteMemory(path_array_addr, path_array.data(),
807                          path_array.size(), utility_error);
808 
809     if (utility_error.Fail()) {
810       error.SetErrorStringWithFormat("dlopen error: could not write path array:"
811                                      " %s", utility_error.AsCString());
812       return LLDB_INVALID_IMAGE_TOKEN;
813     }
814     // Now make spaces in the target for the buffer.  We need to add one for
815     // the '/' that the utility function will insert and one for the '\0':
816     buffer_size += path.size() + 2;
817 
818     buffer_addr = process->AllocateMemory(buffer_size,
819                                           permissions,
820                                           utility_error);
821     if (buffer_addr == LLDB_INVALID_ADDRESS) {
822       error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
823                                       "for buffer: %s",
824                                       utility_error.AsCString());
825       return LLDB_INVALID_IMAGE_TOKEN;
826     }
827 
828     // Make sure we deallocate the buffer memory:
829     buffer_cleanup.emplace([process, buffer_addr]() {
830       // Deallocate the buffer.
831       process->DeallocateMemory(buffer_addr);
832     });
833   }
834 
835   arguments.GetValueAtIndex(0)->GetScalar() = path_addr;
836   arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr;
837   arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr;
838   arguments.GetValueAtIndex(3)->GetScalar() = return_addr;
839 
840   lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS;
841 
842   diagnostics.Clear();
843   if (!do_dlopen_function->WriteFunctionArguments(exe_ctx,
844                                                  func_args_addr,
845                                                  arguments,
846                                                  diagnostics)) {
847     error.SetErrorStringWithFormat("dlopen error: could not write function "
848                                    "arguments: %s",
849                                    diagnostics.GetString().c_str());
850     return LLDB_INVALID_IMAGE_TOKEN;
851   }
852 
853   // Make sure we clean up the args structure.  We can't reuse it because the
854   // Platform lives longer than the process and the Platforms don't get a
855   // signal to clean up cached data when a process goes away.
856   auto args_cleanup =
857       llvm::make_scope_exit([do_dlopen_function, &exe_ctx, func_args_addr] {
858         do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr);
859       });
860 
861   // Now run the caller:
862   EvaluateExpressionOptions options;
863   options.SetExecutionPolicy(eExecutionPolicyAlways);
864   options.SetLanguage(eLanguageTypeC_plus_plus);
865   options.SetIgnoreBreakpoints(true);
866   options.SetUnwindOnError(true);
867   options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
868                                     // don't do the work to trap them.
869   options.SetTimeout(process->GetUtilityExpressionTimeout());
870   options.SetIsForUtilityExpr(true);
871 
872   Value return_value;
873   // Fetch the clang types we will need:
874   TypeSystemClang *ast =
875       ScratchTypeSystemClang::GetForTarget(process->GetTarget());
876   if (!ast) {
877     error.SetErrorString("dlopen error: Unable to get TypeSystemClang");
878     return LLDB_INVALID_IMAGE_TOKEN;
879   }
880 
881   CompilerType clang_void_pointer_type
882       = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
883 
884   return_value.SetCompilerType(clang_void_pointer_type);
885 
886   ExpressionResults results = do_dlopen_function->ExecuteFunction(
887       exe_ctx, &func_args_addr, options, diagnostics, return_value);
888   if (results != eExpressionCompleted) {
889     error.SetErrorStringWithFormat("dlopen error: failed executing "
890                                    "dlopen wrapper function: %s",
891                                    diagnostics.GetString().c_str());
892     return LLDB_INVALID_IMAGE_TOKEN;
893   }
894 
895   // Read the dlopen token from the return area:
896   lldb::addr_t token = process->ReadPointerFromMemory(return_addr,
897                                                       utility_error);
898   if (utility_error.Fail()) {
899     error.SetErrorStringWithFormat("dlopen error: could not read the return "
900                                     "struct: %s", utility_error.AsCString());
901     return LLDB_INVALID_IMAGE_TOKEN;
902   }
903 
904   // The dlopen succeeded!
905   if (token != 0x0) {
906     if (loaded_image && buffer_addr != 0x0)
907     {
908       // Capture the image which was loaded.  We leave it in the buffer on
909       // exit from the dlopen function, so we can just read it from there:
910       std::string name_string;
911       process->ReadCStringFromMemory(buffer_addr, name_string, utility_error);
912       if (utility_error.Success())
913         loaded_image->SetFile(name_string, llvm::sys::path::Style::posix);
914     }
915     return process->AddImageToken(token);
916   }
917 
918   // We got an error, lets read in the error string:
919   std::string dlopen_error_str;
920   lldb::addr_t error_addr
921     = process->ReadPointerFromMemory(return_addr + addr_size, utility_error);
922   if (utility_error.Fail()) {
923     error.SetErrorStringWithFormat("dlopen error: could not read error string: "
924                                     "%s", utility_error.AsCString());
925     return LLDB_INVALID_IMAGE_TOKEN;
926   }
927 
928   size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size,
929                                                     dlopen_error_str,
930                                                     utility_error);
931   if (utility_error.Success() && num_chars > 0)
932     error.SetErrorStringWithFormat("dlopen error: %s",
933                                    dlopen_error_str.c_str());
934   else
935     error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
936 
937   return LLDB_INVALID_IMAGE_TOKEN;
938 }
939 
940 Status PlatformPOSIX::UnloadImage(lldb_private::Process *process,
941                                   uint32_t image_token) {
942   const addr_t image_addr = process->GetImagePtrFromToken(image_token);
943   if (image_addr == LLDB_INVALID_ADDRESS)
944     return Status("Invalid image token");
945 
946   StreamString expr;
947   expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr);
948   llvm::StringRef prefix = GetLibdlFunctionDeclarations(process);
949   lldb::ValueObjectSP result_valobj_sp;
950   Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
951                                          result_valobj_sp);
952   if (error.Fail())
953     return error;
954 
955   if (result_valobj_sp->GetError().Fail())
956     return result_valobj_sp->GetError();
957 
958   Scalar scalar;
959   if (result_valobj_sp->ResolveValue(scalar)) {
960     if (scalar.UInt(1))
961       return Status("expression failed: \"%s\"", expr.GetData());
962     process->ResetImageToken(image_token);
963   }
964   return Status();
965 }
966 
967 llvm::StringRef
968 PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
969   return R"(
970               extern "C" void* dlopen(const char*, int);
971               extern "C" void* dlsym(void*, const char*);
972               extern "C" int   dlclose(void*);
973               extern "C" char* dlerror(void);
974              )";
975 }
976 
977 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) {
978   if (basename.IsEmpty())
979     return basename;
980 
981   StreamString stream;
982   stream.Printf("lib%s.so", basename.GetCString());
983   return ConstString(stream.GetString());
984 }
985