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), 49f02a2e96SJim Ingham m_step_past_prologue (true), 50f02a2e96SJim Ingham m_virtual_step (false) 5130fdc8d8SChris Lattner { 5230fdc8d8SChris Lattner SetFlagsToDefault (); 5330fdc8d8SChris Lattner } 5430fdc8d8SChris Lattner 55c627682eSJim Ingham ThreadPlanStepInRange::ThreadPlanStepInRange 56c627682eSJim Ingham ( 57c627682eSJim Ingham Thread &thread, 58c627682eSJim Ingham const AddressRange &range, 59c627682eSJim Ingham const SymbolContext &addr_context, 60c627682eSJim Ingham const char *step_into_target, 61c627682eSJim Ingham lldb::RunMode stop_others 62c627682eSJim Ingham ) : 63c627682eSJim Ingham ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), 64c627682eSJim Ingham ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL), 65c627682eSJim Ingham m_step_past_prologue (true), 66c627682eSJim Ingham m_virtual_step (false), 67c627682eSJim Ingham m_step_into_target (step_into_target) 68c627682eSJim Ingham { 69c627682eSJim Ingham SetFlagsToDefault (); 70c627682eSJim Ingham } 71c627682eSJim Ingham 7230fdc8d8SChris Lattner ThreadPlanStepInRange::~ThreadPlanStepInRange () 7330fdc8d8SChris Lattner { 7430fdc8d8SChris Lattner } 7530fdc8d8SChris Lattner 7630fdc8d8SChris Lattner void 7730fdc8d8SChris Lattner ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level) 7830fdc8d8SChris Lattner { 7930fdc8d8SChris Lattner if (level == lldb::eDescriptionLevelBrief) 8030fdc8d8SChris Lattner s->Printf("step in"); 8130fdc8d8SChris Lattner else 8230fdc8d8SChris Lattner { 8330fdc8d8SChris Lattner s->Printf ("Stepping through range (stepping into functions): "); 84c4c9fedcSJim Ingham DumpRanges(s); 854d56e9c1SJim Ingham const char *step_into_target = m_step_into_target.AsCString(); 864d56e9c1SJim Ingham if (step_into_target && step_into_target[0] != '\0') 87c627682eSJim Ingham s->Printf (" targeting %s.", m_step_into_target.AsCString()); 884d56e9c1SJim Ingham else 894d56e9c1SJim Ingham s->PutChar('.'); 9030fdc8d8SChris Lattner } 9130fdc8d8SChris Lattner } 9230fdc8d8SChris Lattner 9330fdc8d8SChris Lattner bool 9430fdc8d8SChris Lattner ThreadPlanStepInRange::ShouldStop (Event *event_ptr) 9530fdc8d8SChris Lattner { 965160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 9730fdc8d8SChris Lattner 9830fdc8d8SChris Lattner if (log) 9930fdc8d8SChris Lattner { 10030fdc8d8SChris Lattner StreamString s; 101514487e8SGreg Clayton s.Address (m_thread.GetRegisterContext()->GetPC(), 1021ac04c30SGreg Clayton m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); 10330fdc8d8SChris Lattner log->Printf("ThreadPlanStepInRange reached %s.", s.GetData()); 10430fdc8d8SChris Lattner } 10530fdc8d8SChris Lattner 10625f66700SJim Ingham if (IsPlanComplete()) 10725f66700SJim Ingham return true; 10825f66700SJim Ingham 1094d56e9c1SJim Ingham m_no_more_plans = false; 1104d56e9c1SJim Ingham if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) 1114d56e9c1SJim Ingham { 1124d56e9c1SJim Ingham if (!m_sub_plan_sp->PlanSucceeded()) 1134d56e9c1SJim Ingham { 1144d56e9c1SJim Ingham SetPlanComplete(); 1154d56e9c1SJim Ingham m_no_more_plans = true; 1164d56e9c1SJim Ingham return true; 1174d56e9c1SJim Ingham } 1184d56e9c1SJim Ingham else 1194d56e9c1SJim Ingham m_sub_plan_sp.reset(); 1204d56e9c1SJim Ingham } 12130fdc8d8SChris Lattner 122f02a2e96SJim Ingham if (m_virtual_step) 123f02a2e96SJim Ingham { 124f02a2e96SJim Ingham // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise 125f02a2e96SJim Ingham // we're done. 1264d56e9c1SJim Ingham m_sub_plan_sp = InvokeShouldStopHereCallback(); 127f02a2e96SJim Ingham } 128f02a2e96SJim Ingham else 129f02a2e96SJim Ingham { 1304a58e968SJim Ingham // Stepping through should be done running other threads in general, since we're setting a breakpoint and 1314a58e968SJim Ingham // continuing. So only stop others if we are explicitly told to do so. 1329d790c5dSJim Ingham 13330fdc8d8SChris Lattner bool stop_others; 1344a58e968SJim Ingham if (m_stop_others == lldb::eOnlyThisThread) 1354a58e968SJim Ingham stop_others = true; 136*6cf5b8f1SEd Maste else 137*6cf5b8f1SEd Maste stop_others = false; 13830fdc8d8SChris Lattner 139b5c0d1ccSJim Ingham FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 140b5c0d1ccSJim Ingham 141b5c0d1ccSJim Ingham if (frame_order == eFrameCompareOlder) 1425822173bSJim Ingham { 1435822173bSJim Ingham // If we're in an older frame then we should stop. 1445822173bSJim Ingham // 1455822173bSJim Ingham // A caveat to this is if we think the frame is older but we're actually in a trampoline. 1465822173bSJim Ingham // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are 1475822173bSJim Ingham // in a trampoline we think the frame is older because the trampoline confused the backtracer. 1484d56e9c1SJim Ingham m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); 1494d56e9c1SJim Ingham if (!m_sub_plan_sp) 1505822173bSJim Ingham return true; 1515822173bSJim Ingham else if (log) 1525822173bSJim Ingham { 1535822173bSJim Ingham log->Printf("Thought I stepped out, but in fact arrived at a trampoline."); 1545822173bSJim Ingham } 1555822173bSJim Ingham 1565822173bSJim Ingham } 157564d8bc2SJim Ingham else if (frame_order == eFrameCompareEqual && InSymbol()) 1585822173bSJim Ingham { 1595822173bSJim Ingham // If we are not in a place we should step through, we're done. 1605822173bSJim Ingham // One tricky bit here is that some stubs don't push a frame, so we have to check 1615822173bSJim Ingham // both the case of a frame that is younger, or the same as this frame. 1625822173bSJim Ingham // However, if the frame is the same, and we are still in the symbol we started 1635822173bSJim Ingham // in, the we don't need to do this. This first check isn't strictly necessary, 1645822173bSJim Ingham // but it is more efficient. 1655822173bSJim Ingham 166564d8bc2SJim Ingham // If we're still in the range, keep going, either by running to the next branch breakpoint, or by 167564d8bc2SJim Ingham // stepping. 168564d8bc2SJim Ingham if (InRange()) 169564d8bc2SJim Ingham { 170564d8bc2SJim Ingham SetNextBranchBreakpoint(); 171564d8bc2SJim Ingham return false; 172564d8bc2SJim Ingham } 173564d8bc2SJim Ingham 1745822173bSJim Ingham SetPlanComplete(); 175c627682eSJim Ingham m_no_more_plans = true; 1765822173bSJim Ingham return true; 1775822173bSJim Ingham } 1785822173bSJim Ingham 179564d8bc2SJim Ingham // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it: 180564d8bc2SJim Ingham ClearNextBranchBreakpoint(); 181564d8bc2SJim Ingham 1825822173bSJim Ingham // We may have set the plan up above in the FrameIsOlder section: 1835822173bSJim Ingham 1844d56e9c1SJim Ingham if (!m_sub_plan_sp) 1854d56e9c1SJim Ingham m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); 18608b87e0dSJim Ingham 18708b87e0dSJim Ingham if (log) 18808b87e0dSJim Ingham { 1894d56e9c1SJim Ingham if (m_sub_plan_sp) 1904d56e9c1SJim Ingham log->Printf ("Found a step through plan: %s", m_sub_plan_sp->GetName()); 19108b87e0dSJim Ingham else 19208b87e0dSJim Ingham log->Printf ("No step through plan found."); 19308b87e0dSJim Ingham } 19408b87e0dSJim Ingham 19530fdc8d8SChris Lattner // If not, give the "should_stop" callback a chance to push a plan to get us out of here. 19630fdc8d8SChris Lattner // But only do that if we actually have stepped in. 1974d56e9c1SJim Ingham if (!m_sub_plan_sp && frame_order == eFrameCompareYounger) 1984d56e9c1SJim Ingham m_sub_plan_sp = InvokeShouldStopHereCallback(); 19930fdc8d8SChris Lattner 2007ce490c6SJim Ingham // If we've stepped in and we are going to stop here, check to see if we were asked to 2017ce490c6SJim Ingham // run past the prologue, and if so do that. 2027ce490c6SJim Ingham 2034d56e9c1SJim Ingham if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue) 2047ce490c6SJim Ingham { 205b57e4a1bSJason Molenda lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); 2067ce490c6SJim Ingham if (curr_frame) 2077ce490c6SJim Ingham { 2087ce490c6SJim Ingham size_t bytes_to_skip = 0; 2097ce490c6SJim Ingham lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); 2107ce490c6SJim Ingham Address func_start_address; 2117ce490c6SJim Ingham 2127ce490c6SJim Ingham SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol); 2137ce490c6SJim Ingham 2147ce490c6SJim Ingham if (sc.function) 2157ce490c6SJim Ingham { 2167ce490c6SJim Ingham func_start_address = sc.function->GetAddressRange().GetBaseAddress(); 217d9e416c0SGreg Clayton if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get())) 2187ce490c6SJim Ingham bytes_to_skip = sc.function->GetPrologueByteSize(); 2197ce490c6SJim Ingham } 2207ce490c6SJim Ingham else if (sc.symbol) 2217ce490c6SJim Ingham { 222e7612134SGreg Clayton func_start_address = sc.symbol->GetAddress(); 223d9e416c0SGreg Clayton if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get())) 2247ce490c6SJim Ingham bytes_to_skip = sc.symbol->GetPrologueByteSize(); 2257ce490c6SJim Ingham } 2267ce490c6SJim Ingham 2277ce490c6SJim Ingham if (bytes_to_skip != 0) 2287ce490c6SJim Ingham { 2297ce490c6SJim Ingham func_start_address.Slide (bytes_to_skip); 23020ad3c40SCaroline Tice log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); 2317ce490c6SJim Ingham if (log) 2327ce490c6SJim Ingham log->Printf ("Pushing past prologue "); 2337ce490c6SJim Ingham 2344d56e9c1SJim Ingham m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true); 2357ce490c6SJim Ingham } 2367ce490c6SJim Ingham } 2377ce490c6SJim Ingham } 238f02a2e96SJim Ingham } 2397ce490c6SJim Ingham 2404d56e9c1SJim Ingham if (!m_sub_plan_sp) 24130fdc8d8SChris Lattner { 24230fdc8d8SChris Lattner m_no_more_plans = true; 24330fdc8d8SChris Lattner SetPlanComplete(); 24430fdc8d8SChris Lattner return true; 24530fdc8d8SChris Lattner } 24630fdc8d8SChris Lattner else 24730fdc8d8SChris Lattner { 24830fdc8d8SChris Lattner m_no_more_plans = false; 24930fdc8d8SChris Lattner return false; 25030fdc8d8SChris Lattner } 25130fdc8d8SChris Lattner } 25230fdc8d8SChris Lattner 25330fdc8d8SChris Lattner void 25430fdc8d8SChris Lattner ThreadPlanStepInRange::SetFlagsToDefault () 25530fdc8d8SChris Lattner { 25630fdc8d8SChris Lattner GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values); 25730fdc8d8SChris Lattner } 25830fdc8d8SChris Lattner 25930fdc8d8SChris Lattner void 260a56c8006SJim Ingham ThreadPlanStepInRange::SetAvoidRegexp(const char *name) 261a56c8006SJim Ingham { 262a56c8006SJim Ingham if (m_avoid_regexp_ap.get() == NULL) 263a56c8006SJim Ingham m_avoid_regexp_ap.reset (new RegularExpression(name)); 264a56c8006SJim Ingham 265a56c8006SJim Ingham m_avoid_regexp_ap->Compile (name); 266a56c8006SJim Ingham } 267a56c8006SJim Ingham 268a56c8006SJim Ingham void 26930fdc8d8SChris Lattner ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value) 27030fdc8d8SChris Lattner { 27130fdc8d8SChris Lattner // TODO: Should we test this for sanity? 27230fdc8d8SChris Lattner ThreadPlanStepInRange::s_default_flag_values = new_value; 27330fdc8d8SChris Lattner } 27430fdc8d8SChris Lattner 275a56c8006SJim Ingham bool 276a56c8006SJim Ingham ThreadPlanStepInRange::FrameMatchesAvoidRegexp () 277a56c8006SJim Ingham { 278b57e4a1bSJason Molenda StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get(); 279a56c8006SJim Ingham 28067cc0636SGreg Clayton const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get(); 281ee8aea10SJim Ingham if (avoid_regexp_to_use == NULL) 282ee8aea10SJim Ingham avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp(); 283ee8aea10SJim Ingham 284ee8aea10SJim Ingham if (avoid_regexp_to_use != NULL) 285a56c8006SJim Ingham { 2864592cbc4SGreg Clayton SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol); 287a56c8006SJim Ingham if (sc.symbol != NULL) 288a56c8006SJim Ingham { 2894592cbc4SGreg Clayton const char *frame_function_name = sc.GetFunctionName().GetCString(); 2904592cbc4SGreg Clayton if (frame_function_name) 2913101ba33SJim Ingham { 292cf2667c4SJim Ingham size_t num_matches = 0; 2935160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 2943101ba33SJim Ingham if (log) 295cf2667c4SJim Ingham num_matches = 1; 296bc43cab5SGreg Clayton 297bc43cab5SGreg Clayton RegularExpression::Match regex_match(num_matches); 298bc43cab5SGreg Clayton 299bc43cab5SGreg Clayton bool return_value = avoid_regexp_to_use->Execute(frame_function_name, ®ex_match); 300cf2667c4SJim Ingham if (return_value) 301cf2667c4SJim Ingham { 302cf2667c4SJim Ingham if (log) 303cf2667c4SJim Ingham { 304cf2667c4SJim Ingham std::string match; 305bc43cab5SGreg Clayton regex_match.GetMatchAtIndex(frame_function_name,0, match); 306cf2667c4SJim Ingham log->Printf ("Stepping out of function \"%s\" because it matches the avoid regexp \"%s\" - match substring: \"%s\".", 3073101ba33SJim Ingham frame_function_name, 308cf2667c4SJim Ingham avoid_regexp_to_use->GetText(), 309cf2667c4SJim Ingham match.c_str()); 310cf2667c4SJim Ingham } 3113101ba33SJim Ingham 3123101ba33SJim Ingham } 3133101ba33SJim Ingham return return_value; 3143101ba33SJim Ingham } 315a56c8006SJim Ingham } 316a56c8006SJim Ingham } 317a56c8006SJim Ingham return false; 318a56c8006SJim Ingham } 319a56c8006SJim Ingham 3204d56e9c1SJim Ingham ThreadPlanSP 32130fdc8d8SChris Lattner ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton) 32230fdc8d8SChris Lattner { 323a56c8006SJim Ingham bool should_step_out = false; 324b57e4a1bSJason Molenda StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 3255160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 32630fdc8d8SChris Lattner 32773b472d4SGreg Clayton if (flags.Test(eAvoidNoDebug)) 328a56c8006SJim Ingham { 32930fdc8d8SChris Lattner if (!frame->HasDebugInformation()) 330af0f1759SJim Ingham { 331af0f1759SJim Ingham if (log) 332af0f1759SJim Ingham log->Printf ("Stepping out of frame with no debug info"); 333af0f1759SJim Ingham 334a56c8006SJim Ingham should_step_out = true; 335a56c8006SJim Ingham } 336af0f1759SJim Ingham } 337a56c8006SJim Ingham 338a56c8006SJim Ingham if (current_plan->GetKind() == eKindStepInRange) 339a56c8006SJim Ingham { 340a56c8006SJim Ingham ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); 341c627682eSJim Ingham if (step_in_range_plan->m_step_into_target) 342c627682eSJim Ingham { 343c627682eSJim Ingham SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol); 344c627682eSJim Ingham if (sc.symbol != NULL) 345c627682eSJim Ingham { 346c627682eSJim Ingham // First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare. 347c627682eSJim Ingham if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) 348c627682eSJim Ingham { 349c627682eSJim Ingham should_step_out = false; 350c627682eSJim Ingham } 351c627682eSJim Ingham else 352c627682eSJim Ingham { 353c627682eSJim Ingham const char *target_name = step_in_range_plan->m_step_into_target.AsCString(); 354c627682eSJim Ingham const char *function_name = sc.GetFunctionName().AsCString(); 355c627682eSJim Ingham 356c627682eSJim Ingham if (function_name == NULL) 357c627682eSJim Ingham should_step_out = true; 358c627682eSJim Ingham else if (strstr (function_name, target_name) == NULL) 359c627682eSJim Ingham should_step_out = true; 360c627682eSJim Ingham } 3613101ba33SJim Ingham if (log && should_step_out) 3623101ba33SJim Ingham log->Printf("Stepping out of frame %s which did not match step into target %s.", 3633101ba33SJim Ingham sc.GetFunctionName().AsCString(), 3643101ba33SJim Ingham step_in_range_plan->m_step_into_target.AsCString()); 365c627682eSJim Ingham } 366c627682eSJim Ingham } 367c627682eSJim Ingham 368c627682eSJim Ingham if (!should_step_out) 369c627682eSJim Ingham { 370c627682eSJim Ingham ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); 3713101ba33SJim Ingham // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidRegexp. 372a56c8006SJim Ingham should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp (); 373a56c8006SJim Ingham } 374a56c8006SJim Ingham } 375a56c8006SJim Ingham 376c627682eSJim Ingham 377a56c8006SJim Ingham if (should_step_out) 37830fdc8d8SChris Lattner { 37930fdc8d8SChris Lattner // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions. 3804a58e968SJim Ingham // We really should have all plans take the tri-state for "stop others" so we can do the right 3814a58e968SJim Ingham // thing. For now let's be safe and always run others when we are likely to run arbitrary code. 3824a58e968SJim Ingham const bool stop_others = false; 383481cef25SGreg Clayton return current_plan->GetThread().QueueThreadPlanForStepOut (false, 384481cef25SGreg Clayton NULL, 385481cef25SGreg Clayton true, 3864a58e968SJim Ingham stop_others, 387481cef25SGreg Clayton eVoteNo, 388481cef25SGreg Clayton eVoteNoOpinion, 389481cef25SGreg Clayton 0); // Frame index 39030fdc8d8SChris Lattner } 39130fdc8d8SChris Lattner 3924d56e9c1SJim Ingham return ThreadPlanSP(); 39330fdc8d8SChris Lattner } 394fbbfe6ecSJim Ingham 395fbbfe6ecSJim Ingham bool 396221d51cfSJim Ingham ThreadPlanStepInRange::DoPlanExplainsStop (Event *event_ptr) 397fbbfe6ecSJim Ingham { 398fbbfe6ecSJim Ingham // We always explain a stop. Either we've just done a single step, in which 399fbbfe6ecSJim Ingham // case we'll do our ordinary processing, or we stopped for some 400fbbfe6ecSJim Ingham // reason that isn't handled by our sub-plans, in which case we want to just stop right 401fbbfe6ecSJim Ingham // away. 402c627682eSJim Ingham // In general, we don't want to mark the plan as complete for unexplained stops. 403c627682eSJim Ingham // For instance, if you step in to some code with no debug info, so you step out 404c627682eSJim Ingham // and in the course of that hit a breakpoint, then you want to stop & show the user 405c627682eSJim Ingham // the breakpoint, but not unship the step in plan, since you still may want to complete that 406c627682eSJim Ingham // plan when you continue. This is particularly true when doing "step in to target function." 407c627682eSJim Ingham // stepping. 408fbbfe6ecSJim Ingham // 409fbbfe6ecSJim Ingham // The only variation is that if we are doing "step by running to next branch" in which case 410fbbfe6ecSJim Ingham // if we hit our branch breakpoint we don't set the plan to complete. 411fbbfe6ecSJim Ingham 412221d51cfSJim Ingham bool return_value; 413f02a2e96SJim Ingham 414221d51cfSJim Ingham if (m_virtual_step) 415221d51cfSJim Ingham { 416221d51cfSJim Ingham return_value = true; 417221d51cfSJim Ingham } 418221d51cfSJim Ingham else 419221d51cfSJim Ingham { 42060c4118cSJim Ingham StopInfoSP stop_info_sp = GetPrivateStopInfo (); 421fbbfe6ecSJim Ingham if (stop_info_sp) 422fbbfe6ecSJim Ingham { 423fbbfe6ecSJim Ingham StopReason reason = stop_info_sp->GetStopReason(); 424fbbfe6ecSJim Ingham 425fbbfe6ecSJim Ingham switch (reason) 426fbbfe6ecSJim Ingham { 427fbbfe6ecSJim Ingham case eStopReasonBreakpoint: 428fbbfe6ecSJim Ingham if (NextRangeBreakpointExplainsStop(stop_info_sp)) 429221d51cfSJim Ingham { 430221d51cfSJim Ingham return_value = true; 431221d51cfSJim Ingham break; 432221d51cfSJim Ingham } 433fbbfe6ecSJim Ingham case eStopReasonWatchpoint: 434fbbfe6ecSJim Ingham case eStopReasonSignal: 435fbbfe6ecSJim Ingham case eStopReasonException: 43690ba8115SGreg Clayton case eStopReasonExec: 437f85defaeSAndrew Kaylor case eStopReasonThreadExiting: 438513c6bb8SJim Ingham { 4395160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 440fbbfe6ecSJim Ingham if (log) 441fbbfe6ecSJim Ingham log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); 442513c6bb8SJim Ingham } 443221d51cfSJim Ingham return_value = false; 444fbbfe6ecSJim Ingham break; 445fbbfe6ecSJim Ingham default: 446221d51cfSJim Ingham return_value = true; 447fbbfe6ecSJim Ingham break; 448fbbfe6ecSJim Ingham } 449fbbfe6ecSJim Ingham } 450221d51cfSJim Ingham else 451221d51cfSJim Ingham return_value = true; 452221d51cfSJim Ingham } 453221d51cfSJim Ingham 454221d51cfSJim Ingham return return_value; 455fbbfe6ecSJim Ingham } 456513c6bb8SJim Ingham 457513c6bb8SJim Ingham bool 458221d51cfSJim Ingham ThreadPlanStepInRange::DoWillResume (lldb::StateType resume_state, bool current_plan) 459513c6bb8SJim Ingham { 460513c6bb8SJim Ingham if (resume_state == eStateStepping && current_plan) 461513c6bb8SJim Ingham { 462513c6bb8SJim Ingham // See if we are about to step over a virtual inlined call. 463513c6bb8SJim Ingham bool step_without_resume = m_thread.DecrementCurrentInlinedDepth(); 464513c6bb8SJim Ingham if (step_without_resume) 465513c6bb8SJim Ingham { 4665160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 467513c6bb8SJim Ingham if (log) 468221d51cfSJim Ingham log->Printf ("ThreadPlanStepInRange::DoWillResume: returning false, inline_depth: %d", 469513c6bb8SJim Ingham m_thread.GetCurrentInlinedDepth()); 470513c6bb8SJim Ingham SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread)); 471f02a2e96SJim Ingham 472f02a2e96SJim Ingham // FIXME: Maybe it would be better to create a InlineStep stop reason, but then 473f02a2e96SJim Ingham // the whole rest of the world would have to handle that stop reason. 474f02a2e96SJim Ingham m_virtual_step = true; 475513c6bb8SJim Ingham } 476513c6bb8SJim Ingham return !step_without_resume; 477513c6bb8SJim Ingham } 478221d51cfSJim Ingham return true; 479513c6bb8SJim Ingham } 480246cb611SDaniel Malea 481246cb611SDaniel Malea bool 482246cb611SDaniel Malea ThreadPlanStepInRange::IsVirtualStep() 483246cb611SDaniel Malea { 484246cb611SDaniel Malea return m_virtual_step; 485246cb611SDaniel Malea } 486