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/Target/RegisterContext.h"
21 #include "lldb/Target/Thread.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Symbol/Function.h"
24 #include "lldb/Symbol/Symbol.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 
30 //----------------------------------------------------------------------
31 // ThreadPlanStepRange: Step through a stack range, either stepping over or into
32 // based on the value of \a type.
33 //----------------------------------------------------------------------
34 
35 ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind, const char *name, Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others) :
36     ThreadPlan (ThreadPlan::eKindGeneric, name, thread, eVoteNoOpinion, eVoteNoOpinion),
37     m_address_range (range),
38     m_addr_context (addr_context),
39     m_stop_others (stop_others),
40     m_stack_depth (0),
41     m_no_more_plans (false),
42     m_stack_id (),
43     m_first_run_event (true)
44 {
45     m_stack_depth = m_thread.GetStackFrameCount();
46     m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
47 }
48 
49 ThreadPlanStepRange::~ThreadPlanStepRange ()
50 {
51 }
52 
53 bool
54 ThreadPlanStepRange::ValidatePlan (Stream *error)
55 {
56     return true;
57 }
58 
59 bool
60 ThreadPlanStepRange::PlanExplainsStop ()
61 {
62     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
63     // out will be handled by a child plan.
64     Thread::StopInfo info;
65     if (m_thread.GetStopInfo (&info))
66     {
67         StopReason reason = info.GetStopReason();
68 
69         switch (reason)
70         {
71             case eStopReasonBreakpoint:
72             case eStopReasonWatchpoint:
73             case eStopReasonSignal:
74             case eStopReasonException:
75                 return false;
76             default:
77                 return true;
78         }
79     }
80     return true;
81 }
82 
83 Vote
84 ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
85 {
86     if (IsPlanComplete())
87         return eVoteYes;
88     else
89         return eVoteNo;
90 }
91 
92 bool
93 ThreadPlanStepRange::InRange ()
94 {
95     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
96     bool ret_value = false;
97 
98     lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
99 
100     ret_value = m_address_range.ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess());
101 
102     if (!ret_value)
103     {
104         // See if we've just stepped to another part of the same line number...
105         StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
106 
107         SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
108         if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
109         {
110            if ((m_addr_context.line_entry.file == new_context.line_entry.file)
111                && (m_addr_context.line_entry.line == new_context.line_entry.line))
112             {
113                 m_addr_context = new_context;
114                 m_address_range = m_addr_context.line_entry.range;
115                 ret_value = true;
116                 if (log)
117                 {
118                     StreamString s;
119                     m_address_range.Dump (&s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
120 
121                     log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
122                 }
123             }
124         }
125 
126     }
127 
128     if (!ret_value && log)
129         log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
130 
131     return ret_value;
132 }
133 
134 bool
135 ThreadPlanStepRange::InSymbol()
136 {
137     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
138     Process *process = m_thread.CalculateProcess();
139 
140     if (m_addr_context.function != NULL)
141     {
142         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, process);
143     }
144     else if (m_addr_context.symbol != NULL)
145     {
146         return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, process);
147     }
148     return false;
149 }
150 
151 // FIXME: This should also handle inlining if we aren't going to do inlining in the
152 // main stack.
153 //
154 // Ideally we should remember the whole stack frame list, and then compare that
155 // to the current list.
156 
157 bool
158 ThreadPlanStepRange::FrameIsYounger ()
159 {
160     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
161     uint32_t current_depth = m_thread.GetStackFrameCount();
162     if (current_depth == m_stack_depth)
163     {
164         if (log)
165             log->Printf ("Step range FrameIsYounger still in start function.");
166         return false;
167     }
168     else if (current_depth < m_stack_depth)
169     {
170         if (log)
171             log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
172         return false;
173     }
174     else
175     {
176         if (log)
177             log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
178         return true;
179     }
180 }
181 
182 bool
183 ThreadPlanStepRange::FrameIsOlder ()
184 {
185     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
186     uint32_t current_depth = m_thread.GetStackFrameCount();
187     if (current_depth == m_stack_depth)
188     {
189         if (log)
190             log->Printf ("Step range FrameIsOlder still in start function.");
191         return false;
192     }
193     else if (current_depth < m_stack_depth)
194     {
195         if (log)
196             log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
197         return true;
198     }
199     else
200     {
201         if (log)
202             log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
203         return false;
204     }
205 }
206 
207 bool
208 ThreadPlanStepRange::StopOthers ()
209 {
210     if (m_stop_others == lldb::eOnlyThisThread
211         || m_stop_others == lldb::eOnlyDuringStepping)
212         return true;
213     else
214         return false;
215 }
216 
217 bool
218 ThreadPlanStepRange::WillStop ()
219 {
220     return true;
221 }
222 
223 StateType
224 ThreadPlanStepRange::RunState ()
225 {
226     return eStateStepping;
227 }
228 
229 bool
230 ThreadPlanStepRange::MischiefManaged ()
231 {
232     bool done = true;
233     if (!IsPlanComplete())
234     {
235         if (InRange())
236         {
237             done = false;
238         }
239         else if (!FrameIsOlder())
240         {
241             if (m_no_more_plans)
242                 done = true;
243             else
244                 done = false;
245         }
246         else
247             done = true;
248     }
249 
250     if (done)
251     {
252         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
253         if (log)
254             log->Printf("Completed step through range plan.");
255         ThreadPlan::MischiefManaged ();
256         return true;
257     }
258     else
259     {
260         return false;
261     }
262 
263 }
264