aboutsummaryrefslogtreecommitdiff
path: root/include/mach-o/unwind.h
blob: 44635dd9793e9d786a170d4c53f1ab6777c6e203 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/* Mach-O compact unwind encoding.
   Copyright (C) 2014-2022 Free Software Foundation, Inc.

   This file is part of BFD, the Binary File Descriptor library.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

#ifndef _MACH_O_UNWIND_H
#define _MACH_O_UNWIND_H

/* Encodings bits for all cpus.  */
#define MACH_O_UNWIND_IS_NOT_FUNCTION_START 0x80000000
#define MACH_O_UNWIND_HAS_LSDA              0x40000000
#define MACH_O_UNWIND_PERSONALITY_MASK      0x30000000
#define MACH_O_UNWIND_PERSONALITY_SHIFT     28

/* Encodings for x86-64.  */

/* Kind of encoding (4 bits).  */
#define MACH_O_UNWIND_X86_64_MODE_MASK       0x0f000000

/* Frame is RBP based, using the standard sequence: push %rbp; mov %rsp, %rbp.
   Non-volatile registers must be saved in the stack starting at %rbp-8 to
   %rbp-2040 (offset is encoded in offset bits * 8).  Registers saved are
   encoded in registers bits, 3 bits per register.  */
#define MACH_O_UNWIND_X86_64_MODE_RBP_FRAME  0x01000000
#define  MACH_O_UNWIND_X86_64_RBP_FRAME_REGISTERS 0x00007FFF
#define  MACH_O_UNWIND_X86_64_RBP_FRAME_OFFSET    0x00FF0000

/* Frameless function, with a small stack size.  */
#define MACH_O_UNWIND_X86_64_MODE_STACK_IMMD 0x02000000
#define  MACH_O_UNWIND_X86_64_FRAMELESS_STACK_SIZE      0x00FF0000
#define  MACH_O_UNWIND_X86_64_FRAMELESS_REG_COUNT       0x00001C00
#define  MACH_O_UNWIND_X86_64_FRAMELESS_REG_PERMUTATION 0x000003FF

/* Frameless function, with a larger stack size. The stack size is the sum
   of the X in subq $X,%rsp (address of X is at function + stack size bits)
   and stack adjust.  */
#define MACH_O_UNWIND_X86_64_MODE_STACK_IND          0x03000000
#define  MACH_O_UNWIND_X86_64_FRAMELESS_STACK_ADJUST 0x0000E000

/* Use dwarf.  */
#define MACH_O_UNWIND_X86_64_MODE_DWARF      0x04000000
#define  MACH_O_UNWIND_X86_64_DWARF_SECTION_OFFSET 0x00ffffff

/* Registers.  */
#define MACH_O_UNWIND_X86_64_REG_NONE 0
#define MACH_O_UNWIND_X86_64_REG_RBX 1
#define MACH_O_UNWIND_X86_64_REG_R12 2
#define MACH_O_UNWIND_X86_64_REG_R13 3
#define MACH_O_UNWIND_X86_64_REG_R14 4
#define MACH_O_UNWIND_X86_64_REG_R15 5
#define MACH_O_UNWIND_X86_64_REG_RBP 6

/* Encodings for x86 (almot the same as x86-64).  */

/* Kind of encoding (4 bits).  */
#define MACH_O_UNWIND_X86_MODE_MASK       0x0f000000

/* Frame is EBP based, using the standard sequence: push %ebp; mov %esp, %ebp.
   Non-volatile registers must be saved in the stack starting at %ebp-4 to
   %ebp-240 (offset is encoded in offset bits * 4).  Registers saved are
   encoded in registers bits, 3 bits per register.  */
#define MACH_O_UNWIND_X86_MODE_EBP_FRAME  0x01000000
#define  MACH_O_UNWIND_X86_EBP_FRAME_REGISTERS 0x00007FFF
#define  MACH_O_UNWIND_X86_EBP_FRAME_OFFSET    0x00FF0000

/* Frameless function, with a small stack size.  */
#define MACH_O_UNWIND_X86_MODE_STACK_IMMD 0x02000000
#define  MACH_O_UNWIND_X86_FRAMELESS_STACK_SIZE      0x00FF0000
#define  MACH_O_UNWIND_X86_FRAMELESS_REG_COUNT       0x00001C00
#define  MACH_O_UNWIND_X86_FRAMELESS_REG_PERMUTATION 0x000003FF

/* Frameless function, with a larger stack size. The stack size is the sum
   of the X in subq $X,%esp (address of X is at function + stack size bits)
   and stack adjust.  */
#define MACH_O_UNWIND_X86_MODE_STACK_IND          0x03000000
#define  MACH_O_UNWIND_X86_FRAMELESS_STACK_ADJUST 0x0000E000

/* Use dwarf.  */
#define MACH_O_UNWIND_X86_MODE_DWARF      0x04000000
#define  MACH_O_UNWIND_X86_DWARF_SECTION_OFFSET 0x00ffffff

