1*0b57cec5SDimitry Andric //===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric
9*0b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOverRange.h"
10*0b57cec5SDimitry Andric #include "lldb/Symbol/Block.h"
11*0b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
12*0b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
13*0b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h"
14*0b57cec5SDimitry Andric #include "lldb/Target/Process.h"
15*0b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
16*0b57cec5SDimitry Andric #include "lldb/Target/Target.h"
17*0b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
18*0b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOut.h"
19*0b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepThrough.h"
20*0b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
21*0b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
22*0b57cec5SDimitry Andric
23*0b57cec5SDimitry Andric using namespace lldb_private;
24*0b57cec5SDimitry Andric using namespace lldb;
25*0b57cec5SDimitry Andric
26*0b57cec5SDimitry Andric uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
27*0b57cec5SDimitry Andric
28*0b57cec5SDimitry Andric // ThreadPlanStepOverRange: Step through a stack range, either stepping over or
29*0b57cec5SDimitry Andric // into based on the value of \a type.
30*0b57cec5SDimitry Andric
ThreadPlanStepOverRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,LazyBool step_out_avoids_code_without_debug_info)31*0b57cec5SDimitry Andric ThreadPlanStepOverRange::ThreadPlanStepOverRange(
32*0b57cec5SDimitry Andric Thread &thread, const AddressRange &range,
33*0b57cec5SDimitry Andric const SymbolContext &addr_context, lldb::RunMode stop_others,
34*0b57cec5SDimitry Andric LazyBool step_out_avoids_code_without_debug_info)
35*0b57cec5SDimitry Andric : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange,
36*0b57cec5SDimitry Andric "Step range stepping over", thread, range,
37*0b57cec5SDimitry Andric addr_context, stop_others),
38*0b57cec5SDimitry Andric ThreadPlanShouldStopHere(this), m_first_resume(true) {
39*0b57cec5SDimitry Andric SetFlagsToDefault();
40*0b57cec5SDimitry Andric SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
41*0b57cec5SDimitry Andric }
42*0b57cec5SDimitry Andric
43*0b57cec5SDimitry Andric ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default;
44*0b57cec5SDimitry Andric
GetDescription(Stream * s,lldb::DescriptionLevel level)45*0b57cec5SDimitry Andric void ThreadPlanStepOverRange::GetDescription(Stream *s,
46*0b57cec5SDimitry Andric lldb::DescriptionLevel level) {
47*0b57cec5SDimitry Andric auto PrintFailureIfAny = [&]() {
48*0b57cec5SDimitry Andric if (m_status.Success())
49*0b57cec5SDimitry Andric return;
50*0b57cec5SDimitry Andric s->Printf(" failed (%s)", m_status.AsCString());
51*0b57cec5SDimitry Andric };
52*0b57cec5SDimitry Andric
53*0b57cec5SDimitry Andric if (level == lldb::eDescriptionLevelBrief) {
54*0b57cec5SDimitry Andric s->Printf("step over");
55*0b57cec5SDimitry Andric PrintFailureIfAny();
56*0b57cec5SDimitry Andric return;
57*0b57cec5SDimitry Andric }
58*0b57cec5SDimitry Andric
59*0b57cec5SDimitry Andric s->Printf("Stepping over");
60*0b57cec5SDimitry Andric bool printed_line_info = false;
61*0b57cec5SDimitry Andric if (m_addr_context.line_entry.IsValid()) {
62*0b57cec5SDimitry Andric s->Printf(" line ");
63*0b57cec5SDimitry Andric m_addr_context.line_entry.DumpStopContext(s, false);
64*0b57cec5SDimitry Andric printed_line_info = true;
65*0b57cec5SDimitry Andric }
66*0b57cec5SDimitry Andric
67*0b57cec5SDimitry Andric if (!printed_line_info || level == eDescriptionLevelVerbose) {
68*0b57cec5SDimitry Andric s->Printf(" using ranges: ");
69*0b57cec5SDimitry Andric DumpRanges(s);
70*0b57cec5SDimitry Andric }
71*0b57cec5SDimitry Andric
72*0b57cec5SDimitry Andric PrintFailureIfAny();
73*0b57cec5SDimitry Andric
74*0b57cec5SDimitry Andric s->PutChar('.');
75*0b57cec5SDimitry Andric }
76*0b57cec5SDimitry Andric
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)77*0b57cec5SDimitry Andric void ThreadPlanStepOverRange::SetupAvoidNoDebug(
78*0b57cec5SDimitry Andric LazyBool step_out_avoids_code_without_debug_info) {
79*0b57cec5SDimitry Andric bool avoid_nodebug = true;
80*0b57cec5SDimitry Andric switch (step_out_avoids_code_without_debug_info) {
81*0b57cec5SDimitry Andric case eLazyBoolYes:
82*0b57cec5SDimitry Andric avoid_nodebug = true;
83*0b57cec5SDimitry Andric break;
84*0b57cec5SDimitry Andric case eLazyBoolNo:
85*0b57cec5SDimitry Andric avoid_nodebug = false;
86*0b57cec5SDimitry Andric break;
87*0b57cec5SDimitry Andric case eLazyBoolCalculate:
88*0b57cec5SDimitry Andric avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
89*0b57cec5SDimitry Andric break;
90*0b57cec5SDimitry Andric }
91*0b57cec5SDimitry Andric if (avoid_nodebug)
92*0b57cec5SDimitry Andric GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
93*0b57cec5SDimitry Andric else
94*0b57cec5SDimitry Andric GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
95*0b57cec5SDimitry Andric // Step Over plans should always avoid no-debug on step in. Seems like you
96*0b57cec5SDimitry Andric // shouldn't have to say this, but a tail call looks more like a step in that
97*0b57cec5SDimitry Andric // a step out, so we want to catch this case.
98*0b57cec5SDimitry Andric GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
99*0b57cec5SDimitry Andric }
100*0b57cec5SDimitry Andric
IsEquivalentContext(const SymbolContext & context)101*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::IsEquivalentContext(
102*0b57cec5SDimitry Andric const SymbolContext &context) {
103*0b57cec5SDimitry Andric // Match as much as is specified in the m_addr_context: This is a fairly
104*0b57cec5SDimitry Andric // loose sanity check. Note, sometimes the target doesn't get filled in so I
105*0b57cec5SDimitry Andric // left out the target check. And sometimes the module comes in as the .o
106*0b57cec5SDimitry Andric // file from the inlined range, so I left that out too...
107*0b57cec5SDimitry Andric if (m_addr_context.comp_unit) {
108*0b57cec5SDimitry Andric if (m_addr_context.comp_unit != context.comp_unit)
109*0b57cec5SDimitry Andric return false;
110*0b57cec5SDimitry Andric if (m_addr_context.function) {
111*0b57cec5SDimitry Andric if (m_addr_context.function != context.function)
112*0b57cec5SDimitry Andric return false;
113*0b57cec5SDimitry Andric // It is okay to return to a different block of a straight function, we
114*0b57cec5SDimitry Andric // only have to be more careful if returning from one inlined block to
115*0b57cec5SDimitry Andric // another.
116*0b57cec5SDimitry Andric if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr &&
117*0b57cec5SDimitry Andric context.block->GetInlinedFunctionInfo() == nullptr)
118*0b57cec5SDimitry Andric return true;
119*0b57cec5SDimitry Andric return m_addr_context.block == context.block;
120*0b57cec5SDimitry Andric }
121*0b57cec5SDimitry Andric }
122*0b57cec5SDimitry Andric // Fall back to symbol if we have no decision from comp_unit/function/block.
123*0b57cec5SDimitry Andric return m_addr_context.symbol && m_addr_context.symbol == context.symbol;
124*0b57cec5SDimitry Andric }
125*0b57cec5SDimitry Andric
ShouldStop(Event * event_ptr)126*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
127*0b57cec5SDimitry Andric Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
128*0b57cec5SDimitry Andric Thread &thread = GetThread();
129*0b57cec5SDimitry Andric
130*0b57cec5SDimitry Andric if (log) {
131*0b57cec5SDimitry Andric StreamString s;
132*0b57cec5SDimitry Andric DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(),
133*0b57cec5SDimitry Andric GetTarget().GetArchitecture().GetAddressByteSize());
134*0b57cec5SDimitry Andric LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData());
135*0b57cec5SDimitry Andric }
136*0b57cec5SDimitry Andric
137*0b57cec5SDimitry Andric // If we're out of the range but in the same frame or in our caller's frame
138*0b57cec5SDimitry Andric // then we should stop. When stepping out we only stop others if we are
139*0b57cec5SDimitry Andric // forcing running one thread.
140*0b57cec5SDimitry Andric bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
141*0b57cec5SDimitry Andric ThreadPlanSP new_plan_sp;
142*0b57cec5SDimitry Andric FrameComparison frame_order = CompareCurrentFrameToStartFrame();
143*0b57cec5SDimitry Andric
144*0b57cec5SDimitry Andric if (frame_order == eFrameCompareOlder) {
145*0b57cec5SDimitry Andric // If we're in an older frame then we should stop.
146*0b57cec5SDimitry Andric //
147*0b57cec5SDimitry Andric // A caveat to this is if we think the frame is older but we're actually in
148*0b57cec5SDimitry Andric // a trampoline.
149*0b57cec5SDimitry Andric // I'm going to make the assumption that you wouldn't RETURN to a
150*0b57cec5SDimitry Andric // trampoline. So if we are in a trampoline we think the frame is older
151*0b57cec5SDimitry Andric // because the trampoline confused the backtracer. As below, we step
152*0b57cec5SDimitry Andric // through first, and then try to figure out how to get back out again.
153*0b57cec5SDimitry Andric
154*0b57cec5SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
155*0b57cec5SDimitry Andric stop_others, m_status);
156*0b57cec5SDimitry Andric
157*0b57cec5SDimitry Andric if (new_plan_sp && log)
158*0b57cec5SDimitry Andric LLDB_LOGF(log,
159*0b57cec5SDimitry Andric "Thought I stepped out, but in fact arrived at a trampoline.");
160*0b57cec5SDimitry Andric } else if (frame_order == eFrameCompareYounger) {
161*0b57cec5SDimitry Andric // Make sure we really are in a new frame. Do that by unwinding and seeing
162*0b57cec5SDimitry Andric // if the start function really is our start function...
163*0b57cec5SDimitry Andric for (uint32_t i = 1;; ++i) {
164*0b57cec5SDimitry Andric StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i);
165*0b57cec5SDimitry Andric if (!older_frame_sp) {
166*0b57cec5SDimitry Andric // We can't unwind the next frame we should just get out of here &
167*0b57cec5SDimitry Andric // stop...
168*0b57cec5SDimitry Andric break;
169*0b57cec5SDimitry Andric }
170*0b57cec5SDimitry Andric
171*0b57cec5SDimitry Andric const SymbolContext &older_context =
172*0b57cec5SDimitry Andric older_frame_sp->GetSymbolContext(eSymbolContextEverything);
173*0b57cec5SDimitry Andric if (IsEquivalentContext(older_context)) {
174*0b57cec5SDimitry Andric // If we have the next-branch-breakpoint in the range, we can just
175*0b57cec5SDimitry Andric // rely on that breakpoint to trigger once we return to the range.
176*0b57cec5SDimitry Andric if (m_next_branch_bp_sp)
177*0b57cec5SDimitry Andric return false;
178*0b57cec5SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop(
179*0b57cec5SDimitry Andric false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
180*0b57cec5SDimitry Andric m_status, true);
181*0b57cec5SDimitry Andric break;
182*0b57cec5SDimitry Andric } else {
183*0b57cec5SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(
184*0b57cec5SDimitry Andric m_stack_id, false, stop_others, m_status);
185*0b57cec5SDimitry Andric // If we found a way through, then we should stop recursing.
186*0b57cec5SDimitry Andric if (new_plan_sp)
187*0b57cec5SDimitry Andric break;
188*0b57cec5SDimitry Andric }
189*0b57cec5SDimitry Andric }
190*0b57cec5SDimitry Andric } else {
191*0b57cec5SDimitry Andric // If we're still in the range, keep going.
192*0b57cec5SDimitry Andric if (InRange()) {
193*0b57cec5SDimitry Andric SetNextBranchBreakpoint();
194*0b57cec5SDimitry Andric return false;
195*0b57cec5SDimitry Andric }
196*0b57cec5SDimitry Andric
197*0b57cec5SDimitry Andric if (!InSymbol()) {
198*0b57cec5SDimitry Andric // This one is a little tricky. Sometimes we may be in a stub or
199*0b57cec5SDimitry Andric // something similar, in which case we need to get out of there. But if
200*0b57cec5SDimitry Andric // we are in a stub then it's likely going to be hard to get out from
201*0b57cec5SDimitry Andric // here. It is probably easiest to step into the stub, and then it will
202*0b57cec5SDimitry Andric // be straight-forward to step out.
203*0b57cec5SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
204*0b57cec5SDimitry Andric stop_others, m_status);
205*0b57cec5SDimitry Andric } else {
206*0b57cec5SDimitry Andric // The current clang (at least through 424) doesn't always get the
207*0b57cec5SDimitry Andric // address range for the DW_TAG_inlined_subroutines right, so that when
208*0b57cec5SDimitry Andric // you leave the inlined range the line table says you are still in the
209*0b57cec5SDimitry Andric // source file of the inlining function. This is bad, because now you
210*0b57cec5SDimitry Andric // are missing the stack frame for the function containing the inlining,
211*0b57cec5SDimitry Andric // and if you sensibly do "finish" to get out of this function you will
212*0b57cec5SDimitry Andric // instead exit the containing function. To work around this, we check
213*0b57cec5SDimitry Andric // whether we are still in the source file we started in, and if not
214*0b57cec5SDimitry Andric // assume it is an error, and push a plan to get us out of this line and
215*0b57cec5SDimitry Andric // back to the containing file.
216*0b57cec5SDimitry Andric
217*0b57cec5SDimitry Andric if (m_addr_context.line_entry.IsValid()) {
218*0b57cec5SDimitry Andric SymbolContext sc;
219*0b57cec5SDimitry Andric StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0);
220*0b57cec5SDimitry Andric sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
221*0b57cec5SDimitry Andric if (sc.line_entry.IsValid()) {
222*0b57cec5SDimitry Andric if (sc.line_entry.original_file !=
223*0b57cec5SDimitry Andric m_addr_context.line_entry.original_file &&
224*0b57cec5SDimitry Andric sc.comp_unit == m_addr_context.comp_unit &&
225*0b57cec5SDimitry Andric sc.function == m_addr_context.function) {
226*0b57cec5SDimitry Andric // Okay, find the next occurrence of this file in the line table:
227*0b57cec5SDimitry Andric LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
228*0b57cec5SDimitry Andric if (line_table) {
229*0b57cec5SDimitry Andric Address cur_address = frame_sp->GetFrameCodeAddress();
230*0b57cec5SDimitry Andric uint32_t entry_idx;
231*0b57cec5SDimitry Andric LineEntry line_entry;
232*0b57cec5SDimitry Andric if (line_table->FindLineEntryByAddress(cur_address, line_entry,
233*0b57cec5SDimitry Andric &entry_idx)) {
234*0b57cec5SDimitry Andric LineEntry next_line_entry;
235*0b57cec5SDimitry Andric bool step_past_remaining_inline = false;
236*0b57cec5SDimitry Andric if (entry_idx > 0) {
237*0b57cec5SDimitry Andric // We require the previous line entry and the current line
238*0b57cec5SDimitry Andric // entry come from the same file. The other requirement is
239*0b57cec5SDimitry Andric // that the previous line table entry be part of an inlined
240*0b57cec5SDimitry Andric // block, we don't want to step past cases where people have
241*0b57cec5SDimitry Andric // inlined some code fragment by using #include <source-
242*0b57cec5SDimitry Andric // fragment.c> directly.
243*0b57cec5SDimitry Andric LineEntry prev_line_entry;
244*0b57cec5SDimitry Andric if (line_table->GetLineEntryAtIndex(entry_idx - 1,
245*0b57cec5SDimitry Andric prev_line_entry) &&
246*0b57cec5SDimitry Andric prev_line_entry.original_file ==
247*0b57cec5SDimitry Andric line_entry.original_file) {
248*0b57cec5SDimitry Andric SymbolContext prev_sc;
249*0b57cec5SDimitry Andric Address prev_address =
250*0b57cec5SDimitry Andric prev_line_entry.range.GetBaseAddress();
251*0b57cec5SDimitry Andric prev_address.CalculateSymbolContext(&prev_sc);
252*0b57cec5SDimitry Andric if (prev_sc.block) {
253*0b57cec5SDimitry Andric Block *inlined_block =
254*0b57cec5SDimitry Andric prev_sc.block->GetContainingInlinedBlock();
255*0b57cec5SDimitry Andric if (inlined_block) {
256*0b57cec5SDimitry Andric AddressRange inline_range;
257*0b57cec5SDimitry Andric inlined_block->GetRangeContainingAddress(prev_address,
258*0b57cec5SDimitry Andric inline_range);
259*0b57cec5SDimitry Andric if (!inline_range.ContainsFileAddress(cur_address)) {
260*0b57cec5SDimitry Andric
261*0b57cec5SDimitry Andric step_past_remaining_inline = true;
262*0b57cec5SDimitry Andric }
263*0b57cec5SDimitry Andric }
264*0b57cec5SDimitry Andric }
265*0b57cec5SDimitry Andric }
266*0b57cec5SDimitry Andric }
267*0b57cec5SDimitry Andric
268*0b57cec5SDimitry Andric if (step_past_remaining_inline) {
269*0b57cec5SDimitry Andric uint32_t look_ahead_step = 1;
270*0b57cec5SDimitry Andric while (line_table->GetLineEntryAtIndex(
271*0b57cec5SDimitry Andric entry_idx + look_ahead_step, next_line_entry)) {
272*0b57cec5SDimitry Andric // Make sure we haven't wandered out of the function we
273*0b57cec5SDimitry Andric // started from...
274*0b57cec5SDimitry Andric Address next_line_address =
275*0b57cec5SDimitry Andric next_line_entry.range.GetBaseAddress();
276*0b57cec5SDimitry Andric Function *next_line_function =
277*0b57cec5SDimitry Andric next_line_address.CalculateSymbolContextFunction();
278*0b57cec5SDimitry Andric if (next_line_function != m_addr_context.function)
279*0b57cec5SDimitry Andric break;
280*0b57cec5SDimitry Andric
281*0b57cec5SDimitry Andric if (next_line_entry.original_file ==
282*0b57cec5SDimitry Andric m_addr_context.line_entry.original_file) {
283*0b57cec5SDimitry Andric const bool abort_other_plans = false;
284*0b57cec5SDimitry Andric const RunMode stop_other_threads = RunMode::eAllThreads;
285*0b57cec5SDimitry Andric lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
286*0b57cec5SDimitry Andric ->GetRegisterContext()
287*0b57cec5SDimitry Andric ->GetPC();
288*0b57cec5SDimitry Andric AddressRange step_range(
289*0b57cec5SDimitry Andric cur_pc,
290*0b57cec5SDimitry Andric next_line_address.GetLoadAddress(&GetTarget()) -
291*0b57cec5SDimitry Andric cur_pc);
292*0b57cec5SDimitry Andric
293*0b57cec5SDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepOverRange(
294*0b57cec5SDimitry Andric abort_other_plans, step_range, sc, stop_other_threads,
295*0b57cec5SDimitry Andric m_status);
296*0b57cec5SDimitry Andric break;
297*0b57cec5SDimitry Andric }
298*0b57cec5SDimitry Andric look_ahead_step++;
299*0b57cec5SDimitry Andric }
300*0b57cec5SDimitry Andric }
301*0b57cec5SDimitry Andric }
302*0b57cec5SDimitry Andric }
303*0b57cec5SDimitry Andric }
304*0b57cec5SDimitry Andric }
305*0b57cec5SDimitry Andric }
306*0b57cec5SDimitry Andric }
307*0b57cec5SDimitry Andric }
308*0b57cec5SDimitry Andric
309*0b57cec5SDimitry Andric // If we get to this point, we're not going to use a previously set "next
310*0b57cec5SDimitry Andric // branch" breakpoint, so delete it:
311*0b57cec5SDimitry Andric ClearNextBranchBreakpoint();
312*0b57cec5SDimitry Andric
313*0b57cec5SDimitry Andric // If we haven't figured out something to do yet, then ask the ShouldStopHere
314*0b57cec5SDimitry Andric // callback:
315*0b57cec5SDimitry Andric if (!new_plan_sp) {
316*0b57cec5SDimitry Andric new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
317*0b57cec5SDimitry Andric }
318*0b57cec5SDimitry Andric
319*0b57cec5SDimitry Andric if (!new_plan_sp)
320*0b57cec5SDimitry Andric m_no_more_plans = true;
321*0b57cec5SDimitry Andric else {
322*0b57cec5SDimitry Andric // Any new plan will be an implementation plan, so mark it private:
323*0b57cec5SDimitry Andric new_plan_sp->SetPrivate(true);
324*0b57cec5SDimitry Andric m_no_more_plans = false;
325*0b57cec5SDimitry Andric }
326*0b57cec5SDimitry Andric
327*0b57cec5SDimitry Andric if (!new_plan_sp) {
328*0b57cec5SDimitry Andric // For efficiencies sake, we know we're done here so we don't have to do
329*0b57cec5SDimitry Andric // this calculation again in MischiefManaged.
330*0b57cec5SDimitry Andric SetPlanComplete(m_status.Success());
331*0b57cec5SDimitry Andric return true;
332*0b57cec5SDimitry Andric } else
333*0b57cec5SDimitry Andric return false;
334*0b57cec5SDimitry Andric }
335*0b57cec5SDimitry Andric
DoPlanExplainsStop(Event * event_ptr)336*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
337*0b57cec5SDimitry Andric // For crashes, breakpoint hits, signals, etc, let the base plan (or some
338*0b57cec5SDimitry Andric // plan above us) handle the stop. That way the user can see the stop, step
339*0b57cec5SDimitry Andric // around, and then when they are done, continue and have their step
340*0b57cec5SDimitry Andric // complete. The exception is if we've hit our "run to next branch"
341*0b57cec5SDimitry Andric // breakpoint. Note, unlike the step in range plan, we don't mark ourselves
342*0b57cec5SDimitry Andric // complete if we hit an unexplained breakpoint/crash.
343*0b57cec5SDimitry Andric
344*0b57cec5SDimitry Andric Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
345*0b57cec5SDimitry Andric StopInfoSP stop_info_sp = GetPrivateStopInfo();
346*0b57cec5SDimitry Andric bool return_value;
347*0b57cec5SDimitry Andric
348*0b57cec5SDimitry Andric if (stop_info_sp) {
349*0b57cec5SDimitry Andric StopReason reason = stop_info_sp->GetStopReason();
350*0b57cec5SDimitry Andric
351*0b57cec5SDimitry Andric if (reason == eStopReasonTrace) {
352*0b57cec5SDimitry Andric return_value = true;
353*0b57cec5SDimitry Andric } else if (reason == eStopReasonBreakpoint) {
354*0b57cec5SDimitry Andric return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
355*0b57cec5SDimitry Andric } else {
356*0b57cec5SDimitry Andric if (log)
357*0b57cec5SDimitry Andric log->PutCString("ThreadPlanStepInRange got asked if it explains the "
358*0b57cec5SDimitry Andric "stop for some reason other than step.");
359*0b57cec5SDimitry Andric return_value = false;
360*0b57cec5SDimitry Andric }
361*0b57cec5SDimitry Andric } else
362*0b57cec5SDimitry Andric return_value = true;
363*0b57cec5SDimitry Andric
364*0b57cec5SDimitry Andric return return_value;
365*0b57cec5SDimitry Andric }
366*0b57cec5SDimitry Andric
DoWillResume(lldb::StateType resume_state,bool current_plan)367*0b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
368*0b57cec5SDimitry Andric bool current_plan) {
369*0b57cec5SDimitry Andric if (resume_state != eStateSuspended && m_first_resume) {
370*0b57cec5SDimitry Andric m_first_resume = false;
371*0b57cec5SDimitry Andric if (resume_state == eStateStepping && current_plan) {
372*0b57cec5SDimitry Andric Thread &thread = GetThread();
373*0b57cec5SDimitry Andric // See if we are about to step over an inlined call in the middle of the
374*0b57cec5SDimitry Andric // inlined stack, if so figure out its extents and reset our range to
375*0b57cec5SDimitry Andric // step over that.
376*0b57cec5SDimitry Andric bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
377*0b57cec5SDimitry Andric if (in_inlined_stack) {
378*0b57cec5SDimitry Andric Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
379*0b57cec5SDimitry Andric LLDB_LOGF(log,
380*0b57cec5SDimitry Andric "ThreadPlanStepInRange::DoWillResume: adjusting range to "
381*0b57cec5SDimitry Andric "the frame at inlined depth %d.",
382*0b57cec5SDimitry Andric thread.GetCurrentInlinedDepth());
383*0b57cec5SDimitry Andric StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
384*0b57cec5SDimitry Andric if (stack_sp) {
385*0b57cec5SDimitry Andric Block *frame_block = stack_sp->GetFrameBlock();
386*0b57cec5SDimitry Andric lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
387*0b57cec5SDimitry Andric AddressRange my_range;
388*0b57cec5SDimitry Andric if (frame_block->GetRangeContainingLoadAddress(
389*0b57cec5SDimitry Andric curr_pc, m_process.GetTarget(), my_range)) {
390*0b57cec5SDimitry Andric m_address_ranges.clear();
391*0b57cec5SDimitry Andric m_address_ranges.push_back(my_range);
392*0b57cec5SDimitry Andric if (log) {
393*0b57cec5SDimitry Andric StreamString s;
394*0b57cec5SDimitry Andric const InlineFunctionInfo *inline_info =
395*0b57cec5SDimitry Andric frame_block->GetInlinedFunctionInfo();
396*0b57cec5SDimitry Andric const char *name;
397*0b57cec5SDimitry Andric if (inline_info)
398*0b57cec5SDimitry Andric name = inline_info->GetName().AsCString();
399*0b57cec5SDimitry Andric else
400*0b57cec5SDimitry Andric name = "<unknown-notinlined>";
401*0b57cec5SDimitry Andric
402*0b57cec5SDimitry Andric s.Printf(
403*0b57cec5SDimitry Andric "Stepping over inlined function \"%s\" in inlined stack: ",
404*0b57cec5SDimitry Andric name);
405*0b57cec5SDimitry Andric DumpRanges(&s);
406*0b57cec5SDimitry Andric log->PutString(s.GetString());
407*0b57cec5SDimitry Andric }
408*0b57cec5SDimitry Andric }
409*0b57cec5SDimitry Andric }
410*0b57cec5SDimitry Andric }
411*0b57cec5SDimitry Andric }
412*0b57cec5SDimitry Andric }
413*0b57cec5SDimitry Andric
414*0b57cec5SDimitry Andric return true;
415 }
416