blob: 9fc3ad6360a799928fc3bf7351228e89ef4e553a [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- ThreadPlanStepInRange.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/ThreadPlanStepInRange.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"
Jim Ingham809ab9b2010-07-10 02:27:39 +000020#include "lldb/Symbol/Symbol.h"
Jim Ingham0e81b642010-09-16 00:58:09 +000021#include "lldb/Symbol/Function.h"
Chris Lattner24943d22010-06-08 16:52:24 +000022#include "lldb/Target/Process.h"
23#include "lldb/Target/RegisterContext.h"
Greg Clayton395fc332011-02-15 21:59:32 +000024#include "lldb/Target/Target.h"
Chris Lattner24943d22010-06-08 16:52:24 +000025#include "lldb/Target/Thread.h"
26#include "lldb/Target/ThreadPlanStepOut.h"
27#include "lldb/Target/ThreadPlanStepThrough.h"
Jim Ingham809ab9b2010-07-10 02:27:39 +000028#include "lldb/Core/RegularExpression.h"
Chris Lattner24943d22010-06-08 16:52:24 +000029
30using namespace lldb;
31using namespace lldb_private;
32
33uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
34
35//----------------------------------------------------------------------
36// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
37// based on the value of \a type.
38//----------------------------------------------------------------------
39
40ThreadPlanStepInRange::ThreadPlanStepInRange
41(
42 Thread &thread,
43 const AddressRange &range,
44 const SymbolContext &addr_context,
45 lldb::RunMode stop_others
46) :
Jim Ingham5a47e8b2010-06-19 04:45:32 +000047 ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
Jim Ingham0e81b642010-09-16 00:58:09 +000048 ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
49 m_step_past_prologue (true)
Chris Lattner24943d22010-06-08 16:52:24 +000050{
51 SetFlagsToDefault ();
52}
53
54ThreadPlanStepInRange::~ThreadPlanStepInRange ()
55{
56}
57
58void
59ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
60{
61 if (level == lldb::eDescriptionLevelBrief)
62 s->Printf("step in");
63 else
64 {
65 s->Printf ("Stepping through range (stepping into functions): ");
Jim Ingham76e55f72011-10-15 00:24:48 +000066 DumpRanges(s);
Chris Lattner24943d22010-06-08 16:52:24 +000067 }
68}
69
70bool
Jim Inghamad382c52011-12-03 01:52:59 +000071ThreadPlanStepInRange::PlanExplainsStop ()
72{
73 // We always explain a stop. Either we've just done a single step, in which
74 // case we'll do our ordinary processing, or we stopped for some
75 // reason that isn't handled by our sub-plans, in which case we want to just stop right
76 // away.
77
78 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
79 StopInfoSP stop_info_sp = GetPrivateStopReason();
80 if (stop_info_sp)
81 {
82 StopReason reason = stop_info_sp->GetStopReason();
83
84 switch (reason)
85 {
86 case eStopReasonBreakpoint:
87 case eStopReasonWatchpoint:
88 case eStopReasonSignal:
89 case eStopReasonException:
90 if (log)
91 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
92 SetPlanComplete();
93 break;
94 default:
95 break;
96 }
97 }
98 return true;
99}
100
101bool
Chris Lattner24943d22010-06-08 16:52:24 +0000102ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
103{
Greg Claytone005f2c2010-11-06 01:53:30 +0000104 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +0000105 m_no_more_plans = false;
106
107 if (log)
108 {
109 StreamString s;
Greg Clayton395fc332011-02-15 21:59:32 +0000110 s.Address (m_thread.GetRegisterContext()->GetPC(),
Greg Claytonf4124de2012-02-21 00:09:25 +0000111 m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
Chris Lattner24943d22010-06-08 16:52:24 +0000112 log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
113 }
114
Jim Inghamad382c52011-12-03 01:52:59 +0000115 if (IsPlanComplete())
116 return true;
117
Chris Lattner24943d22010-06-08 16:52:24 +0000118 // If we're still in the range, keep going.
119 if (InRange())
120 return false;
121
Chris Lattner24943d22010-06-08 16:52:24 +0000122 ThreadPlan* new_plan = NULL;
123
Jim Ingham81cfc992010-07-14 02:25:06 +0000124 // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
125 // continuing...
126
Chris Lattner24943d22010-06-08 16:52:24 +0000127 bool stop_others;
Jim Ingham81cfc992010-07-14 02:25:06 +0000128 if (m_stop_others != lldb::eAllThreads)
Chris Lattner24943d22010-06-08 16:52:24 +0000129 stop_others = true;
130 else
131 stop_others = false;
132
Jim Ingham441e3b92012-03-01 00:50:50 +0000133 FrameComparison frame_order = CompareCurrentFrameToStartFrame();
134
135 if (frame_order == eFrameCompareOlder)
Jim Ingham4f385f12010-11-05 00:18:21 +0000136 {
137 // If we're in an older frame then we should stop.
138 //
139 // A caveat to this is if we think the frame is older but we're actually in a trampoline.
140 // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
141 // in a trampoline we think the frame is older because the trampoline confused the backtracer.
142 new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
143 if (new_plan == NULL)
144 return true;
145 else if (log)
146 {
147 log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
148 }
149
150 }
Jim Ingham441e3b92012-03-01 00:50:50 +0000151 else if (frame_order != eFrameCompareYounger && InSymbol())
Jim Ingham4f385f12010-11-05 00:18:21 +0000152 {
153 // If we are not in a place we should step through, we're done.
154 // One tricky bit here is that some stubs don't push a frame, so we have to check
155 // both the case of a frame that is younger, or the same as this frame.
156 // However, if the frame is the same, and we are still in the symbol we started
157 // in, the we don't need to do this. This first check isn't strictly necessary,
158 // but it is more efficient.
159
160 SetPlanComplete();
161 return true;
162 }
163
164 // We may have set the plan up above in the FrameIsOlder section:
165
166 if (new_plan == NULL)
167 new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
Jim Ingham17454cf2010-09-14 22:03:00 +0000168
169 if (log)
170 {
171 if (new_plan != NULL)
172 log->Printf ("Found a step through plan: %s", new_plan->GetName());
173 else
174 log->Printf ("No step through plan found.");
175 }
176
Chris Lattner24943d22010-06-08 16:52:24 +0000177 // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
178 // But only do that if we actually have stepped in.
Jim Ingham441e3b92012-03-01 00:50:50 +0000179 if (!new_plan && frame_order == eFrameCompareYounger)
Chris Lattner24943d22010-06-08 16:52:24 +0000180 new_plan = InvokeShouldStopHereCallback();
181
Jim Ingham0e81b642010-09-16 00:58:09 +0000182 // If we've stepped in and we are going to stop here, check to see if we were asked to
183 // run past the prologue, and if so do that.
184
Jim Ingham441e3b92012-03-01 00:50:50 +0000185 if (new_plan == NULL && frame_order == eFrameCompareYounger && m_step_past_prologue)
Chris Lattner24943d22010-06-08 16:52:24 +0000186 {
Jim Ingham0e81b642010-09-16 00:58:09 +0000187 lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
188 if (curr_frame)
189 {
190 size_t bytes_to_skip = 0;
191 lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
192 Address func_start_address;
193
194 SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
195
196 if (sc.function)
197 {
198 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
Greg Clayton289afcb2012-02-18 05:35:26 +0000199 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
Jim Ingham0e81b642010-09-16 00:58:09 +0000200 bytes_to_skip = sc.function->GetPrologueByteSize();
201 }
202 else if (sc.symbol)
203 {
204 func_start_address = sc.symbol->GetValue();
Greg Clayton289afcb2012-02-18 05:35:26 +0000205 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
Jim Ingham0e81b642010-09-16 00:58:09 +0000206 bytes_to_skip = sc.symbol->GetPrologueByteSize();
207 }
208
209 if (bytes_to_skip != 0)
210 {
211 func_start_address.Slide (bytes_to_skip);
Caroline Tice926060e2010-10-29 21:48:37 +0000212 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
Jim Ingham0e81b642010-09-16 00:58:09 +0000213 if (log)
214 log->Printf ("Pushing past prologue ");
215
216 new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
217 }
218 }
219 }
220
221 if (new_plan == NULL)
222 {
Chris Lattner24943d22010-06-08 16:52:24 +0000223 m_no_more_plans = true;
224 SetPlanComplete();
225 return true;
226 }
227 else
228 {
229 m_no_more_plans = false;
230 return false;
231 }
232}
233
234void
235ThreadPlanStepInRange::SetFlagsToDefault ()
236{
237 GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
238}
239
Jim Ingham809ab9b2010-07-10 02:27:39 +0000240void
241ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
242{
243 if (m_avoid_regexp_ap.get() == NULL)
244 m_avoid_regexp_ap.reset (new RegularExpression(name));
245
246 m_avoid_regexp_ap->Compile (name);
247}
248
Chris Lattner24943d22010-06-08 16:52:24 +0000249void
250ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
251{
252 // TODO: Should we test this for sanity?
253 ThreadPlanStepInRange::s_default_flag_values = new_value;
254}
255
Jim Ingham809ab9b2010-07-10 02:27:39 +0000256bool
257ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
258{
259 StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
260
Jim Ingham20594b12010-09-08 03:14:33 +0000261 RegularExpression *avoid_regexp_to_use;
262
263 avoid_regexp_to_use = m_avoid_regexp_ap.get();
264 if (avoid_regexp_to_use == NULL)
265 avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
266
267 if (avoid_regexp_to_use != NULL)
Jim Ingham809ab9b2010-07-10 02:27:39 +0000268 {
269 SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol);
270 if (sc.symbol != NULL)
271 {
272 const char *unnamed_symbol = "<UNKNOWN>";
273 const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol);
274 if (strcmp (sym_name, unnamed_symbol) != 0)
Jim Ingham20594b12010-09-08 03:14:33 +0000275 return avoid_regexp_to_use->Execute(sym_name);
Jim Ingham809ab9b2010-07-10 02:27:39 +0000276 }
277 }
278 return false;
279}
280
Chris Lattner24943d22010-06-08 16:52:24 +0000281ThreadPlan *
282ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
283{
Jim Ingham809ab9b2010-07-10 02:27:39 +0000284 bool should_step_out = false;
285 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
Greg Claytone005f2c2010-11-06 01:53:30 +0000286 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Jim Ingham809ab9b2010-07-10 02:27:39 +0000287
Greg Claytonf3d0b0c2010-10-27 03:32:59 +0000288 if (flags.Test(eAvoidNoDebug))
Chris Lattner24943d22010-06-08 16:52:24 +0000289 {
Chris Lattner24943d22010-06-08 16:52:24 +0000290 if (!frame->HasDebugInformation())
Jim Inghame4b8aeb2010-09-15 00:06:51 +0000291 {
292 if (log)
293 log->Printf ("Stepping out of frame with no debug info");
294
Jim Ingham809ab9b2010-07-10 02:27:39 +0000295 should_step_out = true;
Jim Inghame4b8aeb2010-09-15 00:06:51 +0000296 }
Jim Ingham809ab9b2010-07-10 02:27:39 +0000297 }
298
299 if (!should_step_out)
300 {
301 if (current_plan->GetKind() == eKindStepInRange)
Chris Lattner24943d22010-06-08 16:52:24 +0000302 {
Jim Ingham809ab9b2010-07-10 02:27:39 +0000303 ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
304 should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
Chris Lattner24943d22010-06-08 16:52:24 +0000305 }
306 }
Jim Ingham809ab9b2010-07-10 02:27:39 +0000307
308 if (should_step_out)
309 {
310 // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
Greg Clayton1ebdcc72011-01-21 06:11:58 +0000311 return current_plan->GetThread().QueueThreadPlanForStepOut (false,
312 NULL,
313 true,
Jim Ingham809ab9b2010-07-10 02:27:39 +0000314 current_plan->StopOthers(),
Greg Clayton1ebdcc72011-01-21 06:11:58 +0000315 eVoteNo,
316 eVoteNoOpinion,
317 0); // Frame index
Jim Ingham809ab9b2010-07-10 02:27:39 +0000318 }
Chris Lattner24943d22010-06-08 16:52:24 +0000319
320 return NULL;
321}