ThreadPlanStepUntil.cpp revision 353358
155714Skris//===-- ThreadPlanStepUntil.cpp ---------------------------------*- C++ -*-===//
255714Skris//
355714Skris// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
455714Skris// See https://llvm.org/LICENSE.txt for license information.
555714Skris// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
655714Skris//
755714Skris//===----------------------------------------------------------------------===//
855714Skris
955714Skris#include "lldb/Target/ThreadPlanStepUntil.h"
1055714Skris
1155714Skris#include "lldb/Breakpoint/Breakpoint.h"
1255714Skris#include "lldb/Symbol/SymbolContextScope.h"
1355714Skris#include "lldb/Target/Process.h"
1455714Skris#include "lldb/Target/RegisterContext.h"
1555714Skris#include "lldb/Target/StopInfo.h"
1655714Skris#include "lldb/Target/Target.h"
1755714Skris#include "lldb/Utility/Log.h"
1855714Skris
1955714Skrisusing namespace lldb;
2055714Skrisusing namespace lldb_private;
2155714Skris
2255714Skris// ThreadPlanStepUntil: Run until we reach a given line number or step out of
2355714Skris// the current frame
2455714Skris
2555714SkrisThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread,
2655714Skris                                         lldb::addr_t *address_list,
2755714Skris                                         size_t num_addresses, bool stop_others,
2855714Skris                                         uint32_t frame_idx)
2955714Skris    : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread,
3055714Skris                 eVoteNoOpinion, eVoteNoOpinion),
3155714Skris      m_step_from_insn(LLDB_INVALID_ADDRESS),
3255714Skris      m_return_bp_id(LLDB_INVALID_BREAK_ID),
3355714Skris      m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false),
3455714Skris      m_should_stop(false), m_ran_analyze(false), m_explains_stop(false),
3555714Skris      m_until_points(), m_stop_others(stop_others) {
3655714Skris  // Stash away our "until" addresses:
3755714Skris  TargetSP target_sp(m_thread.CalculateTarget());
3855714Skris
3955714Skris  StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx));
4055714Skris  if (frame_sp) {
4155714Skris    m_step_from_insn = frame_sp->GetStackID().GetPC();
4255714Skris    lldb::user_id_t thread_id = m_thread.GetID();
4355714Skris
4455714Skris    // Find the return address and set a breakpoint there:
4555714Skris    // FIXME - can we do this more securely if we know first_insn?
4655714Skris
4755714Skris    StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1));
4855714Skris    if (return_frame_sp) {
4955714Skris      // TODO: add inline functionality
5055714Skris      m_return_addr = return_frame_sp->GetStackID().GetPC();
5155714Skris      Breakpoint *return_bp =
5255714Skris          target_sp->CreateBreakpoint(m_return_addr, true, false).get();
5355714Skris
5455714Skris      if (return_bp != nullptr) {
5555714Skris        if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())
5655714Skris          m_could_not_resolve_hw_bp = true;
5755714Skris        return_bp->SetThreadID(thread_id);
5855714Skris        m_return_bp_id = return_bp->GetID();
5955714Skris        return_bp->SetBreakpointKind("until-return-backstop");
6055714Skris      }
6155714Skris    }
6255714Skris
6355714Skris    m_stack_id = frame_sp->GetStackID();
6455714Skris
6555714Skris    // Now set breakpoints on all our return addresses:
6659191Skris    for (size_t i = 0; i < num_addresses; i++) {
6755714Skris      Breakpoint *until_bp =
6855714Skris          target_sp->CreateBreakpoint(address_list[i], true, false).get();
6955714Skris      if (until_bp != nullptr) {
7055714Skris        until_bp->SetThreadID(thread_id);
7155714Skris        m_until_points[address_list[i]] = until_bp->GetID();
7255714Skris        until_bp->SetBreakpointKind("until-target");
73238405Sjkim      } else {
74238405Sjkim        m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
75238405Sjkim      }
76109998Smarkm    }
7755714Skris  }
7859191Skris}
7959191Skris
8055714SkrisThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); }
8155714Skris
82109998Smarkmvoid ThreadPlanStepUntil::Clear() {
83160814Ssimon  TargetSP target_sp(m_thread.CalculateTarget());
8455714Skris  if (target_sp) {
85238405Sjkim    if (m_return_bp_id != LLDB_INVALID_BREAK_ID) {
8668651Skris      target_sp->RemoveBreakpointByID(m_return_bp_id);
87238405Sjkim      m_return_bp_id = LLDB_INVALID_BREAK_ID;
8855714Skris    }
8955714Skris
90160814Ssimon    until_collection::iterator pos, end = m_until_points.end();
91111147Snectar    for (pos = m_until_points.begin(); pos != end; pos++) {
92109998Smarkm      target_sp->RemoveBreakpointByID((*pos).second);
93111147Snectar    }
9455714Skris  }
9555714Skris  m_until_points.clear();
9655714Skris  m_could_not_resolve_hw_bp = false;
97238405Sjkim}
9855714Skris
9955714Skrisvoid ThreadPlanStepUntil::GetDescription(Stream *s,
10055714Skris                                         lldb::DescriptionLevel level) {
10155714Skris  if (level == lldb::eDescriptionLevelBrief) {
10255714Skris    s->Printf("step until");
10355714Skris    if (m_stepped_out)
10455714Skris      s->Printf(" - stepped out");
10555714Skris  } else {
10655714Skris    if (m_until_points.size() == 1)
107109998Smarkm      s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64
108109998Smarkm                " using breakpoint %d",
109109998Smarkm                (uint64_t)m_step_from_insn,
11055714Skris                (uint64_t)(*m_until_points.begin()).first,
11155714Skris                (*m_until_points.begin()).second);
11255714Skris    else {
11355714Skris      until_collection::iterator pos, end = m_until_points.end();
11455714Skris      s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:",
11555714Skris                (uint64_t)m_step_from_insn);
11655714Skris      for (pos = m_until_points.begin(); pos != end; pos++) {
11755714Skris        s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)(*pos).first,
11855714Skris                  (*pos).second);
11955714Skris      }
12055714Skris    }
12155714Skris    s->Printf(" stepped out address is 0x%" PRIx64 ".",
12255714Skris              (uint64_t)m_return_addr);
12355714Skris  }
12455714Skris}
12555714Skris
126160814Ssimonbool ThreadPlanStepUntil::ValidatePlan(Stream *error) {
127160814Ssimon  if (m_could_not_resolve_hw_bp) {
12859191Skris    if (error)
129160814Ssimon      error->PutCString(
13059191Skris          "Could not create hardware breakpoint for thread plan.");
131160814Ssimon    return false;
13259191Skris  } else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) {
13359191Skris    if (error)
13459191Skris      error->PutCString("Could not create return breakpoint.");
13559191Skris    return false;
13659191Skris  } else {
13759191Skris    until_collection::iterator pos, end = m_until_points.end();
13868651Skris    for (pos = m_until_points.begin(); pos != end; pos++) {
13968651Skris      if (!LLDB_BREAK_ID_IS_VALID((*pos).second))
14068651Skris        return false;
14168651Skris    }
14268651Skris    return true;
143238405Sjkim  }
144238405Sjkim}
145238405Sjkim
146238405Sjkimvoid ThreadPlanStepUntil::AnalyzeStop() {
147238405Sjkim  if (m_ran_analyze)
148111147Snectar    return;
149109998Smarkm
150109998Smarkm  StopInfoSP stop_info_sp = GetPrivateStopInfo();
151109998Smarkm  m_should_stop = true;
152109998Smarkm  m_explains_stop = false;
153109998Smarkm
154111147Snectar  if (stop_info_sp) {
15555714Skris    StopReason reason = stop_info_sp->GetStopReason();
15655714Skris
15755714Skris    if (reason == eStopReasonBreakpoint) {
15855714Skris      // If this is OUR breakpoint, we're fine, otherwise we don't know why
15955714Skris      // this happened...
16055714Skris      BreakpointSiteSP this_site =
16155714Skris          m_thread.GetProcess()->GetBreakpointSiteList().FindByID(
16255714Skris              stop_info_sp->GetValue());
16355714Skris      if (!this_site) {
16455714Skris        m_explains_stop = false;
16555714Skris        return;
16655714Skris      }
16755714Skris
16855714Skris      if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) {
16955714Skris        // If we are at our "step out" breakpoint, and the stack depth has
170111147Snectar        // shrunk, then this is indeed our stop. If the stack depth has grown,
171109998Smarkm        // then we've hit our step out breakpoint recursively. If we are the
172111147Snectar        // only breakpoint at that location, then we do explain the stop, and
173109998Smarkm        // we'll just continue. If there was another breakpoint here, then we
174160814Ssimon        // don't explain the stop, but we won't mark ourselves Completed,
175160814Ssimon        // because maybe that breakpoint will continue, and then we'll finish
176160814Ssimon        // the "until".
17755714Skris        bool done;
17855714Skris        StackID cur_frame_zero_id;
17959191Skris
18059191Skris        done = (m_stack_id < cur_frame_zero_id);
18159191Skris
18259191Skris        if (done) {
18359191Skris          m_stepped_out = true;
18459191Skris          SetPlanComplete();
18559191Skris        } else
18659191Skris          m_should_stop = false;
18755714Skris
18855714Skris        if (this_site->GetNumberOfOwners() == 1)
18955714Skris          m_explains_stop = true;
19059191Skris        else
19159191Skris          m_explains_stop = false;
19259191Skris        return;
19359191Skris      } else {
19459191Skris        // Check if we've hit one of our "until" breakpoints.
19559191Skris        until_collection::iterator pos, end = m_until_points.end();
19659191Skris        for (pos = m_until_points.begin(); pos != end; pos++) {
19759191Skris          if (this_site->IsBreakpointAtThisSite((*pos).second)) {
19855714Skris            // If we're at the right stack depth, then we're done.
19959191Skris
20055714Skris            bool done;
201238405Sjkim            StackID frame_zero_id =
202238405Sjkim                m_thread.GetStackFrameAtIndex(0)->GetStackID();
203238405Sjkim
204238405Sjkim            if (frame_zero_id == m_stack_id)
205238405Sjkim              done = true;
20659191Skris            else if (frame_zero_id < m_stack_id)
20759191Skris              done = false;
20859191Skris            else {
209238405Sjkim              StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
210238405Sjkim
211238405Sjkim              // But if we can't even unwind one frame we should just get out
212238405Sjkim              // of here & stop...
213238405Sjkim              if (older_frame_sp) {
21468651Skris                const SymbolContext &older_context =
21568651Skris                    older_frame_sp->GetSymbolContext(eSymbolContextEverything);
21668651Skris                SymbolContext stack_context;
217238405Sjkim                m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(
218238405Sjkim                    &stack_context);
219238405Sjkim
220238405Sjkim                done = (older_context == stack_context);
221238405Sjkim              } else
222238405Sjkim                done = false;
223238405Sjkim            }
224238405Sjkim
225246772Sjkim            if (done)
226246772Sjkim              SetPlanComplete();
227246772Sjkim            else
228246772Sjkim              m_should_stop = false;
229246772Sjkim
230246772Sjkim            // Otherwise we've hit this breakpoint recursively.  If we're the
23155714Skris            // only breakpoint here, then we do explain the stop, and we'll
232246772Sjkim            // continue. If not then we should let higher plans handle this
23355714Skris            // stop.
234246772Sjkim            if (this_site->GetNumberOfOwners() == 1)
235246772Sjkim              m_explains_stop = true;
236246772Sjkim            else {
237246772Sjkim              m_should_stop = true;
23855714Skris              m_explains_stop = false;
23959191Skris            }
240111147Snectar            return;
241238405Sjkim          }
242111147Snectar        }
243111147Snectar      }
244111147Snectar      // If we get here we haven't hit any of our breakpoints, so let the
245111147Snectar      // higher plans take care of the stop.
246246772Sjkim      m_explains_stop = false;
24759191Skris      return;
248246772Sjkim    } else if (IsUsuallyUnexplainedStopReason(reason)) {
249246772Sjkim      m_explains_stop = false;
25059191Skris    } else {
25159191Skris      m_explains_stop = true;
252246772Sjkim    }
253246772Sjkim  }
254246772Sjkim}
255246772Sjkim
25659191Skrisbool ThreadPlanStepUntil::DoPlanExplainsStop(Event *event_ptr) {
257160814Ssimon  // We don't explain signals or breakpoints (breakpoints that handle stepping
25855714Skris  // in or out will be handled by a child plan.
25959191Skris  AnalyzeStop();
26068651Skris  return m_explains_stop;
261238405Sjkim}
262109998Smarkm
263246772Sjkimbool ThreadPlanStepUntil::ShouldStop(Event *event_ptr) {
26455714Skris  // If we've told our self in ExplainsStop that we plan to continue, then do
26555714Skris  // so here.  Otherwise, as long as this thread has stopped for a reason, we
266238405Sjkim  // will stop.
267238405Sjkim
268238405Sjkim  StopInfoSP stop_info_sp = GetPrivateStopInfo();
26955714Skris  if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
27055714Skris    return false;
27155714Skris
27259191Skris  AnalyzeStop();
27355714Skris  return m_should_stop;
274109998Smarkm}
27555714Skris
27655714Skrisbool ThreadPlanStepUntil::StopOthers() { return m_stop_others; }
27755714Skris
27855714SkrisStateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; }
27959191Skris
28059191Skrisbool ThreadPlanStepUntil::DoWillResume(StateType resume_state,
28159191Skris                                       bool current_plan) {
28259191Skris  if (current_plan) {
28359191Skris    TargetSP target_sp(m_thread.CalculateTarget());
28459191Skris    if (target_sp) {
285109998Smarkm      Breakpoint *return_bp =
286109998Smarkm          target_sp->GetBreakpointByID(m_return_bp_id).get();
287109998Smarkm      if (return_bp != nullptr)
288109998Smarkm        return_bp->SetEnabled(true);
289109998Smarkm
290109998Smarkm      until_collection::iterator pos, end = m_until_points.end();
29168651Skris      for (pos = m_until_points.begin(); pos != end; pos++) {
292238405Sjkim        Breakpoint *until_bp =
293238405Sjkim            target_sp->GetBreakpointByID((*pos).second).get();
29459191Skris        if (until_bp != nullptr)
29559191Skris          until_bp->SetEnabled(true);
29655714Skris      }
29755714Skris    }
29855714Skris  }
299186872Ssimon
30055714Skris  m_should_stop = true;
30155714Skris  m_ran_analyze = false;
30255714Skris  m_explains_stop = false;
30355714Skris  return true;
30455714Skris}
30555714Skris
30655714Skrisbool ThreadPlanStepUntil::WillStop() {
30755714Skris  TargetSP target_sp(m_thread.CalculateTarget());
30855714Skris  if (target_sp) {
30955714Skris    Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
31055714Skris    if (return_bp != nullptr)
31155714Skris      return_bp->SetEnabled(false);
31255714Skris
313238405Sjkim    until_collection::iterator pos, end = m_until_points.end();
314238405Sjkim    for (pos = m_until_points.begin(); pos != end; pos++) {
31555714Skris      Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
31655714Skris      if (until_bp != nullptr)
31755714Skris        until_bp->SetEnabled(false);
318238405Sjkim    }
319160814Ssimon  }
320238405Sjkim  return true;
321238405Sjkim}
322238405Sjkim
323238405Sjkimbool ThreadPlanStepUntil::MischiefManaged() {
324160814Ssimon  // I'm letting "PlanExplainsStop" do all the work, and just reporting that
325238405Sjkim  // here.
326238405Sjkim  bool done = false;
327238405Sjkim  if (IsPlanComplete()) {
328238405Sjkim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
329238405Sjkim    if (log)
330238405Sjkim      log->Printf("Completed step until plan.");
331238405Sjkim
332238405Sjkim    Clear();
333238405Sjkim    done = true;
334238405Sjkim  }
335160814Ssimon  if (done)
336238405Sjkim    ThreadPlan::MischiefManaged();
337238405Sjkim
338238405Sjkim  return done;
339238405Sjkim}
340238405Sjkim