15ffd83dbSDimitry Andric //===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOverRange.h"
100b57cec5SDimitry Andric #include "lldb/Symbol/Block.h"
110b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
120b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
130b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h"
140b57cec5SDimitry Andric #include "lldb/Target/Process.h"
150b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
160b57cec5SDimitry Andric #include "lldb/Target/Target.h"
170b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
180b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepOut.h"
190b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepThrough.h"
2081ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
210b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
220b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric using namespace lldb_private;
250b57cec5SDimitry Andric using namespace lldb;
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric // ThreadPlanStepOverRange: Step through a stack range, either stepping over or
300b57cec5SDimitry Andric // into based on the value of \a type.
310b57cec5SDimitry Andric
ThreadPlanStepOverRange(Thread & thread,const AddressRange & range,const SymbolContext & addr_context,lldb::RunMode stop_others,LazyBool step_out_avoids_code_without_debug_info)320b57cec5SDimitry Andric ThreadPlanStepOverRange::ThreadPlanStepOverRange(
330b57cec5SDimitry Andric Thread &thread, const AddressRange &range,
340b57cec5SDimitry Andric const SymbolContext &addr_context, lldb::RunMode stop_others,
350b57cec5SDimitry Andric LazyBool step_out_avoids_code_without_debug_info)
360b57cec5SDimitry Andric : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange,
370b57cec5SDimitry Andric "Step range stepping over", thread, range,
380b57cec5SDimitry Andric addr_context, stop_others),
390b57cec5SDimitry Andric ThreadPlanShouldStopHere(this), m_first_resume(true) {
400b57cec5SDimitry Andric SetFlagsToDefault();
410b57cec5SDimitry Andric SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric
440b57cec5SDimitry Andric ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default;
450b57cec5SDimitry Andric
GetDescription(Stream * s,lldb::DescriptionLevel level)460b57cec5SDimitry Andric void ThreadPlanStepOverRange::GetDescription(Stream *s,
470b57cec5SDimitry Andric lldb::DescriptionLevel level) {
480b57cec5SDimitry Andric auto PrintFailureIfAny = [&]() {
490b57cec5SDimitry Andric if (m_status.Success())
500b57cec5SDimitry Andric return;
510b57cec5SDimitry Andric s->Printf(" failed (%s)", m_status.AsCString());
520b57cec5SDimitry Andric };
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric if (level == lldb::eDescriptionLevelBrief) {
550b57cec5SDimitry Andric s->Printf("step over");
560b57cec5SDimitry Andric PrintFailureIfAny();
570b57cec5SDimitry Andric return;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric s->Printf("Stepping over");
610b57cec5SDimitry Andric bool printed_line_info = false;
620b57cec5SDimitry Andric if (m_addr_context.line_entry.IsValid()) {
630b57cec5SDimitry Andric s->Printf(" line ");
640b57cec5SDimitry Andric m_addr_context.line_entry.DumpStopContext(s, false);
650b57cec5SDimitry Andric printed_line_info = true;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric if (!printed_line_info || level == eDescriptionLevelVerbose) {
690b57cec5SDimitry Andric s->Printf(" using ranges: ");
700b57cec5SDimitry Andric DumpRanges(s);
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric PrintFailureIfAny();
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric s->PutChar('.');
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)780b57cec5SDimitry Andric void ThreadPlanStepOverRange::SetupAvoidNoDebug(
790b57cec5SDimitry Andric LazyBool step_out_avoids_code_without_debug_info) {
800b57cec5SDimitry Andric bool avoid_nodebug = true;
810b57cec5SDimitry Andric switch (step_out_avoids_code_without_debug_info) {
820b57cec5SDimitry Andric case eLazyBoolYes:
830b57cec5SDimitry Andric avoid_nodebug = true;
840b57cec5SDimitry Andric break;
850b57cec5SDimitry Andric case eLazyBoolNo:
860b57cec5SDimitry Andric avoid_nodebug = false;
870b57cec5SDimitry Andric break;
880b57cec5SDimitry Andric case eLazyBoolCalculate:
895ffd83dbSDimitry Andric avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug();
900b57cec5SDimitry Andric break;
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric if (avoid_nodebug)
930b57cec5SDimitry Andric GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
940b57cec5SDimitry Andric else
950b57cec5SDimitry Andric GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
960b57cec5SDimitry Andric // Step Over plans should always avoid no-debug on step in. Seems like you
970b57cec5SDimitry Andric // shouldn't have to say this, but a tail call looks more like a step in that
980b57cec5SDimitry Andric // a step out, so we want to catch this case.
990b57cec5SDimitry Andric GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric
IsEquivalentContext(const SymbolContext & context)1020b57cec5SDimitry Andric bool ThreadPlanStepOverRange::IsEquivalentContext(
1030b57cec5SDimitry Andric const SymbolContext &context) {
1040b57cec5SDimitry Andric // Match as much as is specified in the m_addr_context: This is a fairly
1050b57cec5SDimitry Andric // loose sanity check. Note, sometimes the target doesn't get filled in so I
1060b57cec5SDimitry Andric // left out the target check. And sometimes the module comes in as the .o
1070b57cec5SDimitry Andric // file from the inlined range, so I left that out too...
1080b57cec5SDimitry Andric if (m_addr_context.comp_unit) {
1090b57cec5SDimitry Andric if (m_addr_context.comp_unit != context.comp_unit)
1100b57cec5SDimitry Andric return false;
1110b57cec5SDimitry Andric if (m_addr_context.function) {
1120b57cec5SDimitry Andric if (m_addr_context.function != context.function)
1130b57cec5SDimitry Andric return false;
1140b57cec5SDimitry Andric // It is okay to return to a different block of a straight function, we
1150b57cec5SDimitry Andric // only have to be more careful if returning from one inlined block to
1160b57cec5SDimitry Andric // another.
1170b57cec5SDimitry Andric if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr &&
1180b57cec5SDimitry Andric context.block->GetInlinedFunctionInfo() == nullptr)
1190b57cec5SDimitry Andric return true;
1200b57cec5SDimitry Andric return m_addr_context.block == context.block;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric // Fall back to symbol if we have no decision from comp_unit/function/block.
1240b57cec5SDimitry Andric return m_addr_context.symbol && m_addr_context.symbol == context.symbol;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric
ShouldStop(Event * event_ptr)1270b57cec5SDimitry Andric bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) {
12881ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Step);
1295ffd83dbSDimitry Andric Thread &thread = GetThread();
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric if (log) {
1320b57cec5SDimitry Andric StreamString s;
1335ffd83dbSDimitry Andric DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(),
1345ffd83dbSDimitry Andric GetTarget().GetArchitecture().GetAddressByteSize());
1359dba64beSDimitry Andric LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData());
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric // If we're out of the range but in the same frame or in our caller's frame
1390b57cec5SDimitry Andric // then we should stop. When stepping out we only stop others if we are
1400b57cec5SDimitry Andric // forcing running one thread.
1410b57cec5SDimitry Andric bool stop_others = (m_stop_others == lldb::eOnlyThisThread);
1420b57cec5SDimitry Andric ThreadPlanSP new_plan_sp;
1430b57cec5SDimitry Andric FrameComparison frame_order = CompareCurrentFrameToStartFrame();
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric if (frame_order == eFrameCompareOlder) {
1460b57cec5SDimitry Andric // If we're in an older frame then we should stop.
1470b57cec5SDimitry Andric //
1480b57cec5SDimitry Andric // A caveat to this is if we think the frame is older but we're actually in
1490b57cec5SDimitry Andric // a trampoline.
1500b57cec5SDimitry Andric // I'm going to make the assumption that you wouldn't RETURN to a
1510b57cec5SDimitry Andric // trampoline. So if we are in a trampoline we think the frame is older
1520b57cec5SDimitry Andric // because the trampoline confused the backtracer. As below, we step
1530b57cec5SDimitry Andric // through first, and then try to figure out how to get back out again.
1540b57cec5SDimitry Andric
1555ffd83dbSDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
1560b57cec5SDimitry Andric stop_others, m_status);
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric if (new_plan_sp && log)
1599dba64beSDimitry Andric LLDB_LOGF(log,
1600b57cec5SDimitry Andric "Thought I stepped out, but in fact arrived at a trampoline.");
1610b57cec5SDimitry Andric } else if (frame_order == eFrameCompareYounger) {
1620b57cec5SDimitry Andric // Make sure we really are in a new frame. Do that by unwinding and seeing
1630b57cec5SDimitry Andric // if the start function really is our start function...
1640b57cec5SDimitry Andric for (uint32_t i = 1;; ++i) {
1655ffd83dbSDimitry Andric StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i);
1660b57cec5SDimitry Andric if (!older_frame_sp) {
1670b57cec5SDimitry Andric // We can't unwind the next frame we should just get out of here &
1680b57cec5SDimitry Andric // stop...
1690b57cec5SDimitry Andric break;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric const SymbolContext &older_context =
1730b57cec5SDimitry Andric older_frame_sp->GetSymbolContext(eSymbolContextEverything);
1740b57cec5SDimitry Andric if (IsEquivalentContext(older_context)) {
1755ffd83dbSDimitry Andric // If we have the next-branch-breakpoint in the range, we can just
1765ffd83dbSDimitry Andric // rely on that breakpoint to trigger once we return to the range.
1775ffd83dbSDimitry Andric if (m_next_branch_bp_sp)
1785ffd83dbSDimitry Andric return false;
1795ffd83dbSDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop(
1800b57cec5SDimitry Andric false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0,
1810b57cec5SDimitry Andric m_status, true);
1820b57cec5SDimitry Andric break;
1830b57cec5SDimitry Andric } else {
1845ffd83dbSDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(
1850b57cec5SDimitry Andric m_stack_id, false, stop_others, m_status);
1860b57cec5SDimitry Andric // If we found a way through, then we should stop recursing.
1870b57cec5SDimitry Andric if (new_plan_sp)
1880b57cec5SDimitry Andric break;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric } else {
1920b57cec5SDimitry Andric // If we're still in the range, keep going.
1930b57cec5SDimitry Andric if (InRange()) {
1940b57cec5SDimitry Andric SetNextBranchBreakpoint();
1950b57cec5SDimitry Andric return false;
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric if (!InSymbol()) {
1990b57cec5SDimitry Andric // This one is a little tricky. Sometimes we may be in a stub or
2000b57cec5SDimitry Andric // something similar, in which case we need to get out of there. But if
2010b57cec5SDimitry Andric // we are in a stub then it's likely going to be hard to get out from
2020b57cec5SDimitry Andric // here. It is probably easiest to step into the stub, and then it will
2030b57cec5SDimitry Andric // be straight-forward to step out.
2045ffd83dbSDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false,
2055ffd83dbSDimitry Andric stop_others, m_status);
2060b57cec5SDimitry Andric } else {
2070b57cec5SDimitry Andric // The current clang (at least through 424) doesn't always get the
2080b57cec5SDimitry Andric // address range for the DW_TAG_inlined_subroutines right, so that when
2090b57cec5SDimitry Andric // you leave the inlined range the line table says you are still in the
2100b57cec5SDimitry Andric // source file of the inlining function. This is bad, because now you
2110b57cec5SDimitry Andric // are missing the stack frame for the function containing the inlining,
2120b57cec5SDimitry Andric // and if you sensibly do "finish" to get out of this function you will
2130b57cec5SDimitry Andric // instead exit the containing function. To work around this, we check
2140b57cec5SDimitry Andric // whether we are still in the source file we started in, and if not
2150b57cec5SDimitry Andric // assume it is an error, and push a plan to get us out of this line and
2160b57cec5SDimitry Andric // back to the containing file.
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric if (m_addr_context.line_entry.IsValid()) {
2190b57cec5SDimitry Andric SymbolContext sc;
2205ffd83dbSDimitry Andric StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0);
2210b57cec5SDimitry Andric sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
2220b57cec5SDimitry Andric if (sc.line_entry.IsValid()) {
223*a58f00eaSDimitry Andric if (*sc.line_entry.original_file_sp !=
224*a58f00eaSDimitry Andric *m_addr_context.line_entry.original_file_sp &&
2250b57cec5SDimitry Andric sc.comp_unit == m_addr_context.comp_unit &&
2260b57cec5SDimitry Andric sc.function == m_addr_context.function) {
2270b57cec5SDimitry Andric // Okay, find the next occurrence of this file in the line table:
2280b57cec5SDimitry Andric LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
2290b57cec5SDimitry Andric if (line_table) {
2300b57cec5SDimitry Andric Address cur_address = frame_sp->GetFrameCodeAddress();
2310b57cec5SDimitry Andric uint32_t entry_idx;
2320b57cec5SDimitry Andric LineEntry line_entry;
2330b57cec5SDimitry Andric if (line_table->FindLineEntryByAddress(cur_address, line_entry,
2340b57cec5SDimitry Andric &entry_idx)) {
2350b57cec5SDimitry Andric LineEntry next_line_entry;
2360b57cec5SDimitry Andric bool step_past_remaining_inline = false;
2370b57cec5SDimitry Andric if (entry_idx > 0) {
2380b57cec5SDimitry Andric // We require the previous line entry and the current line
2390b57cec5SDimitry Andric // entry come from the same file. The other requirement is
2400b57cec5SDimitry Andric // that the previous line table entry be part of an inlined
2410b57cec5SDimitry Andric // block, we don't want to step past cases where people have
2420b57cec5SDimitry Andric // inlined some code fragment by using #include <source-
2430b57cec5SDimitry Andric // fragment.c> directly.
2440b57cec5SDimitry Andric LineEntry prev_line_entry;
2450b57cec5SDimitry Andric if (line_table->GetLineEntryAtIndex(entry_idx - 1,
2460b57cec5SDimitry Andric prev_line_entry) &&
247*a58f00eaSDimitry Andric *prev_line_entry.original_file_sp ==
248*a58f00eaSDimitry Andric *line_entry.original_file_sp) {
2490b57cec5SDimitry Andric SymbolContext prev_sc;
2500b57cec5SDimitry Andric Address prev_address =
2510b57cec5SDimitry Andric prev_line_entry.range.GetBaseAddress();
2520b57cec5SDimitry Andric prev_address.CalculateSymbolContext(&prev_sc);
2530b57cec5SDimitry Andric if (prev_sc.block) {
2540b57cec5SDimitry Andric Block *inlined_block =
2550b57cec5SDimitry Andric prev_sc.block->GetContainingInlinedBlock();
2560b57cec5SDimitry Andric if (inlined_block) {
2570b57cec5SDimitry Andric AddressRange inline_range;
2580b57cec5SDimitry Andric inlined_block->GetRangeContainingAddress(prev_address,
2590b57cec5SDimitry Andric inline_range);
2600b57cec5SDimitry Andric if (!inline_range.ContainsFileAddress(cur_address)) {
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric step_past_remaining_inline = true;
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric if (step_past_remaining_inline) {
2700b57cec5SDimitry Andric uint32_t look_ahead_step = 1;
2710b57cec5SDimitry Andric while (line_table->GetLineEntryAtIndex(
2720b57cec5SDimitry Andric entry_idx + look_ahead_step, next_line_entry)) {
2730b57cec5SDimitry Andric // Make sure we haven't wandered out of the function we
2740b57cec5SDimitry Andric // started from...
2750b57cec5SDimitry Andric Address next_line_address =
2760b57cec5SDimitry Andric next_line_entry.range.GetBaseAddress();
2770b57cec5SDimitry Andric Function *next_line_function =
2780b57cec5SDimitry Andric next_line_address.CalculateSymbolContextFunction();
2790b57cec5SDimitry Andric if (next_line_function != m_addr_context.function)
2800b57cec5SDimitry Andric break;
2810b57cec5SDimitry Andric
282*a58f00eaSDimitry Andric if (*next_line_entry.original_file_sp ==
283*a58f00eaSDimitry Andric *m_addr_context.line_entry.original_file_sp) {
2840b57cec5SDimitry Andric const bool abort_other_plans = false;
2850b57cec5SDimitry Andric const RunMode stop_other_threads = RunMode::eAllThreads;
2865ffd83dbSDimitry Andric lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0)
2870b57cec5SDimitry Andric ->GetRegisterContext()
2880b57cec5SDimitry Andric ->GetPC();
2890b57cec5SDimitry Andric AddressRange step_range(
2900b57cec5SDimitry Andric cur_pc,
2910b57cec5SDimitry Andric next_line_address.GetLoadAddress(&GetTarget()) -
2920b57cec5SDimitry Andric cur_pc);
2930b57cec5SDimitry Andric
2945ffd83dbSDimitry Andric new_plan_sp = thread.QueueThreadPlanForStepOverRange(
2950b57cec5SDimitry Andric abort_other_plans, step_range, sc, stop_other_threads,
2960b57cec5SDimitry Andric m_status);
2970b57cec5SDimitry Andric break;
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric look_ahead_step++;
3000b57cec5SDimitry Andric }
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric }
3080b57cec5SDimitry Andric }
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric // If we get to this point, we're not going to use a previously set "next
3110b57cec5SDimitry Andric // branch" breakpoint, so delete it:
3120b57cec5SDimitry Andric ClearNextBranchBreakpoint();
3130b57cec5SDimitry Andric
3140b57cec5SDimitry Andric // If we haven't figured out something to do yet, then ask the ShouldStopHere
3150b57cec5SDimitry Andric // callback:
3160b57cec5SDimitry Andric if (!new_plan_sp) {
3170b57cec5SDimitry Andric new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order, m_status);
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric if (!new_plan_sp)
3210b57cec5SDimitry Andric m_no_more_plans = true;
3220b57cec5SDimitry Andric else {
3230b57cec5SDimitry Andric // Any new plan will be an implementation plan, so mark it private:
3240b57cec5SDimitry Andric new_plan_sp->SetPrivate(true);
3250b57cec5SDimitry Andric m_no_more_plans = false;
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric
3280b57cec5SDimitry Andric if (!new_plan_sp) {
3290b57cec5SDimitry Andric // For efficiencies sake, we know we're done here so we don't have to do
3300b57cec5SDimitry Andric // this calculation again in MischiefManaged.
3310b57cec5SDimitry Andric SetPlanComplete(m_status.Success());
3320b57cec5SDimitry Andric return true;
3330b57cec5SDimitry Andric } else
3340b57cec5SDimitry Andric return false;
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric
DoPlanExplainsStop(Event * event_ptr)3370b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) {
3380b57cec5SDimitry Andric // For crashes, breakpoint hits, signals, etc, let the base plan (or some
3390b57cec5SDimitry Andric // plan above us) handle the stop. That way the user can see the stop, step
3400b57cec5SDimitry Andric // around, and then when they are done, continue and have their step
3410b57cec5SDimitry Andric // complete. The exception is if we've hit our "run to next branch"
3420b57cec5SDimitry Andric // breakpoint. Note, unlike the step in range plan, we don't mark ourselves
3430b57cec5SDimitry Andric // complete if we hit an unexplained breakpoint/crash.
3440b57cec5SDimitry Andric
34581ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Step);
3460b57cec5SDimitry Andric StopInfoSP stop_info_sp = GetPrivateStopInfo();
3470b57cec5SDimitry Andric bool return_value;
3480b57cec5SDimitry Andric
3490b57cec5SDimitry Andric if (stop_info_sp) {
3500b57cec5SDimitry Andric StopReason reason = stop_info_sp->GetStopReason();
3510b57cec5SDimitry Andric
3520b57cec5SDimitry Andric if (reason == eStopReasonTrace) {
3530b57cec5SDimitry Andric return_value = true;
3540b57cec5SDimitry Andric } else if (reason == eStopReasonBreakpoint) {
3550b57cec5SDimitry Andric return_value = NextRangeBreakpointExplainsStop(stop_info_sp);
3560b57cec5SDimitry Andric } else {
3570b57cec5SDimitry Andric if (log)
3580b57cec5SDimitry Andric log->PutCString("ThreadPlanStepInRange got asked if it explains the "
3590b57cec5SDimitry Andric "stop for some reason other than step.");
3600b57cec5SDimitry Andric return_value = false;
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric } else
3630b57cec5SDimitry Andric return_value = true;
3640b57cec5SDimitry Andric
3650b57cec5SDimitry Andric return return_value;
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric
DoWillResume(lldb::StateType resume_state,bool current_plan)3680b57cec5SDimitry Andric bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state,
3690b57cec5SDimitry Andric bool current_plan) {
3700b57cec5SDimitry Andric if (resume_state != eStateSuspended && m_first_resume) {
3710b57cec5SDimitry Andric m_first_resume = false;
3720b57cec5SDimitry Andric if (resume_state == eStateStepping && current_plan) {
3735ffd83dbSDimitry Andric Thread &thread = GetThread();
3740b57cec5SDimitry Andric // See if we are about to step over an inlined call in the middle of the
3750b57cec5SDimitry Andric // inlined stack, if so figure out its extents and reset our range to
3760b57cec5SDimitry Andric // step over that.
3775ffd83dbSDimitry Andric bool in_inlined_stack = thread.DecrementCurrentInlinedDepth();
3780b57cec5SDimitry Andric if (in_inlined_stack) {
37981ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Step);
3809dba64beSDimitry Andric LLDB_LOGF(log,
3819dba64beSDimitry Andric "ThreadPlanStepInRange::DoWillResume: adjusting range to "
3820b57cec5SDimitry Andric "the frame at inlined depth %d.",
3835ffd83dbSDimitry Andric thread.GetCurrentInlinedDepth());
3845ffd83dbSDimitry Andric StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
3850b57cec5SDimitry Andric if (stack_sp) {
3860b57cec5SDimitry Andric Block *frame_block = stack_sp->GetFrameBlock();
3875ffd83dbSDimitry Andric lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
3880b57cec5SDimitry Andric AddressRange my_range;
3890b57cec5SDimitry Andric if (frame_block->GetRangeContainingLoadAddress(
3905ffd83dbSDimitry Andric curr_pc, m_process.GetTarget(), my_range)) {
3910b57cec5SDimitry Andric m_address_ranges.clear();
3920b57cec5SDimitry Andric m_address_ranges.push_back(my_range);
3930b57cec5SDimitry Andric if (log) {
3940b57cec5SDimitry Andric StreamString s;
3950b57cec5SDimitry Andric const InlineFunctionInfo *inline_info =
3960b57cec5SDimitry Andric frame_block->GetInlinedFunctionInfo();
3970b57cec5SDimitry Andric const char *name;
3980b57cec5SDimitry Andric if (inline_info)
3995ffd83dbSDimitry Andric name = inline_info->GetName().AsCString();
4000b57cec5SDimitry Andric else
4010b57cec5SDimitry Andric name = "<unknown-notinlined>";
4020b57cec5SDimitry Andric
4030b57cec5SDimitry Andric s.Printf(
4040b57cec5SDimitry Andric "Stepping over inlined function \"%s\" in inlined stack: ",
4050b57cec5SDimitry Andric name);
4060b57cec5SDimitry Andric DumpRanges(&s);
4070b57cec5SDimitry Andric log->PutString(s.GetString());
4080b57cec5SDimitry Andric }
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric }
4110b57cec5SDimitry Andric }
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric return true;
4160b57cec5SDimitry Andric }
417