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 "Protocol/ProtocolRequests.h"
11#include "RequestHandler.h"
12#include "lldb/API/SBInstruction.h"
13#include "lldb/lldb-defines.h"
14
15using namespace lldb_dap::protocol;
16namespace lldb_dap {
17
18// This request retrieves the possible step-in targets for the specified stack
19// frame.
20// These targets can be used in the `stepIn` request.
21// Clients should only call this request if the corresponding capability
22// `supportsStepInTargetsRequest` is true.
23llvm::Expected<StepInTargetsResponseBody>
24StepInTargetsRequestHandler::Run(const StepInTargetsArguments &args) const {
25 dap.step_in_targets.clear();
26 const lldb::SBFrame frame = dap.GetLLDBFrame(frame_id: args.frameId);
27 if (!frame.IsValid())
28 return llvm::make_error<DAPError>(Args: "Failed to get frame for input frameId.");
29
30 lldb::SBAddress pc_addr = frame.GetPCAddress();
31 lldb::SBAddress line_end_addr =
32 pc_addr.GetLineEntry().GetSameLineContiguousAddressRangeEnd(include_inlined_functions: true);
33 lldb::SBInstructionList insts = dap.target.ReadInstructions(
34 start_addr: pc_addr, end_addr: line_end_addr, /*flavor_string=*/nullptr);
35
36 if (!insts.IsValid())
37 return llvm::make_error<DAPError>(Args: "Failed to get instructions for frame.");
38
39 StepInTargetsResponseBody body;
40 const size_t num_insts = insts.GetSize();
41 for (size_t i = 0; i < num_insts; ++i) {
42 lldb::SBInstruction inst = insts.GetInstructionAtIndex(idx: i);
43 if (!inst.IsValid())
44 break;
45
46 const lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(target: dap.target);
47 if (inst_addr == LLDB_INVALID_ADDRESS)
48 break;
49
50 // Note: currently only x86/x64 supports flow kind.
51 const lldb::InstructionControlFlowKind flow_kind =
52 inst.GetControlFlowKind(target: dap.target);
53
54 if (flow_kind == lldb::eInstructionControlFlowKindCall) {
55
56 const llvm::StringRef call_operand_name = inst.GetOperands(target: dap.target);
57 lldb::addr_t call_target_addr = LLDB_INVALID_ADDRESS;
58 if (call_operand_name.getAsInteger(Radix: 0, Result&: call_target_addr))
59 continue;
60
61 const lldb::SBAddress call_target_load_addr =
62 dap.target.ResolveLoadAddress(vm_addr: call_target_addr);
63 if (!call_target_load_addr.IsValid())
64 continue;
65
66 // The existing ThreadPlanStepInRange only accept step in target
67 // function with debug info.
68 lldb::SBSymbolContext sc = dap.target.ResolveSymbolContextForAddress(
69 addr: call_target_load_addr, resolve_scope: lldb::eSymbolContextFunction);
70
71 // The existing ThreadPlanStepInRange only accept step in target
72 // function with debug info.
73 llvm::StringRef step_in_target_name;
74 if (sc.IsValid() && sc.GetFunction().IsValid())
75 step_in_target_name = sc.GetFunction().GetDisplayName();
76
77 // Skip call sites if we fail to resolve its symbol name.
78 if (step_in_target_name.empty())
79 continue;
80
81 StepInTarget target;
82 target.id = inst_addr;
83 target.label = step_in_target_name;
84 dap.step_in_targets.try_emplace(Key: inst_addr, Args&: step_in_target_name);
85 body.targets.emplace_back(args: std::move(target));
86 }
87 }
88 return body;
89}
90
91} // namespace lldb_dap
92

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