blob: c039a32f5515215c75064464a9c72d04c7bd6875 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- ThreadPlanStepThrough.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
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Eugene Zelenkoe65b2cf2015-12-15 01:33:19 +000014#include "lldb/Target/ThreadPlanStepThrough.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000015#include "lldb/Breakpoint/Breakpoint.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000016#include "lldb/Target/DynamicLoader.h"
Jim Ingham5a369122010-09-28 01:25:32 +000017#include "lldb/Target/ObjCLanguageRuntime.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000018#include "lldb/Target/Process.h"
19#include "lldb/Target/RegisterContext.h"
Jim Ingham25f66702011-12-03 01:52:59 +000020#include "lldb/Target/Target.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000021#include "lldb/Utility/Log.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000022#include "lldb/Utility/Stream.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000023
24using namespace lldb;
25using namespace lldb_private;
26
27//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000028// ThreadPlanStepThrough: If the current instruction is a trampoline, step
Adrian Prantl05097242018-04-30 16:49:04 +000029// through it If it is the beginning of the prologue of a function, step
30// through that as well.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000031// FIXME: At present only handles DYLD trampolines.
32//----------------------------------------------------------------------
33
Kate Stoneb9c1b512016-09-06 20:57:50 +000034ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread,
35 StackID &m_stack_id,
36 bool stop_others)
37 : ThreadPlan(ThreadPlan::eKindStepThrough,
38 "Step through trampolines and prologues", thread,
39 eVoteNoOpinion, eVoteNoOpinion),
40 m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID),
41 m_backstop_addr(LLDB_INVALID_ADDRESS), m_return_stack_id(m_stack_id),
42 m_stop_others(stop_others) {
43 LookForPlanToStepThroughFromCurrentPC();
44
45 // If we don't get a valid step through plan, don't bother to set up a
46 // backstop.
47 if (m_sub_plan_sp) {
48 m_start_address = GetThread().GetRegisterContext()->GetPC(0);
49
50 // We are going to return back to the concrete frame 1, we might pass by
Adrian Prantl05097242018-04-30 16:49:04 +000051 // some inlined code that we're in the middle of by doing this, but it's
52 // easier than trying to figure out where the inlined code might return to.
Kate Stoneb9c1b512016-09-06 20:57:50 +000053
54 StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID(m_stack_id);
55
56 if (return_frame_sp) {
57 m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(
58 m_thread.CalculateTarget().get());
59 Breakpoint *return_bp =
60 m_thread.GetProcess()
61 ->GetTarget()
62 .CreateBreakpoint(m_backstop_addr, true, false)
63 .get();
64 if (return_bp != nullptr) {
65 return_bp->SetThreadID(m_thread.GetID());
66 m_backstop_bkpt_id = return_bp->GetID();
67 return_bp->SetBreakpointKind("step-through-backstop");
68 }
69 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
70 if (log) {
71 log->Printf("Setting backstop breakpoint %d at address: 0x%" PRIx64,
72 m_backstop_bkpt_id, m_backstop_addr);
73 }
Jim Ingham25f66702011-12-03 01:52:59 +000074 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000075 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076}
77
Kate Stoneb9c1b512016-09-06 20:57:50 +000078ThreadPlanStepThrough::~ThreadPlanStepThrough() { ClearBackstopBreakpoint(); }
79
80void ThreadPlanStepThrough::DidPush() {
81 if (m_sub_plan_sp)
82 PushPlan(m_sub_plan_sp);
Jim Ingham25f66702011-12-03 01:52:59 +000083}
84
Kate Stoneb9c1b512016-09-06 20:57:50 +000085void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() {
86 DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader();
87 if (loader)
88 m_sub_plan_sp =
89 loader->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
Jim Ingham25f66702011-12-03 01:52:59 +000090
Kate Stoneb9c1b512016-09-06 20:57:50 +000091 // If that didn't come up with anything, try the ObjC runtime plugin:
92 if (!m_sub_plan_sp.get()) {
93 ObjCLanguageRuntime *objc_runtime =
94 m_thread.GetProcess()->GetObjCLanguageRuntime();
95 if (objc_runtime)
96 m_sub_plan_sp =
97 objc_runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
98 }
99
100 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
101 if (log) {
102 lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0);
103 if (m_sub_plan_sp) {
104 StreamString s;
105 m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
106 log->Printf("Found step through plan from 0x%" PRIx64 ": %s",
107 current_address, s.GetData());
108 } else {
109 log->Printf("Couldn't find step through plan from address 0x%" PRIx64 ".",
110 current_address);
Jim Ingham25f66702011-12-03 01:52:59 +0000111 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000113}
114
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115void ThreadPlanStepThrough::GetDescription(Stream *s,
116 lldb::DescriptionLevel level) {
117 if (level == lldb::eDescriptionLevelBrief)
118 s->Printf("Step through");
119 else {
120 s->PutCString("Stepping through trampoline code from: ");
121 s->Address(m_start_address, sizeof(addr_t));
122 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {
123 s->Printf(" with backstop breakpoint ID: %d at address: ",
124 m_backstop_bkpt_id);
125 s->Address(m_backstop_addr, sizeof(addr_t));
126 } else
127 s->PutCString(" unable to set a backstop breakpoint.");
128 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000129}
130
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131bool ThreadPlanStepThrough::ValidatePlan(Stream *error) {
132 return m_sub_plan_sp.get() != nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000133}
134
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135bool ThreadPlanStepThrough::DoPlanExplainsStop(Event *event_ptr) {
136 // If we have a sub-plan, it will have been asked first if we explain the
Adrian Prantl05097242018-04-30 16:49:04 +0000137 // stop, and we won't get asked. The only time we would be the one directly
138 // asked this question is if we hit our backstop breakpoint.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139
140 return HitOurBackstopBreakpoint();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000141}
142
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143bool ThreadPlanStepThrough::ShouldStop(Event *event_ptr) {
144 // If we've already marked ourselves done, then we're done...
145 if (IsPlanComplete())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000146 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000147
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 // First, did we hit the backstop breakpoint?
149 if (HitOurBackstopBreakpoint()) {
150 SetPlanComplete(true);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000151 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 // If we don't have a sub-plan, then we're also done (can't see how we would
Adrian Prantl05097242018-04-30 16:49:04 +0000155 // ever get here without a plan, but just in case.
Jim Ingham18de2fd2012-05-10 01:35:39 +0000156
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157 if (!m_sub_plan_sp) {
158 SetPlanComplete();
159 return true;
160 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000161
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 // If the current sub plan is not done, we don't want to stop. Actually, we
Adrian Prantl05097242018-04-30 16:49:04 +0000163 // probably won't ever get here in this state, since we generally won't get
164 // asked any questions if out current sub-plan is not done...
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165 if (!m_sub_plan_sp->IsPlanComplete())
Jim Ingham25f66702011-12-03 01:52:59 +0000166 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167
Adrian Prantl05097242018-04-30 16:49:04 +0000168 // If our current sub plan failed, then let's just run to our backstop. If
169 // we can't do that then just stop.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 if (!m_sub_plan_sp->PlanSucceeded()) {
171 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {
172 m_sub_plan_sp.reset();
173 return false;
174 } else {
175 SetPlanComplete(false);
176 return true;
177 }
178 }
179
180 // Next see if there is a specific step through plan at our current pc (these
Adrian Prantl05097242018-04-30 16:49:04 +0000181 // might chain, for instance stepping through a dylib trampoline to the objc
Kate Stoneb9c1b512016-09-06 20:57:50 +0000182 // dispatch function...)
183 LookForPlanToStepThroughFromCurrentPC();
184 if (m_sub_plan_sp) {
185 PushPlan(m_sub_plan_sp);
186 return false;
187 } else {
188 SetPlanComplete();
189 return true;
190 }
191}
192
193bool ThreadPlanStepThrough::StopOthers() { return m_stop_others; }
194
195StateType ThreadPlanStepThrough::GetPlanRunState() { return eStateRunning; }
196
197bool ThreadPlanStepThrough::DoWillResume(StateType resume_state,
198 bool current_plan) {
199 return true;
200}
201
202bool ThreadPlanStepThrough::WillStop() { return true; }
203
204void ThreadPlanStepThrough::ClearBackstopBreakpoint() {
205 if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {
206 m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id);
207 m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
208 }
209}
210
211bool ThreadPlanStepThrough::MischiefManaged() {
212 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
213
214 if (!IsPlanComplete()) {
215 return false;
216 } else {
217 if (log)
218 log->Printf("Completed step through step plan.");
219
220 ClearBackstopBreakpoint();
221 ThreadPlan::MischiefManaged();
222 return true;
223 }
224}
225
226bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() {
227 StopInfoSP stop_info_sp(m_thread.GetStopInfo());
228 if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) {
229 break_id_t stop_value = (break_id_t)stop_info_sp->GetValue();
230 BreakpointSiteSP cur_site_sp =
231 m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value);
232 if (cur_site_sp &&
233 cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) {
234 StackID cur_frame_zero_id =
235 m_thread.GetStackFrameAtIndex(0)->GetStackID();
236
237 if (cur_frame_zero_id == m_return_stack_id) {
238 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
239 if (log)
240 log->PutCString("ThreadPlanStepThrough hit backstop breakpoint.");
241 return true;
242 }
243 }
244 }
245 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000246}