blob: 01803a169c1e02d2e8d3eeca68534b58af2efa21 [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
Chris Lattner24943d22010-06-08 16:52:24 +000066Vote
67ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
68{
Greg Claytone005f2c2010-11-06 01:53:30 +000069 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Greg Clayton5205f0b2010-09-03 17:10:42 +000070
71 const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
72 if (log)
Greg Clayton590cce32011-01-18 21:44:45 +000073 log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
Greg Clayton5205f0b2010-09-03 17:10:42 +000074 return vote;
Chris Lattner24943d22010-06-08 16:52:24 +000075}
76
Jim Ingham76e55f72011-10-15 00:24:48 +000077void
78ThreadPlanStepRange::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
86void
87ThreadPlanStepRange::DumpRanges(Stream *s)
88{
89 size_t num_ranges = m_address_ranges.size();
90 if (num_ranges == 1)
91 {
Greg Claytonf4124de2012-02-21 00:09:25 +000092 m_address_ranges[0].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
Jim Ingham76e55f72011-10-15 00:24:48 +000093 }
94 else
95 {
96 for (size_t i = 0; i < num_ranges; i++)
97 {
98 s->PutCString("%d: ");
Greg Claytonf4124de2012-02-21 00:09:25 +000099 m_address_ranges[i].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
Jim Ingham76e55f72011-10-15 00:24:48 +0000100 }
101 }
102}
103
Chris Lattner24943d22010-06-08 16:52:24 +0000104bool
105ThreadPlanStepRange::InRange ()
106{
Greg Claytone005f2c2010-11-06 01:53:30 +0000107 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000108 bool ret_value = false;
109
110 lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
111
Jim Ingham76e55f72011-10-15 00:24:48 +0000112 size_t num_ranges = m_address_ranges.size();
113 for (size_t i = 0; i < num_ranges; i++)
114 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000115 ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get());
Jim Ingham76e55f72011-10-15 00:24:48 +0000116 if (ret_value)
117 break;
118 }
Chris Lattner24943d22010-06-08 16:52:24 +0000119
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 {
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000128 if (m_addr_context.line_entry.file == new_context.line_entry.file)
Chris Lattner24943d22010-06-08 16:52:24 +0000129 {
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000130 if (m_addr_context.line_entry.line == new_context.line_entry.line)
Chris Lattner24943d22010-06-08 16:52:24 +0000131 {
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000132 m_addr_context = new_context;
Jim Ingham76e55f72011-10-15 00:24:48 +0000133 AddRange(m_addr_context.line_entry.range);
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000134 ret_value = true;
135 if (log)
136 {
137 StreamString s;
Jim Ingham76e55f72011-10-15 00:24:48 +0000138 m_addr_context.line_entry.range.Dump (&s,
Greg Claytonf4124de2012-02-21 00:09:25 +0000139 m_thread.CalculateTarget().get(),
Jim Ingham76e55f72011-10-15 00:24:48 +0000140 Address::DumpStyleLoadAddress);
Chris Lattner24943d22010-06-08 16:52:24 +0000141
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000142 log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
143 }
144 }
Greg Claytonf4124de2012-02-21 00:09:25 +0000145 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get())
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000146 != 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;
Jim Ingham76e55f72011-10-15 00:24:48 +0000153 m_address_ranges.clear();
154 AddRange(m_addr_context.line_entry.range);
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000155 ret_value = true;
156 if (log)
157 {
158 StreamString s;
Jim Ingham76e55f72011-10-15 00:24:48 +0000159 m_addr_context.line_entry.range.Dump (&s,
Greg Claytonf4124de2012-02-21 00:09:25 +0000160 m_thread.CalculateTarget().get(),
Jim Ingham76e55f72011-10-15 00:24:48 +0000161 Address::DumpStyleLoadAddress);
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000162
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
Chris Lattner24943d22010-06-08 16:52:24 +0000168 }
169 }
Jim Ingham0f4d0f32011-09-23 21:08:11 +0000170
Chris Lattner24943d22010-06-08 16:52:24 +0000171 }
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
181bool
182ThreadPlanStepRange::InSymbol()
183{
184 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
Chris Lattner24943d22010-06-08 16:52:24 +0000185 if (m_addr_context.function != NULL)
186 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000187 return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
Chris Lattner24943d22010-06-08 16:52:24 +0000188 }
189 else if (m_addr_context.symbol != NULL)
190 {
Greg Claytonf4124de2012-02-21 00:09:25 +0000191 return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
Chris Lattner24943d22010-06-08 16:52:24 +0000192 }
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
202bool
203ThreadPlanStepRange::FrameIsYounger ()
204{
Greg Claytone005f2c2010-11-06 01:53:30 +0000205 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Jim Ingham0e81b642010-09-16 00:58:09 +0000206
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
Chris Lattner24943d22010-06-08 16:52:24 +0000210 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
231bool
232ThreadPlanStepRange::FrameIsOlder ()
233{
Greg Claytone005f2c2010-11-06 01:53:30 +0000234 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000235 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
256bool
257ThreadPlanStepRange::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
266bool
267ThreadPlanStepRange::WillStop ()
268{
269 return true;
270}
271
272StateType
Jim Ingham745ac7a2010-11-11 19:26:09 +0000273ThreadPlanStepRange::GetPlanRunState ()
Chris Lattner24943d22010-06-08 16:52:24 +0000274{
275 return eStateStepping;
276}
277
278bool
279ThreadPlanStepRange::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 {
Greg Claytone005f2c2010-11-06 01:53:30 +0000301 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000302 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}