Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Symbol/UnwindPlan.h
Line
Count
Source (jump to first uncovered line)
1
//===-- UnwindPlan.h --------------------------------------------*- C++ -*-===//
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
#ifndef LLDB_SYMBOL_UNWINDPLAN_H
10
#define LLDB_SYMBOL_UNWINDPLAN_H
11
12
#include <map>
13
#include <memory>
14
#include <vector>
15
16
#include "lldb/Core/AddressRange.h"
17
#include "lldb/Utility/ConstString.h"
18
#include "lldb/Utility/Stream.h"
19
#include "lldb/lldb-private.h"
20
21
namespace lldb_private {
22
23
// The UnwindPlan object specifies how to unwind out of a function - where this
24
// function saves the caller's register values before modifying them (for non-
25
// volatile aka saved registers) and how to find this frame's Canonical Frame
26
// Address (CFA) or Aligned Frame Address (AFA).
27
28
// CFA is a DWARF's Canonical Frame Address.
29
// Most commonly, registers are saved on the stack, offset some bytes from the
30
// Canonical Frame Address, or CFA, which is the starting address of this
31
// function's stack frame (the CFA is same as the eh_frame's CFA, whatever that
32
// may be on a given architecture). The CFA address for the stack frame does
33
// not change during the lifetime of the function.
34
35
// AFA is an artificially introduced Aligned Frame Address.
36
// It is used only for stack frames with realignment (e.g. when some of the
37
// locals has an alignment requirement higher than the stack alignment right
38
// after the function call). It is used to access register values saved on the
39
// stack after the realignment (and so they are inaccessible through the CFA).
40
// AFA usually equals the stack pointer value right after the realignment.
41
42
// Internally, the UnwindPlan is structured as a vector of register locations
43
// organized by code address in the function, showing which registers have been
44
// saved at that point and where they are saved. It can be thought of as the
45
// expanded table form of the DWARF CFI encoded information.
46
47
// Other unwind information sources will be converted into UnwindPlans before
48
// being added to a FuncUnwinders object.  The unwind source may be an eh_frame
49
// FDE, a DWARF debug_frame FDE, or assembly language based prologue analysis.
50
// The UnwindPlan is the canonical form of this information that the unwinder
51
// code will use when walking the stack.
52
53
class UnwindPlan {
54
public:
55
  class Row {
56
  public:
57
    class RegisterLocation {
58
    public:
59
      enum RestoreType {
60
        unspecified,       // not specified, we may be able to assume this
61
                           // is the same register. gcc doesn't specify all
62
                           // initial values so we really don't know...
63
        undefined,         // reg is not available, e.g. volatile reg
64
        same,              // reg is unchanged
65
        atCFAPlusOffset,   // reg = deref(CFA + offset)
66
        isCFAPlusOffset,   // reg = CFA + offset
67
        atAFAPlusOffset,   // reg = deref(AFA + offset)
68
        isAFAPlusOffset,   // reg = AFA + offset
69
        inOtherRegister,   // reg = other reg
70
        atDWARFExpression, // reg = deref(eval(dwarf_expr))
71
        isDWARFExpression  // reg = eval(dwarf_expr)
72
      };
73
74
1.15M
      RegisterLocation() : m_location() {}
75
76
      bool operator==(const RegisterLocation &rhs) const;
77
78
34
      bool operator!=(const RegisterLocation &rhs) const {
79
34
        return !(*this == rhs);
80
34
      }
81
82
0
      void SetUnspecified() { m_type = unspecified; }
83
84
172
      void SetUndefined() { m_type = undefined; }
85
86
47
      void SetSame() { m_type = same; }
87
88
438k
      bool IsSame() const { return m_type == same; }
89
90
438k
      bool IsUnspecified() const { return m_type == unspecified; }
91
92
816k
      bool IsUndefined() const { return m_type == undefined; }
93
94
448k
      bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
95
96
435k
      bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
97
98
48
      bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
99
100
49
      bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
101
102
129
      bool IsInOtherRegister() const { return m_type == inOtherRegister; }
103
104
10
      bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
105
106
84
      bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
107
108
199k
      void SetAtCFAPlusOffset(int32_t offset) {
109
199k
        m_type = atCFAPlusOffset;
110
199k
        m_location.offset = offset;
111
199k
      }
112
113
74.3k
      void SetIsCFAPlusOffset(int32_t offset) {
114
74.3k
        m_type = isCFAPlusOffset;
115
74.3k
        m_location.offset = offset;
116
74.3k
      }
117
118
2
      void SetAtAFAPlusOffset(int32_t offset) {
119
2
        m_type = atAFAPlusOffset;
120
2
        m_location.offset = offset;
121
2
      }
122
123
0
      void SetIsAFAPlusOffset(int32_t offset) {
124
0
        m_type = isAFAPlusOffset;
125
0
        m_location.offset = offset;
126
0
      }
127
128
13
      void SetInRegister(uint32_t reg_num) {
129
13
        m_type = inOtherRegister;
130
13
        m_location.reg_num = reg_num;
131
13
      }
132
133
12
      uint32_t GetRegisterNumber() const {
134
12
        if (m_type == inOtherRegister)
135
12
          return m_location.reg_num;
136
0
        return LLDB_INVALID_REGNUM;
137
12
      }
138
139
0
      RestoreType GetLocationType() const { return m_type; }
140
141
458k
      int32_t GetOffset() const {
142
458k
        switch(m_type)
143
458k
        {
144
435k
        case atCFAPlusOffset:
145
458k
        case isCFAPlusOffset:
146
458k
        case atAFAPlusOffset:
147
458k
        case isAFAPlusOffset:
148
458k
          return m_location.offset;
149
0
        default:
150
0
          return 0;
151
458k
        }
152
458k
      }
153
154
0
      void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
155
0
        if (m_type == atDWARFExpression || m_type == isDWARFExpression) {
156
0
          *opcodes = m_location.expr.opcodes;
157
0
          len = m_location.expr.length;
158
0
        } else {
159
0
          *opcodes = nullptr;
160
0
          len = 0;
161
0
        }
162
0
      }
163
164
      void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len);
165
166
      void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len);
167
168
42
      const uint8_t *GetDWARFExpressionBytes() {
169
42
        if (m_type == atDWARFExpression || 
m_type == isDWARFExpression32
)
170
42
          return m_location.expr.opcodes;
171
0
        return nullptr;
172
42
      }
173
174
42
      int GetDWARFExpressionLength() {
175
42
        if (m_type == atDWARFExpression || 
m_type == isDWARFExpression32
)
176
42
          return m_location.expr.length;
177
0
        return 0;
178
42
      }
179
180
      void Dump(Stream &s, const UnwindPlan *unwind_plan,
181
                const UnwindPlan::Row *row, Thread *thread, bool verbose) const;
182
183
    private:
184
      RestoreType m_type = unspecified; // How do we locate this register?
185
      union {
186
        // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
187
        int32_t offset;
188
        // For m_type == inOtherRegister
189
        uint32_t reg_num; // The register number
190
        // For m_type == atDWARFExpression or m_type == isDWARFExpression
191
        struct {
192
          const uint8_t *opcodes;
193
          uint16_t length;
194
        } expr;
195
      } m_location;
196
    };
