[Lldb-commits] [lldb] [lldb] Add step back single instruction for targets supporting reverse execution (PR #191183)

Maarten Steevens via lldb-commits lldb-commits at lists.llvm.org
Thu Apr 9 05:57:41 PDT 2026


https://github.com/MaartenS11 updated https://github.com/llvm/llvm-project/pull/191183

>From 0c0db27fff745bd87908181435ad07beb5e56243 Mon Sep 17 00:00:00 2001
From: MaartenS11 <maarten.steevens at gmail.com>
Date: Thu, 9 Apr 2026 10:08:17 +0200
Subject: [PATCH 1/5] Early attempt at step back with a threadplan

---
 .../Process/gdb-remote/ProcessGDBRemote.cpp   | 53 +++++++++++++++++++
 .../Process/gdb-remote/ProcessGDBRemote.h     |  2 +
 2 files changed, 55 insertions(+)

diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index d74649a48405d..ed99c5103fb5d 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3903,6 +3903,37 @@ void ProcessGDBRemote::StopAsyncThread() {
         __FUNCTION__);
 }
 
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+
+class ThreadPlanStepBackInstruction : public ThreadPlanStepInstruction {
+public:
+  ThreadPlanStepBackInstruction(Thread &thread,
+                                                     bool step_over,
+                                                     bool stop_other_threads,
+                                                     Vote report_stop_vote,
+                                                     Vote report_run_vote)
+    : ThreadPlanStepInstruction(thread, step_over, stop_other_threads, report_stop_vote, report_run_vote) {}
+
+  lldb::RunDirection GetDirection() const override {
+    return lldb::RunDirection::eRunReverse;
+  }
+};
+
+Status ProcessGDBRemote::StepBack() {
+  LLDB_LOGF(GetLog(GDBRLog::Process), "Thread count = %d", m_thread_ids.size());
+  ThreadSP thread = GetThreadList().FindThreadByID(m_thread_ids[0]);
+
+  ThreadPlanSP thread_plan_sp(new ThreadPlanStepBackInstruction(
+      *thread, false, true, eVoteNoOpinion, eVoteNoOpinion));
+  thread->QueueThreadPlan(thread_plan_sp, false);
+
+  thread_plan_sp->SetIsControllingPlan(true);
+  thread_plan_sp->SetOkayToDiscard(false);
+
+  GetThreadList().SetSelectedThreadByID(m_thread_ids[0]);
+  return Resume();
+}
+
 thread_result_t ProcessGDBRemote::AsyncThread() {
   Log *log = GetLog(GDBRLog::Process);
   LLDB_LOGF(log, "ProcessGDBRemote::%s(pid = %" PRIu64 ") thread starting...",
@@ -5953,6 +5984,25 @@ class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed {
   }
 };
 
+class CommandObjectProcessGDBRemotePacketStepBack : public CommandObjectParsed {
+  private:
+public:
+  CommandObjectProcessGDBRemotePacketStepBack(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "process plugin packet step-back",
+                            "Step back one instruction",
+                            nullptr) {}
+
+  ~CommandObjectProcessGDBRemotePacketStepBack() override = default;
+
+  void DoExecute(Args &command, CommandReturnObject &result) override {
+    ProcessGDBRemote *process =
+        (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+    if (process) {
+        process->StepBack();
+    }
+  }
+};
+
 class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw {
 private:
 public:
@@ -6012,6 +6062,9 @@ class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword {
     LoadSubCommand(
         "send", CommandObjectSP(
                     new CommandObjectProcessGDBRemotePacketSend(interpreter)));
+    LoadSubCommand(
+        "step-back", CommandObjectSP(
+                    new CommandObjectProcessGDBRemotePacketStepBack(interpreter)));
     LoadSubCommand(
         "monitor",
         CommandObjectSP(
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 434c4f29201e5..5dec9b1061e77 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -255,6 +255,8 @@ class ProcessGDBRemote : public Process,
 
   llvm::Expected<bool> SaveCore(llvm::StringRef outfile) override;
 
+  Status StepBack();
+
 protected:
   friend class ThreadGDBRemote;
   friend class GDBRemoteCommunicationClient;

>From 25dc464c626e275ac94a0f0ac12326cb2045afb8 Mon Sep 17 00:00:00 2001
From: MaartenS11 <maarten.steevens at gmail.com>
Date: Thu, 9 Apr 2026 10:24:45 +0200
Subject: [PATCH 2/5] Use the currently selected thread instead of thread 0

---
 lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index ed99c5103fb5d..860339a0ec28f 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3920,8 +3920,7 @@ class ThreadPlanStepBackInstruction : public ThreadPlanStepInstruction {
 };
 
 Status ProcessGDBRemote::StepBack() {
-  LLDB_LOGF(GetLog(GDBRLog::Process), "Thread count = %d", m_thread_ids.size());
-  ThreadSP thread = GetThreadList().FindThreadByID(m_thread_ids[0]);
+  ThreadSP thread = GetThreadList().GetSelectedThread();
 
   ThreadPlanSP thread_plan_sp(new ThreadPlanStepBackInstruction(
       *thread, false, true, eVoteNoOpinion, eVoteNoOpinion));
@@ -3930,7 +3929,6 @@ Status ProcessGDBRemote::StepBack() {
   thread_plan_sp->SetIsControllingPlan(true);
   thread_plan_sp->SetOkayToDiscard(false);
 
-  GetThreadList().SetSelectedThreadByID(m_thread_ids[0]);
   return Resume();
 }
 

>From 3959964d73d24fc8ddb7f9b3897e4619f94acfd7 Mon Sep 17 00:00:00 2001
From: MaartenS11 <maarten.steevens at gmail.com>
Date: Thu, 9 Apr 2026 10:39:08 +0200
Subject: [PATCH 3/5] Move some code into Thread.cpp so other platforms can
 also implement step back

---
 lldb/include/lldb/Target/Thread.h             |  7 ++++
 .../Process/gdb-remote/ProcessGDBRemote.cpp   | 31 +--------------
 .../Process/gdb-remote/ProcessGDBRemote.h     |  2 -
 lldb/source/Target/Thread.cpp                 | 38 +++++++++++++++++++
 4 files changed, 46 insertions(+), 32 deletions(-)

diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
index c698dd8015885..7b52fc3238b97 100644
--- a/lldb/include/lldb/Target/Thread.h
+++ b/lldb/include/lldb/Target/Thread.h
@@ -629,6 +629,13 @@ class Thread : public std::enable_shared_from_this<Thread>,
   ///     An error that describes anything that went wrong
   virtual Status StepOut(uint32_t frame_idx = 0);
 
+  /// Default implementation for stepping back one instruction.
+  ///
+  /// This function is designed to be used by commands where the
+  /// process is publicly stopped.
+  ///
+  virtual Status StepBack();
+
   /// Retrieves the per-thread data area.
   /// Most OSs maintain a per-thread pointer (e.g. the FS register on
   /// x64), which we return the value of here.
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 860339a0ec28f..d75d092954611 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3903,35 +3903,6 @@ void ProcessGDBRemote::StopAsyncThread() {
         __FUNCTION__);
 }
 
-#include "lldb/Target/ThreadPlanStepInstruction.h"
-
-class ThreadPlanStepBackInstruction : public ThreadPlanStepInstruction {
-public:
-  ThreadPlanStepBackInstruction(Thread &thread,
-                                                     bool step_over,
-                                                     bool stop_other_threads,
-                                                     Vote report_stop_vote,
-                                                     Vote report_run_vote)
-    : ThreadPlanStepInstruction(thread, step_over, stop_other_threads, report_stop_vote, report_run_vote) {}
-
-  lldb::RunDirection GetDirection() const override {
-    return lldb::RunDirection::eRunReverse;
-  }
-};
-
-Status ProcessGDBRemote::StepBack() {
-  ThreadSP thread = GetThreadList().GetSelectedThread();
-
-  ThreadPlanSP thread_plan_sp(new ThreadPlanStepBackInstruction(
-      *thread, false, true, eVoteNoOpinion, eVoteNoOpinion));
-  thread->QueueThreadPlan(thread_plan_sp, false);
-
-  thread_plan_sp->SetIsControllingPlan(true);
-  thread_plan_sp->SetOkayToDiscard(false);
-
-  return Resume();
-}
-
 thread_result_t ProcessGDBRemote::AsyncThread() {
   Log *log = GetLog(GDBRLog::Process);
   LLDB_LOGF(log, "ProcessGDBRemote::%s(pid = %" PRIu64 ") thread starting...",
@@ -5996,7 +5967,7 @@ class CommandObjectProcessGDBRemotePacketStepBack : public CommandObjectParsed {
     ProcessGDBRemote *process =
         (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
     if (process) {
-        process->StepBack();
+        process->GetThreadList().GetSelectedThread()->StepBack();
     }
   }
 };
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 5dec9b1061e77..434c4f29201e5 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -255,8 +255,6 @@ class ProcessGDBRemote : public Process,
 
   llvm::Expected<bool> SaveCore(llvm::StringRef outfile) override;
 
-  Status StepBack();
-
 protected:
   friend class ThreadGDBRemote;
   friend class GDBRemoteCommunicationClient;
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index c8e50db2316ad..5c5449126343b 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -2322,6 +2322,44 @@ Status Thread::StepOut(uint32_t frame_idx) {
   return error;
 }
 
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+
+class ThreadPlanStepBackInstruction : public ThreadPlanStepInstruction {
+public:
+  ThreadPlanStepBackInstruction(Thread &thread,
+                                                     bool step_over,
+                                                     bool stop_other_threads,
+                                                     Vote report_stop_vote,
+                                                     Vote report_run_vote)
+    : ThreadPlanStepInstruction(thread, step_over, stop_other_threads, report_stop_vote, report_run_vote) {}
+
+  lldb::RunDirection GetDirection() const override {
+    return lldb::RunDirection::eRunReverse;
+  }
+};
+
+Status Thread::StepBack() {
+  Process *process = GetProcess().get();
+  if (!StateIsStoppedState(process->GetState(), true)) {
+    return Status::FromErrorString("process not stopped");
+  }
+
+  if (!process->SupportsReverseDirection()) {
+    return Status::FromErrorString("process does not support reverse execution");
+  }
+  
+  ThreadPlanSP thread_plan_sp(new ThreadPlanStepBackInstruction(
+      *this, false, true, eVoteNoOpinion, eVoteNoOpinion));
+  QueueThreadPlan(thread_plan_sp, false);
+
+  thread_plan_sp->SetIsControllingPlan(true);
+  thread_plan_sp->SetOkayToDiscard(false);
+
+  // Why do we need to set the current thread by ID here???
+  process->GetThreadList().SetSelectedThreadByID(GetID());
+  return process->Resume();
+}
+
 ValueObjectSP Thread::GetCurrentException() {
   if (auto frame_sp = GetStackFrameAtIndex(0))
     if (auto recognized_frame = frame_sp->GetRecognizedFrame())

>From 789629468bc5aa85a9aedba79429d5df1193b433 Mon Sep 17 00:00:00 2001
From: MaartenS11 <maarten.steevens at gmail.com>
Date: Thu, 9 Apr 2026 11:16:29 +0200
Subject: [PATCH 4/5] Add thread step-back-inst + stepbi sbi alias + remove old
 testing command

---
 lldb/source/Commands/CommandObjectThread.cpp  | 24 +++++++++++++++++++
 .../source/Interpreter/CommandInterpreter.cpp |  6 +++++
 .../Process/gdb-remote/ProcessGDBRemote.cpp   | 22 -----------------
 3 files changed, 30 insertions(+), 22 deletions(-)

diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 6786741cd04b6..bbf38981aee60 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -632,6 +632,26 @@ class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
   OptionGroupOptions m_all_options;
 };
 
+// CommandObjectThreadStepBackInstruction
+
+class CommandObjectThreadStepBackInstruction : public CommandObjectParsed {
+  private:
+public:
+  CommandObjectThreadStepBackInstruction(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "process plugin packet step-back",
+                            "Step back one instruction.",
+                            nullptr) {}
+
+  ~CommandObjectThreadStepBackInstruction() override = default;
+
+  void DoExecute(Args &command, CommandReturnObject &result) override {
+    Process *process = m_exe_ctx.GetProcessPtr();
+    if (process) {
+        process->GetThreadList().GetSelectedThread()->StepBack();
+    }
+  }
+};
+
 // CommandObjectThreadContinue
 
 class CommandObjectThreadContinue : public CommandObjectParsed {
@@ -2590,6 +2610,10 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread(
                      "Defaults to current thread unless specified.",
                      nullptr, eStepTypeTrace)));
 
+  LoadSubCommand("step-back-inst",
+                 CommandObjectSP(new CommandObjectThreadStepBackInstruction(
+                     interpreter)));
+
   LoadSubCommand("step-inst-over",
                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
                      interpreter, "thread step-inst-over",
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index eeb1ae0ff3eb8..139ac072a4ee9 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -335,6 +335,12 @@ void CommandInterpreter::Initialize() {
     AddAlias("si", cmd_obj_sp);
   }
 
+  cmd_obj_sp = GetCommandSPExact("thread step-back-inst");
+  if (cmd_obj_sp) {
+    AddAlias("stepbi", cmd_obj_sp);
+    AddAlias("sbi", cmd_obj_sp);
+  }
+
   cmd_obj_sp = GetCommandSPExact("thread step-inst-over");
   if (cmd_obj_sp) {
     AddAlias("nexti", cmd_obj_sp);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index d75d092954611..d74649a48405d 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5953,25 +5953,6 @@ class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed {
   }
 };
 
-class CommandObjectProcessGDBRemotePacketStepBack : public CommandObjectParsed {
-  private:
-public:
-  CommandObjectProcessGDBRemotePacketStepBack(CommandInterpreter &interpreter)
-      : CommandObjectParsed(interpreter, "process plugin packet step-back",
-                            "Step back one instruction",
-                            nullptr) {}
-
-  ~CommandObjectProcessGDBRemotePacketStepBack() override = default;
-
-  void DoExecute(Args &command, CommandReturnObject &result) override {
-    ProcessGDBRemote *process =
-        (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
-    if (process) {
-        process->GetThreadList().GetSelectedThread()->StepBack();
-    }
-  }
-};
-
 class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw {
 private:
 public:
@@ -6031,9 +6012,6 @@ class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword {
     LoadSubCommand(
         "send", CommandObjectSP(
                     new CommandObjectProcessGDBRemotePacketSend(interpreter)));
-    LoadSubCommand(
-        "step-back", CommandObjectSP(
-                    new CommandObjectProcessGDBRemotePacketStepBack(interpreter)));
     LoadSubCommand(
         "monitor",
         CommandObjectSP(

>From 6d4acca4f66f806f57dcc163600d697523f33243 Mon Sep 17 00:00:00 2001
From: MaartenS11 <maarten.steevens at gmail.com>
Date: Thu, 9 Apr 2026 14:23:40 +0200
Subject: [PATCH 5/5] Refactor code to integerate with
 QueueThreadPlanForStepSingleInstruction which now has a direction

---
 lldb/include/lldb/Target/Thread.h             |  4 +-
 .../lldb/Target/ThreadPlanStepInstruction.h   |  9 ++-
 lldb/include/lldb/lldb-private-enumerations.h |  1 +
 lldb/source/API/SBThread.cpp                  |  8 ++-
 lldb/source/API/SBThreadPlan.cpp              |  2 +-
 lldb/source/Commands/CommandObjectThread.cpp  | 43 +++++--------
 .../MacOSX-DYLD/DynamicLoaderDarwin.cpp       |  4 +-
 .../Windows-DYLD/DynamicLoaderWindowsDYLD.cpp |  2 +-
 lldb/source/Target/StopInfo.cpp               |  6 +-
 lldb/source/Target/Thread.cpp                 | 63 ++++++++-----------
 .../Target/ThreadPlanStepInstruction.cpp      | 14 +++--
 11 files changed, 72 insertions(+), 84 deletions(-)

diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
index 7b52fc3238b97..31205acba5fb3 100644
--- a/lldb/include/lldb/Target/Thread.h
+++ b/lldb/include/lldb/Target/Thread.h
@@ -730,8 +730,8 @@ class Thread : public std::enable_shared_from_this<Thread>,
   ///     A shared pointer to the newly queued thread plan, or nullptr if the
   ///     plan could not be queued.
   virtual lldb::ThreadPlanSP QueueThreadPlanForStepSingleInstruction(
-      bool step_over, bool abort_other_plans, bool stop_other_threads,
-      Status &status);
+      bool step_over, lldb::RunDirection direction, bool abort_other_plans,
+      bool stop_other_threads, Status &status);
 
   /// Queues the plan used to step through an address range, stepping  over
   /// function calls.
diff --git a/lldb/include/lldb/Target/ThreadPlanStepInstruction.h b/lldb/include/lldb/Target/ThreadPlanStepInstruction.h
index 52a5a2efc0a47..f8a3f56cb422a 100644
--- a/lldb/include/lldb/Target/ThreadPlanStepInstruction.h
+++ b/lldb/include/lldb/Target/ThreadPlanStepInstruction.h
@@ -17,7 +17,8 @@ namespace lldb_private {
 
 class ThreadPlanStepInstruction : public ThreadPlan {
 public:
-  ThreadPlanStepInstruction(Thread &thread, bool step_over, bool stop_others,
+  ThreadPlanStepInstruction(Thread &thread, bool step_over,
+                            lldb::RunDirection direction, bool stop_others,
                             Vote report_stop_vote, Vote report_run_vote);
 
   ~ThreadPlanStepInstruction() override;
@@ -30,6 +31,7 @@ class ThreadPlanStepInstruction : public ThreadPlan {
   bool WillStop() override;
   bool MischiefManaged() override;
   bool IsPlanStale() override;
+  lldb::RunDirection GetDirection() const override;
 
 protected:
   bool DoPlanExplainsStop(Event *event_ptr) override;
@@ -38,12 +40,13 @@ class ThreadPlanStepInstruction : public ThreadPlan {
 
 private:
   friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction(
-      bool step_over, bool abort_other_plans, bool stop_other_threads,
-      Status &status);
+      bool step_over, lldb::RunDirection direction, bool abort_other_plans,
+      bool stop_other_threads, Status &status);
 
   lldb::addr_t m_instruction_addr;
   bool m_stop_other_threads;
   bool m_step_over;
+  lldb::RunDirection m_direction;
   // These two are used only for the step over case.
   bool m_start_has_symbol;
   StackID m_stack_id;
diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h
index a6965657f5bc9..db26f53f4056b 100644
--- a/lldb/include/lldb/lldb-private-enumerations.h
+++ b/lldb/include/lldb/lldb-private-enumerations.h
@@ -21,6 +21,7 @@ namespace lldb_private {
 enum StepType {
   eStepTypeNone,
   eStepTypeTrace,     ///< Single step one instruction.
+  eStepTypeTraceBack, ///< Single step back one instruction.
   eStepTypeTraceOver, ///< Single step one instruction, stepping over.
   eStepTypeInto,      ///< Single step into a specified context.
   eStepTypeOver,      ///< Single step over a specified context.
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index 9efc39c70d1a4..2c4bc8795a53b 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -507,7 +507,8 @@ void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) {
           new_plan_status, avoid_no_debug);
     } else {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, stop_other_threads, new_plan_status);
+          true, eRunForward, abort_other_plans, stop_other_threads,
+          new_plan_status);
     }
   }
   error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
@@ -573,7 +574,8 @@ void SBThread::StepInto(const char *target_name, uint32_t end_line,
         step_out_avoids_code_without_debug_info);
   } else {
     new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-        false, abort_other_plans, stop_other_threads, new_plan_status);
+        false, eRunForward, abort_other_plans, stop_other_threads,
+        new_plan_status);
   }
 
   if (new_plan_status.Success())
@@ -694,7 +696,7 @@ void SBThread::StepInstruction(bool step_over, SBError &error) {
   Thread *thread = exe_ctx->GetThreadPtr();
   Status new_plan_status;
   ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction(
-      step_over, false, true, new_plan_status));
+      step_over, eRunForward, false, true, new_plan_status));
 
   if (new_plan_status.Success())
     error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
diff --git a/lldb/source/API/SBThreadPlan.cpp b/lldb/source/API/SBThreadPlan.cpp
index c8ca6c81a3efb..21d834e0674dd 100644
--- a/lldb/source/API/SBThreadPlan.cpp
+++ b/lldb/source/API/SBThreadPlan.cpp
@@ -335,7 +335,7 @@ SBThreadPlan::QueueThreadPlanForStepSingleInstruction(bool step_over,
     Status plan_status;
     SBThreadPlan plan(
         thread_plan_sp->GetThread().QueueThreadPlanForStepSingleInstruction(
-            step_over, false, false, plan_status));
+            step_over, eRunForward, false, false, plan_status));
 
     if (plan_status.Fail())
       error.SetErrorString(plan_status.AsCString());
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index bbf38981aee60..2b882468a380e 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -536,7 +536,8 @@ class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
         }
       } else
         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-            false, abort_other_plans, bool_stop_other_threads, new_plan_status);
+            false, eRunForward, abort_other_plans, bool_stop_other_threads,
+            new_plan_status);
     } else if (m_step_type == eStepTypeOver) {
       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
 
@@ -549,13 +550,20 @@ class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
             m_options.m_step_out_avoid_no_debug);
       else
         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-            true, abort_other_plans, bool_stop_other_threads, new_plan_status);
+            true, eRunForward, abort_other_plans, bool_stop_other_threads,
+            new_plan_status);
     } else if (m_step_type == eStepTypeTrace) {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          false, abort_other_plans, bool_stop_other_threads, new_plan_status);
