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