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