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     {
87         if (!frame->HasDebugInformation())
88         {
89             if (log)
90                 log->Printf ("Stepping out of frame with no debug info");
91 
92             should_stop_here = false;
93         }
94     }
95 
96     // Always avoid code with line number 0.
97     // FIXME: At present the ShouldStop and the StepFromHere calculate this independently.  If this ever
98     // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use.
99     if (frame)
100     {
101         SymbolContext sc;
102         sc = frame->GetSymbolContext (eSymbolContextLineEntry);
103         if (sc.line_entry.line == 0)
104             should_stop_here = false;
105     }
106 
107     return should_stop_here;
108 }
109 
110 ThreadPlanSP
111 ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan,
112                                                          Flags &flags,
113                                                          FrameComparison operation,
114                                                          void *baton)
115 {
116     const bool stop_others = false;
117     const size_t frame_index = 0;
118     ThreadPlanSP return_plan_sp;
119     // If we are stepping through code at line number 0, then we need to step over this range.  Otherwise
120     // we will step out.
121     StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
122     if (!frame)
123         return return_plan_sp;
124     SymbolContext sc;
125     sc = frame->GetSymbolContext (eSymbolContextLineEntry);
126     if (sc.line_entry.line == 0)
127     {
128         AddressRange range = sc.line_entry.range;
129         return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOverRange(false,
130                                                                                    range,
131                                                                                    sc,
132                                                                                    eOnlyDuringStepping,
133                                                                                    eLazyBoolNo);
134     }
135 
136     if (!return_plan_sp)
137         return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop (false,
138                                                                                           NULL,
139                                                                                           true,
140                                                                                           stop_others,
141                                                                                           eVoteNo,
142                                                                                           eVoteNoOpinion,
143                                                                                           frame_index);
144     return return_plan_sp;
145 }
146 
147 ThreadPlanSP
148 ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation)
149 {
150     ThreadPlanSP return_plan_sp;
151     if (m_callbacks.step_from_here_callback)
152     {
153          return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton);
154     }
155     return return_plan_sp;
156 
157 }
158 
159 lldb::ThreadPlanSP
160 ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation)
161 {
162     if (!InvokeShouldStopHereCallback(operation))
163         return QueueStepOutFromHerePlan(m_flags, operation);
164     else
165         return ThreadPlanSP();
166 }
167 
168