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"
2430fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2530fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2630fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
27a56c8006SJim Ingham #include "lldb/Core/RegularExpression.h"
2830fdc8d8SChris Lattner 
2930fdc8d8SChris Lattner using namespace lldb;
3030fdc8d8SChris Lattner using namespace lldb_private;
3130fdc8d8SChris Lattner 
3230fdc8d8SChris Lattner uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner //----------------------------------------------------------------------
3530fdc8d8SChris Lattner // ThreadPlanStepInRange: Step through a stack range, either stepping over or into
3630fdc8d8SChris Lattner // based on the value of \a type.
3730fdc8d8SChris Lattner //----------------------------------------------------------------------
3830fdc8d8SChris Lattner 
3930fdc8d8SChris Lattner ThreadPlanStepInRange::ThreadPlanStepInRange
4030fdc8d8SChris Lattner (
4130fdc8d8SChris Lattner     Thread &thread,
4230fdc8d8SChris Lattner     const AddressRange &range,
4330fdc8d8SChris Lattner     const SymbolContext &addr_context,
4430fdc8d8SChris Lattner     lldb::RunMode stop_others
4530fdc8d8SChris Lattner ) :
46b01e742aSJim Ingham     ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
477ce490c6SJim Ingham     ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
487ce490c6SJim Ingham     m_step_past_prologue (true)
4930fdc8d8SChris Lattner {
5030fdc8d8SChris Lattner     SetFlagsToDefault ();
5130fdc8d8SChris Lattner }
5230fdc8d8SChris Lattner 
5330fdc8d8SChris Lattner ThreadPlanStepInRange::~ThreadPlanStepInRange ()
5430fdc8d8SChris Lattner {
5530fdc8d8SChris Lattner }
5630fdc8d8SChris Lattner 
5730fdc8d8SChris Lattner void
5830fdc8d8SChris Lattner ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
5930fdc8d8SChris Lattner {
6030fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
6130fdc8d8SChris Lattner         s->Printf("step in");
6230fdc8d8SChris Lattner     else
6330fdc8d8SChris Lattner     {
6430fdc8d8SChris Lattner         s->Printf ("Stepping through range (stepping into functions): ");
65f5e56de0SGreg Clayton         m_address_range.Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress);
6630fdc8d8SChris Lattner     }
6730fdc8d8SChris Lattner }
6830fdc8d8SChris Lattner 
6930fdc8d8SChris Lattner bool
7030fdc8d8SChris Lattner ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
7130fdc8d8SChris Lattner {
722d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
7330fdc8d8SChris Lattner     m_no_more_plans = false;
7430fdc8d8SChris Lattner 
7530fdc8d8SChris Lattner     if (log)
7630fdc8d8SChris Lattner     {
7730fdc8d8SChris Lattner         StreamString s;
7830fdc8d8SChris Lattner         s.Address (m_thread.GetRegisterContext()->GetPC(), m_thread.GetProcess().GetAddressByteSize());
7930fdc8d8SChris Lattner         log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
8030fdc8d8SChris Lattner     }
8130fdc8d8SChris Lattner 
8230fdc8d8SChris Lattner     // If we're still in the range, keep going.
8330fdc8d8SChris Lattner     if (InRange())
8430fdc8d8SChris Lattner         return false;
8530fdc8d8SChris Lattner 
8630fdc8d8SChris Lattner     ThreadPlan* new_plan = NULL;
8730fdc8d8SChris Lattner 
889d790c5dSJim Ingham     // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
899d790c5dSJim Ingham     // continuing...
909d790c5dSJim Ingham 
9130fdc8d8SChris Lattner     bool stop_others;
929d790c5dSJim Ingham     if (m_stop_others != lldb::eAllThreads)
9330fdc8d8SChris Lattner         stop_others = true;
9430fdc8d8SChris Lattner     else
9530fdc8d8SChris Lattner         stop_others = false;
9630fdc8d8SChris Lattner 
975822173bSJim Ingham     if (FrameIsOlder())
985822173bSJim Ingham     {
995822173bSJim Ingham         // If we're in an older frame then we should stop.
1005822173bSJim Ingham         //
1015822173bSJim Ingham         // A caveat to this is if we think the frame is older but we're actually in a trampoline.
1025822173bSJim Ingham         // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
1035822173bSJim Ingham         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
1045822173bSJim Ingham         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
1055822173bSJim Ingham         if (new_plan == NULL)
1065822173bSJim Ingham             return true;
1075822173bSJim Ingham         else if (log)
1085822173bSJim Ingham         {
1095822173bSJim Ingham             log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
1105822173bSJim Ingham         }
1115822173bSJim Ingham 
1125822173bSJim Ingham     }
1135822173bSJim Ingham     else if (!FrameIsYounger() && InSymbol())
1145822173bSJim Ingham     {
1155822173bSJim Ingham         // If we are not in a place we should step through, we're done.
1165822173bSJim Ingham         // One tricky bit here is that some stubs don't push a frame, so we have to check
1175822173bSJim Ingham         // both the case of a frame that is younger, or the same as this frame.
1185822173bSJim Ingham         // However, if the frame is the same, and we are still in the symbol we started
1195822173bSJim Ingham         // in, the we don't need to do this.  This first check isn't strictly necessary,
1205822173bSJim Ingham         // but it is more efficient.
1215822173bSJim Ingham 
1225822173bSJim Ingham         SetPlanComplete();
1235822173bSJim Ingham         return true;
1245822173bSJim Ingham     }
1255822173bSJim Ingham 
1265822173bSJim Ingham     // We may have set the plan up above in the FrameIsOlder section:
1275822173bSJim Ingham 
1285822173bSJim Ingham     if (new_plan == NULL)
12930fdc8d8SChris Lattner         new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
13008b87e0dSJim Ingham 
13108b87e0dSJim Ingham     if (log)
13208b87e0dSJim Ingham     {
13308b87e0dSJim Ingham         if (new_plan != NULL)
13408b87e0dSJim Ingham             log->Printf ("Found a step through plan: %s", new_plan->GetName());
13508b87e0dSJim Ingham         else
13608b87e0dSJim Ingham             log->Printf ("No step through plan found.");
13708b87e0dSJim Ingham     }
13808b87e0dSJim Ingham 
13930fdc8d8SChris Lattner     // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
14030fdc8d8SChris Lattner     // But only do that if we actually have stepped in.
14130fdc8d8SChris Lattner     if (!new_plan && FrameIsYounger())
14230fdc8d8SChris Lattner         new_plan = InvokeShouldStopHereCallback();
14330fdc8d8SChris Lattner 
1447ce490c6SJim Ingham     // If we've stepped in and we are going to stop here, check to see if we were asked to
1457ce490c6SJim Ingham     // run past the prologue, and if so do that.
1467ce490c6SJim Ingham 
1477ce490c6SJim Ingham     if (new_plan == NULL && FrameIsYounger() && m_step_past_prologue)
1487ce490c6SJim Ingham     {
1497ce490c6SJim Ingham         lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
1507ce490c6SJim Ingham         if (curr_frame)
1517ce490c6SJim Ingham         {
1527ce490c6SJim Ingham             size_t bytes_to_skip = 0;
1537ce490c6SJim Ingham             lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
1547ce490c6SJim Ingham             Address func_start_address;
1557ce490c6SJim Ingham 
1567ce490c6SJim Ingham             SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
1577ce490c6SJim Ingham 
1587ce490c6SJim Ingham             if (sc.function)
1597ce490c6SJim Ingham             {
1607ce490c6SJim Ingham                 func_start_address = sc.function->GetAddressRange().GetBaseAddress();
1617ce490c6SJim Ingham                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget()))
1627ce490c6SJim Ingham                     bytes_to_skip = sc.function->GetPrologueByteSize();
1637ce490c6SJim Ingham             }
1647ce490c6SJim Ingham             else if (sc.symbol)
1657ce490c6SJim Ingham             {
1667ce490c6SJim Ingham                 func_start_address = sc.symbol->GetValue();
1677ce490c6SJim Ingham                 if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget()))
1687ce490c6SJim Ingham                     bytes_to_skip = sc.symbol->GetPrologueByteSize();
1697ce490c6SJim Ingham             }
1707ce490c6SJim Ingham 
1717ce490c6SJim Ingham             if (bytes_to_skip != 0)
1727ce490c6SJim Ingham             {
1737ce490c6SJim Ingham                 func_start_address.Slide (bytes_to_skip);
17420ad3c40SCaroline Tice                 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
1757ce490c6SJim Ingham                 if (log)
1767ce490c6SJim Ingham                     log->Printf ("Pushing past prologue ");
1777ce490c6SJim Ingham 
1787ce490c6SJim Ingham                 new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
1797ce490c6SJim Ingham             }
1807ce490c6SJim Ingham         }
1817ce490c6SJim Ingham     }
1827ce490c6SJim Ingham 
18330fdc8d8SChris Lattner      if (new_plan == NULL)
18430fdc8d8SChris Lattner      {
18530fdc8d8SChris Lattner         m_no_more_plans = true;
18630fdc8d8SChris Lattner         SetPlanComplete();
18730fdc8d8SChris Lattner         return true;
18830fdc8d8SChris Lattner     }
18930fdc8d8SChris Lattner     else
19030fdc8d8SChris Lattner     {
19130fdc8d8SChris Lattner         m_no_more_plans = false;
19230fdc8d8SChris Lattner         return false;
19330fdc8d8SChris Lattner     }
19430fdc8d8SChris Lattner }
19530fdc8d8SChris Lattner 
19630fdc8d8SChris Lattner void
19730fdc8d8SChris Lattner ThreadPlanStepInRange::SetFlagsToDefault ()
19830fdc8d8SChris Lattner {
19930fdc8d8SChris Lattner     GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
20030fdc8d8SChris Lattner }
20130fdc8d8SChris Lattner 
20230fdc8d8SChris Lattner void
203a56c8006SJim Ingham ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
204a56c8006SJim Ingham {
205a56c8006SJim Ingham     if (m_avoid_regexp_ap.get() == NULL)
206a56c8006SJim Ingham         m_avoid_regexp_ap.reset (new RegularExpression(name));
207a56c8006SJim Ingham 
208a56c8006SJim Ingham     m_avoid_regexp_ap->Compile (name);
209a56c8006SJim Ingham }
210a56c8006SJim Ingham 
211a56c8006SJim Ingham void
21230fdc8d8SChris Lattner ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
21330fdc8d8SChris Lattner {
21430fdc8d8SChris Lattner     // TODO: Should we test this for sanity?
21530fdc8d8SChris Lattner     ThreadPlanStepInRange::s_default_flag_values = new_value;
21630fdc8d8SChris Lattner }
21730fdc8d8SChris Lattner 
218a56c8006SJim Ingham bool
219a56c8006SJim Ingham ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
220a56c8006SJim Ingham {
221a56c8006SJim Ingham     StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
222a56c8006SJim Ingham 
223ee8aea10SJim Ingham     RegularExpression *avoid_regexp_to_use;
224ee8aea10SJim Ingham 
225ee8aea10SJim Ingham     avoid_regexp_to_use = m_avoid_regexp_ap.get();
226ee8aea10SJim Ingham     if (avoid_regexp_to_use == NULL)
227ee8aea10SJim Ingham         avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
228ee8aea10SJim Ingham 
229ee8aea10SJim Ingham     if (avoid_regexp_to_use != NULL)
230a56c8006SJim Ingham     {
231a56c8006SJim Ingham         SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol);
232a56c8006SJim Ingham         if (sc.symbol != NULL)
233a56c8006SJim Ingham         {
234a56c8006SJim Ingham             const char *unnamed_symbol = "<UNKNOWN>";
235a56c8006SJim Ingham             const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol);
236a56c8006SJim Ingham             if (strcmp (sym_name, unnamed_symbol) != 0)
237ee8aea10SJim Ingham                return avoid_regexp_to_use->Execute(sym_name);
238a56c8006SJim Ingham         }
239a56c8006SJim Ingham     }
240a56c8006SJim Ingham     return false;
241a56c8006SJim Ingham }
242a56c8006SJim Ingham 
24330fdc8d8SChris Lattner ThreadPlan *
24430fdc8d8SChris Lattner ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
24530fdc8d8SChris Lattner {
246a56c8006SJim Ingham     bool should_step_out = false;
24730fdc8d8SChris Lattner     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
2482d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
24930fdc8d8SChris Lattner 
25073b472d4SGreg Clayton     if (flags.Test(eAvoidNoDebug))
251a56c8006SJim Ingham     {
25230fdc8d8SChris Lattner         if (!frame->HasDebugInformation())
253af0f1759SJim Ingham         {
254af0f1759SJim Ingham             if (log)
255af0f1759SJim Ingham                 log->Printf ("Stepping out of frame with no debug info");
256af0f1759SJim Ingham 
257a56c8006SJim Ingham             should_step_out = true;
258a56c8006SJim Ingham         }
259af0f1759SJim Ingham     }
260a56c8006SJim Ingham 
261a56c8006SJim Ingham     if (!should_step_out)
262a56c8006SJim Ingham     {
263a56c8006SJim Ingham         if (current_plan->GetKind() == eKindStepInRange)
264a56c8006SJim Ingham         {
265a56c8006SJim Ingham             ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
266a56c8006SJim Ingham             should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
267a56c8006SJim Ingham         }
268a56c8006SJim Ingham     }
269a56c8006SJim Ingham 
270a56c8006SJim Ingham     if (should_step_out)
27130fdc8d8SChris Lattner     {
27230fdc8d8SChris Lattner         // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
273*481cef25SGreg Clayton         return current_plan->GetThread().QueueThreadPlanForStepOut (false,
274*481cef25SGreg Clayton                                                                     NULL,
275*481cef25SGreg Clayton                                                                     true,
276a56c8006SJim Ingham                                                                     current_plan->StopOthers(),
277*481cef25SGreg Clayton                                                                     eVoteNo,
278*481cef25SGreg Clayton                                                                     eVoteNoOpinion,
279*481cef25SGreg Clayton                                                                     0); // Frame index
28030fdc8d8SChris Lattner     }
28130fdc8d8SChris Lattner 
28230fdc8d8SChris Lattner     return NULL;
28330fdc8d8SChris Lattner }
284