653 lines · c
1//===-- Request.h ---------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H10#define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H11 12#include "DAP.h"13#include "DAPError.h"14#include "DAPLog.h"15#include "Protocol/ProtocolBase.h"16#include "Protocol/ProtocolRequests.h"17#include "Protocol/ProtocolTypes.h"18#include "llvm/ADT/DenseSet.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/Support/Error.h"21#include "llvm/Support/JSON.h"22#include <optional>23#include <type_traits>24#include <variant>25#include <vector>26 27template <typename T> struct is_optional : std::false_type {};28 29template <typename T> struct is_optional<std::optional<T>> : std::true_type {};30 31template <typename T>32inline constexpr bool is_optional_v = is_optional<T>::value;33 34namespace lldb_dap {35struct DAP;36 37/// Base class for request handlers. Do not extend this directly: Extend38/// the RequestHandler template subclass instead.39class BaseRequestHandler {40public:41 BaseRequestHandler(DAP &dap) : dap(dap) {}42 43 /// BaseRequestHandler are not copyable.44 /// @{45 BaseRequestHandler(const BaseRequestHandler &) = delete;46 BaseRequestHandler &operator=(const BaseRequestHandler &) = delete;47 /// @}48 49 virtual ~BaseRequestHandler() = default;50 51 void Run(const protocol::Request &);52 53 virtual void operator()(const protocol::Request &request) const = 0;54 55 using FeatureSet = llvm::SmallDenseSet<AdapterFeature, 1>;56 virtual FeatureSet GetSupportedFeatures() const { return {}; }57 58protected:59 /// Helpers used by multiple request handlers.60 /// FIXME: Move these into the DAP class?61 /// @{62 63 /// Prints a welcome message on the editor if the preprocessor variable64 /// LLDB_DAP_WELCOME_MESSAGE is defined.65 void PrintWelcomeMessage() const;66 67 // Takes a LaunchRequest object and launches the process, also handling68 // runInTerminal if applicable. It doesn't do any of the additional69 // initialization and bookkeeping stuff that is needed for `request_launch`.70 // This way we can reuse the process launching logic for RestartRequest too.71 llvm::Error72 LaunchProcess(const protocol::LaunchRequestArguments &request) const;73 74 // Check if the step-granularity is `instruction`.75 bool HasInstructionGranularity(const llvm::json::Object &request) const;76 77 /// @}78 79 DAP &dap;80};81 82/// FIXME: Migrate callers to typed RequestHandler for improved type handling.83class LegacyRequestHandler : public BaseRequestHandler {84 using BaseRequestHandler::BaseRequestHandler;85 virtual void operator()(const llvm::json::Object &request) const = 0;86 void operator()(const protocol::Request &request) const override {87 auto req = toJSON(request);88 (*this)(*req.getAsObject());89 }90};91 92template <typename Args>93llvm::Expected<Args> parseArgs(const protocol::Request &request) {94 if (!is_optional_v<Args> && !request.arguments)95 return llvm::make_error<DAPError>(96 llvm::formatv("arguments required for command '{0}' "97 "but none received",98 request.command)99 .str());100 101 Args arguments;102 llvm::json::Path::Root root("arguments");103 if (request.arguments && !fromJSON(*request.arguments, arguments, root)) {104 std::string parse_failure;105 llvm::raw_string_ostream OS(parse_failure);106 OS << "invalid arguments for request '" << request.command107 << "': " << llvm::toString(root.getError()) << "\n";108 root.printErrorContext(*request.arguments, OS);109 return llvm::make_error<DAPError>(parse_failure);110 }111 112 return arguments;113}114template <>115inline llvm::Expected<protocol::EmptyArguments>116parseArgs(const protocol::Request &request) {117 return std::nullopt;118}119 120/// Base class for handling DAP requests. Handlers should declare their121/// arguments and response body types like:122///123/// class MyRequestHandler : public RequestHandler<Arguments, Response> {124/// ....125/// };126template <typename Args, typename Resp>127class RequestHandler : public BaseRequestHandler {128 using BaseRequestHandler::BaseRequestHandler;129 130 void operator()(const protocol::Request &request) const override {131 protocol::Response response;132 response.request_seq = request.seq;133 response.command = request.command;134 135 llvm::Expected<Args> arguments = parseArgs<Args>(request);136 if (llvm::Error err = arguments.takeError()) {137 HandleErrorResponse(std::move(err), response);138 dap.Send(response);139 return;140 }141 142 if constexpr (std::is_same_v<Resp, llvm::Error>) {143 if (llvm::Error err = Run(*arguments)) {144 HandleErrorResponse(std::move(err), response);145 } else {146 response.success = true;147 }148 } else {149 Resp body = Run(*arguments);150 if (llvm::Error err = body.takeError()) {151 HandleErrorResponse(std::move(err), response);152 } else {153 response.success = true;154 response.body = std::move(*body);155 }156 }157 158 // Mark the request as 'cancelled' if the debugger was interrupted while159 // evaluating this handler.160 if (dap.debugger.InterruptRequested()) {161 dap.debugger.CancelInterruptRequest();162 response.success = false;163 response.message = protocol::eResponseMessageCancelled;164 response.body = std::nullopt;165 }166 167 dap.Send(response);168 169 PostRun();170 };171 172 virtual Resp Run(const Args &) const = 0;173 174 /// A hook for a request handler to run additional operations after the175 /// request response is sent but before the next request handler.176 ///177 /// *NOTE*: PostRun will be invoked even if the `Run` operation returned an178 /// error.179 virtual void PostRun() const {};180 181 void HandleErrorResponse(llvm::Error err,182 protocol::Response &response) const {183 response.success = false;184 llvm::handleAllErrors(185 std::move(err),186 [&](const NotStoppedError &err) {187 response.message = lldb_dap::protocol::eResponseMessageNotStopped;188 },189 [&](const DAPError &err) {190 protocol::ErrorMessage error_message;191 error_message.sendTelemetry = false;192 error_message.format = err.getMessage();193 error_message.showUser = err.getShowUser();194 error_message.id = err.convertToErrorCode().value();195 error_message.url = err.getURL();196 error_message.urlLabel = err.getURLLabel();197 protocol::ErrorResponseBody body;198 body.error = error_message;199 response.body = body;200 },201 [&](const llvm::ErrorInfoBase &err) {202 protocol::ErrorMessage error_message;203 error_message.showUser = true;204 error_message.sendTelemetry = false;205 error_message.format = err.message();206 error_message.id = err.convertToErrorCode().value();207 protocol::ErrorResponseBody body;208 body.error = error_message;209 response.body = body;210 });211 }212};213 214class AttachRequestHandler215 : public RequestHandler<protocol::AttachRequestArguments,216 protocol::AttachResponse> {217public:218 using RequestHandler::RequestHandler;219 static llvm::StringLiteral GetCommand() { return "attach"; }220 llvm::Error Run(const protocol::AttachRequestArguments &args) const override;221 void PostRun() const override;222};223 224class BreakpointLocationsRequestHandler225 : public RequestHandler<226 protocol::BreakpointLocationsArguments,227 llvm::Expected<protocol::BreakpointLocationsResponseBody>> {228public:229 using RequestHandler::RequestHandler;230 static llvm::StringLiteral GetCommand() { return "breakpointLocations"; }231 FeatureSet GetSupportedFeatures() const override {232 return {protocol::eAdapterFeatureBreakpointLocationsRequest};233 }234 llvm::Expected<protocol::BreakpointLocationsResponseBody>235 Run(const protocol::BreakpointLocationsArguments &args) const override;236 237 std::vector<std::pair<uint32_t, uint32_t>>238 GetSourceBreakpointLocations(std::string path, uint32_t start_line,239 uint32_t start_column, uint32_t end_line,240 uint32_t end_column) const;241 std::vector<std::pair<uint32_t, uint32_t>>242 GetAssemblyBreakpointLocations(int64_t source_reference, uint32_t start_line,243 uint32_t end_line) const;244};245 246class CompletionsRequestHandler247 : public RequestHandler<protocol::CompletionsArguments,248 llvm::Expected<protocol::CompletionsResponseBody>> {249public:250 using RequestHandler::RequestHandler;251 static llvm::StringLiteral GetCommand() { return "completions"; }252 FeatureSet GetSupportedFeatures() const override {253 return {protocol::eAdapterFeatureCompletionsRequest};254 }255 llvm::Expected<protocol::CompletionsResponseBody>256 Run(const protocol::CompletionsArguments &args) const override;257};258 259class ContinueRequestHandler260 : public RequestHandler<protocol::ContinueArguments,261 llvm::Expected<protocol::ContinueResponseBody>> {262public:263 using RequestHandler::RequestHandler;264 static llvm::StringLiteral GetCommand() { return "continue"; }265 llvm::Expected<protocol::ContinueResponseBody>266 Run(const protocol::ContinueArguments &args) const override;267};268 269class ConfigurationDoneRequestHandler270 : public RequestHandler<protocol::ConfigurationDoneArguments,271 protocol::ConfigurationDoneResponse> {272public:273 using RequestHandler::RequestHandler;274 static llvm::StringLiteral GetCommand() { return "configurationDone"; }275 FeatureSet GetSupportedFeatures() const override {276 return {protocol::eAdapterFeatureConfigurationDoneRequest};277 }278 protocol::ConfigurationDoneResponse279 Run(const protocol::ConfigurationDoneArguments &) const override;280};281 282class DisconnectRequestHandler283 : public RequestHandler<std::optional<protocol::DisconnectArguments>,284 protocol::DisconnectResponse> {285public:286 using RequestHandler::RequestHandler;287 static llvm::StringLiteral GetCommand() { return "disconnect"; }288 FeatureSet GetSupportedFeatures() const override {289 return {protocol::eAdapterFeatureTerminateDebuggee};290 }291 llvm::Error292 Run(const std::optional<protocol::DisconnectArguments> &args) const override;293};294 295class EvaluateRequestHandler296 : public RequestHandler<protocol::EvaluateArguments,297 llvm::Expected<protocol::EvaluateResponseBody>> {298public:299 using RequestHandler::RequestHandler;300 static llvm::StringLiteral GetCommand() { return "evaluate"; }301 llvm::Expected<protocol::EvaluateResponseBody>302 Run(const protocol::EvaluateArguments &) const override;303 FeatureSet GetSupportedFeatures() const override {304 return {protocol::eAdapterFeatureEvaluateForHovers};305 }306};307 308class ExceptionInfoRequestHandler final309 : public RequestHandler<310 protocol::ExceptionInfoArguments,311 llvm::Expected<protocol::ExceptionInfoResponseBody>> {312public:313 using RequestHandler::RequestHandler;314 static llvm::StringLiteral GetCommand() { return "exceptionInfo"; }315 FeatureSet GetSupportedFeatures() const override {316 return {protocol::eAdapterFeatureExceptionInfoRequest};317 }318 llvm::Expected<protocol::ExceptionInfoResponseBody>319 Run(const protocol::ExceptionInfoArguments &args) const override;320};321 322class InitializeRequestHandler323 : public RequestHandler<protocol::InitializeRequestArguments,324 llvm::Expected<protocol::InitializeResponse>> {325public:326 using RequestHandler::RequestHandler;327 static llvm::StringLiteral GetCommand() { return "initialize"; }328 llvm::Expected<protocol::InitializeResponse>329 Run(const protocol::InitializeRequestArguments &args) const override;330};331 332class LaunchRequestHandler333 : public RequestHandler<protocol::LaunchRequestArguments,334 protocol::LaunchResponse> {335public:336 using RequestHandler::RequestHandler;337 static llvm::StringLiteral GetCommand() { return "launch"; }338 llvm::Error339 Run(const protocol::LaunchRequestArguments &arguments) const override;340 void PostRun() const override;341};342 343class RestartRequestHandler : public LegacyRequestHandler {344public:345 using LegacyRequestHandler::LegacyRequestHandler;346 static llvm::StringLiteral GetCommand() { return "restart"; }347 void operator()(const llvm::json::Object &request) const override;348};349 350class NextRequestHandler351 : public RequestHandler<protocol::NextArguments, protocol::NextResponse> {352public:353 using RequestHandler::RequestHandler;354 static llvm::StringLiteral GetCommand() { return "next"; }355 llvm::Error Run(const protocol::NextArguments &args) const override;356};357 358class StepInRequestHandler : public RequestHandler<protocol::StepInArguments,359 protocol::StepInResponse> {360public:361 using RequestHandler::RequestHandler;362 static llvm::StringLiteral GetCommand() { return "stepIn"; }363 llvm::Error Run(const protocol::StepInArguments &args) const override;364};365 366class StepInTargetsRequestHandler367 : public RequestHandler<368 protocol::StepInTargetsArguments,369 llvm::Expected<protocol::StepInTargetsResponseBody>> {370public:371 using RequestHandler::RequestHandler;372 static llvm::StringLiteral GetCommand() { return "stepInTargets"; }373 llvm::Expected<protocol::StepInTargetsResponseBody>374 Run(const protocol::StepInTargetsArguments &args) const override;375};376 377class StepOutRequestHandler : public RequestHandler<protocol::StepOutArguments,378 protocol::StepOutResponse> {379public:380 using RequestHandler::RequestHandler;381 static llvm::StringLiteral GetCommand() { return "stepOut"; }382 llvm::Error Run(const protocol::StepOutArguments &args) const override;383};384 385class SetBreakpointsRequestHandler386 : public RequestHandler<387 protocol::SetBreakpointsArguments,388 llvm::Expected<protocol::SetBreakpointsResponseBody>> {389public:390 using RequestHandler::RequestHandler;391 static llvm::StringLiteral GetCommand() { return "setBreakpoints"; }392 FeatureSet GetSupportedFeatures() const override {393 return {protocol::eAdapterFeatureConditionalBreakpoints,394 protocol::eAdapterFeatureHitConditionalBreakpoints};395 }396 llvm::Expected<protocol::SetBreakpointsResponseBody>397 Run(const protocol::SetBreakpointsArguments &args) const override;398};399 400class SetExceptionBreakpointsRequestHandler401 : public RequestHandler<402 protocol::SetExceptionBreakpointsArguments,403 llvm::Expected<protocol::SetExceptionBreakpointsResponseBody>> {404public:405 using RequestHandler::RequestHandler;406 static llvm::StringLiteral GetCommand() { return "setExceptionBreakpoints"; }407 FeatureSet GetSupportedFeatures() const override {408 /// Prefer the `filterOptions` feature over the `exceptionOptions`.409 /// exceptionOptions is not supported in VSCode, while `filterOptions` is410 /// supported.411 return {protocol::eAdapterFeatureExceptionFilterOptions};412 }413 llvm::Expected<protocol::SetExceptionBreakpointsResponseBody>414 Run(const protocol::SetExceptionBreakpointsArguments &args) const override;415};416 417class SetFunctionBreakpointsRequestHandler418 : public RequestHandler<419 protocol::SetFunctionBreakpointsArguments,420 llvm::Expected<protocol::SetFunctionBreakpointsResponseBody>> {421public:422 using RequestHandler::RequestHandler;423 static llvm::StringLiteral GetCommand() { return "setFunctionBreakpoints"; }424 FeatureSet GetSupportedFeatures() const override {425 return {protocol::eAdapterFeatureFunctionBreakpoints};426 }427 llvm::Expected<protocol::SetFunctionBreakpointsResponseBody>428 Run(const protocol::SetFunctionBreakpointsArguments &args) const override;429};430 431class DataBreakpointInfoRequestHandler432 : public RequestHandler<433 protocol::DataBreakpointInfoArguments,434 llvm::Expected<protocol::DataBreakpointInfoResponseBody>> {435public:436 using RequestHandler::RequestHandler;437 static llvm::StringLiteral GetCommand() { return "dataBreakpointInfo"; }438 FeatureSet GetSupportedFeatures() const override {439 return {protocol::eAdapterFeatureDataBreakpointBytes};440 }441 llvm::Expected<protocol::DataBreakpointInfoResponseBody>442 Run(const protocol::DataBreakpointInfoArguments &args) const override;443};444 445class SetDataBreakpointsRequestHandler446 : public RequestHandler<447 protocol::SetDataBreakpointsArguments,448 llvm::Expected<protocol::SetDataBreakpointsResponseBody>> {449public:450 using RequestHandler::RequestHandler;451 static llvm::StringLiteral GetCommand() { return "setDataBreakpoints"; }452 FeatureSet GetSupportedFeatures() const override {453 return {protocol::eAdapterFeatureDataBreakpoints};454 }455 llvm::Expected<protocol::SetDataBreakpointsResponseBody>456 Run(const protocol::SetDataBreakpointsArguments &args) const override;457};458 459class SetInstructionBreakpointsRequestHandler460 : public RequestHandler<461 protocol::SetInstructionBreakpointsArguments,462 llvm::Expected<protocol::SetInstructionBreakpointsResponseBody>> {463public:464 using RequestHandler::RequestHandler;465 static llvm::StringLiteral GetCommand() {466 return "setInstructionBreakpoints";467 }468 FeatureSet GetSupportedFeatures() const override {469 return {protocol::eAdapterFeatureInstructionBreakpoints};470 }471 llvm::Expected<protocol::SetInstructionBreakpointsResponseBody>472 Run(const protocol::SetInstructionBreakpointsArguments &args) const override;473};474 475class CompileUnitsRequestHandler : public LegacyRequestHandler {476public:477 using LegacyRequestHandler::LegacyRequestHandler;478 static llvm::StringLiteral GetCommand() { return "compileUnits"; }479 void operator()(const llvm::json::Object &request) const override;480};481 482class ModulesRequestHandler final483 : public RequestHandler<std::optional<protocol::ModulesArguments>,484 llvm::Expected<protocol::ModulesResponseBody>> {485public:486 using RequestHandler::RequestHandler;487 static llvm::StringLiteral GetCommand() { return "modules"; }488 FeatureSet GetSupportedFeatures() const override {489 return {protocol::eAdapterFeatureModulesRequest};490 }491 llvm::Expected<protocol::ModulesResponseBody>492 Run(const std::optional<protocol::ModulesArguments> &args) const override;493};494 495class PauseRequestHandler : public LegacyRequestHandler {496public:497 using LegacyRequestHandler::LegacyRequestHandler;498 static llvm::StringLiteral GetCommand() { return "pause"; }499 void operator()(const llvm::json::Object &request) const override;500};501 502class ScopesRequestHandler final503 : public RequestHandler<protocol::ScopesArguments,504 llvm::Expected<protocol::ScopesResponseBody>> {505public:506 using RequestHandler::RequestHandler;507 static llvm::StringLiteral GetCommand() { return "scopes"; }508 509 llvm::Expected<protocol::ScopesResponseBody>510 Run(const protocol::ScopesArguments &args) const override;511};512 513class SetVariableRequestHandler final514 : public RequestHandler<protocol::SetVariableArguments,515 llvm::Expected<protocol::SetVariableResponseBody>> {516public:517 using RequestHandler::RequestHandler;518 static llvm::StringLiteral GetCommand() { return "setVariable"; }519 FeatureSet GetSupportedFeatures() const override {520 return {protocol::eAdapterFeatureSetVariable};521 }522 llvm::Expected<protocol::SetVariableResponseBody>523 Run(const protocol::SetVariableArguments &args) const override;524};525 526class SourceRequestHandler final527 : public RequestHandler<protocol::SourceArguments,528 llvm::Expected<protocol::SourceResponseBody>> {529public:530 using RequestHandler::RequestHandler;531 static llvm::StringLiteral GetCommand() { return "source"; }532 llvm::Expected<protocol::SourceResponseBody>533 Run(const protocol::SourceArguments &args) const override;534};535 536class StackTraceRequestHandler : public LegacyRequestHandler {537public:538 using LegacyRequestHandler::LegacyRequestHandler;539 static llvm::StringLiteral GetCommand() { return "stackTrace"; }540 void operator()(const llvm::json::Object &request) const override;541 FeatureSet GetSupportedFeatures() const override {542 return {protocol::eAdapterFeatureDelayedStackTraceLoading};543 }544};545 546class ThreadsRequestHandler547 : public RequestHandler<protocol::ThreadsArguments,548 llvm::Expected<protocol::ThreadsResponseBody>> {549public:550 using RequestHandler::RequestHandler;551 static llvm::StringLiteral GetCommand() { return "threads"; }552 llvm::Expected<protocol::ThreadsResponseBody>553 Run(const protocol::ThreadsArguments &) const override;554};555 556class VariablesRequestHandler557 : public RequestHandler<protocol::VariablesArguments,558 llvm::Expected<protocol::VariablesResponseBody>> {559public:560 using RequestHandler::RequestHandler;561 static llvm::StringLiteral GetCommand() { return "variables"; }562 llvm::Expected<protocol::VariablesResponseBody>563 Run(const protocol::VariablesArguments &) const override;564};565 566class LocationsRequestHandler : public LegacyRequestHandler {567public:568 using LegacyRequestHandler::LegacyRequestHandler;569 static llvm::StringLiteral GetCommand() { return "locations"; }570 void operator()(const llvm::json::Object &request) const override;571};572 573class DisassembleRequestHandler final574 : public RequestHandler<protocol::DisassembleArguments,575 llvm::Expected<protocol::DisassembleResponseBody>> {576public:577 using RequestHandler::RequestHandler;578 static llvm::StringLiteral GetCommand() { return "disassemble"; }579 FeatureSet GetSupportedFeatures() const override {580 return {protocol::eAdapterFeatureDisassembleRequest};581 }582 llvm::Expected<protocol::DisassembleResponseBody>583 Run(const protocol::DisassembleArguments &args) const override;584};585 586class ReadMemoryRequestHandler final587 : public RequestHandler<protocol::ReadMemoryArguments,588 llvm::Expected<protocol::ReadMemoryResponseBody>> {589public:590 using RequestHandler::RequestHandler;591 static llvm::StringLiteral GetCommand() { return "readMemory"; }592 FeatureSet GetSupportedFeatures() const override {593 return {protocol::eAdapterFeatureReadMemoryRequest};594 }595 llvm::Expected<protocol::ReadMemoryResponseBody>596 Run(const protocol::ReadMemoryArguments &args) const override;597};598 599class CancelRequestHandler : public RequestHandler<protocol::CancelArguments,600 protocol::CancelResponse> {601public:602 using RequestHandler::RequestHandler;603 static llvm::StringLiteral GetCommand() { return "cancel"; }604 FeatureSet GetSupportedFeatures() const override {605 return {protocol::eAdapterFeatureCancelRequest};606 }607 llvm::Error Run(const protocol::CancelArguments &args) const override;608};609 610class ModuleSymbolsRequestHandler611 : public RequestHandler<612 protocol::ModuleSymbolsArguments,613 llvm::Expected<protocol::ModuleSymbolsResponseBody>> {614public:615 using RequestHandler::RequestHandler;616 static llvm::StringLiteral GetCommand() { return "__lldb_moduleSymbols"; }617 FeatureSet GetSupportedFeatures() const override {618 return {protocol::eAdapterFeatureSupportsModuleSymbolsRequest};619 }620 llvm::Expected<protocol::ModuleSymbolsResponseBody>621 Run(const protocol::ModuleSymbolsArguments &args) const override;622};623 624/// A request used in testing to get the details on all breakpoints that are625/// currently set in the target. This helps us to test "setBreakpoints" and626/// "setFunctionBreakpoints" requests to verify we have the correct set of627/// breakpoints currently set in LLDB.628class TestGetTargetBreakpointsRequestHandler : public LegacyRequestHandler {629public:630 using LegacyRequestHandler::LegacyRequestHandler;631 static llvm::StringLiteral GetCommand() {632 return "_testGetTargetBreakpoints";633 }634 void operator()(const llvm::json::Object &request) const override;635};636 637class WriteMemoryRequestHandler final638 : public RequestHandler<protocol::WriteMemoryArguments,639 llvm::Expected<protocol::WriteMemoryResponseBody>> {640public:641 using RequestHandler::RequestHandler;642 static llvm::StringLiteral GetCommand() { return "writeMemory"; }643 FeatureSet GetSupportedFeatures() const override {644 return {protocol::eAdapterFeatureWriteMemoryRequest};645 }646 llvm::Expected<protocol::WriteMemoryResponseBody>647 Run(const protocol::WriteMemoryArguments &args) const override;648};649 650} // namespace lldb_dap651 652#endif653