kpdev42 created this revision.
kpdev42 added reviewers: DavidSpickett, clayborg, k8stone, davide.
kpdev42 added a project: LLDB.
Herald added subscribers: JDevlieghere, s.egerton, dmgreen, simoncook, emaste.
Herald added a project: All.
kpdev42 requested review of this revision.
Herald added subscribers: lldb-commits, pcwang-thead.

Before this patch, stepping off a breakpoint in lldb might end up inside a 
signal handler if a signal was received, which would result in continuing and 
hitting the same breakpoint again, while on the surface no instruction was 
executed and the user is not interested in that specific signal or its 
handling. This patch uses the machinery set up for software single-stepping to 
circumvent this behavior. This changes what a eStateStepping in lldb-server 
does to a thread on linux platforms: if a single-step is requested right after 
an ignored (pass=true, stop=false, notify=false) signal is received by the 
inferior, then a breakpoint is installed on the current pc, and the thread is 
continued (not single-stepped). When that breakpoint hits (presumably after the 
user signal handler returns or immediately after the continue, if the handler 
is not installed), it is removed, the stop is ignored and the thread is 
continued with single-stepping again. If a stop occurs inside the handler, then 
the stepping ends there, and the breakpoint is removed as well.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D144392

Files:
  lldb/include/lldb/Host/common/NativeProcessProtocol.h
  lldb/source/Host/common/NativeProcessProtocol.cpp
  lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
  lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
  lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
  lldb/source/Plugins/Process/Utility/CMakeLists.txt
  lldb/source/Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.cpp
  lldb/source/Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.h
  lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
  lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h
  lldb/test/API/functionalities/thread/signal_during_breakpoint_step/Makefile
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/SignalDuringBreakpointStepTestCase.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepIn.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepOut.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepOver.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepUntil.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepOut.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepOver.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepUntil.py
  
lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalStepOverHandler.py
  lldb/test/API/functionalities/thread/signal_during_breakpoint_step/main.cpp

Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/main.cpp
@@ -0,0 +1,166 @@
+// This test is intended to create a situation in which signals are received by
+// a thread while it is stepping off a breakpoint. The intended behavior is to
+// skip the handler and to not stop at the breakpoint we are trying to step off
+// the second time, as the corresponding instruction was not executed anyway.
+// If a breakpoint is hit inside the handler, the breakpoint on the line with
+// the original instruction should be hit when the handler is finished.
+//
+// This checks stepping off breakpoints set on single instructions and function
+// calls as well, to see a potential pc change when single-stepping.
+
+#include "pseudo_barrier.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <thread>
+#include <chrono>
+
+pseudo_barrier_t g_barrier;
+std::atomic<bool> g_send_signals;
+int g_action = 0;
+int g_signal_count = 0;
+int g_cur_iter = 0;
+
+// number of times to repeat the action
+int NUM_ITERS = 0;
+// number of times to send a signal per action
+int NUM_SIGNAL_ITERS = 0;
+// number of microseconds to wait between new action checks
+int SIGNAL_ITER_BACKOFF_US = 0;
+// number of microseconds to wait before sending another signal
+int SIGNAL_SIGNAL_ITER_BACKOFF_US = 0;
+// number of microseconds to wait inside the signal handler
+int HANDLER_SLEEP_US = 0;
+
+using action_t = void (*)();
+
+void do_action_func(action_t action) {
+  // Wait until all threads are running
+  pseudo_barrier_wait(g_barrier);
+
+  // Do the action
+  for (g_cur_iter = 0; g_cur_iter < NUM_ITERS; g_cur_iter++) {
+    g_send_signals.store(true);
+    action();
+  }
+}
+
+void step_in_helper() {
+  g_action++; // step-in-func line
+}
+
+void step_in_func() {
+  step_in_helper(); // step-in-func breakpoint
+}
+
+void do_something() { g_action++; } // do something breakpoint
+
+void step_over_func() {
+  do_something(); // step-over-func breakpoint
+  g_action++;     // step-over-func line
+}
+
+void step_over() {
+  g_action++; // step-over breakpoint
+  g_action++; // step-over line
+}
+
+void step_out_func_helper() {
+  do_something(); // step-out-func breakpoint
+}
+
+void step_out_helper() {
+  g_action++; // step-out breakpoint
+}
+
+void step_out_func() {
+  step_out_func_helper();
+  g_action++; // step-out-func line
+}
+
+void step_out() {
+  step_out_helper();
+  g_action++; // step-out line
+}
+
+void step_until() {
+  g_action++; // step-until breakpoint
+  g_action++; // step-until line
+}
+
+void step_until_func() {
+  do_something(); // step-until-func breakpoint
+  g_action++;     // step-until-func line
+}
+
+void signal_handler(int sig) {
+  if (HANDLER_SLEEP_US > 0)
+    usleep(HANDLER_SLEEP_US);
+  if (sig == SIGRTMIN)
+    g_signal_count += 1; // Break here in signal handler
+}
+
+/// Register a simple function to handle signal
+void register_signal_handler(int signal, sighandler_t handler, int sa_flags = 0) {
+  sigset_t empty_sigset;
+  sigemptyset(&empty_sigset);
+
+  struct sigaction action;
+  action.sa_sigaction = 0;
+  action.sa_mask = empty_sigset;
+  action.sa_flags = sa_flags;
+  action.sa_handler = handler;
+  sigaction(signal, &action, 0);
+}
+
+int dotest() {
+  action_t actions[] = {
+    step_in_func,
+    step_over,
+    step_over_func,
+    step_out,
+    step_out_func,
+    step_until,
+    step_until_func
+  };
+
+  int action_idx = 0;
+  bool should_ignore_signal = false;
+  bool should_nomask = false;
+
+  // Don't let either thread do anything until they're both ready.
+  pseudo_barrier_init(g_barrier, 2); // Break here and adjust
+                                     // NUM_ITERS, action_idx, and sa_flags
+
+  register_signal_handler(SIGRTMIN, should_ignore_signal ? SIG_IGN : signal_handler,
+                          should_nomask ? SA_NODEFER : 0);
+
+  pthread_t pid = pthread_self();
+  std::thread signaller([pid]() {
+    // Wait until all threads are running
+    pseudo_barrier_wait(g_barrier);
+
+    // Send user-defined signals to the current thread
+    for (int i = 0; i < NUM_ITERS; i++) {
+      // Wait until the next action iteration cycle
+      while (!g_send_signals.exchange(false))
+        std::this_thread::sleep_for(std::chrono::microseconds(SIGNAL_ITER_BACKOFF_US));
+
+      // Send some signals
+      for (int i = 0; i < NUM_SIGNAL_ITERS; i++) {
+        pthread_kill(pid, SIGRTMIN);
+        std::this_thread::sleep_for(
+            std::chrono::microseconds(SIGNAL_SIGNAL_ITER_BACKOFF_US));
+      }
+    }
+  });
+
+  do_action_func(actions[action_idx]);
+  return 0; // Break here to not fall out
+}
+
+int main() {
+  return dotest();
+}
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalStepOverHandler.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalStepOverHandler.py
@@ -0,0 +1,66 @@
+"""
+This test is intended to create a situation in which signals are received by
+a thread while it is stepping off a breakpoint. Breakpoints inside the handler
+should still be hit. If a handler is not set at all, nothing should break.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class TestSignalStepOverHandler(SignalDuringBreakpointStepTestCase):
+
+    num_iters = 10
+    num_signal_iters = 5
+    action = 'step-until-func'
+
+    def set_up_step_over_handler_with_breakpoint(self):
+        self.handler_bp = self.target.BreakpointCreateBySourceRegex(
+            'Break here in signal handler',
+            self.main_source_spec)
+
+    def check_handler_bp_continue(self, action, is_breakpoint_disabled):
+        # Start at the relevand line with breakpoint, enable the handler breakpoint for this iteration
+        self.handler_bp.SetEnabled(True)
+
+        # Step
+        self.runCmd('thread %s' % self.action2cmd(action))
+
+        handler_cnt = 0
+        self.runCmd('expr g_signal_count = 0')
+        while lldbutil.get_one_thread_stopped_at_breakpoint(self.process, self.handler_bp) == self.thread:
+            # Stopped inside the handler, continue until we are back in our parent function
+            handler_cnt += 1
+            self.runCmd('continue')
+
+        # Now stopped at the corresponding line
+        self.check_stopped_at_action_line(action)
+        self.assertEquals(handler_cnt,
+            self.get_counter_value('g_signal_count'),
+            'Missed some breakpoint hits inside the signal handler')
+        self.handler_bp.SetEnabled(False)
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_breakpoint_inside_handler_continue(self):
+        self.set_up_step_over_handler_with_breakpoint()
+        self.set_up_and_iterate(self.action, True, self.check_handler_bp_continue)
+
+    @skipIf(triple='^mips')
+    def test_recursive_handler(self):
+        # Test that recursive handlers do not influence stepping
+        self.handler_useconds_sleep = 2000
+        self.should_nomask = True
+        self.run_to_breakpoint_and_step(self.action, False)
+
+    @skipIf(triple='^mips')
+    def test_ignored_handler(self):
+        # Test that ignored handlers do not influence stepping
+        self.should_ignore_signal = True
+        self.run_to_breakpoint_and_step(self.action, False)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepUntil.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepUntil.py
@@ -0,0 +1,20 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointStepUntilTestCase(SignalDuringBreakpointStepTestCase):
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_step_until_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-until', False)
+
+    @skipIf(triple='^mips')
+    def test_step_until_no_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-until', True)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepOver.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepOver.py
@@ -0,0 +1,20 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointStepOverTestCase(SignalDuringBreakpointStepTestCase):
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_step_over_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-over', False)
+
+    @skipIf(triple='^mips')
+    def test_step_over_no_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-over', True)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepOut.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointStepOut.py
@@ -0,0 +1,20 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointStepOutTestCase(SignalDuringBreakpointStepTestCase):
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_step_out_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-out', False)
+
+    @skipIf(triple='^mips')
+    def test_step_out_no_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-out', True)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepUntil.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepUntil.py
@@ -0,0 +1,20 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointFuncStepUntilTestCase(SignalDuringBreakpointStepTestCase):
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_step_until_func_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-until-func', False)
+
+    @skipIf(triple='^mips')
+    def test_step_until_func_no_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-until-func', True)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepOver.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepOver.py
@@ -0,0 +1,34 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointFuncStepOverTestCase(SignalDuringBreakpointStepTestCase):
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_step_over_func_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-over-func', False)
+
+    @skipIf(triple='^mips')
+    def test_step_over_func_no_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-over-func', True)
+
+    def check_user_bp(self, action, is_breakpoint_disabled):
+        self.runCmd('thread %s' % self.action2cmd(action))
+        self.check_stopped_at_breakpoint(self.user_bp, 'Expected to not skip the user breakpoint')
+        self.runCmd('continue')
+        self.check_stopped_at_action_line(action)
+
+    @skipIf(triple='^mips')
+    def test_user_breakpoint(self):
+        self.user_bp = self.target.BreakpointCreateBySourceRegex(
+            'do something breakpoint',
+            self.main_source_spec)
+        self.check_breakpoint(self.user_bp)
+        self.set_up_and_iterate('step-over-func', False, self.check_user_bp)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepOut.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepOut.py
@@ -0,0 +1,20 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointFuncStepOutTestCase(SignalDuringBreakpointStepTestCase):
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_step_out_func_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-out-func', False)
+
+    @skipIf(triple='^mips')
+    def test_step_out_func_no_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-out-func', True)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepIn.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/TestSignalDuringBreakpointFuncStepIn.py
@@ -0,0 +1,20 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+from SignalDuringBreakpointStepTestCase import SignalDuringBreakpointStepTestCase
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointFuncStepInTestCase(SignalDuringBreakpointStepTestCase):
+
+    # Atomic sequences are not supported yet for MIPS in LLDB.
+    # (Copied from concurrent_events/TestConcurrentSignalBreak.py)
+    @skipIf(triple='^mips')
+    def test_step_in_func_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-in-func', False)
+
+    @skipIf(triple='^mips')
+    def test_step_in_func_no_breakpoint(self):
+        self.run_to_breakpoint_and_step('step-in-func', True)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/SignalDuringBreakpointStepTestCase.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/SignalDuringBreakpointStepTestCase.py
@@ -0,0 +1,175 @@
+"""
+This test is intended to create a situation in which signals are received by
+a thread while it is stepping off a breakpoint. The intended behavior is to
+skip the handler and to not stop at the breakpoint we are trying to step off
+the second time, as the corresponding instruction was not executed anyway.
+If a breakpoint is hit inside the handler, the breakpoint on the line with
+the original instruction should be hit when the handler is finished.
+
+This checks stepping off breakpoints set on single instructions and function
+calls as well, to see a potential pc change when single-stepping.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+# Needs os-specific implementation
+@skipUnlessPlatform(["linux"])
+class SignalDuringBreakpointStepTestCase(TestBase):
+
+    actions = [
+        'step-in-func',
+        'step-over',
+        'step-over-func',
+        'step-out',
+        'step-out-func',
+        'step-until',
+        'step-until-func'
+    ]
+
+    should_ignore_signal = False
+    num_iters = 100
+    num_signal_iters = 20
+    signal_iter_backoff_us = 1000
+    signal_signal_iter_backoff_us = 1000
+    handler_sleep_us = 0
+    should_nomask = False
+    cur_iter = 0
+
+    def action2cmd(self, action):
+        res = action
+        if res.endswith('-func'):
+            res = res[:-5]
+        if res == 'step-until':
+            res = 'until %s' % self.lines[action]
+        return res
+
+    def check_breakpoint(self, bp):
+        self.assertTrue(bp and bp.GetNumLocations() == 1, VALID_BREAKPOINT)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line numbers and set the breakpoints
+        self.main_source = 'main.cpp'
+        self.main_source_spec = lldb.SBFileSpec(self.main_source)
+
+        self.build()
+        (self.target, self.process, self.thread, _) = \
+            lldbutil.run_to_source_breakpoint(self,
+                'Break here and adjust', self.main_source_spec)
+
+        self.breakpoints = {}
+        self.lines = {}
+        for action in self.actions:
+            bp = self.target.BreakpointCreateBySourceRegex(
+                '%s breakpoint' % action,
+                self.main_source_spec)
+            self.check_breakpoint(bp)
+            self.breakpoints[action] = bp
+            self.lines[action] = line_number(self.main_source, '%s line' % action)
+        self.fall_out_breakpoint = self.target.BreakpointCreateBySourceRegex(
+            'Break here to not fall out',
+            self.main_source_spec)
+        self.check_breakpoint(self.fall_out_breakpoint)
+
+    def get_thread_stopped_at(self):
+        frame = self.thread.GetFrameAtIndex(0)
+        desc = lldbutil.get_description(frame.GetLineEntry())
+        return '(stopped at %s for iteration %d)' % (desc, self.cur_iter)
+
+    def get_counter_value(self, var_name):
+        return self.thread.GetSelectedFrame().EvaluateExpression(var_name).GetValueAsSigned()
+
+    def check_iteration(self):
+        cur_iter = self.get_counter_value('g_cur_iter')
+        skipped = cur_iter > self.cur_iter
+        self.assertEquals(self.cur_iter, cur_iter,
+            'Expected action iteration %d to %s (was a breakpoint %s?) %s' %
+                (self.cur_iter, 'continue' if skipped else 'end',
+                    'skipped' if skipped else 'hit twice', self.get_thread_stopped_at()))
+
+    def check_stopped_at_breakpoint(self, bp, msg):
+        self.check_iteration()
+        thread1 = lldbutil.get_one_thread_stopped_at_breakpoint(self.process, bp)
+        self.assertEquals(self.thread, thread1,
+            '%s %s.' % (msg, self.get_thread_stopped_at()))
+
+    def check_stopped_at_line(self, line):
+        self.check_iteration()
+        desc = self.get_thread_stopped_at()
+        expect = '%s:%d' % (self.main_source, line)
+        self.assertTrue(expect in desc, 'Expected to stop at %s %s' % (expect, desc))
+        self.assertEquals(self.thread.GetStopReason(), lldb.eStopReasonPlanComplete,
+            'Expected stop reason to be step into/over/out %s.' % desc)
+
+    def check_stopped_at_action_breakpoint(self, action):
+        self.check_stopped_at_breakpoint(self.breakpoints[action],
+            "Didn't stop at breakpoint for %s action" % action)
+
+    def check_stopped_at_action_line(self, action):
+        self.check_stopped_at_line(self.lines[action])
+
+
+    def set_up_for_action(self, action):
+        def to_bool_str(x): return str(x).lower()
+
+        action_idx = self.actions.index(action)
+        self.runCmd('expr action_idx=%d' % action_idx)
+        self.runCmd('expr should_ignore_signal=%s' % to_bool_str(self.should_ignore_signal))
+        self.runCmd('expr NUM_ITERS=%d' % self.num_iters)
+        self.runCmd('expr NUM_SIGNAL_ITERS=%d' % self.num_signal_iters)
+        self.runCmd('expr SIGNAL_ITER_BACKOFF_US=%d' % self.signal_iter_backoff_us)
+        self.runCmd('expr SIGNAL_SIGNAL_ITER_BACKOFF_US=%d' % self.signal_signal_iter_backoff_us)
+        self.runCmd('expr HANDLER_SLEEP_US=%d' % self.handler_sleep_us)
+        self.runCmd('expr should_nomask=%s' % to_bool_str(self.should_nomask))
+
+        self.thread = self.process.GetThreadAtIndex(0)
+
+        # Configure signal settings
+        self.runCmd('process handle SIGRTMIN -p true -s false -n false')
+        # TODO: signal numbering is wrong for linux musl right now (SIGRTMIN=35!=34)
+        # For now just configure multiple rt signals
+        self.runCmd('process handle SIGRTMIN+1 -p true -s false -n false')
+
+        # Continue the inferior so threads are spawned
+        self.runCmd('continue')
+
+    def set_up_and_iterate(self, action, do_disable_breakpoint, checker):
+        # Set up
+        self.set_up_for_action(action)
+
+        # Iterate and check
+        for i in range(self.num_iters):
+            self.cur_iter = i
+            # Check if stopped at the right breakpoint
+            self.check_stopped_at_action_breakpoint(action)
+            # Disable the breakpoint, if needed
+            if do_disable_breakpoint:
+                self.breakpoints[action].SetEnabled(False)
+            # Delegate to custom checker
+            checker(action, do_disable_breakpoint)
+            # Enable the breakpoint, if we disabled it
+            if do_disable_breakpoint:
+                self.breakpoints[action].SetEnabled(True)
+            # Continue
+            self.runCmd('continue')
+
+        # Should be at the last breakpoint before exit
+        self.cur_iter += 1
+        self.check_stopped_at_breakpoint(self.fall_out_breakpoint, 'Expected to stop at the last fall-out breakpoint')
+
+    def check_step_off(self, action, is_breakpoint_disabled):
+        # Step off the breakpoint
+        self.runCmd('thread %s' % self.action2cmd(action))
+
+        # Should be stopped at the corresponding line with 'plan complete' reason
+        self.check_stopped_at_action_line(action)
+
+    def run_to_breakpoint_and_step(self, action, do_disable_breakpoint):
+        self.set_up_and_iterate(action, do_disable_breakpoint, self.check_step_off)
Index: lldb/test/API/functionalities/thread/signal_during_breakpoint_step/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/thread/signal_during_breakpoint_step/Makefile
@@ -0,0 +1,5 @@
+CXX_SOURCES := main.cpp
+
+ENABLE_THREADS := YES
+
+include Makefile.rules
Index: lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h
===================================================================
--- lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===-- NativeProcessSoftwareSingleStep.h -----------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef lldb_NativeProcessSoftwareSingleStep_h
-#define lldb_NativeProcessSoftwareSingleStep_h
-
-#include "lldb/Host/common/NativeProcessProtocol.h"
-#include "lldb/Host/common/NativeThreadProtocol.h"
-
-#include <map>
-
-namespace lldb_private {
-
-class NativeProcessSoftwareSingleStep {
-public:
-  Status SetupSoftwareSingleStepping(NativeThreadProtocol &thread);
-
-protected:
-  // List of thread ids stepping with a breakpoint with the address of
-  // the relevan breakpoint
-  std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
-};
-
-} // namespace lldb_private
-
-#endif // #ifndef lldb_NativeProcessSoftwareSingleStep_h
Index: lldb/source/Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.h
@@ -0,0 +1,47 @@
+//===-- NativeProcessContinueUntilBreakpoint.h ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeProcessContinueUntilBreakpoint_h
+#define lldb_NativeProcessContinueUntilBreakpoint_h
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include <map>
+
+namespace lldb_private {
+
+class NativeProcessContinueUntilBreakpoint {
+public:
+  Status SetupSoftwareSingleStepping(NativeThreadProtocol &thread);
+
+  bool ThreadHasSteppingBreakpoint(const NativeThreadProtocol &thread) const;
+
+protected:
+  // List of thread ids stepping with a breakpoint with the address of
+  // the relevant breakpoint and whether the process should autocontinue
+  // (when skipping a signal handler and returning from it, to try
+  // single-stepping again)
+  struct SteppingBreakpointInfo {
+    lldb::addr_t address;
+    bool autocontinue;
+  };
+  using SteppingBreakpointsTy = std::map<lldb::tid_t, SteppingBreakpointInfo>;
+  SteppingBreakpointsTy m_threads_stepping_with_breakpoint;
+
+  Status SetTemporarySteppingBreakpoint(NativeThreadProtocol &thread,
+                                        lldb::addr_t flags, lldb::addr_t addr,
+                                        bool autocontinue, bool overwrite);
+
+  Status RemoveTemporarySteppingBreakpoint(NativeProcessProtocol &process,
+                                           SteppingBreakpointsTy::iterator at);
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeProcessContinueUntilBreakpoint_h
Index: lldb/source/Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.cpp
+++ lldb/source/Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.cpp
@@ -1,4 +1,4 @@
-//===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===//
+//===-- NativeProcessContinueUntilBreakpoint.cpp --------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,10 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "NativeProcessSoftwareSingleStep.h"
+#include "NativeProcessContinueUntilBreakpoint.h"
 
 #include "lldb/Core/EmulateInstruction.h"
 #include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/RegisterValue.h"
 
 #include <unordered_map>
@@ -17,6 +18,61 @@
 using namespace lldb;
 using namespace lldb_private;
 
+Status NativeProcessContinueUntilBreakpoint::SetTemporarySteppingBreakpoint(
+    NativeThreadProtocol &thread, lldb::addr_t flags, lldb::addr_t addr,
+    bool autocontinue, bool overwrite) {
+  Log *log = GetLog(LLDBLog::Process);
+  Status error;
+
+  tid_t tid = thread.GetID();
+  NativeProcessProtocol &process = thread.GetProcess();
+  const ArchSpec &arch = process.GetArchitecture();
+
+  auto found_bp = m_threads_stepping_with_breakpoint.find(tid);
+  if (found_bp != m_threads_stepping_with_breakpoint.end()) {
+    if (overwrite) {
+      error = RemoveTemporarySteppingBreakpoint(process, found_bp);
+      if (error.Fail())
+        LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", tid, error);
+    } else {
+      return Status();
+    }
+  }
+
+  int size_hint = 0;
+  if (arch.GetMachine() == llvm::Triple::arm) {
+    if (flags & 0x20) {
+      // Thumb mode
+      size_hint = 2;
+    } else {
+      // Arm mode
+      size_hint = 4;
+    }
+  } else if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
+             arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch()) {
+    size_hint = 4;
+  }
+  error = process.SetBreakpoint(addr, size_hint, /*hardware=*/false);
+
+  if (error.Fail())
+    return error;
+
+  m_threads_stepping_with_breakpoint.insert({tid, {addr, autocontinue}});
+  return Status();
+}
+
+Status NativeProcessContinueUntilBreakpoint::RemoveTemporarySteppingBreakpoint(
+    NativeProcessProtocol &process, SteppingBreakpointsTy::iterator at) {
+  addr_t addr = at->second.address;
+  m_threads_stepping_with_breakpoint.erase(at);
+  return process.RemoveBreakpoint(addr, /*hardware=*/false);
+}
+
+bool NativeProcessContinueUntilBreakpoint::ThreadHasSteppingBreakpoint(
+    const NativeThreadProtocol &thread) const {
+  return m_threads_stepping_with_breakpoint.count(thread.GetID()) > 0;
+}
+
 namespace {
 
 struct EmulatorBaton {
@@ -94,7 +150,7 @@
                                                  LLDB_INVALID_ADDRESS);
 }
 
-Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
+Status NativeProcessContinueUntilBreakpoint::SetupSoftwareSingleStepping(
     NativeThreadProtocol &thread) {
   Status error;
   NativeProcessProtocol &process = thread.GetProcess();
@@ -158,28 +214,12 @@
     return Status("Instruction emulation failed unexpectedly.");
   }
 
-  int size_hint = 0;
-  if (arch.GetMachine() == llvm::Triple::arm) {
-    if (next_flags & 0x20) {
-      // Thumb mode
-      size_hint = 2;
-    } else {
-      // Arm mode
-      size_hint = 4;
-    }
-  } else if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
-             arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())
-    size_hint = 4;
-  error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false);
-
+  error = SetTemporarySteppingBreakpoint(thread, next_flags, next_pc,
+                                         /*autocontinue=*/false,
+                                         /*overwrite=*/true);
   // If setting the breakpoint fails because next_pc is out of the address
   // space, ignore it and let the debugee segfault.
