1 //===-- lldb-platform.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 // C Includes
13 #include <errno.h>
14 #if defined(__APPLE__)
15 #include <netinet/in.h>
16 #endif
17 #include <signal.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/wait.h>
23 
24 // C++ Includes
25 
26 // Other libraries and framework includes
27 #include "lldb/Core/Error.h"
28 #include "lldb/Core/ConnectionMachPort.h"
29 #include "lldb/Core/Debugger.h"
30 #include "lldb/Core/StreamFile.h"
31 #include "lldb/Host/ConnectionFileDescriptor.h"
32 #include "lldb/Host/HostGetOpt.h"
33 #include "lldb/Host/OptionParser.h"
34 #include "lldb/Host/Socket.h"
35 #include "lldb/Interpreter/CommandInterpreter.h"
36 #include "lldb/Interpreter/CommandReturnObject.h"
37 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
38 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
39 
40 using namespace lldb;
41 using namespace lldb_private;
42 using namespace lldb_private::process_gdb_remote;
43 
44 //----------------------------------------------------------------------
45 // option descriptors for getopt_long_only()
46 //----------------------------------------------------------------------
47 
48 static int g_debug = 0;
49 static int g_verbose = 0;
50 static int g_server = 0;
51 
52 static struct option g_long_options[] =
53 {
54     { "debug",              no_argument,        &g_debug,           1   },
55     { "verbose",            no_argument,        &g_verbose,         1   },
56     { "listen",             required_argument,  NULL,               'L' },
57     { "port-offset",        required_argument,  NULL,               'p' },
58     { "gdbserver-port",     required_argument,  NULL,               'P' },
59     { "min-gdbserver-port", required_argument,  NULL,               'm' },
60     { "max-gdbserver-port", required_argument,  NULL,               'M' },
61     { "lldb-command",       required_argument,  NULL,               'c' },
62     { "server",             no_argument,        &g_server,          1   },
63     { NULL,                 0,                  NULL,               0   }
64 };
65 
66 #if defined (__APPLE__)
67 #define LOW_PORT    (IPPORT_RESERVED)
68 #define HIGH_PORT   (IPPORT_HIFIRSTAUTO)
69 #else
70 #define LOW_PORT    (1024u)
71 #define HIGH_PORT   (49151u)
72 #endif
73 
74 
75 //----------------------------------------------------------------------
76 // Watch for signals
77 //----------------------------------------------------------------------
78 static void
79 signal_handler(int signo)
80 {
81     switch (signo)
82     {
83     case SIGHUP:
84         // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
85         // And we should not call exit() here because it results in the global destructors
86         // to be invoked and wreaking havoc on the threads still running.
87         Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-server...\n");
88         abort();
89         break;
90     }
91 }
92 
93 static void
94 display_usage (const char *progname, const char *subcommand)
95 {
96     fprintf(stderr, "Usage:\n  %s %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname, subcommand);
97     exit(0);
98 }
99 
100 //----------------------------------------------------------------------
101 // main
102 //----------------------------------------------------------------------
103 int
104 main_platform (int argc, char *argv[])
105 {
106     const char *progname = argv[0];
107     const char *subcommand = argv[1];
108     argc--;
109     argv++;
110     signal (SIGPIPE, SIG_IGN);
111     signal (SIGHUP, signal_handler);
112     int long_option_index = 0;
113     Error error;
114     std::string listen_host_port;
115     int ch;
116 
117     lldb::DebuggerSP debugger_sp = Debugger::CreateInstance ();
118 
119     debugger_sp->SetInputFileHandle(stdin, false);
120     debugger_sp->SetOutputFileHandle(stdout, false);
121     debugger_sp->SetErrorFileHandle(stderr, false);
122 
123     GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
124     int min_gdbserver_port = 0;
125     int max_gdbserver_port = 0;
126     uint16_t port_offset = 0;
127 
128     std::vector<std::string> lldb_commands;
129     bool show_usage = false;
130     int option_error = 0;
131     int socket_error = -1;
132 
133     std::string short_options(OptionParser::GetShortOptionString(g_long_options));
134 
135 #if __GLIBC__
136     optind = 0;
137 #else
138     optreset = 1;
139     optind = 1;
140 #endif
141 
142     while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1)
143     {
144         switch (ch)
145         {
146         case 0:   // Any optional that auto set themselves will return 0
147             break;
148 
149         case 'L':
150             listen_host_port.append (optarg);
151             break;
152 
153         case 'p':
154             {
155                 char *end = NULL;
156                 long tmp_port_offset = strtoul(optarg, &end, 0);
157                 if (end && *end == '\0')
158                 {
159                     if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT)
160                     {
161                         port_offset = (uint16_t)tmp_port_offset;
162                     }
163                     else
164                     {
165                         fprintf (stderr, "error: port offset %li is not in the valid user port range of %u - %u\n", tmp_port_offset, LOW_PORT, HIGH_PORT);
166                         option_error = 5;
167                     }
168                 }
169                 else
170                 {
171                     fprintf (stderr, "error: invalid port offset string %s\n", optarg);
172                     option_error = 4;
173                 }
174             }
175             break;
176 
177         case 'P':
178         case 'm':
179         case 'M':
180             {
181                 char *end = NULL;
182                 long portnum = strtoul(optarg, &end, 0);
183                 if (end && *end == '\0')
184                 {
185                     if (LOW_PORT <= portnum && portnum <= HIGH_PORT)
186                     {
187                         if (ch  == 'P')
188                             gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID;
189                         else if (ch == 'm')
190                             min_gdbserver_port = portnum;
191                         else
192                             max_gdbserver_port = portnum;
193                     }
194                     else
195                     {
196                         fprintf (stderr, "error: port number %li is not in the valid user port range of %u - %u\n", portnum, LOW_PORT, HIGH_PORT);
197                         option_error = 1;
198                     }
199                 }
200                 else
201                 {
202                     fprintf (stderr, "error: invalid port number string %s\n", optarg);
203                     option_error = 2;
204                 }
205             }
206             break;
207 
208         case 'c':
209             lldb_commands.push_back(optarg);
210             break;
211 
212         case 'h':   /* fall-through is intentional */
213         case '?':
214             show_usage = true;
215             break;
216         }
217     }
218 
219     // Make a port map for a port range that was specified.
220     if (min_gdbserver_port < max_gdbserver_port)
221     {
222         for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port)
223             gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID;
224     }
225     else if (min_gdbserver_port != max_gdbserver_port)
226     {
227         fprintf (stderr, "error: --min-gdbserver-port (%u) is greater than --max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port);
228         option_error = 3;
229 
230     }
231 
232     // Print usage and exit if no listening port is specified.
233     if (listen_host_port.empty())
234         show_usage = true;
235 
236     if (show_usage || option_error)
237     {
238         display_usage(progname, subcommand);
239         exit(option_error);
240     }
241 
242     // Execute any LLDB commands that we were asked to evaluate.
243     for (const auto &lldb_command : lldb_commands)
244     {
245         lldb_private::CommandReturnObject result;
246         printf("(lldb) %s\n", lldb_command.c_str());
247         debugger_sp->GetCommandInterpreter().HandleCommand(lldb_command.c_str(), eLazyBoolNo, result);
248         const char *output = result.GetOutputData();
249         if (output && output[0])
250             puts(output);
251     }
252 
253     std::unique_ptr<Socket> listening_socket_up;
254     Socket *socket = nullptr;
255     printf ("Listening for a connection from %s...\n", listen_host_port.c_str());
256     const bool children_inherit_listen_socket = false;
257 
258     // the test suite makes many connections in parallel, let's not miss any.
259     // The highest this should get reasonably is a function of the number
260     // of target CPUs.  For now, let's just use 100
261     const int backlog = 100;
262     error = Socket::TcpListen(listen_host_port.c_str(), children_inherit_listen_socket, socket, NULL, backlog);
263     if (error.Fail())
264     {
265         printf("error: %s\n", error.AsCString());
266         exit(socket_error);
267     }
268     listening_socket_up.reset(socket);
269 
270     do {
271         GDBRemoteCommunicationServerPlatform platform;
272 
273         if (port_offset > 0)
274             platform.SetPortOffset(port_offset);
275 
276         if (!gdbserver_portmap.empty())
277         {
278             platform.SetPortMap(std::move(gdbserver_portmap));
279         }
280 
281         const bool children_inherit_accept_socket = true;
282         socket = nullptr;
283         error = listening_socket_up->BlockingAccept(listen_host_port.c_str(), children_inherit_accept_socket, socket);
284         if (error.Fail())
285         {
286             printf ("error: %s\n", error.AsCString());
287             exit(socket_error);
288         }
289         printf ("Connection established.\n");
290         if (g_server)
291         {
292             // Collect child zombie processes.
293             while (waitpid(-1, nullptr, WNOHANG) > 0);
294             if (fork())
295             {
296                 // Parent doesn't need a connection to the lldb client
297                 delete socket;
298                 socket = nullptr;
299 
300                 // Parent will continue to listen for new connections.
301                 continue;
302             }
303             else
304             {
305                 // Child process will handle the connection and exit.
306                 g_server = 0;
307                 // Listening socket is owned by parent process.
308                 listening_socket_up.release();
309             }
310         }
311         else
312         {
313             // If not running as a server, this process will not accept
314             // connections while a connection is active.
315             listening_socket_up.reset();
316         }
317         platform.SetConnection (new ConnectionFileDescriptor(socket));
318 
319         if (platform.IsConnected())
320         {
321             // After we connected, we need to get an initial ack from...
322             if (platform.HandshakeWithClient(&error))
323             {
324                 bool interrupt = false;
325                 bool done = false;
326                 while (!interrupt && !done)
327                 {
328                     if (platform.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success)
329                         break;
330                 }
331 
332                 if (error.Fail())
333                 {
334                     fprintf(stderr, "error: %s\n", error.AsCString());
335                 }
336             }
337             else
338             {
339                 fprintf(stderr, "error: handshake with client failed\n");
340             }
341         }
342     } while (g_server);
343 
344     fprintf(stderr, "lldb-server exiting...\n");
345 
346     return 0;
347 }
348