/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Target/ThreadPlanStepRange.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- ThreadPlanStepRange.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/ThreadPlanStepRange.h" |
10 | | #include "lldb/Breakpoint/BreakpointLocation.h" |
11 | | #include "lldb/Breakpoint/BreakpointSite.h" |
12 | | #include "lldb/Core/Disassembler.h" |
13 | | #include "lldb/Symbol/Function.h" |
14 | | #include "lldb/Symbol/Symbol.h" |
15 | | #include "lldb/Target/ExecutionContext.h" |
16 | | #include "lldb/Target/Process.h" |
17 | | #include "lldb/Target/RegisterContext.h" |
18 | | #include "lldb/Target/StopInfo.h" |
19 | | #include "lldb/Target/Target.h" |
20 | | #include "lldb/Target/Thread.h" |
21 | | #include "lldb/Target/ThreadPlanRunToAddress.h" |
22 | | #include "lldb/Utility/LLDBLog.h" |
23 | | #include "lldb/Utility/Log.h" |
24 | | #include "lldb/Utility/Stream.h" |
25 | | |
26 | | using namespace lldb; |
27 | | using namespace lldb_private; |
28 | | |
29 | | // ThreadPlanStepRange: Step through a stack range, either stepping over or |
30 | | // into based on the value of \a type. |
31 | | |
32 | | ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name, |
33 | | Thread &thread, |
34 | | const AddressRange &range, |
35 | | const SymbolContext &addr_context, |
36 | | lldb::RunMode stop_others, |
37 | | bool given_ranges_only) |
38 | 427 | : ThreadPlan(kind, name, thread, eVoteNoOpinion, eVoteNoOpinion), |
39 | 427 | m_addr_context(addr_context), m_address_ranges(), |
40 | 427 | m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(), |
41 | 427 | m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false), |
42 | 427 | m_given_ranges_only(given_ranges_only) { |
43 | 427 | m_use_fast_step = GetTarget().GetUseFastStepping(); |
44 | 427 | AddRange(range); |
45 | 427 | m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID(); |
46 | 427 | StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1); |
47 | 427 | if (parent_stack) |
48 | 427 | m_parent_stack_id = parent_stack->GetStackID(); |
49 | 427 | } |
50 | | |
51 | 427 | ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); } |
52 | | |
53 | 427 | void ThreadPlanStepRange::DidPush() { |
54 | | // See if we can find a "next range" breakpoint: |
55 | 427 | SetNextBranchBreakpoint(); |
56 | 427 | } |
57 | | |
58 | 860 | bool ThreadPlanStepRange::ValidatePlan(Stream *error) { |
59 | 860 | if (m_could_not_resolve_hw_bp) { |
60 | 0 | if (error) |
61 | 0 | error->PutCString( |
62 | 0 | "Could not create hardware breakpoint for thread plan."); |
63 | 0 | return false; |
64 | 0 | } |
65 | 860 | return true; |
66 | 860 | } |
67 | | |
68 | 389 | Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) { |
69 | 389 | Log *log = GetLog(LLDBLog::Step); |
70 | | |
71 | 389 | const Vote vote = IsPlanComplete() ? eVoteYes7 : eVoteNo382 ; |
72 | 389 | LLDB_LOGF(log, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", |
73 | 389 | vote); |
74 | 389 | return vote; |
75 | 389 | } |
76 | | |
77 | 521 | void ThreadPlanStepRange::AddRange(const AddressRange &new_range) { |
78 | | // For now I'm just adding the ranges. At some point we may want to condense |
79 | | // the ranges if they overlap, though I don't think it is likely to be very |
80 | | // important. |
81 | 521 | m_address_ranges.push_back(new_range); |
82 | | |
83 | | // Fill the slot for this address range with an empty DisassemblerSP in the |
84 | | // instruction ranges. I want the indices to match, but I don't want to do |
85 | | // the work to disassemble this range if I don't step into it. |
86 | 521 | m_instruction_ranges.push_back(DisassemblerSP()); |
87 | 521 | } |
88 | | |
89 | 0 | void ThreadPlanStepRange::DumpRanges(Stream *s) { |
90 | 0 | size_t num_ranges = m_address_ranges.size(); |
91 | 0 | if (num_ranges == 1) { |
92 | 0 | m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); |
93 | 0 | } else { |
94 | 0 | for (size_t i = 0; i < num_ranges; i++) { |
95 | 0 | s->Printf(" %" PRIu64 ": ", uint64_t(i)); |
96 | 0 | m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); |
97 | 0 | } |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | 806 | bool ThreadPlanStepRange::InRange() { |
102 | 806 | Log *log = GetLog(LLDBLog::Step); |
103 | 806 | bool ret_value = false; |
104 | 806 | Thread &thread = GetThread(); |
105 | 806 | lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC(); |
106 | | |
107 | 806 | size_t num_ranges = m_address_ranges.size(); |
108 | 1.38k | for (size_t i = 0; i < num_ranges; i++580 ) { |
109 | 915 | ret_value = |
110 | 915 | m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget()); |
111 | 915 | if (ret_value) |
112 | 335 | break; |
113 | 915 | } |
114 | | |
115 | 806 | if (!ret_value && !m_given_ranges_only471 ) { |
116 | | // See if we've just stepped to another part of the same line number... |
117 | 471 | StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); |
118 | | |
119 | 471 | SymbolContext new_context( |
120 | 471 | frame->GetSymbolContext(eSymbolContextEverything)); |
121 | 471 | if (m_addr_context.line_entry.IsValid() && |
122 | 471 | new_context.line_entry.IsValid()) { |
123 | 471 | if (m_addr_context.line_entry.original_file == |
124 | 471 | new_context.line_entry.original_file) { |
125 | 471 | if (m_addr_context.line_entry.line == new_context.line_entry.line) { |
126 | 94 | m_addr_context = new_context; |
127 | 94 | const bool include_inlined_functions = |
128 | 94 | GetKind() == eKindStepOverRange; |
129 | 94 | AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange( |
130 | 94 | include_inlined_functions)); |
131 | 94 | ret_value = true; |
132 | 94 | if (log) { |
133 | 0 | StreamString s; |
134 | 0 | m_addr_context.line_entry.Dump(&s, &GetTarget(), true, |
135 | 0 | Address::DumpStyleLoadAddress, |
136 | 0 | Address::DumpStyleLoadAddress, true); |
137 | |
|
138 | 0 | LLDB_LOGF( |
139 | 0 | log, |
140 | 0 | "Step range plan stepped to another range of same line: %s", |
141 | 0 | s.GetData()); |
142 | 0 | } |
143 | 377 | } else if (new_context.line_entry.line == 0) { |
144 | 0 | new_context.line_entry.line = m_addr_context.line_entry.line; |
145 | 0 | m_addr_context = new_context; |
146 | 0 | const bool include_inlined_functions = |
147 | 0 | GetKind() == eKindStepOverRange; |
148 | 0 | AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange( |
149 | 0 | include_inlined_functions)); |
150 | 0 | ret_value = true; |
151 | 0 | if (log) { |
152 | 0 | StreamString s; |
153 | 0 | m_addr_context.line_entry.Dump(&s, &GetTarget(), true, |
154 | 0 | Address::DumpStyleLoadAddress, |
155 | 0 | Address::DumpStyleLoadAddress, true); |
156 | |
|
157 | 0 | LLDB_LOGF(log, |
158 | 0 | "Step range plan stepped to a range at linenumber 0 " |
159 | 0 | "stepping through that range: %s", |
160 | 0 | s.GetData()); |
161 | 0 | } |
162 | 377 | } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress( |
163 | 377 | &GetTarget()) != pc_load_addr) { |
164 | | // Another thing that sometimes happens here is that we step out of |
165 | | // one line into the MIDDLE of another line. So far I mostly see |
166 | | // this due to bugs in the debug information. But we probably don't |
167 | | // want to be in the middle of a line range, so in that case reset |
168 | | // the stepping range to the line we've stepped into the middle of |
169 | | // and continue. |
170 | 0 | m_addr_context = new_context; |
171 | 0 | m_address_ranges.clear(); |
172 | 0 | AddRange(m_addr_context.line_entry.range); |
173 | 0 | ret_value = true; |
174 | 0 | if (log) { |
175 | 0 | StreamString s; |
176 | 0 | m_addr_context.line_entry.Dump(&s, &GetTarget(), true, |
177 | 0 | Address::DumpStyleLoadAddress, |
178 | 0 | Address::DumpStyleLoadAddress, true); |
179 | |
|
180 | 0 | LLDB_LOGF(log, |
181 | 0 | "Step range plan stepped to the middle of new " |
182 | 0 | "line(%d): %s, continuing to clear this line.", |
183 | 0 | new_context.line_entry.line, s.GetData()); |
184 | 0 | } |
185 | 0 | } |
186 | 471 | } |
187 | 471 | } |
188 | 471 | } |
189 | | |
190 | 806 | if (!ret_value && log377 ) |
191 | 0 | LLDB_LOGF(log, "Step range plan out of range to 0x%" PRIx64, pc_load_addr); |
192 | | |
193 | 806 | return ret_value; |
194 | 806 | } |
195 | | |
196 | 653 | bool ThreadPlanStepRange::InSymbol() { |
197 | 653 | lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC(); |
198 | 653 | if (m_addr_context.function != nullptr) { |
199 | 653 | return m_addr_context.function->GetAddressRange().ContainsLoadAddress( |
200 | 653 | cur_pc, &GetTarget()); |
201 | 653 | } else if (0 m_addr_context.symbol0 && m_addr_context.symbol->ValueIsAddress()0 ) { |
202 | 0 | AddressRange range(m_addr_context.symbol->GetAddressRef(), |
203 | 0 | m_addr_context.symbol->GetByteSize()); |
204 | 0 | return range.ContainsLoadAddress(cur_pc, &GetTarget()); |
205 | 0 | } |
206 | 0 | return false; |
207 | 653 | } |
208 | | |
209 | | // FIXME: This should also handle inlining if we aren't going to do inlining in |
210 | | // the |
211 | | // main stack. |
212 | | // |
213 | | // Ideally we should remember the whole stack frame list, and then compare that |
214 | | // to the current list. |
215 | | |
216 | 1.22k | lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() { |
217 | 1.22k | FrameComparison frame_order; |
218 | 1.22k | Thread &thread = GetThread(); |
219 | 1.22k | StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID(); |
220 | | |
221 | 1.22k | if (cur_frame_id == m_stack_id) { |
222 | 806 | frame_order = eFrameCompareEqual; |
223 | 806 | } else if (417 cur_frame_id < m_stack_id417 ) { |
224 | 388 | frame_order = eFrameCompareYounger; |
225 | 388 | } else { |
226 | 29 | StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1); |
227 | 29 | StackID cur_parent_id; |
228 | 29 | if (cur_parent_frame) |
229 | 27 | cur_parent_id = cur_parent_frame->GetStackID(); |
230 | 29 | if (m_parent_stack_id.IsValid() && cur_parent_id.IsValid() && |
231 | 29 | m_parent_stack_id == cur_parent_id27 ) |
232 | 0 | frame_order = eFrameCompareSameParent; |
233 | 29 | else |
234 | 29 | frame_order = eFrameCompareOlder; |
235 | 29 | } |
236 | 1.22k | return frame_order; |
237 | 1.22k | } |
238 | | |
239 | 2.02k | bool ThreadPlanStepRange::StopOthers() { |
240 | 2.02k | switch (m_stop_others) { |
241 | 44 | case lldb::eOnlyThisThread: |
242 | 44 | return true; |
243 | 1.82k | case lldb::eOnlyDuringStepping: |
244 | | // If there is a call in the range of the next branch breakpoint, |
245 | | // then we should always run all threads, since a call can execute |
246 | | // arbitrary code which might for instance take a lock that's held |
247 | | // by another thread. |
248 | 1.82k | return !m_found_calls; |
249 | 161 | case lldb::eAllThreads: |
250 | 161 | return false; |
251 | 2.02k | } |
252 | 0 | llvm_unreachable("Unhandled run mode!"); |
253 | 0 | } |
254 | | |
255 | | InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( |
256 | 776 | lldb::addr_t addr, size_t &range_index, size_t &insn_offset) { |
257 | 776 | size_t num_ranges = m_address_ranges.size(); |
258 | 952 | for (size_t i = 0; i < num_ranges; i++176 ) { |
259 | 942 | if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) { |
260 | | // Some joker added a zero size range to the stepping range... |
261 | 766 | if (m_address_ranges[i].GetByteSize() == 0) |
262 | 0 | return nullptr; |
263 | | |
264 | 766 | if (!m_instruction_ranges[i]) { |
265 | | // Disassemble the address range given: |
266 | 511 | const char *plugin_name = nullptr; |
267 | 511 | const char *flavor = nullptr; |
268 | 511 | m_instruction_ranges[i] = Disassembler::DisassembleRange( |
269 | 511 | GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(), |
270 | 511 | m_address_ranges[i]); |
271 | 511 | } |
272 | 766 | if (!m_instruction_ranges[i]) |
273 | 0 | return nullptr; |
274 | 766 | else { |
275 | | // Find where we are in the instruction list as well. If we aren't at |
276 | | // an instruction, return nullptr. In this case, we're probably lost, |
277 | | // and shouldn't try to do anything fancy. |
278 | | |
279 | 766 | insn_offset = |
280 | 766 | m_instruction_ranges[i] |
281 | 766 | ->GetInstructionList() |
282 | 766 | .GetIndexOfInstructionAtLoadAddress(addr, GetTarget()); |
283 | 766 | if (insn_offset == UINT32_MAX) |
284 | 0 | return nullptr; |
285 | 766 | else { |
286 | 766 | range_index = i; |
287 | 766 | return &m_instruction_ranges[i]->GetInstructionList(); |
288 | 766 | } |
289 | 766 | } |
290 | 766 | } |
291 | 942 | } |
292 | 10 | return nullptr; |
293 | 776 | } |
294 | | |
295 | 1.69k | void ThreadPlanStepRange::ClearNextBranchBreakpoint() { |
296 | 1.69k | if (m_next_branch_bp_sp) { |
297 | 206 | Log *log = GetLog(LLDBLog::Step); |
298 | 206 | LLDB_LOGF(log, "Removing next branch breakpoint: %d.", |
299 | 206 | m_next_branch_bp_sp->GetID()); |
300 | 206 | GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID()); |
301 | 206 | m_next_branch_bp_sp.reset(); |
302 | 206 | m_could_not_resolve_hw_bp = false; |
303 | 206 | m_found_calls = false; |
304 | 206 | } |
305 | 1.69k | } |
306 | | |
307 | 836 | bool ThreadPlanStepRange::SetNextBranchBreakpoint() { |
308 | 836 | if (m_next_branch_bp_sp) |
309 | 60 | return true; |
310 | | |
311 | 776 | Log *log = GetLog(LLDBLog::Step); |
312 | | // Stepping through ranges using breakpoints doesn't work yet, but with this |
313 | | // off we fall back to instruction single stepping. |
314 | 776 | if (!m_use_fast_step) |
315 | 0 | return false; |
316 | | |
317 | | // clear the m_found_calls, we'll rediscover it for this range. |
318 | 776 | m_found_calls = false; |
319 | | |
320 | 776 | lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC(); |
321 | | // Find the current address in our address ranges, and fetch the disassembly |
322 | | // if we haven't already: |
323 | 776 | size_t pc_index; |
324 | 776 | size_t range_index; |
325 | 776 | InstructionList *instructions = |
326 | 776 | GetInstructionsForAddress(cur_addr, range_index, pc_index); |
327 | 776 | if (instructions == nullptr) |
328 | 10 | return false; |
329 | 766 | else { |
330 | 766 | const bool ignore_calls = GetKind() == eKindStepOverRange; |
331 | 766 | uint32_t branch_index = instructions->GetIndexOfNextBranchInstruction( |
332 | 766 | pc_index, ignore_calls, &m_found_calls); |
333 | 766 | Address run_to_address; |
334 | | |
335 | | // If we didn't find a branch, run to the end of the range. |
336 | 766 | if (branch_index == UINT32_MAX) { |
337 | 362 | uint32_t last_index = instructions->GetSize() - 1; |
338 | 362 | if (last_index - pc_index > 1) { |
339 | 101 | InstructionSP last_inst = |
340 | 101 | instructions->GetInstructionAtIndex(last_index); |
341 | 101 | size_t last_inst_size = last_inst->GetOpcode().GetByteSize(); |
342 | 101 | run_to_address = last_inst->GetAddress(); |
343 | 101 | run_to_address.Slide(last_inst_size); |
344 | 101 | } |
345 | 404 | } else if (branch_index - pc_index > 1) { |
346 | 105 | run_to_address = |
347 | 105 | instructions->GetInstructionAtIndex(branch_index)->GetAddress(); |
348 | 105 | } |
349 | | |
350 | 766 | if (run_to_address.IsValid()) { |
351 | 206 | const bool is_internal = true; |
352 | 206 | m_next_branch_bp_sp = |
353 | 206 | GetTarget().CreateBreakpoint(run_to_address, is_internal, false); |
354 | 206 | if (m_next_branch_bp_sp) { |
355 | | |
356 | 206 | if (m_next_branch_bp_sp->IsHardware() && |
357 | 206 | !m_next_branch_bp_sp->HasResolvedLocations()2 ) |
358 | 0 | m_could_not_resolve_hw_bp = true; |
359 | | |
360 | 206 | if (log) { |
361 | 0 | lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID; |
362 | 0 | BreakpointLocationSP bp_loc = |
363 | 0 | m_next_branch_bp_sp->GetLocationAtIndex(0); |
364 | 0 | if (bp_loc) { |
365 | 0 | BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite(); |
366 | 0 | if (bp_site) { |
367 | 0 | bp_site_id = bp_site->GetID(); |
368 | 0 | } |
369 | 0 | } |
370 | 0 | LLDB_LOGF(log, |
371 | 0 | "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting " |
372 | 0 | "breakpoint %d (site %d) to run to address 0x%" PRIx64, |
373 | 0 | m_next_branch_bp_sp->GetID(), bp_site_id, |
374 | 0 | run_to_address.GetLoadAddress(&m_process.GetTarget())); |
375 | 0 | } |
376 | | |
377 | 206 | m_next_branch_bp_sp->SetThreadID(m_tid); |
378 | 206 | m_next_branch_bp_sp->SetBreakpointKind("next-branch-location"); |
379 | | |
380 | 206 | return true; |
381 | 206 | } else |
382 | 0 | return false; |
383 | 206 | } |
384 | 766 | } |
385 | 560 | return false; |
386 | 776 | } |
387 | | |
388 | | bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( |
389 | 227 | lldb::StopInfoSP stop_info_sp) { |
390 | 227 | Log *log = GetLog(LLDBLog::Step); |
391 | 227 | if (!m_next_branch_bp_sp) |
392 | 23 | return false; |
393 | | |
394 | 204 | break_id_t bp_site_id = stop_info_sp->GetValue(); |
395 | 204 | BreakpointSiteSP bp_site_sp = |
396 | 204 | m_process.GetBreakpointSiteList().FindByID(bp_site_id); |
397 | 204 | if (!bp_site_sp) |
398 | 0 | return false; |
399 | 204 | else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID())) |
400 | 6 | return false; |
401 | 198 | else { |
402 | | // If we've hit the next branch breakpoint, then clear it. |
403 | 198 | size_t num_owners = bp_site_sp->GetNumberOfOwners(); |
404 | 198 | bool explains_stop = true; |
405 | | // If all the owners are internal, then we are probably just stepping over |
406 | | // this range from multiple threads, or multiple frames, so we want to |
407 | | // continue. If one is not internal, then we should not explain the stop, |
408 | | // and let the user breakpoint handle the stop. |
409 | 394 | for (size_t i = 0; i < num_owners; i++196 ) { |
410 | 198 | if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { |
411 | 2 | explains_stop = false; |
412 | 2 | break; |
413 | 2 | } |
414 | 198 | } |
415 | 198 | LLDB_LOGF(log, |
416 | 198 | "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit " |
417 | 198 | "next range breakpoint which has %" PRIu64 |
418 | 198 | " owners - explains stop: %u.", |
419 | 198 | (uint64_t)num_owners, explains_stop); |
420 | 198 | ClearNextBranchBreakpoint(); |
421 | 198 | return explains_stop; |
422 | 198 | } |
423 | 204 | } |
424 | | |
425 | 418 | bool ThreadPlanStepRange::WillStop() { return true; } |
426 | | |
427 | 1.27k | StateType ThreadPlanStepRange::GetPlanRunState() { |
428 | 1.27k | if (m_next_branch_bp_sp) |
429 | 349 | return eStateRunning; |
430 | 922 | else |
431 | 922 | return eStateStepping; |
432 | 1.27k | } |
433 | | |
434 | 1.05k | bool ThreadPlanStepRange::MischiefManaged() { |
435 | | // If we have pushed some plans between ShouldStop & MischiefManaged, then |
436 | | // we're not done... |
437 | | // I do this check first because we might have stepped somewhere that will |
438 | | // fool InRange into |
439 | | // thinking it needs to step past the end of that line. This happens, for |
440 | | // instance, when stepping over inlined code that is in the middle of the |
441 | | // current line. |
442 | | |
443 | 1.05k | if (!m_no_more_plans) |
444 | 668 | return false; |
445 | | |
446 | 383 | bool done = true; |
447 | 383 | if (!IsPlanComplete()) { |
448 | 0 | if (InRange()) { |
449 | 0 | done = false; |
450 | 0 | } else { |
451 | 0 | FrameComparison frame_order = CompareCurrentFrameToStartFrame(); |
452 | 0 | done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true; |
453 | 0 | } |
454 | 0 | } |
455 | | |
456 | 383 | if (done) { |
457 | 383 | Log *log = GetLog(LLDBLog::Step); |
458 | 383 | LLDB_LOGF(log, "Completed step through range plan."); |
459 | 383 | ClearNextBranchBreakpoint(); |
460 | 383 | ThreadPlan::MischiefManaged(); |
461 | 383 | return true; |
462 | 383 | } else { |
463 | 0 | return false; |
464 | 0 | } |
465 | 383 | } |
466 | | |
467 | 72 | bool ThreadPlanStepRange::IsPlanStale() { |
468 | 72 | Log *log = GetLog(LLDBLog::Step); |
469 | 72 | FrameComparison frame_order = CompareCurrentFrameToStartFrame(); |
470 | | |
471 | 72 | if (frame_order == eFrameCompareOlder) { |
472 | 0 | if (log) { |
473 | 0 | LLDB_LOGF(log, "ThreadPlanStepRange::IsPlanStale returning true, we've " |
474 | 0 | "stepped out."); |
475 | 0 | } |
476 | 0 | return true; |
477 | 72 | } else if (frame_order == eFrameCompareEqual && InSymbol()38 ) { |
478 | | // If we are not in a place we should step through, we've gotten stale. One |
479 | | // tricky bit here is that some stubs don't push a frame, so we should. |
480 | | // check that we are in the same symbol. |
481 | 38 | if (!InRange()) { |
482 | | // Set plan Complete when we reach next instruction just after the range |
483 | 18 | lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1; |
484 | 18 | size_t num_ranges = m_address_ranges.size(); |
485 | 36 | for (size_t i = 0; i < num_ranges; i++18 ) { |
486 | 18 | bool in_range = |
487 | 18 | m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()); |
488 | 18 | if (in_range) { |
489 | 18 | SetPlanComplete(); |
490 | 18 | } |
491 | 18 | } |
492 | 18 | return true; |
493 | 18 | } |
494 | 38 | } |
495 | 54 | return false; |
496 | 72 | } |