aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/tools/lldb-server
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/tools/lldb-server')
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/Acceptor.cpp131
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/Acceptor.h60
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-Info.plist21
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-entitlements.plist28
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-macos-entitlements.plist8
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-mig.defs5
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.cpp79
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.h29
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/LLGSOptions.td62
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.cpp101
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.h23
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp473
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp385
-rw-r--r--contrib/llvm-project/lldb/tools/lldb-server/lldb-server.cpp82
14 files changed, 1487 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/Acceptor.cpp b/contrib/llvm-project/lldb/tools/lldb-server/Acceptor.cpp
new file mode 100644
index 000000000000..2037f1e0f62b
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/Acceptor.cpp
@@ -0,0 +1,131 @@
+//===-- Acceptor.cpp --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Acceptor.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UriParser.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+using namespace llvm;
+
+namespace {
+
+struct SocketScheme {
+ const char *m_scheme;
+ const Socket::SocketProtocol m_protocol;
+};
+
+SocketScheme socket_schemes[] = {
+ {"tcp", Socket::ProtocolTcp},
+ {"udp", Socket::ProtocolUdp},
+ {"unix", Socket::ProtocolUnixDomain},
+ {"unix-abstract", Socket::ProtocolUnixAbstract},
+};
+
+bool FindProtocolByScheme(const char *scheme,
+ Socket::SocketProtocol &protocol) {
+ for (auto s : socket_schemes) {
+ if (!strcmp(s.m_scheme, scheme)) {
+ protocol = s.m_protocol;
+ return true;
+ }
+ }
+ return false;
+}
+
+const char *FindSchemeByProtocol(const Socket::SocketProtocol protocol) {
+ for (auto s : socket_schemes) {
+ if (s.m_protocol == protocol)
+ return s.m_scheme;
+ }
+ return nullptr;
+}
+}
+
+Status Acceptor::Listen(int backlog) {
+ return m_listener_socket_up->Listen(StringRef(m_name), backlog);
+}
+
+Status Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) {
+ Socket *conn_socket = nullptr;
+ auto error = m_listener_socket_up->Accept(conn_socket);
+ if (error.Success())
+ conn = new ConnectionFileDescriptor(conn_socket);
+
+ return error;
+}
+
+Socket::SocketProtocol Acceptor::GetSocketProtocol() const {
+ return m_listener_socket_up->GetSocketProtocol();
+}
+
+const char *Acceptor::GetSocketScheme() const {
+ return FindSchemeByProtocol(GetSocketProtocol());
+}
+
+std::string Acceptor::GetLocalSocketId() const { return m_local_socket_id(); }
+
+std::unique_ptr<Acceptor> Acceptor::Create(StringRef name,
+ const bool child_processes_inherit,
+ Status &error) {
+ error.Clear();
+
+ Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain;
+ // Try to match socket name as URL - e.g., tcp://localhost:5555
+ if (std::optional<URI> res = URI::Parse(name)) {
+ if (!FindProtocolByScheme(res->scheme.str().c_str(), socket_protocol))
+ error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"",
+ res->scheme.str().c_str());
+ else
+ name = name.drop_front(res->scheme.size() + strlen("://"));
+ } else {
+ // Try to match socket name as $host:port - e.g., localhost:5555
+ if (!llvm::errorToBool(Socket::DecodeHostAndPort(name).takeError()))
+ socket_protocol = Socket::ProtocolTcp;
+ }
+
+ if (error.Fail())
+ return std::unique_ptr<Acceptor>();
+
+ std::unique_ptr<Socket> listener_socket_up =
+ Socket::Create(socket_protocol, child_processes_inherit, error);
+
+ LocalSocketIdFunc local_socket_id;
+ if (error.Success()) {
+ if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp) {
+ TCPSocket *tcp_socket =
+ static_cast<TCPSocket *>(listener_socket_up.get());
+ local_socket_id = [tcp_socket]() {
+ auto local_port = tcp_socket->GetLocalPortNumber();
+ return (local_port != 0) ? llvm::to_string(local_port) : "";
+ };
+ } else {
+ const std::string socket_name = std::string(name);
+ local_socket_id = [socket_name]() { return socket_name; };
+ }
+
+ return std::unique_ptr<Acceptor>(
+ new Acceptor(std::move(listener_socket_up), name, local_socket_id));
+ }
+
+ return std::unique_ptr<Acceptor>();
+}
+
+Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket, StringRef name,
+ const LocalSocketIdFunc &local_socket_id)
+ : m_listener_socket_up(std::move(listener_socket)), m_name(name.str()),
+ m_local_socket_id(local_socket_id) {}
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/Acceptor.h b/contrib/llvm-project/lldb/tools/lldb-server/Acceptor.h
new file mode 100644
index 000000000000..b441e92dcd22
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/Acceptor.h
@@ -0,0 +1,60 @@
+//===-- Acceptor.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLDB_TOOLS_LLDB_SERVER_ACCEPTOR_H
+#define LLDB_TOOLS_LLDB_SERVER_ACCEPTOR_H
+
+#include "lldb/Host/Socket.h"
+#include "lldb/Utility/Connection.h"
+#include "lldb/Utility/Status.h"
+
+#include <functional>
+#include <memory>
+#include <string>
+
+namespace llvm {
+class StringRef;
+}
+
+namespace lldb_private {
+namespace lldb_server {
+
+class Acceptor {
+public:
+ virtual ~Acceptor() = default;
+
+ Status Listen(int backlog);
+
+ Status Accept(const bool child_processes_inherit, Connection *&conn);
+
+ static std::unique_ptr<Acceptor> Create(llvm::StringRef name,
+ const bool child_processes_inherit,
+ Status &error);
+
+ Socket::SocketProtocol GetSocketProtocol() const;
+
+ const char *GetSocketScheme() const;
+
+ // Returns either TCP port number as string or domain socket path.
+ // Empty string is returned in case of error.
+ std::string GetLocalSocketId() const;
+
+private:
+ typedef std::function<std::string()> LocalSocketIdFunc;
+
+ Acceptor(std::unique_ptr<Socket> &&listener_socket, llvm::StringRef name,
+ const LocalSocketIdFunc &local_socket_id);
+
+ const std::unique_ptr<Socket> m_listener_socket_up;
+ const std::string m_name;
+ const LocalSocketIdFunc m_local_socket_id;
+};
+
+} // namespace lldb_server
+} // namespace lldb_private
+
+#endif // LLDB_TOOLS_LLDB_SERVER_ACCEPTOR_H
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-Info.plist b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-Info.plist
new file mode 100644
index 000000000000..58a34ca5e438
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-Info.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.lldb-server</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>lldb-server</string>
+ <key>CFBundleVersion</key>
+ <string>2</string>
+ <key>SecTaskAccess</key>
+ <array>
+ <string>allowed</string>
+ <string>debug</string>
+ </array>
+</dict>
+</plist>
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-entitlements.plist b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-entitlements.plist
new file mode 100644
index 000000000000..e05a9baa5d0b
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-entitlements.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.springboard.debugapplications</key>
+ <true/>
+ <key>com.apple.backboardd.launchapplications</key>
+ <true/>
+ <key>com.apple.backboardd.debugapplications</key>
+ <true/>
+ <key>com.apple.frontboard.launchapplications</key>
+ <true/>
+ <key>com.apple.frontboard.debugapplications</key>
+ <true/>
+ <key>run-unsigned-code</key>
+ <true/>
+ <key>seatbelt-profiles</key>
+ <array>
+ <string>debugserver</string>
+ </array>
+ <key>com.apple.private.logging.diagnostic</key>
+ <true/>
+ <key>com.apple.security.network.server</key>
+ <true/>
+ <key>com.apple.security.network.client</key>
+ <true/>
+</dict>
+</plist>
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-macos-entitlements.plist b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-macos-entitlements.plist
new file mode 100644
index 000000000000..edf79b3b3eed
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-macos-entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.private.logging.diagnostic</key>
+ <true/>
+</dict>
+</plist>
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-mig.defs b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-mig.defs
new file mode 100644
index 000000000000..cd5be1700704
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/Darwin/resources/lldb-server-mig.defs
@@ -0,0 +1,5 @@
+/*
+ * nub.defs
+ */
+
+#import <mach/mach_exc.defs>
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.cpp b/contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.cpp
new file mode 100644
index 000000000000..c3a8df19e969
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.cpp
@@ -0,0 +1,79 @@
+//===-- LLDBServerUtilities.cpp ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LLDBServerUtilities.h"
+
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+
+using namespace lldb;
+using namespace lldb_private::lldb_server;
+using namespace lldb_private;
+using namespace llvm;
+
+class TestLogHandler : public LogHandler {
+public:
+ TestLogHandler(std::shared_ptr<llvm::raw_ostream> stream_sp)
+ : m_stream_sp(stream_sp) {}
+
+ void Emit(llvm::StringRef message) override {
+ (*m_stream_sp) << message;
+ m_stream_sp->flush();
+ }
+
+private:
+ std::shared_ptr<raw_ostream> m_stream_sp;
+};
+
+static std::shared_ptr<TestLogHandler> GetLogStream(StringRef log_file) {
+ if (!log_file.empty()) {
+ std::error_code EC;
+ auto stream_sp = std::make_shared<raw_fd_ostream>(
+ log_file, EC, sys::fs::OF_TextWithCRLF | sys::fs::OF_Append);
+ if (!EC)
+ return std::make_shared<TestLogHandler>(stream_sp);
+ errs() << llvm::formatv(
+ "Failed to open log file `{0}`: {1}\nWill log to stderr instead.\n",
+ log_file, EC.message());
+ }
+ // No need to delete the stderr stream.
+ return std::make_shared<TestLogHandler>(
+ std::shared_ptr<raw_ostream>(&errs(), [](raw_ostream *) {}));
+}
+
+bool LLDBServerUtilities::SetupLogging(const std::string &log_file,
+ const StringRef &log_channels,
+ uint32_t log_options) {
+
+ auto log_stream_sp = GetLogStream(log_file);
+
+ SmallVector<StringRef, 32> channel_array;
+ log_channels.split(channel_array, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+ for (auto channel_with_categories : channel_array) {
+ std::string error;
+ llvm::raw_string_ostream error_stream(error);
+ Args channel_then_categories(channel_with_categories);
+ std::string channel(channel_then_categories.GetArgumentAtIndex(0));
+ channel_then_categories.Shift(); // Shift off the channel
+
+ bool success = Log::EnableLogChannel(
+ log_stream_sp, log_options, channel,
+ channel_then_categories.GetArgumentArrayRef(), error_stream);
+ if (!success) {
+ errs() << formatv("Unable to setup logging for channel \"{0}\": {1}",
+ channel, error_stream.str());
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.h b/contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.h
new file mode 100644
index 000000000000..b59d1e411540
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/LLDBServerUtilities.h
@@ -0,0 +1,29 @@
+#ifndef LLDB_TOOLS_LLDB_SERVER_LLDBSERVERUTILITIES_H
+
+#define LLDB_TOOLS_LLDB_SERVER_LLDBSERVERUTILITIES_H
+
+//===-- LLDBServerUtilities.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+
+namespace lldb_private {
+namespace lldb_server {
+
+class LLDBServerUtilities {
+public:
+ static bool SetupLogging(const std::string &log_file,
+ const llvm::StringRef &log_channels,
+ uint32_t log_options);
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/LLGSOptions.td b/contrib/llvm-project/lldb/tools/lldb-server/LLGSOptions.td
new file mode 100644
index 000000000000..429a4671764f
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/LLGSOptions.td
@@ -0,0 +1,62 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name>: Flag<["--", "-"], name>;
+class R<list<string> prefixes, string name>
+ : Option<prefixes, name, KIND_REMAINING_ARGS>;
+
+multiclass SJ<string name, string help> {
+ def NAME: Separate<["--", "-"], name>,
+ HelpText<help>;
+ def NAME # _eq: Joined<["--", "-"], name # "=">,
+ Alias<!cast<Separate>(NAME)>;
+}
+
+def grp_connect : OptionGroup<"connection">, HelpText<"CONNECTION">;
+
+defm fd: SJ<"fd", "Communicate over the given file descriptor.">,
+ MetaVarName<"<fd>">,
+ Group<grp_connect>;
+
+defm named_pipe: SJ<"named-pipe", "Write port lldb-server will listen on to the given named pipe.">,
+ MetaVarName<"<name>">,
+ Group<grp_connect>;
+
+defm pipe: SJ<"pipe", "Write port lldb-server will listen on to the given file descriptor.">,
+ MetaVarName<"<fd>">,
+ Group<grp_connect>;
+
+def reverse_connect: F<"reverse-connect">,
+ HelpText<"Connect to the client instead of passively waiting for a connection. In this case [host]:port denotes the remote address to connect to.">,
+ Group<grp_connect>;
+
+def grp_general : OptionGroup<"general options">, HelpText<"GENERAL OPTIONS">;
+
+defm log_channels: SJ<"log-channels", "Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories.">,
+ MetaVarName<"<channel1 categories...:channel2 categories...>">,
+ Group<grp_general>;
+
+defm log_file: SJ<"log-file", "Destination file to log to. If empty, log to stderr.">,
+ MetaVarName<"<file>">,
+ Group<grp_general>;
+
+def setsid: F<"setsid">, HelpText<"Run lldb-server in a new session.">,
+ Group<grp_general>;
+def: Flag<["-"], "S">, Alias<setsid>,
+ Group<grp_general>;
+
+def help: F<"help">, HelpText<"Prints out the usage information for lldb-server.">,
+ Group<grp_general>;
+def: Flag<["-"], "h">, Alias<help>,
+ Group<grp_general>;
+
+def grp_target : OptionGroup<"target selection">, HelpText<"TARGET SELECTION">;
+
+defm attach: SJ<"attach", "Attach to the process given by a (numeric) process id or a name.">,
+ MetaVarName<"<pid-or-name>">,
+ Group<grp_target>;
+
+def REM : R<["--"], "">, HelpText<"Launch program for debugging.">,
+ MetaVarName<"program args">,
+ Group<grp_target>;
+
+def: F<"native-regs">; // Noop. Present for backwards compatibility only.
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
new file mode 100644
index 000000000000..4233252a84df
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
@@ -0,0 +1,101 @@
+//===-- SystemInitializerLLGS.cpp -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemInitializerLLGS.h"
+
+#if defined(__APPLE__)
+#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
+using HostObjectFile = ObjectFileMachO;
+#elif defined(_WIN32)
+#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+using HostObjectFile = ObjectFilePECOFF;
+#else
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+using HostObjectFile = ObjectFileELF;
+#endif
+
+#if defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
+#define LLDB_TARGET_ARM64
+#endif
+
+#if defined(__arm__) || defined(__arm) || defined(_ARM) || defined(_M_ARM) || \
+ defined(LLDB_TARGET_ARM64)
+#define LLDB_TARGET_ARM
+#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
+#endif
+
+#if defined(__loongarch__)
+#define LLDB_TARGET_LoongArch
+#include "Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h"
+#endif
+
+#if defined(__mips64__) || defined(mips64) || defined(__mips64) || \
+ defined(__MIPS64__) || defined(_M_MIPS64)
+#define LLDB_TARGET_MIPS64
+#include "Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h"
+#endif
+
+#if defined(__mips__) || defined(mips) || defined(__mips) || \
+ defined(__MIPS__) || defined(_M_MIPS) || defined(LLDB_TARGET_MIPS64)
+#define LLDB_TARGET_MIPS
+#include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h"
+#endif
+
+#if defined(__riscv)
+#define LLDB_TARGET_RISCV
+#include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h"
+#endif
+
+using namespace lldb_private;
+
+llvm::Error SystemInitializerLLGS::Initialize() {
+ if (auto e = SystemInitializerCommon::Initialize())
+ return e;
+
+ HostObjectFile::Initialize();
+
+#if defined(LLDB_TARGET_ARM) || defined(LLDB_TARGET_ARM64)
+ EmulateInstructionARM::Initialize();
+#endif
+#if defined(LLDB_TARGET_LoongArch)
+ EmulateInstructionLoongArch::Initialize();
+#endif
+#if defined(LLDB_TARGET_MIPS) || defined(LLDB_TARGET_MIPS64)
+ EmulateInstructionMIPS::Initialize();
+#endif
+#if defined(LLDB_TARGET_MIPS64)
+ EmulateInstructionMIPS64::Initialize();
+#endif
+#if defined(LLDB_TARGET_RISCV)
+ EmulateInstructionRISCV::Initialize();
+#endif
+
+ return llvm::Error::success();
+}
+
+void SystemInitializerLLGS::Terminate() {
+ HostObjectFile::Terminate();
+
+#if defined(LLDB_TARGET_ARM) || defined(LLDB_TARGET_ARM64)
+ EmulateInstructionARM::Terminate();
+#endif
+#if defined(LLDB_TARGET_LoongArch)
+ EmulateInstructionLoongArch::Terminate();
+#endif
+#if defined(LLDB_TARGET_MIPS) || defined(LLDB_TARGET_MIPS64)
+ EmulateInstructionMIPS::Terminate();
+#endif
+#if defined(LLDB_TARGET_MIPS64)
+ EmulateInstructionMIPS64::Terminate();
+#endif
+#if defined(LLDB_TARGET_RISCV)
+ EmulateInstructionRISCV::Terminate();
+#endif
+
+ SystemInitializerCommon::Terminate();
+}
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.h b/contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.h
new file mode 100644
index 000000000000..4469a8ba5f60
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/SystemInitializerLLGS.h
@@ -0,0 +1,23 @@
+//===-- SystemInitializerLLGS.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TOOLS_LLDB_SERVER_SYSTEMINITIALIZERLLGS_H
+#define LLDB_TOOLS_LLDB_SERVER_SYSTEMINITIALIZERLLGS_H
+
+#include "lldb/Initialization/SystemInitializer.h"
+#include "lldb/Initialization/SystemInitializerCommon.h"
+
+class SystemInitializerLLGS : public lldb_private::SystemInitializerCommon {
+public:
+ SystemInitializerLLGS() : SystemInitializerCommon(nullptr) {}
+
+ llvm::Error Initialize() override;
+ void Terminate() override;
+};
+
+#endif // LLDB_TOOLS_LLDB_SERVER_SYSTEMINITIALIZERLLGS_H
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp b/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp
new file mode 100644
index 000000000000..563284730bc7
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -0,0 +1,473 @@
+//===-- lldb-gdbserver.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#ifndef _WIN32
+#include <csignal>
+#include <unistd.h>
+#endif
+
+#include "LLDBServerUtilities.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Pipe.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/WithColor.h"
+
+#if defined(__linux__)
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+#elif defined(__FreeBSD__)
+#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
+#elif defined(__NetBSD__)
+#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
+#elif defined(_WIN32)
+#include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
+#endif
+
+#ifndef LLGS_PROGRAM_NAME
+#define LLGS_PROGRAM_NAME "lldb-server"
+#endif
+
+#ifndef LLGS_VERSION_STR
+#define LLGS_VERSION_STR "local_build"
+#endif
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+using namespace lldb_private::process_gdb_remote;
+
+namespace {
+#if defined(__linux__)
+typedef process_linux::NativeProcessLinux::Manager NativeProcessManager;
+#elif defined(__FreeBSD__)
+typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager;
+#elif defined(__NetBSD__)
+typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager;
+#elif defined(_WIN32)
+typedef NativeProcessWindows::Manager NativeProcessManager;
+#else
+// Dummy implementation to make sure the code compiles
+class NativeProcessManager : public NativeProcessProtocol::Manager {
+public:
+ NativeProcessManager(MainLoop &mainloop)
+ : NativeProcessProtocol::Manager(mainloop) {}
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info,
+ NativeProcessProtocol::NativeDelegate &native_delegate) override {
+ llvm_unreachable("Not implemented");
+ }
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid,
+ NativeProcessProtocol::NativeDelegate &native_delegate) override {
+ llvm_unreachable("Not implemented");
+ }
+};
+#endif
+}
+
+#ifndef _WIN32
+// Watch for signals
+static int g_sighup_received_count = 0;
+
+static void sighup_handler(MainLoopBase &mainloop) {
+ ++g_sighup_received_count;
+
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)",
+ __FUNCTION__, g_sighup_received_count);
+
+ if (g_sighup_received_count >= 2)
+ mainloop.RequestTermination();
+}
+#endif // #ifndef _WIN32
+
+void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server,
+ lldb::pid_t pid) {
+ Status error = gdb_server.AttachToProcess(pid);
+ if (error.Fail()) {
+ fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid,
+ error.AsCString());
+ exit(1);
+ }
+}
+
+void handle_attach_to_process_name(GDBRemoteCommunicationServerLLGS &gdb_server,
+ const std::string &process_name) {
+ // FIXME implement.
+}
+
+void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server,
+ const std::string &attach_target) {
+ assert(!attach_target.empty() && "attach_target cannot be empty");
+
+ // First check if the attach_target is convertible to a long. If so, we'll use
+ // it as a pid.
+ char *end_p = nullptr;
+ const long int pid = strtol(attach_target.c_str(), &end_p, 10);
+
+ // We'll call it a match if the entire argument is consumed.
+ if (end_p &&
+ static_cast<size_t>(end_p - attach_target.c_str()) ==
+ attach_target.size())
+ handle_attach_to_pid(gdb_server, static_cast<lldb::pid_t>(pid));
+ else
+ handle_attach_to_process_name(gdb_server, attach_target);
+}
+
+void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server,
+ llvm::ArrayRef<llvm::StringRef> Arguments) {
+ ProcessLaunchInfo info;
+ info.GetFlags().Set(eLaunchFlagStopAtEntry | eLaunchFlagDebug |
+ eLaunchFlagDisableASLR);
+ info.SetArguments(Args(Arguments), true);
+
+ llvm::SmallString<64> cwd;
+ if (std::error_code ec = llvm::sys::fs::current_path(cwd)) {
+ llvm::errs() << "Error getting current directory: " << ec.message() << "\n";
+ exit(1);
+ }
+ FileSpec cwd_spec(cwd);
+ FileSystem::Instance().Resolve(cwd_spec);
+ info.SetWorkingDirectory(cwd_spec);
+ info.GetEnvironment() = Host::GetEnvironment();
+
+ gdb_server.SetLaunchInfo(info);
+
+ Status error = gdb_server.LaunchProcess();
+ if (error.Fail()) {
+ llvm::errs() << llvm::formatv("error: failed to launch '{0}': {1}\n",
+ Arguments[0], error);
+ exit(1);
+ }
+}
+
+Status writeSocketIdToPipe(Pipe &port_pipe, llvm::StringRef socket_id) {
+ size_t bytes_written = 0;
+ // Write the port number as a C string with the NULL terminator.
+ return port_pipe.Write(socket_id.data(), socket_id.size() + 1, bytes_written);
+}
+
+Status writeSocketIdToPipe(const char *const named_pipe_path,
+ llvm::StringRef socket_id) {
+ Pipe port_name_pipe;
+ // Wait for 10 seconds for pipe to be opened.
+ auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
+ std::chrono::seconds{10});
+ if (error.Fail())
+ return error;
+ return writeSocketIdToPipe(port_name_pipe, socket_id);
+}
+
+Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
+ llvm::StringRef socket_id) {
+ Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
+ return writeSocketIdToPipe(port_pipe, socket_id);
+}
+
+void ConnectToRemote(MainLoop &mainloop,
+ GDBRemoteCommunicationServerLLGS &gdb_server,
+ bool reverse_connect, llvm::StringRef host_and_port,
+ const char *const progname, const char *const subcommand,
+ const char *const named_pipe_path, pipe_t unnamed_pipe,
+ int connection_fd) {
+ Status error;
+
+ std::unique_ptr<Connection> connection_up;
+ std::string url;
+
+ if (connection_fd != -1) {
+ url = llvm::formatv("fd://{0}", connection_fd).str();
+
+ // Create the connection.
+#if LLDB_ENABLE_POSIX && !defined _WIN32
+ ::fcntl(connection_fd, F_SETFD, FD_CLOEXEC);
+#endif
+ } else if (!host_and_port.empty()) {
+ llvm::Expected<std::string> url_exp =
+ LLGSArgToURL(host_and_port, reverse_connect);
+ if (!url_exp) {
+ llvm::errs() << llvm::formatv("error: invalid host:port or URL '{0}': "
+ "{1}\n",
+ host_and_port,
+ llvm::toString(url_exp.takeError()));
+ exit(-1);
+ }
+
+ url = std::move(url_exp.get());
+ }
+
+ if (!url.empty()) {
+ // Create the connection or server.
+ std::unique_ptr<ConnectionFileDescriptor> conn_fd_up{
+ new ConnectionFileDescriptor};
+ auto connection_result = conn_fd_up->Connect(
+ url,
+ [named_pipe_path, unnamed_pipe](llvm::StringRef socket_id) {
+ // If we have a named pipe to write the socket id back to, do that
+ // now.
+ if (named_pipe_path && named_pipe_path[0]) {
+ Status error = writeSocketIdToPipe(named_pipe_path, socket_id);
+ if (error.Fail())
+ llvm::errs() << llvm::formatv(
+ "failed to write to the named pipe '{0}': {1}\n",
+ named_pipe_path, error.AsCString());
+ }
+ // If we have an unnamed pipe to write the socket id back to, do
+ // that now.
+ else if (unnamed_pipe != LLDB_INVALID_PIPE) {
+ Status error = writeSocketIdToPipe(unnamed_pipe, socket_id);
+ if (error.Fail())
+ llvm::errs() << llvm::formatv(
+ "failed to write to the unnamed pipe: {0}\n", error);
+ }
+ },
+ &error);
+
+ if (error.Fail()) {
+ llvm::errs() << llvm::formatv(
+ "error: failed to connect to client at '{0}': {1}\n", url, error);
+ exit(-1);
+ }
+ if (connection_result != eConnectionStatusSuccess) {
+ llvm::errs() << llvm::formatv(
+ "error: failed to connect to client at '{0}' "
+ "(connection status: {1})\n",
+ url, static_cast<int>(connection_result));
+ exit(-1);
+ }
+ connection_up = std::move(conn_fd_up);
+ }
+ error = gdb_server.InitializeConnection(std::move(connection_up));
+ if (error.Fail()) {
+ llvm::errs() << llvm::formatv("failed to initialize connection\n", error);
+ exit(-1);
+ }
+ llvm::outs() << "Connection established.\n";
+}
+
+namespace {
+using namespace llvm::opt;
+
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
+#include "LLGSOptions.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) \
+ constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
+ constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
+ NAME##_init, std::size(NAME##_init) - 1);
+#include "LLGSOptions.inc"
+#undef PREFIX
+
+static constexpr opt::OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#include "LLGSOptions.inc"
+#undef OPTION
+};
+
+class LLGSOptTable : public opt::GenericOptTable {
+public:
+ LLGSOptTable() : opt::GenericOptTable(InfoTable) {}
+
+ void PrintHelp(llvm::StringRef Name) {
+ std::string Usage =
+ (Name + " [options] [[host]:port] [[--] program args...]").str();
+ OptTable::printHelp(llvm::outs(), Usage.c_str(), "lldb-server");
+ llvm::outs() << R"(
+DESCRIPTION
+ lldb-server connects to the LLDB client, which drives the debugging session.
+ If no connection options are given, the [host]:port argument must be present
+ and will denote the address that lldb-server will listen on. [host] defaults
+ to "localhost" if empty. Port can be zero, in which case the port number will
+ be chosen dynamically and written to destinations given by --named-pipe and
+ --pipe arguments.
+
+ If no target is selected at startup, lldb-server can be directed by the LLDB
+ client to launch or attach to a process.
+
+)";
+ }
+};
+} // namespace
+
+int main_gdbserver(int argc, char *argv[]) {
+ Status error;
+ MainLoop mainloop;
+#ifndef _WIN32
+ // Setup signal handlers first thing.
+ signal(SIGPIPE, SIG_IGN);
+ MainLoop::SignalHandleUP sighup_handle =
+ mainloop.RegisterSignal(SIGHUP, sighup_handler, error);
+#endif
+
+ const char *progname = argv[0];
+ const char *subcommand = argv[1];
+ std::string attach_target;
+ std::string named_pipe_path;
+ std::string log_file;
+ StringRef
+ log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
+ lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE;
+ bool reverse_connect = false;
+ int connection_fd = -1;
+
+ // ProcessLaunchInfo launch_info;
+ ProcessAttachInfo attach_info;
+
+ LLGSOptTable Opts;
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Saver(Alloc);
+ bool HasError = false;
+ opt::InputArgList Args = Opts.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN,
+ Saver, [&](llvm::StringRef Msg) {
+ WithColor::error() << Msg << "\n";
+ HasError = true;
+ });
+ std::string Name =
+ (llvm::sys::path::filename(argv[0]) + " g[dbserver]").str();
+ std::string HelpText =
+ "Use '" + Name + " --help' for a complete list of options.\n";
+ if (HasError) {
+ llvm::errs() << HelpText;
+ return 1;
+ }
+
+ if (Args.hasArg(OPT_help)) {
+ Opts.PrintHelp(Name);
+ return 0;
+ }
+
+#ifndef _WIN32
+ if (Args.hasArg(OPT_setsid)) {
+ // Put llgs into a new session. Terminals group processes
+ // into sessions and when a special terminal key sequences
+ // (like control+c) are typed they can cause signals to go out to
+ // all processes in a session. Using this --setsid (-S) option
+ // will cause debugserver to run in its own sessions and be free
+ // from such issues.
+ //
+ // This is useful when llgs is spawned from a command
+ // line application that uses llgs to do the debugging,
+ // yet that application doesn't want llgs receiving the
+ // signals sent to the session (i.e. dying when anyone hits ^C).
+ {
+ const ::pid_t new_sid = setsid();
+ if (new_sid == -1) {
+ WithColor::warning()
+ << llvm::formatv("failed to set new session id for {0} ({1})\n",
+ LLGS_PROGRAM_NAME, llvm::sys::StrError());
+ }
+ }
+ }
+#endif
+
+ log_file = Args.getLastArgValue(OPT_log_file).str();
+ log_channels = Args.getLastArgValue(OPT_log_channels);
+ named_pipe_path = Args.getLastArgValue(OPT_named_pipe).str();
+ reverse_connect = Args.hasArg(OPT_reverse_connect);
+ attach_target = Args.getLastArgValue(OPT_attach).str();
+ if (Args.hasArg(OPT_pipe)) {
+ uint64_t Arg;
+ if (!llvm::to_integer(Args.getLastArgValue(OPT_pipe), Arg)) {
+ WithColor::error() << "invalid '--pipe' argument\n" << HelpText;
+ return 1;
+ }
+ unnamed_pipe = (pipe_t)Arg;
+ }
+ if (Args.hasArg(OPT_fd)) {
+ if (!llvm::to_integer(Args.getLastArgValue(OPT_fd), connection_fd)) {
+ WithColor::error() << "invalid '--fd' argument\n" << HelpText;
+ return 1;
+ }
+ }
+
+ if (!LLDBServerUtilities::SetupLogging(
+ log_file, log_channels,
+ LLDB_LOG_OPTION_PREPEND_TIMESTAMP |
+ LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION))
+ return -1;
+
+ std::vector<llvm::StringRef> Inputs;
+ for (opt::Arg *Arg : Args.filtered(OPT_INPUT))
+ Inputs.push_back(Arg->getValue());
+ if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) {
+ for (const char *Val : Arg->getValues())
+ Inputs.push_back(Val);
+ }
+ if (Inputs.empty() && connection_fd == -1) {
+ WithColor::error() << "no connection arguments\n" << HelpText;
+ return 1;
+ }
+
+ NativeProcessManager manager(mainloop);
+ GDBRemoteCommunicationServerLLGS gdb_server(mainloop, manager);
+
+ llvm::StringRef host_and_port;
+ if (!Inputs.empty()) {
+ host_and_port = Inputs.front();
+ Inputs.erase(Inputs.begin());
+ }
+
+ // Any arguments left over are for the program that we need to launch. If
+ // there
+ // are no arguments, then the GDB server will start up and wait for an 'A'
+ // packet
+ // to launch a program, or a vAttach packet to attach to an existing process,
+ // unless
+ // explicitly asked to attach with the --attach={pid|program_name} form.
+ if (!attach_target.empty())
+ handle_attach(gdb_server, attach_target);
+ else if (!Inputs.empty())
+ handle_launch(gdb_server, Inputs);
+
+ // Print version info.
+ printf("%s-%s\n", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
+
+ ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
+ progname, subcommand, named_pipe_path.c_str(),
+ unnamed_pipe, connection_fd);
+
+ if (!gdb_server.IsConnected()) {
+ fprintf(stderr, "no connection information provided, unable to run\n");
+ return 1;
+ }
+
+ Status ret = mainloop.Run();
+ if (ret.Fail()) {
+ fprintf(stderr, "lldb-server terminating due to error: %s\n",
+ ret.AsCString());
+ return 1;
+ }
+ fprintf(stderr, "lldb-server exiting...\n");
+
+ return 0;
+}
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp b/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp
new file mode 100644
index 000000000000..7148a1d2a309
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp
@@ -0,0 +1,385 @@
+//===-- lldb-platform.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#if defined(__APPLE__)
+#include <netinet/in.h>
+#endif
+#include <csignal>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#if !defined(_WIN32)
+#include <sys/wait.h>
+#endif
+#include <fstream>
+#include <optional>
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "Acceptor.h"
+#include "LLDBServerUtilities.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/HostGetOpt.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+using namespace lldb_private::process_gdb_remote;
+using namespace llvm;
+
+// option descriptors for getopt_long_only()
+
+static int g_debug = 0;
+static int g_verbose = 0;
+static int g_server = 0;
+
+static struct option g_long_options[] = {
+ {"debug", no_argument, &g_debug, 1},
+ {"verbose", no_argument, &g_verbose, 1},
+ {"log-file", required_argument, nullptr, 'l'},
+ {"log-channels", required_argument, nullptr, 'c'},
+ {"listen", required_argument, nullptr, 'L'},
+ {"port-offset", required_argument, nullptr, 'p'},
+ {"gdbserver-port", required_argument, nullptr, 'P'},
+ {"min-gdbserver-port", required_argument, nullptr, 'm'},
+ {"max-gdbserver-port", required_argument, nullptr, 'M'},
+ {"socket-file", required_argument, nullptr, 'f'},
+ {"server", no_argument, &g_server, 1},
+ {nullptr, 0, nullptr, 0}};
+
+#if defined(__APPLE__)
+#define LOW_PORT (IPPORT_RESERVED)
+#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
+#else
+#define LOW_PORT (1024u)
+#define HIGH_PORT (49151u)
+#endif
+
+#if !defined(_WIN32)
+// Watch for signals
+static void signal_handler(int signo) {
+ switch (signo) {
+ case SIGHUP:
+ // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
+ // And we should not call exit() here because it results in the global
+ // destructors to be invoked and wreaking havoc on the threads still
+ // running.
+ llvm::errs() << "SIGHUP received, exiting lldb-server...\n";
+ abort();
+ break;
+ }
+}
+#endif
+
+static void display_usage(const char *progname, const char *subcommand) {
+ fprintf(stderr, "Usage:\n %s %s [--log-file log-file-name] [--log-channels "
+ "log-channel-list] [--port-file port-file-path] --server "
+ "--listen port\n",
+ progname, subcommand);
+ exit(0);
+}
+
+static Status save_socket_id_to_file(const std::string &socket_id,
+ const FileSpec &file_spec) {
+ FileSpec temp_file_spec(file_spec.GetDirectory().GetStringRef());
+ Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
+ if (error.Fail())
+ return Status("Failed to create directory %s: %s",
+ temp_file_spec.GetPath().c_str(), error.AsCString());
+
+ Status status;
+ if (auto Err = llvm::writeToOutput(file_spec.GetPath(),
+ [&socket_id](llvm::raw_ostream &OS) {
+ OS << socket_id;
+ return llvm::Error::success();
+ }))
+ return Status("Failed to atomically write file %s: %s",
+ file_spec.GetPath().c_str(),
+ llvm::toString(std::move(Err)).c_str());
+ return status;
+}
+
+// main
+int main_platform(int argc, char *argv[]) {
+ const char *progname = argv[0];
+ const char *subcommand = argv[1];
+ argc--;
+ argv++;
+#if !defined(_WIN32)
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, signal_handler);
+#endif
+ int long_option_index = 0;
+ Status error;
+ std::string listen_host_port;
+ int ch;
+
+ std::string log_file;
+ StringRef
+ log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
+
+ GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap;
+ int min_gdbserver_port = 0;
+ int max_gdbserver_port = 0;
+ uint16_t port_offset = 0;
+
+ FileSpec socket_file;
+ bool show_usage = false;
+ int option_error = 0;
+ int socket_error = -1;
+
+ std::string short_options(OptionParser::GetShortOptionString(g_long_options));
+
+#if __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+
+ while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
+ g_long_options, &long_option_index)) != -1) {
+ switch (ch) {
+ case 0: // Any optional that auto set themselves will return 0
+ break;
+
+ case 'L':
+ listen_host_port.append(optarg);
+ break;
+
+ case 'l': // Set Log File
+ if (optarg && optarg[0])
+ log_file.assign(optarg);
+ break;
+
+ case 'c': // Log Channels
+ if (optarg && optarg[0])
+ log_channels = StringRef(optarg);
+ break;
+
+ case 'f': // Socket file
+ if (optarg && optarg[0])
+ socket_file.SetFile(optarg, FileSpec::Style::native);
+ break;
+
+ case 'p': {
+ if (!llvm::to_integer(optarg, port_offset)) {
+ WithColor::error() << "invalid port offset string " << optarg << "\n";
+ option_error = 4;
+ break;
+ }
+ if (port_offset < LOW_PORT || port_offset > HIGH_PORT) {
+ WithColor::error() << llvm::formatv(
+ "port offset {0} is not in the "
+ "valid user port range of {1} - {2}\n",
+ port_offset, LOW_PORT, HIGH_PORT);
+ option_error = 5;
+ }
+ } break;
+
+ case 'P':
+ case 'm':
+ case 'M': {
+ uint16_t portnum;
+ if (!llvm::to_integer(optarg, portnum)) {
+ WithColor::error() << "invalid port number string " << optarg << "\n";
+ option_error = 2;
+ break;
+ }
+ if (portnum < LOW_PORT || portnum > HIGH_PORT) {
+ WithColor::error() << llvm::formatv(
+ "port number {0} is not in the "
+ "valid user port range of {1} - {2}\n",
+ portnum, LOW_PORT, HIGH_PORT);
+ option_error = 1;
+ break;
+ }
+ if (ch == 'P')
+ gdbserver_portmap.AllowPort(portnum);
+ else if (ch == 'm')
+ min_gdbserver_port = portnum;
+ else
+ max_gdbserver_port = portnum;
+ } break;
+
+ case 'h': /* fall-through is intentional */
+ case '?':
+ show_usage = true;
+ break;
+ }
+ }
+
+ if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
+ return -1;
+
+ // Make a port map for a port range that was specified.
+ if (min_gdbserver_port && min_gdbserver_port < max_gdbserver_port) {
+ gdbserver_portmap = GDBRemoteCommunicationServerPlatform::PortMap(
+ min_gdbserver_port, max_gdbserver_port);
+ } else if (min_gdbserver_port || max_gdbserver_port) {
+ WithColor::error() << llvm::formatv(
+ "--min-gdbserver-port ({0}) is not lower than "
+ "--max-gdbserver-port ({1})\n",
+ min_gdbserver_port, max_gdbserver_port);
+ option_error = 3;
+ }
+
+ // Print usage and exit if no listening port is specified.
+ if (listen_host_port.empty())
+ show_usage = true;
+
+ if (show_usage || option_error) {
+ display_usage(progname, subcommand);
+ exit(option_error);
+ }
+
+ // Skip any options we consumed with getopt_long_only.
+ argc -= optind;
+ argv += optind;
+ lldb_private::Args inferior_arguments;
+ inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
+
+ const bool children_inherit_listen_socket = false;
+ // the test suite makes many connections in parallel, let's not miss any.
+ // The highest this should get reasonably is a function of the number
+ // of target CPUs. For now, let's just use 100.
+ const int backlog = 100;
+
+ std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
+ listen_host_port, children_inherit_listen_socket, error));
+ if (error.Fail()) {
+ fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
+ exit(socket_error);
+ }
+
+ error = acceptor_up->Listen(backlog);
+ if (error.Fail()) {
+ printf("failed to listen: %s\n", error.AsCString());
+ exit(socket_error);
+ }
+ if (socket_file) {
+ error =
+ save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
+ if (error.Fail()) {
+ fprintf(stderr, "failed to write socket id to %s: %s\n",
+ socket_file.GetPath().c_str(), error.AsCString());
+ return 1;
+ }
+ }
+
+ GDBRemoteCommunicationServerPlatform platform(
+ acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
+ if (port_offset > 0)
+ platform.SetPortOffset(port_offset);
+
+ do {
+ const bool children_inherit_accept_socket = true;
+ Connection *conn = nullptr;
+ error = acceptor_up->Accept(children_inherit_accept_socket, conn);
+ if (error.Fail()) {
+ WithColor::error() << error.AsCString() << '\n';
+ exit(socket_error);
+ }
+ printf("Connection established.\n");
+
+ if (g_server) {
+ // Collect child zombie processes.
+#if !defined(_WIN32)
+ ::pid_t waitResult;
+ while ((waitResult = waitpid(-1, nullptr, WNOHANG)) > 0) {
+ // waitResult is the child pid
+ gdbserver_portmap.FreePortForProcess(waitResult);
+ }
+#endif
+ // TODO: Clean up portmap for Windows when children die
+ // See https://github.com/llvm/llvm-project/issues/90923
+
+ // After collecting zombie ports, get the next available
+ GDBRemoteCommunicationServerPlatform::PortMap portmap_for_child;
+ llvm::Expected<uint16_t> available_port =
+ gdbserver_portmap.GetNextAvailablePort();
+ if (available_port) {
+ // GetNextAvailablePort() may return 0 if gdbserver_portmap is empty.
+ if (*available_port)
+ portmap_for_child.AllowPort(*available_port);
+ } else {
+ llvm::consumeError(available_port.takeError());
+ fprintf(stderr,
+ "no available gdbserver port for connection - dropping...\n");
+ delete conn;
+ continue;
+ }
+ platform.SetPortMap(std::move(portmap_for_child));
+
+ auto childPid = fork();
+ if (childPid) {
+ gdbserver_portmap.AssociatePortWithProcess(*available_port, childPid);
+ // Parent doesn't need a connection to the lldb client
+ delete conn;
+
+ // Parent will continue to listen for new connections.
+ continue;
+ } else {
+ // Child process will handle the connection and exit.
+ g_server = 0;
+ // Listening socket is owned by parent process.
+ acceptor_up.release();
+ }
+ } else {
+ // If not running as a server, this process will not accept
+ // connections while a connection is active.
+ acceptor_up.reset();
+
+ // When not running in server mode, use all available ports
+ platform.SetPortMap(std::move(gdbserver_portmap));
+ }
+
+ platform.SetConnection(std::unique_ptr<Connection>(conn));
+
+ if (platform.IsConnected()) {
+ if (inferior_arguments.GetArgumentCount() > 0) {
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ std::optional<uint16_t> port;
+ std::string socket_name;
+ Status error = platform.LaunchGDBServer(inferior_arguments,
+ "", // hostname
+ pid, port, socket_name);
+ if (error.Success())
+ platform.SetPendingGdbServer(pid, *port, socket_name);
+ else
+ fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString());
+ }
+
+ bool interrupt = false;
+ bool done = false;
+ while (!interrupt && !done) {
+ if (platform.GetPacketAndSendResponse(std::nullopt, error, interrupt,
+ done) !=
+ GDBRemoteCommunication::PacketResult::Success)
+ break;
+ }
+
+ if (error.Fail())
+ WithColor::error() << error.AsCString() << '\n';
+ }
+ } while (g_server);
+
+ fprintf(stderr, "lldb-server exiting...\n");
+
+ return 0;
+}
diff --git a/contrib/llvm-project/lldb/tools/lldb-server/lldb-server.cpp b/contrib/llvm-project/lldb/tools/lldb-server/lldb-server.cpp
new file mode 100644
index 000000000000..e2e6bfcd8645
--- /dev/null
+++ b/contrib/llvm-project/lldb/tools/lldb-server/lldb-server.cpp
@@ -0,0 +1,82 @@
+//===-- lldb-server.cpp -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemInitializerLLGS.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Initialization/SystemLifetimeManager.h"
+#include "lldb/Version/Version.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+static llvm::ManagedStatic<lldb_private::SystemLifetimeManager>
+ g_debugger_lifetime;
+
+static void display_usage(const char *progname) {
+ fprintf(stderr, "Usage:\n"
+ " %s v[ersion]\n"
+ " %s g[dbserver] [options]\n"
+ " %s p[latform] [options]\n"
+ "Invoke subcommand for additional help\n",
+ progname, progname, progname);
+ exit(0);
+}
+
+// Forward declarations of subcommand main methods.
+int main_gdbserver(int argc, char *argv[]);
+int main_platform(int argc, char *argv[]);
+
+namespace llgs {
+static void initialize() {
+ if (auto e = g_debugger_lifetime->Initialize(
+ std::make_unique<SystemInitializerLLGS>(), nullptr))
+ llvm::consumeError(std::move(e));
+}
+
+static void terminate_debugger() { g_debugger_lifetime->Terminate(); }
+} // namespace llgs
+
+// main
+int main(int argc, char *argv[]) {
+ llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
+ llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
+ " and include the crash backtrace.\n");
+
+ int option_error = 0;
+ const char *progname = argv[0];
+ if (argc < 2) {
+ display_usage(progname);
+ exit(option_error);
+ }
+
+ switch (argv[1][0]) {
+ case 'g':
+ llgs::initialize();
+ main_gdbserver(argc, argv);
+ llgs::terminate_debugger();
+ break;
+ case 'p':
+ llgs::initialize();
+ main_platform(argc, argv);
+ llgs::terminate_debugger();
+ break;
+ case 'v':
+ fprintf(stderr, "%s\n", lldb_private::GetVersion());
+ break;
+ default:
+ display_usage(progname);
+ exit(option_error);
+ }
+}