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/Debugger.h"
18 #include "lldb/Core/Module.h"
19 #include "lldb/Core/ModuleSpec.h"
20 #include "lldb/Core/ValueObject.h"
21 #include "lldb/Expression/UserExpression.h"
22 #include "lldb/Host/File.h"
23 #include "lldb/Host/FileCache.h"
24 #include "lldb/Host/FileSystem.h"
25 #include "lldb/Host/Host.h"
26 #include "lldb/Host/HostInfo.h"
27 #include "lldb/Target/DynamicLoader.h"
28 #include "lldb/Target/ExecutionContext.h"
29 #include "lldb/Target/Process.h"
30 #include "lldb/Target/ProcessLaunchInfo.h"
31 #include "lldb/Target/Thread.h"
32 #include "lldb/Utility/DataBufferHeap.h"
33 #include "lldb/Utility/FileSpec.h"
34 #include "lldb/Utility/Log.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     uint64_t Size;
440     if (llvm::sys::fs::file_size(file_spec.GetPath(), Size))
441       return 0;
442     return Size;
443   } else if (m_remote_platform_sp)
444     return m_remote_platform_sp->GetFileSize(file_spec);
445   else
446     return Platform::GetFileSize(file_spec);
447 }
448 
449 Error PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) {
450   if (IsHost())
451     return FileSystem::Symlink(src, dst);
452   else if (m_remote_platform_sp)
453     return m_remote_platform_sp->CreateSymlink(src, dst);
454   else
455     return Platform::CreateSymlink(src, dst);
456 }
457 
458 bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) {
459   if (IsHost())
460     return file_spec.Exists();
461   else if (m_remote_platform_sp)
462     return m_remote_platform_sp->GetFileExists(file_spec);
463   else
464     return Platform::GetFileExists(file_spec);
465 }
466 
467 Error PlatformPOSIX::Unlink(const FileSpec &file_spec) {
468   if (IsHost())
469     return llvm::sys::fs::remove(file_spec.GetPath());
470   else if (m_remote_platform_sp)
471     return m_remote_platform_sp->Unlink(file_spec);
472   else
473     return Platform::Unlink(file_spec);
474 }
475 
476 lldb_private::Error PlatformPOSIX::GetFile(
477     const lldb_private::FileSpec &source,      // remote file path
478     const lldb_private::FileSpec &destination) // local file path
479 {
480   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
481 
482   // Check the args, first.
483   std::string src_path(source.GetPath());
484   if (src_path.empty())
485     return Error("unable to get file path for source");
486   std::string dst_path(destination.GetPath());
487   if (dst_path.empty())
488     return Error("unable to get file path for destination");
489   if (IsHost()) {
490     if (FileSpec::Equal(source, destination, true))
491       return Error("local scenario->source and destination are the same file "
492                    "path: no operation performed");
493     // cp src dst
494     StreamString cp_command;
495     cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
496     int status;
497     RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 10);
498     if (status != 0)
499       return Error("unable to perform copy");
500     return Error();
501   } else if (m_remote_platform_sp) {
502     if (GetSupportsRSync()) {
503       StreamString command;
504       if (GetIgnoresRemoteHostname()) {
505         if (!GetRSyncPrefix())
506           command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(),
507                          dst_path.c_str());
508         else
509           command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(),
510                          src_path.c_str(), dst_path.c_str());
511       } else
512         command.Printf("rsync %s %s:%s %s", GetRSyncOpts(),
513                        m_remote_platform_sp->GetHostname(), src_path.c_str(),
514                        dst_path.c_str());
515       if (log)
516         log->Printf("[GetFile] Running command: %s\n", command.GetData());
517       int retcode;
518       Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60);
519       if (retcode == 0)
520         return Error();
521       // If we are here, rsync has failed - let's try the slow way before giving
522       // up
523     }
524     // open src and dst
525     // read/write, read/write, read/write, ...
526     // close src
527     // close dst
528     if (log)
529       log->Printf("[GetFile] Using block by block transfer....\n");
530     Error error;
531     user_id_t fd_src = OpenFile(source, File::eOpenOptionRead,
532                                 lldb::eFilePermissionsFileDefault, error);
533 
534     if (fd_src == UINT64_MAX)
535       return Error("unable to open source file");
536 
537     uint32_t permissions = 0;
538     error = GetFilePermissions(source, permissions);
539 
540     if (permissions == 0)
541       permissions = lldb::eFilePermissionsFileDefault;
542 
543     user_id_t fd_dst = FileCache::GetInstance().OpenFile(
544         destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite |
545                          File::eOpenOptionTruncate,
546         permissions, error);
547 
548     if (fd_dst == UINT64_MAX) {
549       if (error.Success())
550         error.SetErrorString("unable to open destination file");
551     }
552 
553     if (error.Success()) {
554       lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
555       uint64_t offset = 0;
556       error.Clear();
557       while (error.Success()) {
558         const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(),
559                                          buffer_sp->GetByteSize(), error);
560         if (error.Fail())
561           break;
562         if (n_read == 0)
563           break;
564         if (FileCache::GetInstance().WriteFile(fd_dst, offset,
565                                                buffer_sp->GetBytes(), n_read,
566                                                error) != n_read) {
567           if (!error.Fail())
568             error.SetErrorString("unable to write to destination file");
569           break;
570         }
571         offset += n_read;
572       }
573     }
574     // Ignore the close error of src.
575     if (fd_src != UINT64_MAX)
576       CloseFile(fd_src, error);
577     // And close the dst file descriptot.
578     if (fd_dst != UINT64_MAX &&
579         !FileCache::GetInstance().CloseFile(fd_dst, error)) {
580       if (!error.Fail())
581         error.SetErrorString("unable to close destination file");
582     }
583     return error;
584   }
585   return Platform::GetFile(source, destination);
586 }
587 
588 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() {
589   StreamString stream;
590   if (GetSupportsRSync()) {
591     stream.PutCString("rsync");
592     if ((GetRSyncOpts() && *GetRSyncOpts()) ||
593         (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) {
594       stream.Printf(", options: ");
595       if (GetRSyncOpts() && *GetRSyncOpts())
596         stream.Printf("'%s' ", GetRSyncOpts());
597       stream.Printf(", prefix: ");
598       if (GetRSyncPrefix() && *GetRSyncPrefix())
599         stream.Printf("'%s' ", GetRSyncPrefix());
600       if (GetIgnoresRemoteHostname())
601         stream.Printf("ignore remote-hostname ");
602     }
603   }
604   if (GetSupportsSSH()) {
605     stream.PutCString("ssh");
606     if (GetSSHOpts() && *GetSSHOpts())
607       stream.Printf(", options: '%s' ", GetSSHOpts());
608   }
609   if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
610     stream.Printf("cache dir: %s", GetLocalCacheDirectory());
611   if (stream.GetSize())
612     return stream.GetString();
613   else
614     return "";
615 }
616 
617 bool PlatformPOSIX::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
618                                  uint64_t &high) {
619   if (IsHost())
620     return Platform::CalculateMD5(file_spec, low, high);
621   if (m_remote_platform_sp)
622     return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
623   return false;
624 }
625 
626 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() {
627   if (IsRemote() && m_remote_platform_sp)
628     return m_remote_platform_sp->GetRemoteUnixSignals();
629   return Platform::GetRemoteUnixSignals();
630 }
631 
632 FileSpec PlatformPOSIX::GetRemoteWorkingDirectory() {
633   if (IsRemote() && m_remote_platform_sp)
634     return m_remote_platform_sp->GetRemoteWorkingDirectory();
635   else
636     return Platform::GetRemoteWorkingDirectory();
637 }
638 
639 bool PlatformPOSIX::SetRemoteWorkingDirectory(const FileSpec &working_dir) {
640   if (IsRemote() && m_remote_platform_sp)
641     return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir);
642   else
643     return Platform::SetRemoteWorkingDirectory(working_dir);
644 }
645 
646 bool PlatformPOSIX::GetRemoteOSVersion() {
647   if (m_remote_platform_sp)
648     return m_remote_platform_sp->GetOSVersion(
649         m_major_os_version, m_minor_os_version, m_update_os_version);
650   return false;
651 }
652 
653 bool PlatformPOSIX::GetRemoteOSBuildString(std::string &s) {
654   if (m_remote_platform_sp)
655     return m_remote_platform_sp->GetRemoteOSBuildString(s);
656   s.clear();
657   return false;
658 }
659 
660 size_t PlatformPOSIX::GetEnvironment(StringList &env) {
661   if (IsRemote()) {
662     if (m_remote_platform_sp)
663       return m_remote_platform_sp->GetEnvironment(env);
664     return 0;
665   }
666   return Host::GetEnvironment(env);
667 }
668 
669 bool PlatformPOSIX::GetRemoteOSKernelDescription(std::string &s) {
670   if (m_remote_platform_sp)
671     return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
672   s.clear();
673   return false;
674 }
675 
676 // Remote Platform subclasses need to override this function
677 ArchSpec PlatformPOSIX::GetRemoteSystemArchitecture() {
678   if (m_remote_platform_sp)
679     return m_remote_platform_sp->GetRemoteSystemArchitecture();
680   return ArchSpec();
681 }
682 
683 const char *PlatformPOSIX::GetHostname() {
684   if (IsHost())
685     return Platform::GetHostname();
686 
687   if (m_remote_platform_sp)
688     return m_remote_platform_sp->GetHostname();
689   return NULL;
690 }
691 
692 const char *PlatformPOSIX::GetUserName(uint32_t uid) {
693   // Check the cache in Platform in case we have already looked this uid up
694   const char *user_name = Platform::GetUserName(uid);
695   if (user_name)
696     return user_name;
697 
698   if (IsRemote() && m_remote_platform_sp)
699     return m_remote_platform_sp->GetUserName(uid);
700   return NULL;
701 }
702 
703 const char *PlatformPOSIX::GetGroupName(uint32_t gid) {
704   const char *group_name = Platform::GetGroupName(gid);
705   if (group_name)
706     return group_name;
707 
708   if (IsRemote() && m_remote_platform_sp)
709     return m_remote_platform_sp->GetGroupName(gid);
710   return NULL;
711 }
712 
713 Error PlatformPOSIX::ConnectRemote(Args &args) {
714   Error error;
715   if (IsHost()) {
716     error.SetErrorStringWithFormat(
717         "can't connect to the host platform '%s', always connected",
718         GetPluginName().GetCString());
719   } else {
720     if (!m_remote_platform_sp)
721       m_remote_platform_sp =
722           Platform::Create(ConstString("remote-gdb-server"), error);
723 
724     if (m_remote_platform_sp && error.Success())
725       error = m_remote_platform_sp->ConnectRemote(args);
726     else
727       error.SetErrorString("failed to create a 'remote-gdb-server' platform");
728 
729     if (error.Fail())
730       m_remote_platform_sp.reset();
731   }
732 
733   if (error.Success() && m_remote_platform_sp) {
734     if (m_option_group_platform_rsync.get() &&
735         m_option_group_platform_ssh.get() &&
736         m_option_group_platform_caching.get()) {
737       if (m_option_group_platform_rsync->m_rsync) {
738         SetSupportsRSync(true);
739         SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str());
740         SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str());
741         SetIgnoresRemoteHostname(
742             m_option_group_platform_rsync->m_ignores_remote_hostname);
743       }
744       if (m_option_group_platform_ssh->m_ssh) {
745         SetSupportsSSH(true);
746         SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str());
747       }
748       SetLocalCacheDirectory(
749           m_option_group_platform_caching->m_cache_dir.c_str());
750     }
751   }
752 
753   return error;
754 }
755 
756 Error PlatformPOSIX::DisconnectRemote() {
757   Error error;
758 
759   if (IsHost()) {
760     error.SetErrorStringWithFormat(
761         "can't disconnect from the host platform '%s', always connected",
762         GetPluginName().GetCString());
763   } else {
764     if (m_remote_platform_sp)
765       error = m_remote_platform_sp->DisconnectRemote();
766     else
767       error.SetErrorString("the platform is not currently connected");
768   }
769   return error;
770 }
771 
772 Error PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) {
773   Error error;
774 
775   if (IsHost()) {
776     error = Platform::LaunchProcess(launch_info);
777   } else {
778     if (m_remote_platform_sp)
779       error = m_remote_platform_sp->LaunchProcess(launch_info);
780     else
781       error.SetErrorString("the platform is not currently connected");
782   }
783   return error;
784 }
785 
786 lldb_private::Error PlatformPOSIX::KillProcess(const lldb::pid_t pid) {
787   if (IsHost())
788     return Platform::KillProcess(pid);
789 
790   if (m_remote_platform_sp)
791     return m_remote_platform_sp->KillProcess(pid);
792 
793   return Error("the platform is not currently connected");
794 }
795 
796 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info,
797                                       Debugger &debugger, Target *target,
798                                       Error &error) {
799   lldb::ProcessSP process_sp;
800   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
801 
802   if (IsHost()) {
803     if (target == NULL) {
804       TargetSP new_target_sp;
805 
806       error = debugger.GetTargetList().CreateTarget(debugger, "", "", false,
807                                                     NULL, new_target_sp);
808       target = new_target_sp.get();
809       if (log)
810         log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__);
811     } else {
812       error.Clear();
813       if (log)
814         log->Printf("PlatformPOSIX::%s target already existed, setting target",
815                     __FUNCTION__);
816     }
817 
818     if (target && error.Success()) {
819       debugger.GetTargetList().SetSelectedTarget(target);
820       if (log) {
821         ModuleSP exe_module_sp = target->GetExecutableModule();
822         log->Printf("PlatformPOSIX::%s set selected target to %p %s",
823                     __FUNCTION__, (void *)target,
824                     exe_module_sp
825                         ? exe_module_sp->GetFileSpec().GetPath().c_str()
826                         : "<null>");
827       }
828 
829       process_sp =
830           target->CreateProcess(attach_info.GetListenerForProcess(debugger),
831                                 attach_info.GetProcessPluginName(), NULL);
832 
833       if (process_sp) {
834         ListenerSP listener_sp = attach_info.GetHijackListener();
835         if (listener_sp == nullptr) {
836           listener_sp =
837               Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack");
838           attach_info.SetHijackListener(listener_sp);
839         }
840         process_sp->HijackProcessEvents(listener_sp);
841         error = process_sp->Attach(attach_info);
842       }
843     }
844   } else {
845     if (m_remote_platform_sp)
846       process_sp =
847           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
848     else
849       error.SetErrorString("the platform is not currently connected");
850   }
851   return process_sp;
852 }
853 
854 lldb::ProcessSP
855 PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
856                             Target *target, // Can be NULL, if NULL create a new
857                                             // target, else use existing one
858                             Error &error) {
859   ProcessSP process_sp;
860 
861   if (IsHost()) {
862     // We are going to hand this process off to debugserver which will be in
863     // charge of setting the exit status.
864     // We still need to reap it from lldb but if we let the monitor thread also
865     // set the exit status, we set up a
866     // race between debugserver & us for who will find out about the debugged
867     // process's death.
868     launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus);
869     process_sp = Platform::DebugProcess(launch_info, debugger, target, error);
870   } else {
871     if (m_remote_platform_sp)
872       process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
873                                                       target, error);
874     else
875       error.SetErrorString("the platform is not currently connected");
876   }
877   return process_sp;
878 }
879 
880 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() {
881   m_trap_handlers.push_back(ConstString("_sigtramp"));
882 }
883 
884 Error PlatformPOSIX::EvaluateLibdlExpression(
885     lldb_private::Process *process, const char *expr_cstr,
886     const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp) {
887   DynamicLoader *loader = process->GetDynamicLoader();
888   if (loader) {
889     Error error = loader->CanLoadImage();
890     if (error.Fail())
891       return error;
892   }
893 
894   ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread());
895   if (!thread_sp)
896     return Error("Selected thread isn't valid");
897 
898   StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0));
899   if (!frame_sp)
900     return Error("Frame 0 isn't valid");
901 
902   ExecutionContext exe_ctx;
903   frame_sp->CalculateExecutionContext(exe_ctx);
904   EvaluateExpressionOptions expr_options;
905   expr_options.SetUnwindOnError(true);
906   expr_options.SetIgnoreBreakpoints(true);
907   expr_options.SetExecutionPolicy(eExecutionPolicyAlways);
908   expr_options.SetLanguage(eLanguageTypeC_plus_plus);
909   expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
910                                          // don't do the work to trap them.
911   expr_options.SetTimeout(std::chrono::seconds(2));
912 
913   Error expr_error;
914   ExpressionResults result =
915       UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix,
916                                result_valobj_sp, expr_error);
917   if (result != eExpressionCompleted)
918     return expr_error;
919 
920   if (result_valobj_sp->GetError().Fail())
921     return result_valobj_sp->GetError();
922   return Error();
923 }
924 
925 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
926                                     const lldb_private::FileSpec &remote_file,
927                                     lldb_private::Error &error) {
928   char path[PATH_MAX];
929   remote_file.GetPath(path, sizeof(path));
930 
931   StreamString expr;
932   expr.Printf(R"(
933                    struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result;
934                    the_result.image_ptr = dlopen ("%s", 2);
935                    if (the_result.image_ptr == (void *) 0x0)
936                    {
937                        the_result.error_str = dlerror();
938                    }
939                    else
940                    {
941                        the_result.error_str = (const char *) 0x0;
942                    }
943                    the_result;
944                   )",
945               path);
946   const char *prefix = GetLibdlFunctionDeclarations();
947   lldb::ValueObjectSP result_valobj_sp;
948   error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
949                                   result_valobj_sp);
950   if (error.Fail())
951     return LLDB_INVALID_IMAGE_TOKEN;
952 
953   error = result_valobj_sp->GetError();
954   if (error.Fail())
955     return LLDB_INVALID_IMAGE_TOKEN;
956 
957   Scalar scalar;
958   ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true);
959   if (!image_ptr_sp || !image_ptr_sp->ResolveValue(scalar)) {
960     error.SetErrorStringWithFormat("unable to load '%s'", path);
961     return LLDB_INVALID_IMAGE_TOKEN;
962   }
963 
964   addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
965   if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS)
966     return process->AddImageToken(image_ptr);
967 
968   if (image_ptr == 0) {
969     ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true);
970     if (error_str_sp) {
971       DataBufferSP buffer_sp(new DataBufferHeap(10240, 0));
972       size_t num_chars =
973           error_str_sp->ReadPointedString(buffer_sp, error, 10240).first;
974       if (error.Success() && num_chars > 0)
975         error.SetErrorStringWithFormat("dlopen error: %s",
976                                        buffer_sp->GetBytes());
977       else
978         error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
979       return LLDB_INVALID_IMAGE_TOKEN;
980     }
981   }
982   error.SetErrorStringWithFormat("unable to load '%s'", path);
983   return LLDB_INVALID_IMAGE_TOKEN;
984 }
985 
986 Error PlatformPOSIX::UnloadImage(lldb_private::Process *process,
987                                  uint32_t image_token) {
988   const addr_t image_addr = process->GetImagePtrFromToken(image_token);
989   if (image_addr == LLDB_INVALID_ADDRESS)
990     return Error("Invalid image token");
991 
992   StreamString expr;
993   expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr);
994   const char *prefix = GetLibdlFunctionDeclarations();
995   lldb::ValueObjectSP result_valobj_sp;
996   Error error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
997                                         result_valobj_sp);
998   if (error.Fail())
999     return error;
1000 
1001   if (result_valobj_sp->GetError().Fail())
1002     return result_valobj_sp->GetError();
1003 
1004   Scalar scalar;
1005   if (result_valobj_sp->ResolveValue(scalar)) {
1006     if (scalar.UInt(1))
1007       return Error("expression failed: \"%s\"", expr.GetData());
1008     process->ResetImageToken(image_token);
1009   }
1010   return Error();
1011 }
1012 
1013 lldb::ProcessSP PlatformPOSIX::ConnectProcess(llvm::StringRef connect_url,
1014                                               llvm::StringRef plugin_name,
1015                                               lldb_private::Debugger &debugger,
1016                                               lldb_private::Target *target,
1017                                               lldb_private::Error &error) {
1018   if (m_remote_platform_sp)
1019     return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name,
1020                                                 debugger, target, error);
1021 
1022   return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
1023                                   error);
1024 }
1025 
1026 const char *PlatformPOSIX::GetLibdlFunctionDeclarations() const {
1027   return R"(
1028               extern "C" void* dlopen(const char*, int);
1029               extern "C" void* dlsym(void*, const char*);
1030               extern "C" int   dlclose(void*);
1031               extern "C" char* dlerror(void);
1032              )";
1033 }
1034 
1035 size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger,
1036                                                 Error &error) {
1037   if (m_remote_platform_sp)
1038     return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
1039   return Platform::ConnectToWaitingProcesses(debugger, error);
1040 }
1041 
1042 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) {
1043   if (basename.IsEmpty())
1044     return basename;
1045 
1046   StreamString stream;
1047   stream.Printf("lib%s.so", basename.GetCString());
1048   return ConstString(stream.GetString());
1049 }
1050