197
198
    class FAValue {
199
    public:
200
      enum ValueType {
201
        unspecified,            // not specified
202
        isRegisterPlusOffset,   // FA = register + offset
203
        isRegisterDereferenced, // FA = [reg]
204
        isDWARFExpression,      // FA = eval(dwarf_expr)
205
        isRaSearch,             // FA = SP + offset + ???
206
      };
207
208
444k
      FAValue() : m_value() {}
209
210
      bool operator==(const FAValue &rhs) const;
211
212
34
      bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
213
214
1.91k
      void SetUnspecified() { m_type = unspecified; }
215
216
75
      bool IsUnspecified() const { return m_type == unspecified; }
217
218
9
      void SetRaSearch(int32_t offset) {
219
9
        m_type = isRaSearch;
220
9
        m_value.ra_search_offset = offset;
221
9
      }
222
223
118
      bool IsRegisterPlusOffset() const {
224
118
        return m_type == isRegisterPlusOffset;
225
118
      }
226
227
142k
      void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
228
142k
        m_type = isRegisterPlusOffset;
229
142k
        m_value.reg.reg_num = reg_num;
230
142k
        m_value.reg.offset = offset;
231
142k
      }
232
233
0
      bool IsRegisterDereferenced() const {
234
0
        return m_type == isRegisterDereferenced;
235
0
      }
