1278332Semaste//===-- CompactUnwindInfo.h -------------------------------------*- C++ -*-===//
2278332Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6278332Semaste//
7278332Semaste//===----------------------------------------------------------------------===//
8278332Semaste
9278332Semaste#ifndef liblldb_CompactUnwindInfo_h_
10278332Semaste#define liblldb_CompactUnwindInfo_h_
11278332Semaste
12278332Semaste#include "lldb/Symbol/ObjectFile.h"
13278332Semaste#include "lldb/Symbol/UnwindPlan.h"
14321369Sdim#include "lldb/Utility/DataExtractor.h"
15353358Sdim#include "lldb/Utility/RangeMap.h"
16278332Semaste#include "lldb/lldb-private.h"
17353358Sdim#include <mutex>
18353358Sdim#include <vector>
19278332Semaste
20278332Semastenamespace lldb_private {
21278332Semaste
22314564Sdim// Compact Unwind info is an unwind format used on Darwin.  The unwind
23341825Sdim// instructions for typical compiler-generated functions can be expressed in a
24341825Sdim// 32-bit encoding. The format includes a two-level index so the unwind
25341825Sdim// information for a function can be found by two binary searches in the
26341825Sdim// section.  It can represent both stack frames that use a frame-pointer
27341825Sdim// register and frameless functions, on i386/x86_64 for instance.  When a
28341825Sdim// function is too complex to be represented in the compact unwind format, it
29341825Sdim// calls out to eh_frame unwind instructions.
30278332Semaste
31314564Sdim// On Mac OS X / iOS, a function will have either a compact unwind
32341825Sdim// representation or an eh_frame representation.  If lldb is going to benefit
33341825Sdim// from the compiler's description about saved register locations, it must be
34341825Sdim// able to read both sources of information.
35278332Semaste
36314564Sdimclass CompactUnwindInfo {
37278332Semastepublic:
38314564Sdim  CompactUnwindInfo(ObjectFile &objfile, lldb::SectionSP &section);
39278332Semaste
40314564Sdim  ~CompactUnwindInfo();
41278332Semaste
42314564Sdim  bool GetUnwindPlan(Target &target, Address addr, UnwindPlan &unwind_plan);
43278332Semaste
44314564Sdim  bool IsValid(const lldb::ProcessSP &process_sp);
45278332Semaste
46278332Semasteprivate:
47314564Sdim  // The top level index entries of the compact unwind info
48314564Sdim  //   (internal representation of struct
49314564Sdim  //   unwind_info_section_header_index_entry)
50341825Sdim  // There are relatively few of these (one per 500/1000 functions, depending
51341825Sdim  // on format) so creating them on first scan will not be too costly.
52314564Sdim  struct UnwindIndex {
53314564Sdim    uint32_t function_offset; // The offset of the first function covered by
54314564Sdim                              // this index
55314564Sdim    uint32_t second_level; // The offset (inside unwind_info sect) to the second
56314564Sdim                           // level page for this index
57314564Sdim    // (either UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED)
58314564Sdim    uint32_t lsda_array_start; // The offset (inside unwind_info sect) LSDA
59314564Sdim                               // array for this index
60314564Sdim    uint32_t lsda_array_end; // The offset to the LSDA array for the NEXT index
61314564Sdim    bool sentinal_entry; // There is an empty index at the end which provides
62314564Sdim                         // the upper bound of
63314564Sdim    // function addresses that are described
64278332Semaste
65314564Sdim    UnwindIndex()
66314564Sdim        : function_offset(0), second_level(0), lsda_array_start(0),
67314564Sdim          lsda_array_end(0), sentinal_entry(false) {}
68278332Semaste
69314564Sdim    bool operator<(const CompactUnwindInfo::UnwindIndex &rhs) const {
70314564Sdim      return function_offset < rhs.function_offset;
71314564Sdim    }
72278332Semaste
73314564Sdim    bool operator==(const CompactUnwindInfo::UnwindIndex &rhs) const {
74314564Sdim      return function_offset == rhs.function_offset;
75314564Sdim    }
76314564Sdim  };
77278332Semaste
78314564Sdim  // An internal object used to store the information we retrieve about a
79341825Sdim  // function -- the encoding bits and possibly the LSDA/personality function.
80314564Sdim  struct FunctionInfo {
81314564Sdim    uint32_t encoding;    // compact encoding 32-bit value for this function
82314564Sdim    Address lsda_address; // the address of the LSDA data for this function
83314564Sdim    Address personality_ptr_address; // the address where the personality
84314564Sdim                                     // routine addr can be found
85278332Semaste
86314564Sdim    uint32_t valid_range_offset_start; // first offset that this encoding is
87314564Sdim                                       // valid for (start of the function)
88314564Sdim    uint32_t
89314564Sdim        valid_range_offset_end; // the offset of the start of the next function
90314564Sdim    FunctionInfo()
91314564Sdim        : encoding(0), lsda_address(), personality_ptr_address(),
92314564Sdim          valid_range_offset_start(0), valid_range_offset_end(0) {}
93314564Sdim  };
94278332Semaste
95314564Sdim  struct UnwindHeader {
96314564Sdim    uint32_t version;
97314564Sdim    uint32_t common_encodings_array_offset;
98314564Sdim    uint32_t common_encodings_array_count;
99314564Sdim    uint32_t personality_array_offset;
100314564Sdim    uint32_t personality_array_count;
101278332Semaste
102314564Sdim    UnwindHeader()
103314564Sdim        : common_encodings_array_offset(0), common_encodings_array_count(0),
104314564Sdim          personality_array_offset(0), personality_array_count(0) {}
105314564Sdim  };
106278332Semaste
107314564Sdim  void ScanIndex(const lldb::ProcessSP &process_sp);
108278332Semaste
109314564Sdim  bool GetCompactUnwindInfoForFunction(Target &target, Address address,
110314564Sdim                                       FunctionInfo &unwind_info);
111278332Semaste
112314564Sdim  lldb::offset_t
113314564Sdim  BinarySearchRegularSecondPage(uint32_t entry_page_offset,
114314564Sdim                                uint32_t entry_count, uint32_t function_offset,
115314564Sdim                                uint32_t *entry_func_start_offset,
116314564Sdim                                uint32_t *entry_func_end_offset);
117278332Semaste
118314564Sdim  uint32_t BinarySearchCompressedSecondPage(uint32_t entry_page_offset,
119314564Sdim                                            uint32_t entry_count,
120314564Sdim                                            uint32_t function_offset_to_find,
121314564Sdim                                            uint32_t function_offset_base,
122314564Sdim                                            uint32_t *entry_func_start_offset,
123314564Sdim                                            uint32_t *entry_func_end_offset);
124278332Semaste
125314564Sdim  uint32_t GetLSDAForFunctionOffset(uint32_t lsda_offset, uint32_t lsda_count,
126314564Sdim                                    uint32_t function_offset);
127278332Semaste
128314564Sdim  bool CreateUnwindPlan_x86_64(Target &target, FunctionInfo &function_info,
129314564Sdim                               UnwindPlan &unwind_plan,
130314564Sdim                               Address pc_or_function_start);
131278332Semaste
132314564Sdim  bool CreateUnwindPlan_i386(Target &target, FunctionInfo &function_info,
133314564Sdim                             UnwindPlan &unwind_plan,
134314564Sdim                             Address pc_or_function_start);
135278332Semaste
136314564Sdim  bool CreateUnwindPlan_arm64(Target &target, FunctionInfo &function_info,
137314564Sdim                              UnwindPlan &unwind_plan,
138314564Sdim                              Address pc_or_function_start);
139278332Semaste
140314564Sdim  bool CreateUnwindPlan_armv7(Target &target, FunctionInfo &function_info,
141314564Sdim                              UnwindPlan &unwind_plan,
142314564Sdim                              Address pc_or_function_start);
143309124Sdim
144314564Sdim  ObjectFile &m_objfile;
145314564Sdim  lldb::SectionSP m_section_sp;
146314564Sdim  lldb::DataBufferSP m_section_contents_if_encrypted; // if the binary is
147314564Sdim                                                      // encrypted, read the
148314564Sdim                                                      // sect contents
149314564Sdim  // out of live memory and cache them here
150314564Sdim  std::mutex m_mutex;
151314564Sdim  std::vector<UnwindIndex> m_indexes;
152309124Sdim
153314564Sdim  LazyBool m_indexes_computed; // eLazyBoolYes once we've tried to parse the
154314564Sdim                               // unwind info
155314564Sdim  // eLazyBoolNo means we cannot parse the unwind info & should not retry
156314564Sdim  // eLazyBoolCalculate means we haven't tried to parse it yet
157278332Semaste
158314564Sdim  DataExtractor m_unwindinfo_data;
159314564Sdim  bool m_unwindinfo_data_computed; // true once we've mapped in the unwindinfo
160314564Sdim                                   // data
161278332Semaste
162314564Sdim  UnwindHeader m_unwind_header;
163278332Semaste};
164278332Semaste
165278332Semaste} // namespace lldb_private
166278332Semaste
167314564Sdim#endif // liblldb_CompactUnwindInfo_h_
168