1 //===-- ThreadPlanStepInRange.cpp -------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Target/ThreadPlanStepInRange.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 
17 #include "lldb/lldb-private-log.h"
18 #include "lldb/Core/Log.h"
19 #include "lldb/Core/Stream.h"
20 #include "lldb/Symbol/Symbol.h"
21 #include "lldb/Symbol/Function.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/RegisterContext.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Target/ThreadPlanStepOut.h"
27 #include "lldb/Target/ThreadPlanStepThrough.h"
28 #include "lldb/Core/RegularExpression.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
34 
35 //----------------------------------------------------------------------
36 // ThreadPlanStepInRange: Step through a stack range, either stepping over or into
37 // based on the value of \a type.
38 //----------------------------------------------------------------------
39 
40 ThreadPlanStepInRange::ThreadPlanStepInRange
41 (
42     Thread &thread,
43     const AddressRange &range,
44     const SymbolContext &addr_context,
45     lldb::RunMode stop_others
46 ) :
47     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
48     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
49     m_step_past_prologue (true)
50 {
51     SetFlagsToDefault ();
52 }
53 
54 ThreadPlanStepInRange::~ThreadPlanStepInRange ()
55 {
56 }
57 
58 void
59 ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
60 {
61     if (level == lldb::eDescriptionLevelBrief)
62         s->Printf("step in");
63     else
64     {
65         s->Printf ("Stepping through range (stepping into functions): ");
66         DumpRanges(s);
67     }
68 }
69 
70 bool
71 ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
72 {
73     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
74     m_no_more_plans = false;
75 
76     if (log)
77     {
78         StreamString s;
79         s.Address (m_thread.GetRegisterContext()->GetPC(),
80                    m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
81         log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
82     }
83 
84     if (IsPlanComplete())
85         return true;
86 
87     ThreadPlan* new_plan = NULL;
88 
89     // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
90     // continuing...
91 
92     bool stop_others;
93     if (m_stop_others != lldb::eAllThreads)
94         stop_others = true;
95     else
96         stop_others = false;
97 
98     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
99 
100     if (frame_order == eFrameCompareOlder)
101     {
102         // If we're in an older frame then we should stop.
103         //
104         // A caveat to this is if we think the frame is older but we're actually in a trampoline.
105         // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
106         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
107         new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
108         if (new_plan == NULL)
109             return true;
110         else if (log)
111         {
112             log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
113         }
114 
115     }
116     else if (frame_order == eFrameCompareEqual && InSymbol())
117     {
118         // If we are not in a place we should step through, we're done.
119         // One tricky bit here is that some stubs don't push a frame, so we have to check
120         // both the case of a frame that is younger, or the same as this frame.
121         // However, if the frame is the same, and we are still in the symbol we started
122         // in, the we don't need to do this.  This first check isn't strictly necessary,
123         // but it is more efficient.
124 
125         // If we're still in the range, keep going, either by running to the next branch breakpoint, or by
126         // stepping.
127         if (InRange())
128         {
129             SetNextBranchBreakpoint();
130             return false;
131         }
132 
133         SetPlanComplete();
134         return true;
135     }
136 
137     // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
138     ClearNextBranchBreakpoint();
139 
140     // We may have set the plan up above in the FrameIsOlder section:
141 
142     if (new_plan == NULL)
143         new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
144 
145     if (log)
146     {
147         if (new_plan != NULL)
148             log->Printf ("Found a step through plan: %s", new_plan->GetName());
149         else
150             log->Printf ("No step through plan found.");
151     }
152 
153     // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
154     // But only do that if we actually have stepped in.
155     if (!new_plan && frame_order == eFrameCompareYounger)
156         new_plan = InvokeShouldStopHereCallback();
157 
158     // If we've stepped in and we are going to stop here, check to see if we were asked to
159     // run past the prologue, and if so do that.
160 
161     if (new_plan == NULL && frame_order == eFrameCompareYounger && m_step_past_prologue)
162     {
163         lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
164         if (curr_frame)
165         {
166             size_t bytes_to_skip = 0;
167             lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
168             Address func_start_address;
169 
170             SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
171 
172             if (sc.function)
173             {
174                 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
175                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
176                     bytes_to_skip = sc.function->GetPrologueByteSize();
177             }
178             else if (sc.symbol)
179             {
180                 func_start_address = sc.symbol->GetAddress();
181                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
182                     bytes_to_skip = sc.symbol->GetPrologueByteSize();
183             }
184 
185             if (bytes_to_skip != 0)
186             {
187                 func_start_address.Slide (bytes_to_skip);
188                 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
189                 if (log)
190                     log->Printf ("Pushing past prologue ");
191 
192                 new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
193             }
194         }
195     }
196 
197      if (new_plan == NULL)
198      {
199         m_no_more_plans = true;
200         SetPlanComplete();
201         return true;
202     }
203     else
204     {
205         m_no_more_plans = false;
206         return false;
207     }
208 }
209 
210 void
211 ThreadPlanStepInRange::SetFlagsToDefault ()
212 {
213     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
214 }
215 
216 void
217 ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
218 {
219     if (m_avoid_regexp_ap.get() == NULL)
220         m_avoid_regexp_ap.reset (new RegularExpression(name));
221 
222     m_avoid_regexp_ap->Compile (name);
223 }
224 
225 void
226 ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
227 {
228     // TODO: Should we test this for sanity?
229     ThreadPlanStepInRange::s_default_flag_values = new_value;
230 }
231 
232 bool
233 ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
234 {
235     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
236 
237     const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
238     if (avoid_regexp_to_use == NULL)
239         avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
240 
241     if (avoid_regexp_to_use != NULL)
242     {
243         SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
244         if (sc.symbol != NULL)
245         {
246             const char *frame_function_name = sc.GetFunctionName().GetCString();
247             if (frame_function_name)
248                return avoid_regexp_to_use->Execute(frame_function_name);
249         }
250     }
251     return false;
252 }
253 
254 ThreadPlan *
255 ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
256 {
257     bool should_step_out = false;
258     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
259     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
260 
261     if (flags.Test(eAvoidNoDebug))
262     {
263         if (!frame->HasDebugInformation())
264         {
265             if (log)
266                 log->Printf ("Stepping out of frame with no debug info");
267 
268             should_step_out = true;
269         }
270     }
271 
272     if (!should_step_out)
273     {
274         if (current_plan->GetKind() == eKindStepInRange)
275         {
276             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
277             should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
278         }
279     }
280 
281     if (should_step_out)
282     {
283         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
284         return current_plan->GetThread().QueueThreadPlanForStepOut (false,
285                                                                     NULL,
286                                                                     true,
287                                                                     current_plan->StopOthers(),
288                                                                     eVoteNo,
289                                                                     eVoteNoOpinion,
290                                                                     0); // Frame index
291     }
292 
293     return NULL;
294 }
295 
296 bool
297 ThreadPlanStepInRange::PlanExplainsStop ()
298 {
299     // We always explain a stop.  Either we've just done a single step, in which
300     // case we'll do our ordinary processing, or we stopped for some
301     // reason that isn't handled by our sub-plans, in which case we want to just stop right
302     // away.
303     // We also set ourselves complete when we stop for this sort of unintended reason, but mark
304     // success as false so we don't end up being the reason for the stop.
305     //
306     // The only variation is that if we are doing "step by running to next branch" in which case
307     // if we hit our branch breakpoint we don't set the plan to complete.
308 
309     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
310     StopInfoSP stop_info_sp = GetPrivateStopReason();
311     if (stop_info_sp)
312     {
313         StopReason reason = stop_info_sp->GetStopReason();
314 
315         switch (reason)
316         {
317         case eStopReasonBreakpoint:
318             if (NextRangeBreakpointExplainsStop(stop_info_sp))
319                 return true;
320         case eStopReasonWatchpoint:
321         case eStopReasonSignal:
322         case eStopReasonException:
323             if (log)
324                 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
325             SetPlanComplete(false);
326             break;
327         default:
328             break;
329         }
330     }
331     return true;
332 }
333