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::PlanExplainsStop ()
72 {
73     // We always explain a stop.  Either we've just done a single step, in which
74     // case we'll do our ordinary processing, or we stopped for some
75     // reason that isn't handled by our sub-plans, in which case we want to just stop right
76     // away.
77 
78     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
79     StopInfoSP stop_info_sp = GetPrivateStopReason();
80     if (stop_info_sp)
81     {
82         StopReason reason = stop_info_sp->GetStopReason();
83 
84         switch (reason)
85         {
86         case eStopReasonBreakpoint:
87         case eStopReasonWatchpoint:
88         case eStopReasonSignal:
89         case eStopReasonException:
90             if (log)
91                 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
92             SetPlanComplete();
93             break;
94         default:
95             break;
96         }
97     }
98     return true;
99 }
100 
101 bool
102 ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
103 {
104     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
105     m_no_more_plans = false;
106 
107     if (log)
108     {
109         StreamString s;
110         s.Address (m_thread.GetRegisterContext()->GetPC(),
111                    m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
112         log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
113     }
114 
115     if (IsPlanComplete())
116         return true;
117 
118     // If we're still in the range, keep going.
119     if (InRange())
120         return false;
121 
122     ThreadPlan* new_plan = NULL;
123 
124     // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
125     // continuing...
126 
127     bool stop_others;
128     if (m_stop_others != lldb::eAllThreads)
129         stop_others = true;
130     else
131         stop_others = false;
132 
133     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
134 
135     if (frame_order == eFrameCompareOlder)
136     {
137         // If we're in an older frame then we should stop.
138         //
139         // A caveat to this is if we think the frame is older but we're actually in a trampoline.
140         // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
141         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
142         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
143         if (new_plan == NULL)
144             return true;
145         else if (log)
146         {
147             log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
148         }
149 
150     }
151     else if (frame_order != eFrameCompareYounger && InSymbol())
152     {
153         // If we are not in a place we should step through, we're done.
154         // One tricky bit here is that some stubs don't push a frame, so we have to check
155         // both the case of a frame that is younger, or the same as this frame.
156         // However, if the frame is the same, and we are still in the symbol we started
157         // in, the we don't need to do this.  This first check isn't strictly necessary,
158         // but it is more efficient.
159 
160         SetPlanComplete();
161         return true;
162     }
163 
164     // We may have set the plan up above in the FrameIsOlder section:
165 
166     if (new_plan == NULL)
167         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
168 
169     if (log)
170     {
171         if (new_plan != NULL)
172             log->Printf ("Found a step through plan: %s", new_plan->GetName());
173         else
174             log->Printf ("No step through plan found.");
175     }
176 
177     // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
178     // But only do that if we actually have stepped in.
179     if (!new_plan && frame_order == eFrameCompareYounger)
180         new_plan = InvokeShouldStopHereCallback();
181 
182     // If we've stepped in and we are going to stop here, check to see if we were asked to
183     // run past the prologue, and if so do that.
184 
185     if (new_plan == NULL && frame_order == eFrameCompareYounger && m_step_past_prologue)
186     {
187         lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
188         if (curr_frame)
189         {
190             size_t bytes_to_skip = 0;
191             lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
192             Address func_start_address;
193 
194             SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
195 
196             if (sc.function)
197             {
198                 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
199                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
200                     bytes_to_skip = sc.function->GetPrologueByteSize();
201             }
202             else if (sc.symbol)
203             {
204                 func_start_address = sc.symbol->GetAddress();
205                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
206                     bytes_to_skip = sc.symbol->GetPrologueByteSize();
207             }
208 
209             if (bytes_to_skip != 0)
210             {
211                 func_start_address.Slide (bytes_to_skip);
212                 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
213                 if (log)
214                     log->Printf ("Pushing past prologue ");
215 
216                 new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
217             }
218         }
219     }
220 
221      if (new_plan == NULL)
222      {
223         m_no_more_plans = true;
224         SetPlanComplete();
225         return true;
226     }
227     else
228     {
229         m_no_more_plans = false;
230         return false;
231     }
232 }
233 
234 void
235 ThreadPlanStepInRange::SetFlagsToDefault ()
236 {
237     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
238 }
239 
240 void
241 ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
242 {
243     if (m_avoid_regexp_ap.get() == NULL)
244         m_avoid_regexp_ap.reset (new RegularExpression(name));
245 
246     m_avoid_regexp_ap->Compile (name);
247 }
248 
249 void
250 ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
251 {
252     // TODO: Should we test this for sanity?
253     ThreadPlanStepInRange::s_default_flag_values = new_value;
254 }
255 
256 bool
257 ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
258 {
259     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
260 
261     RegularExpression *avoid_regexp_to_use;
262 
263     avoid_regexp_to_use = m_avoid_regexp_ap.get();
264     if (avoid_regexp_to_use == NULL)
265         avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
266 
267     if (avoid_regexp_to_use != NULL)
268     {
269         SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol);
270         if (sc.symbol != NULL)
271         {
272             const char *unnamed_symbol = "<UNKNOWN>";
273             const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol);
274             if (strcmp (sym_name, unnamed_symbol) != 0)
275                return avoid_regexp_to_use->Execute(sym_name);
276         }
277     }
278     return false;
279 }
280 
281 ThreadPlan *
282 ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
283 {
284     bool should_step_out = false;
285     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
286     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
287 
288     if (flags.Test(eAvoidNoDebug))
289     {
290         if (!frame->HasDebugInformation())
291         {
292             if (log)
293                 log->Printf ("Stepping out of frame with no debug info");
294 
295             should_step_out = true;
296         }
297     }
298 
299     if (!should_step_out)
300     {
301         if (current_plan->GetKind() == eKindStepInRange)
302         {
303             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
304             should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
305         }
306     }
307 
308     if (should_step_out)
309     {
310         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
311         return current_plan->GetThread().QueueThreadPlanForStepOut (false,
312                                                                     NULL,
313                                                                     true,
314                                                                     current_plan->StopOthers(),
315                                                                     eVoteNo,
316                                                                     eVoteNoOpinion,
317                                                                     0); // Frame index
318     }
319 
320     return NULL;
321 }
322