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 #include "lldb/Core/Log.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Symbol/Symbol.h"
20 #include "lldb/Symbol/Function.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Target/ThreadPlanStepOut.h"
26 #include "lldb/Target/ThreadPlanStepThrough.h"
27 #include "lldb/Core/RegularExpression.h"
28
29 using namespace lldb;
30 using namespace lldb_private;
31
32 uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
33
34 //----------------------------------------------------------------------
35 // ThreadPlanStepInRange: Step through a stack range, either stepping over or into
36 // based on the value of \a type.
37 //----------------------------------------------------------------------
38
ThreadPlanStepInRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,LazyBool step_in_avoids_code_without_debug_info,LazyBool step_out_avoids_code_without_debug_info)39 ThreadPlanStepInRange::ThreadPlanStepInRange
40 (
41 Thread &thread,
42 const AddressRange &range,
43 const SymbolContext &addr_context,
44 lldb::RunMode stop_others,
45 LazyBool step_in_avoids_code_without_debug_info,
46 LazyBool step_out_avoids_code_without_debug_info
47 ) :
48 ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
49 ThreadPlanShouldStopHere (this),
50 m_step_past_prologue (true),
51 m_virtual_step (false)
52 {
53 SetCallbacks();
54 SetFlagsToDefault ();
55 SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);
56 }
57
ThreadPlanStepInRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,const char * step_into_target,lldb::RunMode stop_others,LazyBool step_in_avoids_code_without_debug_info,LazyBool step_out_avoids_code_without_debug_info)58 ThreadPlanStepInRange::ThreadPlanStepInRange
59 (
60 Thread &thread,
61 const AddressRange &range,
62 const SymbolContext &addr_context,
63 const char *step_into_target,
64 lldb::RunMode stop_others,
65 LazyBool step_in_avoids_code_without_debug_info,
66 LazyBool step_out_avoids_code_without_debug_info
67 ) :
68 ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
69 ThreadPlanShouldStopHere (this),
70 m_step_past_prologue (true),
71 m_virtual_step (false),
72 m_step_into_target (step_into_target)
73 {
74 SetCallbacks();
75 SetFlagsToDefault ();
76 SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);
77 }
78
~ThreadPlanStepInRange()79 ThreadPlanStepInRange::~ThreadPlanStepInRange ()
80 {
81 }
82
83 void
SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info,LazyBool step_out_avoids_code_without_debug_info)84 ThreadPlanStepInRange::SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info,
85 LazyBool step_out_avoids_code_without_debug_info)
86 {
87 bool avoid_nodebug = true;
88
89 switch (step_in_avoids_code_without_debug_info)
90 {
91 case eLazyBoolYes:
92 avoid_nodebug = true;
93 break;
94 case eLazyBoolNo:
95 avoid_nodebug = false;
96 break;
97 case eLazyBoolCalculate:
98 avoid_nodebug = m_thread.GetStepInAvoidsNoDebug();
99 break;
100 }
101 if (avoid_nodebug)
102 GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
103 else
104 GetFlags().Clear (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
105
106 switch (step_out_avoids_code_without_debug_info)
107 {
108 case eLazyBoolYes:
109 avoid_nodebug = true;
110 break;
111 case eLazyBoolNo:
112 avoid_nodebug = false;
113 break;
114 case eLazyBoolCalculate:
115 avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
116 break;
117 }
118 if (avoid_nodebug)
119 GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
120 else
121 GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
122 }
123
124 void
GetDescription(Stream * s,lldb::DescriptionLevel level)125 ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
126 {
127 if (level == lldb::eDescriptionLevelBrief)
128 {
129 s->Printf("step in");
130 return;
131 }
132
133 s->Printf ("Stepping in");
134 bool printed_line_info = false;
135 if (m_addr_context.line_entry.IsValid())
136 {
137 s->Printf (" through line ");
138 m_addr_context.line_entry.DumpStopContext (s, false);
139 printed_line_info = true;
140 }
141
142 const char *step_into_target = m_step_into_target.AsCString();
143 if (step_into_target && step_into_target[0] != '\0')
144 s->Printf (" targeting %s", m_step_into_target.AsCString());
145
146 if (!printed_line_info || level == eDescriptionLevelVerbose)
147 {
148 s->Printf (" using ranges:");
149 DumpRanges(s);
150 }
151
152 s->PutChar('.');
153 }
154
155 bool
ShouldStop(Event * event_ptr)156 ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
157 {
158 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
159
160 if (log)
161 {
162 StreamString s;
163 s.Address (m_thread.GetRegisterContext()->GetPC(),
164 m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
165 log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
166 }
167
168 if (IsPlanComplete())
169 return true;
170
171 m_no_more_plans = false;
172 if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete())
173 {
174 if (!m_sub_plan_sp->PlanSucceeded())
175 {
176 SetPlanComplete();
177 m_no_more_plans = true;
178 return true;
179 }
180 else
181 m_sub_plan_sp.reset();
182 }
183
184 if (m_virtual_step)
185 {
186 // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
187 // we're done.
188 // FIXME - This can be both a step in and a step out. Probably should record which in the m_virtual_step.
189 m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);
190 }
191 else
192 {
193 // Stepping through should be done running other threads in general, since we're setting a breakpoint and
194 // continuing. So only stop others if we are explicitly told to do so.
195
196 bool stop_others;
197 if (m_stop_others == lldb::eOnlyThisThread)
198 stop_others = true;
199 else
200 stop_others = false;
201
202 FrameComparison frame_order = CompareCurrentFrameToStartFrame();
203
204 if (frame_order == eFrameCompareOlder || frame_order == eFrameCompareSameParent)
205 {
206 // If we're in an older frame then we should stop.
207 //
208 // A caveat to this is if we think the frame is older but we're actually in a trampoline.
209 // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
210 // in a trampoline we think the frame is older because the trampoline confused the backtracer.
211 m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
212 if (!m_sub_plan_sp)
213 {
214 // Otherwise check the ShouldStopHere for step out:
215 m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
216 if (log)
217 log->Printf ("ShouldStopHere says we should step out of this frame.");
218 }
219 else if (log)
220 {
221 log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
222 }
223
224 }
225 else if (frame_order == eFrameCompareEqual && InSymbol())
226 {
227 // If we are not in a place we should step through, we're done.
228 // One tricky bit here is that some stubs don't push a frame, so we have to check
229 // both the case of a frame that is younger, or the same as this frame.
230 // However, if the frame is the same, and we are still in the symbol we started
231 // in, the we don't need to do this. This first check isn't strictly necessary,
232 // but it is more efficient.
233
234 // If we're still in the range, keep going, either by running to the next branch breakpoint, or by
235 // stepping.
236 if (InRange())
237 {
238 SetNextBranchBreakpoint();
239 return false;
240 }
241
242 SetPlanComplete();
243 m_no_more_plans = true;
244 return true;
245 }
246
247 // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
248 ClearNextBranchBreakpoint();
249
250 // We may have set the plan up above in the FrameIsOlder section:
251
252 if (!m_sub_plan_sp)
253 m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
254
255 if (log)
256 {
257 if (m_sub_plan_sp)
258 log->Printf ("Found a step through plan: %s", m_sub_plan_sp->GetName());
259 else
260 log->Printf ("No step through plan found.");
261 }
262
263 // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
264 // But only do that if we actually have stepped in.
265 if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
266 m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
267
268 // If we've stepped in and we are going to stop here, check to see if we were asked to
269 // run past the prologue, and if so do that.
270
271 if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue)
272 {
273 lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
274 if (curr_frame)
275 {
276 size_t bytes_to_skip = 0;
277 lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
278 Address func_start_address;
279
280 SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
281
282 if (sc.function)
283 {
284 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
285 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
286 bytes_to_skip = sc.function->GetPrologueByteSize();
287 }
288 else if (sc.symbol)
289 {
290 func_start_address = sc.symbol->GetAddress();
291 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
292 bytes_to_skip = sc.symbol->GetPrologueByteSize();
293 }
294
295 if (bytes_to_skip != 0)
296 {
297 func_start_address.Slide (bytes_to_skip);
298 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
299 if (log)
300 log->Printf ("Pushing past prologue ");
301
302 m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
303 }
304 }
305 }
306 }
307
308 if (!m_sub_plan_sp)
309 {
310 m_no_more_plans = true;
311 SetPlanComplete();
312 return true;
313 }
314 else
315 {
316 m_no_more_plans = false;
317 m_sub_plan_sp->SetPrivate(true);
318 return false;
319 }
320 }
321
322 void
SetAvoidRegexp(const char * name)323 ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
324 {
325 if (m_avoid_regexp_ap.get() == NULL)
326 m_avoid_regexp_ap.reset (new RegularExpression(name));
327
328 m_avoid_regexp_ap->Compile (name);
329 }
330
331 void
SetDefaultFlagValue(uint32_t new_value)332 ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
333 {
334 // TODO: Should we test this for sanity?
335 ThreadPlanStepInRange::s_default_flag_values = new_value;
336 }
337
338 bool
FrameMatchesAvoidCriteria()339 ThreadPlanStepInRange::FrameMatchesAvoidCriteria ()
340 {
341 StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
342
343 // Check the library list first, as that's cheapest:
344 bool libraries_say_avoid = false;
345
346 FileSpecList libraries_to_avoid (GetThread().GetLibrariesToAvoid());
347 size_t num_libraries = libraries_to_avoid.GetSize();
348 if (num_libraries > 0)
349 {
350 SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule));
351 FileSpec frame_library(sc.module_sp->GetFileSpec());
352
353 if (frame_library)
354 {
355 for (size_t i = 0; i < num_libraries; i++)
356 {
357 const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i));
358 if (FileSpec::Equal (file_spec, frame_library, false))
359 {
360 libraries_say_avoid = true;
361 break;
362 }
363 }
364 }
365 }
366 if (libraries_say_avoid)
367 return true;
368
369 const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
370 if (avoid_regexp_to_use == NULL)
371 avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
372
373 if (avoid_regexp_to_use != NULL)
374 {
375 SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
376 if (sc.symbol != NULL)
377 {
378 const char *frame_function_name = sc.GetFunctionName().GetCString();
379 if (frame_function_name)
380 {
381 size_t num_matches = 0;
382 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
383 if (log)
384 num_matches = 1;
385
386 RegularExpression::Match regex_match(num_matches);
387
388 bool return_value = avoid_regexp_to_use->Execute(frame_function_name, ®ex_match);
389 if (return_value)
390 {
391 if (log)
392 {
393 std::string match;
394 regex_match.GetMatchAtIndex(frame_function_name,0, match);
395 log->Printf ("Stepping out of function \"%s\" because it matches the avoid regexp \"%s\" - match substring: \"%s\".",
396 frame_function_name,
397 avoid_regexp_to_use->GetText(),
398 match.c_str());
399 }
400
401 }
402 return return_value;
403 }
404 }
405 }
406 return false;
407 }
408
409 bool
DefaultShouldStopHereCallback(ThreadPlan * current_plan,Flags & flags,FrameComparison operation,void * baton)410 ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, FrameComparison operation, void *baton)
411 {
412 bool should_stop_here = true;
413 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
414 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
415
416 // First see if the ThreadPlanShouldStopHere default implementation thinks we should get out of here:
417 should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (current_plan, flags, operation, baton);
418 if (!should_stop_here)
419 return should_stop_here;
420
421 if (should_stop_here && current_plan->GetKind() == eKindStepInRange && operation == eFrameCompareYounger)
422 {
423 ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
424 if (step_in_range_plan->m_step_into_target)
425 {
426 SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
427 if (sc.symbol != NULL)
428 {
429 // First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare.
430 if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())
431 {
432 should_stop_here = true;
433 }
434 else
435 {
436 const char *target_name = step_in_range_plan->m_step_into_target.AsCString();
437 const char *function_name = sc.GetFunctionName().AsCString();
438
439 if (function_name == NULL)
440 should_stop_here = false;
441 else if (strstr (function_name, target_name) == NULL)
442 should_stop_here = false;
443 }
444 if (log && !should_stop_here)
445 log->Printf("Stepping out of frame %s which did not match step into target %s.",
446 sc.GetFunctionName().AsCString(),
447 step_in_range_plan->m_step_into_target.AsCString());
448 }
449 }
450
451 if (should_stop_here)
452 {
453 ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
454 // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria.
455 should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria ();
456 }
457 }
458
459 return should_stop_here;
460 }
461
462 bool
DoPlanExplainsStop(Event * event_ptr)463 ThreadPlanStepInRange::DoPlanExplainsStop (Event *event_ptr)
464 {
465 // We always explain a stop. Either we've just done a single step, in which
466 // case we'll do our ordinary processing, or we stopped for some
467 // reason that isn't handled by our sub-plans, in which case we want to just stop right
468 // away.
469 // In general, we don't want to mark the plan as complete for unexplained stops.
470 // For instance, if you step in to some code with no debug info, so you step out
471 // and in the course of that hit a breakpoint, then you want to stop & show the user
472 // the breakpoint, but not unship the step in plan, since you still may want to complete that
473 // plan when you continue. This is particularly true when doing "step in to target function."
474 // stepping.
475 //
476 // The only variation is that if we are doing "step by running to next branch" in which case
477 // if we hit our branch breakpoint we don't set the plan to complete.
478
479 bool return_value;
480
481 if (m_virtual_step)
482 {
483 return_value = true;
484 }
485 else
486 {
487 StopInfoSP stop_info_sp = GetPrivateStopInfo ();
488 if (stop_info_sp)
489 {
490 StopReason reason = stop_info_sp->GetStopReason();
491
492 switch (reason)
493 {
494 case eStopReasonBreakpoint:
495 if (NextRangeBreakpointExplainsStop(stop_info_sp))
496 {
497 return_value = true;
498 break;
499 }
500 case eStopReasonWatchpoint:
501 case eStopReasonSignal:
502 case eStopReasonException:
503 case eStopReasonExec:
504 case eStopReasonThreadExiting:
505 {
506 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
507 if (log)
508 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
509 }
510 return_value = false;
511 break;
512 default:
513 return_value = true;
514 break;
515 }
516 }
517 else
518 return_value = true;
519 }
520
521 return return_value;
522 }
523
524 bool
DoWillResume(lldb::StateType resume_state,bool current_plan)525 ThreadPlanStepInRange::DoWillResume (lldb::StateType resume_state, bool current_plan)
526 {
527 m_virtual_step = false;
528 if (resume_state == eStateStepping && current_plan)
529 {
530 // See if we are about to step over a virtual inlined call.
531 bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
532 if (step_without_resume)
533 {
534 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
535 if (log)
536 log->Printf ("ThreadPlanStepInRange::DoWillResume: returning false, inline_depth: %d",
537 m_thread.GetCurrentInlinedDepth());
538 SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
539
540 // FIXME: Maybe it would be better to create a InlineStep stop reason, but then
541 // the whole rest of the world would have to handle that stop reason.
542 m_virtual_step = true;
543 }
544 return !step_without_resume;
545 }
546 return true;
547 }
548
549 bool
IsVirtualStep()550 ThreadPlanStepInRange::IsVirtualStep()
551 {
552 return m_virtual_step;
553 }
554