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