Coverage Report

Created: 2023-11-11 10:31

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Target/ThreadPlanStepRange.cpp
Line
Count
Source (jump to first uncovered line)
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
26
using namespace lldb;
27
using 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
32
ThreadPlanStepRange::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
427
    : ThreadPlan(kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
39
427
      m_addr_context(addr_context), m_address_ranges(),
40
427
      m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(),
41
427
      m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false),
42
427
      m_given_ranges_only(given_ranges_only) {
43
427
  m_use_fast_step = GetTarget().GetUseFastStepping();
44
427
  AddRange(range);
45
427
  m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID();
46
427
  StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1);
47
427
  if (parent_stack)
48
427
    m_parent_stack_id = parent_stack->GetStackID();
49
427
}
50
51
427
ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); }
52
53
427
void ThreadPlanStepRange::DidPush() {
54
  // See if we can find a "next range" breakpoint:
55
427
  SetNextBranchBreakpoint();
56
427
}
57
58
860
bool ThreadPlanStepRange::ValidatePlan(Stream *error) {
59
860
  if (m_could_not_resolve_hw_bp) {
60
0
    if (error)
61
0
      error->PutCString(
62
0
          "Could not create hardware breakpoint for thread plan.");
63
0
    return false;
64
0
  }
65
860
  return true;
66
860
}
67
68
389
Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) {
69
389
  Log *log = GetLog(LLDBLog::Step);
70
71
389
  const Vote vote = IsPlanComplete() ? 
eVoteYes7
:
eVoteNo382
;
72
389
  LLDB_LOGF(log, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n",
73
389
            vote);
74
389
  return vote;
75
389
}
76
77
521
void 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
521
  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
521
  m_instruction_ranges.push_back(DisassemblerSP());
87
521
}
88
89
0
void ThreadPlanStepRange::DumpRanges(Stream *s) {
90
0
  size_t num_ranges = m_address_ranges.size();
91
0
  if (num_ranges == 1) {
92
0
    m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
93
0
  } else {
94
0
    for (size_t i = 0; i < num_ranges; i++) {
95
0
      s->Printf(" %" PRIu64 ": ", uint64_t(i));
96
0
      m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress);
97
0
    }
98
0
  }
99
0
}
100
101
806
bool ThreadPlanStepRange::InRange() {
102
806
  Log *log = GetLog(LLDBLog::Step);
103
806
  bool ret_value = false;
104
806
  Thread &thread = GetThread();
105
806
  lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC();
106
107
806
  size_t num_ranges = m_address_ranges.size();
108
1.38k
  for (size_t i = 0; i < num_ranges; 
i++580
) {
109
915
    ret_value = 
110
915
        m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget());
111
915
    if (ret_value)
112
335
      break;
113
915
  }
114
115
806
  if (!ret_value && 
!m_given_ranges_only471
) {
116
    // See if we've just stepped to another part of the same line number...
117
471
    StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
118
119
471
    SymbolContext new_context(
120
471
        frame->GetSymbolContext(eSymbolContextEverything));
121
471
    if (m_addr_context.line_entry.IsValid() &&
122
471
        new_context.line_entry.IsValid()) {
123
471
      if (m_addr_context.line_entry.original_file ==
124
471
          new_context.line_entry.original_file) {
125
471
        if (m_addr_context.line_entry.line == new_context.line_entry.line) {
126
94
          m_addr_context = new_context;
127
94
          const bool include_inlined_functions =
128
94
              GetKind() == eKindStepOverRange;
129
94
          AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
130
94
              include_inlined_functions));
131
94
          ret_value = true;
132
94
          if (log) {
133
0
            StreamString s;
134
0
            m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
135
0
                                           Address::DumpStyleLoadAddress,
136
0
                                           Address::DumpStyleLoadAddress, true);
137
138
0
            LLDB_LOGF(
139
0
                log,
140
0
                "Step range plan stepped to another range of same line: %s",
141
0
                s.GetData());
142
0
          }
143
377
        } else if (new_context.line_entry.line == 0) {
144
0
          new_context.line_entry.line = m_addr_context.line_entry.line;
145
0
          m_addr_context = new_context;
146
0
          const bool include_inlined_functions =
147
0
              GetKind() == eKindStepOverRange;
148
0
          AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange(
149
0
              include_inlined_functions));