/* Registers.  */
#define MACH_O_UNWIND_X86_REG_NONE 0
#define MACH_O_UNWIND_X86_REG_EBX 1
#define MACH_O_UNWIND_X86_REG_ECX 2
#define MACH_O_UNWIND_X86_REG_EDX 3
#define MACH_O_UNWIND_X86_REG_EDI 4
#define MACH_O_UNWIND_X86_REG_ESI 5
#define MACH_O_UNWIND_X86_REG_EBP 6

/* Encodings for arm64.  */

#define MACH_O_UNWIND_ARM64_MODE_MASK		0x0f000000

/* Leaf function:  FP/LR are *not* saved, none or some non-volatile registers
   are saved, stack is allocated.  The size of the frame (register saved and
   memory) is encoded in STACK_SIZE in 16 byte units.  */
#define MACH_O_UNWIND_ARM64_MODE_FRAMELESS	0x02000000

#define MACH_O_UNWIND_ARM64_MODE_DWARF		0x03000000

/* Standard frame: FP/LR are pushed, SP is copied to FP, then non-volatile
   registers are saved.  */
#define MACH_O_UNWIND_ARM64_MODE_FRAME		0x04000000

/* Registers (for FRAME).  */
#define MACH_O_UNWIND_ARM64_FRAME_X19_X20_PAIR	0x00000001
#define MACH_O_UNWIND_ARM64_FRAME_X21_X22_PAIR	0x00000002
#define MACH_O_UNWIND_ARM64_FRAME_X23_X24_PAIR	0x00000004
#define MACH_O_UNWIND_ARM64_FRAME_X25_X26_PAIR	0x00000008
#define MACH_O_UNWIND_ARM64_FRAME_X27_X28_PAIR	0x00000010
#define MACH_O_UNWIND_ARM64_FRAME_D8_D9_PAIR	0x00000100
#define MACH_O_UNWIND_ARM64_FRAME_D10_D11_PAIR	0x00000200
#define MACH_O_UNWIND_ARM64_FRAME_D12_D13_PAIR	0x00000400
#define MACH_O_UNWIND_ARM64_FRAME_D14_D15_PAIR	0x00000800

#define MACH_O_UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK 0x00fff000
#define MACH_O_UNWIND_ARM64_DWARF_SECTION_OFFSET 0x00ffffff

/* Entry in object file (in __LD,__compact_unwind section).  */

struct mach_o_compact_unwind_32
{
  unsigned char start[4];
  unsigned char length[4];
  unsigned char encoding[4];
  unsigned char personality[4];
  unsigned char lsda[4];
};

struct mach_o_compact_unwind_64
{
  unsigned char start[8];
  unsigned char length[4];
  unsigned char encoding[4];
  unsigned char personality[8];
  unsigned char lsda[8];
};

/* Header in images (in __TEXT,__unwind_info).  */

#define MACH_O_UNWIND_SECTION_VERSION 1 /* Current verion in header.  */
struct mach_o_unwind_info_header
{
  unsigned char version[4];	/* Currently MACH_O_UNWIND_SECTION_VERSION. */
  unsigned char encodings_array_offset[4];
  unsigned char encodings_array_count[4];
  unsigned char personality_array_offset[4];
  unsigned char personality_array_count[4];
  unsigned char index_offset[4];
  unsigned char index_count[4];
  /* Followed by:
     - encodings array
       These are the encodings shared, for index < encoding_array_count
     - personality array
       count given by personality_array_count
     - index entries
       count given by index_count
     - lsda index entries
       last offset given by lsda offset of last index_entry.
  */
};

struct mach_o_unwind_index_entry
{
  unsigned char function_offset[4];
  unsigned char second_level_offset[4];
  unsigned char lsda_index_offset[4];
};

struct mach_o_unwind_lsda_index_entry
{
  unsigned char function_offset[4];
  unsigned char lsda_offset[4];
};

/* Second level index pages.  */

#define MACH_O_UNWIND_SECOND_LEVEL_REGULAR 2
struct mach_o_unwind_regular_second_level_page_header
{
  unsigned char kind[4];
  unsigned char entry_page_offset[2];
  unsigned char entry_count[2];
  /* Array of entries.  */
};

struct mach_o_unwind_regular_second_level_entry
{
  unsigned char function_offset[4];
  unsigned char encoding[4];
};

#define MACH_O_UNWIND_SECOND_LEVEL_COMPRESSED 3
struct mach_o_unwind_compressed_second_level_page_header
{
  unsigned char kind[4];
  unsigned char entry_page_offset[2];
  unsigned char entry_count[2];
  unsigned char encodings_offset[2];
  unsigned char encodings_count[2];
  /* Followed by entries array (one word, see below).  */
  /* Followed by (non-common) encodings array.  */
};

/* Compressed entries are one word, containing function offset and encoding
   index.  */
#define MACH_O_UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(en) \
   ((en) & 0x00FFFFFF)
#define MACH_O_UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(en) \
   (((en) >> 24) & 0xFF)

#endif /* _MACH_O_UNWIND_H */