summaryrefslogtreecommitdiffstats
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rw-r--r--lldb/include/lldb/Target/Thread.h94
-rw-r--r--lldb/include/lldb/Target/ThreadPlanShouldStopHere.h85
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepInRange.h39
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepOut.h27
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepOverRange.h19
-rw-r--r--lldb/include/lldb/lldb-private-interfaces.h3
-rw-r--r--lldb/source/API/SBThread.cpp14
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp38
-rw-r--r--lldb/source/Core/IOHandler.cpp5
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp18
-rw-r--r--lldb/source/Target/Thread.cpp100
-rw-r--r--lldb/source/Target/ThreadPlanShouldStopHere.cpp108
-rw-r--r--lldb/source/Target/ThreadPlanStepInRange.cpp121
-rw-r--r--lldb/source/Target/ThreadPlanStepInstruction.cpp14
-rw-r--r--lldb/source/Target/ThreadPlanStepOut.cpp179
-rw-r--r--lldb/source/Target/ThreadPlanStepOverRange.cpp51
-rw-r--r--lldb/test/make/Makefile.rules3
17 files changed, 685 insertions, 233 deletions
diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
index dc627961823..e6bc939477a 100644
--- a/lldb/include/lldb/Target/Thread.h
+++ b/lldb/include/lldb/Target/Thread.h
@@ -49,6 +49,12 @@ public:
bool
GetTraceEnabledState() const;
+
+ bool
+ GetStepInAvoidsNoDebug () const;
+
+ bool
+ GetStepOutAvoidsNoDebug () const;
};
typedef std::shared_ptr<ThreadProperties> ThreadPropertiesSP;
@@ -440,17 +446,22 @@ public:
/// If true and the frame has debug info, then do a source level
/// step in, else do a single instruction step in.
///
- /// @param[in] avoid_code_without_debug_info
+ /// @param[in] step_in_avoids_code_without_debug_info
/// If \a true, then avoid stepping into code that doesn't have
/// debug info, else step into any code regardless of wether it
/// has debug info.
///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If \a true, then if you step out to code with no debug info, keep
+ /// stepping out till you get to code with debug info.
+ ///
/// @return
/// An error that describes anything that went wrong
//------------------------------------------------------------------
virtual Error
StepIn (bool source_step,
- bool avoid_code_without_debug_info);
+ LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Default implementation for stepping over.
@@ -466,7 +477,8 @@ public:
/// An error that describes anything that went wrong
//------------------------------------------------------------------
virtual Error
- StepOver (bool source_step);
+ StepOver (bool source_step,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Default implementation for stepping out.
@@ -592,14 +604,19 @@ public:
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
+ /// If eLazyBoolCalculate, we will consult the default set in the thread.
+ ///
/// @return
/// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual lldb::ThreadPlanSP
QueueThreadPlanForStepOverRange (bool abort_other_plans,
- const AddressRange &range,
- const SymbolContext &addr_context,
- lldb::RunMode stop_other_threads);
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_other_threads,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Queues the plan used to step through an address range, stepping into functions.
@@ -627,19 +644,25 @@ public:
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
- /// @param[in] avoid_code_without_debug_info
- /// If \b true we will step out if we step into code with no debug info.
+ /// @param[in] step_in_avoids_code_without_debug_info
+ /// If eLazyBoolYes we will step out if we step into code with no debug info.
+ /// If eLazyBoolCalculate we will consult the default set in the thread.
+ ///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
+ /// If eLazyBoolCalculate, it will consult the default set in the thread.
///
/// @return
/// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual lldb::ThreadPlanSP
QueueThreadPlanForStepInRange (bool abort_other_plans,
- const AddressRange &range,
- const SymbolContext &addr_context,
- const char *step_in_target,
- lldb::RunMode stop_other_threads,
- bool avoid_code_without_debug_info);
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
+ lldb::RunMode stop_other_threads,
+ LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Queue the plan used to step out of the function at the current PC of
@@ -666,6 +689,10 @@ public:
/// @param[in] run_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
+ /// If eLazyBoolCalculate, it will consult the default set in the thread.
+ ///
/// @return
/// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
@@ -676,7 +703,46 @@ public:
bool stop_other_threads,
Vote stop_vote, // = eVoteYes,
Vote run_vote, // = eVoteNoOpinion);
- uint32_t frame_idx);
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
+
+ //------------------------------------------------------------------
+ /// Queue the plan used to step out of the function at the current PC of
+ /// a thread. This version does not consult the should stop here callback, and should only
+ /// be used by other thread plans when they need to retain control of the step out.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] addr_context
+ /// When dealing with stepping through inlined functions the current PC is not enough information to know
+ /// what "step" means. For instance a series of nested inline functions might start at the same address.
+ // The \a addr_context provides the current symbol context the step
+ /// is supposed to be out of.
+ // FIXME: Currently unused.
+ ///
+ /// @param[in] first_insn
+ /// \b true if this is the first instruction of a function.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @param[in] stop_vote
+ /// @param[in] run_vote
+ /// See standard meanings for the stop & run votes in ThreadPlan.h.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepOutNoShouldStop (bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_other_threads,
+ Vote stop_vote, // = eVoteYes,
+ Vote run_vote, // = eVoteNoOpinion);
+ uint32_t frame_idx);
//------------------------------------------------------------------
/// Gets the plan used to step through the code that steps from a function
diff --git a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
index 62068b78ae4..956a5d5266d 100644
--- a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
+++ b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
@@ -21,8 +21,9 @@ namespace lldb_private {
// This is an interface that ThreadPlans can adopt to allow flexible modifications of the behavior
// when a thread plan comes to a place where it would ordinarily stop. If such modification makes
// sense for your plan, inherit from this class, and when you would be about to stop (in your ShouldStop
-// method), call InvokeShouldStopHereCallback, and if that returns a non-NULL plan, execute that
-// plan instead of stopping.
+// method), call InvokeShouldStopHereCallback, passing in the frame comparision between where the step operation
+// started and where you arrived. If it returns true, then QueueStepOutFromHere will queue the plan
+// to execute instead of stopping.
//
// The classic example of the use of this is ThreadPlanStepInRange not stopping in frames that have
// no debug information.
@@ -34,27 +35,84 @@ namespace lldb_private {
class ThreadPlanShouldStopHere
{
public:
+ struct ThreadPlanShouldStopHereCallbacks
+ {
+ ThreadPlanShouldStopHereCallbacks()
+ {
+ should_stop_here_callback = nullptr;
+ step_from_here_callback = nullptr;
+ }
+
+ ThreadPlanShouldStopHereCallbacks(ThreadPlanShouldStopHereCallback should_stop,
+ ThreadPlanStepFromHereCallback step_from_here)
+ {
+ should_stop_here_callback = should_stop;
+ step_from_here_callback = step_from_here;
+ }
+
+ void
+ Clear()
+ {
+ should_stop_here_callback = nullptr;
+ step_from_here_callback = nullptr;
+ }
+
+ ThreadPlanShouldStopHereCallback should_stop_here_callback;
+ ThreadPlanStepFromHereCallback step_from_here_callback;
+ };
+
enum
{
eNone = 0,
- eAvoidInlines = (1 << 0),
- eAvoidNoDebug = (1 << 1)
+ eAvoidInlines = (1 << 0),
+ eStepInAvoidNoDebug = (1 << 1),
+ eStepOutAvoidNoDebug = (1 << 2)
};
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
+ ThreadPlanShouldStopHere (ThreadPlan *owner);
+
ThreadPlanShouldStopHere (ThreadPlan *owner,
- ThreadPlanShouldStopHereCallback callback = NULL,
+ const ThreadPlanShouldStopHereCallbacks *callbacks,
void *baton = NULL);
virtual
~ThreadPlanShouldStopHere();
-
+
+ // Set the ShouldStopHere callbacks. Pass in null to clear them and have no special behavior (though you
+ // can also call ClearShouldStopHereCallbacks for that purpose. If you pass in a valid pointer, it will
+ // adopt the non-null fields, and any null fields will be set to the default values.
+
void
- SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton);
+ SetShouldStopHereCallbacks (const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton)
+ {
+ if (callbacks)
+ {
+ m_callbacks = *callbacks;
+ if (!m_callbacks.should_stop_here_callback)
+ m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback;
+ if (!m_callbacks.step_from_here_callback)
+ m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback;
+ }
+ else
+ {
+ ClearShouldStopHereCallbacks ();
+ }
+ m_baton = baton;
+ }
+
+ void
+ ClearShouldStopHereCallbacks()
+ {
+ m_callbacks.Clear();
+ }
+ bool
+ InvokeShouldStopHereCallback (lldb::FrameComparison operation);
+
lldb::ThreadPlanSP
- InvokeShouldStopHereCallback ();
+ CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation);
lldb_private::Flags &
GetFlags ()
@@ -69,13 +127,22 @@ public:
}
protected:
+ static bool
+ DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+
+ static lldb::ThreadPlanSP
+ DefaultStepFromHereCallback (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+
+ virtual lldb::ThreadPlanSP
+ QueueStepOutFromHerePlan (Flags &flags, lldb::FrameComparison operation);
+
// Implement this, and call it in the plan's constructor to set the default flags.
virtual void SetFlagsToDefault () = 0;
//------------------------------------------------------------------
// Classes that inherit from ThreadPlanShouldStopHere can see and modify these
//------------------------------------------------------------------
- ThreadPlanShouldStopHereCallback m_callback;
+ ThreadPlanShouldStopHereCallbacks m_callbacks;
void * m_baton;
ThreadPlan *m_owner;
lldb_private::Flags m_flags;
diff --git a/lldb/include/lldb/Target/ThreadPlanStepInRange.h b/lldb/include/lldb/Target/ThreadPlanStepInRange.h
index 2f741f179bd..3a22e97e30d 100644
--- a/lldb/include/lldb/Target/ThreadPlanStepInRange.h
+++ b/lldb/include/lldb/Target/ThreadPlanStepInRange.h
@@ -30,13 +30,17 @@ public:
ThreadPlanStepInRange (Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others);
-
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
+
ThreadPlanStepInRange (Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
const char *step_into_function_name,
- lldb::RunMode stop_others);
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
virtual
~ThreadPlanStepInRange ();
@@ -54,9 +58,6 @@ public:
m_step_into_target.SetCString(target);
}
- static lldb::ThreadPlanSP
- DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton);
-
static void
SetDefaultFlagValue (uint32_t new_value);
@@ -64,13 +65,26 @@ public:
IsVirtualStep();
protected:
+ static bool
+ DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+
virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
virtual bool
DoPlanExplainsStop (Event *event_ptr);
virtual void
- SetFlagsToDefault ();
+ SetFlagsToDefault ()
+ {
+ GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
+ }
+
+ void
+ SetCallbacks()
+ {
+ ThreadPlanShouldStopHere::ThreadPlanShouldStopHereCallbacks callbacks(ThreadPlanStepInRange::DefaultShouldStopHereCallback, nullptr);
+ SetShouldStopHereCallbacks (&callbacks, nullptr);
+ }
bool
FrameMatchesAvoidCriteria ();
@@ -81,20 +95,23 @@ private:
Thread::QueueThreadPlanForStepOverRange (bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others);
+ lldb::RunMode stop_others,
+ LazyBool avoid_code_without_debug_info);
friend lldb::ThreadPlanSP
Thread::QueueThreadPlanForStepInRange (bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
const char *step_in_target,
lldb::RunMode stop_others,
- bool avoid_code_without_debug_info);
-
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
+ void SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
// Need an appropriate marker for the current stack so we can tell step out
// from step in.
- static uint32_t s_default_flag_values;
+ static uint32_t s_default_flag_values; // These are the default flag values for the ThreadPlanStepThrough.
lldb::ThreadPlanSP m_sub_plan_sp; // Keep track of the last plan we were running. If it fails, we should stop.
std::unique_ptr<RegularExpression> m_avoid_regexp_ap;
bool m_step_past_prologue; // FIXME: For now hard-coded to true, we could put a switch in for this if there's
diff --git a/lldb/include/lldb/Target/ThreadPlanStepOut.h b/lldb/include/lldb/Target/ThreadPlanStepOut.h
index 2737978a4ed..8c140dc9d95 100644
--- a/lldb/include/lldb/Target/ThreadPlanStepOut.h
+++ b/lldb/include/lldb/Target/ThreadPlanStepOut.h
@@ -16,10 +16,12 @@
// Project includes
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.h"
namespace lldb_private {
-class ThreadPlanStepOut : public ThreadPlan
+class ThreadPlanStepOut : public ThreadPlan,
+ public ThreadPlanShouldStopHere
{
public:
ThreadPlanStepOut (Thread &thread,
@@ -28,7 +30,8 @@ public:
bool stop_others,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx);
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info);
virtual ~ThreadPlanStepOut ();
@@ -48,21 +51,29 @@ public:
}
protected:
+ virtual void
+ SetFlagsToDefault ()
+ {
+ GetFlags().Set(ThreadPlanStepOut::s_default_flag_values);
+ }
+
virtual bool DoPlanExplainsStop (Event *event_ptr);
virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
bool QueueInlinedStepPlan (bool queue_now);
private:
- SymbolContext *m_step_from_context;
+ static uint32_t s_default_flag_values; // These are the default flag values for the ThreadPlanStepThrough.
+
lldb::addr_t m_step_from_insn;
StackID m_step_out_to_id;
StackID m_immediate_step_from_id;
lldb::break_id_t m_return_bp_id;
lldb::addr_t m_return_addr;
- bool m_first_insn;
bool m_stop_others;
- lldb::ThreadPlanSP m_step_through_inline_plan_sp;
- lldb::ThreadPlanSP m_step_out_plan_sp;
+ lldb::ThreadPlanSP m_step_out_to_inline_plan_sp; // This plan implements step out to the real function containing
+ // an inlined frame so we can then step out of that.
+ lldb::ThreadPlanSP m_step_through_inline_plan_sp; // This plan then steps past the inlined frame(s).
+ lldb::ThreadPlanSP m_step_out_further_plan_sp; // This plan keeps stepping out if ShouldStopHere told us to.
Function *m_immediate_step_from_function;
lldb::ValueObjectSP m_return_valobj_sp;
@@ -73,8 +84,10 @@ private:
bool stop_others,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx);
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info);
+ void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info);
// Need an appropriate marker for the current stack so we can tell step out
// from step in.
diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
index 2cb5288272e..d47c6c9429d 100644
--- a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
+++ b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
@@ -21,14 +21,16 @@
namespace lldb_private {
-class ThreadPlanStepOverRange : public ThreadPlanStepRange
+class ThreadPlanStepOverRange : public ThreadPlanStepRange,
+ ThreadPlanShouldStopHere
{
public:
ThreadPlanStepOverRange (Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others);
+ lldb::RunMode stop_others,
+ LazyBool step_out_avoids_no_debug);
virtual ~ThreadPlanStepOverRange ();
@@ -38,9 +40,20 @@ public:
protected:
virtual bool DoPlanExplainsStop (Event *event_ptr);
virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
-
+
+ virtual void
+ SetFlagsToDefault ()
+ {
+ GetFlags().Set(ThreadPlanStepOverRange::s_default_flag_values);
+ }
+
+
+
private:
+ static uint32_t s_default_flag_values;
+
+ void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info);
bool IsEquivalentContext(const SymbolContext &context);
bool m_first_resume;
diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
index 13b5bb5ad5c..2f05d771555 100644
--- a/lldb/include/lldb/lldb-private-interfaces.h
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -35,7 +35,8 @@ namespace lldb_private
typedef SymbolVendor* (*SymbolVendorCreateInstance) (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm); // Module can be NULL for default system symbol vendor
typedef bool (*BreakpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
typedef bool (*WatchpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id);
- typedef lldb::ThreadPlanSP (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, void *baton);
+ typedef bool (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+ typedef lldb::ThreadPlanSP (*ThreadPlanStepFromHereCallback) (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
typedef UnwindAssembly* (*UnwindAssemblyCreateInstance) (const ArchSpec &arch);
typedef int (*ComparisonFunction)(const void *, const void *);
typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index 66f9df3b13c..29381dff326 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -601,11 +601,13 @@ SBThread::StepOver (lldb::RunMode stop_other_threads)
{
if (frame_sp->HasDebugInformation ())
{
+ const LazyBool avoid_no_debug = eLazyBoolCalculate;
SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
new_plan_sp = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
sc.line_entry.range,
sc,
- stop_other_threads);
+ stop_other_threads,
+ avoid_no_debug);
}
else
{
@@ -650,14 +652,16 @@ SBThread::StepInto (const char *target_name, lldb::RunMode stop_other_threads)
if (frame_sp && frame_sp->HasDebugInformation ())
{
- bool avoid_code_without_debug_info = true;
+ const LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate;
+ const LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate;
SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
new_plan_sp = thread->QueueThreadPlanForStepInRange (abort_other_plans,
sc.line_entry.range,
sc,
target_name,
stop_other_threads,
- avoid_code_without_debug_info);
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
}
else
{
@@ -690,13 +694,15 @@ SBThread::StepOut ()
Thread *thread = exe_ctx.GetThreadPtr();
+ const LazyBool avoid_no_debug = eLazyBoolCalculate;
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut (abort_other_plans,
NULL,
false,
stop_other_threads,
eVoteYes,
eVoteNoOpinion,
- 0));
+ 0,
+ avoid_no_debug));
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 10d661882c9..b693cb37345 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -348,9 +348,26 @@ public:
case 'a':
{
bool success;
- m_avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
+ bool avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
if (!success)
error.SetErrorStringWithFormat("invalid boolean value for option '%c'", short_option);
+ else
+ {
+ m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
+ }
+ }
+ break;
+
+ case 'A':
+ {
+ bool success;
+ bool avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid boolean value for option '%c'", short_option);
+ else
+ {
+ m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
+ }
}
break;
@@ -386,7 +403,8 @@ public:
void
OptionParsingStarting ()
{
- m_avoid_no_debug = true;
+ m_step_in_avoid_no_debug = eLazyBoolCalculate;
+ m_step_out_avoid_no_debug = eLazyBoolCalculate;
m_run_mode = eOnlyDuringStepping;
m_avoid_regexp.clear();
m_step_in_target.clear();
@@ -403,7 +421,8 @@ public:
static OptionDefinition g_option_table[];
// Instance variables to hold the values for command options.
- bool m_avoid_no_debug;
+ LazyBool m_step_in_avoid_no_debug;
+ LazyBool m_step_out_avoid_no_debug;
RunMode m_run_mode;
std::string m_avoid_regexp;
std::string m_step_in_target;
@@ -522,7 +541,9 @@ protected:
frame->GetSymbolContext(eSymbolContextEverything),
m_options.m_step_in_target.c_str(),
stop_other_threads,
- m_options.m_avoid_no_debug);
+ m_options.m_step_in_avoid_no_debug,
+ m_options.m_step_out_avoid_no_debug);
+
if (new_plan_sp && !m_options.m_avoid_regexp.empty())
{
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (new_plan_sp.get());
@@ -541,7 +562,8 @@ protected:
new_plan_sp = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
frame->GetSymbolContext(eSymbolContextEverything),
- stop_other_threads);
+ stop_other_threads,
+ m_options.m_step_out_avoid_no_debug);
else
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true,
abort_other_plans,
@@ -564,7 +586,8 @@ protected:
bool_stop_other_threads,
eVoteYes,
eVoteNoOpinion,
- thread->GetSelectedFrameIndex());
+ thread->GetSelectedFrameIndex(),
+ m_options.m_step_out_avoid_no_debug);
}
else
{
@@ -639,7 +662,8 @@ g_duo_running_mode[] =
OptionDefinition
CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "avoid-no-debug", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether step-in will step over functions with no debug information."},
+{ LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information."},
+{ LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information."},
{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp
index 3bedb713c42..f3113c647e8 100644
--- a/lldb/source/Core/IOHandler.cpp
+++ b/lldb/source/Core/IOHandler.cpp
@@ -4092,7 +4092,7 @@ public:
{
Process *process = exe_ctx.GetProcessPtr();
if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
- exe_ctx.GetThreadRef().StepIn(true, true);
+ exe_ctx.GetThreadRef().StepIn(true);
}
}
return MenuActionResult::Handled;
@@ -5117,8 +5117,7 @@ public:
if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
{
bool source_step = (c == 's');
- bool avoid_code_without_debug_info = true;
- exe_ctx.GetThreadRef().StepIn(source_step, avoid_code_without_debug_info);
+ exe_ctx.GetThreadRef().StepIn(source_step);
}
}
return eKeyHandled;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
index 2b56e2208d6..cdd5b465479 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
@@ -187,14 +187,16 @@ AppleThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr)
log->Printf ("Implementation lookup returned msgForward function: 0x%" PRIx64 ", stopping.", target_addr);
SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything);
- m_run_to_sp.reset(new ThreadPlanStepOut (m_thread,
- &sc,
- true,
- m_stop_others,
- eVoteNoOpinion,
- eVoteNoOpinion,
- 0));
- m_thread.QueueThreadPlan(m_run_to_sp, false);
+ const bool abort_other_plans = false;
+ const bool first_insn = true;
+ const uint32_t frame_idx = 0;
+ m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (abort_other_plans,
+ &sc,
+ first_insn,
+ m_stop_others,
+ eVoteNoOpinion,
+ eVoteNoOpinion,
+ frame_idx);
m_run_to_sp->SetPrivate(true);
return false;
}
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 1550fce86bb..15768b087a2 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -61,6 +61,9 @@ Thread::GetGlobalProperties()
static PropertyDefinition
g_properties[] =
{
+ { "step-in-avoid-nodebug", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, step-in will not stop in functions with no debug information." },
+ { "step-out-avoid-nodebug", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, when step-in/step-out/step-over leave the current frame, they will continue to step out till they come to a function with "
+ "debug information. Passing a frame argument to step-out will override this option." },
{ "step-avoid-regexp", OptionValue::eTypeRegex , true , REG_EXTENDED, "^std::", NULL, "A regular expression defining functions step-in won't stop in." },
{ "step-avoid-libraries", OptionValue::eTypeFileSpecList , true , REG_EXTENDED, NULL, NULL, "A list of libraries that source stepping won't stop in." },
{ "trace-thread", OptionValue::eTypeBoolean, false, false, NULL, NULL, "If true, this thread will single-step and log execution." },
@@ -68,6 +71,8 @@ g_properties[] =
};
enum {
+ ePropertyStepInAvoidsNoDebug,
+ ePropertyStepOutAvoidsNoDebug,
ePropertyStepAvoidRegex,
ePropertyStepAvoidLibraries,
ePropertyEnableThreadTrace
@@ -151,6 +156,21 @@ ThreadProperties::GetTraceEnabledState() const
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
}
+bool
+ThreadProperties::GetStepInAvoidsNoDebug() const
+{
+ const uint32_t idx = ePropertyStepInAvoidsNoDebug;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+ThreadProperties::GetStepOutAvoidsNoDebug() const
+{
+ const uint32_t idx = ePropertyStepOutAvoidsNoDebug;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+
//------------------------------------------------------------------
// Thread Event Data
//------------------------------------------------------------------
@@ -1425,12 +1445,13 @@ Thread::QueueThreadPlanForStepOverRange
bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_other_threads
+ lldb::RunMode stop_other_threads,
+ LazyBool step_out_avoids_code_withoug_debug_info
)
{
ThreadPlanSP thread_plan_sp;
- thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads));
-
+ thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads, step_out_avoids_code_withoug_debug_info));
+
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp;
}
@@ -1443,17 +1464,21 @@ Thread::QueueThreadPlanForStepInRange
const SymbolContext &addr_context,
const char *step_in_target,
lldb::RunMode stop_other_threads,
- bool avoid_code_without_debug_info
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info
)
{
ThreadPlanSP thread_plan_sp;
- ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads);
- if (avoid_code_without_debug_info)
- plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
- else
- plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this,
+ range,
+ addr_context,
+ stop_other_threads,
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
+
if (step_in_target)
plan->SetStepInTarget(step_in_target);
+
thread_plan_sp.reset (plan);
QueueThreadPlan (thread_plan_sp, abort_other_plans);
@@ -1470,7 +1495,8 @@ Thread::QueueThreadPlanForStepOut
bool stop_other_threads,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_withoug_debug_info
)
{
ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this,
@@ -1479,7 +1505,42 @@ Thread::QueueThreadPlanForStepOut
stop_other_threads,
stop_vote,
run_vote,
- frame_idx));
+ frame_idx,
+ step_out_avoids_code_withoug_debug_info));
+
+ if (thread_plan_sp->ValidatePlan(NULL))
+ {
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+ }
+ else
+ {
+ return ThreadPlanSP();
+ }
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepOutNoShouldStop
+(
+ bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_other_threads,
+ Vote stop_vote,
+ Vote run_vote,
+ uint32_t frame_idx
+)
+{
+ ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this,
+ addr_context,
+ first_insn,
+ stop_other_threads,
+ stop_vote,
+ run_vote,
+ frame_idx,
+ eLazyBoolNo);
+ new_plan->ClearShouldStopHereCallbacks();
+ ThreadPlanSP thread_plan_sp(new_plan);
if (thread_plan_sp->ValidatePlan(NULL))
{
@@ -2070,8 +2131,9 @@ Thread::IsStillAtLastBreakpointHit ()
Error
Thread::StepIn (bool source_step,
- bool avoid_code_without_debug_info)
-
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info)
+
{
Error error;
Process *process = GetProcess().get();
@@ -2090,7 +2152,8 @@ Thread::StepIn (bool source_step,
sc,
NULL,
run_mode,
- avoid_code_without_debug_info);
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
}
else
{
@@ -2114,8 +2177,8 @@ Thread::StepIn (bool source_step,
}
Error
-Thread::StepOver (bool source_step)
-
+Thread::StepOver (bool source_step,
+ LazyBool step_out_avoids_code_without_debug_info)
{
Error error;
Process *process = GetProcess().get();
@@ -2133,7 +2196,8 @@ Thread::StepOver (bool source_step)
new_plan_sp = QueueThreadPlanForStepOverRange (abort_other_plans,
sc.line_entry.range,
sc,
- run_mode);
+ run_mode,
+ step_out_avoids_code_without_debug_info);
}
else
{
@@ -2187,4 +2251,4 @@ Thread::StepOut ()
error.SetErrorString("process not stopped");
}
return error;
-} \ No newline at end of file
+}
diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
index 87662345a06..7ef615bcc9f 100644
--- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp
+++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
@@ -23,12 +23,23 @@ using namespace lldb_private;
//----------------------------------------------------------------------
// ThreadPlanShouldStopHere constructor
//----------------------------------------------------------------------
-ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, ThreadPlanShouldStopHereCallback callback, void *baton) :
- m_callback (callback),
- m_baton (baton),
+ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) :
+ m_callbacks (),
+ m_baton (NULL),
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);
}
//----------------------------------------------------------------------
@@ -38,37 +49,86 @@ ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere()
{
}
-void
-ThreadPlanShouldStopHere::SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton)
-{
- m_callback = callback;
- m_baton = baton;
-}
-
-ThreadPlanSP
-ThreadPlanShouldStopHere::InvokeShouldStopHereCallback ()
+bool
+ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation)
{
- if (m_callback)
+ bool should_stop_here = true;
+ if (m_callbacks.should_stop_here_callback)
{
- ThreadPlanSP return_plan_sp(m_callback (m_owner, m_flags, m_baton));
+ should_stop_here = m_callbacks.should_stop_here_callback (m_owner, m_flags, operation, m_baton);
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
{
lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0);
- if (return_plan_sp)
- {
- StreamString s;
- return_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
- log->Printf ("ShouldStopHere callback found a step out plan from 0x%" PRIx64 ": %s.", current_addr, s.GetData());
- }
- else
- {
- log->Printf ("ShouldStopHere callback didn't find a step out plan from: 0x%" PRIx64 ".", current_addr);
- }
+ log->Printf ("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,
+ void *baton)
+{
+ bool should_stop_here = true;
+ StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug))
+ || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)))
+ {
+ if (!frame->HasDebugInformation())
+ {
+ if (log)
+ log->Printf ("Stepping out of frame with no debug info");
+
+ should_stop_here = false;
+ }
+ }
+
+ return should_stop_here;
+}
+
+ThreadPlanSP
+ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan,
+ Flags &flags,
+ FrameComparison operation,
+ void *baton)
+{
+ const bool stop_others = false;
+ const size_t frame_index = 0;
+ ThreadPlanSP return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ frame_index);
return return_plan_sp;
+}
+
+ThreadPlanSP
+ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation)
+{
+ ThreadPlanSP return_plan_sp;
+ if (m_callbacks.step_from_here_callback)
+ {
+ return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton);
}
+ return return_plan_sp;
+
+}
+
+lldb::ThreadPlanSP
+ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation)
+{
+ if (!InvokeShouldStopHereCallback(operation))
+ return QueueStepOutFromHerePlan(m_flags, operation);
else
return ThreadPlanSP();
}
+
diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp
index c4cb9aba1b3..c149c34fbaf 100644
--- a/lldb/source/Target/ThreadPlanStepInRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -31,7 +31,7 @@
using namespace lldb;
using namespace lldb_private;
-uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
+uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
//----------------------------------------------------------------------
// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
@@ -43,14 +43,18 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
- ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ ThreadPlanShouldStopHere (this),
m_step_past_prologue (true),
m_virtual_step (false)
{
+ SetCallbacks();
SetFlagsToDefault ();
+ SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);
}
ThreadPlanStepInRange::ThreadPlanStepInRange
@@ -59,15 +63,19 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
const AddressRange &range,
const SymbolContext &addr_context,
const char *step_into_target,
- lldb::RunMode stop_others
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
- ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ ThreadPlanShouldStopHere (this),
m_step_past_prologue (true),
m_virtual_step (false),
m_step_into_target (step_into_target)
{
+ SetCallbacks();
SetFlagsToDefault ();
+ SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);
}
ThreadPlanStepInRange::~ThreadPlanStepInRange ()
@@ -75,6 +83,48 @@ ThreadPlanStepInRange::~ThreadPlanStepInRange ()
}
void
+ThreadPlanStepInRange::SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info)
+{
+ bool avoid_nodebug = true;
+
+ switch (step_in_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepInAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
+
+ avoid_nodebug = true;
+ switch (step_out_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+}
+
+void
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
@@ -124,7 +174,8 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
{
// If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
// we're done.
- m_sub_plan_sp = InvokeShouldStopHereCallback();
+ // FIXME - This can be both a step in and a step out. Probably should record which in the m_virtual_step.
+ m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);
}
else
{
@@ -148,7 +199,12 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
// in a trampoline we think the frame is older because the trampoline confused the backtracer.
m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
if (!m_sub_plan_sp)
- return true;
+ {
+ // Otherwise check the ShouldStopHere for step out:
+ m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareOlder);
+ if (log)
+ log->Printf ("ShouldStopHere says we should step out of this frame.");
+ }
else if (log)
{
log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
@@ -196,7 +252,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
// If not, give the "should_stop" callback a chance to push a plan to get us out of here.
// But only do that if we actually have stepped in.
if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
- m_sub_plan_sp = InvokeShouldStopHereCallback();
+ m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
// If we've stepped in and we are going to stop here, check to see if we were asked to
// run past the prologue, and if so do that.
@@ -251,12 +307,6 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
}
}
-void
-ThreadPlanStepInRange::SetFlagsToDefault ()
-{
- GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
-}
-
void
ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
{
@@ -344,25 +394,26 @@ ThreadPlanStepInRange::FrameMatchesAvoidCriteria ()
return false;
}
-ThreadPlanSP
-ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
+bool
+ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, FrameComparison operation, void *baton)
{
- bool should_step_out = false;
+ bool should_stop_here = true;
StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (flags.Test(eAvoidNoDebug))
+ if ((operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug))
+ || (operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)))
{
if (!frame->HasDebugInformation())
{
if (log)
log->Printf ("Stepping out of frame with no debug info");
- should_step_out = true;
+ should_stop_here = false;
}
}
- if (current_plan->GetKind() == eKindStepInRange)
+ if (should_stop_here && current_plan->GetKind() == eKindStepInRange && operation == eFrameCompareYounger)
{
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
if (step_in_range_plan->m_step_into_target)
@@ -373,7 +424,7 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
// First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare.
if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())
{
- should_step_out = false;
+ should_stop_here = true;
}
else
{
@@ -381,42 +432,26 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
const char *function_name = sc.GetFunctionName().AsCString();
if (function_name == NULL)
- should_step_out = true;
+ should_stop_here = false;
else if (strstr (function_name, target_name) == NULL)
- should_step_out = true;
+ should_stop_here = false;
}
- if (log && should_step_out)
+ if (log && !should_stop_here)
log->Printf("Stepping out of frame %s which did not match step into target %s.",
sc.GetFunctionName().AsCString(),
step_in_range_plan->m_step_into_target.AsCString());
}
}
- if (!should_step_out)
+ if (should_stop_here)
{
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
// Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria.
- should_step_out = step_in_range_plan->FrameMatchesAvoidCriteria ();
+ should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria ();
}
}
-
- if (should_step_out)
- {
- // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
- // We really should have all plans take the tri-state for "stop others" so we can do the right
- // thing. For now let's be safe and always run others when we are likely to run arbitrary code.
- const bool stop_others = false;
- return current_plan->GetThread().QueueThreadPlanForStepOut (false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0); // Frame index
- }
-
- return ThreadPlanSP();
+ return should_stop_here;
}
bool
diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp
index f644ee88f70..8365d709ca8 100644
--- a/lldb/source/Target/ThreadPlanStepInstruction.cpp
+++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp
@@ -147,13 +147,13 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
// StepInstruction should probably have the tri-state RunMode, but for now it is safer to
// run others.
const bool stop_others = false;
- m_thread.QueueThreadPlanForStepOut(false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0);
+ m_thread.QueueThreadPlanForStepOutNoShouldStop(false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
return false;
}
else
diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp
index c5efb558152..b62f557319a 100644
--- a/lldb/source/Target/ThreadPlanStepOut.cpp
+++ b/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -26,10 +26,13 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanStepOverRange.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
using namespace lldb;
using namespace lldb_private;
+uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
+
//----------------------------------------------------------------------
// ThreadPlanStepOut: Step out of the current frame
//----------------------------------------------------------------------
@@ -41,20 +44,21 @@ ThreadPlanStepOut::ThreadPlanStepOut
bool stop_others,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
- m_step_from_context (context),
+ ThreadPlanShouldStopHere (this),
m_step_from_insn (LLDB_INVALID_ADDRESS),
m_return_bp_id (LLDB_INVALID_BREAK_ID),
m_return_addr (LLDB_INVALID_ADDRESS),
- m_first_insn (first_insn),
m_stop_others (stop_others),
- m_step_through_inline_plan_sp(),
- m_step_out_plan_sp (),
m_immediate_step_from_function(NULL)
{
+ SetFlagsToDefault();
+ SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
+
m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
@@ -77,13 +81,15 @@ ThreadPlanStepOut::ThreadPlanStepOut
{
// First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second
// plan that walks us out of this frame.
- m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread,
+ m_step_out_to_inline_plan_sp.reset (new ThreadPlanStepOut(m_thread,
NULL,
false,
stop_others,
eVoteNoOpinion,
eVoteNoOpinion,
- frame_idx - 1));
+ frame_idx - 1,
+ eLazyBoolNo));
+ static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr);
}
else
{
@@ -123,10 +129,32 @@ ThreadPlanStepOut::ThreadPlanStepOut
}
void
+ThreadPlanStepOut::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)
+{
+ bool avoid_nodebug = true;
+ switch (step_out_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+}
+
+void
ThreadPlanStepOut::DidPush()
{
- if (m_step_out_plan_sp)
- m_thread.QueueThreadPlan(m_step_out_plan_sp, false);
+ if (m_step_out_to_inline_plan_sp)
+ m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
else if (m_step_through_inline_plan_sp)
m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
}
@@ -144,7 +172,7 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
s->Printf ("step out");
else
{
- if (m_step_out_plan_sp)
+ if (m_step_out_to_inline_plan_sp)
s->Printf ("Stepping out to inlined frame so we can walk through it.");
else if (m_step_through_inline_plan_sp)
s->Printf ("Stepping out by stepping through inlined function.");
@@ -159,8 +187,8 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
bool
ThreadPlanStepOut::ValidatePlan (Stream *error)
{
- if (m_step_out_plan_sp)
- return m_step_out_plan_sp->ValidatePlan (error);
+ if (m_step_out_to_inline_plan_sp)
+ return m_step_out_to_inline_plan_sp->ValidatePlan (error);
else if (m_step_through_inline_plan_sp)
return m_step_through_inline_plan_sp->ValidatePlan (error);
else if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
@@ -176,12 +204,18 @@ ThreadPlanStepOut::ValidatePlan (Stream *error)
bool
ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
{
- // If one of our child plans just finished, then we do explain the stop.
- if (m_step_out_plan_sp)
+ // If the step out plan is done, then we just need to step through the inlined frame.
+ if (m_step_out_to_inline_plan_sp)
{
- if (m_step_out_plan_sp->MischiefManaged())
+ if (m_step_out_to_inline_plan_sp->MischiefManaged())
+ return true;
+ else
+ return false;
+ }
+ else if (m_step_through_inline_plan_sp)
+ {
+ if (m_step_through_inline_plan_sp->MischiefManaged())
{
- // If this one is done, then we are all done.
CalculateReturnValue();
SetPlanComplete();
return true;
@@ -189,9 +223,9 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
else
return false;
}
- else if (m_step_through_inline_plan_sp)
+ else if (m_step_out_further_plan_sp)
{
- if (m_step_through_inline_plan_sp->MischiefManaged())
+ if (m_step_out_further_plan_sp->MischiefManaged())
return true;
else
return false;
@@ -234,8 +268,11 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
if (done)
{
- CalculateReturnValue();
- SetPlanComplete();
+ if (InvokeShouldStopHereCallback (eFrameCompareOlder))
+ {
+ CalculateReturnValue();
+ SetPlanComplete();
+ }
}
// If there was only one owner, then we're done. But if we also hit some
@@ -266,61 +303,70 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
bool
ThreadPlanStepOut::ShouldStop (Event *event_ptr)
{
- if (IsPlanComplete())
- return true;
-
- bool done;
-
+ if (IsPlanComplete())
+ return true;
+
+ bool done = false;
+ if (m_step_out_to_inline_plan_sp)
+ {
+ if (m_step_out_to_inline_plan_sp->MischiefManaged())
+ {
+ // Now step through the inlined stack we are in:
+ if (QueueInlinedStepPlan(true))
+ {
+ // If we can't queue a plan to do this, then just call ourselves done.
+ m_step_out_to_inline_plan_sp.reset();
+ SetPlanComplete (false);
+ return true;
+ }
+ else
+ done = true;
+ }
+ else
+ return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr);
+ }
+ else if (m_step_through_inline_plan_sp)
+ {
+ if (m_step_through_inline_plan_sp->MischiefManaged())
+ done = true;
+ else
+ return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
+ }
+ else if (m_step_out_further_plan_sp)
+ {
+ if (m_step_out_further_plan_sp->MischiefManaged())
+ m_step_out_further_plan_sp.reset();
+ else
+ return m_step_out_further_plan_sp->ShouldStop(event_ptr);
+ }
+
+ if (!done)
+ {
StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
if (frame_zero_id < m_step_out_to_id)
done = false;
else
done = true;
-
- if (done)
+ }
+
+ // The normal step out computations think we are done, so all we need to do is consult the ShouldStopHere,
+ // and we are done.
+
+ if (done)
+ {
+ if (InvokeShouldStopHereCallback(eFrameCompareOlder))
{
CalculateReturnValue();
SetPlanComplete();
- return true;
}
else
{
- if (m_step_out_plan_sp)
- {
- if (m_step_out_plan_sp->MischiefManaged())
- {
- // Now step through the inlined stack we are in:
- if (QueueInlinedStepPlan(true))
- {
- return false;
- }
- else
- {
- CalculateReturnValue();
- SetPlanComplete ();
- return true;
- }
- }
- else
- return m_step_out_plan_sp->ShouldStop(event_ptr);
- }
- else if (m_step_through_inline_plan_sp)
- {
- if (m_step_through_inline_plan_sp->MischiefManaged())
- {
- // We don't calculate the return value here because we don't know how to.
- // But in case we had a return value sitting around from our process in
- // getting here, let's clear it out.
- m_return_valobj_sp.reset();
- SetPlanComplete();
- return true;
- }
- else
- return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
- }
- else
- return false;
+ m_step_out_further_plan_sp = QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder);
+ done = false;
}
+ }
+
+ return done;
}
bool
@@ -338,7 +384,7 @@ ThreadPlanStepOut::GetPlanRunState ()
bool
ThreadPlanStepOut::DoWillResume (StateType resume_state, bool current_plan)
{
- if (m_step_out_plan_sp || m_step_through_inline_plan_sp)
+ if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp)
return true;
if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
@@ -427,10 +473,12 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
inlined_block->CalculateSymbolContext(&inlined_sc);
inlined_sc.target_sp = GetTarget().shared_from_this();
RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
+ const LazyBool avoid_no_debug = eLazyBoolNo;
ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
inline_range,
inlined_sc,
- run_mode);
+ run_mode,
+ avoid_no_debug);
step_through_inline_plan_ptr->SetOkayToDiscard(true);
StreamString errors;
if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
@@ -486,4 +534,3 @@ ThreadPlanStepOut::IsPlanStale()
else
return true;
}
-
diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp
index 2d8108bf9b7..0e1498dc923 100644
--- a/lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -31,6 +31,7 @@
using namespace lldb_private;
using namespace lldb;
+uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
//----------------------------------------------------------------------
// ThreadPlanStepOverRange: Step through a stack range, either stepping over or into
@@ -42,11 +43,15 @@ ThreadPlanStepOverRange::ThreadPlanStepOverRange
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others
+ lldb::RunMode stop_others,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others),
+ ThreadPlanShouldStopHere (this),
m_first_resume(true)
{
+ SetFlagsToDefault();
+ SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
}
ThreadPlanStepOverRange::~ThreadPlanStepOverRange ()
@@ -65,6 +70,28 @@ ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level
}
}
+void
+ThreadPlanStepOverRange::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)
+{
+ bool avoid_nodebug = true;
+ switch (step_out_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+}
+
bool
ThreadPlanStepOverRange::IsEquivalentContext(const SymbolContext &context)
{
@@ -146,13 +173,13 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
if (IsEquivalentContext(older_context))
{
- new_plan_sp = m_thread.QueueThreadPlanForStepOut (false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0);
+ new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
break;
}
else
@@ -277,6 +304,13 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
// If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
ClearNextBranchBreakpoint();
+
+ // If we haven't figured out something to do yet, then ask the ShouldStopHere callback:
+ if (!new_plan_sp)
+ {
+ new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order);
+ }
+
if (!new_plan_sp)
m_no_more_plans = true;
else
@@ -390,3 +424,4 @@ ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool curren
return true;
}
+
diff --git a/lldb/test/make/Makefile.rules b/lldb/test/make/Makefile.rules
index e1cb978025e..d3ba3e7b83d 100644
--- a/lldb/test/make/Makefile.rules
+++ b/lldb/test/make/Makefile.rules
@@ -92,6 +92,9 @@ endif
CFLAGS ?= -g -O0
CFLAGS += $(ARCHFLAG)$(ARCH) $(FRAMEWORK_INCLUDES) $(CFLAGS_EXTRAS)
+# Use this one if you want to build one part of the result without debug information:
+CFLAGS_NO_DEBUG = -O0 $(ARCHFLAG)$(ARCH) $(FRAMEWORK_INCLUDES) $(CFLAGS_EXTRAS)
+
CXXFLAGS +=$(CFLAGS)
LD = $(CC)
LDFLAGS ?= $(CFLAGS)
OpenPOWER on IntegriCloud