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