202 lines · cpp
1//===-- ThreadPlanShouldStopHere.cpp --------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/ThreadPlanShouldStopHere.h"10#include "lldb/Symbol/Symbol.h"11#include "lldb/Target/Language.h"12#include "lldb/Target/LanguageRuntime.h"13#include "lldb/Target/RegisterContext.h"14#include "lldb/Target/Thread.h"15#include "lldb/Utility/LLDBLog.h"16#include "lldb/Utility/Log.h"17 18using namespace lldb;19using namespace lldb_private;20 21// ThreadPlanShouldStopHere constructor22ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner)23 : m_callbacks(), m_baton(nullptr), m_owner(owner),24 m_flags(ThreadPlanShouldStopHere::eNone) {25 m_callbacks.should_stop_here_callback =26 ThreadPlanShouldStopHere::DefaultShouldStopHereCallback;27 m_callbacks.step_from_here_callback =28 ThreadPlanShouldStopHere::DefaultStepFromHereCallback;29}30 31ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(32 ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks,33 void *baton)34 : m_callbacks(), m_baton(), m_owner(owner),35 m_flags(ThreadPlanShouldStopHere::eNone) {36 SetShouldStopHereCallbacks(callbacks, baton);37}38 39ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default;40 41bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback(42 FrameComparison operation, Status &status) {43 bool should_stop_here = true;44 if (m_callbacks.should_stop_here_callback) {45 should_stop_here = m_callbacks.should_stop_here_callback(46 m_owner, m_flags, operation, status, m_baton);47 Log *log = GetLog(LLDBLog::Step);48 if (log) {49 lldb::addr_t current_addr =50 m_owner->GetThread().GetRegisterContext()->GetPC(0);51 52 LLDB_LOGF(log, "ShouldStopHere callback returned %u from 0x%" PRIx64 ".",53 should_stop_here, current_addr);54 }55 }56 57 return should_stop_here;58}59 60bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(61 ThreadPlan *current_plan, Flags &flags, FrameComparison operation,62 Status &status, void *baton) {63 bool should_stop_here = true;64 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();65 if (!frame)66 return true;67 68 Log *log = GetLog(LLDBLog::Step);69 70 if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) ||71 (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) ||72 (operation == eFrameCompareSameParent &&73 flags.Test(eStepInAvoidNoDebug))) {74 if (!frame->HasDebugInformation()) {75 LLDB_LOGF(log, "Stepping out of frame with no debug info");76 77 should_stop_here = false;78 }79 }80 81 // Check whether the frame we are in is a language runtime thunk, only for82 // step out:83 if (operation == eFrameCompareOlder) {84 if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) {85 ProcessSP process_sp(current_plan->GetThread().GetProcess());86 for (auto *runtime : process_sp->GetLanguageRuntimes()) {87 if (runtime->IsSymbolARuntimeThunk(*symbol) &&88 flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) {89 LLDB_LOGF(90 log, "Stepping out past a language thunk %s for: %s",91 frame->GetFunctionName(),92 Language::GetNameForLanguageType(runtime->GetLanguageType()));93 should_stop_here = false;94 break;95 }96 }97 }98 }99 // Always avoid code with line number 0.100 // FIXME: At present the ShouldStop and the StepFromHere calculate this101 // independently. If this ever102 // becomes expensive (this one isn't) we can try to have this set a state103 // that the StepFromHere can use.104 if (frame) {105 SymbolContext sc;106 sc = frame->GetSymbolContext(eSymbolContextLineEntry);107 if (sc.line_entry.line == 0)108 should_stop_here = false;109 }110 111 return should_stop_here;112}113 114ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(115 ThreadPlan *current_plan, Flags &flags, FrameComparison operation,116 Status &status, void *baton) {117 const bool stop_others = false;118 const size_t frame_index = 0;119 ThreadPlanSP return_plan_sp;120 // If we are stepping through code at line number 0, then we need to step121 // over this range. Otherwise we will step out.122 Log *log = GetLog(LLDBLog::Step);123 124 StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();125 if (!frame)126 return return_plan_sp;127 SymbolContext sc;128 sc = frame->GetSymbolContext(eSymbolContextLineEntry | eSymbolContextSymbol);129 130 if (sc.line_entry.line == 0) {131 AddressRange range = sc.line_entry.range;132 bool just_step_out = false;133 if (sc.symbol) {134 ProcessSP process_sp(current_plan->GetThread().GetProcess());135 136 // If this is a runtime thunk, step through it, rather than stepping out137 // because it's marked line 0.138 bool is_thunk = false;139 for (auto *runtime : process_sp->GetLanguageRuntimes()) {140 if (runtime->IsSymbolARuntimeThunk(*sc.symbol) &&141 flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) {142 LLDB_LOGF(143 log, "Stepping out past a language thunk %s for: %s",144 frame->GetFunctionName(),145 Language::GetNameForLanguageType(runtime->GetLanguageType()));146 is_thunk = true;147 break;148 }149 }150 151 // If the whole function is marked line 0 just step out, that's easier &152 // faster than continuing to step through it.153 // FIXME: This assumes that the function is a single line range. It could154 // be a series of contiguous line 0 ranges. Check for that too.155 if (!is_thunk && sc.symbol->ValueIsAddress()) {156 Address symbol_end = sc.symbol->GetAddress();157 symbol_end.Slide(sc.symbol->GetByteSize() - 1);158 if (range.ContainsFileAddress(sc.symbol->GetAddress()) &&159 range.ContainsFileAddress(symbol_end)) {160 LLDB_LOGF(log, "Stopped in a function with only line 0 lines, just "161 "stepping out.");162 just_step_out = true;163 }164 }165 }166 if (!just_step_out) {167 LLDB_LOGF(log, "ThreadPlanShouldStopHere::DefaultStepFromHereCallback "168 "Queueing StepInRange plan to step through line 0 code.");169 170 return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(171 false, range, sc, nullptr, eOnlyDuringStepping, status,172 eLazyBoolCalculate, eLazyBoolNo);173 }174 }175 176 if (!return_plan_sp)177 return_plan_sp =178 current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(179 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion,180 frame_index, status, true);181 return return_plan_sp;182}183 184ThreadPlanSP ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(185 lldb_private::Flags &flags, lldb::FrameComparison operation,186 Status &status) {187 ThreadPlanSP return_plan_sp;188 if (m_callbacks.step_from_here_callback) {189 return_plan_sp = m_callbacks.step_from_here_callback(190 m_owner, flags, operation, status, m_baton);191 }192 return return_plan_sp;193}194 195lldb::ThreadPlanSP ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut(196 lldb::FrameComparison operation, Status &status) {197 if (!InvokeShouldStopHereCallback(operation, status))198 return QueueStepOutFromHerePlan(m_flags, operation, status);199 else200 return ThreadPlanSP();201}202