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