jasonmolenda wrote: > // 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()) > thread.SetStoppedByTrace(); > > StopRunningThreads(thread.GetID()); > } > ``` > > I think this is the correct thing to do, since lldb is completely unaware of > whether software single stepping is taking place(*) I got lost in all of the > mach exceptions, so it's not clear to me what is the conclusion. Are you > saying that debugserver does not do this (i.e., it reports the stop as a > "breakpoint hit", in the mach exception form)?
Ah, very nice, thanks for finding this. I think this helps to show why this is failing with the new "breakpoints are only 'hit' when they are actually executed'" scheme. If the pc is at a BreakpointSite and we're stopped in the debugger. We do "si", a breakpoint is inserted on the next instruction (pc+4 or 2), this thread and pc+4 is added to `m_threads_stepping_with_breakpoint`. We resume execution. The breakpoint at pc is hit, and the pc value does not advance. This method is only checking that the thread is included in the `m_threads_stepping_with_breakpoint` map, not checking that the pc of the breakpoint we hit is the one we inserted (at pc+4/2). I wonder if this can be fixed by ``` NativeRegisterContextLinux ®_ctx = thread.GetRegisterContext(); if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != m_threads_stepping_with_breakpoint.end() && m_threads_stepping_with_breakpoint.find(thread.GetID())->second == reg_ctx.GetPC()) ``` This wasn't necessary with the previous behavior -- if we stopped at a BreakpointSite, we would declare that we hit the breakpoint, even if we'd just stepped up to the BreakpointSite. But now that you may have stepped up to a BreakpointSite OR you may have executed & hit the breakpoint, we're trusting the gdb-remote stub's response more. I think @DavidSpickett was seeing some looping in the test case, and I could imagine a scenario where the pc is at a BreakpointSite, lldb instruction steps, and we get back an instruction-step stop reason without the pc advancing. We haven't hit the breakpoint yet (as far as lldb knows), so we try again. And again. > Just as a curiosity the linux kernel does allow you do use the hardware > single step capability if debugging a 32 bit application on a 64-bit kernel > (I'm not sure if the debugger process needs to be 64-bit or not). At one > point, I wanted to make use of that, which would make our stepping behavior > more reliable in these situations. However it would also make it harder to > reproduce situations like these, as one would have to find actual 32-bit > hardware... Yeah on an armv8 system that can run AArch32 or AArch64 code, both will have MDSCR_EL1.SS instruction stepping capability. It's only on a genuine armv7 processor where that feature doesn't exist. I don't know how much lldb distinguishes between AArch32 and armv7, but this is one important difference. (lldb AArch64 cores don't support AArch32 any more, so I haven't worked with this combination in years). > (*) The code is probably too casual about this check though, in that it does > not check whether it was the actual single-stepping breakpoint that got hit. > If there was a breakpoint under the current PC, it would report this as > "trace" even though it hasn't actually stepped anything. Could this maybe be > the problem that you ran into with this patch? Ah yes, exactly so, we reached the same conclusion, I didn't read your whole response at first. :) https://github.com/llvm/llvm-project/pull/96260 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits