brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · e15635e Raw
265 lines · cpp
1//===-- ThreadPlanStepThrough.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/ThreadPlanStepThrough.h"10#include "lldb/Breakpoint/Breakpoint.h"11#include "lldb/Target/DynamicLoader.h"12#include "lldb/Target/LanguageRuntime.h"13#include "lldb/Target/Process.h"14#include "lldb/Target/RegisterContext.h"15#include "lldb/Target/Target.h"16#include "lldb/Utility/LLDBLog.h"17#include "lldb/Utility/Log.h"18#include "lldb/Utility/Stream.h"19 20using namespace lldb;21using namespace lldb_private;22 23// ThreadPlanStepThrough: If the current instruction is a trampoline, step24// through it If it is the beginning of the prologue of a function, step25// through that as well.26 27ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread,28                                             StackID &m_stack_id,29                                             bool stop_others)30    : ThreadPlan(ThreadPlan::eKindStepThrough,31                 "Step through trampolines and prologues", thread,32                 eVoteNoOpinion, eVoteNoOpinion),33      m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID),34      m_backstop_addr(LLDB_INVALID_ADDRESS), m_return_stack_id(m_stack_id),35      m_stop_others(stop_others) {36  LookForPlanToStepThroughFromCurrentPC();37 38  // If we don't get a valid step through plan, don't bother to set up a39  // backstop.40  if (m_sub_plan_sp) {41    m_start_address = GetThread().GetRegisterContext()->GetPC(0);42 43    // We are going to return back to the concrete frame 1, we might pass by44    // some inlined code that we're in the middle of by doing this, but it's45    // easier than trying to figure out where the inlined code might return to.46 47    StackFrameSP return_frame_sp = thread.GetFrameWithStackID(m_stack_id);48 49    if (return_frame_sp) {50      m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(51          thread.CalculateTarget().get());52      Breakpoint *return_bp =53          m_process.GetTarget()54              .CreateBreakpoint(m_backstop_addr, true, false)55              .get();56 57      if (return_bp != nullptr) {58        if (return_bp->IsHardware() && !return_bp->HasResolvedLocations())59          m_could_not_resolve_hw_bp = true;60        return_bp->SetThreadID(m_tid);61        m_backstop_bkpt_id = return_bp->GetID();62        return_bp->SetBreakpointKind("step-through-backstop");63      }64      Log *log = GetLog(LLDBLog::Step);65      if (log) {66        LLDB_LOGF(log, "Setting backstop breakpoint %d at address: 0x%" PRIx64,67                  m_backstop_bkpt_id, m_backstop_addr);68      }69    }70  }71}72 73ThreadPlanStepThrough::~ThreadPlanStepThrough() { ClearBackstopBreakpoint(); }74 75void ThreadPlanStepThrough::DidPush() {76  if (m_sub_plan_sp)77    PushPlan(m_sub_plan_sp);78}79 80void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() {81  Thread &thread = GetThread();82  DynamicLoader *loader = thread.GetProcess()->GetDynamicLoader();83  if (loader)84    m_sub_plan_sp = loader->GetStepThroughTrampolinePlan(thread, m_stop_others);85 86  // If the DynamicLoader was unable to provide us with a ThreadPlan, then we87  // try the LanguageRuntimes.88  if (!m_sub_plan_sp) {89    for (LanguageRuntime *runtime : m_process.GetLanguageRuntimes()) {90      m_sub_plan_sp =91          runtime->GetStepThroughTrampolinePlan(thread, m_stop_others);92 93      if (m_sub_plan_sp)94        break;95    }96  }97 98  Log *log = GetLog(LLDBLog::Step);99  if (log) {100    lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0);101    if (m_sub_plan_sp) {102      StreamString s;103      m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);104      LLDB_LOGF(log, "Found step through plan from 0x%" PRIx64 ": %s",105                current_address, s.GetData());106    } else {107      LLDB_LOGF(log,108                "Couldn't find step through plan from address 0x%" PRIx64 ".",109                current_address);110    }111  }112}113 114void ThreadPlanStepThrough::GetDescription(Stream *s,115                                           lldb::DescriptionLevel level) {116  if (level == lldb::eDescriptionLevelBrief)117    s->Printf("Step through");118  else {119    s->PutCString("Stepping through trampoline code from: ");120    DumpAddress(s->AsRawOstream(), m_start_address, sizeof(addr_t));121    if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {122      s->Printf(" with backstop breakpoint ID: %d at address: ",123                m_backstop_bkpt_id);124      DumpAddress(s->AsRawOstream(), m_backstop_addr, sizeof(addr_t));125    } else126      s->PutCString(" unable to set a backstop breakpoint.");127  }128}129 130bool ThreadPlanStepThrough::ValidatePlan(Stream *error) {131  if (m_could_not_resolve_hw_bp) {132    if (error)133      error->PutCString(134          "Could not create hardware breakpoint for thread plan.");135    return false;136  }137 138  if (m_backstop_bkpt_id == LLDB_INVALID_BREAK_ID) {139    if (error)140      error->PutCString("Could not create backstop breakpoint.");141    return false;142  }143 144  if (!m_sub_plan_sp.get()) {145    if (error)146      error->PutCString("Does not have a subplan.");147    return false;148  }149 150  return true;151}152 153bool ThreadPlanStepThrough::DoPlanExplainsStop(Event *event_ptr) {154  // If we have a sub-plan, it will have been asked first if we explain the155  // stop, and we won't get asked.  The only time we would be the one directly156  // asked this question is if we hit our backstop breakpoint.157 158  return HitOurBackstopBreakpoint();159}160 161bool ThreadPlanStepThrough::ShouldStop(Event *event_ptr) {162  // If we've already marked ourselves done, then we're done...163  if (IsPlanComplete())164    return true;165 166  // First, did we hit the backstop breakpoint?167  if (HitOurBackstopBreakpoint()) {168    SetPlanComplete(true);169    return true;170  }171 172  // If we don't have a sub-plan, then we're also done (can't see how we would173  // ever get here without a plan, but just in case.174 175  if (!m_sub_plan_sp) {176    SetPlanComplete();177    return true;178  }179 180  // If the current sub plan is not done, we don't want to stop.  Actually, we181  // probably won't ever get here in this state, since we generally won't get182  // asked any questions if out current sub-plan is not done...183  if (!m_sub_plan_sp->IsPlanComplete())184    return false;185 186  // If our current sub plan failed, then let's just run to our backstop.  If187  // we can't do that then just stop.188  if (!m_sub_plan_sp->PlanSucceeded()) {189    if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {190      m_sub_plan_sp.reset();191      return false;192    } else {193      SetPlanComplete(false);194      return true;195    }196  }197 198  // Next see if there is a specific step through plan at our current pc (these199  // might chain, for instance stepping through a dylib trampoline to the objc200  // dispatch function...)201  LookForPlanToStepThroughFromCurrentPC();202  if (m_sub_plan_sp) {203    PushPlan(m_sub_plan_sp);204    return false;205  } else {206    SetPlanComplete();207    return true;208  }209}210 211bool ThreadPlanStepThrough::StopOthers() { return m_stop_others; }212 213StateType ThreadPlanStepThrough::GetPlanRunState() { return eStateRunning; }214 215bool ThreadPlanStepThrough::DoWillResume(StateType resume_state,216                                         bool current_plan) {217  return true;218}219 220bool ThreadPlanStepThrough::WillStop() { return true; }221 222void ThreadPlanStepThrough::ClearBackstopBreakpoint() {223  if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) {224    m_process.GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id);225    m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;226    m_could_not_resolve_hw_bp = false;227  }228}229 230bool ThreadPlanStepThrough::MischiefManaged() {231  Log *log = GetLog(LLDBLog::Step);232 233  if (!IsPlanComplete()) {234    return false;235  } else {236    LLDB_LOGF(log, "Completed step through step plan.");237 238    ClearBackstopBreakpoint();239    ThreadPlan::MischiefManaged();240    return true;241  }242}243 244bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() {245  Thread &thread = GetThread();246  StopInfoSP stop_info_sp(thread.GetStopInfo());247  if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) {248    break_id_t stop_value = (break_id_t)stop_info_sp->GetValue();249    BreakpointSiteSP cur_site_sp =250        m_process.GetBreakpointSiteList().FindByID(stop_value);251    if (cur_site_sp &&252        cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) {253      StackID cur_frame_zero_id = thread.GetStackFrameAtIndex(0)->GetStackID();254 255      if (cur_frame_zero_id == m_return_stack_id) {256        Log *log = GetLog(LLDBLog::Step);257        if (log)258          log->PutCString("ThreadPlanStepThrough hit backstop breakpoint.");259        return true;260      }261    }262  }263  return false;264}265