18#include "llvm/ADT/StringRef.h"
19#include "llvm/Support/Error.h"
31static constexpr StringLiteral kSchemeAndHost =
"lldb-mcp://debugger/";
33struct CommandToolArguments {
39bool fromJSON(
const json::Value &V, CommandToolArguments &A, json::Path P) {
40 json::ObjectMapper O(V, P);
41 return O && O.mapOptional(
"debugger", A.debugger) &&
42 O.mapOptional(
"command", A.command);
47createTextResult(std::string output,
bool is_error =
false) {
49 text_result.
content.emplace_back(
56 return (kSchemeAndHost + std::to_string(debugger->GetID())).str();
61Expected<lldb_protocol::mcp::CallToolResult>
63 if (!std::holds_alternative<json::Value>(args))
64 return createStringError(
"CommandTool requires arguments");
66 json::Path::Root root;
68 CommandToolArguments arguments;
69 if (!
fromJSON(std::get<json::Value>(args), arguments, root))
70 return root.getError();
74 if (!arguments.debugger.empty()) {
75 llvm::StringRef debugger_specifier = arguments.debugger;
76 debugger_specifier.consume_front(kSchemeAndHost);
77 uint32_t debugger_id = 0;
78 if (debugger_specifier.consumeInteger(10, debugger_id))
79 return createStringError(
80 formatv(
"malformed debugger specifier {0}", arguments.debugger));
92 return createStringError(
"no debugger found");
96 debugger_sp->GetCommandInterpreter().HandleCommand(arguments.command.c_str(),
101 if (!output_str.empty())
102 output += output_str.str();
105 if (!err_str.empty()) {
111 return createTextResult(output, !result.
Succeeded());
118 Object{{
"type",
"string"},
120 "The debugger ID or URI to a specific debug session. If not "
121 "specified, the first debugger will be used."}}},
123 Object{{
"type",
"string"}, {
"description",
"An lldb command to run."}}}};
124 Object schema{{
"type",
"object"}, {
"properties", std::move(properties)}};
128Expected<lldb_protocol::mcp::CallToolResult>
130 llvm::json::Path::Root root;
140 llvm::raw_string_ostream os(output);
143 for (
size_t i = 0; i < num_debuggers; ++i) {
148 os <<
"- " << to_uri(debugger_sp) <<
'\n';
151 return createTextResult(output);
156 llvm::Expected<lldb::FileUP> file =
159 llvm::consumeError(file.takeError());
162 return std::move(*file);
165Expected<lldb_protocol::mcp::CallToolResult>
175 return createStringError(
176 "failed to open the null device for debugger stdio");
180 return createStringError(
"failed to create debugger");
182 debugger_sp->SetInputFile(in);
183 debugger_sp->SetOutputFile(out);
184 debugger_sp->SetErrorFile(out);
188 debugger_sp->SetAsyncExecution(
false);
190 return createTextResult(to_uri(debugger_sp));
193Expected<lldb_protocol::mcp::CallToolResult>
195 if (!std::holds_alternative<json::Value>(args))
196 return createStringError(
"DebuggerDeleteTool requires arguments");
198 const json::Object *arguments = std::get<json::Value>(args).getAsObject();
200 return createStringError(
"DebuggerDeleteTool requires arguments");
202 std::optional<StringRef> debugger = arguments->getString(
"debugger");
204 return createStringError(
"DebuggerDeleteTool requires a debugger");
206 StringRef specifier = *debugger;
207 specifier.consume_front(kSchemeAndHost);
208 uint32_t debugger_id = 0;
209 if (specifier.consumeInteger(10, debugger_id))
210 return createStringError(
211 formatv(
"malformed debugger specifier {0}", *debugger));
215 return createStringError(
"no debugger found");
218 return createTextResult(formatv(
"deleted {0}", *debugger).str());
225 Object{{
"type",
"string"},
226 {
"description",
"The debugger ID or URI to destroy."}}}};
227 Object schema{{
"type",
"object"},
228 {
"properties", std::move(properties)},
229 {
"required", Array{
"debugger"}}};
std::string GetErrorString(bool with_diagnostics=true) const
Return the errors as a string.
llvm::StringRef GetOutputString() const
static lldb::DebuggerSP GetDebuggerAtIndex(size_t index)
static lldb::DebuggerSP CreateInstance(lldb::LogOutputCallback log_callback=nullptr, void *baton=nullptr)
static lldb::DebuggerSP FindDebuggerWithID(lldb::user_id_t id)
static void Destroy(lldb::DebuggerSP &debugger_sp)
static size_t GetNumDebuggers()
static const char * DEV_NULL
int Open(const char *path, int flags, int mode=0600)
Wraps open in a platform-independent way.
static FileSystem & Instance()
A class that represents a running process on the host machine.
bool fromJSON(const llvm::json::Value &value, SymbolValue &data, llvm::json::Path path)
std::variant< std::monostate, llvm::json::Value > ToolArguments
std::shared_ptr< lldb_private::Debugger > DebuggerSP
std::shared_ptr< lldb_private::File > FileSP
Text provided to or from an LLM.