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     : Platform(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       m_remote_platform_sp() {}
48 
49 //------------------------------------------------------------------
50 /// Destructor.
51 ///
52 /// The destructor is virtual since this class is designed to be
53 /// inherited from by the plug-in instance.
54 //------------------------------------------------------------------
55 PlatformPOSIX::~PlatformPOSIX() {}
56 
57 bool PlatformPOSIX::GetModuleSpec(const FileSpec &module_file_spec,
58                                   const ArchSpec &arch,
59                                   ModuleSpec &module_spec) {
60   if (m_remote_platform_sp)
61     return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
62                                                module_spec);
63 
64   return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
65 }
66 
67 lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions(
68     lldb_private::CommandInterpreter &interpreter) {
69   auto iter = m_options.find(&interpreter), end = m_options.end();
70   if (iter == end) {
71     std::unique_ptr<lldb_private::OptionGroupOptions> options(
72         new OptionGroupOptions());
73     options->Append(m_option_group_platform_rsync.get());
74     options->Append(m_option_group_platform_ssh.get());
75     options->Append(m_option_group_platform_caching.get());
76     m_options[&interpreter] = std::move(options);
77   }
78 
79   return m_options.at(&interpreter).get();
80 }
81 
82 bool PlatformPOSIX::IsConnected() const {
83   if (IsHost())
84     return true;
85   else if (m_remote_platform_sp)
86     return m_remote_platform_sp->IsConnected();
87   return false;
88 }
89 
90 lldb_private::Status PlatformPOSIX::RunShellCommand(
91     const char *command, // Shouldn't be NULL
92     const FileSpec &
93         working_dir, // Pass empty FileSpec to use the current working directory
94     int *status_ptr, // Pass NULL if you don't want the process exit status
95     int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
96                      // process to exit
97     std::string
98         *command_output, // Pass NULL if you don't want the command output
99     const Timeout<std::micro> &timeout) {
100   if (IsHost())
101     return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
102                                  command_output, timeout);
103   else {
104     if (m_remote_platform_sp)
105       return m_remote_platform_sp->RunShellCommand(
106           command, working_dir, status_ptr, signo_ptr, command_output, timeout);
107     else
108       return Status("unable to run a remote command without a platform");
109   }
110 }
111 
112 Status
113 PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec,
114                                  lldb::ModuleSP &exe_module_sp,
115                                  const FileSpecList *module_search_paths_ptr) {
116   Status error;
117   // Nothing special to do here, just use the actual file and architecture
118 
119   char exe_path[PATH_MAX];
120   ModuleSpec resolved_module_spec(module_spec);
121 
122   if (IsHost()) {
123     // If we have "ls" as the exe_file, resolve the executable location based
124     // on the current path variables
125     if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
126       resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
127       resolved_module_spec.GetFileSpec().SetFile(exe_path,
128                                                  FileSpec::Style::native);
129       FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec());
130     }
131 
132     if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
133       FileSystem::Instance().ResolveExecutableLocation(
134           resolved_module_spec.GetFileSpec());
135 
136     // Resolve any executable within a bundle on MacOSX
137     Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
138 
139     if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
140       error.Clear();
141     else {
142       const uint32_t permissions = FileSystem::Instance().GetPermissions(
143           resolved_module_spec.GetFileSpec());
144       if (permissions && (permissions & eFilePermissionsEveryoneR) == 0)
145         error.SetErrorStringWithFormat(
146             "executable '%s' is not readable",
147             resolved_module_spec.GetFileSpec().GetPath().c_str());
148       else
149         error.SetErrorStringWithFormat(
150             "unable to find executable for '%s'",
151             resolved_module_spec.GetFileSpec().GetPath().c_str());
152     }
153   } else {
154     if (m_remote_platform_sp) {
155       error =
156           GetCachedExecutable(resolved_module_spec, exe_module_sp,
157                               module_search_paths_ptr, *m_remote_platform_sp);
158     } else {
159       // We may connect to a process and use the provided executable (Don't use
160       // local $PATH).
161 
162       // Resolve any executable within a bundle on MacOSX
163       Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
164 
165       if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
166         error.Clear();
167       else
168         error.SetErrorStringWithFormat("the platform is not currently "
169                                        "connected, and '%s' doesn't exist in "
170                                        "the system root.",
171                                        exe_path);
172     }
173   }
174 
175   if (error.Success()) {
176     if (resolved_module_spec.GetArchitecture().IsValid()) {
177       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
178                                           module_search_paths_ptr, nullptr, nullptr);
179       if (error.Fail()) {
180         // If we failed, it may be because the vendor and os aren't known. If
181 	// that is the case, try setting them to the host architecture and give
182 	// it another try.
183         llvm::Triple &module_triple =
184             resolved_module_spec.GetArchitecture().GetTriple();
185         bool is_vendor_specified =
186             (module_triple.getVendor() != llvm::Triple::UnknownVendor);
187         bool is_os_specified =
188             (module_triple.getOS() != llvm::Triple::UnknownOS);
189         if (!is_vendor_specified || !is_os_specified) {
190           const llvm::Triple &host_triple =
191               HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
192 
193           if (!is_vendor_specified)
194             module_triple.setVendorName(host_triple.getVendorName());
195           if (!is_os_specified)
196             module_triple.setOSName(host_triple.getOSName());
197 
198           error = ModuleList::GetSharedModule(resolved_module_spec,
199                                               exe_module_sp, module_search_paths_ptr, nullptr, nullptr);
200         }
201       }
202 
203       // TODO find out why exe_module_sp might be NULL
204       if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) {
205         exe_module_sp.reset();
206         error.SetErrorStringWithFormat(
207             "'%s' doesn't contain the architecture %s",
208             resolved_module_spec.GetFileSpec().GetPath().c_str(),
209             resolved_module_spec.GetArchitecture().GetArchitectureName());
210       }
211     } else {
212       // No valid architecture was specified, ask the platform for the
213       // architectures that we should be using (in the correct order) and see
214       // if we can find a match that way
215       StreamString arch_names;
216       for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
217                idx, resolved_module_spec.GetArchitecture());
218            ++idx) {
219         error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
220                                             module_search_paths_ptr, nullptr, nullptr);
221         // Did we find an executable using one of the
222         if (error.Success()) {
223           if (exe_module_sp && exe_module_sp->GetObjectFile())
224             break;
225           else
226             error.SetErrorToGenericError();
227         }
228 
229         if (idx > 0)
230           arch_names.PutCString(", ");
231         arch_names.PutCString(
232             resolved_module_spec.GetArchitecture().GetArchitectureName());
233       }
234 
235       if (error.Fail() || !exe_module_sp) {
236         if (FileSystem::Instance().Readable(
237                 resolved_module_spec.GetFileSpec())) {
238           error.SetErrorStringWithFormat(
239               "'%s' doesn't contain any '%s' platform architectures: %s",
240               resolved_module_spec.GetFileSpec().GetPath().c_str(),
241               GetPluginName().GetCString(), arch_names.GetData());
242         } else {
243           error.SetErrorStringWithFormat(
244               "'%s' is not readable",
245               resolved_module_spec.GetFileSpec().GetPath().c_str());
246         }
247       }
248     }
249   }
250 
251   return error;
252 }
253 
254 Status PlatformPOSIX::GetFileWithUUID(const FileSpec &platform_file,
255                                       const UUID *uuid_ptr,
256                                       FileSpec &local_file) {
257   if (IsRemote() && m_remote_platform_sp)
258       return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
259                                                    local_file);
260 
261   // Default to the local case
262   local_file = platform_file;
263   return Status();
264 }
265 
266 bool PlatformPOSIX::GetProcessInfo(lldb::pid_t pid,
267                                      ProcessInstanceInfo &process_info) {
268   if (IsHost())
269     return Platform::GetProcessInfo(pid, process_info);
270   if (m_remote_platform_sp)
271     return m_remote_platform_sp->GetProcessInfo(pid, process_info);
272   return false;
273 }
274 
275 uint32_t
276 PlatformPOSIX::FindProcesses(const ProcessInstanceInfoMatch &match_info,
277                                ProcessInstanceInfoList &process_infos) {
278   if (IsHost())
279     return Platform::FindProcesses(match_info, process_infos);
280   if (m_remote_platform_sp)
281     return
282       m_remote_platform_sp->FindProcesses(match_info, process_infos);
283   return 0;
284 }
285 
286 Status PlatformPOSIX::MakeDirectory(const FileSpec &file_spec,
287                                     uint32_t file_permissions) {
288   if (m_remote_platform_sp)
289     return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions);
290   else
291     return Platform::MakeDirectory(file_spec, file_permissions);
292 }
293 
294 Status PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec,
295                                          uint32_t &file_permissions) {
296   if (m_remote_platform_sp)
297     return m_remote_platform_sp->GetFilePermissions(file_spec,
298                                                     file_permissions);
299   else
300     return Platform::GetFilePermissions(file_spec, file_permissions);
301 }
302 
303 Status PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec,
304                                          uint32_t file_permissions) {
305   if (m_remote_platform_sp)
306     return m_remote_platform_sp->SetFilePermissions(file_spec,
307                                                     file_permissions);
308   else
309     return Platform::SetFilePermissions(file_spec, file_permissions);
310 }
311 
312 lldb::user_id_t PlatformPOSIX::OpenFile(const FileSpec &file_spec,
313                                         uint32_t flags, uint32_t mode,
314                                         Status &error) {
315   if (IsHost())
316     return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
317   else if (m_remote_platform_sp)
318     return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
319   else
320     return Platform::OpenFile(file_spec, flags, mode, error);
321 }
322 
323 bool PlatformPOSIX::CloseFile(lldb::user_id_t fd, Status &error) {
324   if (IsHost())
325     return FileCache::GetInstance().CloseFile(fd, error);
326   else if (m_remote_platform_sp)
327     return m_remote_platform_sp->CloseFile(fd, error);
328   else
329     return Platform::CloseFile(fd, error);
330 }
331 
332 uint64_t PlatformPOSIX::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
333                                  uint64_t dst_len, Status &error) {
334   if (IsHost())
335     return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
336   else if (m_remote_platform_sp)
337     return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
338   else
339     return Platform::ReadFile(fd, offset, dst, dst_len, error);
340 }
341 
342 uint64_t PlatformPOSIX::WriteFile(lldb::user_id_t fd, uint64_t offset,
343                                   const void *src, uint64_t src_len,
344                                   Status &error) {
345   if (IsHost())
346     return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
347   else if (m_remote_platform_sp)
348     return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
349   else
350     return Platform::WriteFile(fd, offset, src, src_len, error);
351 }
352 
353 static uint32_t chown_file(Platform *platform, const char *path,
354                            uint32_t uid = UINT32_MAX,
355                            uint32_t gid = UINT32_MAX) {
356   if (!platform || !path || *path == 0)
357     return UINT32_MAX;
358 
359   if (uid == UINT32_MAX && gid == UINT32_MAX)
360     return 0; // pretend I did chown correctly - actually I just didn't care
361 
362   StreamString command;
363   command.PutCString("chown ");
364   if (uid != UINT32_MAX)
365     command.Printf("%d", uid);
366   if (gid != UINT32_MAX)
367     command.Printf(":%d", gid);
368   command.Printf("%s", path);
369   int status;
370   platform->RunShellCommand(command.GetData(), NULL, &status, NULL, NULL,
371                             std::chrono::seconds(10));
372   return status;
373 }
374 
375 lldb_private::Status
376 PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
377                        const lldb_private::FileSpec &destination, uint32_t uid,
378                        uint32_t gid) {
379   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
380 
381   if (IsHost()) {
382     if (FileSpec::Equal(source, destination, true))
383       return Status();
384     // cp src dst
385     // chown uid:gid dst
386     std::string src_path(source.GetPath());
387     if (src_path.empty())
388       return Status("unable to get file path for source");
389     std::string dst_path(destination.GetPath());
390     if (dst_path.empty())
391       return Status("unable to get file path for destination");
392     StreamString command;
393     command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
394     int status;
395     RunShellCommand(command.GetData(), NULL, &status, NULL, NULL,
396                     std::chrono::seconds(10));
397     if (status != 0)
398       return Status("unable to perform copy");
399     if (uid == UINT32_MAX && gid == UINT32_MAX)
400       return Status();
401     if (chown_file(this, dst_path.c_str(), uid, gid) != 0)
402       return Status("unable to perform chown");
403     return Status();
404   } else if (m_remote_platform_sp) {
405     if (GetSupportsRSync()) {
406       std::string src_path(source.GetPath());
407       if (src_path.empty())
408         return Status("unable to get file path for source");
409       std::string dst_path(destination.GetPath());
410       if (dst_path.empty())
411         return Status("unable to get file path for destination");
412       StreamString command;
413       if (GetIgnoresRemoteHostname()) {
414         if (!GetRSyncPrefix())
415           command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(),
416                          dst_path.c_str());
417         else
418           command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(),
419                          GetRSyncPrefix(), dst_path.c_str());
420       } else
421         command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(),
422                        GetHostname(), dst_path.c_str());
423       if (log)
424         log->Printf("[PutFile] Running command: %s\n", command.GetData());
425       int retcode;
426       Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL,
427                             std::chrono::minutes(1));
428       if (retcode == 0) {
429         // Don't chown a local file for a remote system
430         //                if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
431         //                    return Status("unable to perform chown");
432         return Status();
433       }
434       // if we are still here rsync has failed - let's try the slow way before
435       // giving up
436     }
437   }
438   return Platform::PutFile(source, destination, uid, gid);
439 }
440 
441 lldb::user_id_t PlatformPOSIX::GetFileSize(const FileSpec &file_spec) {
442   if (IsHost()) {
443     uint64_t Size;
444     if (llvm::sys::fs::file_size(file_spec.GetPath(), Size))
445       return 0;
446     return Size;
447   } else if (m_remote_platform_sp)
448     return m_remote_platform_sp->GetFileSize(file_spec);
449   else
450     return Platform::GetFileSize(file_spec);
451 }
452 
453 Status PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) {
454   if (IsHost())
455     return FileSystem::Instance().Symlink(src, dst);
456   else if (m_remote_platform_sp)
457     return m_remote_platform_sp->CreateSymlink(src, dst);
458   else
459     return Platform::CreateSymlink(src, dst);
460 }
461 
462 bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) {
463   if (IsHost())
464     return FileSystem::Instance().Exists(file_spec);
465   else if (m_remote_platform_sp)
466     return m_remote_platform_sp->GetFileExists(file_spec);
467   else
468     return Platform::GetFileExists(file_spec);
469 }
470 
471 Status PlatformPOSIX::Unlink(const FileSpec &file_spec) {
472   if (IsHost())
473     return llvm::sys::fs::remove(file_spec.GetPath());
474   else if (m_remote_platform_sp)
475     return m_remote_platform_sp->Unlink(file_spec);
476   else
477     return Platform::Unlink(file_spec);
478 }
479 
480 lldb_private::Status PlatformPOSIX::GetFile(
481     const lldb_private::FileSpec &source,      // remote file path
482     const lldb_private::FileSpec &destination) // local file path
483 {
484   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
485 
486   // Check the args, first.
487   std::string src_path(source.GetPath());
488   if (src_path.empty())
489     return Status("unable to get file path for source");
490   std::string dst_path(destination.GetPath());
491   if (dst_path.empty())
492     return Status("unable to get file path for destination");
493   if (IsHost()) {
494     if (FileSpec::Equal(source, destination, true))
495       return Status("local scenario->source and destination are the same file "
496                     "path: no operation performed");
497     // cp src dst
498     StreamString cp_command;
499     cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
500     int status;
501     RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL,
502                     std::chrono::seconds(10));
503     if (status != 0)
504       return Status("unable to perform copy");
505     return Status();
506   } else if (m_remote_platform_sp) {
507     if (GetSupportsRSync()) {
508       StreamString command;
509       if (GetIgnoresRemoteHostname()) {
510         if (!GetRSyncPrefix())
511           command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(),
512                          dst_path.c_str());
513         else
514           command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(),
515                          src_path.c_str(), dst_path.c_str());
516       } else
517         command.Printf("rsync %s %s:%s %s", GetRSyncOpts(),
518                        m_remote_platform_sp->GetHostname(), src_path.c_str(),
519                        dst_path.c_str());
520       if (log)
521         log->Printf("[GetFile] Running command: %s\n", command.GetData());
522       int retcode;
523       Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL,
524                             std::chrono::minutes(1));
525       if (retcode == 0)
526         return Status();
527       // If we are here, rsync has failed - let's try the slow way before
528       // giving up
529     }
530     // open src and dst
531     // read/write, read/write, read/write, ...
532     // close src
533     // close dst
534     if (log)
535       log->Printf("[GetFile] Using block by block transfer....\n");
536     Status error;
537     user_id_t fd_src = OpenFile(source, File::eOpenOptionRead,
538                                 lldb::eFilePermissionsFileDefault, error);
539 
540     if (fd_src == UINT64_MAX)
541       return Status("unable to open source file");
542 
543     uint32_t permissions = 0;
544     error = GetFilePermissions(source, permissions);
545 
546     if (permissions == 0)
547       permissions = lldb::eFilePermissionsFileDefault;
548 
549     user_id_t fd_dst = FileCache::GetInstance().OpenFile(
550         destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite |
551                          File::eOpenOptionTruncate,
552         permissions, error);
553 
554     if (fd_dst == UINT64_MAX) {
555       if (error.Success())
556         error.SetErrorString("unable to open destination file");
557     }
558 
559     if (error.Success()) {
560       lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
561       uint64_t offset = 0;
562       error.Clear();
563       while (error.Success()) {
564         const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(),
565                                          buffer_sp->GetByteSize(), error);
566         if (error.Fail())
567           break;
568         if (n_read == 0)
569           break;
570         if (FileCache::GetInstance().WriteFile(fd_dst, offset,
571                                                buffer_sp->GetBytes(), n_read,
572                                                error) != n_read) {
573           if (!error.Fail())
574             error.SetErrorString("unable to write to destination file");
575           break;
576         }
577         offset += n_read;
578       }
579     }
580     // Ignore the close error of src.
581     if (fd_src != UINT64_MAX)
582       CloseFile(fd_src, error);
583     // And close the dst file descriptot.
584     if (fd_dst != UINT64_MAX &&
585         !FileCache::GetInstance().CloseFile(fd_dst, error)) {
586       if (!error.Fail())
587         error.SetErrorString("unable to close destination file");
588     }
589     return error;
590   }
591   return Platform::GetFile(source, destination);
592 }
593 
594 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() {
595   StreamString stream;
596   if (GetSupportsRSync()) {
597     stream.PutCString("rsync");
598     if ((GetRSyncOpts() && *GetRSyncOpts()) ||
599         (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) {
600       stream.Printf(", options: ");
601       if (GetRSyncOpts() && *GetRSyncOpts())
602         stream.Printf("'%s' ", GetRSyncOpts());
603       stream.Printf(", prefix: ");
604       if (GetRSyncPrefix() && *GetRSyncPrefix())
605         stream.Printf("'%s' ", GetRSyncPrefix());
606       if (GetIgnoresRemoteHostname())
607         stream.Printf("ignore remote-hostname ");
608     }
609   }
610   if (GetSupportsSSH()) {
611     stream.PutCString("ssh");
612     if (GetSSHOpts() && *GetSSHOpts())
613       stream.Printf(", options: '%s' ", GetSSHOpts());
614   }
615   if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
616     stream.Printf("cache dir: %s", GetLocalCacheDirectory());
617   if (stream.GetSize())
618     return stream.GetString();
619   else
620     return "";
621 }
622 
623 bool PlatformPOSIX::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
624                                  uint64_t &high) {
625   if (IsHost())
626     return Platform::CalculateMD5(file_spec, low, high);
627   if (m_remote_platform_sp)
628     return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
629   return false;
630 }
631 
632 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() {
633   if (IsRemote() && m_remote_platform_sp)
634     return m_remote_platform_sp->GetRemoteUnixSignals();
635   return Platform::GetRemoteUnixSignals();
636 }
637 
638 FileSpec PlatformPOSIX::GetRemoteWorkingDirectory() {
639   if (IsRemote() && m_remote_platform_sp)
640     return m_remote_platform_sp->GetRemoteWorkingDirectory();
641   else
642     return Platform::GetRemoteWorkingDirectory();
643 }
644 
645 bool PlatformPOSIX::SetRemoteWorkingDirectory(const FileSpec &working_dir) {
646   if (IsRemote() && m_remote_platform_sp)
647     return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir);
648   else
649     return Platform::SetRemoteWorkingDirectory(working_dir);
650 }
651 
652 bool PlatformPOSIX::GetRemoteOSVersion() {
653   if (m_remote_platform_sp) {
654     m_os_version = m_remote_platform_sp->GetOSVersion();
655     return !m_os_version.empty();
656   }
657   return false;
658 }
659 
660 bool PlatformPOSIX::GetRemoteOSBuildString(std::string &s) {
661   if (m_remote_platform_sp)
662     return m_remote_platform_sp->GetRemoteOSBuildString(s);
663   s.clear();
664   return false;
665 }
666 
667 Environment PlatformPOSIX::GetEnvironment() {
668   if (IsRemote()) {
669     if (m_remote_platform_sp)
670       return m_remote_platform_sp->GetEnvironment();
671     return Environment();
672   }
673   return Host::GetEnvironment();
674 }
675 
676 bool PlatformPOSIX::GetRemoteOSKernelDescription(std::string &s) {
677   if (m_remote_platform_sp)
678     return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
679   s.clear();
680   return false;
681 }
682 
683 // Remote Platform subclasses need to override this function
684 ArchSpec PlatformPOSIX::GetRemoteSystemArchitecture() {
685   if (m_remote_platform_sp)
686     return m_remote_platform_sp->GetRemoteSystemArchitecture();
687   return ArchSpec();
688 }
689 
690 const char *PlatformPOSIX::GetHostname() {
691   if (IsHost())
692     return Platform::GetHostname();
693 
694   if (m_remote_platform_sp)
695     return m_remote_platform_sp->GetHostname();
696   return NULL;
697 }
698 
699 const char *PlatformPOSIX::GetUserName(uint32_t uid) {
700   // Check the cache in Platform in case we have already looked this uid up
701   const char *user_name = Platform::GetUserName(uid);
702   if (user_name)
703     return user_name;
704 
705   if (IsRemote() && m_remote_platform_sp)
706     return m_remote_platform_sp->GetUserName(uid);
707   return NULL;
708 }
709 
710 const char *PlatformPOSIX::GetGroupName(uint32_t gid) {
711   const char *group_name = Platform::GetGroupName(gid);
712   if (group_name)
713     return group_name;
714 
715   if (IsRemote() && m_remote_platform_sp)
716     return m_remote_platform_sp->GetGroupName(gid);
717   return NULL;
718 }
719 
720 Status PlatformPOSIX::ConnectRemote(Args &args) {
721   Status error;
722   if (IsHost()) {
723     error.SetErrorStringWithFormat(
724         "can't connect to the host platform '%s', always connected",
725         GetPluginName().GetCString());
726   } else {
727     if (!m_remote_platform_sp)
728       m_remote_platform_sp =
729           Platform::Create(ConstString("remote-gdb-server"), error);
730 
731     if (m_remote_platform_sp && error.Success())
732       error = m_remote_platform_sp->ConnectRemote(args);
733     else
734       error.SetErrorString("failed to create a 'remote-gdb-server' platform");
735 
736     if (error.Fail())
737       m_remote_platform_sp.reset();
738   }
739 
740   if (error.Success() && m_remote_platform_sp) {
741     if (m_option_group_platform_rsync.get() &&
742         m_option_group_platform_ssh.get() &&
743         m_option_group_platform_caching.get()) {
744       if (m_option_group_platform_rsync->m_rsync) {
745         SetSupportsRSync(true);
746         SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str());
747         SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str());
748         SetIgnoresRemoteHostname(
749             m_option_group_platform_rsync->m_ignores_remote_hostname);
750       }
751       if (m_option_group_platform_ssh->m_ssh) {
752         SetSupportsSSH(true);
753         SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str());
754       }
755       SetLocalCacheDirectory(
756           m_option_group_platform_caching->m_cache_dir.c_str());
757     }
758   }
759 
760   return error;
761 }
762 
763 Status PlatformPOSIX::DisconnectRemote() {
764   Status error;
765 
766   if (IsHost()) {
767     error.SetErrorStringWithFormat(
768         "can't disconnect from the host platform '%s', always connected",
769         GetPluginName().GetCString());
770   } else {
771     if (m_remote_platform_sp)
772       error = m_remote_platform_sp->DisconnectRemote();
773     else
774       error.SetErrorString("the platform is not currently connected");
775   }
776   return error;
777 }
778 
779 Status PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) {
780   Status error;
781 
782   if (IsHost()) {
783     error = Platform::LaunchProcess(launch_info);
784   } else {
785     if (m_remote_platform_sp)
786       error = m_remote_platform_sp->LaunchProcess(launch_info);
787     else
788       error.SetErrorString("the platform is not currently connected");
789   }
790   return error;
791 }
792 
793 lldb_private::Status PlatformPOSIX::KillProcess(const lldb::pid_t pid) {
794   if (IsHost())
795     return Platform::KillProcess(pid);
796 
797   if (m_remote_platform_sp)
798     return m_remote_platform_sp->KillProcess(pid);
799 
800   return Status("the platform is not currently connected");
801 }
802 
803 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info,
804                                       Debugger &debugger, Target *target,
805                                       Status &error) {
806   lldb::ProcessSP process_sp;
807   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
808 
809   if (IsHost()) {
810     if (target == NULL) {
811       TargetSP new_target_sp;
812 
813       error = debugger.GetTargetList().CreateTarget(
814           debugger, "", "", eLoadDependentsNo, NULL, new_target_sp);
815       target = new_target_sp.get();
816       if (log)
817         log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__);
818     } else {
819       error.Clear();
820       if (log)
821         log->Printf("PlatformPOSIX::%s target already existed, setting target",
822                     __FUNCTION__);
823     }
824 
825     if (target && error.Success()) {
826       debugger.GetTargetList().SetSelectedTarget(target);
827       if (log) {
828         ModuleSP exe_module_sp = target->GetExecutableModule();
829         log->Printf("PlatformPOSIX::%s set selected target to %p %s",
830                     __FUNCTION__, (void *)target,
831                     exe_module_sp
832                         ? exe_module_sp->GetFileSpec().GetPath().c_str()
833                         : "<null>");
834       }
835 
836       process_sp =
837           target->CreateProcess(attach_info.GetListenerForProcess(debugger),
838                                 attach_info.GetProcessPluginName(), NULL);
839 
840       if (process_sp) {
841         ListenerSP listener_sp = attach_info.GetHijackListener();
842         if (listener_sp == nullptr) {
843           listener_sp =
844               Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack");
845           attach_info.SetHijackListener(listener_sp);
846         }
847         process_sp->HijackProcessEvents(listener_sp);
848         error = process_sp->Attach(attach_info);
849       }
850     }
851   } else {
852     if (m_remote_platform_sp)
853       process_sp =
854           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
855     else
856       error.SetErrorString("the platform is not currently connected");
857   }
858   return process_sp;
859 }
860 
861 lldb::ProcessSP
862 PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
863                             Target *target, // Can be NULL, if NULL create a new
864                                             // target, else use existing one
865                             Status &error) {
866   ProcessSP process_sp;
867 
868   if (IsHost()) {
869     // We are going to hand this process off to debugserver which will be in
870     // charge of setting the exit status.  However, we still need to reap it
871     // from lldb. So, make sure we use a exit callback which does not set exit
872     // status.
873     const bool monitor_signals = false;
874     launch_info.SetMonitorProcessCallback(
875         &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals);
876     process_sp = Platform::DebugProcess(launch_info, debugger, target, error);
877   } else {
878     if (m_remote_platform_sp)
879       process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
880                                                       target, error);
881     else
882       error.SetErrorString("the platform is not currently connected");
883   }
884   return process_sp;
885 }
886 
887 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() {
888   m_trap_handlers.push_back(ConstString("_sigtramp"));
889 }
890 
891 Status PlatformPOSIX::EvaluateLibdlExpression(
892     lldb_private::Process *process, const char *expr_cstr,
893     llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) {
894   DynamicLoader *loader = process->GetDynamicLoader();
895   if (loader) {
896     Status error = loader->CanLoadImage();
897     if (error.Fail())
898       return error;
899   }
900 
901   ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread());
902   if (!thread_sp)
903     return Status("Selected thread isn't valid");
904 
905   StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0));
906   if (!frame_sp)
907     return Status("Frame 0 isn't valid");
908 
909   ExecutionContext exe_ctx;
910   frame_sp->CalculateExecutionContext(exe_ctx);
911   EvaluateExpressionOptions expr_options;
912   expr_options.SetUnwindOnError(true);
913   expr_options.SetIgnoreBreakpoints(true);
914   expr_options.SetExecutionPolicy(eExecutionPolicyAlways);
915   expr_options.SetLanguage(eLanguageTypeC_plus_plus);
916   expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
917                                          // don't do the work to trap them.
918   expr_options.SetTimeout(std::chrono::seconds(2));
919 
920   Status expr_error;
921   ExpressionResults result =
922       UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix,
923                                result_valobj_sp, expr_error);
924   if (result != eExpressionCompleted)
925     return expr_error;
926 
927   if (result_valobj_sp->GetError().Fail())
928     return result_valobj_sp->GetError();
929   return Status();
930 }
931 
932 std::unique_ptr<UtilityFunction>
933 PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
934                                             Status &error) {
935   // Remember to prepend this with the prefix from
936   // GetLibdlFunctionDeclarations. The returned values are all in
937   // __lldb_dlopen_result for consistency. The wrapper returns a void * but
938   // doesn't use it because UtilityFunctions don't work with void returns at
939   // present.
940   static const char *dlopen_wrapper_code = R"(
941   struct __lldb_dlopen_result {
942     void *image_ptr;
943     const char *error_str;
944   };
945 
946   extern void *memcpy(void *, const void *, size_t size);
947   extern size_t strlen(const char *);
948 
949 
950   void * __lldb_dlopen_wrapper (const char *name,
951                                 const char *path_strings,
952                                 char *buffer,
953                                 __lldb_dlopen_result *result_ptr)
954   {
955     // This is the case where the name is the full path:
956     if (!path_strings) {
957       result_ptr->image_ptr = dlopen(name, 2);
958       if (result_ptr->image_ptr)
959         result_ptr->error_str = nullptr;
960       return nullptr;
961     }
962 
963     // This is the case where we have a list of paths:
964     size_t name_len = strlen(name);
965     while (path_strings && path_strings[0] != '\0') {
966       size_t path_len = strlen(path_strings);
967       memcpy((void *) buffer, (void *) path_strings, path_len);
968       buffer[path_len] = '/';
969       char *target_ptr = buffer+path_len+1;
970       memcpy((void *) target_ptr, (void *) name, name_len + 1);
971       result_ptr->image_ptr = dlopen(buffer, 2);
972       if (result_ptr->image_ptr) {
973         result_ptr->error_str = nullptr;
974         break;
975       }
976       result_ptr->error_str = dlerror();
977       path_strings = path_strings + path_len + 1;
978     }
979     return nullptr;
980   }
981   )";
982 
983   static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper";
984   Process *process = exe_ctx.GetProcessSP().get();
985   // Insert the dlopen shim defines into our generic expression:
986   std::string expr(GetLibdlFunctionDeclarations(process));
987   expr.append(dlopen_wrapper_code);
988   Status utility_error;
989   DiagnosticManager diagnostics;
990 
991   std::unique_ptr<UtilityFunction> dlopen_utility_func_up(process
992       ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(),
993                                                   eLanguageTypeObjC,
994                                                   dlopen_wrapper_name,
995                                                   utility_error));
996   if (utility_error.Fail()) {
997     error.SetErrorStringWithFormat("dlopen error: could not make utility"
998                                    "function: %s", utility_error.AsCString());
999     return nullptr;
1000   }
1001   if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) {
1002     error.SetErrorStringWithFormat("dlopen error: could not install utility"
1003                                    "function: %s",
1004                                    diagnostics.GetString().c_str());
1005     return nullptr;
1006   }
1007 
1008   Value value;
1009   ValueList arguments;
1010   FunctionCaller *do_dlopen_function = nullptr;
1011 
1012   // Fetch the clang types we will need:
1013   ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1014 
1015   CompilerType clang_void_pointer_type
1016       = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1017   CompilerType clang_char_pointer_type
1018         = ast->GetBasicType(eBasicTypeChar).GetPointerType();
1019 
1020   // We are passing four arguments, the basename, the list of places to look,
1021   // a buffer big enough for all the path + name combos, and
1022   // a pointer to the storage we've made for the result:
1023   value.SetValueType(Value::eValueTypeScalar);
1024   value.SetCompilerType(clang_void_pointer_type);
1025   arguments.PushValue(value);
1026   value.SetCompilerType(clang_char_pointer_type);
1027   arguments.PushValue(value);
1028   arguments.PushValue(value);
1029   arguments.PushValue(value);
1030 
1031   do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller(
1032       clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error);
1033   if (utility_error.Fail()) {
1034     error.SetErrorStringWithFormat("dlopen error: could not make function"
1035                                    "caller: %s", utility_error.AsCString());
1036     return nullptr;
1037   }
1038 
1039   do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller();
1040   if (!do_dlopen_function) {
1041     error.SetErrorString("dlopen error: could not get function caller.");
1042     return nullptr;
1043   }
1044 
1045   // We made a good utility function, so cache it in the process:
1046   return dlopen_utility_func_up;
1047 }
1048 
1049 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
1050                                     const lldb_private::FileSpec &remote_file,
1051                                     const std::vector<std::string> *paths,
1052                                     lldb_private::Status &error,
1053                                     lldb_private::FileSpec *loaded_image) {
1054   if (loaded_image)
1055     loaded_image->Clear();
1056 
1057   std::string path;
1058   path = remote_file.GetPath();
1059 
1060   ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1061   if (!thread_sp) {
1062     error.SetErrorString("dlopen error: no thread available to call dlopen.");
1063     return LLDB_INVALID_IMAGE_TOKEN;
1064   }
1065 
1066   DiagnosticManager diagnostics;
1067 
1068   ExecutionContext exe_ctx;
1069   thread_sp->CalculateExecutionContext(exe_ctx);
1070 
1071   Status utility_error;
1072   UtilityFunction *dlopen_utility_func;
1073   ValueList arguments;
1074   FunctionCaller *do_dlopen_function = nullptr;
1075 
1076   // The UtilityFunction is held in the Process.  Platforms don't track the
1077   // lifespan of the Targets that use them, we can't put this in the Platform.
1078   dlopen_utility_func = process->GetLoadImageUtilityFunction(
1079       this, [&]() -> std::unique_ptr<UtilityFunction> {
1080         return MakeLoadImageUtilityFunction(exe_ctx, error);
1081       });
1082   // If we couldn't make it, the error will be in error, so we can exit here.
1083   if (!dlopen_utility_func)
1084     return LLDB_INVALID_IMAGE_TOKEN;
1085 
1086   do_dlopen_function = dlopen_utility_func->GetFunctionCaller();
1087   if (!do_dlopen_function) {
1088     error.SetErrorString("dlopen error: could not get function caller.");
1089     return LLDB_INVALID_IMAGE_TOKEN;
1090   }
1091   arguments = do_dlopen_function->GetArgumentValues();
1092 
1093   // Now insert the path we are searching for and the result structure into the
1094   // target.
1095   uint32_t permissions = ePermissionsReadable|ePermissionsWritable;
1096   size_t path_len = path.size() + 1;
1097   lldb::addr_t path_addr = process->AllocateMemory(path_len,
1098                                                    permissions,
1099                                                    utility_error);
1100   if (path_addr == LLDB_INVALID_ADDRESS) {
1101     error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
1102                                     "for path: %s", utility_error.AsCString());
1103     return LLDB_INVALID_IMAGE_TOKEN;
1104   }
1105 
1106   // Make sure we deallocate the input string memory:
1107   CleanUp path_cleanup([process, path_addr] {
1108       process->DeallocateMemory(path_addr);
1109   });
1110 
1111   process->WriteMemory(path_addr, path.c_str(), path_len, utility_error);
1112   if (utility_error.Fail()) {
1113     error.SetErrorStringWithFormat("dlopen error: could not write path string:"
1114                                     " %s", utility_error.AsCString());
1115     return LLDB_INVALID_IMAGE_TOKEN;
1116   }
1117 
1118   // Make space for our return structure.  It is two pointers big: the token
1119   // and the error string.
1120   const uint32_t addr_size = process->GetAddressByteSize();
1121   lldb::addr_t return_addr = process->CallocateMemory(2*addr_size,
1122                                                       permissions,
1123                                                       utility_error);
1124   if (utility_error.Fail()) {
1125     error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
1126                                     "for path: %s", utility_error.AsCString());
1127     return LLDB_INVALID_IMAGE_TOKEN;
1128   }
1129 
1130   // Make sure we deallocate the result structure memory
1131   CleanUp return_cleanup([process, return_addr] {
1132       process->DeallocateMemory(return_addr);
1133   });
1134 
1135   // This will be the address of the storage for paths, if we are using them,
1136   // or nullptr to signal we aren't.
1137   lldb::addr_t path_array_addr = 0x0;
1138   llvm::Optional<CleanUp> path_array_cleanup;
1139 
1140   // This is the address to a buffer large enough to hold the largest path
1141   // conjoined with the library name we're passing in.  This is a convenience
1142   // to avoid having to call malloc in the dlopen function.
1143   lldb::addr_t buffer_addr = 0x0;
1144   llvm::Optional<CleanUp> buffer_cleanup;
1145 
1146   // Set the values into our args and write them to the target:
1147   if (paths != nullptr) {
1148     // First insert the paths into the target.  This is expected to be a
1149     // continuous buffer with the strings laid out null terminated and
1150     // end to end with an empty string terminating the buffer.
1151     // We also compute the buffer's required size as we go.
1152     size_t buffer_size = 0;
1153     std::string path_array;
1154     for (auto path : *paths) {
1155       // Don't insert empty paths, they will make us abort the path
1156       // search prematurely.
1157       if (path.empty())
1158         continue;
1159       size_t path_size = path.size();
1160       path_array.append(path);
1161       path_array.push_back('\0');
1162       if (path_size > buffer_size)
1163         buffer_size = path_size;
1164     }
1165     path_array.push_back('\0');
1166 
1167     path_array_addr = process->AllocateMemory(path_array.size(),
1168                                               permissions,
1169                                               utility_error);
1170     if (path_array_addr == LLDB_INVALID_ADDRESS) {
1171       error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
1172                                       "for path array: %s",
1173                                       utility_error.AsCString());
1174       return LLDB_INVALID_IMAGE_TOKEN;
1175     }
1176 
1177     // Make sure we deallocate the paths array.
1178     path_array_cleanup.emplace([process, path_array_addr] {
1179         process->DeallocateMemory(path_array_addr);
1180     });
1181 
1182     process->WriteMemory(path_array_addr, path_array.data(),
1183                          path_array.size(), utility_error);
1184 
1185     if (utility_error.Fail()) {
1186       error.SetErrorStringWithFormat("dlopen error: could not write path array:"
1187                                      " %s", utility_error.AsCString());
1188       return LLDB_INVALID_IMAGE_TOKEN;
1189     }
1190     // Now make spaces in the target for the buffer.  We need to add one for
1191     // the '/' that the utility function will insert and one for the '\0':
1192     buffer_size += path.size() + 2;
1193 
1194     buffer_addr = process->AllocateMemory(buffer_size,
1195                                           permissions,
1196                                           utility_error);
1197     if (buffer_addr == LLDB_INVALID_ADDRESS) {
1198       error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
1199                                       "for buffer: %s",
1200                                       utility_error.AsCString());
1201       return LLDB_INVALID_IMAGE_TOKEN;
1202     }
1203 
1204     // Make sure we deallocate the buffer memory:
1205     buffer_cleanup.emplace([process, buffer_addr] {
1206         process->DeallocateMemory(buffer_addr);
1207     });
1208   }
1209 
1210   arguments.GetValueAtIndex(0)->GetScalar() = path_addr;
1211   arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr;
1212   arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr;
1213   arguments.GetValueAtIndex(3)->GetScalar() = return_addr;
1214 
1215   lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS;
1216 
1217   diagnostics.Clear();
1218   if (!do_dlopen_function->WriteFunctionArguments(exe_ctx,
1219                                                  func_args_addr,
1220                                                  arguments,
1221                                                  diagnostics)) {
1222     error.SetErrorStringWithFormat("dlopen error: could not write function "
1223                                    "arguments: %s",
1224                                    diagnostics.GetString().c_str());
1225     return LLDB_INVALID_IMAGE_TOKEN;
1226   }
1227 
1228   // Make sure we clean up the args structure.  We can't reuse it because the
1229   // Platform lives longer than the process and the Platforms don't get a
1230   // signal to clean up cached data when a process goes away.
1231   CleanUp args_cleanup([do_dlopen_function, &exe_ctx, func_args_addr] {
1232     do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr);
1233   });
1234 
1235   // Now run the caller:
1236   EvaluateExpressionOptions options;
1237   options.SetExecutionPolicy(eExecutionPolicyAlways);
1238   options.SetLanguage(eLanguageTypeC_plus_plus);
1239   options.SetIgnoreBreakpoints(true);
1240   options.SetUnwindOnError(true);
1241   options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
1242                                     // don't do the work to trap them.
1243   options.SetTimeout(std::chrono::seconds(2));
1244   options.SetIsForUtilityExpr(true);
1245 
1246   Value return_value;
1247   // Fetch the clang types we will need:
1248   ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1249 
1250   CompilerType clang_void_pointer_type
1251       = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1252 
1253   return_value.SetCompilerType(clang_void_pointer_type);
1254 
1255   ExpressionResults results = do_dlopen_function->ExecuteFunction(
1256       exe_ctx, &func_args_addr, options, diagnostics, return_value);
1257   if (results != eExpressionCompleted) {
1258     error.SetErrorStringWithFormat("dlopen error: failed executing "
1259                                    "dlopen wrapper function: %s",
1260                                    diagnostics.GetString().c_str());
1261     return LLDB_INVALID_IMAGE_TOKEN;
1262   }
1263 
1264   // Read the dlopen token from the return area:
1265   lldb::addr_t token = process->ReadPointerFromMemory(return_addr,
1266                                                       utility_error);
1267   if (utility_error.Fail()) {
1268     error.SetErrorStringWithFormat("dlopen error: could not read the return "
1269                                     "struct: %s", utility_error.AsCString());
1270     return LLDB_INVALID_IMAGE_TOKEN;
1271   }
1272 
1273   // The dlopen succeeded!
1274   if (token != 0x0) {
1275     if (loaded_image && buffer_addr != 0x0)
1276     {
1277       // Capture the image which was loaded.  We leave it in the buffer on
1278       // exit from the dlopen function, so we can just read it from there:
1279       std::string name_string;
1280       process->ReadCStringFromMemory(buffer_addr, name_string, utility_error);
1281       if (utility_error.Success())
1282         loaded_image->SetFile(name_string, llvm::sys::path::Style::posix);
1283     }
1284     return process->AddImageToken(token);
1285   }
1286 
1287   // We got an error, lets read in the error string:
1288   std::string dlopen_error_str;
1289   lldb::addr_t error_addr
1290     = process->ReadPointerFromMemory(return_addr + addr_size, utility_error);
1291   if (utility_error.Fail()) {
1292     error.SetErrorStringWithFormat("dlopen error: could not read error string: "
1293                                     "%s", utility_error.AsCString());
1294     return LLDB_INVALID_IMAGE_TOKEN;
1295   }
1296 
1297   size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size,
1298                                                     dlopen_error_str,
1299                                                     utility_error);
1300   if (utility_error.Success() && num_chars > 0)
1301     error.SetErrorStringWithFormat("dlopen error: %s",
1302                                    dlopen_error_str.c_str());
1303   else
1304     error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
1305 
1306   return LLDB_INVALID_IMAGE_TOKEN;
1307 }
1308 
1309 Status PlatformPOSIX::UnloadImage(lldb_private::Process *process,
1310                                   uint32_t image_token) {
1311   const addr_t image_addr = process->GetImagePtrFromToken(image_token);
1312   if (image_addr == LLDB_INVALID_ADDRESS)
1313     return Status("Invalid image token");
1314 
1315   StreamString expr;
1316   expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr);
1317   llvm::StringRef prefix = GetLibdlFunctionDeclarations(process);
1318   lldb::ValueObjectSP result_valobj_sp;
1319   Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
1320                                          result_valobj_sp);
1321   if (error.Fail())
1322     return error;
1323 
1324   if (result_valobj_sp->GetError().Fail())
1325     return result_valobj_sp->GetError();
1326 
1327   Scalar scalar;
1328   if (result_valobj_sp->ResolveValue(scalar)) {
1329     if (scalar.UInt(1))
1330       return Status("expression failed: \"%s\"", expr.GetData());
1331     process->ResetImageToken(image_token);
1332   }
1333   return Status();
1334 }
1335 
1336 lldb::ProcessSP PlatformPOSIX::ConnectProcess(llvm::StringRef connect_url,
1337                                               llvm::StringRef plugin_name,
1338                                               lldb_private::Debugger &debugger,
1339                                               lldb_private::Target *target,
1340                                               lldb_private::Status &error) {
1341   if (m_remote_platform_sp)
1342     return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name,
1343                                                 debugger, target, error);
1344 
1345   return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
1346                                   error);
1347 }
1348 
1349 llvm::StringRef
1350 PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
1351   return R"(
1352               extern "C" void* dlopen(const char*, int);
1353               extern "C" void* dlsym(void*, const char*);
1354               extern "C" int   dlclose(void*);
1355               extern "C" char* dlerror(void);
1356              )";
1357 }
1358 
1359 size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger,
1360                                                 Status &error) {
1361   if (m_remote_platform_sp)
1362     return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
1363   return Platform::ConnectToWaitingProcesses(debugger, error);
1364 }
1365 
1366 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) {
1367   if (basename.IsEmpty())
1368     return basename;
1369 
1370   StreamString stream;
1371   stream.Printf("lib%s.so", basename.GetCString());
1372   return ConstString(stream.GetString());
1373 }
1374