Home | History | Annotate | Download | only in Target
      1 //===-- ThreadPlanStepUntil.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 //m_should_stop
     10 
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "lldb/Target/ThreadPlanStepUntil.h"
     15 
     16 // C Includes
     17 // C++ Includes
     18 // Other libraries and framework includes
     19 // Project includes
     20 #include "lldb/Breakpoint/Breakpoint.h"
     21 #include "lldb/lldb-private-log.h"
     22 #include "lldb/Core/Log.h"
     23 #include "lldb/Target/Process.h"
     24 #include "lldb/Target/RegisterContext.h"
     25 #include "lldb/Target/StopInfo.h"
     26 #include "lldb/Target/Target.h"
     27 
     28 using namespace lldb;
     29 using namespace lldb_private;
     30 
     31 //----------------------------------------------------------------------
     32 // ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame
     33 //----------------------------------------------------------------------
     34 
     35 ThreadPlanStepUntil::ThreadPlanStepUntil
     36 (
     37     Thread &thread,
     38     lldb::addr_t *address_list,
     39     size_t num_addresses,
     40     bool stop_others,
     41     uint32_t frame_idx
     42 ) :
     43     ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
     44     m_step_from_insn (LLDB_INVALID_ADDRESS),
     45     m_return_bp_id (LLDB_INVALID_BREAK_ID),
     46     m_return_addr (LLDB_INVALID_ADDRESS),
     47     m_stepped_out (false),
     48     m_should_stop (false),
     49     m_ran_analyze (false),
     50     m_explains_stop (false),
     51     m_until_points (),
     52     m_stop_others (stop_others)
     53 {
     54     // Stash away our "until" addresses:
     55     TargetSP target_sp (m_thread.CalculateTarget());
     56 
     57     StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
     58     if (frame_sp)
     59     {
     60         m_step_from_insn = frame_sp->GetStackID().GetPC();
     61         lldb::user_id_t thread_id = m_thread.GetID();
     62 
     63         // Find the return address and set a breakpoint there:
     64         // FIXME - can we do this more securely if we know first_insn?
     65 
     66         StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
     67         if (return_frame_sp)
     68         {
     69             // TODO: add inline functionality
     70             m_return_addr = return_frame_sp->GetStackID().GetPC();
     71             Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true).get();
     72             if (return_bp != NULL)
     73             {
     74                 return_bp->SetThreadID(thread_id);
     75                 m_return_bp_id = return_bp->GetID();
     76                 return_bp->SetBreakpointKind ("until-return-backstop");
     77             }
     78         }
     79 
     80         m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID();
     81 
     82         // Now set breakpoints on all our return addresses:
     83         for (size_t i = 0; i < num_addresses; i++)
     84         {
     85             Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true).get();
     86             if (until_bp != NULL)
     87             {
     88                 until_bp->SetThreadID(thread_id);
     89                 m_until_points[address_list[i]] = until_bp->GetID();
     90                 until_bp->SetBreakpointKind("until-target");
     91             }
     92             else
     93             {
     94                 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
     95             }
     96         }
     97     }
     98 }
     99 
    100 ThreadPlanStepUntil::~ThreadPlanStepUntil ()
    101 {
    102     Clear();
    103 }
    104 
    105 void
    106 ThreadPlanStepUntil::Clear()
    107 {
    108     TargetSP target_sp (m_thread.CalculateTarget());
    109     if (target_sp)
    110     {
    111         if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
    112         {
    113             target_sp->RemoveBreakpointByID(m_return_bp_id);
    114             m_return_bp_id = LLDB_INVALID_BREAK_ID;
    115         }
    116 
    117         until_collection::iterator pos, end = m_until_points.end();
    118         for (pos = m_until_points.begin(); pos != end; pos++)
    119         {
    120             target_sp->RemoveBreakpointByID((*pos).second);
    121         }
    122     }
    123     m_until_points.clear();
    124 }
    125 
    126 void
    127 ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
    128 {
    129     if (level == lldb::eDescriptionLevelBrief)
    130     {
    131         s->Printf ("step until");
    132         if (m_stepped_out)
    133             s->Printf (" - stepped out");
    134     }
    135     else
    136     {
    137         if (m_until_points.size() == 1)
    138             s->Printf ("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64 " using breakpoint %d",
    139                        (uint64_t)m_step_from_insn,
    140                        (uint64_t) (*m_until_points.begin()).first,
    141                        (*m_until_points.begin()).second);
    142         else
    143         {
    144             until_collection::iterator pos, end = m_until_points.end();
    145             s->Printf ("Stepping from address 0x%" PRIx64 " until we reach one of:",
    146                        (uint64_t)m_step_from_insn);
    147             for (pos = m_until_points.begin(); pos != end; pos++)
    148             {
    149                 s->Printf ("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
    150             }
    151         }
    152         s->Printf(" stepped out address is 0x%" PRIx64 ".", (uint64_t) m_return_addr);
    153     }
    154 }
    155 
    156 bool
    157 ThreadPlanStepUntil::ValidatePlan (Stream *error)
    158 {
    159     if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
    160         return false;
    161     else
    162     {
    163         until_collection::iterator pos, end = m_until_points.end();
    164         for (pos = m_until_points.begin(); pos != end; pos++)
    165         {
    166             if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
    167                 return false;
    168         }
    169         return true;
    170     }
    171 }
    172 
    173 void
    174 ThreadPlanStepUntil::AnalyzeStop()
    175 {
    176     if (m_ran_analyze)
    177         return;
    178 
    179     StopInfoSP stop_info_sp = GetPrivateStopInfo ();
    180     m_should_stop = true;
    181     m_explains_stop = false;
    182 
    183     if (stop_info_sp)
    184     {
    185         StopReason reason = stop_info_sp->GetStopReason();
    186 
    187         switch (reason)
    188         {
    189             case eStopReasonBreakpoint:
    190             {
    191                 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
    192                 BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue());
    193                 if (!this_site)
    194                 {
    195                     m_explains_stop = false;
    196                     return;
    197                 }
    198 
    199                 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
    200                 {
    201                     // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
    202                     // this is indeed our stop.
    203                     // If the stack depth has grown, then we've hit our step out breakpoint recursively.
    204                     // If we are the only breakpoint at that location, then we do explain the stop, and
    205                     // we'll just continue.
    206                     // If there was another breakpoint here, then we don't explain the stop, but we won't
    207                     // mark ourselves Completed, because maybe that breakpoint will continue, and then
    208                     // we'll finish the "until".
    209                     bool done;
    210                     StackID cur_frame_zero_id;
    211 
    212                     if (m_stack_id < cur_frame_zero_id)
    213                         done = true;
    214                     else
    215                         done = false;
    216 
    217                     if (done)
    218                     {
    219                         m_stepped_out = true;
    220                         SetPlanComplete();
    221                     }
    222                     else
    223                         m_should_stop = false;
    224 
    225                     if (this_site->GetNumberOfOwners() == 1)
    226                         m_explains_stop = true;
    227                     else
    228                         m_explains_stop = false;
    229                     return;
    230                 }
    231                 else
    232                 {
    233                     // Check if we've hit one of our "until" breakpoints.
    234                     until_collection::iterator pos, end = m_until_points.end();
    235                     for (pos = m_until_points.begin(); pos != end; pos++)
    236                     {
    237                         if (this_site->IsBreakpointAtThisSite ((*pos).second))
    238                         {
    239                             // If we're at the right stack depth, then we're done.
    240 
    241                             bool done;
    242                             StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
    243 
    244                             if (frame_zero_id == m_stack_id)
    245                                 done = true;
    246                             else if (frame_zero_id < m_stack_id)
    247                                 done = false;
    248                             else
    249                             {
    250                                 StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
    251 
    252                                 // But if we can't even unwind one frame we should just get out of here & stop...
    253                                 if (older_frame_sp)
    254                                 {
    255                                     const SymbolContext &older_context
    256                                         = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
    257                                     SymbolContext stack_context;
    258                                     m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(&stack_context);
    259 
    260                                     if (older_context == stack_context)
    261                                         done = true;
    262                                     else
    263                                         done = false;
    264                                 }
    265                                 else
    266                                     done = false;
    267                             }
    268 
    269                             if (done)
    270                                 SetPlanComplete();
    271                             else
    272                                 m_should_stop = false;
    273 
    274                             // Otherwise we've hit this breakpoint recursively.  If we're the
    275                             // only breakpoint here, then we do explain the stop, and we'll continue.
    276                             // If not then we should let higher plans handle this stop.
    277                             if (this_site->GetNumberOfOwners() == 1)
    278                                 m_explains_stop = true;
    279                             else
    280                             {
    281                                 m_should_stop = true;
    282                                 m_explains_stop = false;
    283                             }
    284                             return;
    285                         }
    286                     }
    287                 }
    288                 // If we get here we haven't hit any of our breakpoints, so let the higher
    289                 // plans take care of the stop.
    290                 m_explains_stop = false;
    291                 return;
    292             }
    293             case eStopReasonWatchpoint:
    294             case eStopReasonSignal:
    295             case eStopReasonException:
    296             case eStopReasonExec:
    297             case eStopReasonThreadExiting:
    298                 m_explains_stop = false;
    299                 break;
    300             default:
    301                 m_explains_stop = true;
    302                 break;
    303         }
    304     }
    305 }
    306 
    307 bool
    308 ThreadPlanStepUntil::DoPlanExplainsStop (Event *event_ptr)
    309 {
    310     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
    311     // out will be handled by a child plan.
    312     AnalyzeStop();
    313     return m_explains_stop;
    314 }
    315 
    316 bool
    317 ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
    318 {
    319     // If we've told our self in ExplainsStop that we plan to continue, then
    320     // do so here.  Otherwise, as long as this thread has stopped for a reason,
    321     // we will stop.
    322 
    323     StopInfoSP stop_info_sp = GetPrivateStopInfo ();
    324     if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
    325         return false;
    326 
    327     AnalyzeStop();
    328     return m_should_stop;
    329 }
    330 
    331 bool
    332 ThreadPlanStepUntil::StopOthers ()
    333 {
    334     return m_stop_others;
    335 }
    336 
    337 StateType
    338 ThreadPlanStepUntil::GetPlanRunState ()
    339 {
    340     return eStateRunning;
    341 }
    342 
    343 bool
    344 ThreadPlanStepUntil::DoWillResume (StateType resume_state, bool current_plan)
    345 {
    346     if (current_plan)
    347     {
    348         TargetSP target_sp (m_thread.CalculateTarget());
    349         if (target_sp)
    350         {
    351             Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
    352             if (return_bp != NULL)
    353                 return_bp->SetEnabled (true);
    354 
    355             until_collection::iterator pos, end = m_until_points.end();
    356             for (pos = m_until_points.begin(); pos != end; pos++)
    357             {
    358                 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
    359                 if (until_bp != NULL)
    360                     until_bp->SetEnabled (true);
    361             }
    362         }
    363     }
    364 
    365     m_should_stop = true;
    366     m_ran_analyze = false;
    367     m_explains_stop = false;
    368     return true;
    369 }
    370 
    371 bool
    372 ThreadPlanStepUntil::WillStop ()
    373 {
    374     TargetSP target_sp (m_thread.CalculateTarget());
    375     if (target_sp)
    376     {
    377         Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
    378         if (return_bp != NULL)
    379             return_bp->SetEnabled (false);
    380 
    381         until_collection::iterator pos, end = m_until_points.end();
    382         for (pos = m_until_points.begin(); pos != end; pos++)
    383         {
    384             Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
    385             if (until_bp != NULL)
    386                 until_bp->SetEnabled (false);
    387         }
    388     }
    389     return true;
    390 }
    391 
    392 bool
    393 ThreadPlanStepUntil::MischiefManaged ()
    394 {
    395 
    396     // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
    397     bool done = false;
    398     if (IsPlanComplete())
    399     {
    400         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    401         if (log)
    402             log->Printf("Completed step until plan.");
    403 
    404         Clear();
    405         done = true;
    406     }
    407     if (done)
    408         ThreadPlan::MischiefManaged ();
    409 
    410     return done;
    411 
    412 }
    413 
    414