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