diff options
Diffstat (limited to 'lldb/source/Target/ThreadPlanShouldStopHere.cpp')
| -rw-r--r-- | lldb/source/Target/ThreadPlanShouldStopHere.cpp | 160 | 
1 files changed, 160 insertions, 0 deletions
diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp new file mode 100644 index 0000000000000..9599d8197b07e --- /dev/null +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -0,0 +1,160 @@ +//===-- ThreadPlanShouldStopHere.cpp ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/ThreadPlanShouldStopHere.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; + +// ThreadPlanShouldStopHere constructor +ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) +    : m_callbacks(), m_baton(nullptr), m_owner(owner), +      m_flags(ThreadPlanShouldStopHere::eNone) { +  m_callbacks.should_stop_here_callback = +      ThreadPlanShouldStopHere::DefaultShouldStopHereCallback; +  m_callbacks.step_from_here_callback = +      ThreadPlanShouldStopHere::DefaultStepFromHereCallback; +} + +ThreadPlanShouldStopHere::ThreadPlanShouldStopHere( +    ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, +    void *baton) +    : m_callbacks(), m_baton(), m_owner(owner), +      m_flags(ThreadPlanShouldStopHere::eNone) { +  SetShouldStopHereCallbacks(callbacks, baton); +} + +ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default; + +bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback( +    FrameComparison operation, Status &status) { +  bool should_stop_here = true; +  if (m_callbacks.should_stop_here_callback) { +    should_stop_here = m_callbacks.should_stop_here_callback( +        m_owner, m_flags, operation, status, m_baton); +    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); +    if (log) { +      lldb::addr_t current_addr = +          m_owner->GetThread().GetRegisterContext()->GetPC(0); + +      LLDB_LOGF(log, "ShouldStopHere callback returned %u from 0x%" PRIx64 ".", +                should_stop_here, current_addr); +    } +  } + +  return should_stop_here; +} + +bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( +    ThreadPlan *current_plan, Flags &flags, FrameComparison operation, +    Status &status, void *baton) { +  bool should_stop_here = true; +  StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); +  if (!frame) +    return true; + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + +  if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) || +      (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) || +      (operation == eFrameCompareSameParent && +       flags.Test(eStepInAvoidNoDebug))) { +    if (!frame->HasDebugInformation()) { +      LLDB_LOGF(log, "Stepping out of frame with no debug info"); + +      should_stop_here = false; +    } +  } + +  // Always avoid code with line number 0. +  // FIXME: At present the ShouldStop and the StepFromHere calculate this +  // independently.  If this ever +  // becomes expensive (this one isn't) we can try to have this set a state +  // that the StepFromHere can use. +  if (frame) { +    SymbolContext sc; +    sc = frame->GetSymbolContext(eSymbolContextLineEntry); +    if (sc.line_entry.line == 0) +      should_stop_here = false; +  } + +  return should_stop_here; +} + +ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( +    ThreadPlan *current_plan, Flags &flags, FrameComparison operation, +    Status &status, void *baton) { +  const bool stop_others = false; +  const size_t frame_index = 0; +  ThreadPlanSP return_plan_sp; +  // If we are stepping through code at line number 0, then we need to step +  // over this range.  Otherwise we will step out. +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + +  StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); +  if (!frame) +    return return_plan_sp; +  SymbolContext sc; +  sc = frame->GetSymbolContext(eSymbolContextLineEntry | eSymbolContextSymbol); + +  if (sc.line_entry.line == 0) { +    AddressRange range = sc.line_entry.range; + +    // If the whole function is marked line 0 just step out, that's easier & +    // faster than continuing to step through it. +    bool just_step_out = false; +    if (sc.symbol && sc.symbol->ValueIsAddress()) { +      Address symbol_end = sc.symbol->GetAddress(); +      symbol_end.Slide(sc.symbol->GetByteSize() - 1); +      if (range.ContainsFileAddress(sc.symbol->GetAddress()) && +          range.ContainsFileAddress(symbol_end)) { +        LLDB_LOGF(log, "Stopped in a function with only line 0 lines, just " +                       "stepping out."); +        just_step_out = true; +      } +    } +    if (!just_step_out) { +      LLDB_LOGF(log, "ThreadPlanShouldStopHere::DefaultStepFromHereCallback " +                     "Queueing StepInRange plan to step through line 0 code."); + +      return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange( +          false, range, sc, nullptr, eOnlyDuringStepping, status, +          eLazyBoolCalculate, eLazyBoolNo); +    } +  } + +  if (!return_plan_sp) +    return_plan_sp = +        current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop( +            false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, +            frame_index, status, true); +  return return_plan_sp; +} + +ThreadPlanSP ThreadPlanShouldStopHere::QueueStepOutFromHerePlan( +    lldb_private::Flags &flags, lldb::FrameComparison operation, +    Status &status) { +  ThreadPlanSP return_plan_sp; +  if (m_callbacks.step_from_here_callback) { +    return_plan_sp = m_callbacks.step_from_here_callback( +        m_owner, flags, operation, status, m_baton); +  } +  return return_plan_sp; +} + +lldb::ThreadPlanSP ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut( +    lldb::FrameComparison operation, Status &status) { +  if (!InvokeShouldStopHereCallback(operation, status)) +    return QueueStepOutFromHerePlan(m_flags, operation, status); +  else +    return ThreadPlanSP(); +}  | 
