blob: 3e87ffeb8e59f08d6b8d80d745bfe4b582ef6d56 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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"
Chris Lattner24943d22010-06-08 16:52:24 +000020#include "lldb/Symbol/Function.h"
21#include "lldb/Symbol/Symbol.h"
Greg Clayton643ee732010-08-04 01:40:35 +000022#include "lldb/Target/Process.h"
23#include "lldb/Target/RegisterContext.h"
24#include "lldb/Target/StopInfo.h"
25#include "lldb/Target/Thread.h"
Chris Lattner24943d22010-06-08 16:52:24 +000026
27using namespace lldb;
28using 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
Jim Ingham8af1bb72011-02-08 04:27:50 +000036ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
37 const char *name,
38 Thread &thread,
39 const AddressRange &range,
40 const SymbolContext &addr_context,
41 lldb::RunMode stop_others) :
Jim Ingham5b668b52010-07-10 02:23:31 +000042 ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
Chris Lattner24943d22010-06-08 16:52:24 +000043 m_addr_context (addr_context),
Jim Ingham76e55f72011-10-15 00:24:48 +000044 m_address_ranges (),
Chris Lattner24943d22010-06-08 16:52:24 +000045 m_stop_others (stop_others),
46 m_stack_depth (0),
Chris Lattner24943d22010-06-08 16:52:24 +000047 m_stack_id (),
Greg Clayton54e7afa2010-07-09 20:39:50 +000048 m_no_more_plans (false),
Chris Lattner24943d22010-06-08 16:52:24 +000049 m_first_run_event (true)
50{
Jim Ingham76e55f72011-10-15 00:24:48 +000051 AddRange(range);
Chris Lattner24943d22010-06-08 16:52:24 +000052 m_stack_depth = m_thread.GetStackFrameCount();
53 m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
54}
55
56ThreadPlanStepRange::~ThreadPlanStepRange ()
57{
58}
59
60bool
61ThreadPlanStepRange::ValidatePlan (Stream *error)
62{
63 return true;
64}
65
66bool
67ThreadPlanStepRange::PlanExplainsStop ()
68{
69 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
70 // out will be handled by a child plan.
Jim Ingham6297a3a2010-10-20 00:39:53 +000071 StopInfoSP stop_info_sp = GetPrivateStopReason();
72 if (stop_info_sp)
Chris Lattner24943d22010-06-08 16:52:24 +000073 {
Jim Ingham6297a3a2010-10-20 00:39:53 +000074 StopReason reason = stop_info_sp->GetStopReason();
Chris Lattner24943d22010-06-08 16:52:24 +000075
76 switch (reason)
77 {
Greg Clayton643ee732010-08-04 01:40:35 +000078 case eStopReasonBreakpoint:
79 case eStopReasonWatchpoint:
80 case eStopReasonSignal:
81 case eStopReasonException:
82 return false;
83 default:
84 return true;
Chris Lattner24943d22010-06-08 16:52:24 +000085 }
86 }
87 return true;
88}
89
90Vote
91ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
92{
Greg Claytone005f2c2010-11-06 01:53:30 +000093 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Greg Clayton5205f0b2010-09-03 17:10:42 +000094
95 const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
96 if (log)
Greg Clayton590cce32011-01-18 21:44:45 +000097 log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
Greg Clayton5205f0b2010-09-03 17:10:42 +000098 return vote;
Chris Lattner24943d22010-06-08 16:52:24 +000099}
100
Jim Ingham76e55f72011-10-15 00:24:48 +0000101void
102ThreadPlanStepRange::AddRange(const AddressRange &new_range)
103{
104 // For now I'm just adding the ranges. At some point we may want to
105 // condense the ranges if they overlap, though I don't think it is likely
106 // to be very important.
107 m_address_ranges.push_back (new_range);
108}
109
110void
111ThreadPlanStepRange::DumpRanges(Stream *s)
112{
113 size_t num_ranges = m_address_ranges.size();
114 if (num_ranges == 1)
115 {
116 m_address_ranges[0].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
117 }
118 else
119 {
120 for (size_t i = 0; i < num_ranges; i++)
121 {
122 s->PutCString("%d: ");
123 m_address_ranges[i].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
124 }
125 }
126}
127
Chris Lattner24943d22010-06-08 16:52:24 +0000128bool
129ThreadPlanStepRange::InRange ()
130{
Greg Claytone005f2c2010-11-06 01:53:30 +0000131 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000132 bool ret_value = false;
133
134 lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
135
Jim Ingham76e55f72011-10-15 00:24:48 +0000136 size_t num_ranges = m_address_ranges.size();
137 for (size_t i = 0; i < num_ranges; i++)
138 {
139 ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess().GetTarget());
140 if (ret_value)
141 break;
142 }
Chris Lattner24943d22010-06-08 16:52:24 +0000143
144 if (!ret_value)
145 {
146 // See if we've just stepped to another part of the same line number...
147 StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
148
149 SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
150 if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
151 {
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000152 if (m_addr_context.line_entry.file == new_context.line_entry.file)
Chris Lattner24943d22010-06-08 16:52:24 +0000153 {
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000154 if (m_addr_context.line_entry.line == new_context.line_entry.line)
Chris Lattner24943d22010-06-08 16:52:24 +0000155 {
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000156 m_addr_context = new_context;
Jim Ingham76e55f72011-10-15 00:24:48 +0000157 AddRange(m_addr_context.line_entry.range);
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000158 ret_value = true;
159 if (log)
160 {
161 StreamString s;
Jim Ingham76e55f72011-10-15 00:24:48 +0000162 m_addr_context.line_entry.range.Dump (&s,
163 &m_thread.GetProcess().GetTarget(),
164 Address::DumpStyleLoadAddress);
Chris Lattner24943d22010-06-08 16:52:24 +0000165
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000166 log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
167 }
168 }
169 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget())
170 != pc_load_addr)
171 {
172 // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
173 // line. So far I mostly see this due to bugs in the debug information.
174 // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
175 // range to the line we've stepped into the middle of and continue.
176 m_addr_context = new_context;
Jim Ingham76e55f72011-10-15 00:24:48 +0000177 m_address_ranges.clear();
178 AddRange(m_addr_context.line_entry.range);
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000179 ret_value = true;
180 if (log)
181 {
182 StreamString s;
Jim Ingham76e55f72011-10-15 00:24:48 +0000183 m_addr_context.line_entry.range.Dump (&s,
184 &m_thread.GetProcess().GetTarget(),
185 Address::DumpStyleLoadAddress);
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000186
187 log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
188 new_context.line_entry.line,
189 s.GetData());
190 }
191
Chris Lattner24943d22010-06-08 16:52:24 +0000192 }
193 }
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000194
Chris Lattner24943d22010-06-08 16:52:24 +0000195 }
196
197 }
198
199 if (!ret_value && log)
200 log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
201
202 return ret_value;
203}
204
205bool
206ThreadPlanStepRange::InSymbol()
207{
208 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
Chris Lattner24943d22010-06-08 16:52:24 +0000209 if (m_addr_context.function != NULL)
210 {
Greg Claytoneea26402010-09-14 23:36:40 +0000211 return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
Chris Lattner24943d22010-06-08 16:52:24 +0000212 }
213 else if (m_addr_context.symbol != NULL)
214 {
Greg Claytoneea26402010-09-14 23:36:40 +0000215 return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget());
Chris Lattner24943d22010-06-08 16:52:24 +0000216 }
217 return false;
218}
219
220// FIXME: This should also handle inlining if we aren't going to do inlining in the
221// main stack.
222//
223// Ideally we should remember the whole stack frame list, and then compare that
224// to the current list.
225
226bool
227ThreadPlanStepRange::FrameIsYounger ()
228{
Greg Claytone005f2c2010-11-06 01:53:30 +0000229 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Jim Ingham0e81b642010-09-16 00:58:09 +0000230
231 // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above
232 // us on the stack. Counting the whole stack could be expensive.
233
Chris Lattner24943d22010-06-08 16:52:24 +0000234 uint32_t current_depth = m_thread.GetStackFrameCount();
235 if (current_depth == m_stack_depth)
236 {
237 if (log)
238 log->Printf ("Step range FrameIsYounger still in start function.");
239 return false;
240 }
241 else if (current_depth < m_stack_depth)
242 {
243 if (log)
244 log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
245 return false;
246 }
247 else
248 {
249 if (log)
250 log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
251 return true;
252 }
253}
254
255bool
256ThreadPlanStepRange::FrameIsOlder ()
257{
Greg Claytone005f2c2010-11-06 01:53:30 +0000258 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000259 uint32_t current_depth = m_thread.GetStackFrameCount();
260 if (current_depth == m_stack_depth)
261 {
262 if (log)
263 log->Printf ("Step range FrameIsOlder still in start function.");
264 return false;
265 }
266 else if (current_depth < m_stack_depth)
267 {
268 if (log)
269 log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
270 return true;
271 }
272 else
273 {
274 if (log)
275 log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
276 return false;
277 }
278}
279
280bool
281ThreadPlanStepRange::StopOthers ()
282{
283 if (m_stop_others == lldb::eOnlyThisThread
284 || m_stop_others == lldb::eOnlyDuringStepping)
285 return true;
286 else
287 return false;
288}
289
290bool
291ThreadPlanStepRange::WillStop ()
292{
293 return true;
294}
295
296StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000297ThreadPlanStepRange::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000298{
299 return eStateStepping;
300}
301
302bool
303ThreadPlanStepRange::MischiefManaged ()
304{
305 bool done = true;
306 if (!IsPlanComplete())
307 {
308 if (InRange())
309 {
310 done = false;
311 }
312 else if (!FrameIsOlder())
313 {
314 if (m_no_more_plans)
315 done = true;
316 else
317 done = false;
318 }
319 else
320 done = true;
321 }
322
323 if (done)
324 {
Greg Claytone005f2c2010-11-06 01:53:30 +0000325 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000326 if (log)
327 log->Printf("Completed step through range plan.");
328 ThreadPlan::MischiefManaged ();
329 return true;
330 }
331 else
332 {
333 return false;
334 }
335
336}