PlatformRemoteGDBServer.cpp revision 263363
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
197bool
198PlatformRemoteGDBServer::IsConnected () const
199{
200    return m_gdb_client.IsConnected();
201}
202
203Error
204PlatformRemoteGDBServer::ConnectRemote (Args& args)
205{
206    Error error;
207    if (IsConnected())
208    {
209        error.SetErrorStringWithFormat ("the platform is already connected to '%s', execute 'platform disconnect' to close the current connection",
210                                        GetHostname());
211    }
212    else
213    {
214        if (args.GetArgumentCount() == 1)
215        {
216            const char *url = args.GetArgumentAtIndex(0);
217            m_gdb_client.SetConnection (new ConnectionFileDescriptor());
218            const ConnectionStatus status = m_gdb_client.Connect(url, &error);
219            if (status == eConnectionStatusSuccess)
220            {
221                if (m_gdb_client.HandshakeWithServer(&error))
222                {
223                    m_gdb_client.QueryNoAckModeSupported();
224                    m_gdb_client.GetHostInfo();
225#if 0
226                    m_gdb_client.TestPacketSpeed(10000);
227#endif
228                }
229                else
230                {
231                    m_gdb_client.Disconnect();
232                }
233            }
234        }
235        else
236        {
237            error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
238        }
239    }
240
241    if (error.Success())
242    {
243
244    }
245
246    return error;
247}
248
249Error
250PlatformRemoteGDBServer::DisconnectRemote ()
251{
252    Error error;
253    m_gdb_client.Disconnect(&error);
254    return error;
255}
256
257const char *
258PlatformRemoteGDBServer::GetHostname ()
259{
260    m_gdb_client.GetHostname (m_name);
261    if (m_name.empty())
262        return NULL;
263    return m_name.c_str();
264}
265
266const char *
267PlatformRemoteGDBServer::GetUserName (uint32_t uid)
268{
269    // Try and get a cache user name first
270    const char *cached_user_name = Platform::GetUserName(uid);
271    if (cached_user_name)
272        return cached_user_name;
273    std::string name;
274    if (m_gdb_client.GetUserName(uid, name))
275        return SetCachedUserName(uid, name.c_str(), name.size());
276
277    SetUserNameNotFound(uid); // Negative cache so we don't keep sending packets
278    return NULL;
279}
280
281const char *
282PlatformRemoteGDBServer::GetGroupName (uint32_t gid)
283{
284    const char *cached_group_name = Platform::GetGroupName(gid);
285    if (cached_group_name)
286        return cached_group_name;
287    std::string name;
288    if (m_gdb_client.GetGroupName(gid, name))
289        return SetCachedGroupName(gid, name.c_str(), name.size());
290
291    SetGroupNameNotFound(gid); // Negative cache so we don't keep sending packets
292    return NULL;
293}
294
295uint32_t
296PlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info,
297                                        ProcessInstanceInfoList &process_infos)
298{
299    return m_gdb_client.FindProcesses (match_info, process_infos);
300}
301
302bool
303PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
304{
305    return m_gdb_client.GetProcessInfo (pid, process_info);
306}
307
308
309Error
310PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
311{
312    Error error;
313    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
314
315    m_gdb_client.SetSTDIN ("/dev/null");
316    m_gdb_client.SetSTDOUT ("/dev/null");
317    m_gdb_client.SetSTDERR ("/dev/null");
318    m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
319
320    const char *working_dir = launch_info.GetWorkingDirectory();
321    if (working_dir && working_dir[0])
322    {
323        m_gdb_client.SetWorkingDir (working_dir);
324    }
325
326    // Send the environment and the program + arguments after we connect
327    const char **argv = launch_info.GetArguments().GetConstArgumentVector();
328    const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector();
329
330    if (envp)
331    {
332        const char *env_entry;
333        for (int i=0; (env_entry = envp[i]); ++i)
334        {
335            if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
336                break;
337        }
338    }
339
340    ArchSpec arch_spec = launch_info.GetArchitecture();
341    const char *arch_triple = arch_spec.GetTriple().str().c_str();
342
343    m_gdb_client.SendLaunchArchPacket(arch_triple);
344
345    const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
346    int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv);
347    m_gdb_client.SetPacketTimeout (old_packet_timeout);
348    if (arg_packet_err == 0)
349    {
350        std::string error_str;
351        if (m_gdb_client.GetLaunchSuccess (error_str))
352        {
353            pid = m_gdb_client.GetCurrentProcessID ();
354            if (pid != LLDB_INVALID_PROCESS_ID)
355                launch_info.SetProcessID (pid);
356        }
357        else
358        {
359            error.SetErrorString (error_str.c_str());
360        }
361    }
362    else
363    {
364        error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
365    }
366    return error;
367}
368
369lldb::ProcessSP
370PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
371                                 Debugger &debugger,
372                                 Target *target,       // Can be NULL, if NULL create a new target, else use existing one
373                                 Listener &listener,
374                                 Error &error)
375{
376    lldb::ProcessSP process_sp;
377    if (IsRemote())
378    {
379        if (IsConnected())
380        {
381            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
382            uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid);
383
384            if (port == 0)
385            {
386                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
387            }
388            else
389            {
390                if (target == NULL)
391                {
392                    TargetSP new_target_sp;
393
394                    error = debugger.GetTargetList().CreateTarget (debugger,
395                                                                   NULL,
396                                                                   NULL,
397                                                                   false,
398                                                                   NULL,
399                                                                   new_target_sp);
400                    target = new_target_sp.get();
401                }
402                else
403                    error.Clear();
404
405                if (target && error.Success())
406                {
407                    debugger.GetTargetList().SetSelectedTarget(target);
408
409                    // The darwin always currently uses the GDB remote debugger plug-in
410                    // so even when debugging locally we are debugging remotely!
411                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
412
413                    if (process_sp)
414                    {
415                        char connect_url[256];
416                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
417                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
418                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
419                        const int connect_url_len = ::snprintf (connect_url,
420                                                                sizeof(connect_url),
421                                                                "connect://%s:%u",
422                                                                override_hostname ? override_hostname : GetHostname (),
423                                                                port + port_offset);
424                        assert (connect_url_len < (int)sizeof(connect_url));
425                        error = process_sp->ConnectRemote (NULL, connect_url);
426                        if (error.Success())
427                            error = process_sp->Attach(attach_info);
428                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
429                        {
430                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
431                        }
432                    }
433                }
434            }
435        }
436        else
437        {
438            error.SetErrorString("not connected to remote gdb server");
439        }
440    }
441    return process_sp;
442}
443
444uint32_t
445PlatformRemoteGDBServer::MakeDirectory (const std::string &path,
446                                        mode_t mode)
447{
448    return m_gdb_client.MakeDirectory(path,mode);
449}
450
451lldb::user_id_t
452PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec,
453                                   uint32_t flags,
454                                   mode_t mode,
455                                   Error &error)
456{
457    return m_gdb_client.OpenFile (file_spec, flags, mode, error);
458}
459
460bool
461PlatformRemoteGDBServer::CloseFile (lldb::user_id_t fd, Error &error)
462{
463    return m_gdb_client.CloseFile (fd, error);
464}
465
466lldb::user_id_t
467PlatformRemoteGDBServer::GetFileSize (const lldb_private::FileSpec& file_spec)
468{
469    return m_gdb_client.GetFileSize(file_spec);
470}
471
472uint32_t
473PlatformRemoteGDBServer::GetFilePermissions (const lldb_private::FileSpec &file_spec,
474                                             lldb_private::Error &error)
475{
476    return m_gdb_client.GetFilePermissions(file_spec, error);
477}
478
479uint64_t
480PlatformRemoteGDBServer::ReadFile (lldb::user_id_t fd,
481                                   uint64_t offset,
482                                   void *dst,
483                                   uint64_t dst_len,
484                                   Error &error)
485{
486    return m_gdb_client.ReadFile (fd, offset, dst, dst_len, error);
487}
488
489uint64_t
490PlatformRemoteGDBServer::WriteFile (lldb::user_id_t fd,
491                                    uint64_t offset,
492                                    const void* src,
493                                    uint64_t src_len,
494                                    Error &error)
495{
496    return m_gdb_client.WriteFile (fd, offset, src, src_len, error);
497}
498
499lldb_private::Error
500PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source,
501         const lldb_private::FileSpec& destination,
502         uint32_t uid,
503         uint32_t gid)
504{
505    return Platform::PutFile(source,destination,uid,gid);
506}
507
508bool
509PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec)
510{
511    return m_gdb_client.GetFileExists (file_spec);
512}
513
514lldb_private::Error
515PlatformRemoteGDBServer::RunShellCommand (const char *command,           // Shouldn't be NULL
516                                          const char *working_dir,       // Pass NULL to use the current working directory
517                                          int *status_ptr,               // Pass NULL if you don't want the process exit status
518                                          int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
519                                          std::string *command_output,   // Pass NULL if you don't want the command output
520                                          uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish
521{
522    return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
523}
524