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 &section);
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 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     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
164