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