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

Jim Ingham via lldb-commits lldb-commits at lists.llvm.org
Tue May 22 09:38:48 PDT 2018


BTW, I think it is likely that we are being interrupted, but the bug happens very infrequently and generally goes away when I turn on more than a trivial amount of logging, so it's been hard to prove that yet.

Jim


> On May 22, 2018, at 9:37 AM, Jim Ingham <jingham at apple.com> wrote:
> 
> I haven't played around with this yet.  Can it also provide enough memory to pretend a stack trace?  Most of the thread plan stuff will fall over pretty early if it doesn't have at least a couple of frames?
> 
> Jim
> 
> 
>> On May 22, 2018, at 2:41 AM, Pavel Labath <labath at google.com> wrote:
>> 
>> 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