1 //===-- 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"
20 #include "lldb/Symbol/Symbol.h"
21 #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"
26 #include "lldb/Core/RegularExpression.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 uint32_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 
38 ThreadPlanStepInRange::ThreadPlanStepInRange
39 (
40     Thread &thread,
41     const AddressRange &range,
42     const SymbolContext &addr_context,
43     lldb::RunMode stop_others
44 ) :
45     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
46     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL)
47 {
48     SetFlagsToDefault ();
49     // SetAvoidRegexp("^std\\:\\:.*");
50 }
51 
52 ThreadPlanStepInRange::~ThreadPlanStepInRange ()
53 {
54 }
55 
56 void
57 ThreadPlanStepInRange::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): ");
64         m_address_range.Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
65     }
66 }
67 
68 bool
69 ThreadPlanStepInRange::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 
104     // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
105     // continuing...
106 
107     bool stop_others;
108     if (m_stop_others != lldb::eAllThreads)
109         stop_others = true;
110     else
111         stop_others = false;
112 
113     new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
114 
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 
123     // 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 
141 void
142 ThreadPlanStepInRange::SetFlagsToDefault ()
143 {
144     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
145 }
146 
147 void
148 ThreadPlanStepInRange::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 
156 void
157 ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
158 {
159     // TODO: Should we test this for sanity?
160     ThreadPlanStepInRange::s_default_flag_values = new_value;
161 }
162 
163 bool
164 ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
165 {
166     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
167 
168     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)
175     {
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)
182                return avoid_regexp_to_use->Execute(sym_name);
183         }
184     }
185     return false;
186 }
187 
188 ThreadPlan *
189 ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
190 {
191     bool should_step_out = false;
192     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
193 
194     if (flags.IsSet(eAvoidNoDebug))
195     {
196         if (!frame->HasDebugInformation())
197             should_step_out = true;
198     }
199 
200     if (!should_step_out)
201     {
202         if (current_plan->GetKind() == eKindStepInRange)
203         {
204             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
205             should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
206         }
207     }
208 
209     if (should_step_out)
210     {
211         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
212         return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true,
213                                                                     current_plan->StopOthers(),
214                                                                     eVoteNo, eVoteNoOpinion);
215     }
216 
217     return NULL;
218 }
219