+          false, eRunForward, abort_other_plans, bool_stop_other_threads,
+          new_plan_status);
+    } else if (m_step_type == eStepTypeTraceBack) {
+      new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
+          false, eRunReverse, abort_other_plans, bool_stop_other_threads,
+          new_plan_status);
     } else if (m_step_type == eStepTypeTraceOver) {
       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, bool_stop_other_threads, new_plan_status);
+          true, eRunForward, abort_other_plans, bool_stop_other_threads,
+          new_plan_status);
     } else if (m_step_type == eStepTypeOut) {
       new_plan_sp = thread->QueueThreadPlanForStepOut(
           abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,
@@ -632,26 +640,6 @@ class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
   OptionGroupOptions m_all_options;
 };
 
-// CommandObjectThreadStepBackInstruction
-
-class CommandObjectThreadStepBackInstruction : public CommandObjectParsed {
-  private:
-public:
-  CommandObjectThreadStepBackInstruction(CommandInterpreter &interpreter)
-      : CommandObjectParsed(interpreter, "process plugin packet step-back",
-                            "Step back one instruction.",
-                            nullptr) {}
-
-  ~CommandObjectThreadStepBackInstruction() override = default;
-
-  void DoExecute(Args &command, CommandReturnObject &result) override {
-    Process *process = m_exe_ctx.GetProcessPtr();
-    if (process) {
-        process->GetThreadList().GetSelectedThread()->StepBack();
-    }
-  }
-};
-
 // CommandObjectThreadContinue
 
 class CommandObjectThreadContinue : public CommandObjectParsed {
@@ -2611,8 +2599,11 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread(
                      nullptr, eStepTypeTrace)));
 
   LoadSubCommand("step-back-inst",
-                 CommandObjectSP(new CommandObjectThreadStepBackInstruction(
-                     interpreter)));
+                 CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
+                     interpreter, "thread step-back-inst",
+                     "Instruction level back step.  "
+                     "Defaults to current thread unless specified.",
+                     nullptr, eStepTypeTraceBack)));
 
   LoadSubCommand("step-inst-over",
                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index afa0ef28a381d..fa11896d749e8 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -1080,8 +1080,8 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread,
     if (!thread_plan_sp && is_branch_island) {
       thread_plan_sp = std::make_shared<ThreadPlanStepInstruction>(
           thread,
-          /* step_over= */ false, /* stop_others */ false, eVoteNoOpinion,
-          eVoteNoOpinion);
+          /* step_over= */ false, eRunForward, /* stop_others */ false,
+          eVoteNoOpinion, eVoteNoOpinion);
       LLDB_LOG(log, "Stepping one instruction over branch island: '{0}'.",
                current_name);
     }
diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
index 79fb4d46eff41..bd735ef884b8f 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
@@ -228,5 +228,5 @@ DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread,
   assert(first_insn->DoesBranch() && !second_insn->DoesBranch());
 
   return ThreadPlanSP(new ThreadPlanStepInstruction(
-      thread, false, false, eVoteNoOpinion, eVoteNoOpinion));
+      thread, false, eRunForward, false, eVoteNoOpinion, eVoteNoOpinion));
 }
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 5110ed16edc91..89c85081733c6 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -788,11 +788,11 @@ class StopInfoWatchpoint : public StopInfo {
   // them and they won't behave correctly.
   class ThreadPlanStepOverWatchpoint : public ThreadPlanStepInstruction {
   public:
-    ThreadPlanStepOverWatchpoint(Thread &thread, 
+    ThreadPlanStepOverWatchpoint(Thread &thread,
                                  StopInfoWatchpointSP stop_info_sp,
                                  WatchpointSP watch_sp)
-        : ThreadPlanStepInstruction(thread, false, true, eVoteNoOpinion,
-                                    eVoteNoOpinion),
+        : ThreadPlanStepInstruction(thread, false, eRunForward, true,
+                                    eVoteNoOpinion, eVoteNoOpinion),
           m_stop_info_sp(stop_info_sp), m_watch_sp(watch_sp) {
       assert(watch_sp);
     }
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 5c5449126343b..3c1b5db81516c 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -372,14 +372,14 @@ lldb::StopInfoSP Thread::GetStopInfo() {
   // from completed plan stack - m_stop_info_sp (trace stop reason is OK now) -
   // ask GetPrivateStopInfo to set stop info
 
-  bool have_valid_stop_info = m_stop_info_sp &&
-      m_stop_info_sp ->IsValid() &&
-      m_stop_info_stop_id == stop_id;
-  bool have_valid_completed_plan = completed_plan_sp && completed_plan_sp->PlanSucceeded();
+  bool have_valid_stop_info = m_stop_info_sp && m_stop_info_sp->IsValid() &&
+                              m_stop_info_stop_id == stop_id;
+  bool have_valid_completed_plan =
+      completed_plan_sp && completed_plan_sp->PlanSucceeded();
   bool plan_failed = completed_plan_sp && !completed_plan_sp->PlanSucceeded();
   bool plan_overrides_trace =
-    have_valid_stop_info && have_valid_completed_plan
-    && (m_stop_info_sp->GetStopReason() == eStopReasonTrace);
+      have_valid_stop_info && have_valid_completed_plan &&
+      (m_stop_info_sp->GetStopReason() == eStopReasonTrace);
 
   if (have_valid_stop_info && !plan_overrides_trace && !plan_failed) {
     return m_stop_info_sp;
@@ -415,8 +415,8 @@ lldb::StopInfoSP Thread::GetPrivateStopInfo(bool calculate) {
       // 4) If this thread wasn't allowed to run the last time round.
       if (m_stop_info_sp) {
         if (m_stop_info_sp->IsValid() || IsStillAtLastBreakpointHit() ||
-            GetCurrentPlan()->IsVirtualStep()
-            || GetTemporaryResumeState() == eStateSuspended)
+            GetCurrentPlan()->IsVirtualStep() ||
+            GetTemporaryResumeState() == eStateSuspended)
           SetStopInfo(m_stop_info_sp);
         else
           m_stop_info_sp.reset();
@@ -1204,7 +1204,7 @@ bool Thread::CompletedPlanOverridesBreakpoint() const {
   return GetPlans().AnyCompletedPlans();
 }
 
-ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) const{
+ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) const {
   return GetPlans().GetPreviousPlan(current_plan);
 }
 
@@ -1294,10 +1294,11 @@ ThreadPlanSP Thread::QueueBasePlan(bool abort_other_plans) {
 }
 
 ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction(
-    bool step_over, bool abort_other_plans, bool stop_other_threads,
-    Status &status) {
+    bool step_over, lldb::RunDirection direction, bool abort_other_plans,
+    bool stop_other_threads, Status &status) {
   ThreadPlanSP thread_plan_sp(new ThreadPlanStepInstruction(
-      *this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion));
+      *this, step_over, direction, stop_other_threads, eVoteNoOpinion,
+      eVoteNoOpinion));
   status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
   return thread_plan_sp;
 }
@@ -2250,7 +2251,7 @@ Status Thread::StepIn(bool source_step,
           step_out_avoids_code_without_debug_info);
     } else {
       new_plan_sp = QueueThreadPlanForStepSingleInstruction(
-          false, abort_other_plans, run_mode, error);
+          false, eRunForward, abort_other_plans, run_mode, error);
     }
 
     new_plan_sp->SetIsControllingPlan(true);
@@ -2283,7 +2284,7 @@ Status Thread::StepOver(bool source_step,
           step_out_avoids_code_without_debug_info);
     } else {
       new_plan_sp = QueueThreadPlanForStepSingleInstruction(
-          true, abort_other_plans, run_mode, error);
+          true, eRunForward, abort_other_plans, run_mode, error);
     }
 
     new_plan_sp->SetIsControllingPlan(true);
