1 //===-- ThreadPlanStepOverRange.cpp -----------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 // Other libraries and framework includes
14 #include "lldb/Target/ThreadPlanStepOverRange.h"
15 #include "lldb/Symbol/Block.h"
16 #include "lldb/Symbol/CompileUnit.h"
17 #include "lldb/Symbol/Function.h"
18 #include "lldb/Symbol/LineTable.h"
19 #include "lldb/Target/Process.h"
20 #include "lldb/Target/RegisterContext.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Target/ThreadPlanStepOut.h"
24 #include "lldb/Target/ThreadPlanStepThrough.h"
25 #include "lldb/Utility/Log.h"
26 #include "lldb/Utility/Stream.h"
28 using namespace lldb_private;
31 uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
33 //----------------------------------------------------------------------
34 // ThreadPlanStepOverRange: Step through a stack range, either stepping over or
36 // based on the value of \a type.
37 //----------------------------------------------------------------------
39 ThreadPlanStepOverRange::ThreadPlanStepOverRange(
40 Thread &thread, const AddressRange &range,
41 const SymbolContext &addr_context, lldb::RunMode stop_others,
42 LazyBool step_out_avoids_code_without_debug_info)
43 : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange,
44 "Step range stepping over", thread, range,
45 addr_context, stop_others),
46 ThreadPlanShouldStopHere(this), m_first_resume(true) {
48 SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
51 ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default;
53 void ThreadPlanStepOverRange::GetDescription(Stream *s,
54 lldb::DescriptionLevel level) {
55 if (level == lldb::eDescriptionLevelBrief) {
56 s->Printf("step over");
59 s->Printf("Stepping over");
60 bool printed_line_info = false;
61 if (m_addr_context.line_entry.IsValid()) {
63 m_addr_context.line_entry.DumpStopContext(s, false);
64 printed_line_info = true;
67 if (!printed_line_info || level == eDescriptionLevelVerbose) {
68 s->Printf(" using ranges: ");
75 void ThreadPlanStepOverRange::SetupAvoidNoDebug(
76 LazyBool step_out_avoids_code_without_debug_info) {
77 bool avoid_nodebug = true;
78 switch (step_out_avoids_code_without_debug_info) {
83 avoid_nodebug = false;
85 case eLazyBoolCalculate:
86 avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
90 GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
92 GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
93 // Step Over plans should always avoid no-debug on step in. Seems like you
95 // have to say this, but a tail call looks more like a step in that a step
97 // we want to catch this case.
98 GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
101 bool ThreadPlanStepOverRange::IsEquivalentContext(
102 const SymbolContext &context) {
103 // Match as much as is specified in the m_addr_context:
104 // This is a fairly loose sanity check. Note, sometimes the target doesn't
106 // in so I left out the target check. And sometimes the module comes in as
107 // the .o file from the
108 // inlined range, so I left that out too...
109 if (m_addr_context.comp_unit) {
110 if (m_addr_context.comp_unit != context.comp_unit)
112 if (m_addr_context.function) {
113 if (m_addr_context.function != context.function)
115 // It is okay to return to a different block of a straight function, we
117 // be more careful if returning from one inlined block to another.
118 if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr &&
119 context.block->GetInlinedFunctionInfo() == nullptr)
121 return m_addr_context.block == context.block;
124 // Fall back to symbol if we have no decision from comp_unit/function/block.
125 if (m_addr_context.symbol && m_addr_context.symbol == context.symbol) {
131 bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
132 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
137 m_thread.GetRegisterContext()->GetPC(),
138 m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
139 log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData());
142 // If we're out of the range but in the same frame or in our caller's frame
143 // then we should stop.
144 // When stepping out we only stop others if we are forcing running one thread.
145 bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
146 ThreadPlanSP new_plan_sp;
147 FrameComparison frame_order = CompareCurrentFrameToStartFrame();
149 if (frame_order == eFrameCompareOlder) {
150 // If we're in an older frame then we should stop.
152 // A caveat to this is if we think the frame is older but we're actually in
154 // I'm going to make the assumption that you wouldn't RETURN to a
155 // trampoline. So if we are
156 // in a trampoline we think the frame is older because the trampoline
157 // confused the backtracer.
158 // As below, we step through first, and then try to figure out how to get
162 m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, stop_others);
164 if (new_plan_sp && log)
166 "Thought I stepped out, but in fact arrived at a trampoline.");
167 } else if (frame_order == eFrameCompareYounger) {
168 // Make sure we really are in a new frame. Do that by unwinding and seeing
170 // start function really is our start function...
171 for (uint32_t i = 1;; ++i) {
172 StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i);
173 if (!older_frame_sp) {
174 // We can't unwind the next frame we should just get out of here &
179 const SymbolContext &older_context =
180 older_frame_sp->GetSymbolContext(eSymbolContextEverything);
181 if (IsEquivalentContext(older_context)) {
182 new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
183 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
187 new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
189 // If we found a way through, then we should stop recursing.
195 // If we're still in the range, keep going.
197 SetNextBranchBreakpoint();
202 // This one is a little tricky. Sometimes we may be in a stub or
203 // something similar,
204 // in which case we need to get out of there. But if we are in a stub
206 // likely going to be hard to get out from here. It is probably easiest
208 // stub, and then it will be straight-forward to step out.
209 new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false,
212 // The current clang (at least through 424) doesn't always get the address
214 // DW_TAG_inlined_subroutines right, so that when you leave the inlined
215 // range the line table says
216 // you are still in the source file of the inlining function. This is
217 // bad, because now you are missing
218 // the stack frame for the function containing the inlining, and if you
219 // sensibly do "finish" to get
220 // out of this function you will instead exit the containing function.
221 // To work around this, we check whether we are still in the source file
222 // we started in, and if not assume
223 // it is an error, and push a plan to get us out of this line and back to
224 // the containing file.
226 if (m_addr_context.line_entry.IsValid()) {
228 StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0);
229 sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
230 if (sc.line_entry.IsValid()) {
231 if (sc.line_entry.original_file !=
232 m_addr_context.line_entry.original_file &&
233 sc.comp_unit == m_addr_context.comp_unit &&
234 sc.function == m_addr_context.function) {
235 // Okay, find the next occurrence of this file in the line table:
236 LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
238 Address cur_address = frame_sp->GetFrameCodeAddress();
240 LineEntry line_entry;
241 if (line_table->FindLineEntryByAddress(cur_address, line_entry,
243 LineEntry next_line_entry;
244 bool step_past_remaining_inline = false;
246 // We require the previous line entry and the current line
248 // from the same file.
249 // The other requirement is that the previous line table entry
251 // inlined block, we don't want to step past cases where
252 // people have inlined
253 // some code fragment by using #include <source-fragment.c>
255 LineEntry prev_line_entry;
256 if (line_table->GetLineEntryAtIndex(entry_idx - 1,
258 prev_line_entry.original_file ==
259 line_entry.original_file) {
260 SymbolContext prev_sc;
261 Address prev_address =
262 prev_line_entry.range.GetBaseAddress();
263 prev_address.CalculateSymbolContext(&prev_sc);
265 Block *inlined_block =
266 prev_sc.block->GetContainingInlinedBlock();
268 AddressRange inline_range;
269 inlined_block->GetRangeContainingAddress(prev_address,
271 if (!inline_range.ContainsFileAddress(cur_address)) {
273 step_past_remaining_inline = true;
280 if (step_past_remaining_inline) {
281 uint32_t look_ahead_step = 1;
282 while (line_table->GetLineEntryAtIndex(
283 entry_idx + look_ahead_step, next_line_entry)) {
284 // Make sure we haven't wandered out of the function we
286 Address next_line_address =
287 next_line_entry.range.GetBaseAddress();
288 Function *next_line_function =
289 next_line_address.CalculateSymbolContextFunction();
290 if (next_line_function != m_addr_context.function)
293 if (next_line_entry.original_file ==
294 m_addr_context.line_entry.original_file) {
295 const bool abort_other_plans = false;
296 const RunMode stop_other_threads = RunMode::eAllThreads;
297 lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0)
298 ->GetRegisterContext()
300 AddressRange step_range(
302 next_line_address.GetLoadAddress(&GetTarget()) -
305 new_plan_sp = m_thread.QueueThreadPlanForStepOverRange(
306 abort_other_plans, step_range, sc,
321 // If we get to this point, we're not going to use a previously set "next
322 // branch" breakpoint, so delete it:
323 ClearNextBranchBreakpoint();
325 // If we haven't figured out something to do yet, then ask the ShouldStopHere
328 new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
332 m_no_more_plans = true;
334 // Any new plan will be an implementation plan, so mark it private:
335 new_plan_sp->SetPrivate(true);
336 m_no_more_plans = false;
340 // For efficiencies sake, we know we're done here so we don't have to do
342 // calculation again in MischiefManaged.
349 bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
350 // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan
352 // handle the stop. That way the user can see the stop, step around, and then
354 // are done, continue and have their step complete. The exception is if we've
356 // "run to next branch" breakpoint.
357 // Note, unlike the step in range plan, we don't mark ourselves complete if we
359 // unexplained breakpoint/crash.
361 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
362 StopInfoSP stop_info_sp = GetPrivateStopInfo();
366 StopReason reason = stop_info_sp->GetStopReason();
368 if (reason == eStopReasonTrace) {
370 } else if (reason == eStopReasonBreakpoint) {
371 return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
374 log->PutCString("ThreadPlanStepInRange got asked if it explains the "
375 "stop for some reason other than step.");
376 return_value = false;
384 bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
386 if (resume_state != eStateSuspended && m_first_resume) {
387 m_first_resume = false;
388 if (resume_state == eStateStepping && current_plan) {
389 // See if we are about to step over an inlined call in the middle of the
390 // inlined stack, if so figure
391 // out its extents and reset our range to step over that.
392 bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth();
393 if (in_inlined_stack) {
394 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
396 log->Printf("ThreadPlanStepInRange::DoWillResume: adjusting range to "
397 "the frame at inlined depth %d.",
398 m_thread.GetCurrentInlinedDepth());
399 StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0);
401 Block *frame_block = stack_sp->GetFrameBlock();
402 lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
403 AddressRange my_range;
404 if (frame_block->GetRangeContainingLoadAddress(
405 curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) {
406 m_address_ranges.clear();
407 m_address_ranges.push_back(my_range);
410 const InlineFunctionInfo *inline_info =
411 frame_block->GetInlinedFunctionInfo();
416 ->GetName(frame_block->CalculateSymbolContextFunction()
420 name = "<unknown-notinlined>";
423 "Stepping over inlined function \"%s\" in inlined stack: ",
426 log->PutString(s.GetString());