1ac7ddfbfSEd Maste //===-- ThreadPlanStepUntil.cpp ---------------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste //                     The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste 
109f2f44ceSEd Maste #include "lldb/Target/ThreadPlanStepUntil.h"
11f678e45dSDimitry Andric 
12ac7ddfbfSEd Maste #include "lldb/Breakpoint/Breakpoint.h"
13f678e45dSDimitry Andric #include "lldb/Symbol/SymbolContextScope.h"
14ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
15ac7ddfbfSEd Maste #include "lldb/Target/RegisterContext.h"
16ac7ddfbfSEd Maste #include "lldb/Target/StopInfo.h"
17ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
18f678e45dSDimitry Andric #include "lldb/Utility/Log.h"
19ac7ddfbfSEd Maste 
20ac7ddfbfSEd Maste using namespace lldb;
21ac7ddfbfSEd Maste using namespace lldb_private;
22ac7ddfbfSEd Maste 
23ac7ddfbfSEd Maste //----------------------------------------------------------------------
24435933ddSDimitry Andric // ThreadPlanStepUntil: Run until we reach a given line number or step out of
25435933ddSDimitry Andric // the current frame
26ac7ddfbfSEd Maste //----------------------------------------------------------------------
27ac7ddfbfSEd Maste 
ThreadPlanStepUntil(Thread & thread,lldb::addr_t * address_list,size_t num_addresses,bool stop_others,uint32_t frame_idx)28435933ddSDimitry Andric ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
29ac7ddfbfSEd Maste                                          lldb::addr_t *address_list,
30435933ddSDimitry Andric                                          size_t num_addresses, bool stop_others,
31435933ddSDimitry Andric                                          uint32_t frame_idx)
32435933ddSDimitry Andric     : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread,
33435933ddSDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion),
34ac7ddfbfSEd Maste       m_step_from_insn(LLDB_INVALID_ADDRESS),
35ac7ddfbfSEd Maste       m_return_bp_id(LLDB_INVALID_BREAK_ID),
36435933ddSDimitry Andric       m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false),
37435933ddSDimitry Andric       m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
38435933ddSDimitry Andric       m_until_points(), m_stop_others(stop_others) {
39ac7ddfbfSEd Maste   // Stash away our "until" addresses:
40ac7ddfbfSEd Maste   TargetSP target_sp(m_thread.CalculateTarget());
41ac7ddfbfSEd Maste 
42ac7ddfbfSEd Maste   StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx));
43435933ddSDimitry Andric   if (frame_sp) {
44ac7ddfbfSEd Maste     m_step_from_insn = frame_sp->GetStackID().GetPC();
45ac7ddfbfSEd Maste     lldb::user_id_t thread_id = m_thread.GetID();
46ac7ddfbfSEd Maste 
47ac7ddfbfSEd Maste     // Find the return address and set a breakpoint there:
48ac7ddfbfSEd Maste     // FIXME - can we do this more securely if we know first_insn?
49ac7ddfbfSEd Maste 
50ac7ddfbfSEd Maste     StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1));
51435933ddSDimitry Andric     if (return_frame_sp) {
52ac7ddfbfSEd Maste       // TODO: add inline functionality
53ac7ddfbfSEd Maste       m_return_addr = return_frame_sp->GetStackID().GetPC();
54435933ddSDimitry Andric       Breakpoint *return_bp =
55435933ddSDimitry Andric           target_sp->CreateBreakpoint(m_return_addr, true, false).get();
56*b5893f02SDimitry Andric 
57435933ddSDimitry Andric       if (return_bp != nullptr) {
58*b5893f02SDimitry Andric         if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
59*b5893f02SDimitry Andric           m_could_not_resolve_hw_bp = true;
60ac7ddfbfSEd Maste         return_bp->SetThreadID(thread_id);
61ac7ddfbfSEd Maste         m_return_bp_id = return_bp->GetID();
62ac7ddfbfSEd Maste         return_bp->SetBreakpointKind("until-return-backstop");
63ac7ddfbfSEd Maste       }
64ac7ddfbfSEd Maste     }
65ac7ddfbfSEd Maste 
660127ef0fSEd Maste     m_stack_id = frame_sp->GetStackID();
67ac7ddfbfSEd Maste 
68ac7ddfbfSEd Maste     // Now set breakpoints on all our return addresses:
69435933ddSDimitry Andric     for (size_t i = 0; i < num_addresses; i++) {
70435933ddSDimitry Andric       Breakpoint *until_bp =
71435933ddSDimitry Andric           target_sp->CreateBreakpoint(address_list[i], true, false).get();
72435933ddSDimitry Andric       if (until_bp != nullptr) {
73ac7ddfbfSEd Maste         until_bp->SetThreadID(thread_id);
74ac7ddfbfSEd Maste         m_until_points[address_list[i]] = until_bp->GetID();
75ac7ddfbfSEd Maste         until_bp->SetBreakpointKind("until-target");
76435933ddSDimitry Andric       } else {
77ac7ddfbfSEd Maste         m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
78ac7ddfbfSEd Maste       }
79ac7ddfbfSEd Maste     }
80ac7ddfbfSEd Maste   }
81ac7ddfbfSEd Maste }
82ac7ddfbfSEd Maste 
~ThreadPlanStepUntil()83435933ddSDimitry Andric ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); }
84ac7ddfbfSEd Maste 
Clear()85435933ddSDimitry Andric void ThreadPlanStepUntil::Clear() {
86ac7ddfbfSEd Maste   TargetSP target_sp(m_thread.CalculateTarget());
87435933ddSDimitry Andric   if (target_sp) {
88435933ddSDimitry Andric     if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
89ac7ddfbfSEd Maste       target_sp->RemoveBreakpointByID(m_return_bp_id);
90ac7ddfbfSEd Maste       m_return_bp_id = LLDB_INVALID_BREAK_ID;
91ac7ddfbfSEd Maste     }
92ac7ddfbfSEd Maste 
93ac7ddfbfSEd Maste     until_collection::iterator pos, end = m_until_points.end();
94435933ddSDimitry Andric     for (pos = m_until_points.begin(); pos != end; pos++) {
95ac7ddfbfSEd Maste       target_sp->RemoveBreakpointByID((*pos).second);
96ac7ddfbfSEd Maste     }
97ac7ddfbfSEd Maste   }
98ac7ddfbfSEd Maste   m_until_points.clear();
99*b5893f02SDimitry Andric   m_could_not_resolve_hw_bp = false;
100ac7ddfbfSEd Maste }
101ac7ddfbfSEd Maste 
GetDescription(Stream * s,lldb::DescriptionLevel level)102435933ddSDimitry Andric void ThreadPlanStepUntil::GetDescription(Stream *s,
103435933ddSDimitry Andric                                          lldb::DescriptionLevel level) {
104435933ddSDimitry Andric   if (level == lldb::eDescriptionLevelBrief) {
105ac7ddfbfSEd Maste     s->Printf("step until");
106ac7ddfbfSEd Maste     if (m_stepped_out)
107ac7ddfbfSEd Maste       s->Printf(" - stepped out");
108435933ddSDimitry Andric   } else {
109ac7ddfbfSEd Maste     if (m_until_points.size() == 1)
110435933ddSDimitry Andric       s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64
111435933ddSDimitry Andric                 " using breakpoint %d",
112ac7ddfbfSEd Maste                 (uint64_t)m_step_from_insn,
113ac7ddfbfSEd Maste                 (uint64_t)(*m_until_points.begin()).first,
114ac7ddfbfSEd Maste                 (*m_until_points.begin()).second);
115435933ddSDimitry Andric     else {
116ac7ddfbfSEd Maste       until_collection::iterator pos, end = m_until_points.end();
117ac7ddfbfSEd Maste       s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:",
118ac7ddfbfSEd Maste                 (uint64_t)m_step_from_insn);
119435933ddSDimitry Andric       for (pos = m_until_points.begin(); pos != end; pos++) {
120435933ddSDimitry Andric         s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)(*pos).first,
121435933ddSDimitry Andric                   (*pos).second);
122ac7ddfbfSEd Maste       }
123ac7ddfbfSEd Maste     }
124435933ddSDimitry Andric     s->Printf(" stepped out address is 0x%" PRIx64 ".",
125435933ddSDimitry Andric               (uint64_t)m_return_addr);
126ac7ddfbfSEd Maste   }
127ac7ddfbfSEd Maste }
128ac7ddfbfSEd Maste 
ValidatePlan(Stream * error)129435933ddSDimitry Andric bool ThreadPlanStepUntil::ValidatePlan(Stream *error) {
130*b5893f02SDimitry Andric   if (m_could_not_resolve_hw_bp) {
131*b5893f02SDimitry Andric     if (error)
132*b5893f02SDimitry Andric       error->PutCString(
133*b5893f02SDimitry Andric           "Could not create hardware breakpoint for thread plan.");
134ac7ddfbfSEd Maste     return false;
135*b5893f02SDimitry Andric   } else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
136*b5893f02SDimitry Andric     if (error)
137*b5893f02SDimitry Andric       error->PutCString("Could not create return breakpoint.");
138*b5893f02SDimitry Andric     return false;
139*b5893f02SDimitry Andric   } else {
140ac7ddfbfSEd Maste     until_collection::iterator pos, end = m_until_points.end();
141435933ddSDimitry Andric     for (pos = m_until_points.begin(); pos != end; pos++) {
142ac7ddfbfSEd Maste       if (!LLDB_BREAK_ID_IS_VALID((*pos).second))
143ac7ddfbfSEd Maste         return false;
144ac7ddfbfSEd Maste     }
145ac7ddfbfSEd Maste     return true;
146ac7ddfbfSEd Maste   }
147ac7ddfbfSEd Maste }
148ac7ddfbfSEd Maste 
AnalyzeStop()149435933ddSDimitry Andric void ThreadPlanStepUntil::AnalyzeStop() {
150ac7ddfbfSEd Maste   if (m_ran_analyze)
151ac7ddfbfSEd Maste     return;
152ac7ddfbfSEd Maste 
153ac7ddfbfSEd Maste   StopInfoSP stop_info_sp = GetPrivateStopInfo();
154ac7ddfbfSEd Maste   m_should_stop = true;
155ac7ddfbfSEd Maste   m_explains_stop = false;
156ac7ddfbfSEd Maste 
157435933ddSDimitry Andric   if (stop_info_sp) {
158ac7ddfbfSEd Maste     StopReason reason = stop_info_sp->GetStopReason();
159ac7ddfbfSEd Maste 
160435933ddSDimitry Andric     if (reason == eStopReasonBreakpoint) {
1614ba319b5SDimitry Andric       // If this is OUR breakpoint, we're fine, otherwise we don't know why
1624ba319b5SDimitry Andric       // this happened...
163435933ddSDimitry Andric       BreakpointSiteSP this_site =
164435933ddSDimitry Andric           m_thread.GetProcess()->GetBreakpointSiteList().FindByID(
165435933ddSDimitry Andric               stop_info_sp->GetValue());
166435933ddSDimitry Andric       if (!this_site) {
167ac7ddfbfSEd Maste         m_explains_stop = false;
168ac7ddfbfSEd Maste         return;
169ac7ddfbfSEd Maste       }
170ac7ddfbfSEd Maste 
171435933ddSDimitry Andric       if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) {
172435933ddSDimitry Andric         // If we are at our "step out" breakpoint, and the stack depth has
1734ba319b5SDimitry Andric         // shrunk, then this is indeed our stop. If the stack depth has grown,
1744ba319b5SDimitry Andric         // then we've hit our step out breakpoint recursively. If we are the
1754ba319b5SDimitry Andric         // only breakpoint at that location, then we do explain the stop, and
1764ba319b5SDimitry Andric         // we'll just continue. If there was another breakpoint here, then we
1774ba319b5SDimitry Andric         // don't explain the stop, but we won't mark ourselves Completed,
1784ba319b5SDimitry Andric         // because maybe that breakpoint will continue, and then we'll finish
1794ba319b5SDimitry Andric         // the "until".
180ac7ddfbfSEd Maste         bool done;
181ac7ddfbfSEd Maste         StackID cur_frame_zero_id;
182ac7ddfbfSEd Maste 
1839f2f44ceSEd Maste         done = (m_stack_id < cur_frame_zero_id);
184ac7ddfbfSEd Maste 
185435933ddSDimitry Andric         if (done) {
186ac7ddfbfSEd Maste           m_stepped_out = true;
187ac7ddfbfSEd Maste           SetPlanComplete();
188435933ddSDimitry Andric         } else
189ac7ddfbfSEd Maste           m_should_stop = false;
190ac7ddfbfSEd Maste 
191ac7ddfbfSEd Maste         if (this_site->GetNumberOfOwners() == 1)
192ac7ddfbfSEd Maste           m_explains_stop = true;
193ac7ddfbfSEd Maste         else
194ac7ddfbfSEd Maste           m_explains_stop = false;
195ac7ddfbfSEd Maste         return;
196435933ddSDimitry Andric       } else {
197ac7ddfbfSEd Maste         // Check if we've hit one of our "until" breakpoints.
198ac7ddfbfSEd Maste         until_collection::iterator pos, end = m_until_points.end();
199435933ddSDimitry Andric         for (pos = m_until_points.begin(); pos != end; pos++) {
200435933ddSDimitry Andric           if (this_site->IsBreakpointAtThisSite((*pos).second)) {
201ac7ddfbfSEd Maste             // If we're at the right stack depth, then we're done.
202ac7ddfbfSEd Maste 
203ac7ddfbfSEd Maste             bool done;
204435933ddSDimitry Andric             StackID frame_zero_id =
205435933ddSDimitry Andric                 m_thread.GetStackFrameAtIndex(0)->GetStackID();
206ac7ddfbfSEd Maste 
207ac7ddfbfSEd Maste             if (frame_zero_id == m_stack_id)
208ac7ddfbfSEd Maste               done = true;
209ac7ddfbfSEd Maste             else if (frame_zero_id < m_stack_id)
210ac7ddfbfSEd Maste               done = false;
211435933ddSDimitry Andric             else {
212ac7ddfbfSEd Maste               StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
213ac7ddfbfSEd Maste 
2144ba319b5SDimitry Andric               // But if we can't even unwind one frame we should just get out
2154ba319b5SDimitry Andric               // of here & stop...
216435933ddSDimitry Andric               if (older_frame_sp) {
217435933ddSDimitry Andric                 const SymbolContext &older_context =
218435933ddSDimitry Andric                     older_frame_sp->GetSymbolContext(eSymbolContextEverything);
219ac7ddfbfSEd Maste                 SymbolContext stack_context;
220435933ddSDimitry Andric                 m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(
221435933ddSDimitry Andric                     &stack_context);
222ac7ddfbfSEd Maste 
2239f2f44ceSEd Maste                 done = (older_context == stack_context);
224435933ddSDimitry Andric               } else
225ac7ddfbfSEd Maste                 done = false;
226ac7ddfbfSEd Maste             }
227ac7ddfbfSEd Maste 
228ac7ddfbfSEd Maste             if (done)
229ac7ddfbfSEd Maste               SetPlanComplete();
230ac7ddfbfSEd Maste             else
231ac7ddfbfSEd Maste               m_should_stop = false;
232ac7ddfbfSEd Maste 
233ac7ddfbfSEd Maste             // Otherwise we've hit this breakpoint recursively.  If we're the
234435933ddSDimitry Andric             // only breakpoint here, then we do explain the stop, and we'll
2354ba319b5SDimitry Andric             // continue. If not then we should let higher plans handle this
2364ba319b5SDimitry Andric             // stop.
237ac7ddfbfSEd Maste             if (this_site->GetNumberOfOwners() == 1)
238ac7ddfbfSEd Maste               m_explains_stop = true;
239435933ddSDimitry Andric             else {
240ac7ddfbfSEd Maste               m_should_stop = true;
241ac7ddfbfSEd Maste               m_explains_stop = false;
242ac7ddfbfSEd Maste             }
243ac7ddfbfSEd Maste             return;
244ac7ddfbfSEd Maste           }
245ac7ddfbfSEd Maste         }
246ac7ddfbfSEd Maste       }
2474ba319b5SDimitry Andric       // If we get here we haven't hit any of our breakpoints, so let the
2484ba319b5SDimitry Andric       // higher plans take care of the stop.
249ac7ddfbfSEd Maste       m_explains_stop = false;
250ac7ddfbfSEd Maste       return;
251435933ddSDimitry Andric     } else if (IsUsuallyUnexplainedStopReason(reason)) {
252ac7ddfbfSEd Maste       m_explains_stop = false;
253435933ddSDimitry Andric     } else {
254ac7ddfbfSEd Maste       m_explains_stop = true;
255ac7ddfbfSEd Maste     }
256ac7ddfbfSEd Maste   }
257ac7ddfbfSEd Maste }
258ac7ddfbfSEd Maste 
DoPlanExplainsStop(Event * event_ptr)259435933ddSDimitry Andric bool ThreadPlanStepUntil::DoPlanExplainsStop(Event *event_ptr) {
260435933ddSDimitry Andric   // We don't explain signals or breakpoints (breakpoints that handle stepping
2614ba319b5SDimitry Andric   // in or out will be handled by a child plan.
262ac7ddfbfSEd Maste   AnalyzeStop();
263ac7ddfbfSEd Maste   return m_explains_stop;
264ac7ddfbfSEd Maste }
265ac7ddfbfSEd Maste 
ShouldStop(Event * event_ptr)266435933ddSDimitry Andric bool ThreadPlanStepUntil::ShouldStop(Event *event_ptr) {
2674ba319b5SDimitry Andric   // If we've told our self in ExplainsStop that we plan to continue, then do
2684ba319b5SDimitry Andric   // so here.  Otherwise, as long as this thread has stopped for a reason, we
2694ba319b5SDimitry Andric   // will stop.
270ac7ddfbfSEd Maste 
271ac7ddfbfSEd Maste   StopInfoSP stop_info_sp = GetPrivateStopInfo();
272ac7ddfbfSEd Maste   if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
273ac7ddfbfSEd Maste     return false;
274ac7ddfbfSEd Maste 
275ac7ddfbfSEd Maste   AnalyzeStop();
276ac7ddfbfSEd Maste   return m_should_stop;
277ac7ddfbfSEd Maste }
278ac7ddfbfSEd Maste 
StopOthers()279435933ddSDimitry Andric bool ThreadPlanStepUntil::StopOthers() { return m_stop_others; }
280ac7ddfbfSEd Maste 
GetPlanRunState()281435933ddSDimitry Andric StateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; }
282ac7ddfbfSEd Maste 
DoWillResume(StateType resume_state,bool current_plan)283435933ddSDimitry Andric bool ThreadPlanStepUntil::DoWillResume(StateType resume_state,
284435933ddSDimitry Andric                                        bool current_plan) {
285435933ddSDimitry Andric   if (current_plan) {
286ac7ddfbfSEd Maste     TargetSP target_sp(m_thread.CalculateTarget());
287435933ddSDimitry Andric     if (target_sp) {
288435933ddSDimitry Andric       Breakpoint *return_bp =
289435933ddSDimitry Andric           target_sp->GetBreakpointByID(m_return_bp_id).get();
2909f2f44ceSEd Maste       if (return_bp != nullptr)
291ac7ddfbfSEd Maste         return_bp->SetEnabled(true);
292ac7ddfbfSEd Maste 
293ac7ddfbfSEd Maste       until_collection::iterator pos, end = m_until_points.end();
294435933ddSDimitry Andric       for (pos = m_until_points.begin(); pos != end; pos++) {
295435933ddSDimitry Andric         Breakpoint *until_bp =
296435933ddSDimitry Andric             target_sp->GetBreakpointByID((*pos).second).get();
2979f2f44ceSEd Maste         if (until_bp != nullptr)
298ac7ddfbfSEd Maste           until_bp->SetEnabled(true);
299ac7ddfbfSEd Maste       }
300ac7ddfbfSEd Maste     }
301ac7ddfbfSEd Maste   }
302ac7ddfbfSEd Maste 
303ac7ddfbfSEd Maste   m_should_stop = true;
304ac7ddfbfSEd Maste   m_ran_analyze = false;
305ac7ddfbfSEd Maste   m_explains_stop = false;
306ac7ddfbfSEd Maste   return true;
307ac7ddfbfSEd Maste }
308ac7ddfbfSEd Maste 
WillStop()309435933ddSDimitry Andric bool ThreadPlanStepUntil::WillStop() {
310ac7ddfbfSEd Maste   TargetSP target_sp(m_thread.CalculateTarget());
311435933ddSDimitry Andric   if (target_sp) {
312ac7ddfbfSEd Maste     Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
3139f2f44ceSEd Maste     if (return_bp != nullptr)
314ac7ddfbfSEd Maste       return_bp->SetEnabled(false);
315ac7ddfbfSEd Maste 
316ac7ddfbfSEd Maste     until_collection::iterator pos, end = m_until_points.end();
317435933ddSDimitry Andric     for (pos = m_until_points.begin(); pos != end; pos++) {
318ac7ddfbfSEd Maste       Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
3199f2f44ceSEd Maste       if (until_bp != nullptr)
320ac7ddfbfSEd Maste         until_bp->SetEnabled(false);
321ac7ddfbfSEd Maste     }
322ac7ddfbfSEd Maste   }
323ac7ddfbfSEd Maste   return true;
324ac7ddfbfSEd Maste }
325ac7ddfbfSEd Maste 
MischiefManaged()326435933ddSDimitry Andric bool ThreadPlanStepUntil::MischiefManaged() {
327435933ddSDimitry Andric   // I'm letting "PlanExplainsStop" do all the work, and just reporting that
328435933ddSDimitry Andric   // here.
329ac7ddfbfSEd Maste   bool done = false;
330435933ddSDimitry Andric   if (IsPlanComplete()) {
331ac7ddfbfSEd Maste     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
332ac7ddfbfSEd Maste     if (log)
333ac7ddfbfSEd Maste       log->Printf("Completed step until plan.");
334ac7ddfbfSEd Maste 
335ac7ddfbfSEd Maste     Clear();
336ac7ddfbfSEd Maste     done = true;
337ac7ddfbfSEd Maste   }
338ac7ddfbfSEd Maste   if (done)
339ac7ddfbfSEd Maste     ThreadPlan::MischiefManaged();
340ac7ddfbfSEd Maste 
341ac7ddfbfSEd Maste   return done;
342ac7ddfbfSEd Maste }
343