Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
unwinding_records.h
Go to the documentation of this file.
1// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4// Class for patching compiled code.
5
6#ifndef RUNTIME_PLATFORM_UNWINDING_RECORDS_H_
7#define RUNTIME_PLATFORM_UNWINDING_RECORDS_H_
8
10
11namespace dart {
12
14 public:
15 static intptr_t SizeInBytes();
16
17 static void RegisterExecutableMemory(void* start,
18 intptr_t size,
19 void** pp_dynamic_table);
20 static void UnregisterDynamicTable(void* p_dynamic_table);
21};
22
23#if (defined(DART_TARGET_OS_WINDOWS) || defined(DART_HOST_OS_WINDOWS)) && \
24 defined(TARGET_ARCH_X64)
25
26#pragma pack(push, 1)
27//
28// Refer to https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64
29//
30typedef unsigned char UBYTE;
31typedef uint16_t USHORT;
32typedef union _UNWIND_CODE {
33 struct {
34 UBYTE CodeOffset;
35 UBYTE UnwindOp : 4;
36 UBYTE OpInfo : 4;
37 };
38 USHORT FrameOffset;
39} UNWIND_CODE, *PUNWIND_CODE;
40
41typedef struct _UNWIND_INFO {
42 UBYTE Version : 3;
43 UBYTE Flags : 5;
44 UBYTE SizeOfProlog;
45 UBYTE CountOfCodes;
46 UBYTE FrameRegister : 4;
47 UBYTE FrameOffset : 4;
48 UNWIND_CODE UnwindCode[2];
49} UNWIND_INFO, *PUNWIND_INFO;
50
51#if !defined(DART_HOST_OS_WINDOWS)
52typedef uint32_t ULONG;
53typedef struct _RUNTIME_FUNCTION {
54 ULONG BeginAddress;
55 ULONG EndAddress;
56 ULONG UnwindData;
57} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
58#endif
59
60static constexpr int kPushRbpInstructionLength = 1;
61static const int kMovRbpRspInstructionLength = 3;
62static constexpr int kRbpPrefixLength =
63 kPushRbpInstructionLength + kMovRbpRspInstructionLength;
64static constexpr int kRBP = 5;
65
66#ifndef UNW_FLAG_NHANDLER
67#define UNW_FLAG_NHANDLER 0
68#endif
69
70struct GeneratedCodeUnwindInfo {
71 UNWIND_INFO unwind_info;
72
73 GeneratedCodeUnwindInfo() {
74 unwind_info.Version = 1;
75 unwind_info.Flags = UNW_FLAG_NHANDLER;
76 unwind_info.SizeOfProlog = kRbpPrefixLength;
77 unwind_info.CountOfCodes = 2;
78 unwind_info.FrameRegister = kRBP;
79 unwind_info.FrameOffset = 0;
80 unwind_info.UnwindCode[0].CodeOffset = kRbpPrefixLength;
81 unwind_info.UnwindCode[0].UnwindOp = 3; // UWOP_SET_FPREG
82 unwind_info.UnwindCode[0].OpInfo = 0;
83 unwind_info.UnwindCode[1].CodeOffset = kPushRbpInstructionLength;
84 unwind_info.UnwindCode[1].UnwindOp = 0; // UWOP_PUSH_NONVOL
85 unwind_info.UnwindCode[1].OpInfo = kRBP;
86 }
87};
88
89static constexpr uint32_t kUnwindingRecordMagic = 0xAABBCCDD;
90
91struct CodeRangeUnwindingRecord {
92 void* dynamic_table;
93 uint32_t magic;
94 uint32_t runtime_function_count;
95 GeneratedCodeUnwindInfo unwind_info;
96 intptr_t exception_handler;
97 RUNTIME_FUNCTION runtime_function[1];
98};
99
100#pragma pack(pop)
101
102#elif defined(TARGET_ARCH_ARM64) && \
103 (defined(DART_TARGET_OS_WINDOWS) || defined(DART_HOST_OS_WINDOWS))
104
105#pragma pack(push, 1)
106
107// ARM64 unwind codes are defined in below doc.
108// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
109enum UnwindOp8Bit {
110 OpNop = 0xE3,
111 OpAllocS = 0x00,
112 OpSaveFpLr = 0x40,
113 OpSaveFpLrX = 0x80,
114 OpSetFp = 0xE1,
115 OpAddFp = 0xE2,
116 OpEnd = 0xE4,
117};
118
119typedef uint32_t UNWIND_CODE;
120
121constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0 = OpNop,
122 uint8_t code1 = OpNop,
123 uint8_t code2 = OpNop,
124 uint8_t code3 = OpNop) {
125 return static_cast<uint32_t>(code0) | (static_cast<uint32_t>(code1) << 8) |
126 (static_cast<uint32_t>(code2) << 16) |
127 (static_cast<uint32_t>(code3) << 24);
128}
129
130// UNWIND_INFO defines the static part (first 32-bit) of the .xdata record in
131// below doc.
132// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records
133struct UNWIND_INFO {
134 uint32_t FunctionLength : 18;
135 uint32_t Version : 2;
136 uint32_t X : 1;
137 uint32_t E : 1;
138 uint32_t EpilogCount : 5;
139 uint32_t CodeWords : 5;
140};
141
142#if !defined(DART_HOST_OS_WINDOWS)
143typedef uint32_t ULONG;
144typedef uint32_t DWORD;
145typedef struct _RUNTIME_FUNCTION {
146 ULONG BeginAddress;
147 ULONG EndAddress;
148 ULONG UnwindData;
149} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
150#endif
151
152/**
153 * Base on below doc, unwind record has 18 bits (unsigned) to encode function
154 * length, besides 2 LSB which are always 0.
155 * https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records
156 */
157static const int kMaxFunctionLength = ((1 << 18) - 1) << 2;
158
159static constexpr int kDefaultNumberOfUnwindCodeWords = 1;
160static constexpr int kMaxExceptionThunkSize = 16;
161static constexpr int kFunctionLengthShiftSize = 2;
162static constexpr int kFunctionLengthMask = (1 << kFunctionLengthShiftSize) - 1;
163
164// Generate an unwind code for "stp fp, lr, [sp, #pre_index_offset]!".
165inline uint8_t MakeOpSaveFpLrX(int pre_index_offset) {
166 // See unwind code save_fplr_x in
167 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
168 ASSERT(pre_index_offset <= -8);
169 ASSERT(pre_index_offset >= -512);
170 constexpr int kShiftSize = 3;
171 constexpr int kShiftMask = (1 << kShiftSize) - 1;
172 ASSERT((pre_index_offset & kShiftMask) == 0);
173 USE(kShiftMask);
174 // Solve for Z where -(Z+1)*8 = pre_index_offset.
175 int encoded_value = (-pre_index_offset >> kShiftSize) - 1;
176 return OpSaveFpLrX | encoded_value;
177}
178
179template <int kNumberOfUnwindCodeWords = kDefaultNumberOfUnwindCodeWords>
180struct UnwindData {
181 UNWIND_INFO unwind_info;
182 UNWIND_CODE unwind_codes[kNumberOfUnwindCodeWords];
183
184 UnwindData() {
185 memset(&unwind_info, 0, sizeof(UNWIND_INFO));
186 unwind_info.X = 0; // no exception handler
187 unwind_info.CodeWords = kNumberOfUnwindCodeWords;
188
189 // Generate unwind codes for the following prolog:
190 //
191 // stp fp, lr, [sp, #-kCallerSPOffset]!
192 // mov fp, sp
193 //
194 // This is a very rough approximation of the actual function prologs used in
195 // V8. In particular, we often push other data before the (fp, lr) pair,
196 // meaning the stack pointer computed for the caller frame is wrong. That
197 // error is acceptable when the unwinding info for the caller frame also
198 // depends on fp rather than sp, as is the case for V8 builtins and runtime-
199 // generated code.
200 static_assert(kNumberOfUnwindCodeWords >= 1);
201 uword kCallerSPOffset = -16;
202 unwind_codes[0] = Combine8BitUnwindCodes(
203 OpSetFp, MakeOpSaveFpLrX(kCallerSPOffset), OpEnd);
204
205 // Fill the rest with nops.
206 for (int i = 1; i < kNumberOfUnwindCodeWords; ++i) {
207 unwind_codes[i] = Combine8BitUnwindCodes();
208 }
209 }
210};
211
212static const uint32_t kDefaultRuntimeFunctionCount = 1;
213static constexpr uint32_t kUnwindingRecordMagic = 0xAABBCCEE;
214
215struct CodeRangeUnwindingRecord {
216 void* dynamic_table;
217 uint32_t magic;
218 uint32_t runtime_function_count;
219 UnwindData<> unwind_info;
220 uint32_t exception_handler;
221
222 // For Windows ARM64 unwinding, register 2 unwind_info for each code range,
223 // unwind_info for all full size ranges (1MB - 4 bytes) and unwind_info1 for
224 // the remaining non full size range. There is at most 1 range which is less
225 // than full size.
226 UnwindData<> unwind_info1;
227
228 // More RUNTIME_FUNCTION structs could follow below array because the number
229 // of RUNTIME_FUNCTION needed to cover given code range is computed at
230 // runtime.
231 RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount];
232};
233
234#pragma pack(pop)
235
236#endif // (defined(DART_TARGET_OS_WINDOWS) || defined(DART_HOST_OS_WINDOWS))
237
238} // namespace dart
239
240#endif // RUNTIME_PLATFORM_UNWINDING_RECORDS_H_
Version
static const SkScalar X
static void RegisterExecutableMemory(void *start, intptr_t size, void **pp_dynamic_table)
static void UnregisterDynamicTable(void *p_dynamic_table)
#define ASSERT(E)
uintptr_t uword
Definition globals.h:501
static void USE(T &&)
Definition globals.h:618
DWORD ULONG
unsigned long DWORD