Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lldb/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
33 changes: 33 additions & 0 deletions lldb/tools/lldb-mcp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
21 changes: 21 additions & 0 deletions lldb/tools/lldb-mcp/lldb-mcp-Info.plist.in
Original file line number Diff line number Diff line change
@@ -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-mcp</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>lldb-mcp</string>
<key>CFBundleVersion</key>
<string>${LLDB_VERSION}</string>
<key>SecTaskAccess</key>
<array>
<string>allowed</string>
<string>debug</string>
</array>
</dict>
</plist>
80 changes: 80 additions & 0 deletions lldb/tools/lldb-mcp/lldb-mcp.cpp
Original file line number Diff line number Diff line change
@@ -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::eOpenOptionWriteOnly, NativeFile::Unowned);

constexpr llvm::StringLiteral client_name = "stdio";
static MainLoop loop;

llvm::sys::SetInterruptFunction([]() {
Copy link
Contributor

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...

Copy link
Member Author

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

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(),
"MCP error: ");
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}
Loading