1 | //===-- CompactUnwindInfo.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_COMPACTUNWINDINFO_H |
10 | #define LLDB_SYMBOL_COMPACTUNWINDINFO_H |
11 | |
12 | #include "lldb/Symbol/ObjectFile.h" |
13 | #include "lldb/Symbol/UnwindPlan.h" |
14 | #include "lldb/Utility/DataExtractor.h" |
15 | #include "lldb/Utility/RangeMap.h" |
16 | #include "lldb/lldb-private.h" |
17 | #include <mutex> |
18 | #include <vector> |
19 | |
20 | namespace lldb_private { |
21 | |
22 | // Compact Unwind info is an unwind format used on Darwin. The unwind |
23 | // instructions for typical compiler-generated functions can be expressed in a |
24 | // 32-bit encoding. The format includes a two-level index so the unwind |
25 | // information for a function can be found by two binary searches in the |
26 | // section. It can represent both stack frames that use a frame-pointer |
27 | // register and frameless functions, on i386/x86_64 for instance. When a |
28 | // function is too complex to be represented in the compact unwind format, it |
29 | // calls out to eh_frame unwind instructions. |
30 | |
31 | // On Mac OS X / iOS, a function will have either a compact unwind |
32 | // representation or an eh_frame representation. If lldb is going to benefit |
33 | // from the compiler's description about saved register locations, it must be |
34 | // able to read both sources of information. |
35 | |
36 | class CompactUnwindInfo { |
37 | public: |
38 | CompactUnwindInfo(ObjectFile &objfile, lldb::SectionSP §ion); |
39 | |
40 | ~CompactUnwindInfo(); |
41 | |
42 | bool GetUnwindPlan(Target &target, Address addr, UnwindPlan &unwind_plan); |
43 | |
44 | bool IsValid(const lldb::ProcessSP &process_sp); |
45 | |
46 | private: |
47 | // The top level index entries of the compact unwind info |
48 | // (internal representation of struct |
49 | // unwind_info_section_header_index_entry) |
50 | // There are relatively few of these (one per 500/1000 functions, depending |
51 | // on format) so creating them on first scan will not be too costly. |
52 | struct UnwindIndex { |
53 | uint32_t function_offset = 0; // The offset of the first function covered by |
54 | // this index |
55 | uint32_t second_level = 0; // The offset (inside unwind_info sect) to the |
56 | // second level page for this index |
57 | // (either UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED) |
58 | uint32_t lsda_array_start = 0; // The offset (inside unwind_info sect) LSDA |
59 | // array for this index |
60 | uint32_t lsda_array_end = |
61 | 0; // The offset to the LSDA array for the NEXT index |
62 | bool sentinal_entry = false; // There is an empty index at the end which |
63 | // provides the upper bound of |
64 | // function addresses that are described |
65 | |
66 | UnwindIndex() = default; |
67 | |
68 | bool operator<(const CompactUnwindInfo::UnwindIndex &rhs) const { |
69 | return function_offset < rhs.function_offset; |
70 | } |
71 | |
72 | bool operator==(const CompactUnwindInfo::UnwindIndex &rhs) const { |
73 | return function_offset == rhs.function_offset; |
74 | } |
75 | }; |
76 | |
77 | // An internal object used to store the information we retrieve about a |
78 | // function -- the encoding bits and possibly the LSDA/personality function. |
79 | struct FunctionInfo { |
80 | uint32_t encoding = 0; // compact encoding 32-bit value for this function |
81 | Address lsda_address; // the address of the LSDA data for this function |
82 | Address personality_ptr_address; // the address where the personality |
83 | // routine addr can be found |
84 | |
85 | uint32_t valid_range_offset_start = 0; // first offset that this encoding is |
86 | // valid for (start of the function) |
87 | uint32_t valid_range_offset_end = |
88 | 0; // the offset of the start of the next function |
89 | FunctionInfo() = default; |
90 | }; |
91 | |
92 | struct { |
93 | uint32_t ; |
94 | uint32_t = 0; |
95 | uint32_t = 0; |
96 | uint32_t = 0; |
97 | uint32_t = 0; |
98 | |
99 | () = default; |
100 | }; |
101 | |
102 | void ScanIndex(const lldb::ProcessSP &process_sp); |
103 | |
104 | bool GetCompactUnwindInfoForFunction(Target &target, Address address, |
105 | FunctionInfo &unwind_info); |
106 | |
107 | lldb::offset_t |
108 | BinarySearchRegularSecondPage(uint32_t entry_page_offset, |
109 | uint32_t entry_count, uint32_t function_offset, |
110 | uint32_t *entry_func_start_offset, |
111 | uint32_t *entry_func_end_offset); |
112 | |
113 | uint32_t BinarySearchCompressedSecondPage(uint32_t entry_page_offset, |
114 | uint32_t entry_count, |
115 | uint32_t function_offset_to_find, |
116 | uint32_t function_offset_base, |
117 | uint32_t *entry_func_start_offset, |
118 | uint32_t *entry_func_end_offset); |
119 | |
120 | uint32_t GetLSDAForFunctionOffset(uint32_t lsda_offset, uint32_t lsda_count, |
121 | uint32_t function_offset); |
122 | |
123 | bool CreateUnwindPlan_x86_64(Target &target, FunctionInfo &function_info, |
124 | UnwindPlan &unwind_plan, |
125 | Address pc_or_function_start); |
126 | |
127 | bool CreateUnwindPlan_i386(Target &target, FunctionInfo &function_info, |
128 | UnwindPlan &unwind_plan, |
129 | Address pc_or_function_start); |
130 | |
131 | bool CreateUnwindPlan_arm64(Target &target, FunctionInfo &function_info, |
132 | UnwindPlan &unwind_plan, |
133 | Address pc_or_function_start); |
134 | |
135 | bool CreateUnwindPlan_armv7(Target &target, FunctionInfo &function_info, |
136 | UnwindPlan &unwind_plan, |
137 | Address pc_or_function_start); |
138 | |
139 | ObjectFile &m_objfile; |
140 | lldb::SectionSP m_section_sp; |
141 | lldb::WritableDataBufferSP |
142 | m_section_contents_if_encrypted; // if the binary is |
143 | // encrypted, read the |
144 | // sect contents |
145 | // out of live memory and cache them here |
146 | std::mutex m_mutex; |
147 | std::vector<UnwindIndex> m_indexes; |
148 | |
149 | LazyBool m_indexes_computed; // eLazyBoolYes once we've tried to parse the |
150 | // unwind info |
151 | // eLazyBoolNo means we cannot parse the unwind info & should not retry |
152 | // eLazyBoolCalculate means we haven't tried to parse it yet |
153 | |
154 | DataExtractor m_unwindinfo_data; |
155 | bool m_unwindinfo_data_computed; // true once we've mapped in the unwindinfo |
156 | // data |
157 | |
158 | UnwindHeader ; |
159 | }; |
160 | |
161 | } // namespace lldb_private |
162 | |
163 | #endif // LLDB_SYMBOL_COMPACTUNWINDINFO_H |
164 | |