CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
244 lines
7.6 KiB
C++
244 lines
7.6 KiB
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 "lldb/Host/Config.h"
|
|
#include "lldb/Host/File.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/Host.h"
|
|
#include "lldb/Host/MainLoop.h"
|
|
#include "lldb/Host/MainLoopBase.h"
|
|
#include "lldb/Host/ProcessLaunchInfo.h"
|
|
#include "lldb/Host/Socket.h"
|
|
#include "lldb/Initialization/SystemInitializerCommon.h"
|
|
#include "lldb/Initialization/SystemLifetimeManager.h"
|
|
#include "lldb/Protocol/MCP/Server.h"
|
|
#include "lldb/Utility/FileSpec.h"
|
|
#include "lldb/Utility/Status.h"
|
|
#include "lldb/Utility/UriParser.h"
|
|
#include "lldb/lldb-forward.h"
|
|
#include "llvm/ADT/ScopeExit.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/InitLLVM.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/Signals.h"
|
|
#include "llvm/Support/WithColor.h"
|
|
#include <chrono>
|
|
#include <cstdlib>
|
|
#include <memory>
|
|
#include <thread>
|
|
|
|
#if defined(_WIN32)
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
using namespace llvm;
|
|
using namespace lldb;
|
|
using namespace lldb_protocol::mcp;
|
|
|
|
using lldb_private::Environment;
|
|
using lldb_private::File;
|
|
using lldb_private::FileSpec;
|
|
using lldb_private::FileSystem;
|
|
using lldb_private::Host;
|
|
using lldb_private::MainLoop;
|
|
using lldb_private::MainLoopBase;
|
|
using lldb_private::NativeFile;
|
|
|
|
namespace {
|
|
|
|
#if defined(_WIN32)
|
|
constexpr StringLiteral kDriverName = "lldb.exe";
|
|
#else
|
|
constexpr StringLiteral kDriverName = "lldb";
|
|
#endif
|
|
|
|
constexpr size_t kForwardIOBufferSize = 1024;
|
|
|
|
inline void exitWithError(llvm::Error Err, StringRef Prefix = "") {
|
|
handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
|
|
WithColor::error(errs(), Prefix) << Info.message() << '\n';
|
|
});
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
|
|
FileSpec driverPath() {
|
|
Environment host_env = Host::GetEnvironment();
|
|
|
|
// Check if an override for which lldb we're using exists, otherwise look next
|
|
// to the current binary.
|
|
std::string lldb_exe_path = host_env.lookup("LLDB_EXE_PATH");
|
|
auto &fs = FileSystem::Instance();
|
|
if (fs.Exists(lldb_exe_path))
|
|
return FileSpec(lldb_exe_path);
|
|
|
|
FileSpec lldb_exec_spec = lldb_private::HostInfo::GetProgramFileSpec();
|
|
lldb_exec_spec.SetFilename(kDriverName);
|
|
return lldb_exec_spec;
|
|
}
|
|
|
|
llvm::Error launch() {
|
|
FileSpec lldb_exec = driverPath();
|
|
lldb_private::ProcessLaunchInfo info;
|
|
info.SetMonitorProcessCallback(
|
|
&lldb_private::ProcessLaunchInfo::NoOpMonitorCallback);
|
|
info.SetExecutableFile(lldb_exec,
|
|
/*add_exe_file_as_first_arg=*/true);
|
|
info.GetArguments().AppendArgument("-O");
|
|
info.GetArguments().AppendArgument("protocol start MCP");
|
|
return Host::LaunchProcess(info).takeError();
|
|
}
|
|
|
|
Expected<ServerInfo> loadOrStart(
|
|
// FIXME: This should become a CLI arg.
|
|
lldb_private::Timeout<std::micro> timeout = std::chrono::seconds(30)) {
|
|
using namespace std::chrono;
|
|
bool started = false;
|
|
|
|
const auto deadline = steady_clock::now() + *timeout;
|
|
while (steady_clock::now() < deadline) {
|
|
Expected<std::vector<ServerInfo>> servers = ServerInfo::Load();
|
|
if (!servers)
|
|
return servers.takeError();
|
|
|
|
if (servers->empty()) {
|
|
if (!started) {
|
|
started = true;
|
|
if (llvm::Error err = launch())
|
|
return std::move(err);
|
|
}
|
|
|
|
// FIXME: Can we use MainLoop to watch the directory?
|
|
std::this_thread::sleep_for(microseconds(250));
|
|
continue;
|
|
}
|
|
|
|
// FIXME: Support selecting / multiplexing a specific lldb instance.
|
|
if (servers->size() > 1)
|
|
return createStringError("too many MCP servers running, picking a "
|
|
"specific one is not yet implemented");
|
|
|
|
return servers->front();
|
|
}
|
|
|
|
return createStringError("timed out waiting for MCP server to start");
|
|
}
|
|
|
|
void forwardIO(MainLoopBase &loop, IOObjectSP &from, IOObjectSP &to) {
|
|
char buf[kForwardIOBufferSize];
|
|
size_t num_bytes = sizeof(buf);
|
|
|
|
if (llvm::Error err = from->Read(buf, num_bytes).takeError())
|
|
exitWithError(std::move(err));
|
|
|
|
// EOF reached.
|
|
if (num_bytes == 0)
|
|
return loop.RequestTermination();
|
|
|
|
if (llvm::Error err = to->Write(buf, num_bytes).takeError())
|
|
exitWithError(std::move(err));
|
|
}
|
|
|
|
llvm::Error connectAndForwardIO(lldb_private::MainLoop &loop, ServerInfo &info,
|
|
IOObjectSP &input_sp, IOObjectSP &output_sp) {
|
|
auto uri = lldb_private::URI::Parse(info.connection_uri);
|
|
if (!uri)
|
|
return createStringError("invalid connection_uri");
|
|
|
|
std::optional<lldb_private::Socket::ProtocolModePair> protocol_and_mode =
|
|
lldb_private::Socket::GetProtocolAndMode(uri->scheme);
|
|
|
|
if (!protocol_and_mode)
|
|
return createStringError("unknown protocol scheme");
|
|
|
|
lldb_private::Status status;
|
|
std::unique_ptr<lldb_private::Socket> sock =
|
|
lldb_private::Socket::Create(protocol_and_mode->first, status);
|
|
|
|
if (status.Fail())
|
|
return status.takeError();
|
|
|
|
if (uri->port && !uri->hostname.empty())
|
|
status = sock->Connect(
|
|
llvm::formatv("[{0}]:{1}", uri->hostname, *uri->port).str());
|
|
else
|
|
status = sock->Connect(uri->path);
|
|
if (status.Fail())
|
|
return status.takeError();
|
|
|
|
IOObjectSP sock_sp = std::move(sock);
|
|
auto input_handle = loop.RegisterReadObject(
|
|
input_sp, std::bind(forwardIO, std::placeholders::_1, input_sp, sock_sp),
|
|
status);
|
|
if (status.Fail())
|
|
return status.takeError();
|
|
|
|
auto socket_handle = loop.RegisterReadObject(
|
|
sock_sp, std::bind(forwardIO, std::placeholders::_1, sock_sp, output_sp),
|
|
status);
|
|
if (status.Fail())
|
|
return status.takeError();
|
|
|
|
return loop.Run().takeError();
|
|
}
|
|
|
|
llvm::ManagedStatic<lldb_private::SystemLifetimeManager> g_debugger_lifetime;
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char *argv[]) {
|
|
llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
|
|
#if !defined(__APPLE__)
|
|
llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
|
|
" and include the crash backtrace.\n");
|
|
#else
|
|
llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
|
|
" and include the crash report from "
|
|
"~/Library/Logs/DiagnosticReports/.\n");
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
// Windows opens stdout and stdin in text mode which converts \n to 13,10
|
|
// while the value is just 10 on Darwin/Linux. Setting the file mode to
|
|
// binary fixes this.
|
|
int result = _setmode(fileno(stdout), _O_BINARY);
|
|
assert(result);
|
|
result = _setmode(fileno(stdin), _O_BINARY);
|
|
UNUSED_IF_ASSERT_DISABLED(result);
|
|
assert(result);
|
|
#endif
|
|
|
|
if (llvm::Error err = g_debugger_lifetime->Initialize(
|
|
std::make_unique<lldb_private::SystemInitializerCommon>()))
|
|
exitWithError(std::move(err));
|
|
|
|
llvm::scope_exit cleanup([] { g_debugger_lifetime->Terminate(); });
|
|
|
|
IOObjectSP input_sp = std::make_shared<NativeFile>(
|
|
fileno(stdin), File::eOpenOptionReadOnly, NativeFile::Unowned);
|
|
|
|
IOObjectSP output_sp = std::make_shared<NativeFile>(
|
|
fileno(stdout), File::eOpenOptionWriteOnly, NativeFile::Unowned);
|
|
|
|
Expected<ServerInfo> server_info = loadOrStart();
|
|
if (!server_info)
|
|
exitWithError(server_info.takeError());
|
|
|
|
static MainLoop loop;
|
|
sys::SetInterruptFunction([]() {
|
|
loop.AddPendingCallback(
|
|
[](MainLoopBase &loop) { loop.RequestTermination(); });
|
|
});
|
|
|
|
if (llvm::Error error =
|
|
connectAndForwardIO(loop, *server_info, input_sp, output_sp))
|
|
exitWithError(std::move(error));
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|