blob: c45dc0d0d6553b609e5c6beebacd8f16fc3eedad [file] [log] [blame]
//===-- 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<llvm::StringRef> 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