Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb] Implement CLI support for reverse-continue #132783

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion lldb/source/Commands/CommandObjectProcess.cpp
Original file line number Diff line number Diff line change
@@ -468,7 +468,13 @@ class CommandObjectProcessContinue : public CommandObjectParsed {
case 'b':
m_run_to_bkpt_args.AppendArgument(option_arg);
m_any_bkpts_specified = true;
break;
break;
case 'F':
m_base_direction = lldb::RunDirection::eRunForward;
break;
case 'R':
m_base_direction = lldb::RunDirection::eRunReverse;
break;
default:
llvm_unreachable("Unimplemented option");
}
@@ -479,6 +485,7 @@ class CommandObjectProcessContinue : public CommandObjectParsed {
m_ignore = 0;
m_run_to_bkpt_args.Clear();
m_any_bkpts_specified = false;
m_base_direction = std::nullopt;
}

llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -488,6 +495,7 @@ class CommandObjectProcessContinue : public CommandObjectParsed {
uint32_t m_ignore = 0;
Args m_run_to_bkpt_args;
bool m_any_bkpts_specified = false;
std::optional<lldb::RunDirection> m_base_direction;
};

void DoExecute(Args &command, CommandReturnObject &result) override {
@@ -654,6 +662,9 @@ class CommandObjectProcessContinue : public CommandObjectParsed {
}
}

if (m_options.m_base_direction.has_value())
process->SetBaseDirection(*m_options.m_base_direction);

const uint32_t iohandler_id = process->GetIOHandlerID();

StreamString stream;
8 changes: 6 additions & 2 deletions lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
@@ -737,13 +737,17 @@ let Command = "process attach" in {
}

let Command = "process continue" in {
def process_continue_ignore_count : Option<"ignore-count", "i">, Group<1>,
def process_continue_ignore_count : Option<"ignore-count", "i">, Groups<[1,2]>,
Arg<"UnsignedInteger">, Desc<"Ignore <N> crossings of the breakpoint (if it"
" exists) for the currently selected thread.">;
def process_continue_run_to_bkpt : Option<"continue-to-bkpt", "b">, Group<2>,
def process_continue_run_to_bkpt : Option<"continue-to-bkpt", "b">, Groups<[3,4]>,
Arg<"BreakpointIDRange">, Desc<"Specify a breakpoint to continue to, temporarily "
"ignoring other breakpoints. Can be specified more than once. "
"The continue action will be done synchronously if this option is specified.">;
def thread_continue_forward : Option<"forward", "F">, Groups<[1,3]>,
Desc<"Set the direction to forward before continuing.">;
def thread_continue_reverse : Option<"reverse", "R">, Groups<[2,4]>,
Desc<"Set the direction to reverse before continuing.">;
}

let Command = "process detach" in {
3 changes: 3 additions & 0 deletions lldb/test/API/commands/process/reverse-continue/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
C_SOURCES := main.c

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
Test the "process continue --reverse" and "--forward" options.
"""


import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test.gdbclientutils import *
from lldbsuite.test.lldbreverse import ReverseTestBase
from lldbsuite.test import lldbutil


class TestReverseContinue(ReverseTestBase):
@skipIfRemote
def test_reverse_continue(self):
target, _, _ = self.setup_recording()

# Set breakpoint and reverse-continue
trigger_bkpt = target.BreakpointCreateByName("trigger_breakpoint", None)
self.assertTrue(trigger_bkpt.GetNumLocations() > 0)
self.expect(
"process continue --reverse",
substrs=["stop reason = breakpoint {0}.1".format(trigger_bkpt.GetID())],
)
# `process continue` should preserve current base direction.
self.expect(
"process continue",
STOPPED_DUE_TO_HISTORY_BOUNDARY,
substrs=["stopped", "stop reason = history boundary"],
)
self.expect(
"process continue --forward",
substrs=["stop reason = breakpoint {0}.1".format(trigger_bkpt.GetID())],
)

def setup_recording(self):
"""
Record execution of code between "start_recording" and "stop_recording" breakpoints.

Returns with the target stopped at "stop_recording", with recording disabled,
ready to reverse-execute.
"""
self.build()
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
process = self.connect(target)

# Record execution from the start of the function "start_recording"
# to the start of the function "stop_recording". We want to keep the
# interval that we record as small as possible to minimize the run-time
# of our single-stepping recorder.
start_recording_bkpt = target.BreakpointCreateByName("start_recording", None)
self.assertTrue(start_recording_bkpt.GetNumLocations() > 0)
initial_threads = lldbutil.continue_to_breakpoint(process, start_recording_bkpt)
self.assertEqual(len(initial_threads), 1)
target.BreakpointDelete(start_recording_bkpt.GetID())
self.start_recording()
stop_recording_bkpt = target.BreakpointCreateByName("stop_recording", None)
self.assertTrue(stop_recording_bkpt.GetNumLocations() > 0)
lldbutil.continue_to_breakpoint(process, stop_recording_bkpt)
target.BreakpointDelete(stop_recording_bkpt.GetID())
self.stop_recording()

self.dbg.SetAsync(False)

return target, process, initial_threads
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Test the "process continue --reverse" and "--forward" options
when reverse-continue is not supported.
"""


import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil


class TestReverseContinueNotSupported(TestBase):
def test_reverse_continue_not_supported(self):
target = self.connect()

# Set breakpoint and reverse-continue
trigger_bkpt = target.BreakpointCreateByName("trigger_breakpoint", None)
self.assertTrue(trigger_bkpt, VALID_BREAKPOINT)
# `process continue --forward` should work.
self.expect(
"process continue --forward",
substrs=["stop reason = breakpoint {0}.1".format(trigger_bkpt.GetID())],
)
self.expect(
"process continue --reverse",
error=True,
substrs=["target does not support reverse-continue"],
)

def test_reverse_continue_forward_and_reverse(self):
self.connect()

self.expect(
"process continue --forward --reverse",
error=True,
substrs=["invalid combination of options for the given command"],
)

def connect(self):
self.build()
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)

main_bkpt = target.BreakpointCreateByName("main", None)
self.assertTrue(main_bkpt, VALID_BREAKPOINT)

process = target.LaunchSimple(None, None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
return target
12 changes: 12 additions & 0 deletions lldb/test/API/commands/process/reverse-continue/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
static void start_recording() {}

static void trigger_breakpoint() {}

static void stop_recording() {}

int main() {
start_recording();
trigger_breakpoint();
stop_recording();
return 0;
}
4 changes: 4 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -223,6 +223,10 @@ Changes to LLDB
* The `min-gdbserver-port` and `max-gdbserver-port` options have been removed
from `lldb-server`'s platform mode. Since the changes to `lldb-server`'s port
handling in LLDB 20, these options have had no effect.
* LLDB now supports `process continue --reverse` when used with debug servers
supporting reverse execution, such as [rr](https://rr-project.org).
When using reverse execution, `process continue --forward` returns to the
forward execution.

### Changes to lldb-dap

Loading
Oops, something went wrong.