aboutsummaryrefslogtreecommitdiff
path: root/include/lldb/Symbol/FuncUnwinders.h
blob: a5b9b801e0336cf0729f15843e890d198a496a3d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#ifndef liblldb_FuncUnwinders_h
#define liblldb_FuncUnwinders_h

#include <mutex>
#include <vector>

#include "lldb/Core/AddressRange.h"
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/ArchSpec.h"

namespace lldb_private {

class UnwindTable;

class FuncUnwinders {
public:
  // FuncUnwinders objects are used to track UnwindPlans for a function
  // (named or not - really just an address range)

  // We'll record four different UnwindPlans for each address range:
  //
  //   1. Unwinding from a call site (a valid exception throw location)
  //      This is often sourced from the eh_frame exception handling info
  //   2. Unwinding from a non-call site (any location in the function)
  //      This is often done by analyzing the function prologue assembly
  //      language instructions
  //   3. A fast unwind method for this function which only retrieves a
  //      limited set of registers necessary to walk the stack
  //   4. An architectural default unwind plan when none of the above are
  //      available for some reason.

  // Additionally, FuncUnwinds object can be asked where the prologue
  // instructions are finished for migrating breakpoints past the
  // stack frame setup instructions when we don't have line table information.

  FuncUnwinders(lldb_private::UnwindTable &unwind_table, AddressRange range);

  ~FuncUnwinders();

  // current_offset is the byte offset into the function.
  // 0 means no instructions have executed yet.  -1 means the offset is unknown.
  // On architectures where the pc points to the next instruction that will
  // execute, this
  // offset value will have already been decremented by 1 to stay within the
  // bounds of the
  // correct function body.
  lldb::UnwindPlanSP GetUnwindPlanAtCallSite(Target &target,
                                             int current_offset);

  lldb::UnwindPlanSP GetUnwindPlanAtNonCallSite(Target &target,
                                                lldb_private::Thread &thread,
                                                int current_offset);

  lldb::UnwindPlanSP GetUnwindPlanFastUnwind(Target &target,
                                             lldb_private::Thread &thread);

  lldb::UnwindPlanSP
  GetUnwindPlanArchitectureDefault(lldb_private::Thread &thread);

  lldb::UnwindPlanSP
  GetUnwindPlanArchitectureDefaultAtFunctionEntry(lldb_private::Thread &thread);

  Address &GetFirstNonPrologueInsn(Target &target);

  const Address &GetFunctionStartAddress() const;

  bool ContainsAddress(const Address &addr) const {
    return m_range.ContainsFileAddress(addr);
  }

  // A function may have a Language Specific Data Area specified -- a block of
  // data in
  // the object file which is used in the processing of an exception throw /
  // catch.
  // If any of the UnwindPlans have the address of the LSDA region for this
  // function,
  // this will return it.
  Address GetLSDAAddress(Target &target);

  // A function may have a Personality Routine associated with it -- used in the
  // processing of throwing an exception.  If any of the UnwindPlans have the
  // address of the personality routine, this will return it.  Read the
  // target-pointer
  // at this address to get the personality function address.
  Address GetPersonalityRoutinePtrAddress(Target &target);

  // The following methods to retrieve specific unwind plans should rarely be
  // used.
  // Instead, clients should ask for the *behavior* they are looking for, using
  // one
  // of the above UnwindPlan retrieval methods.

  lldb::UnwindPlanSP GetAssemblyUnwindPlan(Target &target, Thread &thread,
                                           int current_offset);

  lldb::UnwindPlanSP GetEHFrameUnwindPlan(Target &target, int current_offset);

  lldb::UnwindPlanSP GetEHFrameAugmentedUnwindPlan(Target &target,
                                                   Thread &thread,
                                                   int current_offset);

  lldb::UnwindPlanSP GetCompactUnwindUnwindPlan(Target &target,
                                                int current_offset);

  lldb::UnwindPlanSP GetArmUnwindUnwindPlan(Target &target, int current_offset);

  lldb::UnwindPlanSP GetArchDefaultUnwindPlan(Thread &thread);

  lldb::UnwindPlanSP GetArchDefaultAtFuncEntryUnwindPlan(Thread &thread);

private:
  lldb::UnwindAssemblySP GetUnwindAssemblyProfiler(Target &target);

  // Do a simplistic comparison for the register restore rule for getting
  // the caller's pc value on two UnwindPlans -- returns LazyBoolYes if
  // they have the same unwind rule for the pc, LazyBoolNo if they do not
  // have the same unwind rule for the pc, and LazyBoolCalculate if it was
  // unable to determine this for some reason.
  lldb_private::LazyBool CompareUnwindPlansForIdenticalInitialPCLocation(
      Thread &thread, const lldb::UnwindPlanSP &a, const lldb::UnwindPlanSP &b);

  UnwindTable &m_unwind_table;
  AddressRange m_range;

  std::recursive_mutex m_mutex;

  lldb::UnwindPlanSP m_unwind_plan_assembly_sp;
  lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp;
  lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp; // augmented by
                                                          // assembly inspection
                                                          // so it's valid
                                                          // everywhere
  std::vector<lldb::UnwindPlanSP> m_unwind_plan_compact_unwind;
  lldb::UnwindPlanSP m_unwind_plan_arm_unwind_sp;
  lldb::UnwindPlanSP m_unwind_plan_fast_sp;
  lldb::UnwindPlanSP m_unwind_plan_arch_default_sp;
  lldb::UnwindPlanSP m_unwind_plan_arch_default_at_func_entry_sp;

  // Fetching the UnwindPlans can be expensive - if we've already attempted
  // to get one & failed, don't try again.
  bool m_tried_unwind_plan_assembly : 1, m_tried_unwind_plan_eh_frame : 1,
      m_tried_unwind_plan_eh_frame_augmented : 1,
      m_tried_unwind_plan_compact_unwind : 1,
      m_tried_unwind_plan_arm_unwind : 1, m_tried_unwind_fast : 1,
      m_tried_unwind_arch_default : 1,
      m_tried_unwind_arch_default_at_func_entry : 1;

  Address m_first_non_prologue_insn;

  DISALLOW_COPY_AND_ASSIGN(FuncUnwinders);

}; // class FuncUnwinders

} // namespace lldb_private

#endif // liblldb_FuncUnwinders_h