/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Symbol/CompactUnwindInfo.h
Line | Count | Source (jump to first uncovered line) |
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 | 20.6k | UnwindIndex() = default; |
67 | | |
68 | 15.8k | bool operator<(const CompactUnwindInfo::UnwindIndex &rhs) const { |
69 | 15.8k | return function_offset < rhs.function_offset; |
70 | 15.8k | } |
71 | | |
72 | 0 | bool operator==(const CompactUnwindInfo::UnwindIndex &rhs) const { |
73 | 0 | return function_offset == rhs.function_offset; |
74 | 0 | } |
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 | 7.92k | FunctionInfo() = default; |
90 | | }; |
91 | | |
92 | | struct UnwindHeader { |
93 | | uint32_t version; |
94 | | uint32_t common_encodings_array_offset = 0; |
95 | | uint32_t common_encodings_array_count = 0; |
96 | | uint32_t personality_array_offset = 0; |
97 | | uint32_t personality_array_count = 0; |
98 | | |
99 | 5.60k | UnwindHeader() = 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 m_unwind_header; |
159 | | }; |
160 | | |
161 | | } // namespace lldb_private |
162 | | |
163 | | #endif // LLDB_SYMBOL_COMPACTUNWINDINFO_H |