1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include "lldb/lldb-python.h" |
11 | |
12 | |
13 | #include <errno(*__errno_location ()).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 | |
23 | |
24 | |
25 | |
26 | #include "lldb/lldb-private-log.h" |
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/Interpreter/CommandInterpreter.h" |
35 | #include "lldb/Interpreter/CommandReturnObject.h" |
36 | #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h" |
37 | #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" |
38 | using namespace lldb; |
39 | using namespace lldb_private; |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | int g_debug = 0; |
46 | int g_verbose = 0; |
47 | int g_stay_alive = 0; |
48 | |
49 | static struct option g_long_options[] = |
50 | { |
51 | { "debug", no_argument0, &g_debug, 1 }, |
52 | { "verbose", no_argument0, &g_verbose, 1 }, |
53 | { "stay-alive", no_argument0, &g_stay_alive, 1 }, |
54 | { "listen", required_argument1, NULL__null, 'L' }, |
55 | { "port-offset", required_argument1, NULL__null, 'p' }, |
56 | { "gdbserver-port", required_argument1, NULL__null, 'P' }, |
57 | { "min-gdbserver-port", required_argument1, NULL__null, 'm' }, |
58 | { "max-gdbserver-port", required_argument1, NULL__null, 'M' }, |
59 | { "lldb-command", required_argument1, NULL__null, 'c' }, |
60 | { NULL__null, 0, NULL__null, 0 } |
61 | }; |
62 | |
63 | #if defined (__APPLE__) |
64 | #define LOW_PORT(1024u) (IPPORT_RESERVED) |
65 | #define HIGH_PORT(49151u) (IPPORT_HIFIRSTAUTO) |
66 | #else |
67 | #define LOW_PORT(1024u) (1024u) |
68 | #define HIGH_PORT(49151u) (49151u) |
69 | #endif |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | void |
76 | signal_handler(int signo) |
77 | { |
78 | switch (signo) |
79 | { |
80 | case SIGHUP1: |
81 | |
82 | |
83 | |
84 | Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-platform...\n"); |
85 | abort(); |
86 | break; |
87 | } |
88 | } |
89 | |
90 | static void |
91 | display_usage (const char *progname) |
92 | { |
93 | fprintf(stderrstderr, "Usage:\n %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname); |
94 | exit(0); |
95 | } |
96 | |
97 | |
98 | |
99 | |
100 | int |
101 | main (int argc, char *argv[]) |
102 | { |
103 | const char *progname = argv[0]; |
104 | signal (SIGPIPE13, SIG_IGN((__sighandler_t) 1)); |
105 | signal (SIGHUP1, signal_handler); |
106 | int long_option_index = 0; |
107 | Error error; |
108 | std::string listen_host_port; |
109 | int ch; |
110 | Debugger::Initialize(NULL__null); |
111 | |
112 | lldb::DebuggerSP debugger_sp = Debugger::CreateInstance (); |
113 | |
114 | debugger_sp->SetInputFileHandle(stdinstdin, false); |
115 | debugger_sp->SetOutputFileHandle(stdoutstdout, false); |
116 | debugger_sp->SetErrorFileHandle(stderrstderr, false); |
117 | |
118 | GDBRemoteCommunicationServer::PortMap gdbserver_portmap; |
119 | int min_gdbserver_port = 0; |
120 | int max_gdbserver_port = 0; |
121 | uint16_t port_offset = 0; |
122 | |
123 | std::vector<std::string> lldb_commands; |
124 | bool show_usage = false; |
125 | int option_error = 0; |
126 | |
127 | std::string short_options(OptionParser::GetShortOptionString(g_long_options)); |
128 | |
129 | #if __GLIBC__2 |
130 | optind = 0; |
131 | #else |
132 | optreset = 1; |
133 | optind = 1; |
134 | #endif |
135 | |
136 | while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1) |
137 | { |
138 | switch (ch) |
139 | { |
140 | case 0: |
141 | break; |
142 | |
143 | case 'L': |
144 | listen_host_port.append (optarg); |
145 | break; |
146 | |
147 | case 'p': |
148 | { |
149 | char *end = NULL__null; |
150 | long tmp_port_offset = strtoul(optarg, &end, 0); |
151 | if (end && *end == '\0') |
152 | { |
153 | if (LOW_PORT(1024u) <= tmp_port_offset && tmp_port_offset <= HIGH_PORT(49151u)) |
154 | { |
155 | port_offset = (uint16_t)tmp_port_offset; |
156 | } |
157 | else |
158 | { |
159 | fprintf (stderrstderr, "error: port offset %li is not in the valid user port range of %u - %u\n", tmp_port_offset, LOW_PORT(1024u), HIGH_PORT(49151u)); |
160 | option_error = 5; |
161 | } |
162 | } |
163 | else |
164 | { |
165 | fprintf (stderrstderr, "error: invalid port offset string %s\n", optarg); |
166 | option_error = 4; |
167 | } |
168 | } |
169 | break; |
170 | |
171 | case 'P': |
172 | case 'm': |
173 | case 'M': |
174 | { |
175 | char *end = NULL__null; |
176 | long portnum = strtoul(optarg, &end, 0); |
177 | if (end && *end == '\0') |
178 | { |
179 | if (LOW_PORT(1024u) <= portnum && portnum <= HIGH_PORT(49151u)) |
180 | { |
181 | if (ch == 'P') |
182 | gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID0; |
183 | else if (ch == 'm') |
184 | min_gdbserver_port = portnum; |
185 | else |
186 | max_gdbserver_port = portnum; |
187 | } |
188 | else |
189 | { |
190 | fprintf (stderrstderr, "error: port number %li is not in the valid user port range of %u - %u\n", portnum, LOW_PORT(1024u), HIGH_PORT(49151u)); |
191 | option_error = 1; |
192 | } |
193 | } |
194 | else |
195 | { |
196 | fprintf (stderrstderr, "error: invalid port number string %s\n", optarg); |
197 | option_error = 2; |
198 | } |
199 | } |
200 | break; |
201 | |
202 | case 'c': |
203 | lldb_commands.push_back(optarg); |
204 | break; |
205 | |
206 | case 'h': |
207 | case '?': |
208 | show_usage = true; |
209 | break; |
210 | } |
211 | } |
212 | |
213 | |
214 | if (min_gdbserver_port < max_gdbserver_port) |
215 | { |
216 | for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port) |
217 | gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID0; |
218 | } |
219 | else if (min_gdbserver_port != max_gdbserver_port) |
220 | { |
221 | fprintf (stderrstderr, "error: --min-gdbserver-port (%u) is greater than --max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port); |
222 | option_error = 3; |
223 | |
224 | } |
225 | |
226 | |
227 | if (listen_host_port.empty()) |
228 | show_usage = true; |
229 | |
230 | if (show_usage || option_error) |
231 | { |
232 | display_usage(progname); |
233 | exit(option_error); |
234 | } |
235 | |
236 | |
237 | argc -= optind; |
238 | argv += optind; |
| Value stored to 'argv' is never read |
239 | |
240 | |
241 | for (const auto &lldb_command : lldb_commands) |
242 | { |
243 | lldb_private::CommandReturnObject result; |
244 | printf("(lldb) %s\n", lldb_command.c_str()); |
245 | debugger_sp->GetCommandInterpreter().HandleCommand(lldb_command.c_str(), eLazyBoolNo, result); |
246 | const char *output = result.GetOutputData(); |
247 | if (output && output[0]) |
248 | puts(output); |
249 | } |
250 | |
251 | |
252 | do { |
253 | GDBRemoteCommunicationServer gdb_server (true); |
254 | |
255 | if (port_offset > 0) |
256 | gdb_server.SetPortOffset(port_offset); |
257 | |
258 | if (!gdbserver_portmap.empty()) |
259 | { |
260 | gdb_server.SetPortMap(std::move(gdbserver_portmap)); |
261 | } |
262 | |
263 | if (!listen_host_port.empty()) |
264 | { |
265 | std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); |
266 | if (conn_ap.get()) |
267 | { |
268 | std::string connect_url ("listen://"); |
269 | connect_url.append(listen_host_port.c_str()); |
270 | |
271 | printf ("Listening for a connection from %s...\n", listen_host_port.c_str()); |
272 | if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess) |
273 | { |
274 | printf ("Connection established.\n"); |
275 | gdb_server.SetConnection (conn_ap.release()); |
276 | } |
277 | else |
278 | { |
279 | printf ("error: %s\n", error.AsCString()); |
280 | } |
281 | } |
282 | |
283 | if (gdb_server.IsConnected()) |
284 | { |
285 | |
286 | if (gdb_server.HandshakeWithClient(&error)) |
287 | { |
288 | bool interrupt = false; |
289 | bool done = false; |
290 | while (!interrupt && !done) |
291 | { |
292 | if (gdb_server.GetPacketAndSendResponse (UINT32_MAX(4294967295U), error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success) |
293 | break; |
294 | } |
295 | |
296 | if (error.Fail()) |
297 | { |
298 | fprintf(stderrstderr, "error: %s\n", error.AsCString()); |
299 | } |
300 | } |
301 | else |
302 | { |
303 | fprintf(stderrstderr, "error: handshake with client failed\n"); |
304 | } |
305 | } |
306 | } |
307 | } while (g_stay_alive); |
308 | |
309 | Debugger::Terminate(); |
310 | |
311 | fprintf(stderrstderr, "lldb-platform exiting...\n"); |
312 | |
313 | return 0; |
314 | } |