236
237
0
      void SetIsRegisterDereferenced(uint32_t reg_num) {
238
0
        m_type = isRegisterDereferenced;
239
0
        m_value.reg.reg_num = reg_num;
240
0
      }
241
242
0
      bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
243
244
16
      void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
245
16
        m_type = isDWARFExpression;
246
16
        m_value.expr.opcodes = opcodes;
247
16
        m_value.expr.length = len;
248
16
      }
249
250
312k
      uint32_t GetRegisterNumber() const {
251
312k
        if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
252
312k
          return m_value.reg.reg_num;
253
0
        return LLDB_INVALID_REGNUM;
254
312k
      }
255
256
960k
      ValueType GetValueType() const { return m_type; }
257
258
499k
      int32_t GetOffset() const {
259
499k
        switch (m_type) {
260
499k
          case isRegisterPlusOffset:
261
499k
            return m_value.reg.offset;
262
10
          case isRaSearch:
263
10
            return m_value.ra_search_offset;
264
0
          default:
265
0
            return 0;
266
499k
        }
267
499k
      }
268
269
3
      void IncOffset(int32_t delta) {
270
3
        if (m_type == isRegisterPlusOffset)
271
3
          m_value.reg.offset += delta;
272
3
      }
273
274
6.80k
      void SetOffset(int32_t offset) {
275
6.80k
        if (m_type == isRegisterPlusOffset)
276
6.80k
          m_value.reg.offset = offset;
277
6.80k
      }
278
279
0
      void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
280
0
        if (m_type == isDWARFExpression) {
281
0
          *opcodes = m_value.expr.opcodes;
282
0
          len = m_value.expr.length;
283
0
        } else {
284
0
          *opcodes = nullptr;
285
0
          len = 0;
286
0
        }
287
0
      }
288
289
13
      const uint8_t *GetDWARFExpressionBytes() {
290
13
        if (m_type == isDWARFExpression)
291
13
          return m_value.expr.opcodes;
292
0
        return nullptr;
293
13
      }
294
295
13
      int GetDWARFExpressionLength() {
296
13
        if (m_type == isDWARFExpression)
297
13
          return m_value.expr.length;
298
0
        return 0;
299
13
      }
300
301
      void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
302
303
    private:
304
      ValueType m_type = unspecified; // How do we compute CFA value?
305
      union {
306
        struct {
307
          // For m_type == isRegisterPlusOffset or m_type ==
308
          // isRegisterDereferenced
309
          uint32_t reg_num; // The register number
310
          // For m_type == isRegisterPlusOffset
311
          int32_t offset;
312
        } reg;
313
        // For m_type == isDWARFExpression
314
        struct {
315
          const uint8_t *opcodes;
316
          uint16_t length;
317
        } expr;
318
        // For m_type == isRaSearch
319
        int32_t ra_search_offset;
320
      } m_value;
321
    }; // class FAValue
322
323
    Row();
324
325
    bool operator==(const Row &rhs) const;
326
327
    bool GetRegisterInfo(uint32_t reg_num,
328
                         RegisterLocation &register_location) const;
329
330
    void SetRegisterInfo(uint32_t reg_num,
331
                         const RegisterLocation register_location);
332
333
    void RemoveRegisterInfo(uint32_t reg_num);
334
335
961k
    lldb::addr_t GetOffset() const { return m_offset; }
336
337
115k
    void SetOffset(lldb::addr_t offset) { m_offset = offset; }
338
339
112
    void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
340
341
1.29M
    FAValue &GetCFAValue() { return m_cfa_value; }
