blob: edf80a57d520d325be5eefc41f760c094dcbf10f [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"
20#include "lldb/Target/RegisterContext.h"
21#include "lldb/Target/Thread.h"
22#include "lldb/Target/Process.h"
23#include "lldb/Symbol/Function.h"
24#include "lldb/Symbol/Symbol.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29
30//----------------------------------------------------------------------
31// ThreadPlanStepRange: Step through a stack range, either stepping over or into
32// based on the value of \a type.
33//----------------------------------------------------------------------
34
35ThreadPlanStepRange::ThreadPlanStepRange (const char *name, Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others) :
36 ThreadPlan (name, thread, eVoteNoOpinion, eVoteNoOpinion),
37 m_address_range (range),
38 m_addr_context (addr_context),
39 m_stop_others (stop_others),
40 m_stack_depth (0),
41 m_no_more_plans (false),
42 m_stack_id (),
43 m_first_run_event (true)
44{
45 m_stack_depth = m_thread.GetStackFrameCount();
46 m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
47}
48
49ThreadPlanStepRange::~ThreadPlanStepRange ()
50{
51}
52
53bool
54ThreadPlanStepRange::ValidatePlan (Stream *error)
55{
56 return true;
57}
58
59bool
60ThreadPlanStepRange::PlanExplainsStop ()
61{
62 // We don't explain signals or breakpoints (breakpoints that handle stepping in or
63 // out will be handled by a child plan.
64 Thread::StopInfo info;
65 if (m_thread.GetStopInfo (&info))
66 {
67 StopReason reason = info.GetStopReason();
68
69 switch (reason)
70 {
71 case eStopReasonBreakpoint:
72 case eStopReasonWatchpoint:
73 case eStopReasonSignal:
74 case eStopReasonException:
75 return false;
76 default:
77 return true;
78 }
79 }
80 return true;
81}
82
83Vote
84ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
85{
86 if (IsPlanComplete())
87 return eVoteYes;
88 else
89 return eVoteNo;
90}
91
92bool
93ThreadPlanStepRange::InRange ()
94{
95 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
96 bool ret_value = false;
97
98 lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
99
100 ret_value = m_address_range.ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess());
101
102 if (!ret_value)
103 {
104 // See if we've just stepped to another part of the same line number...
105 StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
106
107 SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
108 if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
109 {
110 if ((m_addr_context.line_entry.file == new_context.line_entry.file)
111 && (m_addr_context.line_entry.line == new_context.line_entry.line))
112 {
113 m_addr_context = new_context;
114 m_address_range = m_addr_context.line_entry.range;
115 ret_value = true;
116 if (log)
117 {
118 StreamString s;
119 m_address_range.Dump (&s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
120
121 log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
122 }
123 }
124 }
125
126 }
127
128 if (!ret_value && log)
129 log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
130
131 return ret_value;
132}
133
134bool
135ThreadPlanStepRange::InSymbol()
136{
137 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
138 Process *process = m_thread.CalculateProcess();
139
140 if (m_addr_context.function != NULL)
141 {
142 return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, process);
143 }
144 else if (m_addr_context.symbol != NULL)
145 {
146 return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, process);
147 }
148 return false;
149}
150
151// FIXME: This should also handle inlining if we aren't going to do inlining in the
152// main stack.
153//
154// Ideally we should remember the whole stack frame list, and then compare that
155// to the current list.
156
157bool
158ThreadPlanStepRange::FrameIsYounger ()
159{
160 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
161 uint32_t current_depth = m_thread.GetStackFrameCount();
162 if (current_depth == m_stack_depth)
163 {
164 if (log)
165 log->Printf ("Step range FrameIsYounger still in start function.");
166 return false;
167 }
168 else if (current_depth < m_stack_depth)
169 {
170 if (log)
171 log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
172 return false;
173 }
174 else
175 {
176 if (log)
177 log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
178 return true;
179 }
180}
181
182bool
183ThreadPlanStepRange::FrameIsOlder ()
184{
185 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
186 uint32_t current_depth = m_thread.GetStackFrameCount();
187 if (current_depth == m_stack_depth)
188 {
189 if (log)
190 log->Printf ("Step range FrameIsOlder still in start function.");
191 return false;
192 }
193 else if (current_depth < m_stack_depth)
194 {
195 if (log)
196 log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
197 return true;
198 }
199 else
200 {
201 if (log)
202 log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
203 return false;
204 }
205}
206
207bool
208ThreadPlanStepRange::StopOthers ()
209{
210 if (m_stop_others == lldb::eOnlyThisThread
211 || m_stop_others == lldb::eOnlyDuringStepping)
212 return true;
213 else
214 return false;
215}
216
217bool
218ThreadPlanStepRange::WillStop ()
219{
220 return true;
221}
222
223StateType
224ThreadPlanStepRange::RunState ()
225{
226 return eStateStepping;
227}
228
229bool
230ThreadPlanStepRange::MischiefManaged ()
231{
232 bool done = true;
233 if (!IsPlanComplete())
234 {
235 if (InRange())
236 {
237 done = false;
238 }
239 else if (!FrameIsOlder())
240 {
241 if (m_no_more_plans)
242 done = true;
243 else
244 done = false;
245 }
246 else
247 done = true;
248 }
249
250 if (done)
251 {
252 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
253 if (log)
254 log->Printf("Completed step through range plan.");
255 ThreadPlan::MischiefManaged ();
256 return true;
257 }
258 else
259 {
260 return false;
261 }
262
263}