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