PlatformRemoteGDBServer.cpp revision 263367
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::GetFile (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#if 0
269                    m_gdb_client.TestPacketSpeed(10000);
270#endif
271                }
272                else
273                {
274                    m_gdb_client.Disconnect();
275                    if (error.Success())
276                        error.SetErrorString("handshake failed");
277                }
278            }
279        }
280        else
281        {
282            error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
283        }
284    }
285
286    return error;
287}
288
289Error
290PlatformRemoteGDBServer::DisconnectRemote ()
291{
292    Error error;
293    m_gdb_client.Disconnect(&error);
294    return error;
295}
296
297const char *
298PlatformRemoteGDBServer::GetHostname ()
299{
300    m_gdb_client.GetHostname (m_name);
301    if (m_name.empty())
302        return NULL;
303    return m_name.c_str();
304}
305
306const char *
307PlatformRemoteGDBServer::GetUserName (uint32_t uid)
308{
309    // Try and get a cache user name first
310    const char *cached_user_name = Platform::GetUserName(uid);
311    if (cached_user_name)
312        return cached_user_name;
313    std::string name;
314    if (m_gdb_client.GetUserName(uid, name))
315        return SetCachedUserName(uid, name.c_str(), name.size());
316
317    SetUserNameNotFound(uid); // Negative cache so we don't keep sending packets
318    return NULL;
319}
320
321const char *
322PlatformRemoteGDBServer::GetGroupName (uint32_t gid)
323{
324    const char *cached_group_name = Platform::GetGroupName(gid);
325    if (cached_group_name)
326        return cached_group_name;
327    std::string name;
328    if (m_gdb_client.GetGroupName(gid, name))
329        return SetCachedGroupName(gid, name.c_str(), name.size());
330
331    SetGroupNameNotFound(gid); // Negative cache so we don't keep sending packets
332    return NULL;
333}
334
335uint32_t
336PlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info,
337                                        ProcessInstanceInfoList &process_infos)
338{
339    return m_gdb_client.FindProcesses (match_info, process_infos);
340}
341
342bool
343PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
344{
345    return m_gdb_client.GetProcessInfo (pid, process_info);
346}
347
348
349Error
350PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
351{
352    Error error;
353    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
354
355    m_gdb_client.SetSTDIN ("/dev/null");
356    m_gdb_client.SetSTDOUT ("/dev/null");
357    m_gdb_client.SetSTDERR ("/dev/null");
358    m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
359
360    const char *working_dir = launch_info.GetWorkingDirectory();
361    if (working_dir && working_dir[0])
362    {
363        m_gdb_client.SetWorkingDir (working_dir);
364    }
365
366    // Send the environment and the program + arguments after we connect
367    const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector();
368
369    if (envp)
370    {
371        const char *env_entry;
372        for (int i=0; (env_entry = envp[i]); ++i)
373        {
374            if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
375                break;
376        }
377    }
378
379    ArchSpec arch_spec = launch_info.GetArchitecture();
380    const char *arch_triple = arch_spec.GetTriple().str().c_str();
381
382    m_gdb_client.SendLaunchArchPacket(arch_triple);
383
384    const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
385    int arg_packet_err = m_gdb_client.SendArgumentsPacket (launch_info);
386    m_gdb_client.SetPacketTimeout (old_packet_timeout);
387    if (arg_packet_err == 0)
388    {
389        std::string error_str;
390        if (m_gdb_client.GetLaunchSuccess (error_str))
391        {
392            pid = m_gdb_client.GetCurrentProcessID ();
393            if (pid != LLDB_INVALID_PROCESS_ID)
394                launch_info.SetProcessID (pid);
395        }
396        else
397        {
398            error.SetErrorString (error_str.c_str());
399        }
400    }
401    else
402    {
403        error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
404    }
405    return error;
406}
407
408lldb::ProcessSP
409PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_info,
410                                       lldb_private::Debugger &debugger,
411                                       lldb_private::Target *target,       // Can be NULL, if NULL create a new target, else use existing one
412                                       lldb_private::Listener &listener,
413                                       lldb_private::Error &error)
414{
415    lldb::ProcessSP process_sp;
416    if (IsRemote())
417    {
418        if (IsConnected())
419        {
420            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
421            uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid);
422
423            if (port == 0)
424            {
425                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
426            }
427            else
428            {
429                if (target == NULL)
430                {
431                    TargetSP new_target_sp;
432
433                    error = debugger.GetTargetList().CreateTarget (debugger,
434                                                                   NULL,
435                                                                   NULL,
436                                                                   false,
437                                                                   NULL,
438                                                                   new_target_sp);
439                    target = new_target_sp.get();
440                }
441                else
442                    error.Clear();
443
444                if (target && error.Success())
445                {
446                    debugger.GetTargetList().SetSelectedTarget(target);
447
448                    // The darwin always currently uses the GDB remote debugger plug-in
449                    // so even when debugging locally we are debugging remotely!
450                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
451
452                    if (process_sp)
453                    {
454                        char connect_url[256];
455                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
456                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
457                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
458                        const int connect_url_len = ::snprintf (connect_url,
459                                                                sizeof(connect_url),
460                                                                "connect://%s:%u",
461                                                                override_hostname ? override_hostname : GetHostname (),
462                                                                port + port_offset);
463                        assert (connect_url_len < (int)sizeof(connect_url));
464                        error = process_sp->ConnectRemote (NULL, connect_url);
465                        if (error.Success())
466                            error = process_sp->Launch(launch_info);
467                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
468                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
469                    }
470                }
471            }
472        }
473        else
474        {
475            error.SetErrorString("not connected to remote gdb server");
476        }
477    }
478    return process_sp;
479
480}
481
482lldb::ProcessSP
483PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
484                                 Debugger &debugger,
485                                 Target *target,       // Can be NULL, if NULL create a new target, else use existing one
486                                 Listener &listener,
487                                 Error &error)
488{
489    lldb::ProcessSP process_sp;
490    if (IsRemote())
491    {
492        if (IsConnected())
493        {
494            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
495            uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid);
496
497            if (port == 0)
498            {
499                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
500            }
501            else
502            {
503                if (target == NULL)
504                {
505                    TargetSP new_target_sp;
506
507                    error = debugger.GetTargetList().CreateTarget (debugger,
508                                                                   NULL,
509                                                                   NULL,
510                                                                   false,
511                                                                   NULL,
512                                                                   new_target_sp);
513                    target = new_target_sp.get();
514                }
515                else
516                    error.Clear();
517
518                if (target && error.Success())
519                {
520                    debugger.GetTargetList().SetSelectedTarget(target);
521
522                    // The darwin always currently uses the GDB remote debugger plug-in
523                    // so even when debugging locally we are debugging remotely!
524                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
525
526                    if (process_sp)
527                    {
528                        char connect_url[256];
529                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
530                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
531                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
532                        const int connect_url_len = ::snprintf (connect_url,
533                                                                sizeof(connect_url),
534                                                                "connect://%s:%u",
535                                                                override_hostname ? override_hostname : GetHostname (),
536                                                                port + port_offset);
537                        assert (connect_url_len < (int)sizeof(connect_url));
538                        error = process_sp->ConnectRemote (NULL, connect_url);
539                        if (error.Success())
540                            error = process_sp->Attach(attach_info);
541                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
542                        {
543                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
544                        }
545                    }
546                }
547            }
548        }
549        else
550        {
551            error.SetErrorString("not connected to remote gdb server");
552        }
553    }
554    return process_sp;
555}
556
557Error
558PlatformRemoteGDBServer::MakeDirectory (const char *path, uint32_t mode)
559{
560    Error error = m_gdb_client.MakeDirectory(path,mode);
561    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
562    if (log)
563        log->Printf ("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) error = %u (%s)", path, mode, error.GetError(), error.AsCString());
564    return error;
565}
566
567
568Error
569PlatformRemoteGDBServer::GetFilePermissions (const char *path, uint32_t &file_permissions)
570{
571    Error error = m_gdb_client.GetFilePermissions(path, file_permissions);
572    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
573    if (log)
574        log->Printf ("PlatformRemoteGDBServer::GetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString());
575    return error;
576}
577
578Error
579PlatformRemoteGDBServer::SetFilePermissions (const char *path, uint32_t file_permissions)
580{
581    Error error = m_gdb_client.SetFilePermissions(path, file_permissions);
582    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
583    if (log)
584        log->Printf ("PlatformRemoteGDBServer::SetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString());
585    return error;
586}
587
588
589lldb::user_id_t
590PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec,
591                                   uint32_t flags,
592                                   uint32_t mode,
593                                   Error &error)
594{
595    return m_gdb_client.OpenFile (file_spec, flags, mode, error);
596}
597
598bool
599PlatformRemoteGDBServer::CloseFile (lldb::user_id_t fd, Error &error)
600{
601    return m_gdb_client.CloseFile (fd, error);
602}
603
604lldb::user_id_t
605PlatformRemoteGDBServer::GetFileSize (const lldb_private::FileSpec& file_spec)
606{
607    return m_gdb_client.GetFileSize(file_spec);
608}
609
610uint64_t
611PlatformRemoteGDBServer::ReadFile (lldb::user_id_t fd,
612                                   uint64_t offset,
613                                   void *dst,
614                                   uint64_t dst_len,
615                                   Error &error)
616{
617    return m_gdb_client.ReadFile (fd, offset, dst, dst_len, error);
618}
619
620uint64_t
621PlatformRemoteGDBServer::WriteFile (lldb::user_id_t fd,
622                                    uint64_t offset,
623                                    const void* src,
624                                    uint64_t src_len,
625                                    Error &error)
626{
627    return m_gdb_client.WriteFile (fd, offset, src, src_len, error);
628}
629
630lldb_private::Error
631PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source,
632         const lldb_private::FileSpec& destination,
633         uint32_t uid,
634         uint32_t gid)
635{
636    return Platform::PutFile(source,destination,uid,gid);
637}
638
639Error
640PlatformRemoteGDBServer::CreateSymlink (const char *src,    // The name of the link is in src
641                                        const char *dst)    // The symlink points to dst
642{
643    Error error = m_gdb_client.CreateSymlink (src, dst);
644    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
645    if (log)
646        log->Printf ("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') error = %u (%s)", src, dst, error.GetError(), error.AsCString());
647    return error;
648}
649
650Error
651PlatformRemoteGDBServer::Unlink (const char *path)
652{
653    Error error = m_gdb_client.Unlink (path);
654    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
655    if (log)
656        log->Printf ("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", path, error.GetError(), error.AsCString());
657    return error;
658}
659
660bool
661PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec)
662{
663    return m_gdb_client.GetFileExists (file_spec);
664}
665
666lldb_private::Error
667PlatformRemoteGDBServer::RunShellCommand (const char *command,           // Shouldn't be NULL
668                                          const char *working_dir,       // Pass NULL to use the current working directory
669                                          int *status_ptr,               // Pass NULL if you don't want the process exit status
670                                          int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
671                                          std::string *command_output,   // Pass NULL if you don't want the command output
672                                          uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish
673{
674    return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
675}
676