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