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             {
120                 if (m_addr_context.line_entry.line == new_context.line_entry.line)
121                 {
122                     m_addr_context = new_context;
123                     m_address_range = m_addr_context.line_entry.range;
124                     ret_value = true;
125                     if (log)
126                     {
127                         StreamString s;
128                         m_address_range.Dump (&s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
129 
130                         log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
131                     }
132                 }
133                 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget())
134                          != pc_load_addr)
135                 {
136                     // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
137                     // line.  So far I mostly see this due to bugs in the debug information.
138                     // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
139                     // range to the line we've stepped into the middle of and continue.
140                     m_addr_context = new_context;
141                     m_address_range = m_addr_context.line_entry.range;
142                     ret_value = true;
143                     if (log)
144                     {
145                         StreamString s;
146                         m_address_range.Dump (&s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
147 
148                         log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
149                                      new_context.line_entry.line,
150                                      s.GetData());
151                     }
152 
153                 }
154             }
155 
156         }
157 
158     }
159 
160     if (!ret_value && log)
161         log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
162 
163     return ret_value;
164 }
165 
166 bool
167 ThreadPlanStepRange::InSymbol()
168 {
169     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
170     if (m_addr_context.function != NULL)
171     {
172         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
173     }
174     else if (m_addr_context.symbol != NULL)
175     {
176         return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
177     }
178     return false;
179 }
180 
181 // FIXME: This should also handle inlining if we aren't going to do inlining in the
182 // main stack.
183 //
184 // Ideally we should remember the whole stack frame list, and then compare that
185 // to the current list.
186 
187 bool
188 ThreadPlanStepRange::FrameIsYounger ()
189 {
190     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
191 
192     // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above
193     // us on the stack.  Counting the whole stack could be expensive.
194 
195     uint32_t current_depth = m_thread.GetStackFrameCount();
196     if (current_depth == m_stack_depth)
197     {
198         if (log)
199             log->Printf ("Step range FrameIsYounger still in start function.");
200         return false;
201     }
202     else if (current_depth < m_stack_depth)
203     {
204         if (log)
205             log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
206         return false;
207     }
208     else
209     {
210         if (log)
211             log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
212         return true;
213     }
214 }
215 
216 bool
217 ThreadPlanStepRange::FrameIsOlder ()
218 {
219     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
220     uint32_t current_depth = m_thread.GetStackFrameCount();
221     if (current_depth == m_stack_depth)
222     {
223         if (log)
224             log->Printf ("Step range FrameIsOlder still in start function.");
225         return false;
226     }
227     else if (current_depth < m_stack_depth)
228     {
229         if (log)
230             log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
231         return true;
232     }
233     else
234     {
235         if (log)
236             log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
237         return false;
238     }
239 }
240 
241 bool
242 ThreadPlanStepRange::StopOthers ()
243 {
244     if (m_stop_others == lldb::eOnlyThisThread
245         || m_stop_others == lldb::eOnlyDuringStepping)
246         return true;
247     else
248         return false;
249 }
250 
251 bool
252 ThreadPlanStepRange::WillStop ()
253 {
254     return true;
255 }
256 
257 StateType
258 ThreadPlanStepRange::GetPlanRunState ()
259 {
260     return eStateStepping;
261 }
262 
263 bool
264 ThreadPlanStepRange::MischiefManaged ()
265 {
266     bool done = true;
267     if (!IsPlanComplete())
268     {
269         if (InRange())
270         {
271             done = false;
272         }
273         else if (!FrameIsOlder())
274         {
275             if (m_no_more_plans)
276                 done = true;
277             else
278                 done = false;
279         }
280         else
281             done = true;
282     }
283 
284     if (done)
285     {
286         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
287         if (log)
288             log->Printf("Completed step through range plan.");
289         ThreadPlan::MischiefManaged ();
290         return true;
291     }
292     else
293     {
294         return false;
295     }
296 
297 }
298