[Lldb-commits] [lldb] r332922 - Work around some odd instruction single-step behavior on macOS.

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Tue May 22 02:41:51 PDT 2018


This probably isn't what was happening here because you would have seen the
extra stops in the logs, but one way I can think of we can end up at the
same PC is if the process gets a signal while we're about to single-step
it, in which case we need to execute the signal handler first and then get
back to the instruction we were about to step over.

Anyway, the reason I am writing this is the testing situation. I think we
already have something that should be able to mock a process to a
sufficient level to test behavior like this: MockGdbServer in
testcases/functionalities/gdb_remote_client. So, I believe it should be
possible to trigger this via a sequence like:
- connect to mock server (server pretends to be stopped at PC 0x1000)
- breakpoint set --address 0x1010
- continue (server pretends to stop at 0x1010)
- continue (after the first $s packet, server stays at 0x1010, after the
second one it advances to 0x1011, after the final $c, return W00)
- verify the expected packets were sent

Have you tried using MockGdbServer in this way?

regards,
pl

On Tue, 22 May 2018 at 01:10, Jim Ingham via lldb-commits <
lldb-commits at lists.llvm.org> wrote:

> Author: jingham
> Date: Mon May 21 17:06:55 2018
> New Revision: 332922

> URL: http://llvm.org/viewvc/llvm-project?rev=332922&view=rev
> Log:
> Work around some odd instruction single-step behavior on macOS.

> We've seen some cases on macOS where you go to instruction single
> step (over a breakpoint), and single step returns but the instruction
> hasn't been executed (and the pc hasn't moved.)  The
ThreadPlanStepOverBreakpoint
> used to handle this case by accident, but the patches to handle two
adjacent
> breakpoints broke that accident.

> This patch fixes the logic of ExplainsStop to explicitly handle the case
where
> the pc didn't move.  It also adds a WillPop that re-enables the
breakpoint we
> were stepping over.  We never want an unexpected path through the plan to
> fool us into not doing that.

> I have no idea how to make this bug happen.  It is very inconsistent when
it
> occurs IRL.  We really need a full MockProcess Plugin before we can start
to write
> tests for this sort of system hiccup.

> <rdar://problem/38505726>

> Modified:
>      lldb/trunk/include/lldb/Target/ThreadPlanStepOverBreakpoint.h
>      lldb/trunk/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme
>      lldb/trunk/source/Target/ThreadPlanStepOverBreakpoint.cpp

> Modified: lldb/trunk/include/lldb/Target/ThreadPlanStepOverBreakpoint.h
> URL:
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanStepOverBreakpoint.h?rev=332922&r1=332921&r2=332922&view=diff

==============================================================================
> --- lldb/trunk/include/lldb/Target/ThreadPlanStepOverBreakpoint.h
(original)
> +++ lldb/trunk/include/lldb/Target/ThreadPlanStepOverBreakpoint.h Mon May
21 17:06:55 2018
> @@ -31,6 +31,7 @@ public:
>     bool StopOthers() override;
>     lldb::StateType GetPlanRunState() override;
>     bool WillStop() override;
> +  void WillPop() override;
>     bool MischiefManaged() override;
>     void ThreadDestroyed() override;
>     void SetAutoContinue(bool do_it);

> Modified:
lldb/trunk/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme
> URL:
http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme?rev=332922&r1=332921&r2=332922&view=diff

==============================================================================
> --- lldb/trunk/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme
(original)
> +++ lldb/trunk/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme Mon
May 21 17:06:55 2018
> @@ -26,10 +26,18 @@
>         buildConfiguration = "Debug"
>         selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
>         selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
> -      language = ""
>         shouldUseLaunchSchemeArgsEnv = "YES">
>         <Testables>
>         </Testables>
> +      <MacroExpansion>
> +         <BuildableReference
> +            BuildableIdentifier = "primary"
> +            BlueprintIdentifier = "26F5C26910F3D9A4009D5894"
> +            BuildableName = "lldb"
> +            BlueprintName = "lldb-tool"
> +            ReferencedContainer = "container:lldb.xcodeproj">
> +         </BuildableReference>
> +      </MacroExpansion>
>         <AdditionalOptions>
>         </AdditionalOptions>
>      </TestAction>
> @@ -37,22 +45,22 @@
>         buildConfiguration = "DebugClang"
>         selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
>         selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
> -      language = ""
> -      launchStyle = "0"
> +      launchStyle = "1"
>         useCustomWorkingDirectory = "NO"
>         ignoresPersistentStateOnLaunch = "NO"
>         debugDocumentVersioning = "YES"
>         debugServiceExtension = "internal"
>         allowLocationSimulation = "YES">
> -      <MacroExpansion>
> +      <BuildableProductRunnable
> +         runnableDebuggingMode = "0">
>            <BuildableReference
>               BuildableIdentifier = "primary"
> -            BlueprintIdentifier = "26CEF3B114FD592B007286B2"
> -            BuildableName = "desktop"
> -            BlueprintName = "desktop"
> +            BlueprintIdentifier = "26F5C26910F3D9A4009D5894"
> +            BuildableName = "lldb"
> +            BlueprintName = "lldb-tool"
>               ReferencedContainer = "container:lldb.xcodeproj">
>            </BuildableReference>
> -      </MacroExpansion>
> +      </BuildableProductRunnable>
>         <AdditionalOptions>
>         </AdditionalOptions>
>      </LaunchAction>

