blob: c6b9fb63bffad8d71f1950d52321d8c703756731 [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"
Chris Lattner24943d22010-06-08 16:52:24 +000021#include "lldb/Target/Process.h"
22#include "lldb/Target/RegisterContext.h"
23#include "lldb/Target/Thread.h"
24#include "lldb/Target/ThreadPlanStepOut.h"
25#include "lldb/Target/ThreadPlanStepThrough.h"
Jim Ingham809ab9b2010-07-10 02:27:39 +000026#include "lldb/Core/RegularExpression.h"
Chris Lattner24943d22010-06-08 16:52:24 +000027
28using namespace lldb;
29using namespace lldb_private;
30
31uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
32
33//----------------------------------------------------------------------
34// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
35// based on the value of \a type.
36//----------------------------------------------------------------------
37
38ThreadPlanStepInRange::ThreadPlanStepInRange
39(
40 Thread &thread,
41 const AddressRange &range,
42 const SymbolContext &addr_context,
43 lldb::RunMode stop_others
44) :
Jim Ingham5a47e8b2010-06-19 04:45:32 +000045 ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
Chris Lattner24943d22010-06-08 16:52:24 +000046 ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL)
47{
48 SetFlagsToDefault ();
Jim Ingham809ab9b2010-07-10 02:27:39 +000049 // SetAvoidRegexp("^std\\:\\:.*");
Chris Lattner24943d22010-06-08 16:52:24 +000050}
51
52ThreadPlanStepInRange::~ThreadPlanStepInRange ()
53{
54}
55
56void
57ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
58{
59 if (level == lldb::eDescriptionLevelBrief)
60 s->Printf("step in");
61 else
62 {
63 s->Printf ("Stepping through range (stepping into functions): ");
Greg Claytoneea26402010-09-14 23:36:40 +000064 m_address_range.Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
Chris Lattner24943d22010-06-08 16:52:24 +000065 }
66}
67
68bool
69ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
70{
71 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
72 m_no_more_plans = false;
73
74 if (log)
75 {
76 StreamString s;
77 s.Address (m_thread.GetRegisterContext()->GetPC(), m_thread.GetProcess().GetAddressByteSize());
78 log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
79 }
80
81 // If we're still in the range, keep going.
82 if (InRange())
83 return false;
84
85 // If we're in an older frame then we should stop.
86 if (FrameIsOlder())
87 return true;
88
89 // See if we are in a place we should step through (i.e. a trampoline of some sort):
90 // One tricky bit here is that some stubs don't push a frame, so we have to check
91 // both the case of a frame that is younger, or the same as this frame.
92 // However, if the frame is the same, and we are still in the symbol we started
93 // in, the we don't need to do this. This first check isn't strictly necessary,
94 // but it is more efficient.
95
96 if (!FrameIsYounger() && InSymbol())
97 {
98 SetPlanComplete();
99 return true;
100 }
101
102 ThreadPlan* new_plan = NULL;
103
Jim Ingham81cfc992010-07-14 02:25:06 +0000104 // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
105 // continuing...
106
Chris Lattner24943d22010-06-08 16:52:24 +0000107 bool stop_others;
Jim Ingham81cfc992010-07-14 02:25:06 +0000108 if (m_stop_others != lldb::eAllThreads)
Chris Lattner24943d22010-06-08 16:52:24 +0000109 stop_others = true;
110 else
111 stop_others = false;
112
113 new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
Jim Ingham17454cf2010-09-14 22:03:00 +0000114
115 if (log)
116 {
117 if (new_plan != NULL)
118 log->Printf ("Found a step through plan: %s", new_plan->GetName());
119 else
120 log->Printf ("No step through plan found.");
121 }
122
Chris Lattner24943d22010-06-08 16:52:24 +0000123 // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
124 // But only do that if we actually have stepped in.
125 if (!new_plan && FrameIsYounger())
126 new_plan = InvokeShouldStopHereCallback();
127
128 if (new_plan == NULL)
129 {
130 m_no_more_plans = true;
131 SetPlanComplete();
132 return true;
133 }
134 else
135 {
136 m_no_more_plans = false;
137 return false;
138 }
139}
140
141void
142ThreadPlanStepInRange::SetFlagsToDefault ()
143{
144 GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
145}
146
Jim Ingham809ab9b2010-07-10 02:27:39 +0000147void
148ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
149{
150 if (m_avoid_regexp_ap.get() == NULL)
151 m_avoid_regexp_ap.reset (new RegularExpression(name));
152
153 m_avoid_regexp_ap->Compile (name);
154}
155
Chris Lattner24943d22010-06-08 16:52:24 +0000156void
157ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
158{
159 // TODO: Should we test this for sanity?
160 ThreadPlanStepInRange::s_default_flag_values = new_value;
161}
162
Jim Ingham809ab9b2010-07-10 02:27:39 +0000163bool
164ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
165{
166 StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
167
Jim Ingham20594b12010-09-08 03:14:33 +0000168 RegularExpression *avoid_regexp_to_use;
169
170 avoid_regexp_to_use = m_avoid_regexp_ap.get();
171 if (avoid_regexp_to_use == NULL)
172 avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
173
174 if (avoid_regexp_to_use != NULL)
Jim Ingham809ab9b2010-07-10 02:27:39 +0000175 {
176 SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol);
177 if (sc.symbol != NULL)
178 {
179 const char *unnamed_symbol = "<UNKNOWN>";
180 const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol);
181 if (strcmp (sym_name, unnamed_symbol) != 0)
Jim Ingham20594b12010-09-08 03:14:33 +0000182 return avoid_regexp_to_use->Execute(sym_name);
Jim Ingham809ab9b2010-07-10 02:27:39 +0000183 }
184 }
185 return false;
186}
187
Chris Lattner24943d22010-06-08 16:52:24 +0000188ThreadPlan *
189ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
190{
Jim Ingham809ab9b2010-07-10 02:27:39 +0000191 bool should_step_out = false;
192 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
Jim Inghame4b8aeb2010-09-15 00:06:51 +0000193 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
Jim Ingham809ab9b2010-07-10 02:27:39 +0000194
Chris Lattner24943d22010-06-08 16:52:24 +0000195 if (flags.IsSet(eAvoidNoDebug))
196 {
Chris Lattner24943d22010-06-08 16:52:24 +0000197 if (!frame->HasDebugInformation())
Jim Inghame4b8aeb2010-09-15 00:06:51 +0000198 {
199 if (log)
200 log->Printf ("Stepping out of frame with no debug info");
201
Jim Ingham809ab9b2010-07-10 02:27:39 +0000202 should_step_out = true;
Jim Inghame4b8aeb2010-09-15 00:06:51 +0000203 }
Jim Ingham809ab9b2010-07-10 02:27:39 +0000204 }
205
206 if (!should_step_out)
207 {
208 if (current_plan->GetKind() == eKindStepInRange)
Chris Lattner24943d22010-06-08 16:52:24 +0000209 {
Jim Ingham809ab9b2010-07-10 02:27:39 +0000210 ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
211 should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
Chris Lattner24943d22010-06-08 16:52:24 +0000212 }
213 }
Jim Ingham809ab9b2010-07-10 02:27:39 +0000214
215 if (should_step_out)
216 {
217 // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
218 return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true,
219 current_plan->StopOthers(),
220 eVoteNo, eVoteNoOpinion);
221 }
Chris Lattner24943d22010-06-08 16:52:24 +0000222
223 return NULL;
224}