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