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" 194da6206dSJim Ingham #include "lldb/Core/Module.h" 2030fdc8d8SChris Lattner #include "lldb/Core/Stream.h" 21a56c8006SJim Ingham #include "lldb/Symbol/Symbol.h" 227ce490c6SJim Ingham #include "lldb/Symbol/Function.h" 2330fdc8d8SChris Lattner #include "lldb/Target/Process.h" 2430fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h" 25514487e8SGreg Clayton #include "lldb/Target/Target.h" 2630fdc8d8SChris Lattner #include "lldb/Target/Thread.h" 2730fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h" 2830fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h" 29a56c8006SJim Ingham #include "lldb/Core/RegularExpression.h" 3030fdc8d8SChris Lattner 3130fdc8d8SChris Lattner using namespace lldb; 3230fdc8d8SChris Lattner using namespace lldb_private; 3330fdc8d8SChris Lattner 3430fdc8d8SChris Lattner uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug; 3530fdc8d8SChris Lattner 3630fdc8d8SChris Lattner //---------------------------------------------------------------------- 3730fdc8d8SChris Lattner // ThreadPlanStepInRange: Step through a stack range, either stepping over or into 3830fdc8d8SChris Lattner // based on the value of \a type. 3930fdc8d8SChris Lattner //---------------------------------------------------------------------- 4030fdc8d8SChris Lattner 4130fdc8d8SChris Lattner ThreadPlanStepInRange::ThreadPlanStepInRange 4230fdc8d8SChris Lattner ( 4330fdc8d8SChris Lattner Thread &thread, 4430fdc8d8SChris Lattner const AddressRange &range, 4530fdc8d8SChris Lattner const SymbolContext &addr_context, 4630fdc8d8SChris Lattner lldb::RunMode stop_others 4730fdc8d8SChris Lattner ) : 48b01e742aSJim Ingham ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), 497ce490c6SJim Ingham ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL), 50f02a2e96SJim Ingham m_step_past_prologue (true), 51f02a2e96SJim Ingham m_virtual_step (false) 5230fdc8d8SChris Lattner { 5330fdc8d8SChris Lattner SetFlagsToDefault (); 5430fdc8d8SChris Lattner } 5530fdc8d8SChris Lattner 56c627682eSJim Ingham ThreadPlanStepInRange::ThreadPlanStepInRange 57c627682eSJim Ingham ( 58c627682eSJim Ingham Thread &thread, 59c627682eSJim Ingham const AddressRange &range, 60c627682eSJim Ingham const SymbolContext &addr_context, 61c627682eSJim Ingham const char *step_into_target, 62c627682eSJim Ingham lldb::RunMode stop_others 63c627682eSJim Ingham ) : 64c627682eSJim Ingham ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), 65c627682eSJim Ingham ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL), 66c627682eSJim Ingham m_step_past_prologue (true), 67c627682eSJim Ingham m_virtual_step (false), 68c627682eSJim Ingham m_step_into_target (step_into_target) 69c627682eSJim Ingham { 70c627682eSJim Ingham SetFlagsToDefault (); 71c627682eSJim Ingham } 72c627682eSJim Ingham 7330fdc8d8SChris Lattner ThreadPlanStepInRange::~ThreadPlanStepInRange () 7430fdc8d8SChris Lattner { 7530fdc8d8SChris Lattner } 7630fdc8d8SChris Lattner 7730fdc8d8SChris Lattner void 7830fdc8d8SChris Lattner ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level) 7930fdc8d8SChris Lattner { 8030fdc8d8SChris Lattner if (level == lldb::eDescriptionLevelBrief) 8130fdc8d8SChris Lattner s->Printf("step in"); 8230fdc8d8SChris Lattner else 8330fdc8d8SChris Lattner { 8430fdc8d8SChris Lattner s->Printf ("Stepping through range (stepping into functions): "); 85c4c9fedcSJim Ingham DumpRanges(s); 864d56e9c1SJim Ingham const char *step_into_target = m_step_into_target.AsCString(); 874d56e9c1SJim Ingham if (step_into_target && step_into_target[0] != '\0') 88c627682eSJim Ingham s->Printf (" targeting %s.", m_step_into_target.AsCString()); 894d56e9c1SJim Ingham else 904d56e9c1SJim Ingham s->PutChar('.'); 9130fdc8d8SChris Lattner } 9230fdc8d8SChris Lattner } 9330fdc8d8SChris Lattner 9430fdc8d8SChris Lattner bool 9530fdc8d8SChris Lattner ThreadPlanStepInRange::ShouldStop (Event *event_ptr) 9630fdc8d8SChris Lattner { 975160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 9830fdc8d8SChris Lattner 9930fdc8d8SChris Lattner if (log) 10030fdc8d8SChris Lattner { 10130fdc8d8SChris Lattner StreamString s; 102514487e8SGreg Clayton s.Address (m_thread.GetRegisterContext()->GetPC(), 1031ac04c30SGreg Clayton m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); 10430fdc8d8SChris Lattner log->Printf("ThreadPlanStepInRange reached %s.", s.GetData()); 10530fdc8d8SChris Lattner } 10630fdc8d8SChris Lattner 10725f66700SJim Ingham if (IsPlanComplete()) 10825f66700SJim Ingham return true; 10925f66700SJim Ingham 1104d56e9c1SJim Ingham m_no_more_plans = false; 1114d56e9c1SJim Ingham if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) 1124d56e9c1SJim Ingham { 1134d56e9c1SJim Ingham if (!m_sub_plan_sp->PlanSucceeded()) 1144d56e9c1SJim Ingham { 1154d56e9c1SJim Ingham SetPlanComplete(); 1164d56e9c1SJim Ingham m_no_more_plans = true; 1174d56e9c1SJim Ingham return true; 1184d56e9c1SJim Ingham } 1194d56e9c1SJim Ingham else 1204d56e9c1SJim Ingham m_sub_plan_sp.reset(); 1214d56e9c1SJim Ingham } 12230fdc8d8SChris Lattner 123f02a2e96SJim Ingham if (m_virtual_step) 124f02a2e96SJim Ingham { 125f02a2e96SJim Ingham // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise 126f02a2e96SJim Ingham // we're done. 1274d56e9c1SJim Ingham m_sub_plan_sp = InvokeShouldStopHereCallback(); 128f02a2e96SJim Ingham } 129f02a2e96SJim Ingham else 130f02a2e96SJim Ingham { 1314a58e968SJim Ingham // Stepping through should be done running other threads in general, since we're setting a breakpoint and 1324a58e968SJim Ingham // continuing. So only stop others if we are explicitly told to do so. 1339d790c5dSJim Ingham 13430fdc8d8SChris Lattner bool stop_others; 1354a58e968SJim Ingham if (m_stop_others == lldb::eOnlyThisThread) 1364a58e968SJim Ingham stop_others = true; 1376cf5b8f1SEd Maste else 1386cf5b8f1SEd Maste stop_others = false; 13930fdc8d8SChris Lattner 140b5c0d1ccSJim Ingham FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 141b5c0d1ccSJim Ingham 142b5c0d1ccSJim Ingham if (frame_order == eFrameCompareOlder) 1435822173bSJim Ingham { 1445822173bSJim Ingham // If we're in an older frame then we should stop. 1455822173bSJim Ingham // 1465822173bSJim Ingham // A caveat to this is if we think the frame is older but we're actually in a trampoline. 1475822173bSJim Ingham // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are 1485822173bSJim Ingham // in a trampoline we think the frame is older because the trampoline confused the backtracer. 1494d56e9c1SJim Ingham m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); 1504d56e9c1SJim Ingham if (!m_sub_plan_sp) 1515822173bSJim Ingham return true; 1525822173bSJim Ingham else if (log) 1535822173bSJim Ingham { 1545822173bSJim Ingham log->Printf("Thought I stepped out, but in fact arrived at a trampoline."); 1555822173bSJim Ingham } 1565822173bSJim Ingham 1575822173bSJim Ingham } 158564d8bc2SJim Ingham else if (frame_order == eFrameCompareEqual && InSymbol()) 1595822173bSJim Ingham { 1605822173bSJim Ingham // If we are not in a place we should step through, we're done. 1615822173bSJim Ingham // One tricky bit here is that some stubs don't push a frame, so we have to check 1625822173bSJim Ingham // both the case of a frame that is younger, or the same as this frame. 1635822173bSJim Ingham // However, if the frame is the same, and we are still in the symbol we started 1645822173bSJim Ingham // in, the we don't need to do this. This first check isn't strictly necessary, 1655822173bSJim Ingham // but it is more efficient. 1665822173bSJim Ingham 167564d8bc2SJim Ingham // If we're still in the range, keep going, either by running to the next branch breakpoint, or by 168564d8bc2SJim Ingham // stepping. 169564d8bc2SJim Ingham if (InRange()) 170564d8bc2SJim Ingham { 171564d8bc2SJim Ingham SetNextBranchBreakpoint(); 172564d8bc2SJim Ingham return false; 173564d8bc2SJim Ingham } 174564d8bc2SJim Ingham 1755822173bSJim Ingham SetPlanComplete(); 176c627682eSJim Ingham m_no_more_plans = true; 1775822173bSJim Ingham return true; 1785822173bSJim Ingham } 1795822173bSJim Ingham 180564d8bc2SJim Ingham // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it: 181564d8bc2SJim Ingham ClearNextBranchBreakpoint(); 182564d8bc2SJim Ingham 1835822173bSJim Ingham // We may have set the plan up above in the FrameIsOlder section: 1845822173bSJim Ingham 1854d56e9c1SJim Ingham if (!m_sub_plan_sp) 1864d56e9c1SJim Ingham m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); 18708b87e0dSJim Ingham 18808b87e0dSJim Ingham if (log) 18908b87e0dSJim Ingham { 1904d56e9c1SJim Ingham if (m_sub_plan_sp) 1914d56e9c1SJim Ingham log->Printf ("Found a step through plan: %s", m_sub_plan_sp->GetName()); 19208b87e0dSJim Ingham else 19308b87e0dSJim Ingham log->Printf ("No step through plan found."); 19408b87e0dSJim Ingham } 19508b87e0dSJim Ingham 19630fdc8d8SChris Lattner // If not, give the "should_stop" callback a chance to push a plan to get us out of here. 19730fdc8d8SChris Lattner // But only do that if we actually have stepped in. 1984d56e9c1SJim Ingham if (!m_sub_plan_sp && frame_order == eFrameCompareYounger) 1994d56e9c1SJim Ingham m_sub_plan_sp = InvokeShouldStopHereCallback(); 20030fdc8d8SChris Lattner 2017ce490c6SJim Ingham // If we've stepped in and we are going to stop here, check to see if we were asked to 2027ce490c6SJim Ingham // run past the prologue, and if so do that. 2037ce490c6SJim Ingham 2044d56e9c1SJim Ingham if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue) 2057ce490c6SJim Ingham { 206b57e4a1bSJason Molenda lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); 2077ce490c6SJim Ingham if (curr_frame) 2087ce490c6SJim Ingham { 2097ce490c6SJim Ingham size_t bytes_to_skip = 0; 2107ce490c6SJim Ingham lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); 2117ce490c6SJim Ingham Address func_start_address; 2127ce490c6SJim Ingham 2137ce490c6SJim Ingham SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol); 2147ce490c6SJim Ingham 2157ce490c6SJim Ingham if (sc.function) 2167ce490c6SJim Ingham { 2177ce490c6SJim Ingham func_start_address = sc.function->GetAddressRange().GetBaseAddress(); 218d9e416c0SGreg Clayton if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get())) 2197ce490c6SJim Ingham bytes_to_skip = sc.function->GetPrologueByteSize(); 2207ce490c6SJim Ingham } 2217ce490c6SJim Ingham else if (sc.symbol) 2227ce490c6SJim Ingham { 223e7612134SGreg Clayton func_start_address = sc.symbol->GetAddress(); 224d9e416c0SGreg Clayton if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get())) 2257ce490c6SJim Ingham bytes_to_skip = sc.symbol->GetPrologueByteSize(); 2267ce490c6SJim Ingham } 2277ce490c6SJim Ingham 2287ce490c6SJim Ingham if (bytes_to_skip != 0) 2297ce490c6SJim Ingham { 2307ce490c6SJim Ingham func_start_address.Slide (bytes_to_skip); 23120ad3c40SCaroline Tice log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); 2327ce490c6SJim Ingham if (log) 2337ce490c6SJim Ingham log->Printf ("Pushing past prologue "); 2347ce490c6SJim Ingham 2354d56e9c1SJim Ingham m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true); 2367ce490c6SJim Ingham } 2377ce490c6SJim Ingham } 2387ce490c6SJim Ingham } 239f02a2e96SJim Ingham } 2407ce490c6SJim Ingham 2414d56e9c1SJim Ingham if (!m_sub_plan_sp) 24230fdc8d8SChris Lattner { 24330fdc8d8SChris Lattner m_no_more_plans = true; 24430fdc8d8SChris Lattner SetPlanComplete(); 24530fdc8d8SChris Lattner return true; 24630fdc8d8SChris Lattner } 24730fdc8d8SChris Lattner else 24830fdc8d8SChris Lattner { 24930fdc8d8SChris Lattner m_no_more_plans = false; 25030fdc8d8SChris Lattner return false; 25130fdc8d8SChris Lattner } 25230fdc8d8SChris Lattner } 25330fdc8d8SChris Lattner 25430fdc8d8SChris Lattner void 25530fdc8d8SChris Lattner ThreadPlanStepInRange::SetFlagsToDefault () 25630fdc8d8SChris Lattner { 25730fdc8d8SChris Lattner GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values); 25830fdc8d8SChris Lattner } 25930fdc8d8SChris Lattner 26030fdc8d8SChris Lattner void 261a56c8006SJim Ingham ThreadPlanStepInRange::SetAvoidRegexp(const char *name) 262a56c8006SJim Ingham { 263a56c8006SJim Ingham if (m_avoid_regexp_ap.get() == NULL) 264a56c8006SJim Ingham m_avoid_regexp_ap.reset (new RegularExpression(name)); 265a56c8006SJim Ingham 266a56c8006SJim Ingham m_avoid_regexp_ap->Compile (name); 267a56c8006SJim Ingham } 268a56c8006SJim Ingham 269a56c8006SJim Ingham void 27030fdc8d8SChris Lattner ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value) 27130fdc8d8SChris Lattner { 27230fdc8d8SChris Lattner // TODO: Should we test this for sanity? 27330fdc8d8SChris Lattner ThreadPlanStepInRange::s_default_flag_values = new_value; 27430fdc8d8SChris Lattner } 27530fdc8d8SChris Lattner 276a56c8006SJim Ingham bool 2774da6206dSJim Ingham ThreadPlanStepInRange::FrameMatchesAvoidCriteria () 278a56c8006SJim Ingham { 279b57e4a1bSJason Molenda StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get(); 280a56c8006SJim Ingham 2814da6206dSJim Ingham // Check the library list first, as that's cheapest: 282*a786e539SJim Ingham bool libraries_say_avoid = false; 283*a786e539SJim Ingham 2844da6206dSJim Ingham FileSpecList libraries_to_avoid (GetThread().GetLibrariesToAvoid()); 2854da6206dSJim Ingham size_t num_libraries = libraries_to_avoid.GetSize(); 286*a786e539SJim Ingham if (num_libraries > 0) 287*a786e539SJim Ingham { 2884da6206dSJim Ingham SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule)); 2894da6206dSJim Ingham FileSpec frame_library(sc.module_sp->GetFileSpec()); 2904da6206dSJim Ingham 2914da6206dSJim Ingham if (frame_library) 2924da6206dSJim Ingham { 2934da6206dSJim Ingham for (size_t i = 0; i < num_libraries; i++) 2944da6206dSJim Ingham { 2954da6206dSJim Ingham const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i)); 2964da6206dSJim Ingham if (FileSpec::Equal (file_spec, frame_library, false)) 2974da6206dSJim Ingham { 2984da6206dSJim Ingham libraries_say_avoid = true; 2994da6206dSJim Ingham break; 3004da6206dSJim Ingham } 3014da6206dSJim Ingham } 3024da6206dSJim Ingham } 303*a786e539SJim Ingham } 3044da6206dSJim Ingham if (libraries_say_avoid) 3054da6206dSJim Ingham return true; 3064da6206dSJim Ingham 30767cc0636SGreg Clayton const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get(); 308ee8aea10SJim Ingham if (avoid_regexp_to_use == NULL) 309ee8aea10SJim Ingham avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp(); 310ee8aea10SJim Ingham 311ee8aea10SJim Ingham if (avoid_regexp_to_use != NULL) 312a56c8006SJim Ingham { 3134592cbc4SGreg Clayton SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol); 314a56c8006SJim Ingham if (sc.symbol != NULL) 315a56c8006SJim Ingham { 3164592cbc4SGreg Clayton const char *frame_function_name = sc.GetFunctionName().GetCString(); 3174592cbc4SGreg Clayton if (frame_function_name) 3183101ba33SJim Ingham { 319cf2667c4SJim Ingham size_t num_matches = 0; 3205160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 3213101ba33SJim Ingham if (log) 322cf2667c4SJim Ingham num_matches = 1; 323bc43cab5SGreg Clayton 324bc43cab5SGreg Clayton RegularExpression::Match regex_match(num_matches); 325bc43cab5SGreg Clayton 326bc43cab5SGreg Clayton bool return_value = avoid_regexp_to_use->Execute(frame_function_name, ®ex_match); 327cf2667c4SJim Ingham if (return_value) 328cf2667c4SJim Ingham { 329cf2667c4SJim Ingham if (log) 330cf2667c4SJim Ingham { 331cf2667c4SJim Ingham std::string match; 332bc43cab5SGreg Clayton regex_match.GetMatchAtIndex(frame_function_name,0, match); 333cf2667c4SJim Ingham log->Printf ("Stepping out of function \"%s\" because it matches the avoid regexp \"%s\" - match substring: \"%s\".", 3343101ba33SJim Ingham frame_function_name, 335cf2667c4SJim Ingham avoid_regexp_to_use->GetText(), 336cf2667c4SJim Ingham match.c_str()); 337cf2667c4SJim Ingham } 3383101ba33SJim Ingham 3393101ba33SJim Ingham } 3403101ba33SJim Ingham return return_value; 3413101ba33SJim Ingham } 342a56c8006SJim Ingham } 343a56c8006SJim Ingham } 344a56c8006SJim Ingham return false; 345a56c8006SJim Ingham } 346a56c8006SJim Ingham 3474d56e9c1SJim Ingham ThreadPlanSP 34830fdc8d8SChris Lattner ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton) 34930fdc8d8SChris Lattner { 350a56c8006SJim Ingham bool should_step_out = false; 351b57e4a1bSJason Molenda StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 3525160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 35330fdc8d8SChris Lattner 35473b472d4SGreg Clayton if (flags.Test(eAvoidNoDebug)) 355a56c8006SJim Ingham { 35630fdc8d8SChris Lattner if (!frame->HasDebugInformation()) 357af0f1759SJim Ingham { 358af0f1759SJim Ingham if (log) 359af0f1759SJim Ingham log->Printf ("Stepping out of frame with no debug info"); 360af0f1759SJim Ingham 361a56c8006SJim Ingham should_step_out = true; 362a56c8006SJim Ingham } 363af0f1759SJim Ingham } 364a56c8006SJim Ingham 365a56c8006SJim Ingham if (current_plan->GetKind() == eKindStepInRange) 366a56c8006SJim Ingham { 367a56c8006SJim Ingham ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); 368c627682eSJim Ingham if (step_in_range_plan->m_step_into_target) 369c627682eSJim Ingham { 370c627682eSJim Ingham SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol); 371c627682eSJim Ingham if (sc.symbol != NULL) 372c627682eSJim Ingham { 373c627682eSJim Ingham // First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare. 374c627682eSJim Ingham if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) 375c627682eSJim Ingham { 376c627682eSJim Ingham should_step_out = false; 377c627682eSJim Ingham } 378c627682eSJim Ingham else 379c627682eSJim Ingham { 380c627682eSJim Ingham const char *target_name = step_in_range_plan->m_step_into_target.AsCString(); 381c627682eSJim Ingham const char *function_name = sc.GetFunctionName().AsCString(); 382c627682eSJim Ingham 383c627682eSJim Ingham if (function_name == NULL) 384c627682eSJim Ingham should_step_out = true; 385c627682eSJim Ingham else if (strstr (function_name, target_name) == NULL) 386c627682eSJim Ingham should_step_out = true; 387c627682eSJim Ingham } 3883101ba33SJim Ingham if (log && should_step_out) 3893101ba33SJim Ingham log->Printf("Stepping out of frame %s which did not match step into target %s.", 3903101ba33SJim Ingham sc.GetFunctionName().AsCString(), 3913101ba33SJim Ingham step_in_range_plan->m_step_into_target.AsCString()); 392c627682eSJim Ingham } 393c627682eSJim Ingham } 394c627682eSJim Ingham 395c627682eSJim Ingham if (!should_step_out) 396c627682eSJim Ingham { 397c627682eSJim Ingham ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); 3984da6206dSJim Ingham // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria. 3994da6206dSJim Ingham should_step_out = step_in_range_plan->FrameMatchesAvoidCriteria (); 400a56c8006SJim Ingham } 401a56c8006SJim Ingham } 402a56c8006SJim Ingham 403c627682eSJim Ingham 404a56c8006SJim Ingham if (should_step_out) 40530fdc8d8SChris Lattner { 40630fdc8d8SChris Lattner // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions. 4074a58e968SJim Ingham // We really should have all plans take the tri-state for "stop others" so we can do the right 4084a58e968SJim Ingham // thing. For now let's be safe and always run others when we are likely to run arbitrary code. 4094a58e968SJim Ingham const bool stop_others = false; 410481cef25SGreg Clayton return current_plan->GetThread().QueueThreadPlanForStepOut (false, 411481cef25SGreg Clayton NULL, 412481cef25SGreg Clayton true, 4134a58e968SJim Ingham stop_others, 414481cef25SGreg Clayton eVoteNo, 415481cef25SGreg Clayton eVoteNoOpinion, 416481cef25SGreg Clayton 0); // Frame index 41730fdc8d8SChris Lattner } 41830fdc8d8SChris Lattner 4194d56e9c1SJim Ingham return ThreadPlanSP(); 42030fdc8d8SChris Lattner } 421fbbfe6ecSJim Ingham 422fbbfe6ecSJim Ingham bool 423221d51cfSJim Ingham ThreadPlanStepInRange::DoPlanExplainsStop (Event *event_ptr) 424fbbfe6ecSJim Ingham { 425fbbfe6ecSJim Ingham // We always explain a stop. Either we've just done a single step, in which 426fbbfe6ecSJim Ingham // case we'll do our ordinary processing, or we stopped for some 427fbbfe6ecSJim Ingham // reason that isn't handled by our sub-plans, in which case we want to just stop right 428fbbfe6ecSJim Ingham // away. 429c627682eSJim Ingham // In general, we don't want to mark the plan as complete for unexplained stops. 430c627682eSJim Ingham // For instance, if you step in to some code with no debug info, so you step out 431c627682eSJim Ingham // and in the course of that hit a breakpoint, then you want to stop & show the user 432c627682eSJim Ingham // the breakpoint, but not unship the step in plan, since you still may want to complete that 433c627682eSJim Ingham // plan when you continue. This is particularly true when doing "step in to target function." 434c627682eSJim Ingham // stepping. 435fbbfe6ecSJim Ingham // 436fbbfe6ecSJim Ingham // The only variation is that if we are doing "step by running to next branch" in which case 437fbbfe6ecSJim Ingham // if we hit our branch breakpoint we don't set the plan to complete. 438fbbfe6ecSJim Ingham 439221d51cfSJim Ingham bool return_value; 440f02a2e96SJim Ingham 441221d51cfSJim Ingham if (m_virtual_step) 442221d51cfSJim Ingham { 443221d51cfSJim Ingham return_value = true; 444221d51cfSJim Ingham } 445221d51cfSJim Ingham else 446221d51cfSJim Ingham { 44760c4118cSJim Ingham StopInfoSP stop_info_sp = GetPrivateStopInfo (); 448fbbfe6ecSJim Ingham if (stop_info_sp) 449fbbfe6ecSJim Ingham { 450fbbfe6ecSJim Ingham StopReason reason = stop_info_sp->GetStopReason(); 451fbbfe6ecSJim Ingham 452fbbfe6ecSJim Ingham switch (reason) 453fbbfe6ecSJim Ingham { 454fbbfe6ecSJim Ingham case eStopReasonBreakpoint: 455fbbfe6ecSJim Ingham if (NextRangeBreakpointExplainsStop(stop_info_sp)) 456221d51cfSJim Ingham { 457221d51cfSJim Ingham return_value = true; 458221d51cfSJim Ingham break; 459221d51cfSJim Ingham } 460fbbfe6ecSJim Ingham case eStopReasonWatchpoint: 461fbbfe6ecSJim Ingham case eStopReasonSignal: 462fbbfe6ecSJim Ingham case eStopReasonException: 46390ba8115SGreg Clayton case eStopReasonExec: 464f85defaeSAndrew Kaylor case eStopReasonThreadExiting: 465513c6bb8SJim Ingham { 4665160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 467fbbfe6ecSJim Ingham if (log) 468fbbfe6ecSJim Ingham log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); 469513c6bb8SJim Ingham } 470221d51cfSJim Ingham return_value = false; 471fbbfe6ecSJim Ingham break; 472fbbfe6ecSJim Ingham default: 473221d51cfSJim Ingham return_value = true; 474fbbfe6ecSJim Ingham break; 475fbbfe6ecSJim Ingham } 476fbbfe6ecSJim Ingham } 477221d51cfSJim Ingham else 478221d51cfSJim Ingham return_value = true; 479221d51cfSJim Ingham } 480221d51cfSJim Ingham 481221d51cfSJim Ingham return return_value; 482fbbfe6ecSJim Ingham } 483513c6bb8SJim Ingham 484513c6bb8SJim Ingham bool 485221d51cfSJim Ingham ThreadPlanStepInRange::DoWillResume (lldb::StateType resume_state, bool current_plan) 486513c6bb8SJim Ingham { 487513c6bb8SJim Ingham if (resume_state == eStateStepping && current_plan) 488513c6bb8SJim Ingham { 489513c6bb8SJim Ingham // See if we are about to step over a virtual inlined call. 490513c6bb8SJim Ingham bool step_without_resume = m_thread.DecrementCurrentInlinedDepth(); 491513c6bb8SJim Ingham if (step_without_resume) 492513c6bb8SJim Ingham { 4935160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 494513c6bb8SJim Ingham if (log) 495221d51cfSJim Ingham log->Printf ("ThreadPlanStepInRange::DoWillResume: returning false, inline_depth: %d", 496513c6bb8SJim Ingham m_thread.GetCurrentInlinedDepth()); 497513c6bb8SJim Ingham SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread)); 498f02a2e96SJim Ingham 499f02a2e96SJim Ingham // FIXME: Maybe it would be better to create a InlineStep stop reason, but then 500f02a2e96SJim Ingham // the whole rest of the world would have to handle that stop reason. 501f02a2e96SJim Ingham m_virtual_step = true; 502513c6bb8SJim Ingham } 503513c6bb8SJim Ingham return !step_without_resume; 504513c6bb8SJim Ingham } 505221d51cfSJim Ingham return true; 506513c6bb8SJim Ingham } 507246cb611SDaniel Malea 508246cb611SDaniel Malea bool 509246cb611SDaniel Malea ThreadPlanStepInRange::IsVirtualStep() 510246cb611SDaniel Malea { 511246cb611SDaniel Malea return m_virtual_step; 512246cb611SDaniel Malea } 513