Home | History | Annotate | Download | only in Target
      1 //===-- 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 
     10 #include "lldb/Target/ThreadPlanStepThrough.h"
     11 
     12 // C Includes
     13 // C++ Includes
     14 // Other libraries and framework includes
     15 // Project includes
     16 #include "lldb/lldb-private-log.h"
     17 #include "lldb/Core/Log.h"
     18 #include "lldb/Core/Stream.h"
     19 #include "lldb/Target/DynamicLoader.h"
     20 #include "lldb/Target/ObjCLanguageRuntime.h"
     21 #include "lldb/Target/Process.h"
     22 #include "lldb/Target/RegisterContext.h"
     23 #include "lldb/Target/Target.h"
     24 #include "lldb/Breakpoint/Breakpoint.h"
     25 
     26 using namespace lldb;
     27 using namespace lldb_private;
     28 
     29 //----------------------------------------------------------------------
     30 // ThreadPlanStepThrough: If the current instruction is a trampoline, step through it
     31 // If it is the beginning of the prologue of a function, step through that as well.
     32 // FIXME: At present only handles DYLD trampolines.
     33 //----------------------------------------------------------------------
     34 
     35 ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, StackID &m_stack_id, bool stop_others) :
     36     ThreadPlan (ThreadPlan::eKindStepThrough, "Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion),
     37     m_start_address (0),
     38     m_backstop_bkpt_id (LLDB_INVALID_BREAK_ID),
     39     m_backstop_addr(LLDB_INVALID_ADDRESS),
     40     m_return_stack_id (m_stack_id),
     41     m_stop_others (stop_others)
     42 {
     43 
     44     LookForPlanToStepThroughFromCurrentPC();
     45 
     46     // If we don't get a valid step through plan, don't bother to set up a backstop.
     47     if (m_sub_plan_sp)
     48     {
     49         m_start_address = GetThread().GetRegisterContext()->GetPC(0);
     50 
     51         // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in
     52         // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to.
     53 
     54         StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID (m_stack_id);
     55 
     56         if (return_frame_sp)
     57         {
     58             m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(m_thread.CalculateTarget().get());
     59             Breakpoint *return_bp = m_thread.GetProcess()->GetTarget().CreateBreakpoint (m_backstop_addr, true).get();
     60             if (return_bp != NULL)
     61             {
     62                 return_bp->SetThreadID(m_thread.GetID());
     63                 m_backstop_bkpt_id = return_bp->GetID();
     64                 return_bp->SetBreakpointKind("step-through-backstop");
     65             }
     66             Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
     67             if (log)
     68             {
     69                 log->Printf ("Setting backstop breakpoint %d at address: 0x%" PRIx64, m_backstop_bkpt_id, m_backstop_addr);
     70             }
     71         }
     72     }
     73 }
     74 
     75 ThreadPlanStepThrough::~ThreadPlanStepThrough ()
     76 {
     77     ClearBackstopBreakpoint ();
     78 }
     79 
     80 void
     81 ThreadPlanStepThrough::DidPush ()
     82 {
     83     if (m_sub_plan_sp)
     84         PushPlan(m_sub_plan_sp);
     85 }
     86 
     87 void
     88 ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC()
     89 {
     90     m_sub_plan_sp = m_thread.GetProcess()->GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
     91     // If that didn't come up with anything, try the ObjC runtime plugin:
     92     if (!m_sub_plan_sp.get())
     93     {
     94         ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess()->GetObjCLanguageRuntime();
     95         if (objc_runtime)
     96             m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
     97     }
     98 
     99     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    100     if (log)
    101     {
    102         lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0);
    103         if (m_sub_plan_sp)
    104         {
    105             StreamString s;
    106             m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
    107             log->Printf ("Found step through plan from 0x%" PRIx64 ": %s", current_address, s.GetData());
    108         }
    109         else
    110         {
    111             log->Printf ("Couldn't find step through plan from address 0x%" PRIx64 ".", current_address);
    112         }
    113     }
    114 }
    115 
    116 void
    117 ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level)
    118 {
    119     if (level == lldb::eDescriptionLevelBrief)
    120         s->Printf ("Step through");
    121     else
    122     {
    123         s->PutCString ("Stepping through trampoline code from: ");
    124         s->Address(m_start_address, sizeof (addr_t));
    125         if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
    126         {
    127             s->Printf (" with backstop breakpoint id: %d at address: ", m_backstop_bkpt_id);
    128             s->Address (m_backstop_addr, sizeof (addr_t));
    129         }
    130         else
    131             s->PutCString (" unable to set a backstop breakpoint.");
    132     }
    133 }
    134 
    135 bool
    136 ThreadPlanStepThrough::ValidatePlan (Stream *error)
    137 {
    138     return m_sub_plan_sp.get() != NULL;
    139 }
    140 
    141 bool
    142 ThreadPlanStepThrough::DoPlanExplainsStop (Event *event_ptr)
    143 {
    144     // If we have a sub-plan, it will have been asked first if we explain the stop, and
    145     // we won't get asked.  The only time we would be the one directly asked this question
    146     // is if we hit our backstop breakpoint.
    147 
    148     if (HitOurBackstopBreakpoint())
    149         return true;
    150     else
    151         return false;
    152 }
    153 
    154 bool
    155 ThreadPlanStepThrough::ShouldStop (Event *event_ptr)
    156 {
    157     // If we've already marked ourselves done, then we're done...
    158     if (IsPlanComplete())
    159         return true;
    160 
    161     // First, did we hit the backstop breakpoint?
    162     if (HitOurBackstopBreakpoint())
    163     {
    164         SetPlanComplete(false);
    165         return true;
    166     }
    167 
    168     // If we don't have a sub-plan, then we're also done (can't see how we would ever get here
    169     // without a plan, but just in case.
    170 
    171     if (!m_sub_plan_sp)
    172     {
    173         SetPlanComplete();
    174         return true;
    175     }
    176 
    177     // If the current sub plan is not done, we don't want to stop.  Actually, we probably won't
    178     // ever get here in this state, since we generally won't get asked any questions if out
    179     // current sub-plan is not done...
    180     if (!m_sub_plan_sp->IsPlanComplete())
    181         return false;
    182 
    183     // If our current sub plan failed, then let's just run to our backstop.  If we can't do that then just stop.
    184     if (!m_sub_plan_sp->PlanSucceeded())
    185     {
    186         if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
    187         {
    188             m_sub_plan_sp.reset();
    189             return false;
    190         }
    191         else
    192         {
    193             SetPlanComplete(false);
    194             return true;
    195         }
    196     }
    197 
    198     // Next see if there is a specific step through plan at our current pc (these might
    199     // chain, for instance stepping through a dylib trampoline to the objc dispatch function...)
    200     LookForPlanToStepThroughFromCurrentPC();
    201     if (m_sub_plan_sp)
    202     {
    203         PushPlan (m_sub_plan_sp);
    204         return false;
    205     }
    206     else
    207     {
    208         SetPlanComplete();
    209         return true;
    210     }
    211 }
    212 
    213 bool
    214 ThreadPlanStepThrough::StopOthers ()
    215 {
    216     return m_stop_others;
    217 }
    218 
    219 StateType
    220 ThreadPlanStepThrough::GetPlanRunState ()
    221 {
    222     return eStateRunning;
    223 }
    224 
    225 bool
    226 ThreadPlanStepThrough::DoWillResume (StateType resume_state, bool current_plan)
    227 {
    228     return true;
    229 }
    230 
    231 bool
    232 ThreadPlanStepThrough::WillStop ()
    233 {
    234     return true;
    235 }
    236 
    237 void
    238 ThreadPlanStepThrough::ClearBackstopBreakpoint ()
    239 {
    240     if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
    241     {
    242         m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
    243         m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
    244     }
    245 }
    246 
    247 bool
    248 ThreadPlanStepThrough::MischiefManaged ()
    249 {
    250     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    251 
    252     if (!IsPlanComplete())
    253     {
    254         return false;
    255     }
    256     else
    257     {
    258         if (log)
    259             log->Printf("Completed step through step plan.");
    260 
    261         ClearBackstopBreakpoint ();
    262         ThreadPlan::MischiefManaged ();
    263         return true;
    264     }
    265 }
    266 
    267 bool
    268 ThreadPlanStepThrough::HitOurBackstopBreakpoint()
    269 {
    270     StopInfoSP stop_info_sp(m_thread.GetStopInfo());
    271     if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
    272     {
    273         break_id_t stop_value = (break_id_t) stop_info_sp->GetValue();
    274         BreakpointSiteSP cur_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value);
    275         if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id))
    276         {
    277             StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
    278 
    279             if (cur_frame_zero_id == m_return_stack_id)
    280             {
    281                 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    282                 if (log)
    283                     log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint.");
    284                 return true;
    285             }
    286         }
    287     }
    288     return false;
    289 }
    290 
    291