342
343
693k
    FAValue &GetAFAValue() { return m_afa_value; }
344
345
    bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
346
                                              bool can_replace);
347
348
    bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
349
                                              bool can_replace);
350
351
    bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
352
                                        bool can_replace_only_if_unspecified);
353
354
    bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
355
356
    bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
357
                                       bool can_replace);
358
359
    bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
360
361
    // When this UnspecifiedRegistersAreUndefined mode is
362
    // set, any register that is not specified by this Row will
363
    // be described as Undefined.
364
    // This will prevent the unwinder from iterating down the
365
    // stack looking for a spill location, or a live register value
366
    // at frame 0.
367
    // It would be used for an UnwindPlan row where we can't track
368
    // spilled registers -- for instance a jitted stack frame where
369
    // we have no unwind information or start address -- and registers
370
    // MAY have been spilled and overwritten, so providing the
371
    // spilled/live value from a newer frame may show an incorrect value.
372
52.0k
    void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) {
373
52.0k
      m_unspecified_registers_are_undefined = unspec_is_undef;
374
52.0k
    }
375
376
0
    bool GetUnspecifiedRegistersAreUndefined() {
377
0
      return m_unspecified_registers_are_undefined;
378
0
    }
379
380
    void Clear();
381
382
    void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
383
              lldb::addr_t base_addr) const;
384
385
  protected:
386
    typedef std::map<uint32_t, RegisterLocation> collection;
387
    lldb::addr_t m_offset = 0; // Offset into the function for this row
388
389
    FAValue m_cfa_value;
390
    FAValue m_afa_value;
391
    collection m_register_locations;
392
    bool m_unspecified_registers_are_undefined = false;
393
  }; // class Row
394
395
  typedef std::shared_ptr<Row> RowSP;
396
397
  UnwindPlan(lldb::RegisterKind reg_kind)
398
86.9k
      : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM),
399
86.9k
        m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
400
86.9k
        m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
401
86.9k
        m_plan_is_for_signal_trap(eLazyBoolCalculate) {}
402
403
  // Performs a deep copy of the plan, including all the rows (expensive).
404
  UnwindPlan(const UnwindPlan &rhs)
405
21
      : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
406
21
        m_register_kind(rhs.m_register_kind),
407
21
        m_return_addr_register(rhs.m_return_addr_register),
408
21
        m_source_name(rhs.m_source_name),
409
21
        m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
410
        m_plan_is_valid_at_all_instruction_locations(
411
21
            rhs.m_plan_is_valid_at_all_instruction_locations),
412
21
        m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap),
413
21
        m_lsda_address(rhs.m_lsda_address),
414
21
        m_personality_func_addr(rhs.m_personality_func_addr) {
415
21
    m_row_list.reserve(rhs.m_row_list.size());
416
21
    for (const RowSP &row_sp : rhs.m_row_list)
417
65
      m_row_list.emplace_back(new Row(*row_sp));
418
21
  }
419
420
85.7k
  ~UnwindPlan() = default;
421
422
  void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
423
424
  void AppendRow(const RowSP &row_sp);
425
426
  void InsertRow(const RowSP &row_sp, bool replace_existing = false);
427
428
  // Returns a pointer to the best row for the given offset into the function's
429
  // instructions. If offset is -1 it indicates that the function start is
430
  // unknown - the final row in the UnwindPlan is returned. In practice, the
431
  // UnwindPlan for a function with no known start address will be the
432
  // architectural default UnwindPlan which will only have one row.
433
  UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
434
435
705k
  lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
436
437
74.5k
  void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
438
439
98
  void SetReturnAddressRegister(uint32_t regnum) {
440
98
    m_return_addr_register = regnum;
441
98
  }
442
443
40.6k
  uint32_t GetReturnAddressRegister() { return m_return_addr_register; }
444
445
17
  uint32_t GetInitialCFARegister() const {
446
17
    if (m_row_list.empty())
447
0
      return LLDB_INVALID_REGNUM;
448
17
    return m_row_list.front()->GetCFAValue().GetRegisterNumber();
449
17
  }
