Mercurial > hg > CbC > CbC_llvm
comparison lldb/source/Target/ThreadPlanStepUntil.cpp @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children | 0572611fdcc8 |
comparison
equal
deleted
inserted
replaced
147:c2174574ed3a | 150:1d019706d866 |
---|---|
1 //===-- ThreadPlanStepUntil.cpp -------------------------------------------===// | |
2 // | |
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
4 // See https://llvm.org/LICENSE.txt for license information. | |
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
6 // | |
7 //===----------------------------------------------------------------------===// | |
8 | |
9 #include "lldb/Target/ThreadPlanStepUntil.h" | |
10 | |
11 #include "lldb/Breakpoint/Breakpoint.h" | |
12 #include "lldb/Symbol/SymbolContextScope.h" | |
13 #include "lldb/Target/Process.h" | |
14 #include "lldb/Target/RegisterContext.h" | |
15 #include "lldb/Target/StopInfo.h" | |
16 #include "lldb/Target/Target.h" | |
17 #include "lldb/Utility/Log.h" | |
18 | |
19 using namespace lldb; | |
20 using namespace lldb_private; | |
21 | |
22 // ThreadPlanStepUntil: Run until we reach a given line number or step out of | |
23 // the current frame | |
24 | |
25 ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, | |
26 lldb::addr_t *address_list, | |
27 size_t num_addresses, bool stop_others, | |
28 uint32_t frame_idx) | |
29 : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread, | |
30 eVoteNoOpinion, eVoteNoOpinion), | |
31 m_step_from_insn(LLDB_INVALID_ADDRESS), | |
32 m_return_bp_id(LLDB_INVALID_BREAK_ID), | |
33 m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false), | |
34 m_should_stop(false), m_ran_analyze(false), m_explains_stop(false), | |
35 m_until_points(), m_stop_others(stop_others) { | |
36 // Stash away our "until" addresses: | |
37 TargetSP target_sp(m_thread.CalculateTarget()); | |
38 | |
39 StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx)); | |
40 if (frame_sp) { | |
41 m_step_from_insn = frame_sp->GetStackID().GetPC(); | |
42 lldb::user_id_t thread_id = m_thread.GetID(); | |
43 | |
44 // Find the return address and set a breakpoint there: | |
45 // FIXME - can we do this more securely if we know first_insn? | |
46 | |
47 StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1)); | |
48 if (return_frame_sp) { | |
49 // TODO: add inline functionality | |
50 m_return_addr = return_frame_sp->GetStackID().GetPC(); | |
51 Breakpoint *return_bp = | |
52 target_sp->CreateBreakpoint(m_return_addr, true, false).get(); | |
53 | |
54 if (return_bp != nullptr) { | |
55 if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) | |
56 m_could_not_resolve_hw_bp = true; | |
57 return_bp->SetThreadID(thread_id); | |
58 m_return_bp_id = return_bp->GetID(); | |
59 return_bp->SetBreakpointKind("until-return-backstop"); | |
60 } | |
61 } | |
62 | |
63 m_stack_id = frame_sp->GetStackID(); | |
64 | |
65 // Now set breakpoints on all our return addresses: | |
66 for (size_t i = 0; i < num_addresses; i++) { | |
67 Breakpoint *until_bp = | |
68 target_sp->CreateBreakpoint(address_list[i], true, false).get(); | |
69 if (until_bp != nullptr) { | |
70 until_bp->SetThreadID(thread_id); | |
71 m_until_points[address_list[i]] = until_bp->GetID(); | |
72 until_bp->SetBreakpointKind("until-target"); | |
73 } else { | |
74 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID; | |
75 } | |
76 } | |
77 } | |
78 } | |
79 | |
80 ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); } | |
81 | |
82 void ThreadPlanStepUntil::Clear() { | |
83 TargetSP target_sp(m_thread.CalculateTarget()); | |
84 if (target_sp) { | |
85 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { | |
86 target_sp->RemoveBreakpointByID(m_return_bp_id); | |
87 m_return_bp_id = LLDB_INVALID_BREAK_ID; | |
88 } | |
89 | |
90 until_collection::iterator pos, end = m_until_points.end(); | |
91 for (pos = m_until_points.begin(); pos != end; pos++) { | |
92 target_sp->RemoveBreakpointByID((*pos).second); | |
93 } | |
94 } | |
95 m_until_points.clear(); | |
96 m_could_not_resolve_hw_bp = false; | |
97 } | |
98 | |
99 void ThreadPlanStepUntil::GetDescription(Stream *s, | |
100 lldb::DescriptionLevel level) { | |
101 if (level == lldb::eDescriptionLevelBrief) { | |
102 s->Printf("step until"); | |
103 if (m_stepped_out) | |
104 s->Printf(" - stepped out"); | |
105 } else { | |
106 if (m_until_points.size() == 1) | |
107 s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64 | |
108 " using breakpoint %d", | |
109 (uint64_t)m_step_from_insn, | |
110 (uint64_t)(*m_until_points.begin()).first, | |
111 (*m_until_points.begin()).second); | |
112 else { | |
113 until_collection::iterator pos, end = m_until_points.end(); | |
114 s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:", | |
115 (uint64_t)m_step_from_insn); | |
116 for (pos = m_until_points.begin(); pos != end; pos++) { | |
117 s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)(*pos).first, | |
118 (*pos).second); | |
119 } | |
120 } | |
121 s->Printf(" stepped out address is 0x%" PRIx64 ".", | |
122 (uint64_t)m_return_addr); | |
123 } | |
124 } | |
125 | |
126 bool ThreadPlanStepUntil::ValidatePlan(Stream *error) { | |
127 if (m_could_not_resolve_hw_bp) { | |
128 if (error) | |
129 error->PutCString( | |
130 "Could not create hardware breakpoint for thread plan."); | |
131 return false; | |
132 } else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) { | |
133 if (error) | |
134 error->PutCString("Could not create return breakpoint."); | |
135 return false; | |
136 } else { | |
137 until_collection::iterator pos, end = m_until_points.end(); | |
138 for (pos = m_until_points.begin(); pos != end; pos++) { | |
139 if (!LLDB_BREAK_ID_IS_VALID((*pos).second)) | |
140 return false; | |
141 } | |
142 return true; | |
143 } | |
144 } | |
145 | |
146 void ThreadPlanStepUntil::AnalyzeStop() { | |
147 if (m_ran_analyze) | |
148 return; | |
149 | |
150 StopInfoSP stop_info_sp = GetPrivateStopInfo(); | |
151 m_should_stop = true; | |
152 m_explains_stop = false; | |
153 | |
154 if (stop_info_sp) { | |
155 StopReason reason = stop_info_sp->GetStopReason(); | |
156 | |
157 if (reason == eStopReasonBreakpoint) { | |
158 // If this is OUR breakpoint, we're fine, otherwise we don't know why | |
159 // this happened... | |
160 BreakpointSiteSP this_site = | |
161 m_thread.GetProcess()->GetBreakpointSiteList().FindByID( | |
162 stop_info_sp->GetValue()); | |
163 if (!this_site) { | |
164 m_explains_stop = false; | |
165 return; | |
166 } | |
167 | |
168 if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) { | |
169 // If we are at our "step out" breakpoint, and the stack depth has | |
170 // shrunk, then this is indeed our stop. If the stack depth has grown, | |
171 // then we've hit our step out breakpoint recursively. If we are the | |
172 // only breakpoint at that location, then we do explain the stop, and | |
173 // we'll just continue. If there was another breakpoint here, then we | |
174 // don't explain the stop, but we won't mark ourselves Completed, | |
175 // because maybe that breakpoint will continue, and then we'll finish | |
176 // the "until". | |
177 bool done; | |
178 StackID cur_frame_zero_id; | |
179 | |
180 done = (m_stack_id < cur_frame_zero_id); | |
181 | |
182 if (done) { | |
183 m_stepped_out = true; | |
184 SetPlanComplete(); | |
185 } else | |
186 m_should_stop = false; | |
187 | |
188 if (this_site->GetNumberOfOwners() == 1) | |
189 m_explains_stop = true; | |
190 else | |
191 m_explains_stop = false; | |
192 return; | |
193 } else { | |
194 // Check if we've hit one of our "until" breakpoints. | |
195 until_collection::iterator pos, end = m_until_points.end(); | |
196 for (pos = m_until_points.begin(); pos != end; pos++) { | |
197 if (this_site->IsBreakpointAtThisSite((*pos).second)) { | |
198 // If we're at the right stack depth, then we're done. | |
199 | |
200 bool done; | |
201 StackID frame_zero_id = | |
202 m_thread.GetStackFrameAtIndex(0)->GetStackID(); | |
203 | |
204 if (frame_zero_id == m_stack_id) | |
205 done = true; | |
206 else if (frame_zero_id < m_stack_id) | |
207 done = false; | |
208 else { | |
209 StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1); | |
210 | |
211 // But if we can't even unwind one frame we should just get out | |
212 // of here & stop... | |
213 if (older_frame_sp) { | |
214 const SymbolContext &older_context = | |
215 older_frame_sp->GetSymbolContext(eSymbolContextEverything); | |
216 SymbolContext stack_context; | |
217 m_stack_id.GetSymbolContextScope()->CalculateSymbolContext( | |
218 &stack_context); | |
219 | |
220 done = (older_context == stack_context); | |
221 } else | |
222 done = false; | |
223 } | |
224 | |
225 if (done) | |
226 SetPlanComplete(); | |
227 else | |
228 m_should_stop = false; | |
229 | |
230 // Otherwise we've hit this breakpoint recursively. If we're the | |
231 // only breakpoint here, then we do explain the stop, and we'll | |
232 // continue. If not then we should let higher plans handle this | |
233 // stop. | |
234 if (this_site->GetNumberOfOwners() == 1) | |
235 m_explains_stop = true; | |
236 else { | |
237 m_should_stop = true; | |
238 m_explains_stop = false; | |
239 } | |
240 return; | |
241 } | |
242 } | |
243 } | |
244 // If we get here we haven't hit any of our breakpoints, so let the | |
245 // higher plans take care of the stop. | |
246 m_explains_stop = false; | |
247 return; | |
248 } else if (IsUsuallyUnexplainedStopReason(reason)) { | |
249 m_explains_stop = false; | |
250 } else { | |
251 m_explains_stop = true; | |
252 } | |
253 } | |
254 } | |
255 | |
256 bool ThreadPlanStepUntil::DoPlanExplainsStop(Event *event_ptr) { | |
257 // We don't explain signals or breakpoints (breakpoints that handle stepping | |
258 // in or 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 do | |
265 // so here. Otherwise, as long as this thread has stopped for a reason, we | |
266 // 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 LLDB_LOGF(log, "Completed step until plan."); | |
330 | |
331 Clear(); | |
332 done = true; | |
333 } | |
334 if (done) | |
335 ThreadPlan::MischiefManaged(); | |
336 | |
337 return done; | |
338 } |