-  if (error.GetError() == EIO || error.GetError() == EFAULT) {
+  if (error.GetError() == EIO || error.GetError() == EFAULT)
     return Status();
-  } else if (error.Fail())
-    return error;
-
-  m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
-
-  return Status();
+  return error;
 }
Index: lldb/source/Plugins/Process/Utility/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -9,7 +9,7 @@
   LinuxSignals.cpp
   MemoryTagManagerAArch64MTE.cpp
   MipsLinuxSignals.cpp
-  NativeProcessSoftwareSingleStep.cpp
+  NativeProcessContinueUntilBreakpoint.cpp
   NativeRegisterContextDBReg_arm64.cpp
   NativeRegisterContextDBReg_x86.cpp
   NativeRegisterContextRegisterInfo.cpp
Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -267,13 +267,17 @@
   if (signo != LLDB_INVALID_SIGNAL_NUMBER)
     data = signo;
 
-  // If hardware single-stepping is not supported, we just do a continue. The
-  // breakpoint on the next instruction has been setup in
-  // NativeProcessLinux::Resume.
+  // If hardware single-stepping is not supported or a breakpoint for skipping a
+  // potential signal handler was set up, we just do a continue. The breakpoint
+  // in the right place has been setup in
+  // NativeProcessLinux::Resume[Thread].
+  bool step_continue = GetProcess().IsThreadSingleStepAContinue(*this);
+  Log *log = GetLog(LLDBLog::Thread);
+  LLDB_LOG(log, "NativeThreadLinux stepping with: {0}.",
+           step_continue ? "cont" : "singlestep");
   return NativeProcessLinux::PtraceWrapper(
-      GetProcess().SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP
-                                                   : PTRACE_CONT,
-      m_tid, nullptr, reinterpret_cast<void *>(data));
+      step_continue ? PTRACE_CONT : PTRACE_SINGLESTEP, m_tid, nullptr,
+      reinterpret_cast<void *>(data));
 }
 
 void NativeThreadLinux::SetStoppedBySignal(uint32_t signo,
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -23,7 +23,7 @@
 #include "IntelPTCollector.h"
 #include "NativeThreadLinux.h"
 #include "Plugins/Process/POSIX/NativeProcessELF.h"
-#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
+#include "Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.h"
 
 namespace lldb_private {
 class Status;
@@ -38,7 +38,7 @@
 ///
 /// Changes in the inferior process state are broadcasted.
 class NativeProcessLinux : public NativeProcessELF,
-                           private NativeProcessSoftwareSingleStep {
+                           private NativeProcessContinueUntilBreakpoint {
 public:
   class Factory : public NativeProcessProtocol::Factory {
   public:
@@ -135,6 +135,17 @@
 
   bool SupportHardwareSingleStepping() const;
 
+  /// Returns true if single-stepping should be performed as a continue.
+  /// This is true for software single stepping and skipping signal handlers.
+  /// Right now this is equivalent to:
+  /// - a temporary software breakpoint for stepping is installed for
+  //    this thread
+  /// OR
+  /// - hardware single stepping is not supported (so that if a breakpoint
+  ///   failed to be set, ptrace does not get called with singlestep when it is
+  ///   not supported).
+  bool IsThreadSingleStepAContinue(NativeThreadLinux &thread) const;
+
   /// Writes a siginfo_t structure corresponding to the given thread ID to the
   /// memory region pointed to by \p siginfo.
   Status GetSignalInfo(lldb::tid_t tid, void *siginfo) const;
@@ -176,7 +187,7 @@
 
   void MonitorTrace(NativeThreadLinux &thread);
 
-  void MonitorBreakpoint(NativeThreadLinux &thread);
+  void MonitorBreakpoint(NativeThreadLinux &thread, bool is_hardware);
 
   void MonitorWatchpoint(NativeThreadLinux &thread, uint32_t wp_index);
 
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -646,7 +646,7 @@
                     "breakpoint hits, pid = {0}, error = {1}",
                thread.GetID(), error);
     if (bp_index != LLDB_INVALID_INDEX32) {
-      MonitorBreakpoint(thread);
+      MonitorBreakpoint(thread, true);
       break;
     }
 
@@ -677,7 +677,7 @@
 // NO BREAK
 #endif
   case TRAP_BRKPT:
-    MonitorBreakpoint(thread);
+    MonitorBreakpoint(thread, false);
     break;
 
   case SIGTRAP:
@@ -709,17 +709,45 @@
   StopRunningThreads(thread.GetID());
 }
 
-void NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread) {
+void NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread,
+                                           bool is_hardware) {
   Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
   LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID());
 
-  // Mark the thread as stopped at breakpoint.
-  thread.SetStoppedByBreakpoint();
   FixupBreakpointPCAsNeeded(thread);
 
-  if (m_threads_stepping_with_breakpoint.find(thread.GetID()) !=
-      m_threads_stepping_with_breakpoint.end())
+  addr_t pc = thread.GetRegisterContext().GetPC();
+  auto tmp_bp = m_threads_stepping_with_breakpoint.find(thread.GetID());
+  if (tmp_bp != m_threads_stepping_with_breakpoint.end()) {
+    if (tmp_bp->second.autocontinue) {
+      if (!is_hardware && tmp_bp->second.address == pc &&
+          GetSoftwareBreakpointRefCount(tmp_bp->second.address) == 1) {
+        // Hit a non-user software breakpoint with the set up address
+        // => we were skipping the signal handler while stepping and returned to
+        // the set breakpoint, can safely autocontinue.
+        LLDB_LOG(log,
+                 "ignoring breakpoint to skip the signal handler, pid = {0}",
+                 thread.GetID());
+        // Remove the breakpoint
+        Status error = RemoveTemporarySteppingBreakpoint(*this, tmp_bp);
+        if (error.Fail())
+          LLDB_LOG(log,
+                   "pid = {0} remove signal handler skipping breakpoint: {1}",
+                   thread.GetID(), error);
+        // Autocontinue
+        ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
+        return;
+      }
+      // We stopped at another breakpoint, it takes priority and stops the step.
+      // The found temporary breakpoint with autocontinue will be erased
+      // when all the threads are stopped.
+    }
+    // We were single-stepping, mark it as such.
     thread.SetStoppedByTrace();
+  } else {
+    // Mark the thread as stopped at breakpoint.
+    thread.SetStoppedByBreakpoint();
+  }
 
   StopRunningThreads(thread.GetID());
 }
@@ -889,6 +917,12 @@
   return true;
 }
 
