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 #include "lldb/Target/RegisterContext.h"
11 #include "lldb/Target/Thread.h"
12 #include "lldb/Target/ThreadPlanShouldStopHere.h"
13 #include "lldb/Core/Log.h"
14 
15 using namespace lldb;
16 using namespace lldb_private;
17 
18 // C Includes
19 // C++ Includes
20 // Other libraries and framework includes
21 // Project includes
22 
23 //----------------------------------------------------------------------
24 // ThreadPlanShouldStopHere constructor
25 //----------------------------------------------------------------------
26 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) :
27     m_callbacks (),
28     m_baton (NULL),
29     m_owner (owner),
30     m_flags (ThreadPlanShouldStopHere::eNone)
31 {
32     m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback;
33     m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback;
34 }
35 
36 ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton) :
37     m_callbacks (),
38     m_baton (),
39     m_owner (owner),
40     m_flags (ThreadPlanShouldStopHere::eNone)
41 {
42     SetShouldStopHereCallbacks(callbacks, baton);
43 }
44 
45 //----------------------------------------------------------------------
46 // Destructor
47 //----------------------------------------------------------------------
48 ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere()
49 {
50 }
51 
52 bool
53 ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation)
54 {
55     bool should_stop_here = true;
56     if (m_callbacks.should_stop_here_callback)
57     {
58         should_stop_here = m_callbacks.should_stop_here_callback (m_owner, m_flags, operation, m_baton);
59         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
60         if (log)
61         {
62             lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0);
63 
64             log->Printf ("ShouldStopHere callback returned %u from 0x%" PRIx64 ".", should_stop_here, current_addr);
65         }
66     }
67 
68     return should_stop_here;
69 }
70 
71 bool
72 ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
73                                                          Flags &flags,
74                                                          FrameComparison operation,
75                                                          void *baton)
76 {
77     bool should_stop_here = true;
78     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
79     if (!frame)
80         return true;
81 
82     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
83 
84     if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug))
85         || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug))
86         || (operation == eFrameCompareSameParent && flags.Test(eStepInAvoidNoDebug)))
87     {
88         if (!frame->HasDebugInformation())
89         {
90             if (log)
91                 log->Printf ("Stepping out of frame with no debug info");
92 
93             should_stop_here = false;
94         }
95     }
96 
97     // Always avoid code with line number 0.
98     // FIXME: At present the ShouldStop and the StepFromHere calculate this independently.  If this ever
99     // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use.
100     if (frame)
101     {
102         SymbolContext sc;
103         sc = frame->GetSymbolContext (eSymbolContextLineEntry);
104         if (sc.line_entry.line == 0)
105             should_stop_here = false;
106     }
107 
108     return should_stop_here;
109 }
110 
111 ThreadPlanSP
112 ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan,
113                                                          Flags &flags,
114                                                          FrameComparison operation,
115                                                          void *baton)
116 {
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 step over this range.  Otherwise
121     // we will step out.
122     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
123     if (!frame)
124         return return_plan_sp;
125     SymbolContext sc;
126     sc = frame->GetSymbolContext (eSymbolContextLineEntry);
127     if (sc.line_entry.line == 0)
128     {
129         AddressRange range = sc.line_entry.range;
130         return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOverRange(false,
131                                                                                    range,
132                                                                                    sc,
133                                                                                    eOnlyDuringStepping,
134                                                                                    eLazyBoolNo);
135     }
136 
137     if (!return_plan_sp)
138         return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop (false,
139                                                                                           NULL,
140                                                                                           true,
141                                                                                           stop_others,
142                                                                                           eVoteNo,
143                                                                                           eVoteNoOpinion,
144                                                                                           frame_index);
145     return return_plan_sp;
146 }
147 
148 ThreadPlanSP
149 ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation)
150 {
151     ThreadPlanSP return_plan_sp;
152     if (m_callbacks.step_from_here_callback)
153     {
154          return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton);
155     }
156     return return_plan_sp;
157 
158 }
159 
160 lldb::ThreadPlanSP
161 ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation)
162 {
163     if (!InvokeShouldStopHereCallback(operation))
164         return QueueStepOutFromHerePlan(m_flags, operation);
165     else
166         return ThreadPlanSP();
167 }
168 
169