1//===-- StepInTargetsRequestHandler.cpp -----------------------------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DAP.h"
10#include "EventHelper.h"
11#include "JSONUtils.h"
12#include "RequestHandler.h"
13#include "lldb/API/SBInstruction.h"
14
15namespace lldb_dap {
16
17// "StepInTargetsRequest": {
18// "allOf": [ { "$ref": "#/definitions/Request" }, {
19// "type": "object",
20// "description": "This request retrieves the possible step-in targets for
21// the specified stack frame.\nThese targets can be used in the `stepIn`
22// request.\nClients should only call this request if the corresponding
23// capability `supportsStepInTargetsRequest` is true.", "properties": {
24// "command": {
25// "type": "string",
26// "enum": [ "stepInTargets" ]
27// },
28// "arguments": {
29// "$ref": "#/definitions/StepInTargetsArguments"
30// }
31// },
32// "required": [ "command", "arguments" ]
33// }]
34// },
35// "StepInTargetsArguments": {
36// "type": "object",
37// "description": "Arguments for `stepInTargets` request.",
38// "properties": {
39// "frameId": {
40// "type": "integer",
41// "description": "The stack frame for which to retrieve the possible
42// step-in targets."
43// }
44// },
45// "required": [ "frameId" ]
46// },
47// "StepInTargetsResponse": {
48// "allOf": [ { "$ref": "#/definitions/Response" }, {
49// "type": "object",
50// "description": "Response to `stepInTargets` request.",
51// "properties": {
52// "body": {
53// "type": "object",
54// "properties": {
55// "targets": {
56// "type": "array",
57// "items": {
58// "$ref": "#/definitions/StepInTarget"
59// },
60// "description": "The possible step-in targets of the specified
61// source location."
62// }
63// },
64// "required": [ "targets" ]
65// }
66// },
67// "required": [ "body" ]
68// }]
69// }
70void StepInTargetsRequestHandler::operator()(
71 const llvm::json::Object &request) const {
72 llvm::json::Object response;
73 FillResponse(request, response);
74 const auto *arguments = request.getObject(K: "arguments");
75
76 dap.step_in_targets.clear();
77 lldb::SBFrame frame = dap.GetLLDBFrame(arguments: *arguments);
78 if (frame.IsValid()) {
79 lldb::SBAddress pc_addr = frame.GetPCAddress();
80 lldb::SBAddress line_end_addr =
81 pc_addr.GetLineEntry().GetSameLineContiguousAddressRangeEnd(include_inlined_functions: true);
82 lldb::SBInstructionList insts = dap.target.ReadInstructions(
83 start_addr: pc_addr, end_addr: line_end_addr, /*flavor_string=*/nullptr);
84
85 if (!insts.IsValid()) {
86 response["success"] = false;
87 response["message"] = "Failed to get instructions for frame.";
88 dap.SendJSON(json: llvm::json::Value(std::move(response)));
89 return;
90 }
91
92 llvm::json::Array step_in_targets;
93 const auto num_insts = insts.GetSize();
94 for (size_t i = 0; i < num_insts; ++i) {
95 lldb::SBInstruction inst = insts.GetInstructionAtIndex(idx: i);
96 if (!inst.IsValid())
97 break;
98
99 lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(target: dap.target);
100
101 // Note: currently only x86/x64 supports flow kind.
102 lldb::InstructionControlFlowKind flow_kind =
103 inst.GetControlFlowKind(target: dap.target);
104 if (flow_kind == lldb::eInstructionControlFlowKindCall) {
105 // Use call site instruction address as id which is easy to debug.
106 llvm::json::Object step_in_target;
107 step_in_target["id"] = inst_addr;
108
109 llvm::StringRef call_operand_name = inst.GetOperands(target: dap.target);
110 lldb::addr_t call_target_addr;
111 if (call_operand_name.getAsInteger(Radix: 0, Result&: call_target_addr))
112 continue;
113
114 lldb::SBAddress call_target_load_addr =
115 dap.target.ResolveLoadAddress(vm_addr: call_target_addr);
116 if (!call_target_load_addr.IsValid())
117 continue;
118
119 // The existing ThreadPlanStepInRange only accept step in target
120 // function with debug info.
121 lldb::SBSymbolContext sc = dap.target.ResolveSymbolContextForAddress(
122 addr: call_target_load_addr, resolve_scope: lldb::eSymbolContextFunction);
123
124 // The existing ThreadPlanStepInRange only accept step in target
125 // function with debug info.
126 std::string step_in_target_name;
127 if (sc.IsValid() && sc.GetFunction().IsValid())
128 step_in_target_name = sc.GetFunction().GetDisplayName();
129
130 // Skip call sites if we fail to resolve its symbol name.
131 if (step_in_target_name.empty())
132 continue;
133
134 dap.step_in_targets.try_emplace(Key: inst_addr, Args&: step_in_target_name);
135 step_in_target.try_emplace(K: "label", Args&: step_in_target_name);
136 step_in_targets.emplace_back(A: std::move(step_in_target));
137 }
138 }
139 llvm::json::Object body;
140 body.try_emplace(K: "targets", Args: std::move(step_in_targets));
141 response.try_emplace(K: "body", Args: std::move(body));
142 } else {
143 response["success"] = llvm::json::Value(false);
144 response["message"] = "Failed to get frame for input frameId.";
145 }
146 dap.SendJSON(json: llvm::json::Value(std::move(response)));
147}
148
149} // namespace lldb_dap
150

source code of lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp