1 //===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PlatformPOSIX.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 
17 #include "lldb/Core/DataBufferHeap.h"
18 #include "lldb/Core/Log.h"
19 #include "lldb/Core/StreamString.h"
20 #include "lldb/Host/File.h"
21 #include "lldb/Host/FileSpec.h"
22 #include "lldb/Host/Host.h"
23 #include "lldb/Target/ProcessLaunchInfo.h"
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
28 
29 //------------------------------------------------------------------
30 /// Default Constructor
31 //------------------------------------------------------------------
32 PlatformPOSIX::PlatformPOSIX (bool is_host) :
33 Platform(is_host),  // This is the local host platform
34 m_remote_platform_sp ()
35 {
36 }
37 
38 //------------------------------------------------------------------
39 /// Destructor.
40 ///
41 /// The destructor is virtual since this class is designed to be
42 /// inherited from by the plug-in instance.
43 //------------------------------------------------------------------
44 PlatformPOSIX::~PlatformPOSIX()
45 {
46 }
47 
48 lldb_private::OptionGroupOptions*
49 PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter)
50 {
51     if (m_options.get() == NULL)
52     {
53         m_options.reset(new OptionGroupOptions(interpreter));
54         m_options->Append(new OptionGroupPlatformRSync());
55         m_options->Append(new OptionGroupPlatformSSH());
56         m_options->Append(new OptionGroupPlatformCaching());
57     }
58     return m_options.get();
59 }
60 
61 bool
62 PlatformPOSIX::IsConnected () const
63 {
64     if (IsHost())
65         return true;
66     else if (m_remote_platform_sp)
67         return m_remote_platform_sp->IsConnected();
68     return false;
69 }
70 
71 lldb_private::Error
72 PlatformPOSIX::RunShellCommand (const char *command,           // Shouldn't be NULL
73                                 const char *working_dir,       // Pass NULL to use the current working directory
74                                 int *status_ptr,               // Pass NULL if you don't want the process exit status
75                                 int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
76                                 std::string *command_output,   // Pass NULL if you don't want the command output
77                                 uint32_t timeout_sec)         // Timeout in seconds to wait for shell program to finish
78 {
79     if (IsHost())
80         return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
81     else
82     {
83         if (m_remote_platform_sp)
84             return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
85         else
86             return Error("unable to run a remote command without a platform");
87     }
88 }
89 
90 Error
91 PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions)
92 {
93     if (m_remote_platform_sp)
94         return m_remote_platform_sp->MakeDirectory(path, file_permissions);
95     else
96         return Platform::MakeDirectory(path ,file_permissions);
97 }
98 
99 Error
100 PlatformPOSIX::GetFilePermissions (const char *path, uint32_t &file_permissions)
101 {
102     if (m_remote_platform_sp)
103         return m_remote_platform_sp->GetFilePermissions(path, file_permissions);
104     else
105         return Platform::GetFilePermissions(path ,file_permissions);
106 }
107 
108 Error
109 PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions)
110 {
111     if (m_remote_platform_sp)
112         return m_remote_platform_sp->SetFilePermissions(path, file_permissions);
113     else
114         return Platform::SetFilePermissions(path ,file_permissions);
115 }
116 
117 lldb::user_id_t
118 PlatformPOSIX::OpenFile (const FileSpec& file_spec,
119                          uint32_t flags,
120                          uint32_t mode,
121                          Error &error)
122 {
123     if (IsHost())
124         return Host::OpenFile(file_spec, flags, mode, error);
125     else if (m_remote_platform_sp)
126         return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
127     else
128         return Platform::OpenFile(file_spec, flags, mode, error);
129 }
130 
131 bool
132 PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error)
133 {
134     if (IsHost())
135         return Host::CloseFile(fd, error);
136     else if (m_remote_platform_sp)
137         return m_remote_platform_sp->CloseFile(fd, error);
138     else
139         return Platform::CloseFile(fd, error);
140 }
141 
142 uint64_t
143 PlatformPOSIX::ReadFile (lldb::user_id_t fd,
144                          uint64_t offset,
145                          void *dst,
146                          uint64_t dst_len,
147                          Error &error)
148 {
149     if (IsHost())
150         return Host::ReadFile(fd, offset, dst, dst_len, error);
151     else if (m_remote_platform_sp)
152         return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
153     else
154         return Platform::ReadFile(fd, offset, dst, dst_len, error);
155 }
156 
157 uint64_t
158 PlatformPOSIX::WriteFile (lldb::user_id_t fd,
159                           uint64_t offset,
160                           const void* src,
161                           uint64_t src_len,
162                           Error &error)
163 {
164     if (IsHost())
165         return Host::WriteFile(fd, offset, src, src_len, error);
166     else if (m_remote_platform_sp)
167         return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
168     else
169         return Platform::WriteFile(fd, offset, src, src_len, error);
170 }
171 
172 static uint32_t
173 chown_file(Platform *platform,
174            const char* path,
175            uint32_t uid = UINT32_MAX,
176            uint32_t gid = UINT32_MAX)
177 {
178     if (!platform || !path || *path == 0)
179         return UINT32_MAX;
180 
181     if (uid == UINT32_MAX && gid == UINT32_MAX)
182         return 0;   // pretend I did chown correctly - actually I just didn't care
183 
184     StreamString command;
185     command.PutCString("chown ");
186     if (uid != UINT32_MAX)
187         command.Printf("%d",uid);
188     if (gid != UINT32_MAX)
189         command.Printf(":%d",gid);
190     command.Printf("%s",path);
191     int status;
192     platform->RunShellCommand(command.GetData(),
193                               NULL,
194                               &status,
195                               NULL,
196                               NULL,
197                               10);
198     return status;
199 }
200 
201 lldb_private::Error
202 PlatformPOSIX::PutFile (const lldb_private::FileSpec& source,
203                          const lldb_private::FileSpec& destination,
204                          uint32_t uid,
205                          uint32_t gid)
206 {
207     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
208 
209     if (IsHost())
210     {
211         if (FileSpec::Equal(source, destination, true))
212             return Error();
213         // cp src dst
214         // chown uid:gid dst
215         std::string src_path (source.GetPath());
216         if (src_path.empty())
217             return Error("unable to get file path for source");
218         std::string dst_path (destination.GetPath());
219         if (dst_path.empty())
220             return Error("unable to get file path for destination");
221         StreamString command;
222         command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
223         int status;
224         RunShellCommand(command.GetData(),
225                         NULL,
226                         &status,
227                         NULL,
228                         NULL,
229                         10);
230         if (status != 0)
231             return Error("unable to perform copy");
232         if (uid == UINT32_MAX && gid == UINT32_MAX)
233             return Error();
234         if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
235             return Error("unable to perform chown");
236         return Error();
237     }
238     else if (m_remote_platform_sp)
239     {
240         if (GetSupportsRSync())
241         {
242             std::string src_path (source.GetPath());
243             if (src_path.empty())
244                 return Error("unable to get file path for source");
245             std::string dst_path (destination.GetPath());
246             if (dst_path.empty())
247                 return Error("unable to get file path for destination");
248             StreamString command;
249             if (GetIgnoresRemoteHostname())
250             {
251                 if (!GetRSyncPrefix())
252                     command.Printf("rsync %s %s %s",
253                                    GetRSyncOpts(),
254                                    src_path.c_str(),
255                                    dst_path.c_str());
256                 else
257                     command.Printf("rsync %s %s %s%s",
258                                    GetRSyncOpts(),
259                                    src_path.c_str(),
260                                    GetRSyncPrefix(),
261                                    dst_path.c_str());
262             }
263             else
264                 command.Printf("rsync %s %s %s:%s",
265                                GetRSyncOpts(),
266                                src_path.c_str(),
267                                GetHostname(),
268                                dst_path.c_str());
269             if (log)
270                 log->Printf("[PutFile] Running command: %s\n", command.GetData());
271             int retcode;
272             Host::RunShellCommand(command.GetData(),
273                                   NULL,
274                                   &retcode,
275                                   NULL,
276                                   NULL,
277                                   60);
278             if (retcode == 0)
279             {
280                 // Don't chown a local file for a remote system
281 //                if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
282 //                    return Error("unable to perform chown");
283                 return Error();
284             }
285             // if we are still here rsync has failed - let's try the slow way before giving up
286         }
287 
288         if (log)
289             log->Printf ("PlatformPOSIX::PutFile(src='%s', dst='%s', uid=%u, gid=%u)",
290                          source.GetPath().c_str(),
291                          destination.GetPath().c_str(),
292                          uid,
293                          gid); // REMOVE THIS PRINTF PRIOR TO CHECKIN
294         // open
295         // read, write, read, write, ...
296         // close
297         // chown uid:gid dst
298         if (log)
299             log->Printf("[PutFile] Using block by block transfer....\n");
300 
301         uint32_t source_open_options = File::eOpenOptionRead;
302         if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink)
303             source_open_options |= File::eOpenoptionDontFollowSymlinks;
304 
305         File source_file(source, source_open_options, lldb::eFilePermissionsUserRW);
306         Error error;
307         uint32_t permissions = source_file.GetPermissions(error);
308         if (permissions == 0)
309             permissions = lldb::eFilePermissionsFileDefault;
310 
311         if (!source_file.IsValid())
312             return Error("unable to open source file");
313         lldb::user_id_t dest_file = OpenFile (destination,
314                                               File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
315                                               permissions,
316                                               error);
317         if (log)
318             log->Printf ("dest_file = %" PRIu64 "\n", dest_file);
319         if (error.Fail())
320             return error;
321         if (dest_file == UINT64_MAX)
322             return Error("unable to open target file");
323         lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
324         uint64_t offset = 0;
325         while (error.Success())
326         {
327             size_t bytes_read = buffer_sp->GetByteSize();
328             error = source_file.Read(buffer_sp->GetBytes(), bytes_read);
329             if (bytes_read)
330             {
331                 WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);
332                 offset += bytes_read;
333             }
334             else
335                 break;
336         }
337         CloseFile(dest_file, error);
338         if (uid == UINT32_MAX && gid == UINT32_MAX)
339             return error;
340         // This is remopve, don't chown a local file...
341 //        std::string dst_path (destination.GetPath());
342 //        if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
343 //            return Error("unable to perform chown");
344         return error;
345     }
346     return Platform::PutFile(source,destination,uid,gid);
347 }
348 
349 lldb::user_id_t
350 PlatformPOSIX::GetFileSize (const FileSpec& file_spec)
351 {
352     if (IsHost())
353         return Host::GetFileSize(file_spec);
354     else if (m_remote_platform_sp)
355         return m_remote_platform_sp->GetFileSize(file_spec);
356     else
357         return Platform::GetFileSize(file_spec);
358 }
359 
360 Error
361 PlatformPOSIX::CreateSymlink(const char *src, const char *dst)
362 {
363     if (IsHost())
364         return Host::Symlink(src, dst);
365     else if (m_remote_platform_sp)
366         return m_remote_platform_sp->CreateSymlink(src, dst);
367     else
368         return Platform::CreateSymlink(src, dst);
369 }
370 
371 bool
372 PlatformPOSIX::GetFileExists (const FileSpec& file_spec)
373 {
374     if (IsHost())
375         return file_spec.Exists();
376     else if (m_remote_platform_sp)
377         return m_remote_platform_sp->GetFileExists(file_spec);
378     else
379         return Platform::GetFileExists(file_spec);
380 }
381 
382 Error
383 PlatformPOSIX::Unlink (const char *path)
384 {
385     if (IsHost())
386         return Host::Unlink (path);
387     else if (m_remote_platform_sp)
388         return m_remote_platform_sp->Unlink(path);
389     else
390         return Platform::Unlink(path);
391 }
392 
393 lldb_private::Error
394 PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */,
395                         const lldb_private::FileSpec& destination /* local file path */)
396 {
397     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
398 
399     // Check the args, first.
400     std::string src_path (source.GetPath());
401     if (src_path.empty())
402         return Error("unable to get file path for source");
403     std::string dst_path (destination.GetPath());
404     if (dst_path.empty())
405         return Error("unable to get file path for destination");
406     if (IsHost())
407     {
408         if (FileSpec::Equal(source, destination, true))
409             return Error("local scenario->source and destination are the same file path: no operation performed");
410         // cp src dst
411         StreamString cp_command;
412         cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
413         int status;
414         RunShellCommand(cp_command.GetData(),
415                         NULL,
416                         &status,
417                         NULL,
418                         NULL,
419                         10);
420         if (status != 0)
421             return Error("unable to perform copy");
422         return Error();
423     }
424     else if (m_remote_platform_sp)
425     {
426         if (GetSupportsRSync())
427         {
428             StreamString command;
429             if (GetIgnoresRemoteHostname())
430             {
431                 if (!GetRSyncPrefix())
432                     command.Printf("rsync %s %s %s",
433                                    GetRSyncOpts(),
434                                    src_path.c_str(),
435                                    dst_path.c_str());
436                 else
437                     command.Printf("rsync %s %s%s %s",
438                                    GetRSyncOpts(),
439                                    GetRSyncPrefix(),
440                                    src_path.c_str(),
441                                    dst_path.c_str());
442             }
443             else
444                 command.Printf("rsync %s %s:%s %s",
445                                GetRSyncOpts(),
446                                m_remote_platform_sp->GetHostname(),
447                                src_path.c_str(),
448                                dst_path.c_str());
449             if (log)
450                 log->Printf("[GetFile] Running command: %s\n", command.GetData());
451             int retcode;
452             Host::RunShellCommand(command.GetData(),
453                                   NULL,
454                                   &retcode,
455                                   NULL,
456                                   NULL,
457                                   60);
458             if (retcode == 0)
459                 return Error();
460             // If we are here, rsync has failed - let's try the slow way before giving up
461         }
462         // open src and dst
463         // read/write, read/write, read/write, ...
464         // close src
465         // close dst
466         if (log)
467             log->Printf("[GetFile] Using block by block transfer....\n");
468         Error error;
469         user_id_t fd_src = OpenFile (source,
470                                      File::eOpenOptionRead,
471                                      lldb::eFilePermissionsFileDefault,
472                                      error);
473 
474         if (fd_src == UINT64_MAX)
475             return Error("unable to open source file");
476 
477         uint32_t permissions = 0;
478         error = GetFilePermissions(source.GetPath().c_str(), permissions);
479 
480         if (permissions == 0)
481             permissions = lldb::eFilePermissionsFileDefault;
482 
483         user_id_t fd_dst = Host::OpenFile(destination,
484                                           File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
485                                           permissions,
486                                           error);
487 
488         if (fd_dst == UINT64_MAX)
489         {
490             if (error.Success())
491                 error.SetErrorString("unable to open destination file");
492         }
493 
494         if (error.Success())
495         {
496             lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
497             uint64_t offset = 0;
498             error.Clear();
499             while (error.Success())
500             {
501                 const uint64_t n_read = ReadFile (fd_src,
502                                                   offset,
503                                                   buffer_sp->GetBytes(),
504                                                   buffer_sp->GetByteSize(),
505                                                   error);
506                 if (error.Fail())
507                     break;
508                 if (n_read == 0)
509                     break;
510                 if (Host::WriteFile(fd_dst,
511                                     offset,
512                                     buffer_sp->GetBytes(),
513                                     n_read,
514                                     error) != n_read)
515                 {
516                     if (!error.Fail())
517                         error.SetErrorString("unable to write to destination file");
518                         break;
519                 }
520                 offset += n_read;
521             }
522         }
523         // Ignore the close error of src.
524         if (fd_src != UINT64_MAX)
525             CloseFile(fd_src, error);
526         // And close the dst file descriptot.
527         if (fd_dst != UINT64_MAX && !Host::CloseFile(fd_dst, error))
528         {
529             if (!error.Fail())
530                 error.SetErrorString("unable to close destination file");
531 
532         }
533         return error;
534     }
535     return Platform::GetFile(source,destination);
536 }
537 
538 std::string
539 PlatformPOSIX::GetPlatformSpecificConnectionInformation()
540 {
541     StreamString stream;
542     if (GetSupportsRSync())
543     {
544         stream.PutCString("rsync");
545         if ( (GetRSyncOpts() && *GetRSyncOpts()) ||
546              (GetRSyncPrefix() && *GetRSyncPrefix()) ||
547              GetIgnoresRemoteHostname())
548         {
549             stream.Printf(", options: ");
550             if (GetRSyncOpts() && *GetRSyncOpts())
551                 stream.Printf("'%s' ",GetRSyncOpts());
552             stream.Printf(", prefix: ");
553             if (GetRSyncPrefix() && *GetRSyncPrefix())
554                 stream.Printf("'%s' ",GetRSyncPrefix());
555             if (GetIgnoresRemoteHostname())
556                 stream.Printf("ignore remote-hostname ");
557         }
558     }
559     if (GetSupportsSSH())
560     {
561         stream.PutCString("ssh");
562         if (GetSSHOpts() && *GetSSHOpts())
563             stream.Printf(", options: '%s' ",GetSSHOpts());
564     }
565     if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
566         stream.Printf("cache dir: %s",GetLocalCacheDirectory());
567     if (stream.GetSize())
568         return stream.GetData();
569     else
570         return "";
571 }
572 
573 bool
574 PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec,
575                             uint64_t &low,
576                             uint64_t &high)
577 {
578     if (IsHost())
579         return Platform::CalculateMD5 (file_spec, low, high);
580     if (m_remote_platform_sp)
581         return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
582     return false;
583 }
584 
585 lldb_private::ConstString
586 PlatformPOSIX::GetRemoteWorkingDirectory()
587 {
588     if (IsRemote() && m_remote_platform_sp)
589         return m_remote_platform_sp->GetRemoteWorkingDirectory();
590     else
591         return Platform::GetRemoteWorkingDirectory();
592 }
593 
594 bool
595 PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path)
596 {
597     if (IsRemote() && m_remote_platform_sp)
598         return m_remote_platform_sp->SetRemoteWorkingDirectory(path);
599     else
600         return Platform::SetRemoteWorkingDirectory(path);
601 }
602 
603 bool
604 PlatformPOSIX::GetRemoteOSVersion ()
605 {
606     if (m_remote_platform_sp)
607         return m_remote_platform_sp->GetOSVersion (m_major_os_version,
608                                                    m_minor_os_version,
609                                                    m_update_os_version);
610     return false;
611 }
612 
613 bool
614 PlatformPOSIX::GetRemoteOSBuildString (std::string &s)
615 {
616     if (m_remote_platform_sp)
617         return m_remote_platform_sp->GetRemoteOSBuildString (s);
618     s.clear();
619     return false;
620 }
621 
622 bool
623 PlatformPOSIX::GetRemoteOSKernelDescription (std::string &s)
624 {
625     if (m_remote_platform_sp)
626         return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
627     s.clear();
628     return false;
629 }
630 
631 // Remote Platform subclasses need to override this function
632 ArchSpec
633 PlatformPOSIX::GetRemoteSystemArchitecture ()
634 {
635     if (m_remote_platform_sp)
636         return m_remote_platform_sp->GetRemoteSystemArchitecture ();
637     return ArchSpec();
638 }
639 
640 const char *
641 PlatformPOSIX::GetHostname ()
642 {
643     if (IsHost())
644         return Platform::GetHostname();
645 
646     if (m_remote_platform_sp)
647         return m_remote_platform_sp->GetHostname ();
648     return NULL;
649 }
650 
651 const char *
652 PlatformPOSIX::GetUserName (uint32_t uid)
653 {
654     // Check the cache in Platform in case we have already looked this uid up
655     const char *user_name = Platform::GetUserName(uid);
656     if (user_name)
657         return user_name;
658 
659     if (IsRemote() && m_remote_platform_sp)
660         return m_remote_platform_sp->GetUserName(uid);
661     return NULL;
662 }
663 
664 const char *
665 PlatformPOSIX::GetGroupName (uint32_t gid)
666 {
667     const char *group_name = Platform::GetGroupName(gid);
668     if (group_name)
669         return group_name;
670 
671     if (IsRemote() && m_remote_platform_sp)
672         return m_remote_platform_sp->GetGroupName(gid);
673     return NULL;
674 }
675 
676 Error
677 PlatformPOSIX::ConnectRemote (Args& args)
678 {
679     Error error;
680     if (IsHost())
681     {
682         error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
683     }
684     else
685     {
686         if (!m_remote_platform_sp)
687             m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
688 
689         if (m_remote_platform_sp && error.Success())
690             error = m_remote_platform_sp->ConnectRemote (args);
691         else
692             error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
693 
694         if (error.Fail())
695             m_remote_platform_sp.reset();
696     }
697 
698     if (error.Success() && m_remote_platform_sp)
699     {
700         if (m_options.get())
701         {
702             OptionGroupOptions* options = m_options.get();
703             OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r');
704             OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s');
705             OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c');
706 
707             if (m_rsync_options->m_rsync)
708             {
709                 SetSupportsRSync(true);
710                 SetRSyncOpts(m_rsync_options->m_rsync_opts.c_str());
711                 SetRSyncPrefix(m_rsync_options->m_rsync_prefix.c_str());
712                 SetIgnoresRemoteHostname(m_rsync_options->m_ignores_remote_hostname);
713             }
714             if (m_ssh_options->m_ssh)
715             {
716                 SetSupportsSSH(true);
717                 SetSSHOpts(m_ssh_options->m_ssh_opts.c_str());
718             }
719             SetLocalCacheDirectory(m_cache_options->m_cache_dir.c_str());
720         }
721     }
722 
723     return error;
724 }
725 
726 Error
727 PlatformPOSIX::DisconnectRemote ()
728 {
729     Error error;
730 
731     if (IsHost())
732     {
733         error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString());
734     }
735     else
736     {
737         if (m_remote_platform_sp)
738             error = m_remote_platform_sp->DisconnectRemote ();
739         else
740             error.SetErrorString ("the platform is not currently connected");
741     }
742     return error;
743 }
744 
745 lldb::ProcessSP
746 PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info,
747                               Debugger &debugger,
748                               Target *target,       // Can be NULL, if NULL create a new target, else use existing one
749                               Listener &listener,
750                               Error &error)
751 {
752     ProcessSP process_sp;
753 
754     if (IsHost())
755     {
756         // We are going to hand this process off to debugserver which will be in charge of setting the exit status.
757         // We still need to reap it from lldb but if we let the monitor thread also set the exit status, we set up a
758         // race between debugserver & us for who will find out about the debugged process's death.
759         launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus);
760         process_sp = Platform::DebugProcess (launch_info, debugger, target, listener, error);
761     }
762     else
763     {
764         if (m_remote_platform_sp)
765             process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, listener, error);
766         else
767             error.SetErrorString ("the platform is not currently connected");
768     }
769     return process_sp;
770 
771 }
772 
773 void
774 PlatformPOSIX::CalculateTrapHandlerSymbolNames ()
775 {
776     m_trap_handlers.push_back (ConstString ("_sigtramp"));
777 }
778