+bool NativeProcessLinux::IsThreadSingleStepAContinue(
+    NativeThreadLinux &thread) const {
+  return !SupportHardwareSingleStepping() ||
+         ThreadHasSteppingBreakpoint(thread);
+}
+
 Status NativeProcessLinux::Resume(const ResumeActionList &resume_actions) {
   Log *log = GetLog(POSIXLog::Process);
   LLDB_LOG(log, "pid {0}", GetID());
@@ -1799,6 +1833,27 @@
     return resume_result;
   }
   case eStateStepping: {
+    if (signo != LLDB_INVALID_SIGNAL_NUMBER &&
+        m_signals_to_ignore.find(signo) != m_signals_to_ignore.end()) {
+      // The signal was ignored, but we might stop in the handler.
+      // Skip it: set up a breakpoint on current pc and wait to hit it,
+      // then try again.
+      auto &rc = thread.GetRegisterContext();
+      Status error;
+
+      // Do not overwrite the breakpoint:
+      // If a single-stepping breakpoint is set, just use that.
+      // If a signal skipping breakpoint is set, that means we are entering
+      // another signal handler, just wait until the first one completely
+      // returns.
+      error = SetTemporarySteppingBreakpoint(thread, rc.GetFlags(), rc.GetPC(),
+                                             /*autocontinue=*/true,
+                                             /*overwrite=*/false);
+      if (error.Fail())
+        LLDB_LOG(log,
+                 "Failed to set a breakpoint to skip the signal handler: {0}.",
+                 error);
+    }
     const auto step_result = thread.SingleStep(signo);
     if (step_result.Success())
       SetState(eStateRunning, true);
@@ -1843,14 +1898,15 @@
   Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
 
   // Clear any temporary breakpoints we used to implement software single
-  // stepping.
-  for (const auto &thread_info : m_threads_stepping_with_breakpoint) {
-    Status error = RemoveBreakpoint(thread_info.second);
+  // stepping and potential signal handler skipping.
+  for (auto thread_info_iter = m_threads_stepping_with_breakpoint.begin();
+       thread_info_iter != m_threads_stepping_with_breakpoint.end();) {
+    auto to_remove = thread_info_iter++;
+    tid_t tid = to_remove->first;
+    Status error = RemoveTemporarySteppingBreakpoint(*this, to_remove);
     if (error.Fail())
-      LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
-               thread_info.first, error);
+      LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", tid, error);
   }
-  m_threads_stepping_with_breakpoint.clear();
 
   // Notify the delegate about the stop
   SetCurrentThreadID(m_pending_notification_tid);
Index: lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h
===================================================================
--- lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h
+++ lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h
@@ -10,7 +10,7 @@
 #define liblldb_NativeProcessFreeBSD_H_
 
 #include "Plugins/Process/POSIX/NativeProcessELF.h"
-#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
+#include "Plugins/Process/Utility/NativeProcessContinueUntilBreakpoint.h"
 
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/ArchSpec.h"
@@ -28,7 +28,7 @@
 ///
 /// Changes in the inferior process state are broadcasted.
 class NativeProcessFreeBSD : public NativeProcessELF,
-                             private NativeProcessSoftwareSingleStep {
+                             private NativeProcessContinueUntilBreakpoint {
 public:
   class Factory : public NativeProcessProtocol::Factory {
   public:
Index: lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
+++ lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
@@ -306,11 +306,11 @@
             m_threads_stepping_with_breakpoint.find(thread->GetID());
         if (thread_info != m_threads_stepping_with_breakpoint.end()) {
           thread->SetStoppedByTrace();
-          Status brkpt_error = RemoveBreakpoint(thread_info->second);
+          Status brkpt_error =
+              RemoveTemporarySteppingBreakpoint(*this, thread_info);
           if (brkpt_error.Fail())
             LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
                      thread_info->first, brkpt_error);
-          m_threads_stepping_with_breakpoint.erase(thread_info);
         } else
           thread->SetStoppedByBreakpoint();
         FixupBreakpointPCAsNeeded(*thread);
Index: lldb/source/Host/common/NativeProcessProtocol.cpp
===================================================================
--- lldb/source/Host/common/NativeProcessProtocol.cpp
+++ lldb/source/Host/common/NativeProcessProtocol.cpp
@@ -419,6 +419,14 @@
   return Status();
 }
 
+uint32_t
+NativeProcessProtocol::GetSoftwareBreakpointRefCount(lldb::addr_t addr) const {
+  auto it = m_software_breakpoints.find(addr);
+  if (it == m_software_breakpoints.end())
+    return 0;
+  return it->second.ref_count;
+}
+
 llvm::Expected<NativeProcessProtocol::SoftwareBreakpoint>
 NativeProcessProtocol::EnableSoftwareBreakpoint(lldb::addr_t addr,
                                                 uint32_t size_hint) {
Index: lldb/include/lldb/Host/common/NativeProcessProtocol.h
===================================================================
--- lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -460,6 +460,7 @@
 
   Status SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint);
   Status RemoveSoftwareBreakpoint(lldb::addr_t addr);
+  uint32_t GetSoftwareBreakpointRefCount(lldb::addr_t addr) const;
 
   virtual llvm::Expected<llvm::ArrayRef<uint8_t>>
   GetSoftwareBreakpointTrapOpcode(size_t size_hint);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to