// 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 "Resource.h" #include "MCPError.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Target/Platform.h" using namespace lldb_private::mcp; namespace { struct DebuggerResource { uint64_t debugger_id = 0; std::string name; uint64_t num_targets = 0; }; llvm::json::Value toJSON(const DebuggerResource &DR) { llvm::json::Object Result{{"debugger_id", DR.debugger_id}, {"num_targets", DR.num_targets}}; if (!DR.name.empty()) Result.insert({"name", DR.name}); return Result; } struct TargetResource { size_t debugger_id = 0; size_t target_idx = 0; bool selected = false; bool dummy = false; std::string arch; std::string path; std::string platform; }; llvm::json::Value toJSON(const TargetResource &TR) { llvm::json::Object Result{{"debugger_id", TR.debugger_id}, {"target_idx", TR.target_idx}, {"selected", TR.selected}, {"dummy", TR.dummy}}; if (!TR.arch.empty()) Result.insert({"arch", TR.arch}); if (!TR.path.empty()) Result.insert({"path", TR.path}); if (!TR.platform.empty()) Result.insert({"platform", TR.platform}); return Result; } } // namespace static constexpr llvm::StringLiteral kMimeTypeJSON = "application/json"; template static llvm::Error createStringError(const char *format, Args &&...args) { return llvm::createStringError( llvm::formatv(format, std::forward(args)...).str()); } static llvm::Error createUnsupportedURIError(llvm::StringRef uri) { return llvm::make_error(uri.str()); } protocol::Resource DebuggerResourceProvider::GetDebuggerResource(Debugger &debugger) { const lldb::user_id_t debugger_id = debugger.GetID(); protocol::Resource resource; resource.uri = llvm::formatv("lldb://debugger/{0}", debugger_id); resource.name = debugger.GetInstanceName(); resource.description = llvm::formatv("Information about debugger instance {0}: {1}", debugger_id, debugger.GetInstanceName()); resource.mimeType = kMimeTypeJSON; return resource; } protocol::Resource DebuggerResourceProvider::GetTargetResource(size_t target_idx, Target &target) { const size_t debugger_id = target.GetDebugger().GetID(); std::string target_name = llvm::formatv("target {0}", target_idx); if (Module *exe_module = target.GetExecutableModulePointer()) target_name = exe_module->GetFileSpec().GetFilename().GetString(); protocol::Resource resource; resource.uri = llvm::formatv("lldb://debugger/{0}/target/{1}", debugger_id, target_idx); resource.name = target_name; resource.description = llvm::formatv("Information about target {0} in debugger instance {1}", target_idx, debugger_id); resource.mimeType = kMimeTypeJSON; return resource; } std::vector DebuggerResourceProvider::GetResources() const { std::vector resources; const size_t num_debuggers = Debugger::GetNumDebuggers(); for (size_t i = 0; i < num_debuggers; ++i) { lldb::DebuggerSP debugger_sp = Debugger::GetDebuggerAtIndex(i); if (!debugger_sp) continue; resources.emplace_back(GetDebuggerResource(*debugger_sp)); TargetList &target_list = debugger_sp->GetTargetList(); const size_t num_targets = target_list.GetNumTargets(); for (size_t j = 0; j < num_targets; ++j) { lldb::TargetSP target_sp = target_list.GetTargetAtIndex(j); if (!target_sp) continue; resources.emplace_back(GetTargetResource(j, *target_sp)); } } return resources; } llvm::Expected DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const { auto [protocol, path] = uri.split("://"); if (protocol != "lldb") return createUnsupportedURIError(uri); llvm::SmallVector components; path.split(components, '/'); if (components.size() < 2) return createUnsupportedURIError(uri); if (components[0] != "debugger") return createUnsupportedURIError(uri); size_t debugger_idx; if (components[1].getAsInteger(0, debugger_idx)) return createStringError("invalid debugger id '{0}': {1}", components[1], path); if (components.size() > 3) { if (components[2] != "target") return createUnsupportedURIError(uri); size_t target_idx; if (components[3].getAsInteger(0, target_idx)) return createStringError("invalid target id '{0}': {1}", components[3], path); return ReadTargetResource(uri, debugger_idx, target_idx); } return ReadDebuggerResource(uri, debugger_idx); } llvm::Expected DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri, lldb::user_id_t debugger_id) { lldb::DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(debugger_id); if (!debugger_sp) return createStringError("invalid debugger id: {0}", debugger_id); DebuggerResource debugger_resource; debugger_resource.debugger_id = debugger_id; debugger_resource.name = debugger_sp->GetInstanceName(); debugger_resource.num_targets = debugger_sp->GetTargetList().GetNumTargets(); protocol::ResourceContents contents; contents.uri = uri; contents.mimeType = kMimeTypeJSON; contents.text = llvm::formatv("{0}", toJSON(debugger_resource)); protocol::ResourceResult result; result.contents.push_back(contents); return result; } llvm::Expected DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri, lldb::user_id_t debugger_id, size_t target_idx) { lldb::DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(debugger_id); if (!debugger_sp) return createStringError("invalid debugger id: {0}", debugger_id); TargetList &target_list = debugger_sp->GetTargetList(); lldb::TargetSP target_sp = target_list.GetTargetAtIndex(target_idx); if (!target_sp) return createStringError("invalid target idx: {0}", target_idx); TargetResource target_resource; target_resource.debugger_id = debugger_id; target_resource.target_idx = target_idx; target_resource.arch = target_sp->GetArchitecture().GetTriple().str(); target_resource.dummy = target_sp->IsDummyTarget(); target_resource.selected = target_sp == debugger_sp->GetSelectedTarget(); if (Module *exe_module = target_sp->GetExecutableModulePointer()) target_resource.path = exe_module->GetFileSpec().GetPath(); if (lldb::PlatformSP platform_sp = target_sp->GetPlatform()) target_resource.platform = platform_sp->GetName(); protocol::ResourceContents contents; contents.uri = uri; contents.mimeType = kMimeTypeJSON; contents.text = llvm::formatv("{0}", toJSON(target_resource)); protocol::ResourceResult result; result.contents.push_back(contents); return result; }