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_ranges (),
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     AddRange(range);
52     m_stack_depth = m_thread.GetStackFrameCount();
53     m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
54 }
55 
56 ThreadPlanStepRange::~ThreadPlanStepRange ()
57 {
58 }
59 
60 bool
61 ThreadPlanStepRange::ValidatePlan (Stream *error)
62 {
63     return true;
64 }
65 
66 Vote
67 ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
68 {
69     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
70 
71     const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
72     if (log)
73         log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
74     return vote;
75 }
76 
77 void
78 ThreadPlanStepRange::AddRange(const AddressRange &new_range)
79 {
80     // For now I'm just adding the ranges.  At some point we may want to
81     // condense the ranges if they overlap, though I don't think it is likely
82     // to be very important.
83     m_address_ranges.push_back (new_range);
84 }
85 
86 void
87 ThreadPlanStepRange::DumpRanges(Stream *s)
88 {
89     size_t num_ranges = m_address_ranges.size();
90     if (num_ranges == 1)
91     {
92         m_address_ranges[0].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
93     }
94     else
95     {
96         for (size_t i = 0; i < num_ranges; i++)
97         {
98             s->PutCString("%d: ");
99             m_address_ranges[i].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
100         }
101     }
102 }
103 
104 bool
105 ThreadPlanStepRange::InRange ()
106 {
107     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
108     bool ret_value = false;
109 
110     lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
111 
112     size_t num_ranges = m_address_ranges.size();
113     for (size_t i = 0; i < num_ranges; i++)
114     {
115         ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess().GetTarget());
116         if (ret_value)
117             break;
118     }
119 
120     if (!ret_value)
121     {
122         // See if we've just stepped to another part of the same line number...
123         StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
124 
125         SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
126         if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
127         {
128             if (m_addr_context.line_entry.file == new_context.line_entry.file)
129             {
130                 if (m_addr_context.line_entry.line == new_context.line_entry.line)
131                 {
132                     m_addr_context = new_context;
133                     AddRange(m_addr_context.line_entry.range);
134                     ret_value = true;
135                     if (log)
136                     {
137                         StreamString s;
138                         m_addr_context.line_entry.range.Dump (&s,
139                                                               &m_thread.GetProcess().GetTarget(),
140                                                               Address::DumpStyleLoadAddress);
141 
142                         log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
143                     }
144                 }
145                 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget())
146                          != pc_load_addr)
147                 {
148                     // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
149                     // line.  So far I mostly see this due to bugs in the debug information.
150                     // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
151                     // range to the line we've stepped into the middle of and continue.
152                     m_addr_context = new_context;
153                     m_address_ranges.clear();
154                     AddRange(m_addr_context.line_entry.range);
155                     ret_value = true;
156                     if (log)
157                     {
158                         StreamString s;
159                         m_addr_context.line_entry.range.Dump (&s,
160                                                               &m_thread.GetProcess().GetTarget(),
161                                                               Address::DumpStyleLoadAddress);
162 
163                         log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
164                                      new_context.line_entry.line,
165                                      s.GetData());
166                     }
167 
168                 }
169             }
170 
171         }
172 
173     }
174 
175     if (!ret_value && log)
176         log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
177 
178     return ret_value;
179 }
180 
181 bool
182 ThreadPlanStepRange::InSymbol()
183 {
184     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
185     if (m_addr_context.function != NULL)
186     {
187         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
188     }
189     else if (m_addr_context.symbol != NULL)
190     {
191         return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
192     }
193     return false;
194 }
195 
196 // FIXME: This should also handle inlining if we aren't going to do inlining in the
197 // main stack.
198 //
199 // Ideally we should remember the whole stack frame list, and then compare that
200 // to the current list.
201 
202 bool
203 ThreadPlanStepRange::FrameIsYounger ()
204 {
205     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
206 
207     // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above
208     // us on the stack.  Counting the whole stack could be expensive.
209 
210     uint32_t current_depth = m_thread.GetStackFrameCount();
211     if (current_depth == m_stack_depth)
212     {
213         if (log)
214             log->Printf ("Step range FrameIsYounger still in start function.");
215         return false;
216     }
217     else if (current_depth < m_stack_depth)
218     {
219         if (log)
220             log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
221         return false;
222     }
223     else
224     {
225         if (log)
226             log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
227         return true;
228     }
229 }
230 
231 bool
232 ThreadPlanStepRange::FrameIsOlder ()
233 {
234     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
235     uint32_t current_depth = m_thread.GetStackFrameCount();
236     if (current_depth == m_stack_depth)
237     {
238         if (log)
239             log->Printf ("Step range FrameIsOlder still in start function.");
240         return false;
241     }
242     else if (current_depth < m_stack_depth)
243     {
244         if (log)
245             log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
246         return true;
247     }
248     else
249     {
250         if (log)
251             log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
252         return false;
253     }
254 }
255 
256 bool
257 ThreadPlanStepRange::StopOthers ()
258 {
259     if (m_stop_others == lldb::eOnlyThisThread
260         || m_stop_others == lldb::eOnlyDuringStepping)
261         return true;
262     else
263         return false;
264 }
265 
266 bool
267 ThreadPlanStepRange::WillStop ()
268 {
269     return true;
270 }
271 
272 StateType
273 ThreadPlanStepRange::GetPlanRunState ()
274 {
275     return eStateStepping;
276 }
277 
278 bool
279 ThreadPlanStepRange::MischiefManaged ()
280 {
281     bool done = true;
282     if (!IsPlanComplete())
283     {
284         if (InRange())
285         {
286             done = false;
287         }
288         else if (!FrameIsOlder())
289         {
290             if (m_no_more_plans)
291                 done = true;
292             else
293                 done = false;
294         }
295         else
296             done = true;
297     }
298 
299     if (done)
300     {
301         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
302         if (log)
303             log->Printf("Completed step through range plan.");
304         ThreadPlan::MischiefManaged ();
305         return true;
306     }
307     else
308     {
309         return false;
310     }
311 
312 }
313