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