150
0
          ret_value = true;
151
0
          if (log) {
152
0
            StreamString s;
153
0
            m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
154
0
                                           Address::DumpStyleLoadAddress,
155
0
                                           Address::DumpStyleLoadAddress, true);
156
157
0
            LLDB_LOGF(log,
158
0
                      "Step range plan stepped to a range at linenumber 0 "
159
0
                      "stepping through that range: %s",
160
0
                      s.GetData());
161
0
          }
162
377
        } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(
163
377
                       &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
0
          m_addr_context = new_context;
171
0
          m_address_ranges.clear();
172
0
          AddRange(m_addr_context.line_entry.range);
173
0
          ret_value = true;
174
0
          if (log) {
175
0
            StreamString s;
176
0
            m_addr_context.line_entry.Dump(&s, &GetTarget(), true,
177
0
                                           Address::DumpStyleLoadAddress,
178
0
                                           Address::DumpStyleLoadAddress, true);
179
180
0
            LLDB_LOGF(log,
181
0
                      "Step range plan stepped to the middle of new "
182
0
                      "line(%d): %s, continuing to clear this line.",
183
0
                      new_context.line_entry.line, s.GetData());
184
0
          }
185
0
        }
186
471
      }
187
471
    }
188
471
  }
189
190
806
  if (!ret_value && 
log377
)
191
0
    LLDB_LOGF(log, "Step range plan out of range to 0x%" PRIx64, pc_load_addr);
192
193
806
  return ret_value;
194
806
}
195
196
653
bool ThreadPlanStepRange::InSymbol() {
197
653
  lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC();
198
653
  if (m_addr_context.function != nullptr) {
199
653
    return m_addr_context.function->GetAddressRange().ContainsLoadAddress(
200
653
        cur_pc, &GetTarget());
201
653
  } else 
if (0
m_addr_context.symbol0
&&
m_addr_context.symbol->ValueIsAddress()0
) {
202
0
    AddressRange range(m_addr_context.symbol->GetAddressRef(),
203
0
                       m_addr_context.symbol->GetByteSize());
204
0
    return range.ContainsLoadAddress(cur_pc, &GetTarget());
205
0
  }
206
0
  return false;
207
653
}
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
216
1.22k
lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() {
217
1.22k
  FrameComparison frame_order;
218
1.22k
  Thread &thread = GetThread();
219
1.22k
  StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID();
220
221
1.22k
  if (cur_frame_id == m_stack_id) {
222
806
    frame_order = eFrameCompareEqual;
223
806
  } else 
if (417
cur_frame_id < m_stack_id417
) {
224
388
    frame_order = eFrameCompareYounger;
225
388
  } else {
226
29
    StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1);
227
29
    StackID cur_parent_id;
228
29
    if (cur_parent_frame)
229
27
      cur_parent_id = cur_parent_frame->GetStackID();
230
29
    if (m_parent_stack_id.IsValid() && cur_parent_id.IsValid() &&
231
29
        
m_parent_stack_id == cur_parent_id27
)
232
0
      frame_order = eFrameCompareSameParent;
233
29
    else
234
29
      frame_order = eFrameCompareOlder;
235
29
  }
236
1.22k
  return frame_order;
