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/Log.h"
19 #include "lldb/Core/Stream.h"
20 #include "lldb/Symbol/Function.h"
21 #include "lldb/Symbol/Symbol.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/RegisterContext.h"
24 #include "lldb/Target/StopInfo.h"
25 #include "lldb/Target/Thread.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 
31 //----------------------------------------------------------------------
32 // ThreadPlanStepRange: Step through a stack range, either stepping over or into
33 // based on the value of \a type.
34 //----------------------------------------------------------------------
35 
36 ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
37                                           const char *name,
38                                           Thread &thread,
39                                           const AddressRange &range,
40                                           const SymbolContext &addr_context,
41                                           lldb::RunMode stop_others) :
42     ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
43     m_addr_context (addr_context),
44     m_address_ranges (),
45     m_stop_others (stop_others),
46     m_stack_depth (0),
47     m_stack_id (),
48     m_no_more_plans (false),
49     m_first_run_event (true)
50 {
51     AddRange(range);
52     m_stack_depth = m_thread.GetStackFrameCount();
53     m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
54 }
55 
56 ThreadPlanStepRange::~ThreadPlanStepRange ()
57 {
58 }
59 
60 bool
61 ThreadPlanStepRange::ValidatePlan (Stream *error)
62 {
63     return true;
64 }
65 
66 bool
67 ThreadPlanStepRange::PlanExplainsStop ()
68 {
69     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
70     // out will be handled by a child plan.
71     StopInfoSP stop_info_sp = GetPrivateStopReason();
72     if (stop_info_sp)
73     {
74         StopReason reason = stop_info_sp->GetStopReason();
75 
76         switch (reason)
77         {
78         case eStopReasonBreakpoint:
79         case eStopReasonWatchpoint:
80         case eStopReasonSignal:
81         case eStopReasonException:
82             return false;
83         default:
84             return true;
85         }
86     }
87     return true;
88 }
89 
90 Vote
91 ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
92 {
93     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
94 
95     const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
96     if (log)
97         log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
98     return vote;
99 }
100 
101 void
102 ThreadPlanStepRange::AddRange(const AddressRange &new_range)
103 {
104     // For now I'm just adding the ranges.  At some point we may want to
105     // condense the ranges if they overlap, though I don't think it is likely
106     // to be very important.
107     m_address_ranges.push_back (new_range);
108 }
109 
110 void
111 ThreadPlanStepRange::DumpRanges(Stream *s)
112 {
113     size_t num_ranges = m_address_ranges.size();
114     if (num_ranges == 1)
115     {
116         m_address_ranges[0].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
117     }
118     else
119     {
120         for (size_t i = 0; i < num_ranges; i++)
121         {
122             s->PutCString("%d: ");
123             m_address_ranges[i].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
124         }
125     }
126 }
127 
128 bool
129 ThreadPlanStepRange::InRange ()
130 {
131     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
132     bool ret_value = false;
133 
134     lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
135 
136     size_t num_ranges = m_address_ranges.size();
137     for (size_t i = 0; i < num_ranges; i++)
138     {
139         ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess().GetTarget());
140         if (ret_value)
141             break;
142     }
143 
144     if (!ret_value)
145     {
146         // See if we've just stepped to another part of the same line number...
147         StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
148 
149         SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
150         if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
151         {
152             if (m_addr_context.line_entry.file == new_context.line_entry.file)
153             {
154                 if (m_addr_context.line_entry.line == new_context.line_entry.line)
155                 {
156                     m_addr_context = new_context;
157                     AddRange(m_addr_context.line_entry.range);
158                     ret_value = true;
159                     if (log)
160                     {
161                         StreamString s;
162                         m_addr_context.line_entry.range.Dump (&s,
163                                                               &m_thread.GetProcess().GetTarget(),
164                                                               Address::DumpStyleLoadAddress);
165 
166                         log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
167                     }
168                 }
169                 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget())
170                          != pc_load_addr)
171                 {
172                     // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
173                     // line.  So far I mostly see this due to bugs in the debug information.
174                     // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
175                     // range to the line we've stepped into the middle of and continue.
176                     m_addr_context = new_context;
177                     m_address_ranges.clear();
178                     AddRange(m_addr_context.line_entry.range);
179                     ret_value = true;
180                     if (log)
181                     {
182                         StreamString s;
183                         m_addr_context.line_entry.range.Dump (&s,
184                                                               &m_thread.GetProcess().GetTarget(),
185                                                               Address::DumpStyleLoadAddress);
186 
187                         log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
188                                      new_context.line_entry.line,
189                                      s.GetData());
190                     }
191 
192                 }
193             }
194 
195         }
196 
197     }
198 
199     if (!ret_value && log)
200         log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
201 
202     return ret_value;
203 }
204 
205 bool
206 ThreadPlanStepRange::InSymbol()
207 {
208     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
209     if (m_addr_context.function != NULL)
210     {
211         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
212     }
213     else if (m_addr_context.symbol != NULL)
214     {
215         return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
216     }
217     return false;
218 }
219 
220 // FIXME: This should also handle inlining if we aren't going to do inlining in the
221 // main stack.
222 //
223 // Ideally we should remember the whole stack frame list, and then compare that
224 // to the current list.
225 
226 bool
227 ThreadPlanStepRange::FrameIsYounger ()
228 {
229     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
230 
231     // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above
232     // us on the stack.  Counting the whole stack could be expensive.
233 
234     uint32_t current_depth = m_thread.GetStackFrameCount();
235     if (current_depth == m_stack_depth)
236     {
237         if (log)
238             log->Printf ("Step range FrameIsYounger still in start function.");
239         return false;
240     }
241     else if (current_depth < m_stack_depth)
242     {
243         if (log)
244             log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
245         return false;
246     }
247     else
248     {
249         if (log)
250             log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
251         return true;
252     }
253 }
254 
255 bool
256 ThreadPlanStepRange::FrameIsOlder ()
257 {
258     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
259     uint32_t current_depth = m_thread.GetStackFrameCount();
260     if (current_depth == m_stack_depth)
261     {
262         if (log)
263             log->Printf ("Step range FrameIsOlder still in start function.");
264         return false;
265     }
266     else if (current_depth < m_stack_depth)
267     {
268         if (log)
269             log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
270         return true;
271     }
272     else
273     {
274         if (log)
275             log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
276         return false;
277     }
278 }
279 
280 bool
281 ThreadPlanStepRange::StopOthers ()
282 {
283     if (m_stop_others == lldb::eOnlyThisThread
284         || m_stop_others == lldb::eOnlyDuringStepping)
285         return true;
286     else
287         return false;
288 }
289 
290 bool
291 ThreadPlanStepRange::WillStop ()
292 {
293     return true;
294 }
295 
296 StateType
297 ThreadPlanStepRange::GetPlanRunState ()
298 {
299     return eStateStepping;
300 }
301 
302 bool
303 ThreadPlanStepRange::MischiefManaged ()
304 {
305     bool done = true;
306     if (!IsPlanComplete())
307     {
308         if (InRange())
309         {
310             done = false;
311         }
312         else if (!FrameIsOlder())
313         {
314             if (m_no_more_plans)
315                 done = true;
316             else
317                 done = false;
318         }
319         else
320             done = true;
321     }
322 
323     if (done)
324     {
325         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
326         if (log)
327             log->Printf("Completed step through range plan.");
328         ThreadPlan::MischiefManaged ();
329         return true;
330     }
331     else
332     {
333         return false;
334     }
335 
336 }
337