1 //===-- ThreadPlanStepUntil.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/ThreadPlanStepUntil.h"
11 
12 #include "lldb/Breakpoint/Breakpoint.h"
13 #include "lldb/Symbol/SymbolContextScope.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/RegisterContext.h"
16 #include "lldb/Target/StopInfo.h"
17 #include "lldb/Target/Target.h"
18 #include "lldb/Utility/Log.h"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 //----------------------------------------------------------------------
24 // ThreadPlanStepUntil: Run until we reach a given line number or step out of
25 // the current frame
26 //----------------------------------------------------------------------
27 
28 ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
29                                          lldb::addr_t *address_list,
30                                          size_t num_addresses, bool stop_others,
31                                          uint32_t frame_idx)
32     : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread,
33                  eVoteNoOpinion, eVoteNoOpinion),
34       m_step_from_insn(LLDB_INVALID_ADDRESS),
35       m_return_bp_id(LLDB_INVALID_BREAK_ID),
36       m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false),
37       m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
38       m_until_points(), m_stop_others(stop_others) {
39   // Stash away our "until" addresses:
40   TargetSP target_sp(m_thread.CalculateTarget());
41 
42   StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx));
43   if (frame_sp) {
44     m_step_from_insn = frame_sp->GetStackID().GetPC();
45     lldb::user_id_t thread_id = m_thread.GetID();
46 
47     // Find the return address and set a breakpoint there:
48     // FIXME - can we do this more securely if we know first_insn?
49 
50     StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1));
51     if (return_frame_sp) {
52       // TODO: add inline functionality
53       m_return_addr = return_frame_sp->GetStackID().GetPC();
54       Breakpoint *return_bp =
55           target_sp->CreateBreakpoint(m_return_addr, true, false).get();
56       if (return_bp != nullptr) {
57         return_bp->SetThreadID(thread_id);
58         m_return_bp_id = return_bp->GetID();
59         return_bp->SetBreakpointKind("until-return-backstop");
60       }
61     }
62 
63     m_stack_id = frame_sp->GetStackID();
64 
65     // Now set breakpoints on all our return addresses:
66     for (size_t i = 0; i < num_addresses; i++) {
67       Breakpoint *until_bp =
68           target_sp->CreateBreakpoint(address_list[i], true, false).get();
69       if (until_bp != nullptr) {
70         until_bp->SetThreadID(thread_id);
71         m_until_points[address_list[i]] = until_bp->GetID();
72         until_bp->SetBreakpointKind("until-target");
73       } else {
74         m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
75       }
76     }
77   }
78 }
79 
80 ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); }
81 
82 void ThreadPlanStepUntil::Clear() {
83   TargetSP target_sp(m_thread.CalculateTarget());
84   if (target_sp) {
85     if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
86       target_sp->RemoveBreakpointByID(m_return_bp_id);
87       m_return_bp_id = LLDB_INVALID_BREAK_ID;
88     }
89 
90     until_collection::iterator pos, end = m_until_points.end();
91     for (pos = m_until_points.begin(); pos != end; pos++) {
92       target_sp->RemoveBreakpointByID((*pos).second);
93     }
94   }
95   m_until_points.clear();
96 }
97 
98 void ThreadPlanStepUntil::GetDescription(Stream *s,
99                                          lldb::DescriptionLevel level) {
100   if (level == lldb::eDescriptionLevelBrief) {
101     s->Printf("step until");
102     if (m_stepped_out)
103       s->Printf(" - stepped out");
104   } else {
105     if (m_until_points.size() == 1)
106       s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64
107                 " using breakpoint %d",
108                 (uint64_t)m_step_from_insn,
109                 (uint64_t)(*m_until_points.begin()).first,
110                 (*m_until_points.begin()).second);
111     else {
112       until_collection::iterator pos, end = m_until_points.end();
113       s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:",
114                 (uint64_t)m_step_from_insn);
115       for (pos = m_until_points.begin(); pos != end; pos++) {
116         s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)(*pos).first,
117                   (*pos).second);
118       }
119     }
120     s->Printf(" stepped out address is 0x%" PRIx64 ".",
121               (uint64_t)m_return_addr);
122   }
123 }
124 
125 bool ThreadPlanStepUntil::ValidatePlan(Stream *error) {
126   if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
127     return false;
128   else {
129     until_collection::iterator pos, end = m_until_points.end();
130     for (pos = m_until_points.begin(); pos != end; pos++) {
131       if (!LLDB_BREAK_ID_IS_VALID((*pos).second))
132         return false;
133     }
134     return true;
135   }
136 }
137 
138 void ThreadPlanStepUntil::AnalyzeStop() {
139   if (m_ran_analyze)
140     return;
141 
142   StopInfoSP stop_info_sp = GetPrivateStopInfo();
143   m_should_stop = true;
144   m_explains_stop = false;
145 
146   if (stop_info_sp) {
147     StopReason reason = stop_info_sp->GetStopReason();
148 
149     if (reason == eStopReasonBreakpoint) {
150       // If this is OUR breakpoint, we're fine, otherwise we don't know why
151       // this happened...
152       BreakpointSiteSP this_site =
153           m_thread.GetProcess()->GetBreakpointSiteList().FindByID(
154               stop_info_sp->GetValue());
155       if (!this_site) {
156         m_explains_stop = false;
157         return;
158       }
159 
160       if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) {
161         // If we are at our "step out" breakpoint, and the stack depth has
162         // shrunk, then this is indeed our stop. If the stack depth has grown,
163         // then we've hit our step out breakpoint recursively. If we are the
164         // only breakpoint at that location, then we do explain the stop, and
165         // we'll just continue. If there was another breakpoint here, then we
166         // don't explain the stop, but we won't mark ourselves Completed,
167         // because maybe that breakpoint will continue, and then we'll finish
168         // the "until".
169         bool done;
170         StackID cur_frame_zero_id;
171 
172         done = (m_stack_id < cur_frame_zero_id);
173 
174         if (done) {
175           m_stepped_out = true;
176           SetPlanComplete();
177         } else
178           m_should_stop = false;
179 
180         if (this_site->GetNumberOfOwners() == 1)
181           m_explains_stop = true;
182         else
183           m_explains_stop = false;
184         return;
185       } else {
186         // Check if we've hit one of our "until" breakpoints.
187         until_collection::iterator pos, end = m_until_points.end();
188         for (pos = m_until_points.begin(); pos != end; pos++) {
189           if (this_site->IsBreakpointAtThisSite((*pos).second)) {
190             // If we're at the right stack depth, then we're done.
191 
192             bool done;
193             StackID frame_zero_id =
194                 m_thread.GetStackFrameAtIndex(0)->GetStackID();
195 
196             if (frame_zero_id == m_stack_id)
197               done = true;
198             else if (frame_zero_id < m_stack_id)
199               done = false;
200             else {
201               StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
202 
203               // But if we can't even unwind one frame we should just get out
204               // of here & stop...
205               if (older_frame_sp) {
206                 const SymbolContext &older_context =
207                     older_frame_sp->GetSymbolContext(eSymbolContextEverything);
208                 SymbolContext stack_context;
209                 m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(
210                     &stack_context);
211 
212                 done = (older_context == stack_context);
213               } else
214                 done = false;
215             }
216 
217             if (done)
218               SetPlanComplete();
219             else
220               m_should_stop = false;
221 
222             // Otherwise we've hit this breakpoint recursively.  If we're the
223             // only breakpoint here, then we do explain the stop, and we'll
224             // continue. If not then we should let higher plans handle this
225             // stop.
226             if (this_site->GetNumberOfOwners() == 1)
227               m_explains_stop = true;
228             else {
229               m_should_stop = true;
230               m_explains_stop = false;
231             }
232             return;
233           }
234         }
235       }
236       // If we get here we haven't hit any of our breakpoints, so let the
237       // higher plans take care of the stop.
238       m_explains_stop = false;
239       return;
240     } else if (IsUsuallyUnexplainedStopReason(reason)) {
241       m_explains_stop = false;
242     } else {
243       m_explains_stop = true;
244     }
245   }
246 }
247 
248 bool ThreadPlanStepUntil::DoPlanExplainsStop(Event *event_ptr) {
249   // We don't explain signals or breakpoints (breakpoints that handle stepping
250   // in or out will be handled by a child plan.
251   AnalyzeStop();
252   return m_explains_stop;
253 }
254 
255 bool ThreadPlanStepUntil::ShouldStop(Event *event_ptr) {
256   // If we've told our self in ExplainsStop that we plan to continue, then do
257   // so here.  Otherwise, as long as this thread has stopped for a reason, we
258   // will stop.
259 
260   StopInfoSP stop_info_sp = GetPrivateStopInfo();
261   if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
262     return false;
263 
264   AnalyzeStop();
265   return m_should_stop;
266 }
267 
268 bool ThreadPlanStepUntil::StopOthers() { return m_stop_others; }
269 
270 StateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; }
271 
272 bool ThreadPlanStepUntil::DoWillResume(StateType resume_state,
273                                        bool current_plan) {
274   if (current_plan) {
275     TargetSP target_sp(m_thread.CalculateTarget());
276     if (target_sp) {
277       Breakpoint *return_bp =
278           target_sp->GetBreakpointByID(m_return_bp_id).get();
279       if (return_bp != nullptr)
280         return_bp->SetEnabled(true);
281 
282       until_collection::iterator pos, end = m_until_points.end();
283       for (pos = m_until_points.begin(); pos != end; pos++) {
284         Breakpoint *until_bp =
285             target_sp->GetBreakpointByID((*pos).second).get();
286         if (until_bp != nullptr)
287           until_bp->SetEnabled(true);
288       }
289     }
290   }
291 
292   m_should_stop = true;
293   m_ran_analyze = false;
294   m_explains_stop = false;
295   return true;
296 }
297 
298 bool ThreadPlanStepUntil::WillStop() {
299   TargetSP target_sp(m_thread.CalculateTarget());
300   if (target_sp) {
301     Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
302     if (return_bp != nullptr)
303       return_bp->SetEnabled(false);
304 
305     until_collection::iterator pos, end = m_until_points.end();
306     for (pos = m_until_points.begin(); pos != end; pos++) {
307       Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
308       if (until_bp != nullptr)
309         until_bp->SetEnabled(false);
310     }
311   }
312   return true;
313 }
314 
315 bool ThreadPlanStepUntil::MischiefManaged() {
316   // I'm letting "PlanExplainsStop" do all the work, and just reporting that
317   // here.
318   bool done = false;
319   if (IsPlanComplete()) {
320     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
321     if (log)
322       log->Printf("Completed step until plan.");
323 
324     Clear();
325     done = true;
326   }
327   if (done)
328     ThreadPlan::MischiefManaged();
329 
330   return done;
331 }
332