1 //===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PlatformPOSIX.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 
17 #include "lldb/Core/DataBufferHeap.h"
18 #include "lldb/Core/Debugger.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/Module.h"
21 #include "lldb/Core/ModuleSpec.h"
22 #include "lldb/Core/ValueObject.h"
23 #include "lldb/Expression/UserExpression.h"
24 #include "lldb/Host/File.h"
25 #include "lldb/Host/FileCache.h"
26 #include "lldb/Host/FileSpec.h"
27 #include "lldb/Host/FileSystem.h"
28 #include "lldb/Host/Host.h"
29 #include "lldb/Host/HostInfo.h"
30 #include "lldb/Target/DynamicLoader.h"
31 #include "lldb/Target/ExecutionContext.h"
32 #include "lldb/Target/Process.h"
33 #include "lldb/Target/ProcessLaunchInfo.h"
34 #include "lldb/Target/Thread.h"
35 #include "lldb/Utility/StreamString.h"
36 
37 using namespace lldb;
38 using namespace lldb_private;
39 
40 //------------------------------------------------------------------
41 /// Default Constructor
42 //------------------------------------------------------------------
43 PlatformPOSIX::PlatformPOSIX(bool is_host)
44     : Platform(is_host), // This is the local host platform
45       m_option_group_platform_rsync(new OptionGroupPlatformRSync()),
46       m_option_group_platform_ssh(new OptionGroupPlatformSSH()),
47       m_option_group_platform_caching(new OptionGroupPlatformCaching()),
48       m_remote_platform_sp() {}
49 
50 //------------------------------------------------------------------
51 /// Destructor.
52 ///
53 /// The destructor is virtual since this class is designed to be
54 /// inherited from by the plug-in instance.
55 //------------------------------------------------------------------
56 PlatformPOSIX::~PlatformPOSIX() {}
57 
58 bool PlatformPOSIX::GetModuleSpec(const FileSpec &module_file_spec,
59                                   const ArchSpec &arch,
60                                   ModuleSpec &module_spec) {
61   if (m_remote_platform_sp)
62     return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
63                                                module_spec);
64 
65   return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
66 }
67 
68 lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions(
69     lldb_private::CommandInterpreter &interpreter) {
70   auto iter = m_options.find(&interpreter), end = m_options.end();
71   if (iter == end) {
72     std::unique_ptr<lldb_private::OptionGroupOptions> options(
73         new OptionGroupOptions());
74     options->Append(m_option_group_platform_rsync.get());
75     options->Append(m_option_group_platform_ssh.get());
76     options->Append(m_option_group_platform_caching.get());
77     m_options[&interpreter] = std::move(options);
78   }
79 
80   return m_options.at(&interpreter).get();
81 }
82 
83 bool PlatformPOSIX::IsConnected() const {
84   if (IsHost())
85     return true;
86   else if (m_remote_platform_sp)
87     return m_remote_platform_sp->IsConnected();
88   return false;
89 }
90 
91 lldb_private::Error PlatformPOSIX::RunShellCommand(
92     const char *command, // Shouldn't be NULL
93     const FileSpec &
94         working_dir, // Pass empty FileSpec to use the current working directory
95     int *status_ptr, // Pass NULL if you don't want the process exit status
96     int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
97                      // process to exit
98     std::string
99         *command_output, // Pass NULL if you don't want the command output
100     uint32_t
101         timeout_sec) // Timeout in seconds to wait for shell program to finish
102 {
103   if (IsHost())
104     return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
105                                  command_output, timeout_sec);
106   else {
107     if (m_remote_platform_sp)
108       return m_remote_platform_sp->RunShellCommand(command, working_dir,
109                                                    status_ptr, signo_ptr,
110                                                    command_output, timeout_sec);
111     else
112       return Error("unable to run a remote command without a platform");
113   }
114 }
115 
116 Error PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec,
117                                   lldb::ModuleSP &exe_module_sp,
118                                   const FileSpecList *module_search_paths_ptr) {
119   Error error;
120   // Nothing special to do here, just use the actual file and architecture
121 
122   char exe_path[PATH_MAX];
123   ModuleSpec resolved_module_spec(module_spec);
124 
125   if (IsHost()) {
126     // If we have "ls" as the exe_file, resolve the executable location based on
127     // the current path variables
128     if (!resolved_module_spec.GetFileSpec().Exists()) {
129       resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
130       resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
131     }
132 
133     if (!resolved_module_spec.GetFileSpec().Exists())
134       resolved_module_spec.GetFileSpec().ResolveExecutableLocation();
135 
136     // Resolve any executable within a bundle on MacOSX
137     Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
138 
139     if (resolved_module_spec.GetFileSpec().Exists())
140       error.Clear();
141     else {
142       const uint32_t permissions =
143           resolved_module_spec.GetFileSpec().GetPermissions();
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 (resolved_module_spec.GetFileSpec().Exists())
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
213       // the architectures that we should be using (in the correct order)
214       // and see 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 (resolved_module_spec.GetFileSpec().Readable()) {
237           error.SetErrorStringWithFormat(
238               "'%s' doesn't contain any '%s' platform architectures: %s",
239               resolved_module_spec.GetFileSpec().GetPath().c_str(),
240               GetPluginName().GetCString(), arch_names.GetData());
241         } else {
242           error.SetErrorStringWithFormat(
243               "'%s' is not readable",
244               resolved_module_spec.GetFileSpec().GetPath().c_str());
245         }
246       }
247     }
248   }
249 
250   return error;
251 }
252 
253 Error PlatformPOSIX::GetFileWithUUID(const FileSpec &platform_file,
254                                        const UUID *uuid_ptr,
255                                        FileSpec &local_file) {
256   if (IsRemote() && m_remote_platform_sp)
257       return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
258                                                    local_file);
259 
260   // Default to the local case
261   local_file = platform_file;
262   return Error();
263 }
264 
265 bool PlatformPOSIX::GetProcessInfo(lldb::pid_t pid,
266                                      ProcessInstanceInfo &process_info) {
267   if (IsHost())
268     return Platform::GetProcessInfo(pid, process_info);
269   if (m_remote_platform_sp)
270     return m_remote_platform_sp->GetProcessInfo(pid, process_info);
271   return false;
272 }
273 
274 uint32_t
275 PlatformPOSIX::FindProcesses(const ProcessInstanceInfoMatch &match_info,
276                                ProcessInstanceInfoList &process_infos) {
277   if (IsHost())
278     return Platform::FindProcesses(match_info, process_infos);
279   if (m_remote_platform_sp)
280     return
281       m_remote_platform_sp->FindProcesses(match_info, process_infos);
282   return 0;
283 }
284 
285 Error PlatformPOSIX::MakeDirectory(const FileSpec &file_spec,
286                                    uint32_t file_permissions) {
287   if (m_remote_platform_sp)
288     return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions);
289   else
290     return Platform::MakeDirectory(file_spec, file_permissions);
291 }
292 
293 Error PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec,
294                                         uint32_t &file_permissions) {
295   if (m_remote_platform_sp)
296     return m_remote_platform_sp->GetFilePermissions(file_spec,
297                                                     file_permissions);
298   else
299     return Platform::GetFilePermissions(file_spec, file_permissions);
300 }
301 
302 Error PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec,
303                                         uint32_t file_permissions) {
304   if (m_remote_platform_sp)
305     return m_remote_platform_sp->SetFilePermissions(file_spec,
306                                                     file_permissions);
307   else
308     return Platform::SetFilePermissions(file_spec, file_permissions);
309 }
310 
311 lldb::user_id_t PlatformPOSIX::OpenFile(const FileSpec &file_spec,
312                                         uint32_t flags, uint32_t mode,
313                                         Error &error) {
314   if (IsHost())
315     return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
316   else if (m_remote_platform_sp)
317     return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
318   else
319     return Platform::OpenFile(file_spec, flags, mode, error);
320 }
321 
322 bool PlatformPOSIX::CloseFile(lldb::user_id_t fd, Error &error) {
323   if (IsHost())
324     return FileCache::GetInstance().CloseFile(fd, error);
325   else if (m_remote_platform_sp)
326     return m_remote_platform_sp->CloseFile(fd, error);
327   else
328     return Platform::CloseFile(fd, error);
329 }
330 
331 uint64_t PlatformPOSIX::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
332                                  uint64_t dst_len, Error &error) {
333   if (IsHost())
334     return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
335   else if (m_remote_platform_sp)
336     return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
337   else
338     return Platform::ReadFile(fd, offset, dst, dst_len, error);
339 }
340 
341 uint64_t PlatformPOSIX::WriteFile(lldb::user_id_t fd, uint64_t offset,
342                                   const void *src, uint64_t src_len,
343                                   Error &error) {
344   if (IsHost())
345     return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
346   else if (m_remote_platform_sp)
347     return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
348   else
349     return Platform::WriteFile(fd, offset, src, src_len, error);
350 }
351 
352 static uint32_t chown_file(Platform *platform, const char *path,
353                            uint32_t uid = UINT32_MAX,
354                            uint32_t gid = UINT32_MAX) {
355   if (!platform || !path || *path == 0)
356     return UINT32_MAX;
357 
358   if (uid == UINT32_MAX && gid == UINT32_MAX)
359     return 0; // pretend I did chown correctly - actually I just didn't care
360 
361   StreamString command;
362   command.PutCString("chown ");
363   if (uid != UINT32_MAX)
364     command.Printf("%d", uid);
365   if (gid != UINT32_MAX)
366     command.Printf(":%d", gid);
367   command.Printf("%s", path);
368   int status;
369   platform->RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 10);
370   return status;
371 }
372 
373 lldb_private::Error
374 PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
375                        const lldb_private::FileSpec &destination, uint32_t uid,
376                        uint32_t gid) {
377   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
378 
379   if (IsHost()) {
380     if (FileSpec::Equal(source, destination, true))
381       return Error();
382     // cp src dst
383     // chown uid:gid dst
384     std::string src_path(source.GetPath());
385     if (src_path.empty())
386       return Error("unable to get file path for source");
387     std::string dst_path(destination.GetPath());
388     if (dst_path.empty())
389       return Error("unable to get file path for destination");
390     StreamString command;
391     command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
392     int status;
393     RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 10);
394     if (status != 0)
395       return Error("unable to perform copy");
396     if (uid == UINT32_MAX && gid == UINT32_MAX)
397       return Error();
398     if (chown_file(this, dst_path.c_str(), uid, gid) != 0)
399       return Error("unable to perform chown");
400     return Error();
401   } else if (m_remote_platform_sp) {
402     if (GetSupportsRSync()) {
403       std::string src_path(source.GetPath());
404       if (src_path.empty())
405         return Error("unable to get file path for source");
406       std::string dst_path(destination.GetPath());
407       if (dst_path.empty())
408         return Error("unable to get file path for destination");
409       StreamString command;
410       if (GetIgnoresRemoteHostname()) {
411         if (!GetRSyncPrefix())
412           command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(),
413                          dst_path.c_str());
414         else
415           command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(),
416                          GetRSyncPrefix(), dst_path.c_str());
417       } else
418         command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(),
419                        GetHostname(), dst_path.c_str());
420       if (log)
421         log->Printf("[PutFile] Running command: %s\n", command.GetData());
422       int retcode;
423       Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60);
424       if (retcode == 0) {
425         // Don't chown a local file for a remote system
426         //                if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
427         //                    return Error("unable to perform chown");
428         return Error();
429       }
430       // if we are still here rsync has failed - let's try the slow way before
431       // giving up
432     }
433   }
434   return Platform::PutFile(source, destination, uid, gid);
435 }
436 
437 lldb::user_id_t PlatformPOSIX::GetFileSize(const FileSpec &file_spec) {
438   if (IsHost())
439     return FileSystem::GetFileSize(file_spec);
440   else if (m_remote_platform_sp)
441     return m_remote_platform_sp->GetFileSize(file_spec);
442   else
443     return Platform::GetFileSize(file_spec);
444 }
445 
446 Error PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) {
447   if (IsHost())
448     return FileSystem::Symlink(src, dst);
449   else if (m_remote_platform_sp)
450     return m_remote_platform_sp->CreateSymlink(src, dst);
451   else
452     return Platform::CreateSymlink(src, dst);
453 }
454 
455 bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) {
456   if (IsHost())
457     return file_spec.Exists();
458   else if (m_remote_platform_sp)
459     return m_remote_platform_sp->GetFileExists(file_spec);
460   else
461     return Platform::GetFileExists(file_spec);
462 }
463 
464 Error PlatformPOSIX::Unlink(const FileSpec &file_spec) {
465   if (IsHost())
466     return FileSystem::Unlink(file_spec);
467   else if (m_remote_platform_sp)
468     return m_remote_platform_sp->Unlink(file_spec);
469   else
470     return Platform::Unlink(file_spec);
471 }
472 
473 lldb_private::Error PlatformPOSIX::GetFile(
474     const lldb_private::FileSpec &source,      // remote file path
475     const lldb_private::FileSpec &destination) // local file path
476 {
477   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
478 
479   // Check the args, first.
480   std::string src_path(source.GetPath());
481   if (src_path.empty())
482     return Error("unable to get file path for source");
483   std::string dst_path(destination.GetPath());
484   if (dst_path.empty())
485     return Error("unable to get file path for destination");
486   if (IsHost()) {
487     if (FileSpec::Equal(source, destination, true))
488       return Error("local scenario->source and destination are the same file "
489                    "path: no operation performed");
490     // cp src dst
491     StreamString cp_command;
492     cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
493     int status;
494     RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 10);
495     if (status != 0)
496       return Error("unable to perform copy");
497     return Error();
498   } else if (m_remote_platform_sp) {
499     if (GetSupportsRSync()) {
500       StreamString command;
501       if (GetIgnoresRemoteHostname()) {
502         if (!GetRSyncPrefix())
503           command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(),
504                          dst_path.c_str());
505         else
506           command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(),
507                          src_path.c_str(), dst_path.c_str());
508       } else
509         command.Printf("rsync %s %s:%s %s", GetRSyncOpts(),
510                        m_remote_platform_sp->GetHostname(), src_path.c_str(),
511                        dst_path.c_str());
512       if (log)
513         log->Printf("[GetFile] Running command: %s\n", command.GetData());
514       int retcode;
515       Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60);
516       if (retcode == 0)
517         return Error();
518       // If we are here, rsync has failed - let's try the slow way before giving
519       // up
520     }
521     // open src and dst
522     // read/write, read/write, read/write, ...
523     // close src
524     // close dst
525     if (log)
526       log->Printf("[GetFile] Using block by block transfer....\n");
527     Error error;
528     user_id_t fd_src = OpenFile(source, File::eOpenOptionRead,
529                                 lldb::eFilePermissionsFileDefault, error);
530 
531     if (fd_src == UINT64_MAX)
532       return Error("unable to open source file");
533 
534     uint32_t permissions = 0;
535     error = GetFilePermissions(source, permissions);
536 
537     if (permissions == 0)
538       permissions = lldb::eFilePermissionsFileDefault;
539 
540     user_id_t fd_dst = FileCache::GetInstance().OpenFile(
541         destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite |
542                          File::eOpenOptionTruncate,
543         permissions, error);
544 
545     if (fd_dst == UINT64_MAX) {
546       if (error.Success())
547         error.SetErrorString("unable to open destination file");
548     }
549 
550     if (error.Success()) {
551       lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
552       uint64_t offset = 0;
553       error.Clear();
554       while (error.Success()) {
555         const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(),
556                                          buffer_sp->GetByteSize(), error);
557         if (error.Fail())
558           break;
559         if (n_read == 0)
560           break;
561         if (FileCache::GetInstance().WriteFile(fd_dst, offset,
562                                                buffer_sp->GetBytes(), n_read,
563                                                error) != n_read) {
564           if (!error.Fail())
565             error.SetErrorString("unable to write to destination file");
566           break;
567         }
568         offset += n_read;
569       }
570     }
571     // Ignore the close error of src.
572     if (fd_src != UINT64_MAX)
573       CloseFile(fd_src, error);
574     // And close the dst file descriptot.
575     if (fd_dst != UINT64_MAX &&
576         !FileCache::GetInstance().CloseFile(fd_dst, error)) {
577       if (!error.Fail())
578         error.SetErrorString("unable to close destination file");
579     }
580     return error;
581   }
582   return Platform::GetFile(source, destination);
583 }
584 
585 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() {
586   StreamString stream;
587   if (GetSupportsRSync()) {
588     stream.PutCString("rsync");
589     if ((GetRSyncOpts() && *GetRSyncOpts()) ||
590         (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) {
591       stream.Printf(", options: ");
592       if (GetRSyncOpts() && *GetRSyncOpts())
593         stream.Printf("'%s' ", GetRSyncOpts());
594       stream.Printf(", prefix: ");
595       if (GetRSyncPrefix() && *GetRSyncPrefix())
596         stream.Printf("'%s' ", GetRSyncPrefix());
597       if (GetIgnoresRemoteHostname())
598         stream.Printf("ignore remote-hostname ");
599     }
600   }
601   if (GetSupportsSSH()) {
602     stream.PutCString("ssh");
603     if (GetSSHOpts() && *GetSSHOpts())
604       stream.Printf(", options: '%s' ", GetSSHOpts());
605   }
606   if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
607     stream.Printf("cache dir: %s", GetLocalCacheDirectory());
608   if (stream.GetSize())
609     return stream.GetString();
610   else
611     return "";
612 }
613 
614 bool PlatformPOSIX::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
615                                  uint64_t &high) {
616   if (IsHost())
617     return Platform::CalculateMD5(file_spec, low, high);
618   if (m_remote_platform_sp)
619     return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
620   return false;
621 }
622 
623 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() {
624   if (IsRemote() && m_remote_platform_sp)
625     return m_remote_platform_sp->GetRemoteUnixSignals();
626   return Platform::GetRemoteUnixSignals();
627 }
628 
629 FileSpec PlatformPOSIX::GetRemoteWorkingDirectory() {
630   if (IsRemote() && m_remote_platform_sp)
631     return m_remote_platform_sp->GetRemoteWorkingDirectory();
632   else
633     return Platform::GetRemoteWorkingDirectory();
634 }
635 
636 bool PlatformPOSIX::SetRemoteWorkingDirectory(const FileSpec &working_dir) {
637   if (IsRemote() && m_remote_platform_sp)
638     return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir);
639   else
640     return Platform::SetRemoteWorkingDirectory(working_dir);
641 }
642 
643 bool PlatformPOSIX::GetRemoteOSVersion() {
644   if (m_remote_platform_sp)
645     return m_remote_platform_sp->GetOSVersion(
646         m_major_os_version, m_minor_os_version, m_update_os_version);
647   return false;
648 }
649 
650 bool PlatformPOSIX::GetRemoteOSBuildString(std::string &s) {
651   if (m_remote_platform_sp)
652     return m_remote_platform_sp->GetRemoteOSBuildString(s);
653   s.clear();
654   return false;
655 }
656 
657 size_t PlatformPOSIX::GetEnvironment(StringList &env) {
658   if (IsRemote()) {
659     if (m_remote_platform_sp)
660       return m_remote_platform_sp->GetEnvironment(env);
661     return 0;
662   }
663   return Host::GetEnvironment(env);
664 }
665 
666 bool PlatformPOSIX::GetRemoteOSKernelDescription(std::string &s) {
667   if (m_remote_platform_sp)
668     return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
669   s.clear();
670   return false;
671 }
672 
673 // Remote Platform subclasses need to override this function
674 ArchSpec PlatformPOSIX::GetRemoteSystemArchitecture() {
675   if (m_remote_platform_sp)
676     return m_remote_platform_sp->GetRemoteSystemArchitecture();
677   return ArchSpec();
678 }
679 
680 const char *PlatformPOSIX::GetHostname() {
681   if (IsHost())
682     return Platform::GetHostname();
683 
684   if (m_remote_platform_sp)
685     return m_remote_platform_sp->GetHostname();
686   return NULL;
687 }
688 
689 const char *PlatformPOSIX::GetUserName(uint32_t uid) {
690   // Check the cache in Platform in case we have already looked this uid up
691   const char *user_name = Platform::GetUserName(uid);
692   if (user_name)
693     return user_name;
694 
695   if (IsRemote() && m_remote_platform_sp)
696     return m_remote_platform_sp->GetUserName(uid);
697   return NULL;
698 }
699 
700 const char *PlatformPOSIX::GetGroupName(uint32_t gid) {
701   const char *group_name = Platform::GetGroupName(gid);
702   if (group_name)
703     return group_name;
704 
705   if (IsRemote() && m_remote_platform_sp)
706     return m_remote_platform_sp->GetGroupName(gid);
707   return NULL;
708 }
709 
710 Error PlatformPOSIX::ConnectRemote(Args &args) {
711   Error error;
712   if (IsHost()) {
713     error.SetErrorStringWithFormat(
714         "can't connect to the host platform '%s', always connected",
715         GetPluginName().GetCString());
716   } else {
717     if (!m_remote_platform_sp)
718       m_remote_platform_sp =
719           Platform::Create(ConstString("remote-gdb-server"), error);
720 
721     if (m_remote_platform_sp && error.Success())
722       error = m_remote_platform_sp->ConnectRemote(args);
723     else
724       error.SetErrorString("failed to create a 'remote-gdb-server' platform");
725 
726     if (error.Fail())
727       m_remote_platform_sp.reset();
728   }
729 
730   if (error.Success() && m_remote_platform_sp) {
731     if (m_option_group_platform_rsync.get() &&
732         m_option_group_platform_ssh.get() &&
733         m_option_group_platform_caching.get()) {
734       if (m_option_group_platform_rsync->m_rsync) {
735         SetSupportsRSync(true);
736         SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str());
737         SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str());
738         SetIgnoresRemoteHostname(
739             m_option_group_platform_rsync->m_ignores_remote_hostname);
740       }
741       if (m_option_group_platform_ssh->m_ssh) {
742         SetSupportsSSH(true);
743         SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str());
744       }
745       SetLocalCacheDirectory(
746           m_option_group_platform_caching->m_cache_dir.c_str());
747     }
748   }
749 
750   return error;
751 }
752 
753 Error PlatformPOSIX::DisconnectRemote() {
754   Error error;
755 
756   if (IsHost()) {
757     error.SetErrorStringWithFormat(
758         "can't disconnect from the host platform '%s', always connected",
759         GetPluginName().GetCString());
760   } else {
761     if (m_remote_platform_sp)
762       error = m_remote_platform_sp->DisconnectRemote();
763     else
764       error.SetErrorString("the platform is not currently connected");
765   }
766   return error;
767 }
768 
769 Error PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) {
770   Error error;
771 
772   if (IsHost()) {
773     error = Platform::LaunchProcess(launch_info);
774   } else {
775     if (m_remote_platform_sp)
776       error = m_remote_platform_sp->LaunchProcess(launch_info);
777     else
778       error.SetErrorString("the platform is not currently connected");
779   }
780   return error;
781 }
782 
783 lldb_private::Error PlatformPOSIX::KillProcess(const lldb::pid_t pid) {
784   if (IsHost())
785     return Platform::KillProcess(pid);
786 
787   if (m_remote_platform_sp)
788     return m_remote_platform_sp->KillProcess(pid);
789 
790   return Error("the platform is not currently connected");
791 }
792 
793 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info,
794                                       Debugger &debugger, Target *target,
795                                       Error &error) {
796   lldb::ProcessSP process_sp;
797   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
798 
799   if (IsHost()) {
800     if (target == NULL) {
801       TargetSP new_target_sp;
802 
803       error = debugger.GetTargetList().CreateTarget(debugger, "", "", false,
804                                                     NULL, new_target_sp);
805       target = new_target_sp.get();
806       if (log)
807         log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__);
808     } else {
809       error.Clear();
810       if (log)
811         log->Printf("PlatformPOSIX::%s target already existed, setting target",
812                     __FUNCTION__);
813     }
814 
815     if (target && error.Success()) {
816       debugger.GetTargetList().SetSelectedTarget(target);
817       if (log) {
818         ModuleSP exe_module_sp = target->GetExecutableModule();
819         log->Printf("PlatformPOSIX::%s set selected target to %p %s",
820                     __FUNCTION__, (void *)target,
821                     exe_module_sp
822                         ? exe_module_sp->GetFileSpec().GetPath().c_str()
823                         : "<null>");
824       }
825 
826       process_sp =
827           target->CreateProcess(attach_info.GetListenerForProcess(debugger),
828                                 attach_info.GetProcessPluginName(), NULL);
829 
830       if (process_sp) {
831         ListenerSP listener_sp = attach_info.GetHijackListener();
832         if (listener_sp == nullptr) {
833           listener_sp =
834               Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack");
835           attach_info.SetHijackListener(listener_sp);
836         }
837         process_sp->HijackProcessEvents(listener_sp);
838         error = process_sp->Attach(attach_info);
839       }
840     }
841   } else {
842     if (m_remote_platform_sp)
843       process_sp =
844           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
845     else
846       error.SetErrorString("the platform is not currently connected");
847   }
848   return process_sp;
849 }
850 
851 lldb::ProcessSP
852 PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
853                             Target *target, // Can be NULL, if NULL create a new
854                                             // target, else use existing one
855                             Error &error) {
856   ProcessSP process_sp;
857 
858   if (IsHost()) {
859     // We are going to hand this process off to debugserver which will be in
860     // charge of setting the exit status.
861     // We still need to reap it from lldb but if we let the monitor thread also
862     // set the exit status, we set up a
863     // race between debugserver & us for who will find out about the debugged
864     // process's death.
865     launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus);
866     process_sp = Platform::DebugProcess(launch_info, debugger, target, error);
867   } else {
868     if (m_remote_platform_sp)
869       process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
870                                                       target, error);
871     else
872       error.SetErrorString("the platform is not currently connected");
873   }
874   return process_sp;
875 }
876 
877 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() {
878   m_trap_handlers.push_back(ConstString("_sigtramp"));
879 }
880 
881 Error PlatformPOSIX::EvaluateLibdlExpression(
882     lldb_private::Process *process, const char *expr_cstr,
883     const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp) {
884   DynamicLoader *loader = process->GetDynamicLoader();
885   if (loader) {
886     Error error = loader->CanLoadImage();
887     if (error.Fail())
888       return error;
889   }
890 
891   ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread());
892   if (!thread_sp)
893     return Error("Selected thread isn't valid");
894 
895   StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0));
896   if (!frame_sp)
897     return Error("Frame 0 isn't valid");
898 
899   ExecutionContext exe_ctx;
900   frame_sp->CalculateExecutionContext(exe_ctx);
901   EvaluateExpressionOptions expr_options;
902   expr_options.SetUnwindOnError(true);
903   expr_options.SetIgnoreBreakpoints(true);
904   expr_options.SetExecutionPolicy(eExecutionPolicyAlways);
905   expr_options.SetLanguage(eLanguageTypeC_plus_plus);
906   expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
907                                          // don't do the work to trap them.
908   expr_options.SetTimeout(std::chrono::seconds(2));
909 
910   Error expr_error;
911   ExpressionResults result =
912       UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix,
913                                result_valobj_sp, expr_error);
914   if (result != eExpressionCompleted)
915     return expr_error;
916 
917   if (result_valobj_sp->GetError().Fail())
918     return result_valobj_sp->GetError();
919   return Error();
920 }
921 
922 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
923                                     const lldb_private::FileSpec &remote_file,
924                                     lldb_private::Error &error) {
925   char path[PATH_MAX];
926   remote_file.GetPath(path, sizeof(path));
927 
928   StreamString expr;
929   expr.Printf(R"(
930                    struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result;
931                    the_result.image_ptr = dlopen ("%s", 2);
932                    if (the_result.image_ptr == (void *) 0x0)
933                    {
934                        the_result.error_str = dlerror();
935                    }
936                    else
937                    {
938                        the_result.error_str = (const char *) 0x0;
939                    }
940                    the_result;
941                   )",
942               path);
943   const char *prefix = GetLibdlFunctionDeclarations();
944   lldb::ValueObjectSP result_valobj_sp;
945   error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
946                                   result_valobj_sp);
947   if (error.Fail())
948     return LLDB_INVALID_IMAGE_TOKEN;
949 
950   error = result_valobj_sp->GetError();
951   if (error.Fail())
952     return LLDB_INVALID_IMAGE_TOKEN;
953 
954   Scalar scalar;
955   ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true);
956   if (!image_ptr_sp || !image_ptr_sp->ResolveValue(scalar)) {
957     error.SetErrorStringWithFormat("unable to load '%s'", path);
958     return LLDB_INVALID_IMAGE_TOKEN;
959   }
960 
961   addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
962   if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS)
963     return process->AddImageToken(image_ptr);
964 
965   if (image_ptr == 0) {
966     ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true);
967     if (error_str_sp) {
968       DataBufferSP buffer_sp(new DataBufferHeap(10240, 0));
969       size_t num_chars =
970           error_str_sp->ReadPointedString(buffer_sp, error, 10240).first;
971       if (error.Success() && num_chars > 0)
972         error.SetErrorStringWithFormat("dlopen error: %s",
973                                        buffer_sp->GetBytes());
974       else
975         error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
976       return LLDB_INVALID_IMAGE_TOKEN;
977     }
978   }
979   error.SetErrorStringWithFormat("unable to load '%s'", path);
980   return LLDB_INVALID_IMAGE_TOKEN;
981 }
982 
983 Error PlatformPOSIX::UnloadImage(lldb_private::Process *process,
984                                  uint32_t image_token) {
985   const addr_t image_addr = process->GetImagePtrFromToken(image_token);
986   if (image_addr == LLDB_INVALID_ADDRESS)
987     return Error("Invalid image token");
988 
989   StreamString expr;
990   expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr);
991   const char *prefix = GetLibdlFunctionDeclarations();
992   lldb::ValueObjectSP result_valobj_sp;
993   Error error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
994                                         result_valobj_sp);
995   if (error.Fail())
996     return error;
997 
998   if (result_valobj_sp->GetError().Fail())
999     return result_valobj_sp->GetError();
1000 
1001   Scalar scalar;
1002   if (result_valobj_sp->ResolveValue(scalar)) {
1003     if (scalar.UInt(1))
1004       return Error("expression failed: \"%s\"", expr.GetData());
1005     process->ResetImageToken(image_token);
1006   }
1007   return Error();
1008 }
1009 
1010 lldb::ProcessSP PlatformPOSIX::ConnectProcess(llvm::StringRef connect_url,
1011                                               llvm::StringRef plugin_name,
1012                                               lldb_private::Debugger &debugger,
1013                                               lldb_private::Target *target,
1014                                               lldb_private::Error &error) {
1015   if (m_remote_platform_sp)
1016     return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name,
1017                                                 debugger, target, error);
1018 
1019   return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
1020                                   error);
1021 }
1022 
1023 const char *PlatformPOSIX::GetLibdlFunctionDeclarations() const {
1024   return R"(
1025               extern "C" void* dlopen(const char*, int);
1026               extern "C" void* dlsym(void*, const char*);
1027               extern "C" int   dlclose(void*);
1028               extern "C" char* dlerror(void);
1029              )";
1030 }
1031 
1032 size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger,
1033                                                 Error &error) {
1034   if (m_remote_platform_sp)
1035     return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
1036   return Platform::ConnectToWaitingProcesses(debugger, error);
1037 }
1038 
1039 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) {
1040   if (basename.IsEmpty())
1041     return basename;
1042 
1043   StreamString stream;
1044   stream.Printf("lib%s.so", basename.GetCString());
1045   return ConstString(stream.GetString());
1046 }
1047