]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Target/ThreadPlanShouldStopHere.cpp
MFV r329807:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Target / ThreadPlanShouldStopHere.cpp
1 //===-- ThreadPlanShouldStopHere.cpp ----------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Target/ThreadPlanShouldStopHere.h"
15 #include "lldb/Symbol/Symbol.h"
16 #include "lldb/Target/RegisterContext.h"
17 #include "lldb/Target/Thread.h"
18 #include "lldb/Utility/Log.h"
19
20 using namespace lldb;
21 using namespace lldb_private;
22
23 //----------------------------------------------------------------------
24 // ThreadPlanShouldStopHere constructor
25 //----------------------------------------------------------------------
26 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner)
27     : m_callbacks(), m_baton(nullptr), m_owner(owner),
28       m_flags(ThreadPlanShouldStopHere::eNone) {
29   m_callbacks.should_stop_here_callback =
30       ThreadPlanShouldStopHere::DefaultShouldStopHereCallback;
31   m_callbacks.step_from_here_callback =
32       ThreadPlanShouldStopHere::DefaultStepFromHereCallback;
33 }
34
35 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(
36     ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks,
37     void *baton)
38     : m_callbacks(), m_baton(), m_owner(owner),
39       m_flags(ThreadPlanShouldStopHere::eNone) {
40   SetShouldStopHereCallbacks(callbacks, baton);
41 }
42
43 ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default;
44
45 bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback(
46     FrameComparison operation) {
47   bool should_stop_here = true;
48   if (m_callbacks.should_stop_here_callback) {
49     should_stop_here = m_callbacks.should_stop_here_callback(
50         m_owner, m_flags, operation, m_baton);
51     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
52     if (log) {
53       lldb::addr_t current_addr =
54           m_owner->GetThread().GetRegisterContext()->GetPC(0);
55
56       log->Printf("ShouldStopHere callback returned %u from 0x%" PRIx64 ".",
57                   should_stop_here, current_addr);
58     }
59   }
60
61   return should_stop_here;
62 }
63
64 bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
65     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
66     void *baton) {
67   bool should_stop_here = true;
68   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
69   if (!frame)
70     return true;
71
72   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
73
74   if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) ||
75       (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) ||
76       (operation == eFrameCompareSameParent &&
77        flags.Test(eStepInAvoidNoDebug))) {
78     if (!frame->HasDebugInformation()) {
79       if (log)
80         log->Printf("Stepping out of frame with no debug info");
81
82       should_stop_here = false;
83     }
84   }
85
86   // Always avoid code with line number 0.
87   // FIXME: At present the ShouldStop and the StepFromHere calculate this
88   // independently.  If this ever
89   // becomes expensive (this one isn't) we can try to have this set a state that
90   // the StepFromHere can use.
91   if (frame) {
92     SymbolContext sc;
93     sc = frame->GetSymbolContext(eSymbolContextLineEntry);
94     if (sc.line_entry.line == 0)
95       should_stop_here = false;
96   }
97
98   return should_stop_here;
99 }
100
101 ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(
102     ThreadPlan *current_plan, Flags &flags, FrameComparison operation,
103     void *baton) {
104   const bool stop_others = false;
105   const size_t frame_index = 0;
106   ThreadPlanSP return_plan_sp;
107   // If we are stepping through code at line number 0, then we need to step over
108   // this range.  Otherwise
109   // we will step out.
110   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
111
112   StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
113   if (!frame)
114     return return_plan_sp;
115   SymbolContext sc;
116   sc = frame->GetSymbolContext(eSymbolContextLineEntry | eSymbolContextSymbol);
117
118   if (sc.line_entry.line == 0) {
119     AddressRange range = sc.line_entry.range;
120
121     // If the whole function is marked line 0 just step out, that's easier &
122     // faster than continuing
123     // to step through it.
124     bool just_step_out = false;
125     if (sc.symbol && sc.symbol->ValueIsAddress()) {
126       Address symbol_end = sc.symbol->GetAddress();
127       symbol_end.Slide(sc.symbol->GetByteSize() - 1);
128       if (range.ContainsFileAddress(sc.symbol->GetAddress()) &&
129           range.ContainsFileAddress(symbol_end)) {
130         if (log)
131           log->Printf("Stopped in a function with only line 0 lines, just "
132                       "stepping out.");
133         just_step_out = true;
134       }
135     }
136     if (!just_step_out) {
137       if (log)
138         log->Printf("ThreadPlanShouldStopHere::DefaultStepFromHereCallback "
139                     "Queueing StepInRange plan to step through line 0 code.");
140
141       return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(
142           false, range, sc, NULL, eOnlyDuringStepping, eLazyBoolCalculate,
143           eLazyBoolNo);
144     }
145   }
146
147   if (!return_plan_sp)
148     return_plan_sp =
149         current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(
150             false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion,
151             frame_index, true);
152   return return_plan_sp;
153 }
154
155 ThreadPlanSP ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(
156     lldb_private::Flags &flags, lldb::FrameComparison operation) {
157   ThreadPlanSP return_plan_sp;
158   if (m_callbacks.step_from_here_callback) {
159     return_plan_sp =
160         m_callbacks.step_from_here_callback(m_owner, flags, operation, m_baton);
161   }
162   return return_plan_sp;
163 }
164
165 lldb::ThreadPlanSP ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut(
166     lldb::FrameComparison operation) {
167   if (!InvokeShouldStopHereCallback(operation))
168     return QueueStepOutFromHerePlan(m_flags, operation);
169   else
170     return ThreadPlanSP();
171 }