> Modified: lldb/trunk/source/Target/ThreadPlanStepOverBreakpoint.cpp
> URL:
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepOverBreakpoint.cpp?rev=332922&r1=332921&r2=332922&view=diff

==============================================================================
> --- lldb/trunk/source/Target/ThreadPlanStepOverBreakpoint.cpp (original)
> +++ lldb/trunk/source/Target/ThreadPlanStepOverBreakpoint.cpp Mon May 21
17:06:55 2018
> @@ -68,27 +68,47 @@ bool ThreadPlanStepOverBreakpoint::DoPla
>       // next instruction also contained a breakpoint.
>       StopReason reason = stop_info_sp->GetStopReason();

> +    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
> +
> +    if (log)
> +      log->Printf("Step over breakpoint stopped for reason: %s.",
> +          Thread::StopReasonAsCString(reason));
> +
>       switch (reason) {
> -    case eStopReasonTrace:
> -    case eStopReasonNone:
> -      return true;
> -    case eStopReasonBreakpoint:
> -      // It's a little surprising that we stop here for a breakpoint hit.
> -      // However, when you single step ONTO a breakpoint we still want
to call
> -      // that a breakpoint hit, and trigger the actions, etc.  Otherwise
you
> -      // would see the PC at the breakpoint without having triggered the
> -      // actions, then you'd continue, the PC wouldn't change, and you'd
see
> -      // the breakpoint hit, which would be odd. So the lower levels
fake "step
> -      // onto breakpoint address" and return that as a breakpoint hit.
So our
> -      // trace step COULD appear as a breakpoint hit if the next
instruction
> -      // also contained a breakpoint.  We don't want to handle that,
since we
> -      // really don't know what to do with breakpoint hits.  But make
sure we
> -      // don't set ourselves to auto-continue or we'll wrench control
away from
> -      // the plans that can deal with this.
> -      SetAutoContinue(false);
> -      return false;
> -    default:
> -      return false;
> +      case eStopReasonTrace:
> +      case eStopReasonNone:
> +        return true;
> +      case eStopReasonBreakpoint:
> +      {
> +        // It's a little surprising that we stop here for a breakpoint
hit.
> +        // However, when you single step ONTO a breakpoint we still want
to call
> +        // that a breakpoint hit, and trigger the actions, etc.
Otherwise you
> +        // would see the PC at the breakpoint without having triggered
the
> +        // actions, then you'd continue, the PC wouldn't change, and
you'd see
> +        // the breakpoint hit, which would be odd. So the lower levels
fake
> +        // "step onto breakpoint address" and return that as a
breakpoint hit.
> +        // So our trace step COULD appear as a breakpoint hit if the next
> +        // instruction also contained a breakpoint.  We don't want to
handle
> +        // that, since we really don't know what to do with breakpoint
hits.
> +        // But make sure we don't set ourselves to auto-continue or
we'll wrench
> +        // control away from the plans that can deal with this.
> +        // Be careful, however, as we may have "seen a breakpoint under
the PC
> +        // because we stopped without changing the PC, in which case we
do want
> +        // to re-claim this stop so we'll try again.
> +        lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC();
> +
> +        if (pc_addr == m_breakpoint_addr) {
> +          if (log)
> +            log->Printf("Got breakpoint stop reason but pc: %" PRIu64
> +                        "hasn't changed.", pc_addr);
> +          return true;
> +        }
> +
> +        SetAutoContinue(false);
> +        return false;
> +      }
> +      default:
> +        return false;
>       }
>     }
>     return false;
> @@ -110,8 +130,10 @@ bool ThreadPlanStepOverBreakpoint::DoWil
>       BreakpointSiteSP bp_site_sp(
>           m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress(
>               m_breakpoint_addr));
> -    if (bp_site_sp && bp_site_sp->IsEnabled())
> +    if (bp_site_sp && bp_site_sp->IsEnabled()) {
>         m_thread.GetProcess()->DisableBreakpointSite(bp_site_sp.get());
> +      m_reenabled_breakpoint_site = false;
> +    }
>     }
>     return true;
>   }
> @@ -121,6 +143,10 @@ bool ThreadPlanStepOverBreakpoint::WillS
>     return true;
>   }

> +void ThreadPlanStepOverBreakpoint::WillPop() {
> +  ReenableBreakpointSite();
> +}
> +
>   bool ThreadPlanStepOverBreakpoint::MischiefManaged() {
>     lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC();



> _______________________________________________
> lldb-commits mailing list
> lldb-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


More information about the lldb-commits mailing list