Home | History | Annotate | Download | only in Target
      1 //===-- ThreadPlanStepRange.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/ThreadPlanStepRange.h"
     11 
     12 // C Includes
     13 // C++ Includes
     14 // Other libraries and framework includes
     15 // Project includes
     16 
     17 #include "lldb/lldb-private-log.h"
     18 #include "lldb/Breakpoint/BreakpointLocation.h"
     19 #include "lldb/Breakpoint/BreakpointSite.h"
     20 #include "lldb/Core/Disassembler.h"
     21 #include "lldb/Core/Log.h"
     22 #include "lldb/Core/Stream.h"
     23 #include "lldb/Symbol/Function.h"
     24 #include "lldb/Symbol/Symbol.h"
     25 #include "lldb/Target/ExecutionContext.h"
     26 #include "lldb/Target/Process.h"
     27 #include "lldb/Target/RegisterContext.h"
     28 #include "lldb/Target/StopInfo.h"
     29 #include "lldb/Target/Target.h"
     30 #include "lldb/Target/Thread.h"
     31 #include "lldb/Target/ThreadPlanRunToAddress.h"
     32 
     33 using namespace lldb;
     34 using namespace lldb_private;
     35 
     36 
     37 //----------------------------------------------------------------------
     38 // ThreadPlanStepRange: Step through a stack range, either stepping over or into
     39 // based on the value of \a type.
     40 //----------------------------------------------------------------------
     41 
     42 ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
     43                                           const char *name,
     44                                           Thread &thread,
     45                                           const AddressRange &range,
     46                                           const SymbolContext &addr_context,
     47                                           lldb::RunMode stop_others) :
     48     ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
     49     m_addr_context (addr_context),
     50     m_address_ranges (),
     51     m_stop_others (stop_others),
     52     m_stack_id (),
     53     m_no_more_plans (false),
     54     m_first_run_event (true),
     55     m_use_fast_step(false)
     56 {
     57     m_use_fast_step = GetTarget().GetUseFastStepping();
     58     AddRange(range);
     59     m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
     60 }
     61 
     62 ThreadPlanStepRange::~ThreadPlanStepRange ()
     63 {
     64     ClearNextBranchBreakpoint();
     65 
     66     size_t num_instruction_ranges = m_instruction_ranges.size();
     67 
     68     // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
     69     // I'll fix that but for now, just clear the list and it will go away nicely.
     70     for (size_t i = 0; i < num_instruction_ranges; i++)
     71     {
     72         if (m_instruction_ranges[i])
     73             m_instruction_ranges[i]->GetInstructionList().Clear();
     74     }
     75 }
     76 
     77 void
     78 ThreadPlanStepRange::DidPush ()
     79 {
     80     // See if we can find a "next range" breakpoint:
     81     SetNextBranchBreakpoint();
     82 }
     83 
     84 bool
     85 ThreadPlanStepRange::ValidatePlan (Stream *error)
     86 {
     87     return true;
     88 }
     89 
     90 Vote
     91 ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
     92 {
     93     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
     94 
     95     const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
     96     if (log)
     97         log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
     98     return vote;
     99 }
    100 
    101 void
    102 ThreadPlanStepRange::AddRange(const AddressRange &new_range)
    103 {
    104     // For now I'm just adding the ranges.  At some point we may want to
    105     // condense the ranges if they overlap, though I don't think it is likely
    106     // to be very important.
    107     m_address_ranges.push_back (new_range);
    108 
    109     // Fill the slot for this address range with an empty DisassemblerSP in the instruction ranges. I want the
    110     // indices to match, but I don't want to do the work to disassemble this range if I don't step into it.
    111     m_instruction_ranges.push_back (DisassemblerSP());
    112 }
    113 
    114 void
    115 ThreadPlanStepRange::DumpRanges(Stream *s)
    116 {
    117     size_t num_ranges = m_address_ranges.size();
    118     if (num_ranges == 1)
    119     {
    120         m_address_ranges[0].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
    121     }
    122     else
    123     {
    124         for (size_t i = 0; i < num_ranges; i++)
    125         {
    126             s->PutCString("%d: ");
    127             m_address_ranges[i].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
    128         }
    129     }
    130 }
    131 
    132 bool
    133 ThreadPlanStepRange::InRange ()
    134 {
    135     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    136     bool ret_value = false;
    137 
    138     lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
    139 
    140     size_t num_ranges = m_address_ranges.size();
    141     for (size_t i = 0; i < num_ranges; i++)
    142     {
    143         ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get());
    144         if (ret_value)
    145             break;
    146     }
    147 
    148     if (!ret_value)
    149     {
    150         // See if we've just stepped to another part of the same line number...
    151         StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
    152 
    153         SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
    154         if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
    155         {
    156             if (m_addr_context.line_entry.file == new_context.line_entry.file)
    157             {
    158                 if (m_addr_context.line_entry.line == new_context.line_entry.line)
    159                 {
    160                     m_addr_context = new_context;
    161                     AddRange(m_addr_context.line_entry.range);
    162                     ret_value = true;
    163                     if (log)
    164                     {
    165                         StreamString s;
    166                         m_addr_context.line_entry.Dump (&s,
    167                                                         m_thread.CalculateTarget().get(),
    168                                                         true,
    169                                                         Address::DumpStyleLoadAddress,
    170                                                         Address::DumpStyleLoadAddress,
    171                                                         true);
    172 
    173                         log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
    174                     }
    175                 }
    176                 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get())
    177                          != pc_load_addr)
    178                 {
    179                     // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
    180                     // line.  So far I mostly see this due to bugs in the debug information.
    181                     // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
    182                     // range to the line we've stepped into the middle of and continue.
    183                     m_addr_context = new_context;
    184                     m_address_ranges.clear();
    185                     AddRange(m_addr_context.line_entry.range);
    186                     ret_value = true;
    187                     if (log)
    188                     {
    189                         StreamString s;
    190                         m_addr_context.line_entry.Dump (&s,
    191                                                         m_thread.CalculateTarget().get(),
    192                                                         true,
    193                                                         Address::DumpStyleLoadAddress,
    194                                                         Address::DumpStyleLoadAddress,
    195                                                         true);
    196 
    197                         log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
    198                                      new_context.line_entry.line,
    199                                      s.GetData());
    200                     }
    201 
    202                 }
    203             }
    204 
    205         }
    206 
    207     }
    208 
    209     if (!ret_value && log)
    210         log->Printf ("Step range plan out of range to 0x%" PRIx64, pc_load_addr);
    211 
    212     return ret_value;
    213 }
    214 
    215 bool
    216 ThreadPlanStepRange::InSymbol()
    217 {
    218     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
    219     if (m_addr_context.function != NULL)
    220     {
    221         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
    222     }
    223     else if (m_addr_context.symbol)
    224     {
    225         AddressRange range(m_addr_context.symbol->GetAddress(), m_addr_context.symbol->GetByteSize());
    226         return range.ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
    227     }
    228     return false;
    229 }
    230 
    231 // FIXME: This should also handle inlining if we aren't going to do inlining in the
    232 // main stack.
    233 //
    234 // Ideally we should remember the whole stack frame list, and then compare that
    235 // to the current list.
    236 
    237 lldb::FrameComparison
    238 ThreadPlanStepRange::CompareCurrentFrameToStartFrame()
    239 {
    240     FrameComparison frame_order;
    241 
    242     StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
    243 
    244     if (cur_frame_id == m_stack_id)
    245     {
    246         frame_order = eFrameCompareEqual;
    247     }
    248     else if (cur_frame_id < m_stack_id)
    249     {
    250         frame_order = eFrameCompareYounger;
    251     }
    252     else
    253     {
    254         frame_order = eFrameCompareOlder;
    255     }
    256     return frame_order;
    257 }
    258 
    259 bool
    260 ThreadPlanStepRange::StopOthers ()
    261 {
    262     if (m_stop_others == lldb::eOnlyThisThread
    263         || m_stop_others == lldb::eOnlyDuringStepping)
    264         return true;
    265     else
    266         return false;
    267 }
    268 
    269 InstructionList *
    270 ThreadPlanStepRange::GetInstructionsForAddress(lldb::addr_t addr, size_t &range_index, size_t &insn_offset)
    271 {
    272     size_t num_ranges = m_address_ranges.size();
    273     for (size_t i = 0; i < num_ranges; i++)
    274     {
    275         if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()))
    276         {
    277             // Some joker added a zero size range to the stepping range...
    278             if (m_address_ranges[i].GetByteSize() == 0)
    279                 return NULL;
    280 
    281             if (!m_instruction_ranges[i])
    282             {
    283                 //Disassemble the address range given:
    284                 ExecutionContext exe_ctx (m_thread.GetProcess());
    285                 const char *plugin_name = NULL;
    286                 const char *flavor = NULL;
    287                 m_instruction_ranges[i] = Disassembler::DisassembleRange(GetTarget().GetArchitecture(),
    288                                                                          plugin_name,
    289                                                                          flavor,
    290                                                                          exe_ctx,
    291                                                                          m_address_ranges[i]);
    292 
    293             }
    294             if (!m_instruction_ranges[i])
    295                 return NULL;
    296             else
    297             {
    298                 // Find where we are in the instruction list as well.  If we aren't at an instruction,
    299                 // return NULL.  In this case, we're probably lost, and shouldn't try to do anything fancy.
    300 
    301                 insn_offset = m_instruction_ranges[i]->GetInstructionList().GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
    302                 if (insn_offset == UINT32_MAX)
    303                     return NULL;
    304                 else
    305                 {
    306                     range_index = i;
    307                     return &m_instruction_ranges[i]->GetInstructionList();
    308                 }
    309             }
    310         }
    311     }
    312     return NULL;
    313 }
    314 
    315 void
    316 ThreadPlanStepRange::ClearNextBranchBreakpoint()
    317 {
    318     if (m_next_branch_bp_sp)
    319     {
    320         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    321         if (log)
    322             log->Printf ("Removing next branch breakpoint: %d.", m_next_branch_bp_sp->GetID());
    323         GetTarget().RemoveBreakpointByID (m_next_branch_bp_sp->GetID());
    324         m_next_branch_bp_sp.reset();
    325     }
    326 }
    327 
    328 bool
    329 ThreadPlanStepRange::SetNextBranchBreakpoint ()
    330 {
    331     if (m_next_branch_bp_sp)
    332         return true;
    333 
    334     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    335     // Stepping through ranges using breakpoints doesn't work yet, but with this off we fall back to instruction
    336     // single stepping.
    337     if (!m_use_fast_step)
    338          return false;
    339 
    340     lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
    341     // Find the current address in our address ranges, and fetch the disassembly if we haven't already:
    342     size_t pc_index;
    343     size_t range_index;
    344     InstructionList *instructions = GetInstructionsForAddress (cur_addr, range_index, pc_index);
    345     if (instructions == NULL)
    346         return false;
    347     else
    348     {
    349         uint32_t branch_index;
    350         branch_index = instructions->GetIndexOfNextBranchInstruction (pc_index);
    351 
    352         Address run_to_address;
    353 
    354         // If we didn't find a branch, run to the end of the range.
    355         if (branch_index == UINT32_MAX)
    356         {
    357             branch_index = instructions->GetSize() - 1;
    358         }
    359 
    360         if (branch_index - pc_index > 1)
    361         {
    362             const bool is_internal = true;
    363             run_to_address = instructions->GetInstructionAtIndex(branch_index)->GetAddress();
    364             m_next_branch_bp_sp = GetTarget().CreateBreakpoint(run_to_address, is_internal);
    365             if (m_next_branch_bp_sp)
    366             {
    367                 if (log)
    368                 {
    369                     lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
    370                     BreakpointLocationSP bp_loc = m_next_branch_bp_sp->GetLocationAtIndex(0);
    371                     if (bp_loc)
    372                     {
    373                         BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
    374                         if (bp_site)
    375                         {
    376                             bp_site_id = bp_site->GetID();
    377                         }
    378                     }
    379                     log->Printf ("ThreadPlanStepRange::SetNextBranchBreakpoint - Setting breakpoint %d (site %d) to run to address 0x%" PRIx64,
    380                                  m_next_branch_bp_sp->GetID(),
    381                                  bp_site_id,
    382                                  run_to_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()));
    383                 }
    384                 m_next_branch_bp_sp->SetThreadID(m_thread.GetID());
    385                 m_next_branch_bp_sp->SetBreakpointKind ("next-branch-location");
    386                 return true;
    387             }
    388             else
    389                 return false;
    390         }
    391     }
    392     return false;
    393 }
    394 
    395 bool
    396 ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info_sp)
    397 {
    398     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    399     if (!m_next_branch_bp_sp)
    400         return false;
    401 
    402     break_id_t bp_site_id = stop_info_sp->GetValue();
    403     BreakpointSiteSP bp_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id);
    404     if (!bp_site_sp)
    405         return false;
    406     else if (!bp_site_sp->IsBreakpointAtThisSite (m_next_branch_bp_sp->GetID()))
    407         return false;
    408     else
    409     {
    410         // If we've hit the next branch breakpoint, then clear it.
    411         size_t num_owners = bp_site_sp->GetNumberOfOwners();
    412         bool explains_stop = true;
    413         // If all the owners are internal, then we are probably just stepping over this range from multiple threads,
    414         // or multiple frames, so we want to continue.  If one is not internal, then we should not explain the stop,
    415         // and let the user breakpoint handle the stop.
    416         for (size_t i = 0; i < num_owners; i++)
    417         {
    418             if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
    419             {
    420                 explains_stop = false;
    421                 break;
    422             }
    423         }
    424         if (log)
    425             log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %zu owners - explains stop: %u.",
    426                         num_owners,
    427                         explains_stop);
    428         ClearNextBranchBreakpoint();
    429         return  explains_stop;
    430     }
    431 }
    432 
    433 bool
    434 ThreadPlanStepRange::WillStop ()
    435 {
    436     return true;
    437 }
    438 
    439 StateType
    440 ThreadPlanStepRange::GetPlanRunState ()
    441 {
    442     if (m_next_branch_bp_sp)
    443         return eStateRunning;
    444     else
    445         return eStateStepping;
    446 }
    447 
    448 bool
    449 ThreadPlanStepRange::MischiefManaged ()
    450 {
    451     // If we have pushed some plans between ShouldStop & MischiefManaged, then we're not done...
    452     // I do this check first because we might have stepped somewhere that will fool InRange into
    453     // thinking it needs to step past the end of that line.  This happens, for instance, when stepping
    454     // over inlined code that is in the middle of the current line.
    455 
    456     if (!m_no_more_plans)
    457         return false;
    458 
    459     bool done = true;
    460     if (!IsPlanComplete())
    461     {
    462         if (InRange())
    463         {
    464             done = false;
    465         }
    466         else
    467         {
    468             FrameComparison frame_order = CompareCurrentFrameToStartFrame();
    469             if (frame_order != eFrameCompareOlder)
    470             {
    471                 if (m_no_more_plans)
    472                     done = true;
    473                 else
    474                     done = false;
    475             }
    476             else
    477                 done = true;
    478         }
    479     }
    480 
    481     if (done)
    482     {
    483         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    484         if (log)
    485             log->Printf("Completed step through range plan.");
    486         ClearNextBranchBreakpoint();
    487         ThreadPlan::MischiefManaged ();
    488         return true;
    489     }
    490     else
    491     {
    492         return false;
    493     }
    494 
    495 }
    496 
    497 bool
    498 ThreadPlanStepRange::IsPlanStale ()
    499 {
    500     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
    501     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
    502 
    503     if (frame_order == eFrameCompareOlder)
    504     {
    505         if (log)
    506         {
    507             log->Printf("ThreadPlanStepRange::IsPlanStale returning true, we've stepped out.");
    508         }
    509         return true;
    510     }
    511     else if (frame_order == eFrameCompareEqual && InSymbol())
    512     {
    513         // If we are not in a place we should step through, we've gotten stale.
    514         // One tricky bit here is that some stubs don't push a frame, so we should.
    515         // check that we are in the same symbol.
    516         if (!InRange())
    517         {
    518             return true;
    519         }
    520     }
    521     return false;
    522 }
    523