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