//===-- SetFunctionBreakpointsRequestHandler.cpp --------------------------===// // // 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 "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" #include "RequestHandler.h" namespace lldb_dap { // "SetFunctionBreakpointsRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", // "description": "SetFunctionBreakpoints request; value of command field is // 'setFunctionBreakpoints'. Sets multiple function breakpoints and clears // all previous function breakpoints. To clear all function breakpoint, // specify an empty array. When a function breakpoint is hit, a StoppedEvent // (event type 'function breakpoint') is generated.", "properties": { // "command": { // "type": "string", // "enum": [ "setFunctionBreakpoints" ] // }, // "arguments": { // "$ref": "#/definitions/SetFunctionBreakpointsArguments" // } // }, // "required": [ "command", "arguments" ] // }] // }, // "SetFunctionBreakpointsArguments": { // "type": "object", // "description": "Arguments for 'setFunctionBreakpoints' request.", // "properties": { // "breakpoints": { // "type": "array", // "items": { // "$ref": "#/definitions/FunctionBreakpoint" // }, // "description": "The function names of the breakpoints." // } // }, // "required": [ "breakpoints" ] // }, // "FunctionBreakpoint": { // "type": "object", // "description": "Properties of a breakpoint passed to the // setFunctionBreakpoints request.", "properties": { // "name": { // "type": "string", // "description": "The name of the function." // }, // "condition": { // "type": "string", // "description": "An optional expression for conditional breakpoints." // }, // "hitCondition": { // "type": "string", // "description": "An optional expression that controls how many hits of // the breakpoint are ignored. The backend is expected to interpret the // expression as needed." // } // }, // "required": [ "name" ] // }, // "SetFunctionBreakpointsResponse": { // "allOf": [ { "$ref": "#/definitions/Response" }, { // "type": "object", // "description": "Response to 'setFunctionBreakpoints' request. Returned is // information about each breakpoint created by this request.", // "properties": { // "body": { // "type": "object", // "properties": { // "breakpoints": { // "type": "array", // "items": { // "$ref": "#/definitions/Breakpoint" // }, // "description": "Information about the breakpoints. The array // elements correspond to the elements of the 'breakpoints' array." // } // }, // "required": [ "breakpoints" ] // } // }, // "required": [ "body" ] // }] // } void SetFunctionBreakpointsRequestHandler::operator()( const llvm::json::Object &request) const { llvm::json::Object response; lldb::SBError error; FillResponse(request, response); const auto *arguments = request.getObject("arguments"); const auto *breakpoints = arguments->getArray("breakpoints"); llvm::json::Array response_breakpoints; // Disable any function breakpoints that aren't in this request. // There is no call to remove function breakpoints other than calling this // function with a smaller or empty "breakpoints" list. const auto name_iter = dap.function_breakpoints.keys(); llvm::DenseSet seen(name_iter.begin(), name_iter.end()); for (const auto &value : *breakpoints) { const auto *bp_obj = value.getAsObject(); if (!bp_obj) continue; FunctionBreakpoint fn_bp(dap, *bp_obj); const auto [it, inserted] = dap.function_breakpoints.try_emplace( fn_bp.GetFunctionName(), dap, *bp_obj); if (inserted) it->second.SetBreakpoint(); else it->second.UpdateBreakpoint(fn_bp); AppendBreakpoint(&it->second, response_breakpoints); seen.erase(fn_bp.GetFunctionName()); } // Remove any breakpoints that are no longer in our list for (const auto &name : seen) { auto fn_bp = dap.function_breakpoints.find(name); if (fn_bp == dap.function_breakpoints.end()) continue; dap.target.BreakpointDelete(fn_bp->second.GetID()); dap.function_breakpoints.erase(name); } llvm::json::Object body; body.try_emplace("breakpoints", std::move(response_breakpoints)); response.try_emplace("body", std::move(body)); dap.SendJSON(llvm::json::Value(std::move(response))); } } // namespace lldb_dap