1254721Semaste//===-- PlatformRemoteGDBServer.cpp -----------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/lldb-python.h"
11254721Semaste
12254721Semaste#include "PlatformRemoteGDBServer.h"
13254721Semaste
14254721Semaste// C Includes
15254721Semaste#include <sys/sysctl.h>
16254721Semaste
17254721Semaste// C++ Includes
18254721Semaste// Other libraries and framework includes
19254721Semaste// Project includes
20254721Semaste#include "lldb/Breakpoint/BreakpointLocation.h"
21254721Semaste#include "lldb/Core/ConnectionFileDescriptor.h"
22254721Semaste#include "lldb/Core/Debugger.h"
23254721Semaste#include "lldb/Core/Error.h"
24254721Semaste#include "lldb/Core/Module.h"
25254721Semaste#include "lldb/Core/ModuleList.h"
26254721Semaste#include "lldb/Core/PluginManager.h"
27254721Semaste#include "lldb/Core/StreamString.h"
28254721Semaste#include "lldb/Host/FileSpec.h"
29254721Semaste#include "lldb/Host/Host.h"
30254721Semaste#include "lldb/Target/Process.h"
31254721Semaste#include "lldb/Target/Target.h"
32254721Semaste
33254721Semasteusing namespace lldb;
34254721Semasteusing namespace lldb_private;
35254721Semaste
36254721Semastestatic bool g_initialized = false;
37254721Semaste
38254721Semastevoid
39254721SemastePlatformRemoteGDBServer::Initialize ()
40254721Semaste{
41254721Semaste    if (g_initialized == false)
42254721Semaste    {
43254721Semaste        g_initialized = true;
44254721Semaste        PluginManager::RegisterPlugin (PlatformRemoteGDBServer::GetPluginNameStatic(),
45254721Semaste                                       PlatformRemoteGDBServer::GetDescriptionStatic(),
46254721Semaste                                       PlatformRemoteGDBServer::CreateInstance);
47254721Semaste    }
48254721Semaste}
49254721Semaste
50254721Semastevoid
51254721SemastePlatformRemoteGDBServer::Terminate ()
52254721Semaste{
53254721Semaste    if (g_initialized)
54254721Semaste    {
55254721Semaste        g_initialized = false;
56254721Semaste        PluginManager::UnregisterPlugin (PlatformRemoteGDBServer::CreateInstance);
57254721Semaste    }
58254721Semaste}
59254721Semaste
60254721SemastePlatform*
61254721SemastePlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
62254721Semaste{
63254721Semaste    bool create = force;
64254721Semaste    if (!create)
65254721Semaste    {
66254721Semaste        create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
67254721Semaste    }
68254721Semaste    if (create)
69254721Semaste        return new PlatformRemoteGDBServer ();
70254721Semaste    return NULL;
71254721Semaste}
72254721Semaste
73254721Semaste
74254721Semastelldb_private::ConstString
75254721SemastePlatformRemoteGDBServer::GetPluginNameStatic()
76254721Semaste{
77254721Semaste    static ConstString g_name("remote-gdb-server");
78254721Semaste    return g_name;
79254721Semaste}
80254721Semaste
81254721Semasteconst char *
82254721SemastePlatformRemoteGDBServer::GetDescriptionStatic()
83254721Semaste{
84254721Semaste    return "A platform that uses the GDB remote protocol as the communication transport.";
85254721Semaste}
86254721Semaste
87254721Semasteconst char *
88254721SemastePlatformRemoteGDBServer::GetDescription ()
89254721Semaste{
90254721Semaste    if (m_platform_description.empty())
91254721Semaste    {
92254721Semaste        if (IsConnected())
93254721Semaste        {
94254721Semaste            // Send the get description packet
95254721Semaste        }
96254721Semaste    }
97254721Semaste
98254721Semaste    if (!m_platform_description.empty())
99254721Semaste        return m_platform_description.c_str();
100254721Semaste    return GetDescriptionStatic();
101254721Semaste}
102254721Semaste
103254721SemasteError
104254721SemastePlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file,
105254721Semaste                                            const ArchSpec &exe_arch,
106254721Semaste                                            lldb::ModuleSP &exe_module_sp,
107254721Semaste                                            const FileSpecList *module_search_paths_ptr)
108254721Semaste{
109254721Semaste    Error error;
110254721Semaste    error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
111254721Semaste    return error;
112254721Semaste}
113254721Semaste
114254721SemasteError
115254721SemastePlatformRemoteGDBServer::GetFile (const FileSpec &platform_file,
116254721Semaste                                  const UUID *uuid_ptr,
117254721Semaste                                  FileSpec &local_file)
118254721Semaste{
119254721Semaste    // Default to the local case
120254721Semaste    local_file = platform_file;
121254721Semaste    return Error();
122254721Semaste}
123254721Semaste
124254721Semaste//------------------------------------------------------------------
125254721Semaste/// Default Constructor
126254721Semaste//------------------------------------------------------------------
127254721SemastePlatformRemoteGDBServer::PlatformRemoteGDBServer () :
128254721Semaste    Platform(false), // This is a remote platform
129254721Semaste    m_gdb_client(true)
130254721Semaste{
131254721Semaste}
132254721Semaste
133254721Semaste//------------------------------------------------------------------
134254721Semaste/// Destructor.
135254721Semaste///
136254721Semaste/// The destructor is virtual since this class is designed to be
137254721Semaste/// inherited from by the plug-in instance.
138254721Semaste//------------------------------------------------------------------
139254721SemastePlatformRemoteGDBServer::~PlatformRemoteGDBServer()
140254721Semaste{
141254721Semaste}
142254721Semaste
143254721Semastebool
144254721SemastePlatformRemoteGDBServer::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
145254721Semaste{
146254721Semaste    return false;
147254721Semaste}
148254721Semaste
149254721Semastesize_t
150254721SemastePlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
151254721Semaste{
152254721Semaste    // This isn't needed if the z/Z packets are supported in the GDB remote
153254721Semaste    // server. But we might need a packet to detect this.
154254721Semaste    return 0;
155254721Semaste}
156254721Semaste
157254721Semastebool
158254721SemastePlatformRemoteGDBServer::GetRemoteOSVersion ()
159254721Semaste{
160254721Semaste    uint32_t major, minor, update;
161254721Semaste    if (m_gdb_client.GetOSVersion (major, minor, update))
162254721Semaste    {
163254721Semaste        m_major_os_version = major;
164254721Semaste        m_minor_os_version = minor;
165254721Semaste        m_update_os_version = update;
166254721Semaste        return true;
167254721Semaste    }
168254721Semaste    return false;
169254721Semaste}
170254721Semaste
171254721Semastebool
172254721SemastePlatformRemoteGDBServer::GetRemoteOSBuildString (std::string &s)
173254721Semaste{
174254721Semaste    return m_gdb_client.GetOSBuildString (s);
175254721Semaste}
176254721Semaste
177254721Semastebool
178254721SemastePlatformRemoteGDBServer::GetRemoteOSKernelDescription (std::string &s)
179254721Semaste{
180254721Semaste    return m_gdb_client.GetOSKernelDescription (s);
181254721Semaste}
182254721Semaste
183254721Semaste// Remote Platform subclasses need to override this function
184254721SemasteArchSpec
185254721SemastePlatformRemoteGDBServer::GetRemoteSystemArchitecture ()
186254721Semaste{
187254721Semaste    return m_gdb_client.GetSystemArchitecture();
188254721Semaste}
189254721Semaste
190254721Semastebool
191254721SemastePlatformRemoteGDBServer::IsConnected () const
192254721Semaste{
193254721Semaste    return m_gdb_client.IsConnected();
194254721Semaste}
195254721Semaste
196254721SemasteError
197254721SemastePlatformRemoteGDBServer::ConnectRemote (Args& args)
198254721Semaste{
199254721Semaste    Error error;
200254721Semaste    if (IsConnected())
201254721Semaste    {
202254721Semaste        error.SetErrorStringWithFormat ("the platform is already connected to '%s', execute 'platform disconnect' to close the current connection",
203254721Semaste                                        GetHostname());
204254721Semaste    }
205254721Semaste    else
206254721Semaste    {
207254721Semaste        if (args.GetArgumentCount() == 1)
208254721Semaste        {
209254721Semaste            const char *url = args.GetArgumentAtIndex(0);
210254721Semaste            m_gdb_client.SetConnection (new ConnectionFileDescriptor());
211254721Semaste            const ConnectionStatus status = m_gdb_client.Connect(url, &error);
212254721Semaste            if (status == eConnectionStatusSuccess)
213254721Semaste            {
214254721Semaste                if (m_gdb_client.HandshakeWithServer(&error))
215254721Semaste                {
216254721Semaste                    m_gdb_client.QueryNoAckModeSupported();
217254721Semaste                    m_gdb_client.GetHostInfo();
218254721Semaste#if 0
219254721Semaste                    m_gdb_client.TestPacketSpeed(10000);
220254721Semaste#endif
221254721Semaste                }
222254721Semaste                else
223254721Semaste                {
224254721Semaste                    m_gdb_client.Disconnect();
225254721Semaste                }
226254721Semaste            }
227254721Semaste        }
228254721Semaste        else
229254721Semaste        {
230254721Semaste            error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
231254721Semaste        }
232254721Semaste    }
233254721Semaste
234254721Semaste    return error;
235254721Semaste}
236254721Semaste
237254721SemasteError
238254721SemastePlatformRemoteGDBServer::DisconnectRemote ()
239254721Semaste{
240254721Semaste    Error error;
241254721Semaste    m_gdb_client.Disconnect(&error);
242254721Semaste    return error;
243254721Semaste}
244254721Semaste
245254721Semasteconst char *
246254721SemastePlatformRemoteGDBServer::GetHostname ()
247254721Semaste{
248254721Semaste    m_gdb_client.GetHostname (m_name);
249254721Semaste    if (m_name.empty())
250254721Semaste        return NULL;
251254721Semaste    return m_name.c_str();
252254721Semaste}
253254721Semaste
254254721Semasteconst char *
255254721SemastePlatformRemoteGDBServer::GetUserName (uint32_t uid)
256254721Semaste{
257254721Semaste    // Try and get a cache user name first
258254721Semaste    const char *cached_user_name = Platform::GetUserName(uid);
259254721Semaste    if (cached_user_name)
260254721Semaste        return cached_user_name;
261254721Semaste    std::string name;
262254721Semaste    if (m_gdb_client.GetUserName(uid, name))
263254721Semaste        return SetCachedUserName(uid, name.c_str(), name.size());
264254721Semaste
265254721Semaste    SetUserNameNotFound(uid); // Negative cache so we don't keep sending packets
266254721Semaste    return NULL;
267254721Semaste}
268254721Semaste
269254721Semasteconst char *
270254721SemastePlatformRemoteGDBServer::GetGroupName (uint32_t gid)
271254721Semaste{
272254721Semaste    const char *cached_group_name = Platform::GetGroupName(gid);
273254721Semaste    if (cached_group_name)
274254721Semaste        return cached_group_name;
275254721Semaste    std::string name;
276254721Semaste    if (m_gdb_client.GetGroupName(gid, name))
277254721Semaste        return SetCachedGroupName(gid, name.c_str(), name.size());
278254721Semaste
279254721Semaste    SetGroupNameNotFound(gid); // Negative cache so we don't keep sending packets
280254721Semaste    return NULL;
281254721Semaste}
282254721Semaste
283254721Semasteuint32_t
284254721SemastePlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info,
285254721Semaste                                        ProcessInstanceInfoList &process_infos)
286254721Semaste{
287254721Semaste    return m_gdb_client.FindProcesses (match_info, process_infos);
288254721Semaste}
289254721Semaste
290254721Semastebool
291254721SemastePlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
292254721Semaste{
293254721Semaste    return m_gdb_client.GetProcessInfo (pid, process_info);
294254721Semaste}
295254721Semaste
296254721Semaste
297254721SemasteError
298254721SemastePlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
299254721Semaste{
300254721Semaste    Error error;
301254721Semaste    lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
302254721Semaste
303254721Semaste    m_gdb_client.SetSTDIN ("/dev/null");
304254721Semaste    m_gdb_client.SetSTDOUT ("/dev/null");
305254721Semaste    m_gdb_client.SetSTDERR ("/dev/null");
306254721Semaste    m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
307254721Semaste
308254721Semaste    const char *working_dir = launch_info.GetWorkingDirectory();
309254721Semaste    if (working_dir && working_dir[0])
310254721Semaste    {
311254721Semaste        m_gdb_client.SetWorkingDir (working_dir);
312254721Semaste    }
313254721Semaste
314254721Semaste    // Send the environment and the program + arguments after we connect
315254721Semaste    const char **argv = launch_info.GetArguments().GetConstArgumentVector();
316254721Semaste    const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector();
317254721Semaste
318254721Semaste    if (envp)
319254721Semaste    {
320254721Semaste        const char *env_entry;
321254721Semaste        for (int i=0; (env_entry = envp[i]); ++i)
322254721Semaste        {
323254721Semaste            if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
324254721Semaste                break;
325254721Semaste        }
326254721Semaste    }
327254721Semaste    const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
328254721Semaste    int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv);
329254721Semaste    m_gdb_client.SetPacketTimeout (old_packet_timeout);
330254721Semaste    if (arg_packet_err == 0)
331254721Semaste    {
332254721Semaste        std::string error_str;
333254721Semaste        if (m_gdb_client.GetLaunchSuccess (error_str))
334254721Semaste        {
335254721Semaste            pid = m_gdb_client.GetCurrentProcessID ();
336254721Semaste            if (pid != LLDB_INVALID_PROCESS_ID)
337254721Semaste                launch_info.SetProcessID (pid);
338254721Semaste        }
339254721Semaste        else
340254721Semaste        {
341254721Semaste            error.SetErrorString (error_str.c_str());
342254721Semaste        }
343254721Semaste    }
344254721Semaste    else
345254721Semaste    {
346254721Semaste        error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
347254721Semaste    }
348254721Semaste    return error;
349254721Semaste}
350254721Semaste
351254721Semastelldb::ProcessSP
352254721SemastePlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
353254721Semaste                                 Debugger &debugger,
354254721Semaste                                 Target *target,       // Can be NULL, if NULL create a new target, else use existing one
355254721Semaste                                 Listener &listener,
356254721Semaste                                 Error &error)
357254721Semaste{
358254721Semaste    lldb::ProcessSP process_sp;
359254721Semaste    if (IsRemote())
360254721Semaste    {
361254721Semaste        if (IsConnected())
362254721Semaste        {
363254721Semaste            uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort();
364254721Semaste
365254721Semaste            if (port == 0)
366254721Semaste            {
367254721Semaste                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
368254721Semaste            }
369254721Semaste            else
370254721Semaste            {
371254721Semaste                if (target == NULL)
372254721Semaste                {
373254721Semaste                    TargetSP new_target_sp;
374254721Semaste
375254721Semaste                    error = debugger.GetTargetList().CreateTarget (debugger,
376254721Semaste                                                                   NULL,
377254721Semaste                                                                   NULL,
378254721Semaste                                                                   false,
379254721Semaste                                                                   NULL,
380254721Semaste                                                                   new_target_sp);
381254721Semaste                    target = new_target_sp.get();
382254721Semaste                }
383254721Semaste                else
384254721Semaste                    error.Clear();
385254721Semaste
386254721Semaste                if (target && error.Success())
387254721Semaste                {
388254721Semaste                    debugger.GetTargetList().SetSelectedTarget(target);
389254721Semaste
390254721Semaste                    // The darwin always currently uses the GDB remote debugger plug-in
391254721Semaste                    // so even when debugging locally we are debugging remotely!
392254721Semaste                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
393254721Semaste
394254721Semaste                    if (process_sp)
395254721Semaste                    {
396254721Semaste                        char connect_url[256];
397254721Semaste                        const int connect_url_len = ::snprintf (connect_url,
398254721Semaste                                                                sizeof(connect_url),
399254721Semaste                                                                "connect://%s:%u",
400254721Semaste                                                                GetHostname (),
401254721Semaste                                                                port);
402254721Semaste                        assert (connect_url_len < (int)sizeof(connect_url));
403254721Semaste                        error = process_sp->ConnectRemote (NULL, connect_url);
404254721Semaste                        if (error.Success())
405254721Semaste                            error = process_sp->Attach(attach_info);
406254721Semaste                    }
407254721Semaste                }
408254721Semaste            }
409254721Semaste        }
410254721Semaste        else
411254721Semaste        {
412254721Semaste            error.SetErrorString("not connected to remote gdb server");
413254721Semaste        }
414254721Semaste    }
415254721Semaste    return process_sp;
416254721Semaste}
417254721Semaste
418254721Semaste
419