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/Core/Disassembler.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/Stream.h"
21 #include "lldb/Symbol/Function.h"
22 #include "lldb/Symbol/Symbol.h"
23 #include "lldb/Target/ExecutionContext.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Target/RegisterContext.h"
26 #include "lldb/Target/StopInfo.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Target/Thread.h"
29 #include "lldb/Target/ThreadPlanRunToAddress.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 
35 //----------------------------------------------------------------------
36 // ThreadPlanStepRange: Step through a stack range, either stepping over or into
37 // based on the value of \a type.
38 //----------------------------------------------------------------------
39 
40 ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
41                                           const char *name,
42                                           Thread &thread,
43                                           const AddressRange &range,
44                                           const SymbolContext &addr_context,
45                                           lldb::RunMode stop_others) :
46     ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
47     m_addr_context (addr_context),
48     m_address_ranges (),
49     m_stop_others (stop_others),
50     m_stack_id (),
51     m_no_more_plans (false),
52     m_first_run_event (true)
53 {
54     AddRange(range);
55     m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
56 }
57 
58 ThreadPlanStepRange::~ThreadPlanStepRange ()
59 {
60     ClearNextBranchBreakpoint();
61 }
62 
63 void
64 ThreadPlanStepRange::DidPush ()
65 {
66     // See if we can find a "next range" breakpoint:
67     SetNextBranchBreakpoint();
68 }
69 
70 bool
71 ThreadPlanStepRange::ValidatePlan (Stream *error)
72 {
73     return true;
74 }
75 
76 Vote
77 ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
78 {
79     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
80 
81     const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
82     if (log)
83         log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
84     return vote;
85 }
86 
87 void
88 ThreadPlanStepRange::AddRange(const AddressRange &new_range)
89 {
90     // For now I'm just adding the ranges.  At some point we may want to
91     // condense the ranges if they overlap, though I don't think it is likely
92     // to be very important.
93     m_address_ranges.push_back (new_range);
94     m_instruction_ranges.push_back (DisassemblerSP());
95 }
96 
97 void
98 ThreadPlanStepRange::DumpRanges(Stream *s)
99 {
100     size_t num_ranges = m_address_ranges.size();
101     if (num_ranges == 1)
102     {
103         m_address_ranges[0].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
104     }
105     else
106     {
107         for (size_t i = 0; i < num_ranges; i++)
108         {
109             s->PutCString("%d: ");
110             m_address_ranges[i].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
111         }
112     }
113 }
114 
115 bool
116 ThreadPlanStepRange::InRange ()
117 {
118     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
119     bool ret_value = false;
120 
121     lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
122 
123     size_t num_ranges = m_address_ranges.size();
124     for (size_t i = 0; i < num_ranges; i++)
125     {
126         ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get());
127         if (ret_value)
128             break;
129     }
130 
131     if (!ret_value)
132     {
133         // See if we've just stepped to another part of the same line number...
134         StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
135 
136         SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
137         if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
138         {
139             if (m_addr_context.line_entry.file == new_context.line_entry.file)
140             {
141                 if (m_addr_context.line_entry.line == new_context.line_entry.line)
142                 {
143                     m_addr_context = new_context;
144                     AddRange(m_addr_context.line_entry.range);
145                     ret_value = true;
146                     if (log)
147                     {
148                         StreamString s;
149                         m_addr_context.line_entry.range.Dump (&s,
150                                                               m_thread.CalculateTarget().get(),
151                                                               Address::DumpStyleLoadAddress);
152 
153                         log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
154                     }
155                 }
156                 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get())
157                          != pc_load_addr)
158                 {
159                     // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
160                     // line.  So far I mostly see this due to bugs in the debug information.
161                     // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
162                     // range to the line we've stepped into the middle of and continue.
163                     m_addr_context = new_context;
164                     m_address_ranges.clear();
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.range.Dump (&s,
171                                                               m_thread.CalculateTarget().get(),
172                                                               Address::DumpStyleLoadAddress);
173 
174                         log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
175                                      new_context.line_entry.line,
176                                      s.GetData());
177                     }
178 
179                 }
180             }
181 
182         }
183 
184     }
185 
186     if (!ret_value && log)
187         log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
188 
189     return ret_value;
190 }
191 
192 bool
193 ThreadPlanStepRange::InSymbol()
194 {
195     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
196     if (m_addr_context.function != NULL)
197     {
198         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
199     }
200     else if (m_addr_context.symbol)
201     {
202         AddressRange range(m_addr_context.symbol->GetAddress(), m_addr_context.symbol->GetByteSize());
203         return range.ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
204     }
205     return false;
206 }
207 
208 // FIXME: This should also handle inlining if we aren't going to do inlining in the
209 // main stack.
210 //
211 // Ideally we should remember the whole stack frame list, and then compare that
212 // to the current list.
213 
214 lldb::FrameComparison
215 ThreadPlanStepRange::CompareCurrentFrameToStartFrame()
216 {
217     FrameComparison frame_order;
218 
219     StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
220 
221     if (cur_frame_id == m_stack_id)
222     {
223         frame_order = eFrameCompareEqual;
224     }
225     else if (cur_frame_id < m_stack_id)
226     {
227         frame_order = eFrameCompareYounger;
228     }
229     else
230     {
231         frame_order = eFrameCompareOlder;
232     }
233     return frame_order;
234 }
235 
236 bool
237 ThreadPlanStepRange::StopOthers ()
238 {
239     if (m_stop_others == lldb::eOnlyThisThread
240         || m_stop_others == lldb::eOnlyDuringStepping)
241         return true;
242     else
243         return false;
244 }
245 
246 InstructionList *
247 ThreadPlanStepRange::GetInstructionsForAddress(lldb::addr_t addr, size_t &range_index, size_t &insn_offset)
248 {
249     size_t num_ranges = m_address_ranges.size();
250     for (size_t i = 0; i < num_ranges; i++)
251     {
252         if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()))
253         {
254             // Some joker added a zero size range to the stepping range...
255             if (m_address_ranges[i].GetByteSize() == 0)
256                 return NULL;
257 
258             if (!m_instruction_ranges[i])
259             {
260                 //Disassemble the address range given:
261                 ExecutionContext exe_ctx (m_thread.GetProcess());
262                 m_instruction_ranges[i] = Disassembler::DisassembleRange(GetTarget().GetArchitecture(),
263                                                                          NULL,
264                                                                          exe_ctx,
265                                                                          m_address_ranges[i]);
266 
267             }
268             if (!m_instruction_ranges[i])
269                 return NULL;
270             else
271             {
272                 // Find where we are in the instruction list as well.  If we aren't at an instruction,
273                 // return NULL.  In this case, we're probably lost, and shouldn't try to do anything fancy.
274 
275                 insn_offset = m_instruction_ranges[i]->GetInstructionList().GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
276                 if (insn_offset == UINT32_MAX)
277                     return NULL;
278                 else
279                 {
280                     range_index = i;
281                     return &m_instruction_ranges[i]->GetInstructionList();
282                 }
283             }
284         }
285     }
286     return NULL;
287 }
288 
289 void
290 ThreadPlanStepRange::ClearNextBranchBreakpoint()
291 {
292     if (m_next_branch_bp_sp)
293     {
294         GetTarget().RemoveBreakpointByID (m_next_branch_bp_sp->GetID());
295         m_next_branch_bp_sp.reset();
296     }
297 }
298 
299 bool
300 ThreadPlanStepRange::SetNextBranchBreakpoint ()
301 {
302     // Stepping through ranges using breakpoints doesn't work yet, but with this off we fall back to instruction
303     // single stepping.
304     return false;
305     // Always clear the next branch breakpoint, we don't want to leave one of these stranded.
306     ClearNextBranchBreakpoint();
307     lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
308     // Find the current address in our address ranges, and fetch the disassembly if we haven't already:
309     size_t pc_index;
310     size_t range_index;
311     InstructionList *instructions = GetInstructionsForAddress (cur_addr, range_index, pc_index);
312     if (instructions == NULL)
313         return false;
314     else
315     {
316         uint32_t branch_index;
317         branch_index = instructions->GetIndexOfNextBranchInstruction (pc_index);
318 
319         Address run_to_address;
320 
321         // If we didn't find a branch, run to the end of the range.
322         if (branch_index == UINT32_MAX)
323         {
324             branch_index = instructions->GetSize() - 2;
325         }
326         if (branch_index - pc_index > 1)
327         {
328             const bool is_internal = true;
329             run_to_address = instructions->GetInstructionAtIndex(branch_index)->GetAddress();
330             m_next_branch_bp_sp = GetTarget().CreateBreakpoint(run_to_address, is_internal);
331             m_next_branch_bp_sp->SetThreadID(m_thread.GetID());
332             return true;
333         }
334     }
335     return false;
336 }
337 
338 bool
339 ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info_sp)
340 {
341     if (!m_next_branch_bp_sp)
342         return false;
343 
344     break_id_t bp_site_id = stop_info_sp->GetValue();
345     BreakpointSiteSP bp_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id);
346     if (!bp_site_sp->IsBreakpointAtThisSite (m_next_branch_bp_sp->GetID()))
347         return false;
348     else
349         return bp_site_sp->GetNumberOfOwners() == 1;
350 }
351 
352 bool
353 ThreadPlanStepRange::PlanExplainsStop ()
354 {
355     // We always explain a stop.  Either we've just done a single step, in which
356     // case we'll do our ordinary processing, or we stopped for some
357     // reason that isn't handled by our sub-plans, in which case we want to just stop right
358     // away.
359 
360     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
361     StopInfoSP stop_info_sp = GetPrivateStopReason();
362     if (stop_info_sp)
363     {
364         StopReason reason = stop_info_sp->GetStopReason();
365 
366         switch (reason)
367         {
368         case eStopReasonBreakpoint:
369             if (NextRangeBreakpointExplainsStop(stop_info_sp))
370                 return true;
371         case eStopReasonWatchpoint:
372         case eStopReasonSignal:
373         case eStopReasonException:
374             if (log)
375                 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
376             SetPlanComplete();
377             break;
378         default:
379             break;
380         }
381     }
382     return true;
383 }
384 
385 bool
386 ThreadPlanStepRange::WillStop ()
387 {
388     return true;
389 }
390 
391 StateType
392 ThreadPlanStepRange::GetPlanRunState ()
393 {
394     if (m_next_branch_bp_sp)
395         return eStateRunning;
396     else
397         return eStateStepping;
398 }
399 
400 bool
401 ThreadPlanStepRange::MischiefManaged ()
402 {
403     bool done = true;
404     if (!IsPlanComplete())
405     {
406         if (InRange())
407         {
408             done = false;
409         }
410         else
411         {
412             FrameComparison frame_order = CompareCurrentFrameToStartFrame();
413             if (frame_order != eFrameCompareOlder)
414             {
415                 if (m_no_more_plans)
416                     done = true;
417                 else
418                     done = false;
419             }
420             else
421                 done = true;
422         }
423     }
424 
425     if (done)
426     {
427         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
428         if (log)
429             log->Printf("Completed step through range plan.");
430         ThreadPlan::MischiefManaged ();
431         return true;
432     }
433     else
434     {
435         return false;
436     }
437 
438 }
439