1//===-- PlatformRemoteGDBServer.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 "lldb/lldb-python.h"
11
12#include "PlatformRemoteGDBServer.h"
13#include "lldb/Host/Config.h"
14
15// C Includes
16#ifndef LLDB_DISABLE_POSIX
17#include <sys/sysctl.h>
18#endif
19
20// C++ Includes
21// Other libraries and framework includes
22// Project includes
23#include "lldb/Breakpoint/BreakpointLocation.h"
24#include "lldb/Core/ConnectionFileDescriptor.h"
25#include "lldb/Core/Debugger.h"
26#include "lldb/Core/Error.h"
27#include "lldb/Core/Module.h"
28#include "lldb/Core/ModuleList.h"
29#include "lldb/Core/PluginManager.h"
30#include "lldb/Core/StreamString.h"
31#include "lldb/Host/FileSpec.h"
32#include "lldb/Host/Host.h"
33#include "lldb/Target/Process.h"
34#include "lldb/Target/Target.h"
35
36using namespace lldb;
37using namespace lldb_private;
38
39static bool g_initialized = false;
40
41void
42PlatformRemoteGDBServer::Initialize ()
43{
44    if (g_initialized == false)
45    {
46        g_initialized = true;
47        PluginManager::RegisterPlugin (PlatformRemoteGDBServer::GetPluginNameStatic(),
48                                       PlatformRemoteGDBServer::GetDescriptionStatic(),
49                                       PlatformRemoteGDBServer::CreateInstance);
50    }
51}
52
53void
54PlatformRemoteGDBServer::Terminate ()
55{
56    if (g_initialized)
57    {
58        g_initialized = false;
59        PluginManager::UnregisterPlugin (PlatformRemoteGDBServer::CreateInstance);
60    }
61}
62
63Platform*
64PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
65{
66    bool create = force;
67    if (!create)
68    {
69        create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
70    }
71    if (create)
72        return new PlatformRemoteGDBServer ();
73    return NULL;
74}
75
76
77lldb_private::ConstString
78PlatformRemoteGDBServer::GetPluginNameStatic()
79{
80    static ConstString g_name("remote-gdb-server");
81    return g_name;
82}
83
84const char *
85PlatformRemoteGDBServer::GetDescriptionStatic()
86{
87    return "A platform that uses the GDB remote protocol as the communication transport.";
88}
89
90const char *
91PlatformRemoteGDBServer::GetDescription ()
92{
93    if (m_platform_description.empty())
94    {
95        if (IsConnected())
96        {
97            // Send the get description packet
98        }
99    }
100
101    if (!m_platform_description.empty())
102        return m_platform_description.c_str();
103    return GetDescriptionStatic();
104}
105
106Error
107PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file,
108                                            const ArchSpec &exe_arch,
109                                            lldb::ModuleSP &exe_module_sp,
110                                            const FileSpecList *module_search_paths_ptr)
111{
112    Error error;
113    //error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
114    if (m_gdb_client.GetFileExists(exe_file))
115        return error;
116    // TODO: get the remote end to somehow resolve this file
117    error.SetErrorString("file not found on remote end");
118    return error;
119}
120
121Error
122PlatformRemoteGDBServer::GetFileWithUUID (const FileSpec &platform_file,
123                                          const UUID *uuid_ptr,
124                                          FileSpec &local_file)
125{
126    // Default to the local case
127    local_file = platform_file;
128    return Error();
129}
130
131//------------------------------------------------------------------
132/// Default Constructor
133//------------------------------------------------------------------
134PlatformRemoteGDBServer::PlatformRemoteGDBServer () :
135    Platform(false), // This is a remote platform
136    m_gdb_client(true)
137{
138}
139
140//------------------------------------------------------------------
141/// Destructor.
142///
143/// The destructor is virtual since this class is designed to be
144/// inherited from by the plug-in instance.
145//------------------------------------------------------------------
146PlatformRemoteGDBServer::~PlatformRemoteGDBServer()
147{
148}
149
150bool
151PlatformRemoteGDBServer::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
152{
153    return false;
154}
155
156size_t
157PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
158{
159    // This isn't needed if the z/Z packets are supported in the GDB remote
160    // server. But we might need a packet to detect this.
161    return 0;
162}
163
164bool
165PlatformRemoteGDBServer::GetRemoteOSVersion ()
166{
167    uint32_t major, minor, update;
168    if (m_gdb_client.GetOSVersion (major, minor, update))
169    {
170        m_major_os_version = major;
171        m_minor_os_version = minor;
172        m_update_os_version = update;
173        return true;
174    }
175    return false;
176}
177
178bool
179PlatformRemoteGDBServer::GetRemoteOSBuildString (std::string &s)
180{
181    return m_gdb_client.GetOSBuildString (s);
182}
183
184bool
185PlatformRemoteGDBServer::GetRemoteOSKernelDescription (std::string &s)
186{
187    return m_gdb_client.GetOSKernelDescription (s);
188}
189
190// Remote Platform subclasses need to override this function
191ArchSpec
192PlatformRemoteGDBServer::GetRemoteSystemArchitecture ()
193{
194    return m_gdb_client.GetSystemArchitecture();
195}
196
197lldb_private::ConstString
198PlatformRemoteGDBServer::GetRemoteWorkingDirectory()
199{
200    if (IsConnected())
201    {
202        Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
203        std::string cwd;
204        if (m_gdb_client.GetWorkingDir(cwd))
205        {
206            ConstString working_dir(cwd.c_str());
207            if (log)
208                log->Printf("PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'", working_dir.GetCString());
209            return working_dir;
210        }
211        else
212        {
213            return ConstString();
214        }
215    }
216    else
217    {
218        return Platform::GetRemoteWorkingDirectory();
219    }
220}
221
222bool
223PlatformRemoteGDBServer::SetRemoteWorkingDirectory(const lldb_private::ConstString &path)
224{
225    if (IsConnected())
226    {
227        // Clear the working directory it case it doesn't get set correctly. This will
228        // for use to re-read it
229        Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
230        if (log)
231            log->Printf("PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')", path.GetCString());
232        return m_gdb_client.SetWorkingDir(path.GetCString()) == 0;
233    }
234    else
235        return Platform::SetRemoteWorkingDirectory(path);
236}
237
238bool
239PlatformRemoteGDBServer::IsConnected () const
240{
241    return m_gdb_client.IsConnected();
242}
243
244Error
245PlatformRemoteGDBServer::ConnectRemote (Args& args)
246{
247    Error error;
248    if (IsConnected())
249    {
250        error.SetErrorStringWithFormat ("the platform is already connected to '%s', execute 'platform disconnect' to close the current connection",
251                                        GetHostname());
252    }
253    else
254    {
255        if (args.GetArgumentCount() == 1)
256        {
257            const char *url = args.GetArgumentAtIndex(0);
258            m_gdb_client.SetConnection (new ConnectionFileDescriptor());
259            const ConnectionStatus status = m_gdb_client.Connect(url, &error);
260            if (status == eConnectionStatusSuccess)
261            {
262                if (m_gdb_client.HandshakeWithServer(&error))
263                {
264                    m_gdb_client.GetHostInfo();
265                    // If a working directory was set prior to connecting, send it down now
266                    if (m_working_dir)
267                        m_gdb_client.SetWorkingDir(m_working_dir.GetCString());
268                }
269                else
270                {
271                    m_gdb_client.Disconnect();
272                    if (error.Success())
273                        error.SetErrorString("handshake failed");
274                }
275            }
276        }
277        else
278        {
279            error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
280        }
281    }
282
283    return error;
284}
285
286Error
287PlatformRemoteGDBServer::DisconnectRemote ()
288{
289    Error error;
290    m_gdb_client.Disconnect(&error);
291    return error;
292}
293
294const char *
295PlatformRemoteGDBServer::GetHostname ()
296{
297    m_gdb_client.GetHostname (m_name);
298    if (m_name.empty())
299        return NULL;
300    return m_name.c_str();
301}
302
303const char *
304PlatformRemoteGDBServer::GetUserName (uint32_t uid)
305{
306    // Try and get a cache user name first
307    const char *cached_user_name = Platform::GetUserName(uid);
308    if (cached_user_name)
309        return cached_user_name;
310    std::string name;
311    if (m_gdb_client.GetUserName(uid, name))
312        return SetCachedUserName(uid, name.c_str(), name.size());
313
314    SetUserNameNotFound(uid); // Negative cache so we don't keep sending packets
315    return NULL;
316}
317
318const char *
319PlatformRemoteGDBServer::GetGroupName (uint32_t gid)
320{
321    const char *cached_group_name = Platform::GetGroupName(gid);
322    if (cached_group_name)
323        return cached_group_name;
324    std::string name;
325    if (m_gdb_client.GetGroupName(gid, name))
326        return SetCachedGroupName(gid, name.c_str(), name.size());
327
328    SetGroupNameNotFound(gid); // Negative cache so we don't keep sending packets
329    return NULL;
330}
331
332uint32_t
333PlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info,
334                                        ProcessInstanceInfoList &process_infos)
335{
336    return m_gdb_client.FindProcesses (match_info, process_infos);
337}
338
339bool
340PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
341{
342    return m_gdb_client.GetProcessInfo (pid, process_info);
343}
344
345
346Error
347PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
348{
349    Error error;
350    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
351
352    m_gdb_client.SetSTDIN ("/dev/null");
353    m_gdb_client.SetSTDOUT ("/dev/null");
354    m_gdb_client.SetSTDERR ("/dev/null");
355    m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
356
357    const char *working_dir = launch_info.GetWorkingDirectory();
358    if (working_dir && working_dir[0])
359    {
360        m_gdb_client.SetWorkingDir (working_dir);
361    }
362
363    // Send the environment and the program + arguments after we connect
364    const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector();
365
366    if (envp)
367    {
368        const char *env_entry;
369        for (int i=0; (env_entry = envp[i]); ++i)
370        {
371            if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
372                break;
373        }
374    }
375
376    ArchSpec arch_spec = launch_info.GetArchitecture();
377    const char *arch_triple = arch_spec.GetTriple().str().c_str();
378
379    m_gdb_client.SendLaunchArchPacket(arch_triple);
380
381    const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
382    int arg_packet_err = m_gdb_client.SendArgumentsPacket (launch_info);
383    m_gdb_client.SetPacketTimeout (old_packet_timeout);
384    if (arg_packet_err == 0)
385    {
386        std::string error_str;
387        if (m_gdb_client.GetLaunchSuccess (error_str))
388        {
389            pid = m_gdb_client.GetCurrentProcessID ();
390            if (pid != LLDB_INVALID_PROCESS_ID)
391                launch_info.SetProcessID (pid);
392        }
393        else
394        {
395            error.SetErrorString (error_str.c_str());
396        }
397    }
398    else
399    {
400        error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
401    }
402    return error;
403}
404
405lldb::ProcessSP
406PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_info,
407                                       lldb_private::Debugger &debugger,
408                                       lldb_private::Target *target,       // Can be NULL, if NULL create a new target, else use existing one
409                                       lldb_private::Listener &listener,
410                                       lldb_private::Error &error)
411{
412    lldb::ProcessSP process_sp;
413    if (IsRemote())
414    {
415        if (IsConnected())
416        {
417            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
418            ArchSpec remote_arch = GetRemoteSystemArchitecture();
419            llvm::Triple &remote_triple = remote_arch.GetTriple();
420            uint16_t port = 0;
421            if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS)
422            {
423                // When remote debugging to iOS, we use a USB mux that always talks
424                // to localhost, so we will need the remote debugserver to accept connections
425                // only from localhost, no matter what our current hostname is
426                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost");
427            }
428            else
429            {
430                // All other hosts should use their actual hostname
431                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL);
432            }
433
434            if (port == 0)
435            {
436                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
437            }
438            else
439            {
440                if (target == NULL)
441                {
442                    TargetSP new_target_sp;
443
444                    error = debugger.GetTargetList().CreateTarget (debugger,
445                                                                   NULL,
446                                                                   NULL,
447                                                                   false,
448                                                                   NULL,
449                                                                   new_target_sp);
450                    target = new_target_sp.get();
451                }
452                else
453                    error.Clear();
454
455                if (target && error.Success())
456                {
457                    debugger.GetTargetList().SetSelectedTarget(target);
458
459                    // The darwin always currently uses the GDB remote debugger plug-in
460                    // so even when debugging locally we are debugging remotely!
461                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
462
463                    if (process_sp)
464                    {
465                        char connect_url[256];
466                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
467                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
468                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
469                        const int connect_url_len = ::snprintf (connect_url,
470                                                                sizeof(connect_url),
471                                                                "connect://%s:%u",
472                                                                override_hostname ? override_hostname : GetHostname (),
473                                                                port + port_offset);
474                        assert (connect_url_len < (int)sizeof(connect_url));
475                        error = process_sp->ConnectRemote (NULL, connect_url);
476                        if (error.Success())
477                            error = process_sp->Launch(launch_info);
478                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
479                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
480                    }
481                }
482            }
483        }
484        else
485        {
486            error.SetErrorString("not connected to remote gdb server");
487        }
488    }
489    return process_sp;
490
491}
492
493lldb::ProcessSP
494PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
495                                 Debugger &debugger,
496                                 Target *target,       // Can be NULL, if NULL create a new target, else use existing one
497                                 Listener &listener,
498                                 Error &error)
499{
500    lldb::ProcessSP process_sp;
501    if (IsRemote())
502    {
503        if (IsConnected())
504        {
505            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
506            ArchSpec remote_arch = GetRemoteSystemArchitecture();
507            llvm::Triple &remote_triple = remote_arch.GetTriple();
508            uint16_t port = 0;
509            if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS)
510            {
511                // When remote debugging to iOS, we use a USB mux that always talks
512                // to localhost, so we will need the remote debugserver to accept connections
513                // only from localhost, no matter what our current hostname is
514                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost");
515            }
516            else
517            {
518                // All other hosts should use their actual hostname
519                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL);
520            }
521
522            if (port == 0)
523            {
524                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
525            }
526            else
527            {
528                if (target == NULL)
529                {
530                    TargetSP new_target_sp;
531
532                    error = debugger.GetTargetList().CreateTarget (debugger,
533                                                                   NULL,
534                                                                   NULL,
535                                                                   false,
536                                                                   NULL,
537                                                                   new_target_sp);
538                    target = new_target_sp.get();
539                }
540                else
541                    error.Clear();
542
543                if (target && error.Success())
544                {
545                    debugger.GetTargetList().SetSelectedTarget(target);
546
547                    // The darwin always currently uses the GDB remote debugger plug-in
548                    // so even when debugging locally we are debugging remotely!
549                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
550
551                    if (process_sp)
552                    {
553                        char connect_url[256];
554                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
555                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
556                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
557                        const int connect_url_len = ::snprintf (connect_url,
558                                                                sizeof(connect_url),
559                                                                "connect://%s:%u",
560                                                                override_hostname ? override_hostname : GetHostname (),
561                                                                port + port_offset);
562                        assert (connect_url_len < (int)sizeof(connect_url));
563                        error = process_sp->ConnectRemote (NULL, connect_url);
564                        if (error.Success())
565                            error = process_sp->Attach(attach_info);
566                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
567                        {
568                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
569                        }
570                    }
571                }
572            }
573        }
574        else
575        {
576            error.SetErrorString("not connected to remote gdb server");
577        }
578    }
579    return process_sp;
580}
581
582Error
583PlatformRemoteGDBServer::MakeDirectory (const char *path, uint32_t mode)
584{
585    Error error = m_gdb_client.MakeDirectory(path,mode);
586    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
587    if (log)
588        log->Printf ("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) error = %u (%s)", path, mode, error.GetError(), error.AsCString());
589    return error;
590}
591
592
593Error
594PlatformRemoteGDBServer::GetFilePermissions (const char *path, uint32_t &file_permissions)
595{
596    Error error = m_gdb_client.GetFilePermissions(path, file_permissions);
597    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
598    if (log)
599        log->Printf ("PlatformRemoteGDBServer::GetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString());
600    return error;
601}
602
603Error
604PlatformRemoteGDBServer::SetFilePermissions (const char *path, uint32_t file_permissions)
605{
606    Error error = m_gdb_client.SetFilePermissions(path, file_permissions);
607    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
608    if (log)
609        log->Printf ("PlatformRemoteGDBServer::SetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString());
610    return error;
611}
612
613
614lldb::user_id_t
615PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec,
616                                   uint32_t flags,
617                                   uint32_t mode,
618                                   Error &error)
619{
620    return m_gdb_client.OpenFile (file_spec, flags, mode, error);
621}
622
623bool
624PlatformRemoteGDBServer::CloseFile (lldb::user_id_t fd, Error &error)
625{
626    return m_gdb_client.CloseFile (fd, error);
627}
628
629lldb::user_id_t
630PlatformRemoteGDBServer::GetFileSize (const lldb_private::FileSpec& file_spec)
631{
632    return m_gdb_client.GetFileSize(file_spec);
633}
634
635uint64_t
636PlatformRemoteGDBServer::ReadFile (lldb::user_id_t fd,
637                                   uint64_t offset,
638                                   void *dst,
639                                   uint64_t dst_len,
640                                   Error &error)
641{
642    return m_gdb_client.ReadFile (fd, offset, dst, dst_len, error);
643}
644
645uint64_t
646PlatformRemoteGDBServer::WriteFile (lldb::user_id_t fd,
647                                    uint64_t offset,
648                                    const void* src,
649                                    uint64_t src_len,
650                                    Error &error)
651{
652    return m_gdb_client.WriteFile (fd, offset, src, src_len, error);
653}
654
655lldb_private::Error
656PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source,
657         const lldb_private::FileSpec& destination,
658         uint32_t uid,
659         uint32_t gid)
660{
661    return Platform::PutFile(source,destination,uid,gid);
662}
663
664Error
665PlatformRemoteGDBServer::CreateSymlink (const char *src,    // The name of the link is in src
666                                        const char *dst)    // The symlink points to dst
667{
668    Error error = m_gdb_client.CreateSymlink (src, dst);
669    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
670    if (log)
671        log->Printf ("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') error = %u (%s)", src, dst, error.GetError(), error.AsCString());
672    return error;
673}
674
675Error
676PlatformRemoteGDBServer::Unlink (const char *path)
677{
678    Error error = m_gdb_client.Unlink (path);
679    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
680    if (log)
681        log->Printf ("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", path, error.GetError(), error.AsCString());
682    return error;
683}
684
685bool
686PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec)
687{
688    return m_gdb_client.GetFileExists (file_spec);
689}
690
691lldb_private::Error
692PlatformRemoteGDBServer::RunShellCommand (const char *command,           // Shouldn't be NULL
693                                          const char *working_dir,       // Pass NULL to use the current working directory
694                                          int *status_ptr,               // Pass NULL if you don't want the process exit status
695                                          int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
696                                          std::string *command_output,   // Pass NULL if you don't want the command output
697                                          uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish
698{
699    return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
700}
701
702void
703PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames ()
704{
705    m_trap_handlers.push_back (ConstString ("_sigtramp"));
706}
707