@@ -2322,22 +2323,6 @@ Status Thread::StepOut(uint32_t frame_idx) {
   return error;
 }
 
-#include "lldb/Target/ThreadPlanStepInstruction.h"
-
-class ThreadPlanStepBackInstruction : public ThreadPlanStepInstruction {
-public:
-  ThreadPlanStepBackInstruction(Thread &thread,
-                                                     bool step_over,
-                                                     bool stop_other_threads,
-                                                     Vote report_stop_vote,
-                                                     Vote report_run_vote)
-    : ThreadPlanStepInstruction(thread, step_over, stop_other_threads, report_stop_vote, report_run_vote) {}
-
-  lldb::RunDirection GetDirection() const override {
-    return lldb::RunDirection::eRunReverse;
-  }
-};
-
 Status Thread::StepBack() {
   Process *process = GetProcess().get();
   if (!StateIsStoppedState(process->GetState(), true)) {
@@ -2345,11 +2330,13 @@ Status Thread::StepBack() {
   }
 
   if (!process->SupportsReverseDirection()) {
-    return Status::FromErrorString("process does not support reverse execution");
+    return Status::FromErrorString(
+        "process does not support reverse execution");
   }
-  
-  ThreadPlanSP thread_plan_sp(new ThreadPlanStepBackInstruction(
-      *this, false, true, eVoteNoOpinion, eVoteNoOpinion));
+
+  Status error;
+  ThreadPlanSP thread_plan_sp(QueueThreadPlanForStepSingleInstruction(
+      false, eRunReverse, false, true, error));
   QueueThreadPlan(thread_plan_sp, false);
 
   thread_plan_sp->SetIsControllingPlan(true);
@@ -2415,7 +2402,9 @@ lldb::ValueObjectSP Thread::GetSiginfoValue() {
     return ValueObjectConstResult::Create(&target,
                                           Status::FromError(data.takeError()));
 
-  DataExtractor data_extractor{data.get()->getBufferStart(), data.get()->getBufferSize(),
-    process_sp->GetByteOrder(), arch.GetAddressByteSize()};
-  return ValueObjectConstResult::Create(&target, type, ConstString("__lldb_siginfo"), data_extractor);
+  DataExtractor data_extractor{
+      data.get()->getBufferStart(), data.get()->getBufferSize(),
+      process_sp->GetByteOrder(), arch.GetAddressByteSize()};
+  return ValueObjectConstResult::Create(
+      &target, type, ConstString("__lldb_siginfo"), data_extractor);
 }
diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp
index e9db3171a5bef..ace663f59841a 100644
--- a/lldb/source/Target/ThreadPlanStepInstruction.cpp
+++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp
@@ -20,16 +20,14 @@ using namespace lldb_private;
 
 // ThreadPlanStepInstruction: Step over the current instruction
 
-ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread,
-                                                     bool step_over,
-                                                     bool stop_other_threads,
-                                                     Vote report_stop_vote,
-                                                     Vote report_run_vote)
+ThreadPlanStepInstruction::ThreadPlanStepInstruction(
+    Thread &thread, bool step_over, lldb::RunDirection direction,
+    bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote)
     : ThreadPlan(ThreadPlan::eKindStepInstruction,
                  "Step over single instruction", thread, report_stop_vote,
                  report_run_vote),
       m_instruction_addr(0), m_stop_other_threads(stop_other_threads),
-      m_step_over(step_over) {
+      m_step_over(step_over), m_direction(direction) {
   m_takes_iteration_count = true;
   SetUpState();
 }
@@ -246,3 +244,7 @@ bool ThreadPlanStepInstruction::MischiefManaged() {
     return false;
   }
 }
+
+lldb::RunDirection ThreadPlanStepInstruction::GetDirection() const {
+  return m_direction;
+}



More information about the lldb-commits mailing list