[lldb-dap] Prevent using an implicit step-in
. (#143644)
When there is a function that is inlined at the current program counter. If you get the current `line_entry` using the program counter's address it will point to the location of the inline function that may be in another file. (this is in implicit step-in and should not happen what step over is called). Use the current frame to get the `line_entry`
This commit is contained in:
parent
8763ac3252
commit
c5f47c6fd2
@ -344,7 +344,12 @@ class DAPTestCaseBase(TestBase):
|
||||
granularity="statement",
|
||||
timeout=DEFAULT_TIMEOUT,
|
||||
):
|
||||
self.dap_server.request_next(threadId=threadId, granularity=granularity)
|
||||
response = self.dap_server.request_next(
|
||||
threadId=threadId, granularity=granularity
|
||||
)
|
||||
self.assertTrue(
|
||||
response["success"], f"next request failed: response {response}"
|
||||
)
|
||||
if waitForStop:
|
||||
return self.dap_server.wait_for_stopped(timeout)
|
||||
return None
|
||||
|
@ -83,3 +83,41 @@ class TestDAP_step(lldbdap_testcase.DAPTestCaseBase):
|
||||
|
||||
# only step one thread that is at the breakpoint and stop
|
||||
break
|
||||
|
||||
def test_step_over_inlined_function(self):
|
||||
"""
|
||||
Test stepping over when the program counter is in another file.
|
||||
"""
|
||||
program = self.getBuildArtifact("a.out")
|
||||
self.build_and_launch(program)
|
||||
source = "main.cpp"
|
||||
breakpoint_lines = [line_number(source, "// breakpoint 2")]
|
||||
step_over_pos = line_number(source, "// position_after_step_over")
|
||||
breakpoint_ids = self.set_source_breakpoints(source, breakpoint_lines)
|
||||
self.assertEqual(
|
||||
len(breakpoint_ids),
|
||||
len(breakpoint_lines),
|
||||
"expect correct number of breakpoints.",
|
||||
)
|
||||
self.continue_to_breakpoints(breakpoint_ids)
|
||||
|
||||
thread_id = self.dap_server.get_thread_id()
|
||||
self.stepOver(thread_id)
|
||||
levels = 1
|
||||
frames = self.get_stackFrames(thread_id, 0, levels)
|
||||
self.assertEqual(len(frames), levels, "expect current number of frame levels.")
|
||||
top_frame = frames[0]
|
||||
self.assertEqual(
|
||||
top_frame["source"]["name"], source, "expect we are in the same file."
|
||||
)
|
||||
self.assertTrue(
|
||||
top_frame["source"]["path"].endswith(source),
|
||||
f"expect path ending with '{source}'.",
|
||||
)
|
||||
self.assertEqual(
|
||||
top_frame["line"],
|
||||
step_over_pos,
|
||||
f"expect step_over on line {step_over_pos}",
|
||||
)
|
||||
|
||||
self.continue_to_exit()
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include "other.h"
|
||||
|
||||
int function(int x) {
|
||||
if ((x % 2) == 0)
|
||||
return function(x - 1) + x; // breakpoint 1
|
||||
@ -5,4 +7,14 @@ int function(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[]) { return function(2); }
|
||||
int function2() {
|
||||
int volatile value = 3; // breakpoint 2
|
||||
inlined_fn(); // position_after_step_over
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
int func_result = function2();
|
||||
return function(2) - func_result; // returns 0
|
||||
}
|
||||
|
7
lldb/test/API/tools/lldb-dap/step/other.h
Normal file
7
lldb/test/API/tools/lldb-dap/step/other.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef OTHER_H
|
||||
#define OTHER_H
|
||||
|
||||
__attribute__((noinline)) void not_inlined_fn() {};
|
||||
|
||||
__attribute__((always_inline)) inline void inlined_fn() { not_inlined_fn(); }
|
||||
#endif // OTHER_H
|
@ -623,6 +623,17 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
|
||||
llvm_unreachable("enum cases exhausted.");
|
||||
}
|
||||
|
||||
std::optional<protocol::Source> DAP::ResolveSource(const lldb::SBFrame &frame) {
|
||||
if (!frame.IsValid())
|
||||
return std::nullopt;
|
||||
|
||||
const lldb::SBAddress frame_pc = frame.GetPCAddress();
|
||||
if (DisplayAssemblySource(debugger, frame_pc))
|
||||
return ResolveAssemblySource(frame_pc);
|
||||
|
||||
return CreateSource(frame.GetLineEntry().GetFileSpec());
|
||||
}
|
||||
|
||||
std::optional<protocol::Source> DAP::ResolveSource(lldb::SBAddress address) {
|
||||
if (DisplayAssemblySource(debugger, address))
|
||||
return ResolveAssemblySource(address);
|
||||
|
@ -254,6 +254,17 @@ struct DAP {
|
||||
ReplMode DetectReplMode(lldb::SBFrame frame, std::string &expression,
|
||||
bool partial_expression);
|
||||
|
||||
/// Create a `protocol::Source` object as described in the debug adapter
|
||||
/// definition.
|
||||
///
|
||||
/// \param[in] frame
|
||||
/// The frame to use when populating the "Source" object.
|
||||
///
|
||||
/// \return
|
||||
/// A `protocol::Source` object that follows the formal JSON
|
||||
/// definition outlined by Microsoft.
|
||||
std::optional<protocol::Source> ResolveSource(const lldb::SBFrame &frame);
|
||||
|
||||
/// Create a "Source" JSON object as described in the debug adapter
|
||||
/// definition.
|
||||
///
|
||||
|
@ -572,9 +572,7 @@ llvm::json::Value CreateStackFrame(DAP &dap, lldb::SBFrame &frame,
|
||||
|
||||
EmplaceSafeString(object, "name", frame_name);
|
||||
|
||||
auto target = frame.GetThread().GetProcess().GetTarget();
|
||||
std::optional<protocol::Source> source =
|
||||
dap.ResolveSource(frame.GetPCAddress());
|
||||
std::optional<protocol::Source> source = dap.ResolveSource(frame);
|
||||
|
||||
if (source && !IsAssemblySource(*source)) {
|
||||
// This is a normal source with a valid line entry.
|
||||
@ -586,8 +584,7 @@ llvm::json::Value CreateStackFrame(DAP &dap, lldb::SBFrame &frame,
|
||||
// This is a source where the disassembly is used, but there is a valid
|
||||
// symbol. Calculate the line of the current PC from the start of the
|
||||
// current symbol.
|
||||
lldb::SBTarget target = frame.GetThread().GetProcess().GetTarget();
|
||||
lldb::SBInstructionList inst_list = target.ReadInstructions(
|
||||
lldb::SBInstructionList inst_list = dap.target.ReadInstructions(
|
||||
frame.GetSymbol().GetStartAddress(), frame.GetPCAddress(), nullptr);
|
||||
size_t inst_line = inst_list.GetSize();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user