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