450
451
  // This UnwindPlan may not be valid at every address of the function span.
452
  // For instance, a FastUnwindPlan will not be valid at the prologue setup
453
  // instructions - only in the body of the function.
454
  void SetPlanValidAddressRange(const AddressRange &range);
455
456
0
  const AddressRange &GetAddressRange() const {
457
0
    return m_plan_valid_address_range;
458
0
  }
459
460
  bool PlanValidAtAddress(Address addr);
461
462
  bool IsValidRowIndex(uint32_t idx) const;
463
464
  const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
465
466
  const UnwindPlan::RowSP GetLastRow() const;
467
468
  lldb_private::ConstString GetSourceName() const;
469
470
  void SetSourceName(const char *);
471
472
  // Was this UnwindPlan emitted by a compiler?
473
46.0k
  lldb_private::LazyBool GetSourcedFromCompiler() const {
474
46.0k
    return m_plan_is_sourced_from_compiler;
475
46.0k
  }
476
477
  // Was this UnwindPlan emitted by a compiler?
478
74.5k
  void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
479
74.5k
    m_plan_is_sourced_from_compiler = from_compiler;
480
74.5k
  }
481
482
  // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
483
  // valid at call sites, e.g. for exception handling.
484
  lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
485
    return m_plan_is_valid_at_all_instruction_locations;
486
  }
487
488
  // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
489
  // valid at call sites, e.g. for exception handling.
490
  void SetUnwindPlanValidAtAllInstructions(
491
65.7k
      lldb_private::LazyBool valid_at_all_insn) {
492
65.7k
    m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
493
65.7k
  }
494
495
  // Is this UnwindPlan for a signal trap frame?  If so, then its saved pc
496
  // may have been set manually by the signal dispatch code and therefore
497
  // not follow a call to the child frame.
498
218k
  lldb_private::LazyBool GetUnwindPlanForSignalTrap() const {
499
218k
    return m_plan_is_for_signal_trap;
500
218k
  }
501
502
65.7k
  void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) {
503
65.7k
    m_plan_is_for_signal_trap = is_for_signal_trap;
504
65.7k
  }
505
506
  int GetRowCount() const;
507
508
69.8k
  void Clear() {
509
69.8k
    m_row_list.clear();
510
69.8k
    m_plan_valid_address_range.Clear();
511
69.8k
    m_register_kind = lldb::eRegisterKindDWARF;
512
69.8k
    m_source_name.Clear();
513
69.8k
    m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
514
69.8k
    m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
515
69.8k
    m_plan_is_for_signal_trap = eLazyBoolCalculate;
516
69.8k
    m_lsda_address.Clear();
517
69.8k
    m_personality_func_addr.Clear();
518
69.8k
  }
519
520
  const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
521
522
0
  Address GetLSDAAddress() const { return m_lsda_address; }
523
524
4.66k
  void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
525
526
0
  Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
527
528
4.66k
  void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
529
4.66k
    m_personality_func_addr = presonality_func_ptr;
530
4.66k
  }
531
532
private:
533
  typedef std::vector<RowSP> collection;
534
  collection m_row_list;
535
  AddressRange m_plan_valid_address_range;
536
  lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
537
                                      // are in terms of - will need to be
538
  // translated to lldb native reg nums at unwind time
539
  uint32_t m_return_addr_register; // The register that has the return address
540
                                   // for the caller frame
541
                                   // e.g. the lr on arm
542
  lldb_private::ConstString
543
      m_source_name; // for logging, where this UnwindPlan originated from
544
  lldb_private::LazyBool m_plan_is_sourced_from_compiler;
545
  lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
546
  lldb_private::LazyBool m_plan_is_for_signal_trap;
547
548
  Address m_lsda_address; // Where the language specific data area exists in the
549
                          // module - used
550
                          // in exception handling.
551
  Address m_personality_func_addr; // The address of a pointer to the
552
                                   // personality function - used in
553
                                   // exception handling.
554
};                                 // class UnwindPlan
555
556
} // namespace lldb_private
557
558
#endif // LLDB_SYMBOL_UNWINDPLAN_H