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/Thread.h"
25 #include "lldb/Target/ThreadPlanStepOut.h"
26 #include "lldb/Target/ThreadPlanStepThrough.h"
27 #include "lldb/Core/RegularExpression.h"
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 uint32_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 
39 ThreadPlanStepInRange::ThreadPlanStepInRange
40 (
41     Thread &thread,
42     const AddressRange &range,
43     const SymbolContext &addr_context,
44     lldb::RunMode stop_others
45 ) :
46     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
47     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
48     m_step_past_prologue (true)
49 {
50     SetFlagsToDefault ();
51 }
52 
53 ThreadPlanStepInRange::~ThreadPlanStepInRange ()
54 {
55 }
56 
57 void
58 ThreadPlanStepInRange::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): ");
65         m_address_range.Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
66     }
67 }
68 
69 bool
70 ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
71 {
72     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
73     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 
86     ThreadPlan* new_plan = NULL;
87 
88     // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
89     // continuing...
90 
91     bool stop_others;
92     if (m_stop_others != lldb::eAllThreads)
93         stop_others = true;
94     else
95         stop_others = false;
96 
97     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);
130 
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 
139     // 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 
144     // 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)
148     {
149         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);
174                 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
175                 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      {
185         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 
196 void
197 ThreadPlanStepInRange::SetFlagsToDefault ()
198 {
199     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
200 }
201 
202 void
203 ThreadPlanStepInRange::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 
211 void
212 ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
213 {
214     // TODO: Should we test this for sanity?
215     ThreadPlanStepInRange::s_default_flag_values = new_value;
216 }
217 
218 bool
219 ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
220 {
221     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
222 
223     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)
230     {
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)
237                return avoid_regexp_to_use->Execute(sym_name);
238         }
239     }
240     return false;
241 }
242 
243 ThreadPlan *
244 ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
245 {
246     bool should_step_out = false;
247     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
248     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
249 
250     if (flags.Test(eAvoidNoDebug))
251     {
252         if (!frame->HasDebugInformation())
253         {
254             if (log)
255                 log->Printf ("Stepping out of frame with no debug info");
256 
257             should_step_out = true;
258         }
259     }
260 
261     if (!should_step_out)
262     {
263         if (current_plan->GetKind() == eKindStepInRange)
264         {
265             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
266             should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
267         }
268     }
269 
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,
274                                                                     NULL,
275                                                                     true,
276                                                                     current_plan->StopOthers(),
277                                                                     eVoteNo,
278                                                                     eVoteNoOpinion,
279                                                                     0); // Frame index
280     }
281 
282     return NULL;
283 }
284