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