237
1.22k
}
238
239
2.02k
bool ThreadPlanStepRange::StopOthers() {
240
2.02k
  switch (m_stop_others) {
241
44
  case lldb::eOnlyThisThread:
242
44
    return true;
243
1.82k
  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
1.82k
    return !m_found_calls;
249
161
  case lldb::eAllThreads:
250
161
    return false;
251
2.02k
  }
252
0
  llvm_unreachable("Unhandled run mode!");
253
0
}
254
255
InstructionList *ThreadPlanStepRange::GetInstructionsForAddress(
256
776
    lldb::addr_t addr, size_t &range_index, size_t &insn_offset) {
257
776
  size_t num_ranges = m_address_ranges.size();
258
952
  for (size_t i = 0; i < num_ranges; 
i++176
) {
259
942
    if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) {
260
      // Some joker added a zero size range to the stepping range...
261
766
      if (m_address_ranges[i].GetByteSize() == 0)
262
0
        return nullptr;
263
264
766
      if (!m_instruction_ranges[i]) {
265
        // Disassemble the address range given:
266
511
        const char *plugin_name = nullptr;
267
511
        const char *flavor = nullptr;
268
511
        m_instruction_ranges[i] = Disassembler::DisassembleRange(
269
511
            GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(),
270
511
            m_address_ranges[i]);
271
511
      }
272
766
      if (!m_instruction_ranges[i])
273
0
        return nullptr;
274
766
      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
766
        insn_offset =
280
766
            m_instruction_ranges[i]
281
766
                ->GetInstructionList()
282
766
                .GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
283
766
        if (insn_offset == UINT32_MAX)
284
0
          return nullptr;
285
766
        else {
286
766
          range_index = i;
287
766
          return &m_instruction_ranges[i]->GetInstructionList();
288
766
        }
289
766
      }
290
766
    }
291
942
  }
292
10
  return nullptr;
293
776
}
294
295
1.69k
void ThreadPlanStepRange::ClearNextBranchBreakpoint() {
296
1.69k
  if (m_next_branch_bp_sp) {
297
206
    Log *log = GetLog(LLDBLog::Step);
298
206
    LLDB_LOGF(log, "Removing next branch breakpoint: %d.",
299
206
              m_next_branch_bp_sp->GetID());
300
206
    GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID());
301
206
    m_next_branch_bp_sp.reset();
302
206
    m_could_not_resolve_hw_bp = false;
303
206
    m_found_calls = false;
304
206
  }
305
1.69k
}
306
307
836
bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
308
836
  if (m_next_branch_bp_sp)
309
60
    return true;
310
311
776
  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
776
  if (!m_use_fast_step)
315
0
    return false;
316
317
  // clear the m_found_calls, we'll rediscover it for this range.
318
776
  m_found_calls = false;
319
  
320
776
  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
776
  size_t pc_index;
324
776
  size_t range_index;
325
776
  InstructionList *instructions =
326
776
      GetInstructionsForAddress(cur_addr, range_index, pc_index);
327
776
  if (instructions == nullptr)
328
10
    return false;
329
766
  else {
330
766
    const bool ignore_calls = GetKind() == eKindStepOverRange;
331
766
    uint32_t branch_index = instructions->GetIndexOfNextBranchInstruction(
332
766
        pc_index, ignore_calls, &m_found_calls);
333
766
    Address run_to_address;
334
335
    // If we didn't find a branch, run to the end of the range.
336
766
    if (branch_index == UINT32_MAX) {
337
362
      uint32_t last_index = instructions->GetSize() - 1;
338
362
      if (last_index - pc_index > 1) {
339
101
        InstructionSP last_inst =
340
101
            instructions->GetInstructionAtIndex(last_index);
341
101
        size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
342
101
        run_to_address = last_inst->GetAddress();
343
101
        run_to_address.Slide(last_inst_size);
344
101
      }
345
404
    } else if (branch_index - pc_index > 1) {
346
105
      run_to_address =
347
105
          instructions->GetInstructionAtIndex(branch_index)->GetAddress();
348
105
    }
349
350
766
    if (run_to_address.IsValid()) {
351
206
      const bool is_internal = true;
352
206
      m_next_branch_bp_sp =
353
206
          GetTarget().CreateBreakpoint(run_to_address, is_internal, false);
354
206
      if (m_next_branch_bp_sp) {
355
356
206
        if (m_next_branch_bp_sp->IsHardware() &&
357
206
            
!m_next_branch_bp_sp->HasResolvedLocations()2
)
358
0
          m_could_not_resolve_hw_bp = true;
359
360
206
        if (log) {
361
0
          lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
362
0
          BreakpointLocationSP bp_loc =
363
0
              m_next_branch_bp_sp->GetLocationAtIndex(0);
364
0
          if (bp_loc) {
365
0
            BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
366
0
            if (bp_site) {
367
0
              bp_site_id = bp_site->GetID();
368
0
            }
369
0
          }
370
0
          LLDB_LOGF(log,
371
0
                    "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting "
372
0
                    "breakpoint %d (site %d) to run to address 0x%" PRIx64,
373
0
                    m_next_branch_bp_sp->GetID(), bp_site_id,
374
0
                    run_to_address.GetLoadAddress(&m_process.GetTarget()));
375
0
        }
376
377
206
        m_next_branch_bp_sp->SetThreadID(m_tid);
378
206
        m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
379
380
206
        return true;
381
206
      } else
382
0
        return false;
383
206
    }
384
766
  }
