Skip to content

Commit aa71d95

Browse files
authored
[lldb] Add lldb-mcp scaffolding (llvm#155708)
Add the scaffolding for a new tool called 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.
1 parent 71a065e commit aa71d95

File tree

4 files changed

+135
-0
lines changed

4 files changed

+135
-0
lines changed

lldb/tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_subdirectory(lldb-fuzzer EXCLUDE_FROM_ALL)
1010

1111
add_lldb_tool_subdirectory(lldb-instr)
1212
add_lldb_tool_subdirectory(lldb-dap)
13+
add_lldb_tool_subdirectory(lldb-mcp)
1314
if (LLDB_BUILD_LLDBRPC)
1415
add_lldb_tool_subdirectory(lldb-rpc-gen)
1516
endif()

lldb/tools/lldb-mcp/CMakeLists.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
add_lldb_tool(lldb-mcp
2+
lldb-mcp.cpp
3+
4+
LINK_COMPONENTS
5+
Option
6+
Support
7+
LINK_LIBS
8+
liblldb
9+
lldbHost
10+
lldbProtocolMCP
11+
)
12+
13+
if(APPLE)
14+
configure_file(
15+
${CMAKE_CURRENT_SOURCE_DIR}/lldb-mcp-Info.plist.in
16+
${CMAKE_CURRENT_BINARY_DIR}/lldb-mcp-Info.plist
17+
)
18+
target_link_options(lldb-mcp
19+
PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-mcp-Info.plist)
20+
endif()
21+
22+
if(LLDB_BUILD_FRAMEWORK)
23+
# In the build-tree, we know the exact path to the framework directory.
24+
# The installed framework can be in different locations.
25+
lldb_setup_rpaths(lldb-mcp
26+
BUILD_RPATH
27+
"${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}"
28+
INSTALL_RPATH
29+
"@loader_path/../../../SharedFrameworks"
30+
"@loader_path/../../System/Library/PrivateFrameworks"
31+
"@loader_path/../../Library/PrivateFrameworks"
32+
)
33+
endif()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>English</string>
7+
<key>CFBundleIdentifier</key>
8+
<string>com.apple.lldb-mcp</string>
9+
<key>CFBundleInfoDictionaryVersion</key>
10+
<string>6.0</string>
11+
<key>CFBundleName</key>
12+
<string>lldb-mcp</string>
13+
<key>CFBundleVersion</key>
14+
<string>${LLDB_VERSION}</string>
15+
<key>SecTaskAccess</key>
16+
<array>
17+
<string>allowed</string>
18+
<string>debug</string>
19+
</array>
20+
</dict>
21+
</plist>

lldb/tools/lldb-mcp/lldb-mcp.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----------------------------------------------------------------------===//
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 "lldb/Host/Config.h"
10+
#include "lldb/Host/File.h"
11+
#include "lldb/Host/MainLoop.h"
12+
#include "lldb/Host/MainLoopBase.h"
13+
#include "lldb/Protocol/MCP/Protocol.h"
14+
#include "lldb/Protocol/MCP/Server.h"
15+
#include "llvm/ADT/StringRef.h"
16+
#include "llvm/Support/InitLLVM.h"
17+
#include "llvm/Support/Signals.h"
18+
#include "llvm/Support/WithColor.h"
19+
20+
using namespace lldb_protocol::mcp;
21+
22+
using lldb_private::File;
23+
using lldb_private::MainLoop;
24+
using lldb_private::MainLoopBase;
25+
using lldb_private::NativeFile;
26+
27+
static constexpr llvm::StringLiteral kName = "lldb-mcp";
28+
static constexpr llvm::StringLiteral kVersion = "0.1.0";
29+
30+
int main(int argc, char *argv[]) {
31+
llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
32+
#if !defined(__APPLE__)
33+
llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
34+
" and include the crash backtrace.\n");
35+
#else
36+
llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
37+
" and include the crash report from "
38+
"~/Library/Logs/DiagnosticReports/.\n");
39+
#endif
40+
41+
#if defined(_WIN32)
42+
// Windows opens stdout and stdin in text mode which converts \n to 13,10
43+
// while the value is just 10 on Darwin/Linux. Setting the file mode to
44+
// binary fixes this.
45+
int result = _setmode(fileno(stdout), _O_BINARY);
46+
assert(result);
47+
result = _setmode(fileno(stdin), _O_BINARY);
48+
UNUSED_IF_ASSERT_DISABLED(result);
49+
assert(result);
50+
#endif
51+
52+
lldb::IOObjectSP input = std::make_shared<NativeFile>(
53+
fileno(stdin), File::eOpenOptionReadOnly, NativeFile::Unowned);
54+
55+
lldb::IOObjectSP output = std::make_shared<NativeFile>(
56+
fileno(stdout), File::eOpenOptionWriteOnly, NativeFile::Unowned);
57+
58+
constexpr llvm::StringLiteral client_name = "stdio";
59+
static MainLoop loop;
60+
61+
llvm::sys::SetInterruptFunction([]() {
62+
loop.AddPendingCallback(
63+
[](MainLoopBase &loop) { loop.RequestTermination(); });
64+
});
65+
66+
auto transport_up = std::make_unique<lldb_protocol::mcp::MCPTransport>(
67+
input, output, std::string(client_name),
68+
[&](llvm::StringRef message) { llvm::errs() << message << '\n'; });
69+
70+
auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
71+
std::string(kName), std::string(kVersion), std::move(transport_up), loop);
72+
73+
if (llvm::Error error = instance_up->Run()) {
74+
llvm::logAllUnhandledErrors(std::move(error), llvm::WithColor::error(),
75+
"MCP error: ");
76+
return EXIT_FAILURE;
77+
}
78+
79+
return EXIT_SUCCESS;
80+
}

0 commit comments

Comments
 (0)