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     StopInfo *stop_info = m_thread.GetStopInfo();
66     if (stop_info)
67     {
68         StopReason reason = stop_info->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     if (IsPlanComplete())
88         return eVoteYes;
89     else
90         return eVoteNo;
91 }
92 
93 bool
94 ThreadPlanStepRange::InRange ()
95 {
96     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
97     bool ret_value = false;
98 
99     lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
100 
101     ret_value = m_address_range.ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess());
102 
103     if (!ret_value)
104     {
105         // See if we've just stepped to another part of the same line number...
106         StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
107 
108         SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
109         if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
110         {
111            if ((m_addr_context.line_entry.file == new_context.line_entry.file)
112                && (m_addr_context.line_entry.line == new_context.line_entry.line))
113             {
114                 m_addr_context = new_context;
115                 m_address_range = m_addr_context.line_entry.range;
116                 ret_value = true;
117                 if (log)
118                 {
119                     StreamString s;
120                     m_address_range.Dump (&s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
121 
122                     log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
123                 }
124             }
125         }
126 
127     }
128 
129     if (!ret_value && log)
130         log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
131 
132     return ret_value;
133 }
134 
135 bool
136 ThreadPlanStepRange::InSymbol()
137 {
138     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
139     Process *process = m_thread.CalculateProcess();
140 
141     if (m_addr_context.function != NULL)
142     {
143         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, process);
144     }
145     else if (m_addr_context.symbol != NULL)
146     {
147         return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, process);
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     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
162     uint32_t current_depth = m_thread.GetStackFrameCount();
163     if (current_depth == m_stack_depth)
164     {
165         if (log)
166             log->Printf ("Step range FrameIsYounger still in start function.");
167         return false;
168     }
169     else if (current_depth < m_stack_depth)
170     {
171         if (log)
172             log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
173         return false;
174     }
175     else
176     {
177         if (log)
178             log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
179         return true;
180     }
181 }
182 
183 bool
184 ThreadPlanStepRange::FrameIsOlder ()
185 {
186     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
187     uint32_t current_depth = m_thread.GetStackFrameCount();
188     if (current_depth == m_stack_depth)
189     {
190         if (log)
191             log->Printf ("Step range FrameIsOlder still in start function.");
192         return false;
193     }
194     else if (current_depth < m_stack_depth)
195     {
196         if (log)
197             log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
198         return true;
199     }
200     else
201     {
202         if (log)
203             log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
204         return false;
205     }
206 }
207 
208 bool
209 ThreadPlanStepRange::StopOthers ()
210 {
211     if (m_stop_others == lldb::eOnlyThisThread
212         || m_stop_others == lldb::eOnlyDuringStepping)
213         return true;
214     else
215         return false;
216 }
217 
218 bool
219 ThreadPlanStepRange::WillStop ()
220 {
221     return true;
222 }
223 
224 StateType
225 ThreadPlanStepRange::RunState ()
226 {
227     return eStateStepping;
228 }
229 
230 bool
231 ThreadPlanStepRange::MischiefManaged ()
232 {
233     bool done = true;
234     if (!IsPlanComplete())
235     {
236         if (InRange())
237         {
238             done = false;
239         }
240         else if (!FrameIsOlder())
241         {
242             if (m_no_more_plans)
243                 done = true;
244             else
245                 done = false;
246         }
247         else
248             done = true;
249     }
250 
251     if (done)
252     {
253         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
254         if (log)
255             log->Printf("Completed step through range plan.");
256         ThreadPlan::MischiefManaged ();
257         return true;
258     }
259     else
260     {
261         return false;
262     }
263 
264 }
265