385
560
  return false;
386
776
}
387
388
bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
389
227
    lldb::StopInfoSP stop_info_sp) {
390
227
  Log *log = GetLog(LLDBLog::Step);
391
227
  if (!m_next_branch_bp_sp)
392
23
    return false;
393
394
204
  break_id_t bp_site_id = stop_info_sp->GetValue();
395
204
  BreakpointSiteSP bp_site_sp =
396
204
      m_process.GetBreakpointSiteList().FindByID(bp_site_id);
397
204
  if (!bp_site_sp)
398
0
    return false;
399
204
  else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID()))
400
6
    return false;
401
198
  else {
402
    // If we've hit the next branch breakpoint, then clear it.
403
198
    size_t num_owners = bp_site_sp->GetNumberOfOwners();
404
198
    bool explains_stop = true;
405
    // If all the owners are internal, then we are probably just stepping over
406
    // 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
394
    for (size_t i = 0; i < num_owners; 
i++196
) {
410
198
      if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) {
411
2
        explains_stop = false;
412
2
        break;
413
2
      }
414
198
    }
415
198
    LLDB_LOGF(log,
416
198
              "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit "
417
198
              "next range breakpoint which has %" PRIu64
418
198
              " owners - explains stop: %u.",
419
198
              (uint64_t)num_owners, explains_stop);
420
198
    ClearNextBranchBreakpoint();
421
198
    return explains_stop;
422
198
  }
423
204
}
424
425
418
bool ThreadPlanStepRange::WillStop() { return true; }
426
427
1.27k
StateType ThreadPlanStepRange::GetPlanRunState() {
428
1.27k
  if (m_next_branch_bp_sp)
429
349
    return eStateRunning;
430
922
  else
431
922
    return eStateStepping;
432
1.27k
}
433
434
1.05k
bool 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
1.05k
  if (!m_no_more_plans)
444
668
    return false;
445
446
383
  bool done = true;
447
383
  if (!IsPlanComplete()) {
448
0
    if (InRange()) {
449
0
      done = false;
450
0
    } else {
451
0
      FrameComparison frame_order = CompareCurrentFrameToStartFrame();
452
0
      done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true;
453
0
    }
454
0
  }
455
456
383
  if (done) {
457
383
    Log *log = GetLog(LLDBLog::Step);
458
383
    LLDB_LOGF(log, "Completed step through range plan.");
459
383
    ClearNextBranchBreakpoint();
460
383
    ThreadPlan::MischiefManaged();
461
383
    return true;
462
383
  } else {
463
0
    return false;
464
0
  }
465
383
}
466
467
72
bool ThreadPlanStepRange::IsPlanStale() {
468
72
  Log *log = GetLog(LLDBLog::Step);
469
72
  FrameComparison frame_order = CompareCurrentFrameToStartFrame();
470
471
72
  if (frame_order == eFrameCompareOlder) {
472
0
    if (log) {
473
0
      LLDB_LOGF(log, "ThreadPlanStepRange::IsPlanStale returning true, we've "
474
0
                     "stepped out.");
475
0
    }
476
0
    return true;
477
72
  } else if (frame_order == eFrameCompareEqual && 
InSymbol()38
) {
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
38
    if (!InRange()) {
482
      // Set plan Complete when we reach next instruction just after the range
483
18
      lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1;
484
18
      size_t num_ranges = m_address_ranges.size();
485
36
      for (size_t i = 0; i < num_ranges; 
i++18
) {
486
18
        bool in_range = 
487
18
            m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget());
488
18
        if (in_range) {
489
18
          SetPlanComplete();
490
18
        }
491
18
      }
492
18
      return true;
493
18
    }
494
38
  }
495
54
  return false;
496
72
}