130fdc8d8SChris Lattner //===-- ThreadPlanStepInRange.cpp -------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepInRange.h"
1130fdc8d8SChris Lattner 
1230fdc8d8SChris Lattner // C Includes
1330fdc8d8SChris Lattner // C++ Includes
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
1630fdc8d8SChris Lattner 
1730fdc8d8SChris Lattner #include "lldb/lldb-private-log.h"
1830fdc8d8SChris Lattner #include "lldb/Core/Log.h"
1930fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
20a56c8006SJim Ingham #include "lldb/Symbol/Symbol.h"
217ce490c6SJim Ingham #include "lldb/Symbol/Function.h"
2230fdc8d8SChris Lattner #include "lldb/Target/Process.h"
2330fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
24514487e8SGreg Clayton #include "lldb/Target/Target.h"
2530fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2630fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2730fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
28a56c8006SJim Ingham #include "lldb/Core/RegularExpression.h"
2930fdc8d8SChris Lattner 
3030fdc8d8SChris Lattner using namespace lldb;
3130fdc8d8SChris Lattner using namespace lldb_private;
3230fdc8d8SChris Lattner 
3330fdc8d8SChris Lattner uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
3430fdc8d8SChris Lattner 
3530fdc8d8SChris Lattner //----------------------------------------------------------------------
3630fdc8d8SChris Lattner // ThreadPlanStepInRange: Step through a stack range, either stepping over or into
3730fdc8d8SChris Lattner // based on the value of \a type.
3830fdc8d8SChris Lattner //----------------------------------------------------------------------
3930fdc8d8SChris Lattner 
4030fdc8d8SChris Lattner ThreadPlanStepInRange::ThreadPlanStepInRange
4130fdc8d8SChris Lattner (
4230fdc8d8SChris Lattner     Thread &thread,
4330fdc8d8SChris Lattner     const AddressRange &range,
4430fdc8d8SChris Lattner     const SymbolContext &addr_context,
4530fdc8d8SChris Lattner     lldb::RunMode stop_others
4630fdc8d8SChris Lattner ) :
47b01e742aSJim Ingham     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
487ce490c6SJim Ingham     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
497ce490c6SJim Ingham     m_step_past_prologue (true)
5030fdc8d8SChris Lattner {
5130fdc8d8SChris Lattner     SetFlagsToDefault ();
5230fdc8d8SChris Lattner }
5330fdc8d8SChris Lattner 
5430fdc8d8SChris Lattner ThreadPlanStepInRange::~ThreadPlanStepInRange ()
5530fdc8d8SChris Lattner {
5630fdc8d8SChris Lattner }
5730fdc8d8SChris Lattner 
5830fdc8d8SChris Lattner void
5930fdc8d8SChris Lattner ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
6030fdc8d8SChris Lattner {
6130fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
6230fdc8d8SChris Lattner         s->Printf("step in");
6330fdc8d8SChris Lattner     else
6430fdc8d8SChris Lattner     {
6530fdc8d8SChris Lattner         s->Printf ("Stepping through range (stepping into functions): ");
66c4c9fedcSJim Ingham         DumpRanges(s);
6730fdc8d8SChris Lattner     }
6830fdc8d8SChris Lattner }
6930fdc8d8SChris Lattner 
7030fdc8d8SChris Lattner bool
7125f66700SJim Ingham ThreadPlanStepInRange::PlanExplainsStop ()
7225f66700SJim Ingham {
7325f66700SJim Ingham     // We always explain a stop.  Either we've just done a single step, in which
7425f66700SJim Ingham     // case we'll do our ordinary processing, or we stopped for some
7525f66700SJim Ingham     // reason that isn't handled by our sub-plans, in which case we want to just stop right
7625f66700SJim Ingham     // away.
7725f66700SJim Ingham 
7825f66700SJim Ingham     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
7925f66700SJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopReason();
8025f66700SJim Ingham     if (stop_info_sp)
8125f66700SJim Ingham     {
8225f66700SJim Ingham         StopReason reason = stop_info_sp->GetStopReason();
8325f66700SJim Ingham 
8425f66700SJim Ingham         switch (reason)
8525f66700SJim Ingham         {
8625f66700SJim Ingham         case eStopReasonBreakpoint:
8725f66700SJim Ingham         case eStopReasonWatchpoint:
8825f66700SJim Ingham         case eStopReasonSignal:
8925f66700SJim Ingham         case eStopReasonException:
9025f66700SJim Ingham             if (log)
9125f66700SJim Ingham                 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
9225f66700SJim Ingham             SetPlanComplete();
9325f66700SJim Ingham             break;
9425f66700SJim Ingham         default:
9525f66700SJim Ingham             break;
9625f66700SJim Ingham         }
9725f66700SJim Ingham     }
9825f66700SJim Ingham     return true;
9925f66700SJim Ingham }
10025f66700SJim Ingham 
10125f66700SJim Ingham bool
10230fdc8d8SChris Lattner ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
10330fdc8d8SChris Lattner {
1042d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
10530fdc8d8SChris Lattner     m_no_more_plans = false;
10630fdc8d8SChris Lattner 
10730fdc8d8SChris Lattner     if (log)
10830fdc8d8SChris Lattner     {
10930fdc8d8SChris Lattner         StreamString s;
110514487e8SGreg Clayton         s.Address (m_thread.GetRegisterContext()->GetPC(),
1111ac04c30SGreg Clayton                    m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
11230fdc8d8SChris Lattner         log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
11330fdc8d8SChris Lattner     }
11430fdc8d8SChris Lattner 
11525f66700SJim Ingham     if (IsPlanComplete())
11625f66700SJim Ingham         return true;
11725f66700SJim Ingham 
11830fdc8d8SChris Lattner     // If we're still in the range, keep going.
11930fdc8d8SChris Lattner     if (InRange())
12030fdc8d8SChris Lattner         return false;
12130fdc8d8SChris Lattner 
12230fdc8d8SChris Lattner     ThreadPlan* new_plan = NULL;
12330fdc8d8SChris Lattner 
1249d790c5dSJim Ingham     // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
1259d790c5dSJim Ingham     // continuing...
1269d790c5dSJim Ingham 
12730fdc8d8SChris Lattner     bool stop_others;
1289d790c5dSJim Ingham     if (m_stop_others != lldb::eAllThreads)
12930fdc8d8SChris Lattner         stop_others = true;
13030fdc8d8SChris Lattner     else
13130fdc8d8SChris Lattner         stop_others = false;
13230fdc8d8SChris Lattner 
133b5c0d1ccSJim Ingham     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
134b5c0d1ccSJim Ingham 
135b5c0d1ccSJim Ingham     if (frame_order == eFrameCompareOlder)
1365822173bSJim Ingham     {
1375822173bSJim Ingham         // If we're in an older frame then we should stop.
1385822173bSJim Ingham         //
1395822173bSJim Ingham         // A caveat to this is if we think the frame is older but we're actually in a trampoline.
1405822173bSJim Ingham         // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
1415822173bSJim Ingham         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
1425822173bSJim Ingham         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
1435822173bSJim Ingham         if (new_plan == NULL)
1445822173bSJim Ingham             return true;
1455822173bSJim Ingham         else if (log)
1465822173bSJim Ingham         {
1475822173bSJim Ingham             log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
1485822173bSJim Ingham         }
1495822173bSJim Ingham 
1505822173bSJim Ingham     }
151b5c0d1ccSJim Ingham     else if (frame_order != eFrameCompareYounger && InSymbol())
1525822173bSJim Ingham     {
1535822173bSJim Ingham         // If we are not in a place we should step through, we're done.
1545822173bSJim Ingham         // One tricky bit here is that some stubs don't push a frame, so we have to check
1555822173bSJim Ingham         // both the case of a frame that is younger, or the same as this frame.
1565822173bSJim Ingham         // However, if the frame is the same, and we are still in the symbol we started
1575822173bSJim Ingham         // in, the we don't need to do this.  This first check isn't strictly necessary,
1585822173bSJim Ingham         // but it is more efficient.
1595822173bSJim Ingham 
1605822173bSJim Ingham         SetPlanComplete();
1615822173bSJim Ingham         return true;
1625822173bSJim Ingham     }
1635822173bSJim Ingham 
1645822173bSJim Ingham     // We may have set the plan up above in the FrameIsOlder section:
1655822173bSJim Ingham 
1665822173bSJim Ingham     if (new_plan == NULL)
16730fdc8d8SChris Lattner         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
16808b87e0dSJim Ingham 
16908b87e0dSJim Ingham     if (log)
17008b87e0dSJim Ingham     {
17108b87e0dSJim Ingham         if (new_plan != NULL)
17208b87e0dSJim Ingham             log->Printf ("Found a step through plan: %s", new_plan->GetName());
17308b87e0dSJim Ingham         else
17408b87e0dSJim Ingham             log->Printf ("No step through plan found.");
17508b87e0dSJim Ingham     }
17608b87e0dSJim Ingham 
17730fdc8d8SChris Lattner     // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
17830fdc8d8SChris Lattner     // But only do that if we actually have stepped in.
179b5c0d1ccSJim Ingham     if (!new_plan && frame_order == eFrameCompareYounger)
18030fdc8d8SChris Lattner         new_plan = InvokeShouldStopHereCallback();
18130fdc8d8SChris Lattner 
1827ce490c6SJim Ingham     // If we've stepped in and we are going to stop here, check to see if we were asked to
1837ce490c6SJim Ingham     // run past the prologue, and if so do that.
1847ce490c6SJim Ingham 
185b5c0d1ccSJim Ingham     if (new_plan == NULL && frame_order == eFrameCompareYounger && m_step_past_prologue)
1867ce490c6SJim Ingham     {
1877ce490c6SJim Ingham         lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
1887ce490c6SJim Ingham         if (curr_frame)
1897ce490c6SJim Ingham         {
1907ce490c6SJim Ingham             size_t bytes_to_skip = 0;
1917ce490c6SJim Ingham             lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
1927ce490c6SJim Ingham             Address func_start_address;
1937ce490c6SJim Ingham 
1947ce490c6SJim Ingham             SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
1957ce490c6SJim Ingham 
1967ce490c6SJim Ingham             if (sc.function)
1977ce490c6SJim Ingham             {
1987ce490c6SJim Ingham                 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
199d9e416c0SGreg Clayton                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
2007ce490c6SJim Ingham                     bytes_to_skip = sc.function->GetPrologueByteSize();
2017ce490c6SJim Ingham             }
2027ce490c6SJim Ingham             else if (sc.symbol)
2037ce490c6SJim Ingham             {
204*e7612134SGreg Clayton                 func_start_address = sc.symbol->GetAddress();
205d9e416c0SGreg Clayton                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
2067ce490c6SJim Ingham                     bytes_to_skip = sc.symbol->GetPrologueByteSize();
2077ce490c6SJim Ingham             }
2087ce490c6SJim Ingham 
2097ce490c6SJim Ingham             if (bytes_to_skip != 0)
2107ce490c6SJim Ingham             {
2117ce490c6SJim Ingham                 func_start_address.Slide (bytes_to_skip);
21220ad3c40SCaroline Tice                 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
2137ce490c6SJim Ingham                 if (log)
2147ce490c6SJim Ingham                     log->Printf ("Pushing past prologue ");
2157ce490c6SJim Ingham 
2167ce490c6SJim Ingham                 new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
2177ce490c6SJim Ingham             }
2187ce490c6SJim Ingham         }
2197ce490c6SJim Ingham     }
2207ce490c6SJim Ingham 
22130fdc8d8SChris Lattner      if (new_plan == NULL)
22230fdc8d8SChris Lattner      {
22330fdc8d8SChris Lattner         m_no_more_plans = true;
22430fdc8d8SChris Lattner         SetPlanComplete();
22530fdc8d8SChris Lattner         return true;
22630fdc8d8SChris Lattner     }
22730fdc8d8SChris Lattner     else
22830fdc8d8SChris Lattner     {
22930fdc8d8SChris Lattner         m_no_more_plans = false;
23030fdc8d8SChris Lattner         return false;
23130fdc8d8SChris Lattner     }
23230fdc8d8SChris Lattner }
23330fdc8d8SChris Lattner 
23430fdc8d8SChris Lattner void
23530fdc8d8SChris Lattner ThreadPlanStepInRange::SetFlagsToDefault ()
23630fdc8d8SChris Lattner {
23730fdc8d8SChris Lattner     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
23830fdc8d8SChris Lattner }
23930fdc8d8SChris Lattner 
24030fdc8d8SChris Lattner void
241a56c8006SJim Ingham ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
242a56c8006SJim Ingham {
243a56c8006SJim Ingham     if (m_avoid_regexp_ap.get() == NULL)
244a56c8006SJim Ingham         m_avoid_regexp_ap.reset (new RegularExpression(name));
245a56c8006SJim Ingham 
246a56c8006SJim Ingham     m_avoid_regexp_ap->Compile (name);
247a56c8006SJim Ingham }
248a56c8006SJim Ingham 
249a56c8006SJim Ingham void
25030fdc8d8SChris Lattner ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
25130fdc8d8SChris Lattner {
25230fdc8d8SChris Lattner     // TODO: Should we test this for sanity?
25330fdc8d8SChris Lattner     ThreadPlanStepInRange::s_default_flag_values = new_value;
25430fdc8d8SChris Lattner }
25530fdc8d8SChris Lattner 
256a56c8006SJim Ingham bool
257a56c8006SJim Ingham ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
258a56c8006SJim Ingham {
259a56c8006SJim Ingham     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
260a56c8006SJim Ingham 
261ee8aea10SJim Ingham     RegularExpression *avoid_regexp_to_use;
262ee8aea10SJim Ingham 
263ee8aea10SJim Ingham     avoid_regexp_to_use = m_avoid_regexp_ap.get();
264ee8aea10SJim Ingham     if (avoid_regexp_to_use == NULL)
265ee8aea10SJim Ingham         avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
266ee8aea10SJim Ingham 
267ee8aea10SJim Ingham     if (avoid_regexp_to_use != NULL)
268a56c8006SJim Ingham     {
269a56c8006SJim Ingham         SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol);
270a56c8006SJim Ingham         if (sc.symbol != NULL)
271a56c8006SJim Ingham         {
272a56c8006SJim Ingham             const char *unnamed_symbol = "<UNKNOWN>";
273a56c8006SJim Ingham             const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol);
274a56c8006SJim Ingham             if (strcmp (sym_name, unnamed_symbol) != 0)
275ee8aea10SJim Ingham                return avoid_regexp_to_use->Execute(sym_name);
276a56c8006SJim Ingham         }
277a56c8006SJim Ingham     }
278a56c8006SJim Ingham     return false;
279a56c8006SJim Ingham }
280a56c8006SJim Ingham 
28130fdc8d8SChris Lattner ThreadPlan *
28230fdc8d8SChris Lattner ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
28330fdc8d8SChris Lattner {
284a56c8006SJim Ingham     bool should_step_out = false;
28530fdc8d8SChris Lattner     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
2862d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
28730fdc8d8SChris Lattner 
28873b472d4SGreg Clayton     if (flags.Test(eAvoidNoDebug))
289a56c8006SJim Ingham     {
29030fdc8d8SChris Lattner         if (!frame->HasDebugInformation())
291af0f1759SJim Ingham         {
292af0f1759SJim Ingham             if (log)
293af0f1759SJim Ingham                 log->Printf ("Stepping out of frame with no debug info");
294af0f1759SJim Ingham 
295a56c8006SJim Ingham             should_step_out = true;
296a56c8006SJim Ingham         }
297af0f1759SJim Ingham     }
298a56c8006SJim Ingham 
299a56c8006SJim Ingham     if (!should_step_out)
300a56c8006SJim Ingham     {
301a56c8006SJim Ingham         if (current_plan->GetKind() == eKindStepInRange)
302a56c8006SJim Ingham         {
303a56c8006SJim Ingham             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
304a56c8006SJim Ingham             should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
305a56c8006SJim Ingham         }
306a56c8006SJim Ingham     }
307a56c8006SJim Ingham 
308a56c8006SJim Ingham     if (should_step_out)
30930fdc8d8SChris Lattner     {
31030fdc8d8SChris Lattner         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
311481cef25SGreg Clayton         return current_plan->GetThread().QueueThreadPlanForStepOut (false,
312481cef25SGreg Clayton                                                                     NULL,
313481cef25SGreg Clayton                                                                     true,
314a56c8006SJim Ingham                                                                     current_plan->StopOthers(),
315481cef25SGreg Clayton                                                                     eVoteNo,
316481cef25SGreg Clayton                                                                     eVoteNoOpinion,
317481cef25SGreg Clayton                                                                     0); // Frame index
31830fdc8d8SChris Lattner     }
31930fdc8d8SChris Lattner 
32030fdc8d8SChris Lattner     return NULL;
32130fdc8d8SChris Lattner }
322