1cfca06d7SDimitry Andric //===-- ThreadPlanStepUntil.cpp -------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9e81d9d49SDimitry Andric #include "lldb/Target/ThreadPlanStepUntil.h"
1074a628f7SDimitry Andric
11f034231aSEd Maste #include "lldb/Breakpoint/Breakpoint.h"
1274a628f7SDimitry Andric #include "lldb/Symbol/SymbolContextScope.h"
13f034231aSEd Maste #include "lldb/Target/Process.h"
14f034231aSEd Maste #include "lldb/Target/RegisterContext.h"
15f034231aSEd Maste #include "lldb/Target/StopInfo.h"
16f034231aSEd Maste #include "lldb/Target/Target.h"
17145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
1874a628f7SDimitry Andric #include "lldb/Utility/Log.h"
19f034231aSEd Maste
20f034231aSEd Maste using namespace lldb;
21f034231aSEd Maste using namespace lldb_private;
22f034231aSEd Maste
2314f1b3e8SDimitry Andric // ThreadPlanStepUntil: Run until we reach a given line number or step out of
2414f1b3e8SDimitry Andric // the current frame
25f034231aSEd Maste
ThreadPlanStepUntil(Thread & thread,lldb::addr_t * address_list,size_t num_addresses,bool stop_others,uint32_t frame_idx)2614f1b3e8SDimitry Andric ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
27f034231aSEd Maste lldb::addr_t *address_list,
2814f1b3e8SDimitry Andric size_t num_addresses, bool stop_others,
2914f1b3e8SDimitry Andric uint32_t frame_idx)
3014f1b3e8SDimitry Andric : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread,
3114f1b3e8SDimitry Andric eVoteNoOpinion, eVoteNoOpinion),
32f034231aSEd Maste m_step_from_insn(LLDB_INVALID_ADDRESS),
33f034231aSEd Maste m_return_bp_id(LLDB_INVALID_BREAK_ID),
3414f1b3e8SDimitry Andric m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false),
3514f1b3e8SDimitry Andric m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
3614f1b3e8SDimitry Andric m_until_points(), m_stop_others(stop_others) {
37f034231aSEd Maste // Stash away our "until" addresses:
38cfca06d7SDimitry Andric TargetSP target_sp(thread.CalculateTarget());
39f034231aSEd Maste
40cfca06d7SDimitry Andric StackFrameSP frame_sp(thread.GetStackFrameAtIndex(frame_idx));
4114f1b3e8SDimitry Andric if (frame_sp) {
42f034231aSEd Maste m_step_from_insn = frame_sp->GetStackID().GetPC();
43f034231aSEd Maste
44f034231aSEd Maste // Find the return address and set a breakpoint there:
45f034231aSEd Maste // FIXME - can we do this more securely if we know first_insn?
46f034231aSEd Maste
47cfca06d7SDimitry Andric StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(frame_idx + 1));
4814f1b3e8SDimitry Andric if (return_frame_sp) {
49f034231aSEd Maste // TODO: add inline functionality
50f034231aSEd Maste m_return_addr = return_frame_sp->GetStackID().GetPC();
5114f1b3e8SDimitry Andric Breakpoint *return_bp =
5214f1b3e8SDimitry Andric target_sp->CreateBreakpoint(m_return_addr, true, false).get();
5394994d37SDimitry Andric
5414f1b3e8SDimitry Andric if (return_bp != nullptr) {
5594994d37SDimitry Andric if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
5694994d37SDimitry Andric m_could_not_resolve_hw_bp = true;
57cfca06d7SDimitry Andric return_bp->SetThreadID(m_tid);
58f034231aSEd Maste m_return_bp_id = return_bp->GetID();
59f034231aSEd Maste return_bp->SetBreakpointKind("until-return-backstop");
60f034231aSEd Maste }
61f034231aSEd Maste }
62f034231aSEd Maste
630cac4ca3SEd Maste m_stack_id = frame_sp->GetStackID();
64f034231aSEd Maste
65f034231aSEd Maste // Now set breakpoints on all our return addresses:
6614f1b3e8SDimitry Andric for (size_t i = 0; i < num_addresses; i++) {
6714f1b3e8SDimitry Andric Breakpoint *until_bp =
6814f1b3e8SDimitry Andric target_sp->CreateBreakpoint(address_list[i], true, false).get();
6914f1b3e8SDimitry Andric if (until_bp != nullptr) {
70cfca06d7SDimitry Andric until_bp->SetThreadID(m_tid);
71f034231aSEd Maste m_until_points[address_list[i]] = until_bp->GetID();
72f034231aSEd Maste until_bp->SetBreakpointKind("until-target");
7314f1b3e8SDimitry Andric } else {
74f034231aSEd Maste m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
75f034231aSEd Maste }
76f034231aSEd Maste }
77f034231aSEd Maste }
78f034231aSEd Maste }
79f034231aSEd Maste
~ThreadPlanStepUntil()8014f1b3e8SDimitry Andric ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); }
81f034231aSEd Maste
Clear()8214f1b3e8SDimitry Andric void ThreadPlanStepUntil::Clear() {
83cfca06d7SDimitry Andric Target &target = GetTarget();
8414f1b3e8SDimitry Andric if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
85cfca06d7SDimitry Andric target.RemoveBreakpointByID(m_return_bp_id);
86f034231aSEd Maste m_return_bp_id = LLDB_INVALID_BREAK_ID;
87f034231aSEd Maste }
88f034231aSEd Maste
89f034231aSEd Maste until_collection::iterator pos, end = m_until_points.end();
9014f1b3e8SDimitry Andric for (pos = m_until_points.begin(); pos != end; pos++) {
91cfca06d7SDimitry Andric target.RemoveBreakpointByID((*pos).second);
92f034231aSEd Maste }
93f034231aSEd Maste m_until_points.clear();
9494994d37SDimitry Andric m_could_not_resolve_hw_bp = false;
95f034231aSEd Maste }
96f034231aSEd Maste
GetDescription(Stream * s,lldb::DescriptionLevel level)9714f1b3e8SDimitry Andric void ThreadPlanStepUntil::GetDescription(Stream *s,
9814f1b3e8SDimitry Andric lldb::DescriptionLevel level) {
9914f1b3e8SDimitry Andric if (level == lldb::eDescriptionLevelBrief) {
100f034231aSEd Maste s->Printf("step until");
101f034231aSEd Maste if (m_stepped_out)
102f034231aSEd Maste s->Printf(" - stepped out");
10314f1b3e8SDimitry Andric } else {
104f034231aSEd Maste if (m_until_points.size() == 1)
10514f1b3e8SDimitry Andric s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64
10614f1b3e8SDimitry Andric " using breakpoint %d",
107f034231aSEd Maste (uint64_t)m_step_from_insn,
108f034231aSEd Maste (uint64_t)(*m_until_points.begin()).first,
109f034231aSEd Maste (*m_until_points.begin()).second);
11014f1b3e8SDimitry Andric else {
111f034231aSEd Maste until_collection::iterator pos, end = m_until_points.end();
112f034231aSEd Maste s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:",
113f034231aSEd Maste (uint64_t)m_step_from_insn);
11414f1b3e8SDimitry Andric for (pos = m_until_points.begin(); pos != end; pos++) {
11514f1b3e8SDimitry Andric s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)(*pos).first,
11614f1b3e8SDimitry Andric (*pos).second);
117f034231aSEd Maste }
118f034231aSEd Maste }
11914f1b3e8SDimitry Andric s->Printf(" stepped out address is 0x%" PRIx64 ".",
12014f1b3e8SDimitry Andric (uint64_t)m_return_addr);
121f034231aSEd Maste }
122f034231aSEd Maste }
123f034231aSEd Maste
ValidatePlan(Stream * error)12414f1b3e8SDimitry Andric bool ThreadPlanStepUntil::ValidatePlan(Stream *error) {
12594994d37SDimitry Andric if (m_could_not_resolve_hw_bp) {
12694994d37SDimitry Andric if (error)
12794994d37SDimitry Andric error->PutCString(
12894994d37SDimitry Andric "Could not create hardware breakpoint for thread plan.");
129f034231aSEd Maste return false;
13094994d37SDimitry Andric } else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
13194994d37SDimitry Andric if (error)
13294994d37SDimitry Andric error->PutCString("Could not create return breakpoint.");
13394994d37SDimitry Andric return false;
13494994d37SDimitry Andric } else {
135f034231aSEd Maste until_collection::iterator pos, end = m_until_points.end();
13614f1b3e8SDimitry Andric for (pos = m_until_points.begin(); pos != end; pos++) {
137f034231aSEd Maste if (!LLDB_BREAK_ID_IS_VALID((*pos).second))
138f034231aSEd Maste return false;
139f034231aSEd Maste }
140f034231aSEd Maste return true;
141f034231aSEd Maste }
142f034231aSEd Maste }
143f034231aSEd Maste
AnalyzeStop()14414f1b3e8SDimitry Andric void ThreadPlanStepUntil::AnalyzeStop() {
145f034231aSEd Maste if (m_ran_analyze)
146f034231aSEd Maste return;
147f034231aSEd Maste
148f034231aSEd Maste StopInfoSP stop_info_sp = GetPrivateStopInfo();
149f034231aSEd Maste m_should_stop = true;
150f034231aSEd Maste m_explains_stop = false;
151f034231aSEd Maste
15214f1b3e8SDimitry Andric if (stop_info_sp) {
153f034231aSEd Maste StopReason reason = stop_info_sp->GetStopReason();
154f034231aSEd Maste
15514f1b3e8SDimitry Andric if (reason == eStopReasonBreakpoint) {
156f73363f1SDimitry Andric // If this is OUR breakpoint, we're fine, otherwise we don't know why
157f73363f1SDimitry Andric // this happened...
15814f1b3e8SDimitry Andric BreakpointSiteSP this_site =
159cfca06d7SDimitry Andric m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue());
16014f1b3e8SDimitry Andric if (!this_site) {
161f034231aSEd Maste m_explains_stop = false;
162f034231aSEd Maste return;
163f034231aSEd Maste }
164f034231aSEd Maste
16514f1b3e8SDimitry Andric if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) {
16614f1b3e8SDimitry Andric // If we are at our "step out" breakpoint, and the stack depth has
167f73363f1SDimitry Andric // shrunk, then this is indeed our stop. If the stack depth has grown,
168f73363f1SDimitry Andric // then we've hit our step out breakpoint recursively. If we are the
169f73363f1SDimitry Andric // only breakpoint at that location, then we do explain the stop, and
170f73363f1SDimitry Andric // we'll just continue. If there was another breakpoint here, then we
171f73363f1SDimitry Andric // don't explain the stop, but we won't mark ourselves Completed,
172f73363f1SDimitry Andric // because maybe that breakpoint will continue, and then we'll finish
173f73363f1SDimitry Andric // the "until".
174f034231aSEd Maste bool done;
175f034231aSEd Maste StackID cur_frame_zero_id;
176f034231aSEd Maste
177e81d9d49SDimitry Andric done = (m_stack_id < cur_frame_zero_id);
178f034231aSEd Maste
17914f1b3e8SDimitry Andric if (done) {
180f034231aSEd Maste m_stepped_out = true;
181f034231aSEd Maste SetPlanComplete();
18214f1b3e8SDimitry Andric } else
183f034231aSEd Maste m_should_stop = false;
184f034231aSEd Maste
185b1c73532SDimitry Andric if (this_site->GetNumberOfConstituents() == 1)
186f034231aSEd Maste m_explains_stop = true;
187f034231aSEd Maste else
188f034231aSEd Maste m_explains_stop = false;
189f034231aSEd Maste return;
19014f1b3e8SDimitry Andric } else {
191f034231aSEd Maste // Check if we've hit one of our "until" breakpoints.
192f034231aSEd Maste until_collection::iterator pos, end = m_until_points.end();
19314f1b3e8SDimitry Andric for (pos = m_until_points.begin(); pos != end; pos++) {
19414f1b3e8SDimitry Andric if (this_site->IsBreakpointAtThisSite((*pos).second)) {
195f034231aSEd Maste // If we're at the right stack depth, then we're done.
196cfca06d7SDimitry Andric Thread &thread = GetThread();
197f034231aSEd Maste bool done;
19814f1b3e8SDimitry Andric StackID frame_zero_id =
199cfca06d7SDimitry Andric thread.GetStackFrameAtIndex(0)->GetStackID();
200f034231aSEd Maste
201f034231aSEd Maste if (frame_zero_id == m_stack_id)
202f034231aSEd Maste done = true;
203f034231aSEd Maste else if (frame_zero_id < m_stack_id)
204f034231aSEd Maste done = false;
20514f1b3e8SDimitry Andric else {
206cfca06d7SDimitry Andric StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(1);
207f034231aSEd Maste
208f73363f1SDimitry Andric // But if we can't even unwind one frame we should just get out
209f73363f1SDimitry Andric // of here & stop...
21014f1b3e8SDimitry Andric if (older_frame_sp) {
21114f1b3e8SDimitry Andric const SymbolContext &older_context =
21214f1b3e8SDimitry Andric older_frame_sp->GetSymbolContext(eSymbolContextEverything);
213f034231aSEd Maste SymbolContext stack_context;
21414f1b3e8SDimitry Andric m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(
21514f1b3e8SDimitry Andric &stack_context);
216f034231aSEd Maste
217e81d9d49SDimitry Andric done = (older_context == stack_context);
21814f1b3e8SDimitry Andric } else
219f034231aSEd Maste done = false;
220f034231aSEd Maste }
221f034231aSEd Maste
222f034231aSEd Maste if (done)
223f034231aSEd Maste SetPlanComplete();
224f034231aSEd Maste else
225f034231aSEd Maste m_should_stop = false;
226f034231aSEd Maste
227f034231aSEd Maste // Otherwise we've hit this breakpoint recursively. If we're the
22814f1b3e8SDimitry Andric // only breakpoint here, then we do explain the stop, and we'll
229f73363f1SDimitry Andric // continue. If not then we should let higher plans handle this
230f73363f1SDimitry Andric // stop.
231b1c73532SDimitry Andric if (this_site->GetNumberOfConstituents() == 1)
232f034231aSEd Maste m_explains_stop = true;
23314f1b3e8SDimitry Andric else {
234f034231aSEd Maste m_should_stop = true;
235f034231aSEd Maste m_explains_stop = false;
236f034231aSEd Maste }
237f034231aSEd Maste return;
238f034231aSEd Maste }
239f034231aSEd Maste }
240f034231aSEd Maste }
241f73363f1SDimitry Andric // If we get here we haven't hit any of our breakpoints, so let the
242f73363f1SDimitry Andric // higher plans take care of the stop.
243f034231aSEd Maste m_explains_stop = false;
244f034231aSEd Maste return;
24514f1b3e8SDimitry Andric } else if (IsUsuallyUnexplainedStopReason(reason)) {
246f034231aSEd Maste m_explains_stop = false;
24714f1b3e8SDimitry Andric } else {
248f034231aSEd Maste m_explains_stop = true;
249f034231aSEd Maste }
250f034231aSEd Maste }
251f034231aSEd Maste }
252f034231aSEd Maste
DoPlanExplainsStop(Event * event_ptr)25314f1b3e8SDimitry Andric bool ThreadPlanStepUntil::DoPlanExplainsStop(Event *event_ptr) {
25414f1b3e8SDimitry Andric // We don't explain signals or breakpoints (breakpoints that handle stepping
255f73363f1SDimitry Andric // in or out will be handled by a child plan.
256f034231aSEd Maste AnalyzeStop();
257f034231aSEd Maste return m_explains_stop;
258f034231aSEd Maste }
259f034231aSEd Maste
ShouldStop(Event * event_ptr)26014f1b3e8SDimitry Andric bool ThreadPlanStepUntil::ShouldStop(Event *event_ptr) {
261f73363f1SDimitry Andric // If we've told our self in ExplainsStop that we plan to continue, then do
262f73363f1SDimitry Andric // so here. Otherwise, as long as this thread has stopped for a reason, we
263f73363f1SDimitry Andric // will stop.
264f034231aSEd Maste
265f034231aSEd Maste StopInfoSP stop_info_sp = GetPrivateStopInfo();
266f034231aSEd Maste if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
267f034231aSEd Maste return false;
268f034231aSEd Maste
269f034231aSEd Maste AnalyzeStop();
270f034231aSEd Maste return m_should_stop;
271f034231aSEd Maste }
272f034231aSEd Maste
StopOthers()27314f1b3e8SDimitry Andric bool ThreadPlanStepUntil::StopOthers() { return m_stop_others; }
274f034231aSEd Maste
GetPlanRunState()27514f1b3e8SDimitry Andric StateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; }
276f034231aSEd Maste
DoWillResume(StateType resume_state,bool current_plan)27714f1b3e8SDimitry Andric bool ThreadPlanStepUntil::DoWillResume(StateType resume_state,
27814f1b3e8SDimitry Andric bool current_plan) {
27914f1b3e8SDimitry Andric if (current_plan) {
280cfca06d7SDimitry Andric Target &target = GetTarget();
281cfca06d7SDimitry Andric Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
282e81d9d49SDimitry Andric if (return_bp != nullptr)
283f034231aSEd Maste return_bp->SetEnabled(true);
284f034231aSEd Maste
285f034231aSEd Maste until_collection::iterator pos, end = m_until_points.end();
28614f1b3e8SDimitry Andric for (pos = m_until_points.begin(); pos != end; pos++) {
287cfca06d7SDimitry Andric Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
288e81d9d49SDimitry Andric if (until_bp != nullptr)
289f034231aSEd Maste until_bp->SetEnabled(true);
290f034231aSEd Maste }
291f034231aSEd Maste }
292f034231aSEd Maste
293f034231aSEd Maste m_should_stop = true;
294f034231aSEd Maste m_ran_analyze = false;
295f034231aSEd Maste m_explains_stop = false;
296f034231aSEd Maste return true;
297f034231aSEd Maste }
298f034231aSEd Maste
WillStop()29914f1b3e8SDimitry Andric bool ThreadPlanStepUntil::WillStop() {
300cfca06d7SDimitry Andric Target &target = GetTarget();
301cfca06d7SDimitry Andric Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
302e81d9d49SDimitry Andric if (return_bp != nullptr)
303f034231aSEd Maste return_bp->SetEnabled(false);
304f034231aSEd Maste
305f034231aSEd Maste until_collection::iterator pos, end = m_until_points.end();
30614f1b3e8SDimitry Andric for (pos = m_until_points.begin(); pos != end; pos++) {
307cfca06d7SDimitry Andric Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
308e81d9d49SDimitry Andric if (until_bp != nullptr)
309f034231aSEd Maste until_bp->SetEnabled(false);
310f034231aSEd Maste }
311f034231aSEd Maste return true;
312f034231aSEd Maste }
313f034231aSEd Maste
MischiefManaged()31414f1b3e8SDimitry Andric bool ThreadPlanStepUntil::MischiefManaged() {
31514f1b3e8SDimitry Andric // I'm letting "PlanExplainsStop" do all the work, and just reporting that
31614f1b3e8SDimitry Andric // here.
317f034231aSEd Maste bool done = false;
31814f1b3e8SDimitry Andric if (IsPlanComplete()) {
319145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Step);
320ead24645SDimitry Andric LLDB_LOGF(log, "Completed step until plan.");
321f034231aSEd Maste
322f034231aSEd Maste Clear();
323f034231aSEd Maste done = true;
324f034231aSEd Maste }
325f034231aSEd Maste if (done)
326f034231aSEd Maste ThreadPlan::MischiefManaged();
327f034231aSEd Maste
328f034231aSEd Maste return done;
329f034231aSEd Maste }
330