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