blob: 9ee8b5621cbfb3a4c6f76885280b555d6d2fea5b [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"
24#include "lldb/Target/Thread.h"
25#include "lldb/Target/ThreadPlanStepOut.h"
26#include "lldb/Target/ThreadPlanStepThrough.h"
Jim Ingham809ab9b2010-07-10 02:27:39 +000027#include "lldb/Core/RegularExpression.h"
Chris Lattner24943d22010-06-08 16:52:24 +000028
29using namespace lldb;
30using namespace lldb_private;
31
32uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
33
34//----------------------------------------------------------------------
35// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
36// based on the value of \a type.
37//----------------------------------------------------------------------
38
39ThreadPlanStepInRange::ThreadPlanStepInRange
40(
41 Thread &thread,
42 const AddressRange &range,
43 const SymbolContext &addr_context,
44 lldb::RunMode stop_others
45) :
Jim Ingham5a47e8b2010-06-19 04:45:32 +000046 ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
Jim Ingham0e81b642010-09-16 00:58:09 +000047 ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
48 m_step_past_prologue (true)
Chris Lattner24943d22010-06-08 16:52:24 +000049{
50 SetFlagsToDefault ();
51}
52
53ThreadPlanStepInRange::~ThreadPlanStepInRange ()
54{
55}
56
57void
58ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
59{
60 if (level == lldb::eDescriptionLevelBrief)
61 s->Printf("step in");
62 else
63 {
64 s->Printf ("Stepping through range (stepping into functions): ");
Greg Claytoneea26402010-09-14 23:36:40 +000065 m_address_range.Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
Chris Lattner24943d22010-06-08 16:52:24 +000066 }
67}
68
69bool
70ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
71{
Greg Claytone005f2c2010-11-06 01:53:30 +000072 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Chris Lattner24943d22010-06-08 16:52:24 +000073 m_no_more_plans = false;
74
75 if (log)
76 {
77 StreamString s;
78 s.Address (m_thread.GetRegisterContext()->GetPC(), m_thread.GetProcess().GetAddressByteSize());
79 log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
80 }
81
82 // If we're still in the range, keep going.
83 if (InRange())
84 return false;
85
Chris Lattner24943d22010-06-08 16:52:24 +000086 ThreadPlan* new_plan = NULL;
87
Jim Ingham81cfc992010-07-14 02:25:06 +000088 // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
89 // continuing...
90
Chris Lattner24943d22010-06-08 16:52:24 +000091 bool stop_others;
Jim Ingham81cfc992010-07-14 02:25:06 +000092 if (m_stop_others != lldb::eAllThreads)
Chris Lattner24943d22010-06-08 16:52:24 +000093 stop_others = true;
94 else
95 stop_others = false;
96
Jim Ingham4f385f12010-11-05 00:18:21 +000097 if (FrameIsOlder())
98 {
99 // If we're in an older frame then we should stop.
100 //
101 // A caveat to this is if we think the frame is older but we're actually in a trampoline.
102 // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
103 // in a trampoline we think the frame is older because the trampoline confused the backtracer.
104 new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
105 if (new_plan == NULL)
106 return true;
107 else if (log)
108 {
109 log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
110 }
111
112 }
113 else if (!FrameIsYounger() && InSymbol())
114 {
115 // If we are not in a place we should step through, we're done.
116 // One tricky bit here is that some stubs don't push a frame, so we have to check
117 // both the case of a frame that is younger, or the same as this frame.
118 // However, if the frame is the same, and we are still in the symbol we started
119 // in, the we don't need to do this. This first check isn't strictly necessary,
120 // but it is more efficient.
121
122 SetPlanComplete();
123 return true;
124 }
125
126 // We may have set the plan up above in the FrameIsOlder section:
127
128 if (new_plan == NULL)
129 new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
Jim Ingham17454cf2010-09-14 22:03:00 +0000130
131 if (log)
132 {
133 if (new_plan != NULL)
134 log->Printf ("Found a step through plan: %s", new_plan->GetName());
135 else
136 log->Printf ("No step through plan found.");
137 }
138
Chris Lattner24943d22010-06-08 16:52:24 +0000139 // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
140 // But only do that if we actually have stepped in.
141 if (!new_plan && FrameIsYounger())
142 new_plan = InvokeShouldStopHereCallback();
143
Jim Ingham0e81b642010-09-16 00:58:09 +0000144 // If we've stepped in and we are going to stop here, check to see if we were asked to
145 // run past the prologue, and if so do that.
146
147 if (new_plan == NULL && FrameIsYounger() && m_step_past_prologue)
Chris Lattner24943d22010-06-08 16:52:24 +0000148 {
Jim Ingham0e81b642010-09-16 00:58:09 +0000149 lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
150 if (curr_frame)
151 {
152 size_t bytes_to_skip = 0;
153 lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
154 Address func_start_address;
155
156 SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
157
158 if (sc.function)
159 {
160 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
161 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget()))
162 bytes_to_skip = sc.function->GetPrologueByteSize();
163 }
164 else if (sc.symbol)
165 {
166 func_start_address = sc.symbol->GetValue();
167 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget()))
168 bytes_to_skip = sc.symbol->GetPrologueByteSize();
169 }
170
171 if (bytes_to_skip != 0)
172 {
173 func_start_address.Slide (bytes_to_skip);
Caroline Tice926060e2010-10-29 21:48:37 +0000174 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
Jim Ingham0e81b642010-09-16 00:58:09 +0000175 if (log)
176 log->Printf ("Pushing past prologue ");
177
178 new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
179 }
180 }
181 }
182
183 if (new_plan == NULL)
184 {
Chris Lattner24943d22010-06-08 16:52:24 +0000185 m_no_more_plans = true;
186 SetPlanComplete();
187 return true;
188 }
189 else
190 {
191 m_no_more_plans = false;
192 return false;
193 }
194}
195
196void
197ThreadPlanStepInRange::SetFlagsToDefault ()
198{
199 GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
200}
201
Jim Ingham809ab9b2010-07-10 02:27:39 +0000202void
203ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
204{
205 if (m_avoid_regexp_ap.get() == NULL)
206 m_avoid_regexp_ap.reset (new RegularExpression(name));
207
208 m_avoid_regexp_ap->Compile (name);
209}
210
Chris Lattner24943d22010-06-08 16:52:24 +0000211void
212ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
213{
214 // TODO: Should we test this for sanity?
215 ThreadPlanStepInRange::s_default_flag_values = new_value;
216}
217
Jim Ingham809ab9b2010-07-10 02:27:39 +0000218bool
219ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
220{
221 StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
222
Jim Ingham20594b12010-09-08 03:14:33 +0000223 RegularExpression *avoid_regexp_to_use;
224
225 avoid_regexp_to_use = m_avoid_regexp_ap.get();
226 if (avoid_regexp_to_use == NULL)
227 avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
228
229 if (avoid_regexp_to_use != NULL)
Jim Ingham809ab9b2010-07-10 02:27:39 +0000230 {
231 SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol);
232 if (sc.symbol != NULL)
233 {
234 const char *unnamed_symbol = "<UNKNOWN>";
235 const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol);
236 if (strcmp (sym_name, unnamed_symbol) != 0)
Jim Ingham20594b12010-09-08 03:14:33 +0000237 return avoid_regexp_to_use->Execute(sym_name);
Jim Ingham809ab9b2010-07-10 02:27:39 +0000238 }
239 }
240 return false;
241}
242
Chris Lattner24943d22010-06-08 16:52:24 +0000243ThreadPlan *
244ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
245{
Jim Ingham809ab9b2010-07-10 02:27:39 +0000246 bool should_step_out = false;
247 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
Greg Claytone005f2c2010-11-06 01:53:30 +0000248 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
Jim Ingham809ab9b2010-07-10 02:27:39 +0000249
Greg Claytonf3d0b0c2010-10-27 03:32:59 +0000250 if (flags.Test(eAvoidNoDebug))
Chris Lattner24943d22010-06-08 16:52:24 +0000251 {
Chris Lattner24943d22010-06-08 16:52:24 +0000252 if (!frame->HasDebugInformation())
Jim Inghame4b8aeb2010-09-15 00:06:51 +0000253 {
254 if (log)
255 log->Printf ("Stepping out of frame with no debug info");
256
Jim Ingham809ab9b2010-07-10 02:27:39 +0000257 should_step_out = true;
Jim Inghame4b8aeb2010-09-15 00:06:51 +0000258 }
Jim Ingham809ab9b2010-07-10 02:27:39 +0000259 }
260
261 if (!should_step_out)
262 {
263 if (current_plan->GetKind() == eKindStepInRange)
Chris Lattner24943d22010-06-08 16:52:24 +0000264 {
Jim Ingham809ab9b2010-07-10 02:27:39 +0000265 ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
266 should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
Chris Lattner24943d22010-06-08 16:52:24 +0000267 }
268 }
Jim Ingham809ab9b2010-07-10 02:27:39 +0000269
270 if (should_step_out)
271 {
272 // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
273 return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true,
274 current_plan->StopOthers(),
275 eVoteNo, eVoteNoOpinion);
276 }
Chris Lattner24943d22010-06-08 16:52:24 +0000277
278 return NULL;
279}