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