diff options
Diffstat (limited to 'source/Target/ThreadPlanStepOverRange.cpp')
-rw-r--r-- | source/Target/ThreadPlanStepOverRange.cpp | 723 |
1 files changed, 362 insertions, 361 deletions
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp index 95dc2205bbf6..48c7ff8be454 100644 --- a/source/Target/ThreadPlanStepOverRange.cpp +++ b/source/Target/ThreadPlanStepOverRange.cpp @@ -31,404 +31,405 @@ using namespace lldb; uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0; //---------------------------------------------------------------------- -// ThreadPlanStepOverRange: Step through a stack range, either stepping over or into +// ThreadPlanStepOverRange: Step through a stack range, either stepping over or +// into // based on the value of \a type. //---------------------------------------------------------------------- -ThreadPlanStepOverRange::ThreadPlanStepOverRange -( - Thread &thread, - const AddressRange &range, - const SymbolContext &addr_context, - lldb::RunMode stop_others, - LazyBool step_out_avoids_code_without_debug_info -) : - ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others), - ThreadPlanShouldStopHere (this), - m_first_resume(true) -{ - SetFlagsToDefault(); - SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); +ThreadPlanStepOverRange::ThreadPlanStepOverRange( + Thread &thread, const AddressRange &range, + const SymbolContext &addr_context, lldb::RunMode stop_others, + LazyBool step_out_avoids_code_without_debug_info) + : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange, + "Step range stepping over", thread, range, + addr_context, stop_others), + ThreadPlanShouldStopHere(this), m_first_resume(true) { + SetFlagsToDefault(); + SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); } ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default; -void -ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - { - s->Printf("step over"); - return; - } - s->Printf ("Stepping over"); - bool printed_line_info = false; - if (m_addr_context.line_entry.IsValid()) - { - s->Printf (" line "); - m_addr_context.line_entry.DumpStopContext (s, false); - printed_line_info = true; - } +void ThreadPlanStepOverRange::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) { + s->Printf("step over"); + return; + } + s->Printf("Stepping over"); + bool printed_line_info = false; + if (m_addr_context.line_entry.IsValid()) { + s->Printf(" line "); + m_addr_context.line_entry.DumpStopContext(s, false); + printed_line_info = true; + } - if (!printed_line_info || level == eDescriptionLevelVerbose) - { - s->Printf (" using ranges: "); - DumpRanges(s); - } + if (!printed_line_info || level == eDescriptionLevelVerbose) { + s->Printf(" using ranges: "); + DumpRanges(s); + } - s->PutChar('.'); + s->PutChar('.'); } -void -ThreadPlanStepOverRange::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info) -{ - bool avoid_nodebug = true; - switch (step_out_avoids_code_without_debug_info) - { - case eLazyBoolYes: - avoid_nodebug = true; - break; - case eLazyBoolNo: - avoid_nodebug = false; - break; - case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); - break; - } - if (avoid_nodebug) - GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); - else - GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); - // Step Over plans should always avoid no-debug on step in. Seems like you shouldn't - // have to say this, but a tail call looks more like a step in that a step out, so - // we want to catch this case. - GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug); +void ThreadPlanStepOverRange::SetupAvoidNoDebug( + LazyBool step_out_avoids_code_without_debug_info) { + bool avoid_nodebug = true; + switch (step_out_avoids_code_without_debug_info) { + case eLazyBoolYes: + avoid_nodebug = true; + break; + case eLazyBoolNo: + avoid_nodebug = false; + break; + case eLazyBoolCalculate: + avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + break; + } + if (avoid_nodebug) + GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); + else + GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); + // Step Over plans should always avoid no-debug on step in. Seems like you + // shouldn't + // have to say this, but a tail call looks more like a step in that a step + // out, so + // we want to catch this case. + GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); } -bool -ThreadPlanStepOverRange::IsEquivalentContext(const SymbolContext &context) -{ - // Match as much as is specified in the m_addr_context: - // This is a fairly loose sanity check. Note, sometimes the target doesn't get filled - // in so I left out the target check. And sometimes the module comes in as the .o file from the - // inlined range, so I left that out too... - if (m_addr_context.comp_unit) - { - if (m_addr_context.comp_unit == context.comp_unit) - { - if (m_addr_context.function && m_addr_context.function == context.function) - { - if (m_addr_context.block && m_addr_context.block == context.block) - return true; - } - } - } - else if (m_addr_context.symbol && m_addr_context.symbol == context.symbol) - { +bool ThreadPlanStepOverRange::IsEquivalentContext( + const SymbolContext &context) { + // Match as much as is specified in the m_addr_context: + // This is a fairly loose sanity check. Note, sometimes the target doesn't + // get filled + // in so I left out the target check. And sometimes the module comes in as + // the .o file from the + // inlined range, so I left that out too... + if (m_addr_context.comp_unit) { + if (m_addr_context.comp_unit != context.comp_unit) + return false; + if (m_addr_context.function) { + if (m_addr_context.function != context.function) + return false; + // It is okay to return to a different block of a straight function, we + // only have to + // be more careful if returning from one inlined block to another. + if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr && + context.block->GetInlinedFunctionInfo() == nullptr) return true; + return m_addr_context.block == context.block; } - return false; + } + // Fall back to symbol if we have no decision from comp_unit/function/block. + if (m_addr_context.symbol && m_addr_context.symbol == context.symbol) { + return true; + } + return false; } -bool -ThreadPlanStepOverRange::ShouldStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - if (log) - { - StreamString s; - s.Address (m_thread.GetRegisterContext()->GetPC(), - m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); - log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData()); +bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if (log) { + StreamString s; + s.Address( + m_thread.GetRegisterContext()->GetPC(), + m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); + log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData()); + } + + // If we're out of the range but in the same frame or in our caller's frame + // then we should stop. + // When stepping out we only stop others if we are forcing running one thread. + bool stop_others = (m_stop_others == lldb::eOnlyThisThread); + ThreadPlanSP new_plan_sp; + FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + + if (frame_order == eFrameCompareOlder) { + // If we're in an older frame then we should stop. + // + // A caveat to this is if we think the frame is older but we're actually in + // a trampoline. + // I'm going to make the assumption that you wouldn't RETURN to a + // trampoline. So if we are + // in a trampoline we think the frame is older because the trampoline + // confused the backtracer. + // As below, we step through first, and then try to figure out how to get + // back out again. + + new_plan_sp = + m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, stop_others); + + if (new_plan_sp && log) + log->Printf( + "Thought I stepped out, but in fact arrived at a trampoline."); + } else if (frame_order == eFrameCompareYounger) { + // Make sure we really are in a new frame. Do that by unwinding and seeing + // if the + // start function really is our start function... + for (uint32_t i = 1;; ++i) { + StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i); + if (!older_frame_sp) { + // We can't unwind the next frame we should just get out of here & + // stop... + break; + } + + const SymbolContext &older_context = + older_frame_sp->GetSymbolContext(eSymbolContextEverything); + if (IsEquivalentContext(older_context)) { + new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, + true); + break; + } else { + new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others); + // If we found a way through, then we should stop recursing. + if (new_plan_sp) + break; + } } - - // If we're out of the range but in the same frame or in our caller's frame - // then we should stop. - // When stepping out we only stop others if we are forcing running one thread. - bool stop_others = (m_stop_others == lldb::eOnlyThisThread); - ThreadPlanSP new_plan_sp; - FrameComparison frame_order = CompareCurrentFrameToStartFrame(); - - if (frame_order == eFrameCompareOlder) - { - // If we're in an older frame then we should stop. - // - // A caveat to this is if we think the frame is older but we're actually in a trampoline. - // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are - // in a trampoline we think the frame is older because the trampoline confused the backtracer. - // As below, we step through first, and then try to figure out how to get back out again. - - new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - - if (new_plan_sp && log) - log->Printf("Thought I stepped out, but in fact arrived at a trampoline."); + } else { + // If we're still in the range, keep going. + if (InRange()) { + SetNextBranchBreakpoint(); + return false; } - else if (frame_order == eFrameCompareYounger) - { - // Make sure we really are in a new frame. Do that by unwinding and seeing if the - // start function really is our start function... - for(uint32_t i = 1;; ++i) - { - StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i); - if (!older_frame_sp) { - // We can't unwind the next frame we should just get out of here & stop... - break; - } - const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything); - if (IsEquivalentContext(older_context)) - { - new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(false, - nullptr, - true, - stop_others, - eVoteNo, - eVoteNoOpinion, - 0, - true); - break; - } - else - { - new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - // If we found a way through, then we should stop recursing. - if (new_plan_sp) - break; - } - } - } - else - { - // If we're still in the range, keep going. - if (InRange()) - { - SetNextBranchBreakpoint(); - return false; - } + if (!InSymbol()) { + // This one is a little tricky. Sometimes we may be in a stub or + // something similar, + // in which case we need to get out of there. But if we are in a stub + // then it's + // likely going to be hard to get out from here. It is probably easiest + // to step into the + // stub, and then it will be straight-forward to step out. + new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others); + } else { + // The current clang (at least through 424) doesn't always get the address + // range for the + // DW_TAG_inlined_subroutines right, so that when you leave the inlined + // range the line table says + // you are still in the source file of the inlining function. This is + // bad, because now you are missing + // the stack frame for the function containing the inlining, and if you + // sensibly do "finish" to get + // out of this function you will instead exit the containing function. + // To work around this, we check whether we are still in the source file + // we started in, and if not assume + // it is an error, and push a plan to get us out of this line and back to + // the containing file. - if (!InSymbol()) - { - // This one is a little tricky. Sometimes we may be in a stub or something similar, - // in which case we need to get out of there. But if we are in a stub then it's - // likely going to be hard to get out from here. It is probably easiest to step into the - // stub, and then it will be straight-forward to step out. - new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - } - else - { - // The current clang (at least through 424) doesn't always get the address range for the - // DW_TAG_inlined_subroutines right, so that when you leave the inlined range the line table says - // you are still in the source file of the inlining function. This is bad, because now you are missing - // the stack frame for the function containing the inlining, and if you sensibly do "finish" to get - // out of this function you will instead exit the containing function. - // To work around this, we check whether we are still in the source file we started in, and if not assume - // it is an error, and push a plan to get us out of this line and back to the containing file. - - if (m_addr_context.line_entry.IsValid()) - { - SymbolContext sc; - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); - sc = frame_sp->GetSymbolContext (eSymbolContextEverything); - if (sc.line_entry.IsValid()) - { - if (sc.line_entry.original_file != m_addr_context.line_entry.original_file - && sc.comp_unit == m_addr_context.comp_unit - && sc.function == m_addr_context.function) - { - // Okay, find the next occurrence of this file in the line table: - LineTable *line_table = m_addr_context.comp_unit->GetLineTable(); - if (line_table) - { - Address cur_address = frame_sp->GetFrameCodeAddress(); - uint32_t entry_idx; - LineEntry line_entry; - if (line_table->FindLineEntryByAddress (cur_address, line_entry, &entry_idx)) - { - LineEntry next_line_entry; - bool step_past_remaining_inline = false; - if (entry_idx > 0) - { - // We require the previous line entry and the current line entry come - // from the same file. - // The other requirement is that the previous line table entry be part of an - // inlined block, we don't want to step past cases where people have inlined - // some code fragment by using #include <source-fragment.c> directly. - LineEntry prev_line_entry; - if (line_table->GetLineEntryAtIndex(entry_idx - 1, prev_line_entry) - && prev_line_entry.original_file == line_entry.original_file) - { - SymbolContext prev_sc; - Address prev_address = prev_line_entry.range.GetBaseAddress(); - prev_address.CalculateSymbolContext(&prev_sc); - if (prev_sc.block) - { - Block *inlined_block = prev_sc.block->GetContainingInlinedBlock(); - if (inlined_block) - { - AddressRange inline_range; - inlined_block->GetRangeContainingAddress(prev_address, inline_range); - if (!inline_range.ContainsFileAddress(cur_address)) - { - - step_past_remaining_inline = true; - } - } - } - } - } - - if (step_past_remaining_inline) - { - uint32_t look_ahead_step = 1; - while (line_table->GetLineEntryAtIndex(entry_idx + look_ahead_step, next_line_entry)) - { - // Make sure we haven't wandered out of the function we started from... - Address next_line_address = next_line_entry.range.GetBaseAddress(); - Function *next_line_function = next_line_address.CalculateSymbolContextFunction(); - if (next_line_function != m_addr_context.function) - break; - - if (next_line_entry.original_file == m_addr_context.line_entry.original_file) - { - const bool abort_other_plans = false; - const RunMode stop_other_threads = RunMode::eAllThreads; - lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); - AddressRange step_range(cur_pc, next_line_address.GetLoadAddress(&GetTarget()) - cur_pc); - - new_plan_sp = m_thread.QueueThreadPlanForStepOverRange (abort_other_plans, - step_range, - sc, - stop_other_threads); - break; - } - look_ahead_step++; - } - } - } + if (m_addr_context.line_entry.IsValid()) { + SymbolContext sc; + StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + sc = frame_sp->GetSymbolContext(eSymbolContextEverything); + if (sc.line_entry.IsValid()) { + if (sc.line_entry.original_file != + m_addr_context.line_entry.original_file && + sc.comp_unit == m_addr_context.comp_unit && + sc.function == m_addr_context.function) { + // Okay, find the next occurrence of this file in the line table: + LineTable *line_table = m_addr_context.comp_unit->GetLineTable(); + if (line_table) { + Address cur_address = frame_sp->GetFrameCodeAddress(); + uint32_t entry_idx; + LineEntry line_entry; + if (line_table->FindLineEntryByAddress(cur_address, line_entry, + &entry_idx)) { + LineEntry next_line_entry; + bool step_past_remaining_inline = false; + if (entry_idx > 0) { + // We require the previous line entry and the current line + // entry come + // from the same file. + // The other requirement is that the previous line table entry + // be part of an + // inlined block, we don't want to step past cases where + // people have inlined + // some code fragment by using #include <source-fragment.c> + // directly. + LineEntry prev_line_entry; + if (line_table->GetLineEntryAtIndex(entry_idx - 1, + prev_line_entry) && + prev_line_entry.original_file == + line_entry.original_file) { + SymbolContext prev_sc; + Address prev_address = + prev_line_entry.range.GetBaseAddress(); + prev_address.CalculateSymbolContext(&prev_sc); + if (prev_sc.block) { + Block *inlined_block = + prev_sc.block->GetContainingInlinedBlock(); + if (inlined_block) { + AddressRange inline_range; + inlined_block->GetRangeContainingAddress(prev_address, + inline_range); + if (!inline_range.ContainsFileAddress(cur_address)) { + + step_past_remaining_inline = true; } + } } + } } + + if (step_past_remaining_inline) { + uint32_t look_ahead_step = 1; + while (line_table->GetLineEntryAtIndex( + entry_idx + look_ahead_step, next_line_entry)) { + // Make sure we haven't wandered out of the function we + // started from... + Address next_line_address = + next_line_entry.range.GetBaseAddress(); + Function *next_line_function = + next_line_address.CalculateSymbolContextFunction(); + if (next_line_function != m_addr_context.function) + break; + + if (next_line_entry.original_file == + m_addr_context.line_entry.original_file) { + const bool abort_other_plans = false; + const RunMode stop_other_threads = RunMode::eAllThreads; + lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0) + ->GetRegisterContext() + ->GetPC(); + AddressRange step_range( + cur_pc, + next_line_address.GetLoadAddress(&GetTarget()) - + cur_pc); + + new_plan_sp = m_thread.QueueThreadPlanForStepOverRange( + abort_other_plans, step_range, sc, + stop_other_threads); + break; + } + look_ahead_step++; + } + } + } } + } } + } } + } - // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it: - ClearNextBranchBreakpoint(); - - - // If we haven't figured out something to do yet, then ask the ShouldStopHere callback: - if (!new_plan_sp) - { - new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order); - } + // If we get to this point, we're not going to use a previously set "next + // branch" breakpoint, so delete it: + ClearNextBranchBreakpoint(); - if (!new_plan_sp) - m_no_more_plans = true; - else - { - // Any new plan will be an implementation plan, so mark it private: - new_plan_sp->SetPrivate(true); - m_no_more_plans = false; - } + // If we haven't figured out something to do yet, then ask the ShouldStopHere + // callback: + if (!new_plan_sp) { + new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); + } - if (!new_plan_sp) - { - // For efficiencies sake, we know we're done here so we don't have to do this - // calculation again in MischiefManaged. - SetPlanComplete(); - return true; - } - else - return false; + if (!new_plan_sp) + m_no_more_plans = true; + else { + // Any new plan will be an implementation plan, so mark it private: + new_plan_sp->SetPrivate(true); + m_no_more_plans = false; + } + + if (!new_plan_sp) { + // For efficiencies sake, we know we're done here so we don't have to do + // this + // calculation again in MischiefManaged. + SetPlanComplete(); + return true; + } else + return false; } -bool -ThreadPlanStepOverRange::DoPlanExplainsStop (Event *event_ptr) -{ - // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan above us) - // handle the stop. That way the user can see the stop, step around, and then when they - // are done, continue and have their step complete. The exception is if we've hit our - // "run to next branch" breakpoint. - // Note, unlike the step in range plan, we don't mark ourselves complete if we hit an - // unexplained breakpoint/crash. - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - bool return_value; - - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason(); - - if (reason == eStopReasonTrace) - { - return_value = true; - } - else if (reason == eStopReasonBreakpoint) - { - return_value = NextRangeBreakpointExplainsStop(stop_info_sp); - } - else - { - if (log) - log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); - return_value = false; - } +bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) { + // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan + // above us) + // handle the stop. That way the user can see the stop, step around, and then + // when they + // are done, continue and have their step complete. The exception is if we've + // hit our + // "run to next branch" breakpoint. + // Note, unlike the step in range plan, we don't mark ourselves complete if we + // hit an + // unexplained breakpoint/crash. + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + bool return_value; + + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + + if (reason == eStopReasonTrace) { + return_value = true; + } else if (reason == eStopReasonBreakpoint) { + return_value = NextRangeBreakpointExplainsStop(stop_info_sp); + } else { + if (log) + log->PutCString("ThreadPlanStepInRange got asked if it explains the " + "stop for some reason other than step."); + return_value = false; } - else - return_value = true; + } else + return_value = true; - return return_value; + return return_value; } -bool -ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool current_plan) -{ - if (resume_state != eStateSuspended && m_first_resume) - { - m_first_resume = false; - if (resume_state == eStateStepping && current_plan) - { - // See if we are about to step over an inlined call in the middle of the inlined stack, if so figure - // out its extents and reset our range to step over that. - bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth(); - if (in_inlined_stack) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("ThreadPlanStepInRange::DoWillResume: adjusting range to the frame at inlined depth %d.", - m_thread.GetCurrentInlinedDepth()); - StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0); - if (stack_sp) - { - Block *frame_block = stack_sp->GetFrameBlock(); - lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); - AddressRange my_range; - if (frame_block->GetRangeContainingLoadAddress(curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) - { - m_address_ranges.clear(); - m_address_ranges.push_back(my_range); - if (log) - { - StreamString s; - const InlineFunctionInfo *inline_info = frame_block->GetInlinedFunctionInfo(); - const char *name; - if (inline_info) - name = inline_info->GetName(frame_block->CalculateSymbolContextFunction()->GetLanguage()).AsCString(); - else - name = "<unknown-notinlined>"; - - s.Printf ("Stepping over inlined function \"%s\" in inlined stack: ", name); - DumpRanges(&s); - log->PutCString(s.GetData()); - } - } - - } +bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state, + bool current_plan) { + if (resume_state != eStateSuspended && m_first_resume) { + m_first_resume = false; + if (resume_state == eStateStepping && current_plan) { + // See if we are about to step over an inlined call in the middle of the + // inlined stack, if so figure + // out its extents and reset our range to step over that. + bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth(); + if (in_inlined_stack) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("ThreadPlanStepInRange::DoWillResume: adjusting range to " + "the frame at inlined depth %d.", + m_thread.GetCurrentInlinedDepth()); + StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0); + if (stack_sp) { + Block *frame_block = stack_sp->GetFrameBlock(); + lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); + AddressRange my_range; + if (frame_block->GetRangeContainingLoadAddress( + curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) { + m_address_ranges.clear(); + m_address_ranges.push_back(my_range); + if (log) { + StreamString s; + const InlineFunctionInfo *inline_info = + frame_block->GetInlinedFunctionInfo(); + const char *name; + if (inline_info) + name = + inline_info + ->GetName(frame_block->CalculateSymbolContextFunction() + ->GetLanguage()) + .AsCString(); + else + name = "<unknown-notinlined>"; + + s.Printf( + "Stepping over inlined function \"%s\" in inlined stack: ", + name); + DumpRanges(&s); + log->PutString(s.GetString()); } + } } + } } - - return true; + } + + return true; } |