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 liblldb_CompactUnwindInfo_h_
10#define liblldb_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
20namespace 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
36class CompactUnwindInfo {
37public:
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
46private:
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; // The offset of the first function covered by
54                              // this index
55    uint32_t second_level; // The offset (inside unwind_info sect) to the second
56                           // level page for this index
57    // (either UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED)
58    uint32_t lsda_array_start; // The offset (inside unwind_info sect) LSDA
59                               // array for this index
60    uint32_t lsda_array_end; // The offset to the LSDA array for the NEXT index
61    bool sentinal_entry; // There is an empty index at the end which provides
62                         // the upper bound of
63    // function addresses that are described
64
65    UnwindIndex()
66        : function_offset(0), second_level(0), lsda_array_start(0),
67          lsda_array_end(0), sentinal_entry(false) {}
68
69    bool operator<(const CompactUnwindInfo::UnwindIndex &rhs) const {
70      return function_offset < rhs.function_offset;
71    }
72
73    bool operator==(const CompactUnwindInfo::UnwindIndex &rhs) const {
74      return function_offset == rhs.function_offset;
75    }
76  };
77
78  // An internal object used to store the information we retrieve about a
79  // function -- the encoding bits and possibly the LSDA/personality function.
80  struct FunctionInfo {
81    uint32_t encoding;    // compact encoding 32-bit value for this function
82    Address lsda_address; // the address of the LSDA data for this function
83    Address personality_ptr_address; // the address where the personality
84                                     // routine addr can be found
85
86    uint32_t valid_range_offset_start; // first offset that this encoding is
87                                       // valid for (start of the function)
88    uint32_t
89        valid_range_offset_end; // the offset of the start of the next function
90    FunctionInfo()
91        : encoding(0), lsda_address(), personality_ptr_address(),
92          valid_range_offset_start(0), valid_range_offset_end(0) {}
93  };
94
95  struct UnwindHeader {
96    uint32_t version;
97    uint32_t common_encodings_array_offset;
98    uint32_t common_encodings_array_count;
99    uint32_t personality_array_offset;
100    uint32_t personality_array_count;
101
102    UnwindHeader()
103        : common_encodings_array_offset(0), common_encodings_array_count(0),
104          personality_array_offset(0), personality_array_count(0) {}
105  };
106
107  void ScanIndex(const lldb::ProcessSP &process_sp);
108
109  bool GetCompactUnwindInfoForFunction(Target &target, Address address,
110                                       FunctionInfo &unwind_info);
111
112  lldb::offset_t
113  BinarySearchRegularSecondPage(uint32_t entry_page_offset,
114                                uint32_t entry_count, uint32_t function_offset,
115                                uint32_t *entry_func_start_offset,
116                                uint32_t *entry_func_end_offset);
117
118  uint32_t BinarySearchCompressedSecondPage(uint32_t entry_page_offset,
119                                            uint32_t entry_count,
120                                            uint32_t function_offset_to_find,
121                                            uint32_t function_offset_base,
122                                            uint32_t *entry_func_start_offset,
123                                            uint32_t *entry_func_end_offset);
124
125  uint32_t GetLSDAForFunctionOffset(uint32_t lsda_offset, uint32_t lsda_count,
126                                    uint32_t function_offset);
127
128  bool CreateUnwindPlan_x86_64(Target &target, FunctionInfo &function_info,
129                               UnwindPlan &unwind_plan,
130                               Address pc_or_function_start);
131
132  bool CreateUnwindPlan_i386(Target &target, FunctionInfo &function_info,
133                             UnwindPlan &unwind_plan,
134                             Address pc_or_function_start);
135
136  bool CreateUnwindPlan_arm64(Target &target, FunctionInfo &function_info,
137                              UnwindPlan &unwind_plan,
138                              Address pc_or_function_start);
139
140  bool CreateUnwindPlan_armv7(Target &target, FunctionInfo &function_info,
141                              UnwindPlan &unwind_plan,
142                              Address pc_or_function_start);
143
144  ObjectFile &m_objfile;
145  lldb::SectionSP m_section_sp;
146  lldb::DataBufferSP m_section_contents_if_encrypted; // if the binary is
147                                                      // encrypted, read the
148                                                      // sect contents
149  // out of live memory and cache them here
150  std::mutex m_mutex;
151  std::vector<UnwindIndex> m_indexes;
152
153  LazyBool m_indexes_computed; // eLazyBoolYes once we've tried to parse the
154                               // unwind info
155  // eLazyBoolNo means we cannot parse the unwind info & should not retry
156  // eLazyBoolCalculate means we haven't tried to parse it yet
157
158  DataExtractor m_unwindinfo_data;
159  bool m_unwindinfo_data_computed; // true once we've mapped in the unwindinfo
160                                   // data
161
162  UnwindHeader m_unwind_header;
163};
164
165} // namespace lldb_private
166
167#endif // liblldb_CompactUnwindInfo_h_
168