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/Symbol/Function.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/RegisterContext.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Target/ThreadPlanStepOut.h"
27 #include "lldb/Target/ThreadPlanStepThrough.h"
28 #include "lldb/Core/RegularExpression.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 uint32_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 
40 ThreadPlanStepInRange::ThreadPlanStepInRange
41 (
42     Thread &thread,
43     const AddressRange &range,
44     const SymbolContext &addr_context,
45     lldb::RunMode stop_others
46 ) :
47     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
48     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
49     m_step_past_prologue (true)
50 {
51     SetFlagsToDefault ();
52 }
53 
54 ThreadPlanStepInRange::~ThreadPlanStepInRange ()
55 {
56 }
57 
58 void
59 ThreadPlanStepInRange::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): ");
66         m_address_range.Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
67     }
68 }
69 
70 bool
71 ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
72 {
73     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
74     m_no_more_plans = false;
75 
76     if (log)
77     {
78         StreamString s;
79         s.Address (m_thread.GetRegisterContext()->GetPC(),
80                    m_thread.GetProcess().GetTarget().GetArchitecture().GetAddressByteSize());
81         log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
82     }
83 
84     // If we're still in the range, keep going.
85     if (InRange())
86         return false;
87 
88     ThreadPlan* new_plan = NULL;
89 
90     // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
91     // continuing...
92 
93     bool stop_others;
94     if (m_stop_others != lldb::eAllThreads)
95         stop_others = true;
96     else
97         stop_others = false;
98 
99     if (FrameIsOlder())
100     {
101         // If we're in an older frame then we should stop.
102         //
103         // A caveat to this is if we think the frame is older but we're actually in a trampoline.
104         // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
105         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
106         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
107         if (new_plan == NULL)
108             return true;
109         else if (log)
110         {
111             log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
112         }
113 
114     }
115     else if (!FrameIsYounger() && InSymbol())
116     {
117         // If we are not in a place we should step through, we're done.
118         // One tricky bit here is that some stubs don't push a frame, so we have to check
119         // both the case of a frame that is younger, or the same as this frame.
120         // However, if the frame is the same, and we are still in the symbol we started
121         // in, the we don't need to do this.  This first check isn't strictly necessary,
122         // but it is more efficient.
123 
124         SetPlanComplete();
125         return true;
126     }
127 
128     // We may have set the plan up above in the FrameIsOlder section:
129 
130     if (new_plan == NULL)
131         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
132 
133     if (log)
134     {
135         if (new_plan != NULL)
136             log->Printf ("Found a step through plan: %s", new_plan->GetName());
137         else
138             log->Printf ("No step through plan found.");
139     }
140 
141     // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
142     // But only do that if we actually have stepped in.
143     if (!new_plan && FrameIsYounger())
144         new_plan = InvokeShouldStopHereCallback();
145 
146     // If we've stepped in and we are going to stop here, check to see if we were asked to
147     // run past the prologue, and if so do that.
148 
149     if (new_plan == NULL && FrameIsYounger() && m_step_past_prologue)
150     {
151         lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
152         if (curr_frame)
153         {
154             size_t bytes_to_skip = 0;
155             lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
156             Address func_start_address;
157 
158             SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
159 
160             if (sc.function)
161             {
162                 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
163                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget()))
164                     bytes_to_skip = sc.function->GetPrologueByteSize();
165             }
166             else if (sc.symbol)
167             {
168                 func_start_address = sc.symbol->GetValue();
169                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget()))
170                     bytes_to_skip = sc.symbol->GetPrologueByteSize();
171             }
172 
173             if (bytes_to_skip != 0)
174             {
175                 func_start_address.Slide (bytes_to_skip);
176                 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
177                 if (log)
178                     log->Printf ("Pushing past prologue ");
179 
180                 new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
181             }
182         }
183     }
184 
185      if (new_plan == NULL)
186      {
187         m_no_more_plans = true;
188         SetPlanComplete();
189         return true;
190     }
191     else
192     {
193         m_no_more_plans = false;
194         return false;
195     }
196 }
197 
198 void
199 ThreadPlanStepInRange::SetFlagsToDefault ()
200 {
201     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
202 }
203 
204 void
205 ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
206 {
207     if (m_avoid_regexp_ap.get() == NULL)
208         m_avoid_regexp_ap.reset (new RegularExpression(name));
209 
210     m_avoid_regexp_ap->Compile (name);
211 }
212 
213 void
214 ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
215 {
216     // TODO: Should we test this for sanity?
217     ThreadPlanStepInRange::s_default_flag_values = new_value;
218 }
219 
220 bool
221 ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
222 {
223     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
224 
225     RegularExpression *avoid_regexp_to_use;
226 
227     avoid_regexp_to_use = m_avoid_regexp_ap.get();
228     if (avoid_regexp_to_use == NULL)
229         avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
230 
231     if (avoid_regexp_to_use != NULL)
232     {
233         SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol);
234         if (sc.symbol != NULL)
235         {
236             const char *unnamed_symbol = "<UNKNOWN>";
237             const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol);
238             if (strcmp (sym_name, unnamed_symbol) != 0)
239                return avoid_regexp_to_use->Execute(sym_name);
240         }
241     }
242     return false;
243 }
244 
245 ThreadPlan *
246 ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
247 {
248     bool should_step_out = false;
249     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
250     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
251 
252     if (flags.Test(eAvoidNoDebug))
253     {
254         if (!frame->HasDebugInformation())
255         {
256             if (log)
257                 log->Printf ("Stepping out of frame with no debug info");
258 
259             should_step_out = true;
260         }
261     }
262 
263     if (!should_step_out)
264     {
265         if (current_plan->GetKind() == eKindStepInRange)
266         {
267             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
268             should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
269         }
270     }
271 
272     if (should_step_out)
273     {
274         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
275         return current_plan->GetThread().QueueThreadPlanForStepOut (false,
276                                                                     NULL,
277                                                                     true,
278                                                                     current_plan->StopOthers(),
279                                                                     eVoteNo,
280                                                                     eVoteNoOpinion,
281                                                                     0); // Frame index
282     }
283 
284     return NULL;
285 }
286