-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[lldb] Add lldb-mcp scaffolding #155708
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb] Add lldb-mcp scaffolding #155708
Conversation
Add the scaffolding for a new tool lldb-mcp. This utility is meant to replace netcat and acts a proxy between the LLM and one or more LLDB instances. In its current form, the utility is a trivial MCP server without any tools or resources.
@llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) ChangesAdd the scaffolding for a new tool lldb-mcp. This utility is meant to replace netcat and acts a proxy between the LLM and one or more LLDB instances. In its current form, the utility is a trivial MCP server without any tools or resources. Full diff: https://github.com/llvm/llvm-project/pull/155708.diff 4 Files Affected:
diff --git a/lldb/tools/CMakeLists.txt b/lldb/tools/CMakeLists.txt
index e2f039527ad75..4a0d2f695481d 100644
--- a/lldb/tools/CMakeLists.txt
+++ b/lldb/tools/CMakeLists.txt
@@ -10,6 +10,7 @@ add_subdirectory(lldb-fuzzer EXCLUDE_FROM_ALL)
add_lldb_tool_subdirectory(lldb-instr)
add_lldb_tool_subdirectory(lldb-dap)
+add_lldb_tool_subdirectory(lldb-mcp)
if (LLDB_BUILD_LLDBRPC)
add_lldb_tool_subdirectory(lldb-rpc-gen)
endif()
diff --git a/lldb/tools/lldb-mcp/CMakeLists.txt b/lldb/tools/lldb-mcp/CMakeLists.txt
new file mode 100644
index 0000000000000..7fe3301ab3081
--- /dev/null
+++ b/lldb/tools/lldb-mcp/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_lldb_tool(lldb-mcp
+ lldb-mcp.cpp
+
+ LINK_COMPONENTS
+ Option
+ Support
+ LINK_LIBS
+ liblldb
+ lldbHost
+ lldbProtocolMCP
+ )
+
+if(APPLE)
+ configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lldb-mcp-Info.plist.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lldb-mcp-Info.plist
+ )
+ target_link_options(lldb-mcp
+ PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-mcp-Info.plist)
+endif()
+
+if(LLDB_BUILD_FRAMEWORK)
+ # In the build-tree, we know the exact path to the framework directory.
+ # The installed framework can be in different locations.
+ lldb_setup_rpaths(lldb-mcp
+ BUILD_RPATH
+ "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}"
+ INSTALL_RPATH
+ "@loader_path/../../../SharedFrameworks"
+ "@loader_path/../../System/Library/PrivateFrameworks"
+ "@loader_path/../../Library/PrivateFrameworks"
+ )
+endif()
diff --git a/lldb/tools/lldb-mcp/lldb-mcp-Info.plist.in b/lldb/tools/lldb-mcp/lldb-mcp-Info.plist.in
new file mode 100644
index 0000000000000..7d01d3145d929
--- /dev/null
+++ b/lldb/tools/lldb-mcp/lldb-mcp-Info.plist.in
@@ -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-dap</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>lldb-dap</string>
+ <key>CFBundleVersion</key>
+ <string>${LLDB_VERSION}</string>
+ <key>SecTaskAccess</key>
+ <array>
+ <string>allowed</string>
+ <string>debug</string>
+ </array>
+</dict>
+</plist>
diff --git a/lldb/tools/lldb-mcp/lldb-mcp.cpp b/lldb/tools/lldb-mcp/lldb-mcp.cpp
new file mode 100644
index 0000000000000..3769b9a7408eb
--- /dev/null
+++ b/lldb/tools/lldb-mcp/lldb-mcp.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/MainLoop.h"
+#include "lldb/Host/MainLoopBase.h"
+#include "lldb/Protocol/MCP/Protocol.h"
+#include "lldb/Protocol/MCP/Server.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/WithColor.h"
+
+using namespace lldb_protocol::mcp;
+
+using lldb_private::File;
+using lldb_private::MainLoop;
+using lldb_private::MainLoopBase;
+using lldb_private::NativeFile;
+
+static constexpr llvm::StringLiteral kName = "lldb-mcp";
+static constexpr llvm::StringLiteral kVersion = "0.1.0";
+
+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
+
+ lldb::IOObjectSP input = std::make_shared<NativeFile>(
+ fileno(stdin), File::eOpenOptionReadOnly, NativeFile::Unowned);
+
+ lldb::IOObjectSP output = std::make_shared<NativeFile>(
+ fileno(stdout), File::eOpenOptionReadOnly, NativeFile::Unowned);
+
+ constexpr llvm::StringLiteral client_name = "stdio";
+ static MainLoop loop;
+
+ llvm::sys::SetInterruptFunction([]() {
+ loop.AddPendingCallback(
+ [](MainLoopBase &loop) { loop.RequestTermination(); });
+ });
+
+ auto transport_up = std::make_unique<lldb_protocol::mcp::MCPTransport>(
+ input, output, std::string(client_name),
+ [&](llvm::StringRef message) { llvm::errs() << message << '\n'; });
+
+ auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
+ std::string(kName), std::string(kVersion), std::move(transport_up), loop);
+
+ if (llvm::Error error = instance_up->Run()) {
+ llvm::logAllUnhandledErrors(std::move(error), llvm::WithColor::error(),
+ "DAP session error: ");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
|
<key>CFBundleInfoDictionaryVersion</key> | ||
<string>6.0</string> | ||
<key>CFBundleName</key> | ||
<string>lldb-dap</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lldb-mcp?
<key>CFBundleDevelopmentRegion</key> | ||
<string>English</string> | ||
<key>CFBundleIdentifier</key> | ||
<string>com.apple.lldb-dap</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
com.apple.lldb-mcp?
lldb/tools/lldb-mcp/lldb-mcp.cpp
Outdated
|
||
if (llvm::Error error = instance_up->Run()) { | ||
llvm::logAllUnhandledErrors(std::move(error), llvm::WithColor::error(), | ||
"DAP session error: "); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/DAP/MCP/
?
lldb/tools/lldb-mcp/lldb-mcp.cpp
Outdated
fileno(stdin), File::eOpenOptionReadOnly, NativeFile::Unowned); | ||
|
||
lldb::IOObjectSP output = std::make_shared<NativeFile>( | ||
fileno(stdout), File::eOpenOptionReadOnly, NativeFile::Unowned); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/eOpenOptionReadOnly/eOpenOptionWriteOnly/
?
constexpr llvm::StringLiteral client_name = "stdio"; | ||
static MainLoop loop; | ||
|
||
llvm::sys::SetInterruptFunction([]() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think MainLoop can register a signal handler, but I suppose thats not cross platform. I wonder how the llvm interrupt handler works on Windows...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I talked with @labath about that at the last EuroLLVM. IIRC he was going to take a stab at making that work on Windows :P
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/181/builds/26803 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/163/builds/25512 Here is the relevant piece of the build log for the reference
|
#155720 should fix the build |
Please note that lldb-remote-linux-win is still failing with:
|
I also ran into this, at https://github.com/mstorsjo/llvm-mingw/actions/runs/17282716726/job/49063271475. It's trivially fixable with this at the head of the file:
It's also possible to switch to using If you don't mind, I can push the former fix to unbreak builds, and you can look into switching to the neater API forms separately afterwards. |
I pushed the trivial fix to add the missing include in 1ec0688. |
Thank you! |
Add the scaffolding for a new tool lldb-mcp. This utility is meant to replace netcat and acts a proxy between the LLM and one or more LLDB instances. In its current form, the utility is a trivial MCP server without any tools or resources.