1 //===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/lldb-python.h"
14 #include "lldb/Host/HostGetOpt.h"
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"
36 using namespace lldb_private;
38 //----------------------------------------------------------------------
39 // option descriptors for getopt_long_only()
40 //----------------------------------------------------------------------
46 static struct option g_long_options[] =
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' },
60 #if defined (__APPLE__)
61 #define LOW_PORT (IPPORT_RESERVED)
62 #define HIGH_PORT (IPPORT_HIFIRSTAUTO)
64 #define LOW_PORT (1024u)
65 #define HIGH_PORT (49151u)
69 //----------------------------------------------------------------------
71 //----------------------------------------------------------------------
73 signal_handler(int signo)
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");
88 display_usage (const char *progname)
90 fprintf(stderr, "Usage:\n %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname);
94 //----------------------------------------------------------------------
96 //----------------------------------------------------------------------
98 main (int argc, char *argv[])
100 const char *progname = argv[0];
101 signal (SIGPIPE, SIG_IGN);
102 signal (SIGHUP, signal_handler);
103 int long_option_index = 0;
105 std::string listen_host_port;
107 Debugger::Initialize(NULL);
109 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance ();
111 debugger_sp->SetInputFileHandle(stdin, false);
112 debugger_sp->SetOutputFileHandle(stdout, false);
113 debugger_sp->SetErrorFileHandle(stderr, false);
115 GDBRemoteCommunicationServer::PortMap gdbserver_portmap;
116 int min_gdbserver_port = 0;
117 int max_gdbserver_port = 0;
118 uint16_t port_offset = 0;
120 std::vector<std::string> lldb_commands;
121 bool show_usage = false;
122 int option_error = 0;
124 std::string short_options(OptionParser::GetShortOptionString(g_long_options));
133 while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1)
137 case 0: // Any optional that auto set themselves will return 0
141 listen_host_port.append (optarg);
147 long tmp_port_offset = strtoul(optarg, &end, 0);
148 if (end && *end == '\0')
150 if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT)
152 port_offset = (uint16_t)tmp_port_offset;
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);
162 fprintf (stderr, "error: invalid port offset string %s\n", optarg);
173 long portnum = strtoul(optarg, &end, 0);
174 if (end && *end == '\0')
176 if (LOW_PORT <= portnum && portnum <= HIGH_PORT)
179 gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID;
181 min_gdbserver_port = portnum;
183 max_gdbserver_port = portnum;
187 fprintf (stderr, "error: port number %li is not in the valid user port range of %u - %u\n", portnum, LOW_PORT, HIGH_PORT);
193 fprintf (stderr, "error: invalid port number string %s\n", optarg);
200 lldb_commands.push_back(optarg);
203 case 'h': /* fall-through is intentional */
210 // Make a port map for a port range that was specified.
211 if (min_gdbserver_port < max_gdbserver_port)
213 for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port)
214 gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID;
216 else if (min_gdbserver_port != max_gdbserver_port)
218 fprintf (stderr, "error: --min-gdbserver-port (%u) is greater than --max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port);
223 // Print usage and exit if no listening port is specified.
224 if (listen_host_port.empty())
227 if (show_usage || option_error)
229 display_usage(progname);
233 // Skip any options we consumed with getopt_long_only
237 // Execute any LLDB commands that we were asked to evaluate.
238 for (const auto &lldb_command : lldb_commands)
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])
250 GDBRemoteCommunicationServer gdb_server (true);
253 gdb_server.SetPortOffset(port_offset);
255 if (!gdbserver_portmap.empty())
257 gdb_server.SetPortMap(std::move(gdbserver_portmap));
260 if (!listen_host_port.empty())
262 std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
265 std::string connect_url ("listen://");
266 connect_url.append(listen_host_port.c_str());
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)
271 printf ("Connection established.\n");
272 gdb_server.SetConnection (conn_ap.release());
276 printf ("error: %s\n", error.AsCString());
280 if (gdb_server.IsConnected())
282 // After we connected, we need to get an initial ack from...
283 if (gdb_server.HandshakeWithClient(&error))
285 bool interrupt = false;
287 while (!interrupt && !done)
289 if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
295 fprintf(stderr, "error: %s\n", error.AsCString());
300 fprintf(stderr, "error: handshake with client failed\n");
304 } while (g_stay_alive);
306 Debugger::Terminate();
308 fprintf(stderr, "lldb-platform exiting...\n");