diff options
Diffstat (limited to 'lldb')
-rw-r--r-- | lldb/include/lldb/Target/Thread.h | 94 | ||||
-rw-r--r-- | lldb/include/lldb/Target/ThreadPlanShouldStopHere.h | 85 | ||||
-rw-r--r-- | lldb/include/lldb/Target/ThreadPlanStepInRange.h | 39 | ||||
-rw-r--r-- | lldb/include/lldb/Target/ThreadPlanStepOut.h | 27 | ||||
-rw-r--r-- | lldb/include/lldb/Target/ThreadPlanStepOverRange.h | 19 | ||||
-rw-r--r-- | lldb/include/lldb/lldb-private-interfaces.h | 3 | ||||
-rw-r--r-- | lldb/source/API/SBThread.cpp | 14 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectThread.cpp | 38 | ||||
-rw-r--r-- | lldb/source/Core/IOHandler.cpp | 5 | ||||
-rw-r--r-- | lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp | 18 | ||||
-rw-r--r-- | lldb/source/Target/Thread.cpp | 100 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanShouldStopHere.cpp | 108 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanStepInRange.cpp | 121 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanStepInstruction.cpp | 14 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanStepOut.cpp | 179 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanStepOverRange.cpp | 51 | ||||
-rw-r--r-- | lldb/test/make/Makefile.rules | 3 |
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) |