1 //===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <cerrno> 10 #include <cstdint> 11 #include <cstdio> 12 #include <cstdlib> 13 #include <cstring> 14 15 #ifndef _WIN32 16 #include <csignal> 17 #include <unistd.h> 18 #endif 19 20 #include "LLDBServerUtilities.h" 21 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h" 22 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" 23 #include "lldb/Host/Config.h" 24 #include "lldb/Host/ConnectionFileDescriptor.h" 25 #include "lldb/Host/FileSystem.h" 26 #include "lldb/Host/Pipe.h" 27 #include "lldb/Host/common/NativeProcessProtocol.h" 28 #include "lldb/Host/common/TCPSocket.h" 29 #include "lldb/Target/Process.h" 30 #include "lldb/Utility/LLDBLog.h" 31 #include "lldb/Utility/Status.h" 32 #include "llvm/ADT/StringRef.h" 33 #include "llvm/Option/ArgList.h" 34 #include "llvm/Option/OptTable.h" 35 #include "llvm/Option/Option.h" 36 #include "llvm/Support/Errno.h" 37 #include "llvm/Support/Error.h" 38 #include "llvm/Support/WithColor.h" 39 40 #if defined(__linux__) 41 #include "Plugins/Process/Linux/NativeProcessLinux.h" 42 #elif defined(__FreeBSD__) 43 #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" 44 #elif defined(__NetBSD__) 45 #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" 46 #elif defined(_WIN32) 47 #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" 48 #endif 49 50 #ifndef LLGS_PROGRAM_NAME 51 #define LLGS_PROGRAM_NAME "lldb-server" 52 #endif 53 54 #ifndef LLGS_VERSION_STR 55 #define LLGS_VERSION_STR "local_build" 56 #endif 57 58 using namespace llvm; 59 using namespace lldb; 60 using namespace lldb_private; 61 using namespace lldb_private::lldb_server; 62 using namespace lldb_private::process_gdb_remote; 63 64 namespace { 65 #if defined(__linux__) 66 typedef process_linux::NativeProcessLinux::Manager NativeProcessManager; 67 #elif defined(__FreeBSD__) 68 typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; 69 #elif defined(__NetBSD__) 70 typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; 71 #elif defined(_WIN32) 72 typedef NativeProcessWindows::Manager NativeProcessManager; 73 #else 74 // Dummy implementation to make sure the code compiles 75 class NativeProcessManager : public NativeProcessProtocol::Manager { 76 public: 77 NativeProcessManager(MainLoop &mainloop) 78 : NativeProcessProtocol::Manager(mainloop) {} 79 80 llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 81 Launch(ProcessLaunchInfo &launch_info, 82 NativeProcessProtocol::NativeDelegate &native_delegate) override { 83 llvm_unreachable("Not implemented"); 84 } 85 llvm::Expected<std::unique_ptr<NativeProcessProtocol>> 86 Attach(lldb::pid_t pid, 87 NativeProcessProtocol::NativeDelegate &native_delegate) override { 88 llvm_unreachable("Not implemented"); 89 } 90 }; 91 #endif 92 } 93 94 #ifndef _WIN32 95 // Watch for signals 96 static int g_sighup_received_count = 0; 97 98 static void sighup_handler(MainLoopBase &mainloop) { 99 ++g_sighup_received_count; 100 101 Log *log = GetLog(LLDBLog::Process); 102 LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)", 103 __FUNCTION__, g_sighup_received_count); 104 105 if (g_sighup_received_count >= 2) 106 mainloop.RequestTermination(); 107 } 108 #endif // #ifndef _WIN32 109 110 void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server, 111 lldb::pid_t pid) { 112 Status error = gdb_server.AttachToProcess(pid); 113 if (error.Fail()) { 114 fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, 115 error.AsCString()); 116 exit(1); 117 } 118 } 119 120 void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server, 121 const std::string &process_name) { 122 // FIXME implement. 123 } 124 125 void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server, 126 const std::string &attach_target) { 127 assert(!attach_target.empty() && "attach_target cannot be empty"); 128 129 // First check if the attach_target is convertible to a long. If so, we'll use 130 // it as a pid. 131 char *end_p = nullptr; 132 const long int pid = strtol(attach_target.c_str(), &end_p, 10); 133 134 // We'll call it a match if the entire argument is consumed. 135 if (end_p && 136 static_cast<size_t>(end_p - attach_target.c_str()) == 137 attach_target.size()) 138 handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid)); 139 else 140 handle_attach_to_process_name(gdb_server, attach_target); 141 } 142 143 void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, 144 llvm::ArrayRef<llvm::StringRef> Arguments) { 145 ProcessLaunchInfo info; 146 info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug | 147 eLaunchFlagDisableASLR); 148 info.SetArguments(Args(Arguments), true); 149 150 llvm::SmallString<64> cwd; 151 if (std::error_code ec = llvm::sys::fs::current_path(cwd)) { 152 llvm::errs() << "Error getting current directory: " << ec.message() << "\n"; 153 exit(1); 154 } 155 FileSpec cwd_spec(cwd); 156 FileSystem::Instance().Resolve(cwd_spec); 157 info.SetWorkingDirectory(cwd_spec); 158 info.GetEnvironment() = Host::GetEnvironment(); 159 160 gdb_server.SetLaunchInfo(info); 161 162 Status error = gdb_server.LaunchProcess(); 163 if (error.Fail()) { 164 llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n", 165 Arguments[0], error); 166 exit(1); 167 } 168 } 169 170 static Status writeSocketIdToPipe(Pipe &port_pipe, 171 const std::string &socket_id) { 172 // NB: Include the nul character at the end. 173 llvm::StringRef buf(socket_id.data(), socket_id.size() + 1); 174 while (!buf.empty()) { 175 if (llvm::Expected<size_t> written = 176 port_pipe.Write(buf.data(), buf.size())) 177 buf = buf.drop_front(*written); 178 else 179 return Status::FromError(written.takeError()); 180 } 181 return Status(); 182 } 183 184 Status writeSocketIdToPipe(const char *const named_pipe_path, 185 llvm::StringRef socket_id) { 186 Pipe port_name_pipe; 187 // Wait for 10 seconds for pipe to be opened. 188 if (llvm::Error err = port_name_pipe.OpenAsWriter(named_pipe_path, 189 std::chrono::seconds{10})) 190 return Status::FromError(std::move(err)); 191 192 return writeSocketIdToPipe(port_name_pipe, socket_id.str()); 193 } 194 195 Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe, 196 llvm::StringRef socket_id) { 197 Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe}; 198 return writeSocketIdToPipe(port_pipe, socket_id.str()); 199 } 200 201 void ConnectToRemote(MainLoop &mainloop, 202 GDBRemoteCommunicationServerLLGS &gdb_server, 203 bool reverse_connect, llvm::StringRef host_and_port, 204 const char *const progname, const char *const subcommand, 205 const char *const named_pipe_path, pipe_t unnamed_pipe, 206 shared_fd_t connection_fd) { 207 Status error; 208 209 std::unique_ptr<Connection> connection_up; 210 std::string url; 211 212 if (connection_fd != SharedSocket::kInvalidFD) { 213 #ifdef _WIN32 214 NativeSocket sockfd; 215 error = SharedSocket::GetNativeSocket(connection_fd, sockfd); 216 if (error.Fail()) { 217 llvm::errs() << llvm::formatv("error: GetNativeSocket failed: {0}\n", 218 error.AsCString()); 219 exit(-1); 220 } 221 connection_up = std::make_unique<ConnectionFileDescriptor>( 222 std::make_unique<TCPSocket>(sockfd, /*should_close=*/true)); 223 #else 224 url = llvm::formatv("fd://{0}", connection_fd).str(); 225 226 // Create the connection. 227 ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC); 228 #endif 229 } else if (!host_and_port.empty()) { 230 llvm::Expected<std::string> url_exp = 231 LLGSArgToURL(host_and_port, reverse_connect); 232 if (!url_exp) { 233 llvm::errs() << llvm::formatv("error: invalid host:port or URL '{0}': " 234 "{1}\n", 235 host_and_port, 236 llvm::toString(url_exp.takeError())); 237 exit(-1); 238 } 239 240 url = std::move(url_exp.get()); 241 } 242 243 if (!url.empty()) { 244 // Create the connection or server. 245 std::unique_ptr<ConnectionFileDescriptor> conn_fd_up{ 246 new ConnectionFileDescriptor}; 247 auto connection_result = conn_fd_up->Connect( 248 url, 249 [named_pipe_path, unnamed_pipe](llvm::StringRef socket_id) { 250 // If we have a named pipe to write the socket id back to, do that 251 // now. 252 if (named_pipe_path && named_pipe_path[0]) { 253 Status error = writeSocketIdToPipe(named_pipe_path, socket_id); 254 if (error.Fail()) 255 llvm::errs() << llvm::formatv( 256 "failed to write to the named pipe '{0}': {1}\n", 257 named_pipe_path, error.AsCString()); 258 } 259 // If we have an unnamed pipe to write the socket id back to, do 260 // that now. 261 else if (unnamed_pipe != LLDB_INVALID_PIPE) { 262 Status error = writeSocketIdToPipe(unnamed_pipe, socket_id); 263 if (error.Fail()) 264 llvm::errs() << llvm::formatv( 265 "failed to write to the unnamed pipe: {0}\n", error); 266 } 267 }, 268 &error); 269 270 if (error.Fail()) { 271 llvm::errs() << llvm::formatv( 272 "error: failed to connect to client at '{0}': {1}\n", url, error); 273 exit(-1); 274 } 275 if (connection_result != eConnectionStatusSuccess) { 276 llvm::errs() << llvm::formatv( 277 "error: failed to connect to client at '{0}' " 278 "(connection status: {1})\n", 279 url, static_cast<int>(connection_result)); 280 exit(-1); 281 } 282 connection_up = std::move(conn_fd_up); 283 } 284 error = gdb_server.InitializeConnection(std::move(connection_up)); 285 if (error.Fail()) { 286 llvm::errs() << llvm::formatv("failed to initialize connection\n", error); 287 exit(-1); 288 } 289 llvm::outs() << "Connection established.\n"; 290 } 291 292 namespace { 293 using namespace llvm::opt; 294 295 enum ID { 296 OPT_INVALID = 0, // This is not an option ID. 297 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 298 #include "LLGSOptions.inc" 299 #undef OPTION 300 }; 301 302 #define OPTTABLE_STR_TABLE_CODE 303 #include "LLGSOptions.inc" 304 #undef OPTTABLE_STR_TABLE_CODE 305 306 #define OPTTABLE_PREFIXES_TABLE_CODE 307 #include "LLGSOptions.inc" 308 #undef OPTTABLE_PREFIXES_TABLE_CODE 309 310 static constexpr opt::OptTable::Info InfoTable[] = { 311 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 312 #include "LLGSOptions.inc" 313 #undef OPTION 314 }; 315 316 class LLGSOptTable : public opt::GenericOptTable { 317 public: 318 LLGSOptTable() 319 : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {} 320 321 void PrintHelp(llvm::StringRef Name) { 322 std::string Usage = 323 (Name + " [options] [[host]:port] [[--] program args...]").str(); 324 OptTable::printHelp(llvm::outs(), Usage.c_str(), "lldb-server"); 325 llvm::outs() << R"( 326 DESCRIPTION 327 lldb-server connects to the LLDB client, which drives the debugging session. 328 If no connection options are given, the [host]:port argument must be present 329 and will denote the address that lldb-server will listen on. [host] defaults 330 to "localhost" if empty. Port can be zero, in which case the port number will 331 be chosen dynamically and written to destinations given by --named-pipe and 332 --pipe arguments. 333 334 If no target is selected at startup, lldb-server can be directed by the LLDB 335 client to launch or attach to a process. 336 337 )"; 338 } 339 }; 340 } // namespace 341 342 int main_gdbserver(int argc, char *argv[]) { 343 Status error; 344 MainLoop mainloop; 345 #ifndef _WIN32 346 // Setup signal handlers first thing. 347 signal(SIGPIPE, SIG_IGN); 348 MainLoop::SignalHandleUP sighup_handle = 349 mainloop.RegisterSignal(SIGHUP, sighup_handler, error); 350 #endif 351 352 const char *progname = argv[0]; 353 const char *subcommand = argv[1]; 354 std::string attach_target; 355 std::string named_pipe_path; 356 std::string log_file; 357 StringRef 358 log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" 359 lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE; 360 bool reverse_connect = false; 361 shared_fd_t connection_fd = SharedSocket::kInvalidFD; 362 363 // ProcessLaunchInfo launch_info; 364 ProcessAttachInfo attach_info; 365 366 LLGSOptTable Opts; 367 llvm::BumpPtrAllocator Alloc; 368 llvm::StringSaver Saver(Alloc); 369 bool HasError = false; 370 opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN, 371 Saver, [&](llvm::StringRef Msg) { 372 WithColor::error() << Msg << "\n"; 373 HasError = true; 374 }); 375 std::string Name = 376 (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str(); 377 std::string HelpText = 378 "Use '" + Name + " --help' for a complete list of options.\n"; 379 if (HasError) { 380 llvm::errs() << HelpText; 381 return 1; 382 } 383 384 if (Args.hasArg(OPT_help)) { 385 Opts.PrintHelp(Name); 386 return 0; 387 } 388 389 #ifndef _WIN32 390 if (Args.hasArg(OPT_setsid)) { 391 // Put llgs into a new session. Terminals group processes 392 // into sessions and when a special terminal key sequences 393 // (like control+c) are typed they can cause signals to go out to 394 // all processes in a session. Using this --setsid (-S) option 395 // will cause debugserver to run in its own sessions and be free 396 // from such issues. 397 // 398 // This is useful when llgs is spawned from a command 399 // line application that uses llgs to do the debugging, 400 // yet that application doesn't want llgs receiving the 401 // signals sent to the session (i.e. dying when anyone hits ^C). 402 { 403 const ::pid_t new_sid = setsid(); 404 if (new_sid == -1) { 405 WithColor::warning() 406 << llvm::formatv("failed to set new session id for {0} ({1})\n", 407 LLGS_PROGRAM_NAME, llvm::sys::StrError()); 408 } 409 } 410 } 411 #endif 412 413 log_file = Args.getLastArgValue(OPT_log_file).str(); 414 log_channels = Args.getLastArgValue(OPT_log_channels); 415 named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str(); 416 reverse_connect = Args.hasArg(OPT_reverse_connect); 417 attach_target = Args.getLastArgValue(OPT_attach).str(); 418 if (Args.hasArg(OPT_pipe)) { 419 uint64_t Arg; 420 if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) { 421 WithColor::error() << "invalid '--pipe' argument\n" << HelpText; 422 return 1; 423 } 424 unnamed_pipe = (pipe_t)Arg; 425 } 426 if (Args.hasArg(OPT_fd)) { 427 int64_t fd; 428 if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), fd)) { 429 WithColor::error() << "invalid '--fd' argument\n" << HelpText; 430 return 1; 431 } 432 connection_fd = (shared_fd_t)fd; 433 } 434 435 if (!LLDBServerUtilities::SetupLogging( 436 log_file, log_channels, 437 LLDB_LOG_OPTION_PREPEND_TIMESTAMP | 438 LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION)) 439 return -1; 440 441 std::vector<llvm::StringRef> Inputs; 442 for (opt::Arg *Arg : Args.filtered(OPT_INPUT)) 443 Inputs.push_back(Arg->getValue()); 444 if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) { 445 for (const char *Val : Arg->getValues()) 446 Inputs.push_back(Val); 447 } 448 if (Inputs.empty() && connection_fd == SharedSocket::kInvalidFD) { 449 WithColor::error() << "no connection arguments\n" << HelpText; 450 return 1; 451 } 452 453 NativeProcessManager manager(mainloop); 454 GDBRemoteCommunicationServerLLGS gdb_server(mainloop, manager); 455 456 llvm::StringRef host_and_port; 457 if (!Inputs.empty() && connection_fd == SharedSocket::kInvalidFD) { 458 host_and_port = Inputs.front(); 459 Inputs.erase(Inputs.begin()); 460 } 461 462 // Any arguments left over are for the program that we need to launch. If 463 // there 464 // are no arguments, then the GDB server will start up and wait for an 'A' 465 // packet 466 // to launch a program, or a vAttach packet to attach to an existing process, 467 // unless 468 // explicitly asked to attach with the --attach={pid|program_name} form. 469 if (!attach_target.empty()) 470 handle_attach(gdb_server, attach_target); 471 else if (!Inputs.empty()) 472 handle_launch(gdb_server, Inputs); 473 474 // Print version info. 475 printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR); 476 477 ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port, 478 progname, subcommand, named_pipe_path.c_str(), 479 unnamed_pipe, connection_fd); 480 481 if (!gdb_server.IsConnected()) { 482 fprintf(stderr, "no connection information provided, unable to run\n"); 483 return 1; 484 } 485 486 Status ret = mainloop.Run(); 487 if (ret.Fail()) { 488 fprintf(stderr, "lldb-server terminating due to error: %s\n", 489 ret.AsCString()); 490 return 1; 491 } 492 fprintf(stderr, "lldb-server exiting...\n"); 493 494 return 0; 495 } 496