ReactOS 0.4.17-dev-37-g0bfb40d
unwind.c
Go to the documentation of this file.
1/*
2 * Unit test suite for exception unwinding
3 *
4 * Copyright 2009, 2024 Alexandre Julliard
5 * Copyright 2020, 2021 Martin Storsjö
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include <stdarg.h>
23#include <stdio.h>
24
25#include "ntstatus.h"
26#define WIN32_NO_STATUS
27#include "windef.h"
28#include "winbase.h"
29#include "winnt.h"
30#include "winreg.h"
31#include "winnt.h"
32#include "winternl.h"
33#include "rtlsupportapi.h"
34#include "wine/test.h"
35
36#ifndef __i386__
37
38static void *code_mem;
40
41static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG_PTR, ULONG_PTR*, UNWIND_HISTORY_TABLE*);
42static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionTable)(ULONG_PTR, ULONG_PTR*, ULONG*);
43static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
44static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
45static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
46static DWORD (WINAPI *pRtlAddGrowableFunctionTable)(void**, RUNTIME_FUNCTION*, DWORD, DWORD, ULONG_PTR, ULONG_PTR);
47static void (WINAPI *pRtlGrowFunctionTable)(void*, DWORD);
48static void (WINAPI *pRtlDeleteGrowableFunctionTable)(void*);
49static NTSTATUS (WINAPI *pRtlVirtualUnwind2)(ULONG,ULONG_PTR,ULONG_PTR,RUNTIME_FUNCTION*,CONTEXT*,BOOLEAN*,void**,ULONG_PTR*,KNONVOLATILE_CONTEXT_POINTERS*,ULONG_PTR*,ULONG_PTR*,PEXCEPTION_ROUTINE*,ULONG);
50static NTSTATUS (WINAPI *pNtAllocateVirtualMemoryEx)(HANDLE,PVOID*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG);
51
52#ifdef __arm__
53
54#define UWOP_TWOBYTES(x) (((x) >> 8) & 0xff), ((x) & 0xff)
55#define UWOP_THREEBYTES(x) (((x) >> 16) & 0xff), (((x) >> 8) & 0xff), ((x) & 0xff)
56#define UWOP_FOURBYTES(x) (((x) >> 24) & 0xff), (((x) >> 16) & 0xff), (((x) >> 8) & 0xff), ((x) & 0xff)
57
58#define UWOP_ALLOC_SMALL(size) (0x00 | (size/4)) /* Max 0x7f * 4 */
59#define UWOP_SAVE_REGSW(regmask) UWOP_TWOBYTES((0x80 << 8) | (regmask))
60#define UWOP_SET_FP(reg) (0xC0 | reg)
61#define UWOP_SAVE_RANGE_4_7_LR(reg,lr) (0xD0 | (reg - 4) | ((lr) ? 0x04 : 0))
62#define UWOP_SAVE_RANGE_4_11_LR(reg,lr)(0xD8 | (reg - 8) | ((lr) ? 0x04 : 0))
63#define UWOP_SAVE_D8_RANGE(reg) (0xE0 | (reg - 8))
64#define UWOP_ALLOC_MEDIUMW(size) UWOP_TWOBYTES((0xE8 << 8) | (size/4)) /* Max 0x3ff * 4 */
65#define UWOP_SAVE_REGS(regmask) UWOP_TWOBYTES((0xEC << 8) | ((regmask) & 0xFF) | (((regmask) & (1<<lr)) ? 0x100 : 0))
66#define UWOP_SAVE_LR(offset) UWOP_TWOBYTES((0xEF << 8) | (offset/4))
67#define UWOP_SAVE_D0_RANGE(first,last) UWOP_TWOBYTES((0xF5 << 8) | (first << 4) | (last))
68#define UWOP_SAVE_D16_RANGE(first,last)UWOP_TWOBYTES((0xF6 << 8) | ((first - 16) << 4) | (last - 16))
69#define UWOP_ALLOC_LARGE(size) UWOP_THREEBYTES((0xF7 << 16) | (size/4))
70#define UWOP_ALLOC_HUGE(size) UWOP_FOURBYTES((0xF8u << 24) | (size/4))
71#define UWOP_ALLOC_LARGEW(size) UWOP_THREEBYTES((0xF9 << 16) | (size/4))
72#define UWOP_ALLOC_HUGEW(size) UWOP_FOURBYTES((0xFAu << 24) | (size/4))
73#define UWOP_MSFT_OP_MACHINE_FRAME 0xEE,0x01
74#define UWOP_MSFT_OP_CONTEXT 0xEE,0x02
75#define UWOP_NOP16 0xFB
76#define UWOP_NOP32 0xFC
77#define UWOP_END_NOP16 0xFD
78#define UWOP_END_NOP32 0xFE
79#define UWOP_END 0xFF
80
81struct results_arm
82{
83 int pc_offset; /* pc offset from code start */
84 int fp_offset; /* fp offset from stack pointer */
85 int handler; /* expect handler to be set? */
86 ULONG_PTR pc; /* expected final pc value */
87 ULONG_PTR frame; /* expected frame return value */
88 int frame_offset; /* whether the frame return value is an offset or an absolute value */
89 LONGLONG regs[47][2];/* expected values for registers */
90};
91
92struct unwind_test_arm
93{
94 const BYTE *function;
95 size_t function_size;
96 const BYTE *unwind_info;
97 size_t unwind_size;
98 const struct results_arm *results;
99 unsigned int nb_results;
100};
101
102enum regs
103{
104 /* Note, lr and sp are swapped to allow using 'lr' in register bitmasks. */
105 r0, r1, r2, r3, r4, r5, r6, r7,
106 r8, r9, r10, r11, r12, lr, sp,
107 d0, d1, d2, d3, d4, d5, d6, d7,
108 d8, d9, d10, d11, d12, d13, d14, d15,
109 d16, d17, d18, d19, d20, d21, d22, d23,
110 d24, d25, d26, d27, d28, d29, d30, d31,
111};
112
113static const char * const reg_names_arm[47] =
114{
115 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
116 "r8", "r9", "r10", "r11", "r12", "lr", "sp",
117 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
118 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
119 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
120 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
121};
122
123#define ORIG_LR 0xCCCCCCCC
124
125static void call_virtual_unwind_arm( int testnum, const struct unwind_test_arm *test )
126{
127 static const int code_offset = 1024;
128 static const int unwind_offset = 2048;
129 void *data;
133 RUNTIME_FUNCTION runtime_func;
134 KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
135 UINT i, j, k;
136 ULONG fake_stack[256];
137 ULONG_PTR frame, orig_pc, orig_fp, unset_reg;
138 ULONGLONG unset_reg64;
139 static const UINT nb_regs = ARRAY_SIZE(test->results[i].regs);
140
141 memcpy( (char *)code_mem + code_offset, test->function, test->function_size );
142 if (test->unwind_info)
143 {
144 memcpy( (char *)code_mem + unwind_offset, test->unwind_info, test->unwind_size );
145 runtime_func.BeginAddress = code_offset;
146 if (test->unwind_size)
147 runtime_func.UnwindData = unwind_offset;
148 else
149 memcpy(&runtime_func.UnwindData, test->unwind_info, 4);
150 }
151
152 for (i = 0; i < test->nb_results; i++)
153 {
154 memset( &ctx_ptr, 0, sizeof(ctx_ptr) );
155 memset( &context, 0x55, sizeof(context) );
156 memset( &unset_reg, 0x55, sizeof(unset_reg) );
157 memset( &unset_reg64, 0x55, sizeof(unset_reg64) );
158 for (j = 0; j < 256; j++) fake_stack[j] = j * 4;
159
160 context.Sp = (ULONG_PTR)fake_stack;
161 context.Lr = (ULONG_PTR)ORIG_LR;
162 context.R11 = (ULONG_PTR)fake_stack + test->results[i].fp_offset;
163 orig_fp = context.R11;
164 orig_pc = (ULONG_PTR)code_mem + code_offset + test->results[i].pc_offset;
165
166 trace( "%u/%u: pc=%p (%02x) fp=%p sp=%p\n", testnum, i,
167 (void *)orig_pc, *(UINT *)orig_pc, (void *)orig_fp, (void *)context.Sp );
168
169 if (test->results[i].handler == -2) orig_pc = context.Lr;
170
171 if (pRtlVirtualUnwind2)
172 {
173 CONTEXT new_context = context;
174
175 handler = (void *)0xdeadbeef;
176 data = (void *)0xdeadbeef;
177 frame = 0xdeadbeef;
178 status = pRtlVirtualUnwind2( UNW_FLAG_EHANDLER, (ULONG)code_mem, orig_pc,
179 test->unwind_info ? &runtime_func : NULL, &new_context,
180 NULL, &data, &frame, &ctx_ptr, NULL, NULL, &handler, 0 );
181 if (test->results[i].handler > 0)
182 {
183 ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
184 ok( (char *)handler == (char *)code_mem + 0x200,
185 "%u/%u: wrong handler %p/%p\n", testnum, i, handler, (char *)code_mem + 0x200 );
186 if (handler) ok( *(DWORD *)data == 0x08070605,
187 "%u/%u: wrong handler data %lx\n", testnum, i, *(DWORD *)data );
188 }
189 else if (test->results[i].handler < -1)
190 {
191 ok( status == STATUS_BAD_FUNCTION_TABLE, "RtlVirtualUnwind2 failed %lx\n", status );
192 ok( handler == (void *)0xdeadbeef, "handler set to %p\n", handler );
193 ok( data == (void *)0xdeadbeef, "handler data set to %p\n", data );
194 }
195 else
196 {
197 ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
198 ok( handler == NULL, "handler %p instead of NULL\n", handler );
199 ok( data == NULL, "handler data set to %p\n", data );
200 }
201 }
202
203 data = (void *)0xdeadbeef;
204 frame = 0xdeadbeef;
205 handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG)code_mem, orig_pc,
206 test->unwind_info ? &runtime_func : NULL,
207 &context, &data, &frame, &ctx_ptr );
208 if (test->results[i].handler > 0)
209 {
210 ok( (char *)handler == (char *)code_mem + 0x200,
211 "%u/%u: wrong handler %p/%p\n", testnum, i, handler, (char *)code_mem + 0x200 );
212 if (handler) ok( *(DWORD *)data == 0x08070605,
213 "%u/%u: wrong handler data %lx\n", testnum, i, *(DWORD *)data );
214 }
215 else
216 {
217 ok( handler == NULL, "%u/%u: handler %p instead of NULL\n", testnum, i, handler );
218 ok( data == (test->results[i].handler < -1 ? (void *)0xdeadbeef : NULL),
219 "%u/%u: handler data set to %p/%p\n", testnum, i, data,
220 (test->results[i].handler < 0 ? (void *)0xdeadbeef : NULL) );
221 }
222
223 ok( context.Pc == test->results[i].pc, "%u/%u: wrong pc %p/%p\n",
224 testnum, i, (void *)context.Pc, (void*)test->results[i].pc );
225 ok( frame == (test->results[i].frame_offset ? (ULONG)fake_stack : 0) + test->results[i].frame, "%u/%u: wrong frame %x/%x\n",
226 testnum, i, (int)((char *)frame - (char *)(test->results[i].frame_offset ? fake_stack : NULL)), test->results[i].frame );
227
228 for (j = 0; j < 47; j++)
229 {
230 for (k = 0; k < nb_regs; k++)
231 {
232 if (test->results[i].regs[k][0] == -1)
233 {
234 k = nb_regs;
235 break;
236 }
237 if (test->results[i].regs[k][0] == j) break;
238 }
239
240 if (j >= 4 && j <= 11 && (&ctx_ptr.R4)[j - 4])
241 {
242 ok( k < nb_regs, "%u/%u: register %s should not be set to %lx\n",
243 testnum, i, reg_names_arm[j], (&context.R0)[j] );
244 if (k < nb_regs)
245 ok( (&context.R0)[j] == test->results[i].regs[k][1],
246 "%u/%u: register %s wrong %p/%x\n",
247 testnum, i, reg_names_arm[j], (void *)(&context.R0)[j], (int)test->results[i].regs[k][1] );
248 }
249 else if (j == lr && ctx_ptr.Lr)
250 {
251 ok( k < nb_regs, "%u/%u: register %s should not be set to %lx\n",
252 testnum, i, reg_names_arm[j], context.Lr );
253 if (k < nb_regs)
254 ok( context.Lr == test->results[i].regs[k][1],
255 "%u/%u: register %s wrong %p/%x\n",
256 testnum, i, reg_names_arm[j], (void *)context.Lr, (int)test->results[i].regs[k][1] );
257 }
258 else if (j == sp)
259 {
260 if (k < nb_regs)
261 ok( context.Sp == test->results[i].regs[k][1],
262 "%u/%u: register %s wrong %p/%x\n",
263 testnum, i, reg_names_arm[j], (void *)context.Sp, (int)test->results[i].regs[k][1] );
264 else if (test->results[i].frame == 0xdeadbeef)
265 ok( (void *)context.Sp == fake_stack, "%u/%u: wrong sp %p/%p\n",
266 testnum, i, (void *)context.Sp, fake_stack);
267 else
268 ok( context.Sp == frame, "%u/%u: wrong sp %p/%p\n",
269 testnum, i, (void *)context.Sp, (void *)frame);
270 }
271 else if (j >= d8 && j <= d15 && (&ctx_ptr.D8)[j - d8])
272 {
273 ok( k < nb_regs, "%u/%u: register %s should not be set to %llx\n",
274 testnum, i, reg_names_arm[j], context.D[j - d0] );
275 if (k < nb_regs)
276 ok( context.D[j - d0] == test->results[i].regs[k][1],
277 "%u/%u: register %s wrong %llx/%llx\n",
278 testnum, i, reg_names_arm[j], context.D[j - d0], test->results[i].regs[k][1] );
279 }
280 else if (k < nb_regs)
281 {
282 if (j <= r12)
283 ok( (&context.R0)[j] == test->results[i].regs[k][1],
284 "%u/%u: register %s wrong %p/%x\n",
285 testnum, i, reg_names_arm[j], (void *)(&context.R0)[j], (int)test->results[i].regs[k][1] );
286 else if (j == lr)
287 ok( context.Lr == test->results[i].regs[k][1],
288 "%u/%u: register %s wrong %p/%x\n",
289 testnum, i, reg_names_arm[j], (void *)context.Lr, (int)test->results[i].regs[k][1] );
290 else
291 ok( context.D[j - d0] == test->results[i].regs[k][1],
292 "%u/%u: register %s wrong %llx/%llx\n",
293 testnum, i, reg_names_arm[j], context.D[j - d0], test->results[i].regs[k][1] );
294 }
295 else
296 {
297 ok( k == nb_regs, "%u/%u: register %s should be set\n", testnum, i, reg_names_arm[j] );
298 if (j == lr)
299 ok( context.Lr == ORIG_LR, "%u/%u: register lr wrong %p/unset\n",
300 testnum, i, (void *)context.Lr );
301 else if (j == r11)
302 ok( context.R11 == orig_fp, "%u/%u: register fp wrong %p/unset\n",
303 testnum, i, (void *)context.R11 );
304 else if (j < d0)
305 ok( (&context.R0)[j] == unset_reg,
306 "%u/%u: register %s wrong %p/unset\n",
307 testnum, i, reg_names_arm[j], (void *)(&context.R0)[j]);
308 else
309 ok( context.D[j - d0] == unset_reg64,
310 "%u/%u: register %s wrong %llx/unset\n",
311 testnum, i, reg_names_arm[j], context.D[j - d0]);
312 }
313 }
314 }
315}
316
317#define DW(dword) ((dword >> 0) & 0xff), ((dword >> 8) & 0xff), ((dword >> 16) & 0xff), ((dword >> 24) & 0xff)
318
319static void test_virtual_unwind_arm(void)
320{
321
322 static const BYTE function_0[] =
323 {
324 0x70, 0xb5, /* 00: push {r4-r6, lr} */
325 0x88, 0xb0, /* 02: sub sp, sp, #32 */
326 0x2d, 0xed, 0x06, 0x8b, /* 04: vpush {d8-d10} */
327 0x00, 0xbf, /* 08: nop */
328 0x2d, 0xed, 0x06, 0x3b, /* 0a: vpush {d3-d5} */
329 0xaf, 0x3f, 0x00, 0x80, /* 0e: nop.w */
330 0x6d, 0xed, 0x06, 0x1b, /* 12: vpush {d17-d19} */
331 0x2d, 0xe9, 0x00, 0x15, /* 16: push.w {r8, r10, r12} */
332 0xeb, 0x46, /* 1a: mov r11, sp */
333 0x00, 0xbf, /* 1c: nop */
334 0xbd, 0xec, 0x06, 0x8b, /* 1e: vpop {d8-d10} */
335 0xdd, 0x46, /* 22: mov sp, r11 */
336 0x08, 0xb0, /* 24: add sp, sp, #32 */
337 0x70, 0xbd, /* 26: pop {r4-r6, pc} */
338 };
339
340 static const DWORD unwind_info_0_header =
341 (sizeof(function_0)/2) | /* function length */
342 (1 << 20) | /* X */
343 (0 << 21) | /* E */
344 (0 << 22) | /* F */
345 (1 << 23) | /* epilog */
346 (5 << 28); /* codes, (sizeof(unwind_info_0)-headers+3)/4 */
347 static const DWORD unwind_info_0_epilog0 =
348 (15 << 0) | /* offset = 0x1e / 2 = 15 */
349 (0xE << 20) | /* condition, 0xE = always */
350 (13 << 24); /* index, byte offset to epilog opcodes */
351
352 static const BYTE unwind_info_0[] =
353 {
354 DW(unwind_info_0_header),
355 DW(unwind_info_0_epilog0),
356
357 UWOP_SET_FP(11), /* mov r11, sp */
358 UWOP_SAVE_REGSW((1<<r8)|(1<<r10)|(1<<r12)), /* push.w {r8, r10, r12} */
359 UWOP_SAVE_D16_RANGE(17,19), /* vpush {d17-d19} */
360 UWOP_NOP32, /* nop.w */
361 UWOP_SAVE_D0_RANGE(3,5), /* vpush {d3-d5} */
362 UWOP_NOP16, /* nop */
363 UWOP_SAVE_D8_RANGE(10), /* vpush {d8-d10} */
364 UWOP_ALLOC_SMALL(32), /* sub sp, sp, #32 */
365 UWOP_SAVE_RANGE_4_7_LR(6, 1), /* push {r4-r6,lr} */
366 UWOP_END,
367
368 UWOP_SAVE_D8_RANGE(10), /* vpop {d8-d10} */
369 UWOP_SET_FP(11), /* mov sp, r11 */
370 UWOP_ALLOC_SMALL(32), /* add sp, sp, #32 */
371 UWOP_SAVE_RANGE_4_7_LR(6, 1), /* pop {r4-r6,pc} */
372 UWOP_END,
373
374 0, 0, /* align */
375 0x00, 0x02, 0x00, 0x00, /* handler */
376 0x05, 0x06, 0x07, 0x08, /* data */
377 };
378
379 static const struct results_arm results_0[] =
380 {
381 /* offset fp handler pc frame offset registers */
382 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
383 { 0x02, 0x10, 0, 0x0c, 0x010, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {lr,0x0c}, {-1,-1} }},
384 { 0x04, 0x10, 0, 0x2c, 0x030, TRUE, { {r4,0x20}, {r5,0x24}, {r6,0x28}, {lr,0x2c}, {-1,-1} }},
385 { 0x08, 0x10, 0, 0x44, 0x048, TRUE, { {r4,0x38}, {r5,0x3c}, {r6,0x40}, {lr,0x44}, {d8, 0x400000000}, {d9, 0xc00000008}, {d10, 0x1400000010}, {-1,-1} }},
386 { 0x0a, 0x10, 0, 0x44, 0x048, TRUE, { {r4,0x38}, {r5,0x3c}, {r6,0x40}, {lr,0x44}, {d8, 0x400000000}, {d9, 0xc00000008}, {d10, 0x1400000010}, {-1,-1} }},
387 { 0x0e, 0x10, 0, 0x5c, 0x060, TRUE, { {r4,0x50}, {r5,0x54}, {r6,0x58}, {lr,0x5c}, {d8, 0x1c00000018}, {d9, 0x2400000020}, {d10, 0x2c00000028}, {d3, 0x400000000}, {d4, 0xc00000008}, {d5, 0x1400000010}, {-1,-1} }},
388 { 0x12, 0x10, 0, 0x5c, 0x060, TRUE, { {r4,0x50}, {r5,0x54}, {r6,0x58}, {lr,0x5c}, {d8, 0x1c00000018}, {d9, 0x2400000020}, {d10, 0x2c00000028}, {d3, 0x400000000}, {d4, 0xc00000008}, {d5, 0x1400000010}, {-1,-1} }},
389 { 0x16, 0x10, 0, 0x74, 0x078, TRUE, { {r4,0x68}, {r5,0x6c}, {r6,0x70}, {lr,0x74}, {d8, 0x3400000030}, {d9, 0x3c00000038}, {d10, 0x4400000040}, {d3, 0x1c00000018}, {d4, 0x2400000020}, {d5, 0x2c00000028}, {d17, 0x400000000}, {d18, 0xc00000008}, {d19, 0x1400000010}, {-1,-1} }},
390 { 0x1a, 0x10, 0, 0x80, 0x084, TRUE, { {r4,0x74}, {r5,0x78}, {r6,0x7c}, {lr,0x80}, {d8, 0x400000003c}, {d9, 0x4800000044}, {d10, 0x500000004c}, {d3, 0x2800000024}, {d4, 0x300000002c}, {d5, 0x3800000034}, {d17, 0x100000000c}, {d18, 0x1800000014}, {d19, 0x200000001c}, {r8,0x00}, {r10,0x04}, {r12,0x08}, {-1,-1} }},
391 { 0x1c, 0x10, 1, 0x90, 0x094, TRUE, { {r4,0x84}, {r5,0x88}, {r6,0x8c}, {lr,0x90}, {d8, 0x500000004c}, {d9, 0x5800000054}, {d10, 0x600000005c}, {d3, 0x3800000034}, {d4, 0x400000003c}, {d5, 0x4800000044}, {d17, 0x200000001c}, {d18, 0x2800000024}, {d19, 0x300000002c}, {r8,0x10}, {r10,0x14}, {r12,0x18}, {-1,-1} }},
392 { 0x1e, 0x10, 0, 0x3c, 0x040, TRUE, { {r4,0x30}, {r5,0x34}, {r6,0x38}, {lr,0x3c}, {d8, 0x400000000}, {d9, 0xc00000008}, {d10, 0x1400000010}, {-1,-1} }},
393 { 0x22, 0x10, 0, 0x3c, 0x040, TRUE, { {r4,0x30}, {r5,0x34}, {r6,0x38}, {lr,0x3c}, {-1,-1} }},
394 { 0x24, 0x10, 0, 0x2c, 0x030, TRUE, { {r4,0x20}, {r5,0x24}, {r6,0x28}, {lr,0x2c}, {-1,-1} }},
395 { 0x26, 0x10, 0, 0x0c, 0x010, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {lr,0x0c}, {-1,-1} }},
396 };
397
398 static const BYTE function_1[] =
399 {
400 0x30, 0xb4, /* 00: push {r4-r5} */
401 0x4d, 0xf8, 0x20, 0xed, /* 02: str lr, [sp, #-32]! */
402 0x00, 0xbf, /* 06: nop */
403 0x5d, 0xf8, 0x20, 0xeb, /* 08: ldr lr, [sp], #32 */
404 0x30, 0xbc, /* 0c: pop {r4-r5} */
405 0x70, 0x47, /* 0e: bx lr */
406 };
407
408 static const DWORD unwind_info_1_header =
409 (sizeof(function_1)/2) | /* function length */
410 (0 << 20) | /* X */
411 (0 << 21) | /* E */
412 (0 << 22) | /* F */
413 (0 << 23) | /* epilog */
414 (0 << 28); /* codes */
415 static const DWORD unwind_info_1_header2 =
416 (1 << 0) | /* epilog */
417 (2 << 16); /* codes, (sizeof(unwind_info_1)-headers+3)/4 */
418 static const DWORD unwind_info_1_epilog0 =
419 (4 << 0) | /* offset = 0x08 / 2 = 4 */
420 (0xE << 20) | /* condition, 0xE = always */
421 (4 << 24); /* index, byte offset to epilog opcodes */
422
423 static const BYTE unwind_info_1[] = {
424 DW(unwind_info_1_header),
425 DW(unwind_info_1_header2),
426 DW(unwind_info_1_epilog0),
427
428 UWOP_SAVE_LR(32), /* str lr, [sp, #-32]! */
429 UWOP_SAVE_RANGE_4_7_LR(5, 0), /* push {r4-r5} */
430 UWOP_END_NOP16,
431
432 UWOP_SAVE_LR(32), /* ldr lr, [sp], #32 */
433 UWOP_SAVE_RANGE_4_7_LR(5, 0), /* pop {r4-r5} */
434 UWOP_END_NOP16, /* bx lr */
435 };
436
437 static const struct results_arm results_1[] =
438 {
439 /* offset fp handler pc frame offset registers */
440 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
441 { 0x02, 0x00, 0, ORIG_LR, 0x008, TRUE, { {r4,0x00}, {r5,0x04}, {-1,-1} }},
442 { 0x06, 0x00, 0, 0x00, 0x028, TRUE, { {r4,0x20}, {r5,0x24}, {lr,0x00}, {-1,-1} }},
443 { 0x08, 0x00, 0, 0x00, 0x028, TRUE, { {r4,0x20}, {r5,0x24}, {lr,0x00}, {-1,-1} }},
444 { 0x0c, 0x00, 0, ORIG_LR, 0x008, TRUE, { {r4,0x00}, {r5,0x04}, {-1,-1} }},
445 { 0x0e, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
446 };
447
448 static const BYTE function_2[] =
449 {
450 0x6f, 0x46, /* 00: mov r7, sp */
451 0x80, 0xb4, /* 02: push {r7} */
452 0x84, 0xb0, /* 04: sub sp, sp, #16 */
453 0x00, 0xbf, /* 06: nop */
454 0x04, 0xb0, /* 08: add sp, sp, #16 */
455 0x80, 0xbc, /* 0a: push {r7} */
456 0xbd, 0x46, /* 0c: mov sp, r7 */
457 0x00, 0xf0, 0x00, 0xb8, /* 0e: b tailcall */
458 };
459
460 static const DWORD unwind_info_2_header =
461 (sizeof(function_2)/2) | /* function length */
462 (0 << 20) | /* X */
463 (1 << 21) | /* E */
464 (0 << 22) | /* F */
465 (0 << 23) | /* epilog */
466 (2 << 28); /* codes, (sizeof(unwind_info_2)-headers+3)/4 */
467
468 static const BYTE unwind_info_2[] =
469 {
470 DW(unwind_info_2_header),
471
472 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
473 UWOP_SAVE_REGS((1<<r7)), /* push {r7} */
474 UWOP_SET_FP(7), /* mov r7, sp */
475 UWOP_END_NOP32, /* b tailcall */
476 };
477
478 static const struct results_arm results_2[] =
479 {
480 /* offset fp handler pc frame offset registers */
481 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
482 { 0x02, 0x00, 0, ORIG_LR, 0x55555555, FALSE, { {-1,-1} }},
483 { 0x04, 0x00, 0, ORIG_LR, 0x000, FALSE, { {r7,0x00}, {-1,-1} }},
484 { 0x06, 0x00, 0, ORIG_LR, 0x010, FALSE, { {r7,0x10}, {-1,-1} }},
485 { 0x08, 0x00, 0, ORIG_LR, 0x010, FALSE, { {r7,0x10}, {-1,-1} }},
486 { 0x0a, 0x00, 0, ORIG_LR, 0x000, FALSE, { {r7,0x00}, {-1,-1} }},
487 { 0x0c, 0x00, 0, ORIG_LR, 0x55555555, FALSE, { {-1,-1} }},
488 { 0x0e, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
489 };
490
491 static const BYTE function_3[] =
492 {
493 0xaf, 0x3f, 0x00, 0x80, /* 00: nop.w */
494 0x00, 0xbf, /* 04: nop */
495 0x00, 0xbf, /* 06: nop */
496 0x04, 0xb0, /* 08: add sp, sp, #16 */
497 0xbd, 0xe8, 0xf0, 0x8f, /* 0a: pop.w {r4-r11,pc} */
498 };
499
500 /* Testing F=1, no prologue */
501 static const DWORD unwind_info_3_header =
502 (sizeof(function_3)/2) | /* function length */
503 (0 << 20) | /* X */
504 (1 << 21) | /* E */
505 (1 << 22) | /* F */
506 (0 << 23) | /* epilog */
507 (1 << 28); /* codes, (sizeof(unwind_info_3)-headers+3)/4 */
508
509 static const BYTE unwind_info_3[] =
510 {
511 DW(unwind_info_3_header),
512
513 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
514 UWOP_SAVE_RANGE_4_11_LR(11, 1), /* pop.w {r4-r11,pc} */
515 UWOP_END,
516 };
517
518 static const struct results_arm results_3[] =
519 {
520 /* offset fp handler pc frame offset registers */
521 { 0x00, 0x00, 0, 0x30, 0x034, TRUE, { {r4,0x10}, {r5,0x14}, {r6,0x18}, {r7,0x1c}, {r8,0x20}, {r9,0x24}, {r10,0x28}, {r11,0x2c}, {lr,0x30}, {-1,-1} }},
522 { 0x04, 0x00, 0, 0x30, 0x034, TRUE, { {r4,0x10}, {r5,0x14}, {r6,0x18}, {r7,0x1c}, {r8,0x20}, {r9,0x24}, {r10,0x28}, {r11,0x2c}, {lr,0x30}, {-1,-1} }},
523 { 0x06, 0x00, 0, 0x30, 0x034, TRUE, { {r4,0x10}, {r5,0x14}, {r6,0x18}, {r7,0x1c}, {r8,0x20}, {r9,0x24}, {r10,0x28}, {r11,0x2c}, {lr,0x30}, {-1,-1} }},
524 { 0x08, 0x00, 0, 0x30, 0x034, TRUE, { {r4,0x10}, {r5,0x14}, {r6,0x18}, {r7,0x1c}, {r8,0x20}, {r9,0x24}, {r10,0x28}, {r11,0x2c}, {lr,0x30}, {-1,-1} }},
525 { 0x0a, 0x00, 0, 0x20, 0x024, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r8,0x10}, {r9,0x14}, {r10,0x18}, {r11,0x1c}, {lr,0x20}, {-1,-1} }},
526 };
527
528 static const BYTE function_4[] =
529 {
530 0x2d, 0xe9, 0x00, 0x55, /* 00: push.w {r8, r10, r12, lr} */
531 0x50, 0xb4, /* 04: push {r4, r6} */
532 0x00, 0xbf, /* 06: nop */
533 0x50, 0xbc, /* 08: pop {r4, r6} */
534 0xbd, 0xe8, 0x00, 0x95, /* 0a: pop.w {r8, r10, r12, pc} */
535 };
536
537 static const DWORD unwind_info_4_header =
538 (sizeof(function_4)/2) | /* function length */
539 (0 << 20) | /* X */
540 (1 << 21) | /* E */
541 (0 << 22) | /* F */
542 (0 << 23) | /* epilog */
543 (2 << 28); /* codes, (sizeof(unwind_info_4)-headers+3)/4 */
544
545 static const BYTE unwind_info_4[] =
546 {
547 DW(unwind_info_4_header),
548
549 UWOP_SAVE_REGS((1<<r4)|(1<<r6)), /* push {r4, r6} */
550 UWOP_SAVE_REGSW((1<<r8)|(1<<r10)|(1<<r12)|(1<<lr)), /* push.w {r8, r10, r12, lr} */
551 UWOP_END,
552 };
553
554 static const struct results_arm results_4[] =
555 {
556 /* offset fp handler pc frame offset registers */
557 { 0x00, 0x10, 0, ORIG_LR, 0x00000, TRUE, { {-1,-1} }},
558 { 0x04, 0x10, 0, 0x0c, 0x00010, TRUE, { {r8,0x00}, {r10,0x04}, {r12,0x08}, {lr,0x0c}, {-1,-1} }},
559 { 0x06, 0x10, 0, 0x14, 0x00018, TRUE, { {r8,0x08}, {r10,0x0c}, {r12,0x10}, {lr,0x14}, {r4,0x00}, {r6,0x04}, {-1,-1} }},
560 { 0x08, 0x10, 0, 0x14, 0x00018, TRUE, { {r8,0x08}, {r10,0x0c}, {r12,0x10}, {lr,0x14}, {r4,0x00}, {r6,0x04}, {-1,-1} }},
561 { 0x0a, 0x10, 0, 0x0c, 0x00010, TRUE, { {r8,0x00}, {r10,0x04}, {r12,0x08}, {lr,0x0c}, {-1,-1} }},
562 };
563
564 static const BYTE function_5[] =
565 {
566 0x50, 0xb5, /* 00: push {r4, r6, lr} */
567 0xad, 0xf2, 0x08, 0x0d, /* 02: subw sp, sp, #8 */
568 0x84, 0xb0, /* 06: sub sp, sp, #16 */
569 0x88, 0xb0, /* 08: sub sp, sp, #32 */
570 0xad, 0xf2, 0x40, 0x0d, /* 0a: subw sp, sp, #64 */
571 0xad, 0xf2, 0x80, 0x0d, /* 0e: subw sp, sp, #128 */
572 0x00, 0xbf, /* 12: nop */
573 0x50, 0xbd, /* 14: pop {r4, r6, pc} */
574 };
575
576 static const DWORD unwind_info_5_header =
577 (sizeof(function_5)/2) | /* function length */
578 (0 << 20) | /* X */
579 (1 << 21) | /* E */
580 (0 << 22) | /* F */
581 (16 << 23) | /* epilog */
582 (5 << 28); /* codes, (sizeof(unwind_info_4)-headers+3)/4 */
583
584 static const BYTE unwind_info_5[] =
585 {
586 DW(unwind_info_5_header),
587
588 UWOP_ALLOC_HUGEW(128), /* subw sp, sp, #128 */
589 UWOP_ALLOC_LARGEW(64), /* subw sp, sp, #64 */
590 UWOP_ALLOC_HUGE(32), /* sub sp, sp, #32 */
591 UWOP_ALLOC_LARGE(16), /* sub sp, sp, #16 */
592 UWOP_ALLOC_MEDIUMW(8), /* subw sp, sp, #8 */
593 UWOP_SAVE_REGS((1<<r4)|(1<<r6)|(1<<lr)), /* push {r4, r6, lr} */
594 UWOP_END,
595 };
596
597 static const struct results_arm results_5[] =
598 {
599 /* offset fp handler pc frame offset registers */
600 { 0x00, 0x00, 0, ORIG_LR, 0x00000, TRUE, { {-1,-1} }},
601 { 0x02, 0x00, 0, 0x008, 0x0000c, TRUE, { {r4,0x00}, {r6,0x04}, {lr,0x08}, {-1,-1} }},
602 { 0x06, 0x00, 0, 0x010, 0x00014, TRUE, { {r4,0x08}, {r6,0x0c}, {lr,0x10}, {-1,-1} }},
603 { 0x08, 0x00, 0, 0x020, 0x00024, TRUE, { {r4,0x18}, {r6,0x1c}, {lr,0x20}, {-1,-1} }},
604 { 0x0a, 0x00, 0, 0x040, 0x00044, TRUE, { {r4,0x38}, {r6,0x3c}, {lr,0x40}, {-1,-1} }},
605 { 0x0e, 0x00, 0, 0x080, 0x00084, TRUE, { {r4,0x78}, {r6,0x7c}, {lr,0x80}, {-1,-1} }},
606 { 0x12, 0x00, 0, 0x100, 0x00104, TRUE, { {r4,0xf8}, {r6,0xfc}, {lr,0x100}, {-1,-1} }},
607 { 0x14, 0x00, 0, 0x008, 0x0000c, TRUE, { {r4,0x00}, {r6,0x04}, {lr,0x08}, {-1,-1} }},
608 };
609
610 static const BYTE function_6[] =
611 {
612 0x00, 0xbf, /* 00: nop */
613 0x00, 0xbf, /* 02: nop */
614 0x00, 0xbf, /* 04: nop */
615 0x70, 0x47, /* 06: bx lr */
616 };
617
618 static const DWORD unwind_info_6_packed =
619 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
620 (sizeof(function_6)/2 << 2) | /* FunctionLength */
621 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
622 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
623 (7 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
624 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
625 (0 << 20) | /* L, push LR */
626 (0 << 21) | /* C - hook up r11 */
627 (0 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
628
629 static const BYTE unwind_info_6[] = { DW(unwind_info_6_packed) };
630
631 static const struct results_arm results_6[] =
632 {
633 /* offset fp handler pc frame offset registers */
634 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
635 { 0x02, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
636 { 0x04, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
637 { 0x06, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
638 };
639
640 static const BYTE function_7[] =
641 {
642 0x10, 0xb4, /* 00: push {r4} */
643 0x00, 0xbf, /* 02: nop */
644 0x10, 0xbc, /* 04: pop {r4} */
645 0x70, 0x47, /* 06: bx lr */
646 };
647
648 static const DWORD unwind_info_7_packed =
649 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
650 (sizeof(function_7)/2 << 2) | /* FunctionLength */
651 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
652 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
653 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
654 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
655 (0 << 20) | /* L, push LR */
656 (0 << 21) | /* C - hook up r11 */
657 (0 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
658
659 static const BYTE unwind_info_7[] = { DW(unwind_info_7_packed) };
660
661 static const struct results_arm results_7[] =
662 {
663 /* offset fp handler pc frame offset registers */
664 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
665 { 0x02, 0x00, 0, ORIG_LR, 0x004, TRUE, { {r4,0x00}, {-1,-1} }},
666 { 0x04, 0x00, 0, ORIG_LR, 0x004, TRUE, { {r4,0x00}, {-1,-1} }},
667 { 0x06, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
668 };
669
670 static const BYTE function_8[] =
671 {
672 0x10, 0xb5, /* 00: push {r4, lr} */
673 0x00, 0xbf, /* 02: nop */
674 0xbd, 0xe8, 0x10, 0x40, /* 04: pop {r4, lr} */
675 0x70, 0x47, /* 08: bx lr */
676 };
677
678 static const DWORD unwind_info_8_packed =
679 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
680 (sizeof(function_8)/2 << 2) | /* FunctionLength */
681 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
682 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
683 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
684 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
685 (1 << 20) | /* L, push LR */
686 (0 << 21) | /* C - hook up r11 */
687 (0 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
688
689 static const BYTE unwind_info_8[] = { DW(unwind_info_8_packed) };
690
691 static const struct results_arm results_8[] =
692 {
693 /* offset fp handler pc frame offset registers */
694 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
695 { 0x02, 0x00, 0, 0x004, 0x008, TRUE, { {r4,0x00}, {lr,0x04}, {-1,-1} }},
696 { 0x04, 0x00, 0, 0x004, 0x008, TRUE, { {r4,0x00}, {lr,0x04}, {-1,-1} }},
697 { 0x06, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, /* Note, there's no instruction at 0x06, but the pop is surprisingly a 4 byte instruction. */
698 { 0x08, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
699 };
700
701 static const BYTE function_9[] =
702 {
703 0x00, 0xb5, /* 00: push {lr} */
704 0x2d, 0xed, 0x02, 0x8b, /* 02: vpush {d8} */
705 0x88, 0xb0, /* 06: sub sp, sp, #32 */
706 0x00, 0xbf, /* 08: nop */
707 0x08, 0xb0, /* 0a: add sp, sp, #32 */
708 0xbd, 0xec, 0x02, 0x8b, /* 0c: vpop {d8} */
709 0x5d, 0xf8, 0x04, 0xeb, /* 10: ldr lr, [sp], #4 */
710 0x00, 0xf0, 0x00, 0xb8, /* 14: b tailcall */
711 };
712
713 static const DWORD unwind_info_9_packed =
714 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
715 (sizeof(function_9)/2 << 2) | /* FunctionLength */
716 (2 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
717 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
718 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
719 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
720 (1 << 20) | /* L, push LR */
721 (0 << 21) | /* C - hook up r11 */
722 (8 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
723
724 static const BYTE unwind_info_9[] = { DW(unwind_info_9_packed) };
725
726 static const struct results_arm results_9[] =
727 {
728 /* offset fp handler pc frame offset registers */
729 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
730 { 0x02, 0x00, 0, 0x00, 0x004, TRUE, { {lr,0x00}, {-1,-1} }},
731 { 0x06, 0x00, 0, 0x08, 0x00c, TRUE, { {lr,0x08}, {d8,0x400000000}, {-1,-1} }},
732 { 0x08, 0x00, 0, 0x28, 0x02c, TRUE, { {lr,0x28}, {d8,0x2400000020}, {-1,-1} }},
733 { 0x0a, 0x00, 0, 0x28, 0x02c, TRUE, { {lr,0x28}, {d8,0x2400000020}, {-1,-1} }},
734#if 0
735 /* L=1, R=1, Ret>0 seems to get incorrect handling of the epilogue */
736 { 0x0c, 0x00, 0, ORIG_LR, 0x008, TRUE, { {d8,0x400000000}, {-1,-1} }},
737 { 0x10, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
738#endif
739 { 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
740 };
741
742 static const BYTE function_10[] =
743 {
744 0x2d, 0xe9, 0x00, 0x48, /* 00: push.w {r11, lr} */
745 0xeb, 0x46, /* 04: mov r11, sp */
746 0x2d, 0xed, 0x04, 0x8b, /* 06: vpush {d8-d9} */
747 0x84, 0xb0, /* 0a: sub sp, sp, #16 */
748 0x00, 0xbf, /* 0c: nop */
749 0x04, 0xb0, /* 0e: add sp, sp, #16 */
750 0xbd, 0xec, 0x04, 0x8b, /* 10: vpop {d8-d9} */
751 0xbd, 0xe8, 0x00, 0x48, /* 14: pop.w {r11, lr} */
752 0x70, 0x47, /* 18: bx lr */
753 };
754
755 static const DWORD unwind_info_10_packed =
756 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
757 (sizeof(function_10)/2 << 2) | /* FunctionLength */
758 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
759 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
760 (1 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
761 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
762 (1 << 20) | /* L, push LR */
763 (1 << 21) | /* C - hook up r11 */
764 (4 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
765
766 static const BYTE unwind_info_10[] = { DW(unwind_info_10_packed) };
767
768 static const struct results_arm results_10[] =
769 {
770 /* offset fp handler pc frame offset registers */
771 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
772 { 0x04, 0x00, 0, 0x04, 0x008, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
773 { 0x06, 0x00, 0, 0x04, 0x008, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
774 { 0x0a, 0x00, 0, 0x14, 0x018, TRUE, { {r11,0x10}, {lr,0x14}, {d8,0x400000000}, {d9,0xc00000008}, {-1,-1} }},
775 { 0x0c, 0x00, 0, 0x24, 0x028, TRUE, { {r11,0x20}, {lr,0x24}, {d8,0x1400000010}, {d9,0x1c00000018}, {-1,-1} }},
776 { 0x0e, 0x00, 0, 0x24, 0x028, TRUE, { {r11,0x20}, {lr,0x24}, {d8,0x1400000010}, {d9,0x1c00000018}, {-1,-1} }},
777#if 0
778 /* L=1, R=1, Ret>0 seems to get incorrect handling of the epilogue */
779 { 0x10, 0x00, 0, 0x14, 0x018, TRUE, { {r11,0x10}, {lr,0x14}, {d8,0x400000000}, {d9,0xc00000008}, {-1,-1} }},
780 { 0x14, 0x00, 0, 0x04, 0x008, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
781#endif
782 { 0x18, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
783 };
784
785 static const BYTE function_11[] =
786 {
787 0x2d, 0xe9, 0x00, 0x48, /* 00: push.w {r11, lr} */
788 0xeb, 0x46, /* 04: mov r11, sp */
789 0x2d, 0xed, 0x04, 0x8b, /* 06: vpush {d8-d9} */
790 0x84, 0xb0, /* 0a: sub sp, sp, #16 */
791 0x00, 0xbf, /* 0c: nop */
792 0x04, 0xb0, /* 0e: add sp, sp, #16 */
793 0xbd, 0xec, 0x04, 0x8b, /* 10: vpop {d8-d9} */
794 0xbd, 0xe8, 0x00, 0x88, /* 14: pop.w {r11, pc} */
795 };
796
797 static const DWORD unwind_info_11_packed =
798 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
799 (sizeof(function_11)/2 << 2) | /* FunctionLength */
800 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
801 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
802 (1 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
803 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
804 (1 << 20) | /* L, push LR */
805 (1 << 21) | /* C - hook up r11 */
806 (4 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
807
808 static const BYTE unwind_info_11[] = { DW(unwind_info_11_packed) };
809
810 static const struct results_arm results_11[] =
811 {
812 /* offset fp handler pc frame offset registers */
813 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
814 { 0x04, 0x00, 0, 0x04, 0x008, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
815 { 0x06, 0x00, 0, 0x04, 0x008, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
816 { 0x0a, 0x00, 0, 0x14, 0x018, TRUE, { {r11,0x10}, {lr,0x14}, {d8,0x400000000}, {d9,0xc00000008}, {-1,-1} }},
817 { 0x0c, 0x00, 0, 0x24, 0x028, TRUE, { {r11,0x20}, {lr,0x24}, {d8,0x1400000010}, {d9,0x1c00000018}, {-1,-1} }},
818 { 0x0e, 0x00, 0, 0x24, 0x028, TRUE, { {r11,0x20}, {lr,0x24}, {d8,0x1400000010}, {d9,0x1c00000018}, {-1,-1} }},
819 { 0x10, 0x00, 0, 0x14, 0x018, TRUE, { {r11,0x10}, {lr,0x14}, {d8,0x400000000}, {d9,0xc00000008}, {-1,-1} }},
820 { 0x14, 0x00, 0, 0x04, 0x008, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
821 };
822
823 static const BYTE function_12[] =
824 {
825 0x2d, 0xed, 0x0e, 0x8b, /* 00: vpush {d8-d14} */
826 0x84, 0xb0, /* 04: sub sp, sp, #16 */
827 0x00, 0xbf, /* 06: nop */
828 0x04, 0xb0, /* 08: add sp, sp, #16 */
829 0xbd, 0xec, 0x0e, 0x8b, /* 0a: vpop {d8-d14} */
830 0x00, 0xf0, 0x00, 0xb8, /* 0e: b tailcall */
831 };
832
833 static const DWORD unwind_info_12_packed =
834 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
835 (sizeof(function_12)/2 << 2) | /* FunctionLength */
836 (2 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
837 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
838 (6 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
839 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
840 (0 << 20) | /* L, push LR */
841 (0 << 21) | /* C - hook up r11 */
842 (4 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
843
844 static const BYTE unwind_info_12[] = { DW(unwind_info_12_packed) };
845
846 static const struct results_arm results_12[] =
847 {
848 /* offset fp handler pc frame offset registers */
849 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
850 { 0x04, 0x00, 0, ORIG_LR, 0x038, TRUE, { {d8,0x400000000}, {d9,0xc00000008}, {d10,0x1400000010}, {d11,0x1c00000018}, {d12,0x2400000020}, {d13,0x2c00000028}, {d14,0x3400000030}, {-1,-1} }},
851 { 0x06, 0x00, 0, ORIG_LR, 0x048, TRUE, { {d8,0x1400000010}, {d9,0x1c00000018}, {d10,0x2400000020}, {d11,0x2c00000028}, {d12,0x3400000030}, {d13,0x3c00000038}, {d14,0x4400000040}, {-1,-1} }},
852 { 0x08, 0x00, 0, ORIG_LR, 0x048, TRUE, { {d8,0x1400000010}, {d9,0x1c00000018}, {d10,0x2400000020}, {d11,0x2c00000028}, {d12,0x3400000030}, {d13,0x3c00000038}, {d14,0x4400000040}, {-1,-1} }},
853 { 0x0a, 0x00, 0, ORIG_LR, 0x038, TRUE, { {d8,0x400000000}, {d9,0xc00000008}, {d10,0x1400000010}, {d11,0x1c00000018}, {d12,0x2400000020}, {d13,0x2c00000028}, {d14,0x3400000030}, {-1,-1} }},
854 { 0x0e, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
855 };
856
857 static const BYTE function_13[] =
858 {
859 0x2d, 0xe9, 0xf0, 0x4f, /* 00: push.w {r4-r11, lr} */
860 0x0d, 0xf1, 0x1c, 0x0b, /* 04: add.w r11, sp, #28 */
861 0x85, 0xb0, /* 08: sub sp, sp, #20 */
862 0x00, 0xbf, /* 0a: nop */
863 0x05, 0xb0, /* 0c: add sp, sp, #20 */
864 0x2d, 0xe8, 0xf0, 0x8f, /* 0e: pop.w {r4-r11, lr} */
865 };
866
867 static const DWORD unwind_info_13_packed =
868 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
869 (sizeof(function_13)/2 << 2) | /* FunctionLength */
870 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
871 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
872 (6 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
873 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
874 (1 << 20) | /* L, push LR */
875 (1 << 21) | /* C - hook up r11 */
876 (5 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
877
878 static const BYTE unwind_info_13[] = { DW(unwind_info_13_packed) };
879
880 static const struct results_arm results_13[] =
881 {
882 /* offset fp handler pc frame offset registers */
883 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
884 { 0x04, 0x10, 0, 0x20, 0x024, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r8,0x10}, {r9,0x14}, {r10,0x18}, {r11,0x1c}, {lr,0x20}, {-1,-1} }},
885 { 0x08, 0x10, 0, 0x20, 0x024, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r8,0x10}, {r9,0x14}, {r10,0x18}, {r11,0x1c}, {lr,0x20}, {-1,-1} }},
886 { 0x0a, 0x10, 0, 0x34, 0x038, TRUE, { {r4,0x14}, {r5,0x18}, {r6,0x1c}, {r7,0x20}, {r8,0x24}, {r9,0x28}, {r10,0x2c}, {r11,0x30}, {lr,0x34}, {-1,-1} }},
887 { 0x0c, 0x10, 0, 0x34, 0x038, TRUE, { {r4,0x14}, {r5,0x18}, {r6,0x1c}, {r7,0x20}, {r8,0x24}, {r9,0x28}, {r10,0x2c}, {r11,0x30}, {lr,0x34}, {-1,-1} }},
888 { 0x0e, 0x10, 0, 0x20, 0x024, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r8,0x10}, {r9,0x14}, {r10,0x18}, {r11,0x1c}, {lr,0x20}, {-1,-1} }},
889 };
890
891 static const BYTE function_14[] =
892 {
893 0x2d, 0xe9, 0xf0, 0x4f, /* 00: push.w {r4-r11, lr} */
894 0x85, 0xb0, /* 04: sub sp, sp, #20 */
895 0x00, 0xbf, /* 06: nop */
896 0x05, 0xb0, /* 08: add sp, sp, #20 */
897 0x2d, 0xe8, 0xf0, 0x8f, /* 0a: pop.w {r4-r11, lr} */
898 };
899
900 static const DWORD unwind_info_14_packed =
901 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
902 (sizeof(function_14)/2 << 2) | /* FunctionLength */
903 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
904 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
905 (7 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
906 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
907 (1 << 20) | /* L, push LR */
908 (0 << 21) | /* C - hook up r11 */
909 (5 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
910
911 static const BYTE unwind_info_14[] = { DW(unwind_info_14_packed) };
912
913 static const struct results_arm results_14[] =
914 {
915 /* offset fp handler pc frame offset registers */
916 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
917 { 0x04, 0x10, 0, 0x20, 0x024, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r8,0x10}, {r9,0x14}, {r10,0x18}, {r11,0x1c}, {lr,0x20}, {-1,-1} }},
918 { 0x06, 0x10, 0, 0x34, 0x038, TRUE, { {r4,0x14}, {r5,0x18}, {r6,0x1c}, {r7,0x20}, {r8,0x24}, {r9,0x28}, {r10,0x2c}, {r11,0x30}, {lr,0x34}, {-1,-1} }},
919 { 0x08, 0x10, 0, 0x34, 0x038, TRUE, { {r4,0x14}, {r5,0x18}, {r6,0x1c}, {r7,0x20}, {r8,0x24}, {r9,0x28}, {r10,0x2c}, {r11,0x30}, {lr,0x34}, {-1,-1} }},
920 { 0x0a, 0x10, 0, 0x20, 0x024, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r8,0x10}, {r9,0x14}, {r10,0x18}, {r11,0x1c}, {lr,0x20}, {-1,-1} }},
921 };
922
923 static const BYTE function_15[] =
924 {
925 0x0f, 0xb4, /* 00: push {r0-r3} */
926 0x10, 0xb5, /* 02: push {r4,lr} */
927 0xad, 0xf5, 0x00, 0x7d, /* 04: sub sp, sp, #512 */
928 0x00, 0xbf, /* 08: nop */
929 0x0d, 0xf5, 0x00, 0x7d, /* 0a: add sp, sp, #512 */
930 0x10, 0xb5, /* 0e: pop {r4} */
931 0x5d, 0xf8, 0x14, 0xfb, /* 10: ldr pc, [sp], #20 */
932 };
933
934 static const DWORD unwind_info_15_packed =
935 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
936 (sizeof(function_15)/2 << 2) | /* FunctionLength */
937 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
938 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
939 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
940 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
941 (1 << 20) | /* L, push LR */
942 (0 << 21) | /* C - hook up r11 */
943 (128 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
944
945 static const BYTE unwind_info_15[] = { DW(unwind_info_15_packed) };
946
947 static const struct results_arm results_15[] =
948 {
949 /* offset fp handler pc frame offset registers */
950 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
951 { 0x02, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
952 { 0x04, 0x10, 0, 0x04, 0x018, TRUE, { {r4,0x00}, {lr,0x04}, {-1,-1} }},
953 { 0x08, 0x10, 0, 0x204, 0x218, TRUE, { {r4,0x200}, {lr,0x204}, {-1,-1} }},
954 { 0x0a, 0x10, 0, 0x204, 0x218, TRUE, { {r4,0x200}, {lr,0x204}, {-1,-1} }},
955 { 0x0e, 0x10, 0, 0x04, 0x018, TRUE, { {r4,0x00}, {lr,0x04}, {-1,-1} }},
956 { 0x10, 0x10, 0, 0x00, 0x014, TRUE, { {lr,0x00}, {-1,-1} }},
957 };
958
959 static const BYTE function_16[] =
960 {
961 0x0f, 0xb4, /* 00: push {r0-r3} */
962 0x2d, 0xe9, 0x00, 0x48, /* 02: push.w {r11,lr} */
963 0xeb, 0x46, /* 06: mov r11, sp */
964 0x00, 0xbf, /* 08: nop */
965 0xbd, 0xe8, 0x10, 0x40, /* 0a: pop.w {r11,lr} */
966 0x04, 0xb0, /* 0e: add sp, sp, #16 */
967 0x00, 0xf0, 0x00, 0xb8, /* 10: b tailcall */
968 };
969
970 static const DWORD unwind_info_16_packed =
971 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
972 (sizeof(function_16)/2 << 2) | /* FunctionLength */
973 (2 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
974 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
975 (7 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
976 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
977 (1 << 20) | /* L, push LR */
978 (1 << 21) | /* C - hook up r11 */
979 (0 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
980
981 static const BYTE unwind_info_16[] = { DW(unwind_info_16_packed) };
982
983 static const struct results_arm results_16[] =
984 {
985 /* offset fp handler pc frame offset registers */
986 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
987 { 0x02, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
988 { 0x06, 0x10, 0, 0x04, 0x018, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
989 { 0x08, 0x10, 0, 0x04, 0x018, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
990 { 0x0a, 0x10, 0, 0x04, 0x018, TRUE, { {r11,0x00}, {lr,0x04}, {-1,-1} }},
991 { 0x0e, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
992 { 0x10, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
993 };
994
995 static const BYTE function_17[] =
996 {
997 0x0f, 0xb4, /* 00: push {r0-r3} */
998 0x10, 0xb4, /* 02: push {r4} */
999 0xad, 0xf5, 0x00, 0x7d, /* 04: sub sp, sp, #512 */
1000 0x00, 0xbf, /* 08: nop */
1001 0x0d, 0xf5, 0x00, 0x7d, /* 0a: add sp, sp, #512 */
1002 0x10, 0xbc, /* 0e: pop {r4} */
1003 0x04, 0xb0, /* 10: add sp, sp, #16 */
1004 0x70, 0x47, /* 12: bx lr */
1005 };
1006
1007 static const DWORD unwind_info_17_packed =
1008 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1009 (sizeof(function_17)/2 << 2) | /* FunctionLength */
1010 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1011 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1012 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1013 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1014 (0 << 20) | /* L, push LR */
1015 (0 << 21) | /* C - hook up r11 */
1016 (128 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1017
1018 static const BYTE unwind_info_17[] = { DW(unwind_info_17_packed) };
1019
1020 static const struct results_arm results_17[] =
1021 {
1022 /* offset fp handler pc frame offset registers */
1023 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1024 { 0x02, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1025 { 0x04, 0x10, 0, ORIG_LR, 0x014, TRUE, { {r4,0x00}, {-1,-1} }},
1026 { 0x08, 0x10, 0, ORIG_LR, 0x214, TRUE, { {r4,0x200}, {-1,-1} }},
1027 { 0x0a, 0x10, 0, ORIG_LR, 0x214, TRUE, { {r4,0x200}, {-1,-1} }},
1028 { 0x0e, 0x10, 0, ORIG_LR, 0x014, TRUE, { {r4,0x00}, {-1,-1} }},
1029 { 0x10, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1030 { 0x12, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1031 };
1032
1033 static const BYTE function_18[] =
1034 {
1035 0x08, 0xb5, /* 00: push {r3,lr} */
1036 0x00, 0xbf, /* 02: nop */
1037 0x08, 0xbd, /* 04: pop {r3,pc} */
1038 };
1039
1040 static const DWORD unwind_info_18_packed =
1041 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1042 (sizeof(function_18)/2 << 2) | /* FunctionLength */
1043 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1044 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1045 (7 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1046 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1047 (1 << 20) | /* L, push LR */
1048 (0 << 21) | /* C - hook up r11 */
1049 (0x3fcu << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1050
1051 static const BYTE unwind_info_18[] = { DW(unwind_info_18_packed) };
1052
1053 static const struct results_arm results_18[] =
1054 {
1055 /* offset fp handler pc frame offset registers */
1056 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1057 { 0x02, 0x10, 0, 0x04, 0x008, TRUE, { {lr,0x04}, {-1,-1} }},
1058 { 0x04, 0x10, 0, 0x04, 0x008, TRUE, { {lr,0x04}, {-1,-1} }},
1059 };
1060
1061 static const BYTE function_19[] =
1062 {
1063 0x0f, 0xb4, /* 00: push {r0-r3} */
1064 0x14, 0xb4, /* 02: push {r0-r4} */
1065 0x00, 0xbf, /* 04: nop */
1066 0x1f, 0xbc, /* 06: pop {r0-r4} */
1067 0x04, 0xb0, /* 08: add sp, sp, #16 */
1068 0x70, 0x47, /* 0a: bx lr */
1069 };
1070
1071 static const DWORD unwind_info_19_packed =
1072 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1073 (sizeof(function_19)/2 << 2) | /* FunctionLength */
1074 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1075 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1076 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1077 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1078 (0 << 20) | /* L, push LR */
1079 (0 << 21) | /* C - hook up r11 */
1080 (0x3ffu << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1081
1082 static const BYTE unwind_info_19[] = { DW(unwind_info_19_packed) };
1083
1084 static const struct results_arm results_19[] =
1085 {
1086 /* offset fp handler pc frame offset registers */
1087 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1088 { 0x02, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1089 { 0x04, 0x10, 0, ORIG_LR, 0x024, TRUE, { {r4,0x10}, {-1,-1} }},
1090 { 0x06, 0x10, 0, ORIG_LR, 0x024, TRUE, { {r4,0x10}, {-1,-1} }},
1091 { 0x08, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1092 { 0x0a, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1093 };
1094
1095 static const BYTE function_20[] =
1096 {
1097 0x0f, 0xb4, /* 00: push {r0-r3} */
1098 0x14, 0xb4, /* 02: push {r0-r4} */
1099 0x00, 0xbf, /* 04: nop */
1100 0x04, 0xb0, /* 06: add sp, sp, #16 */
1101 0x10, 0xbc, /* 08: pop {r4} */
1102 0x04, 0xb0, /* 0a: add sp, sp, #16 */
1103 0x70, 0x47, /* 0c: bx lr */
1104 };
1105
1106 static const DWORD unwind_info_20_packed =
1107 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1108 (sizeof(function_20)/2 << 2) | /* FunctionLength */
1109 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1110 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1111 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1112 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1113 (0 << 20) | /* L, push LR */
1114 (0 << 21) | /* C - hook up r11 */
1115 (0x3f7u << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1116
1117 static const BYTE unwind_info_20[] = { DW(unwind_info_20_packed) };
1118
1119 static const struct results_arm results_20[] =
1120 {
1121 /* offset fp handler pc frame offset registers */
1122 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1123 { 0x02, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1124 { 0x04, 0x10, 0, ORIG_LR, 0x024, TRUE, { {r4,0x10}, {-1,-1} }},
1125 { 0x06, 0x10, 0, ORIG_LR, 0x024, TRUE, { {r4,0x10}, {-1,-1} }},
1126 { 0x08, 0x10, 0, ORIG_LR, 0x014, TRUE, { {r4,0x00}, {-1,-1} }},
1127 { 0x0a, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1128 { 0x0c, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1129 };
1130
1131 static const BYTE function_21[] =
1132 {
1133 0x0f, 0xb4, /* 00: push {r0-r3} */
1134 0x10, 0xb4, /* 02: push {r4} */
1135 0x84, 0xb0, /* 04: sub sp, sp, #16 */
1136 0x00, 0xbf, /* 06: nop */
1137 0x1f, 0xbc, /* 08: pop {r0-r4} */
1138 0x04, 0xb0, /* 0a: add sp, sp, #16 */
1139 0x70, 0x47, /* 0c: bx lr */
1140 };
1141
1142 static const DWORD unwind_info_21_packed =
1143 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1144 (sizeof(function_21)/2 << 2) | /* FunctionLength */
1145 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1146 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1147 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1148 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1149 (0 << 20) | /* L, push LR */
1150 (0 << 21) | /* C - hook up r11 */
1151 (0x3fbu << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1152
1153 static const BYTE unwind_info_21[] = { DW(unwind_info_21_packed) };
1154
1155 static const struct results_arm results_21[] =
1156 {
1157 /* offset fp handler pc frame offset registers */
1158 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1159 { 0x02, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1160 { 0x04, 0x10, 0, ORIG_LR, 0x014, TRUE, { {r4,0x00}, {-1,-1} }},
1161 { 0x06, 0x10, 0, ORIG_LR, 0x024, TRUE, { {r4,0x10}, {-1,-1} }},
1162 { 0x08, 0x10, 0, ORIG_LR, 0x024, TRUE, { {r4,0x10}, {-1,-1} }},
1163 { 0x0a, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1164 { 0x0c, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1165 };
1166
1167 static const BYTE function_22[] =
1168 {
1169 0x00, 0xbf, /* 00: nop */
1170 0x00, 0xbf, /* 02: nop */
1171 0x0d, 0xf5, 0x00, 0x7d, /* 04: add sp, sp, #512 */
1172 0x10, 0xb5, /* 08: pop {r4} */
1173 0x5d, 0xf8, 0x14, 0xfb, /* 0a: ldr pc, [sp], #20 */
1174 };
1175
1176 static const DWORD unwind_info_22_packed =
1177 (2 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1178 (sizeof(function_22)/2 << 2) | /* FunctionLength */
1179 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1180 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1181 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1182 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1183 (1 << 20) | /* L, push LR */
1184 (0 << 21) | /* C - hook up r11 */
1185 (128 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1186
1187 static const BYTE unwind_info_22[] = { DW(unwind_info_22_packed) };
1188
1189 static const struct results_arm results_22[] =
1190 {
1191 /* offset fp handler pc frame offset registers */
1192 { 0x00, 0x10, 0, 0x204, 0x218, TRUE, { {r4,0x200}, {lr,0x204}, {-1,-1} }},
1193 { 0x02, 0x10, 0, 0x204, 0x218, TRUE, { {r4,0x200}, {lr,0x204}, {-1,-1} }},
1194 { 0x04, 0x10, 0, 0x204, 0x218, TRUE, { {r4,0x200}, {lr,0x204}, {-1,-1} }},
1195 { 0x08, 0x10, 0, 0x04, 0x018, TRUE, { {r4,0x00}, {lr,0x04}, {-1,-1} }},
1196 { 0x0a, 0x10, 0, 0x00, 0x014, TRUE, { {lr,0x00}, {-1,-1} }},
1197 };
1198
1199 static const BYTE function_23[] =
1200 {
1201 0x0f, 0xb4, /* 00: push {r0-r3} */
1202 0x10, 0xb5, /* 02: push {r4,lr} */
1203 0xad, 0xf5, 0x00, 0x7d, /* 04: sub sp, sp, #512 */
1204 0x00, 0xbf, /* 08: nop */
1205 0x00, 0xbf, /* 0a: nop */
1206 };
1207
1208 static const DWORD unwind_info_23_packed =
1209 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1210 (sizeof(function_23)/2 << 2) | /* FunctionLength */
1211 (3 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1212 (1 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1213 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1214 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1215 (1 << 20) | /* L, push LR */
1216 (0 << 21) | /* C - hook up r11 */
1217 (128 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1218
1219 static const BYTE unwind_info_23[] = { DW(unwind_info_23_packed) };
1220
1221 static const struct results_arm results_23[] =
1222 {
1223 /* offset fp handler pc frame offset registers */
1224 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1225 { 0x02, 0x10, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1226 { 0x04, 0x10, 0, 0x04, 0x018, TRUE, { {r4,0x00}, {lr,0x04}, {-1,-1} }},
1227 { 0x08, 0x10, 0, 0x204, 0x218, TRUE, { {r4,0x200}, {lr,0x204}, {-1,-1} }},
1228 { 0x0a, 0x10, 0, 0x204, 0x218, TRUE, { {r4,0x200}, {lr,0x204}, {-1,-1} }},
1229 };
1230
1231 static const BYTE function_24[] =
1232 {
1233 0x2d, 0xe9, 0xfc, 0x48, /* 00: push.w {r2-r7,r11,lr} */
1234 0x0d, 0xf1, 0x18, 0x0b, /* 04: add r11, sp, #24 */
1235 0x00, 0xbf, /* 08: nop */
1236 0x02, 0xb0, /* 0a: add sp, sp, #8 */
1237 0xbd, 0xe8, 0x10, 0x48, /* 0c: pop.w {r4-r7,r11,pc} */
1238 };
1239
1240 static const DWORD unwind_info_24_packed =
1241 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1242 (sizeof(function_24)/2 << 2) | /* FunctionLength */
1243 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1244 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1245 (3 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1246 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1247 (1 << 20) | /* L, push LR */
1248 (1 << 21) | /* C - hook up r11 */
1249 (0x3f5u << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1250
1251 static const BYTE unwind_info_24[] = { DW(unwind_info_24_packed) };
1252
1253 static const struct results_arm results_24[] =
1254 {
1255 /* offset fp handler pc frame offset registers */
1256 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1257 { 0x04, 0x10, 0, 0x1c, 0x020, TRUE, { {r4,0x08}, {r5,0x0c}, {r6,0x10}, {r7,0x14}, {r11,0x18}, {lr,0x1c}, {-1,-1} }},
1258 { 0x08, 0x10, 0, 0x1c, 0x020, TRUE, { {r4,0x08}, {r5,0x0c}, {r6,0x10}, {r7,0x14}, {r11,0x18}, {lr,0x1c}, {-1,-1} }},
1259 { 0x0a, 0x10, 0, 0x1c, 0x020, TRUE, { {r4,0x08}, {r5,0x0c}, {r6,0x10}, {r7,0x14}, {r11,0x18}, {lr,0x1c}, {-1,-1} }},
1260 { 0x0c, 0x10, 0, 0x14, 0x018, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r11,0x10}, {lr,0x14}, {-1,-1} }},
1261 };
1262
1263 static const BYTE function_25[] =
1264 {
1265 0x2d, 0xe9, 0xf0, 0x48, /* 00: push.w {r4-r7,r11,lr} */
1266 0x0d, 0xf1, 0x10, 0x0b, /* 04: add r11, sp, #16 */
1267 0x82, 0xb0, /* 08: sub sp, sp, #8 */
1268 0x00, 0xbf, /* 0a: nop */
1269 0xbd, 0xe8, 0xfc, 0x48, /* 0c: pop.w {r2-r7,r11,pc} */
1270 };
1271
1272 static const DWORD unwind_info_25_packed =
1273 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1274 (sizeof(function_25)/2 << 2) | /* FunctionLength */
1275 (0 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1276 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1277 (3 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1278 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1279 (1 << 20) | /* L, push LR */
1280 (1 << 21) | /* C - hook up r11 */
1281 (0x3f9u << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1282
1283 static const BYTE unwind_info_25[] = { DW(unwind_info_25_packed) };
1284
1285 static const struct results_arm results_25[] =
1286 {
1287 /* offset fp handler pc frame offset registers */
1288 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1289 { 0x04, 0x10, 0, 0x14, 0x018, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r11,0x10}, {lr,0x14}, {-1,-1} }},
1290 { 0x08, 0x10, 0, 0x14, 0x018, TRUE, { {r4,0x00}, {r5,0x04}, {r6,0x08}, {r7,0x0c}, {r11,0x10}, {lr,0x14}, {-1,-1} }},
1291 { 0x0a, 0x10, 0, 0x1c, 0x020, TRUE, { {r4,0x08}, {r5,0x0c}, {r6,0x10}, {r7,0x14}, {r11,0x18}, {lr,0x1c}, {-1,-1} }},
1292 { 0x0c, 0x10, 0, 0x1c, 0x020, TRUE, { {r4,0x08}, {r5,0x0c}, {r6,0x10}, {r7,0x14}, {r11,0x18}, {lr,0x1c}, {-1,-1} }},
1293 };
1294
1295 static const BYTE function_26[] =
1296 {
1297 0x2d, 0xe9, 0x10, 0x08, /* 00: push.w {r4, r11} */
1298 0x0d, 0xf1, 0x1c, 0x0b, /* 04: add.w r11, sp, #28 */
1299 0x84, 0xb0, /* 08: sub sp, sp, #16 */
1300 0x00, 0xbf, /* 0a: nop */
1301 0x04, 0xb0, /* 0c: add sp, sp, #16 */
1302 0xbd, 0xe8, 0x10, 0x08, /* 0e: pop.w {r4, r11} */
1303 0x70, 0x47, /* 12: bx lr */
1304 };
1305
1306 /* C=1, L=0 is disallowed by doc */
1307 static const DWORD unwind_info_26_packed =
1308 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1309 (sizeof(function_26)/2 << 2) | /* FunctionLength */
1310 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1311 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1312 (0 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1313 (0 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1314 (0 << 20) | /* L, push LR */
1315 (1 << 21) | /* C - hook up r11 */
1316 (4 << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1317
1318 static const BYTE unwind_info_26[] = { DW(unwind_info_26_packed) };
1319
1320 static const struct results_arm results_26[] =
1321 {
1322 /* offset fp handler pc frame offset registers */
1323 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1324 { 0x04, 0x10, 0, ORIG_LR, 0x008, TRUE, { {r4,0x00}, {r11,0x04}, {-1,-1} }},
1325 { 0x08, 0x10, 0, ORIG_LR, 0x008, TRUE, { {r4,0x00}, {r11,0x04}, {-1,-1} }},
1326 { 0x0a, 0x10, 0, ORIG_LR, 0x018, TRUE, { {r4,0x10}, {r11,0x14}, {-1,-1} }},
1327 { 0x0c, 0x10, 0, ORIG_LR, 0x018, TRUE, { {r4,0x10}, {r11,0x14}, {-1,-1} }},
1328 { 0x0e, 0x10, 0, ORIG_LR, 0x008, TRUE, { {r4,0x00}, {r11,0x04}, {-1,-1} }},
1329 { 0x12, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1330 };
1331
1332 static const BYTE function_27[] =
1333 {
1334 0x0e, 0xb4, /* 00: push {r1-r3} */
1335 0x00, 0xbf, /* 02: nop */
1336 0x03, 0xb0, /* 04: add sp, sp, #12 */
1337 0x70, 0x47, /* 06: bx lr */
1338 };
1339
1340 static const DWORD unwind_info_27_packed =
1341 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1342 (sizeof(function_27)/2 << 2) | /* FunctionLength */
1343 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1344 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1345 (7 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1346 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1347 (0 << 20) | /* L, push LR */
1348 (0 << 21) | /* C - hook up r11 */
1349 (0x3f6u << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1350
1351 static const BYTE unwind_info_27[] = { DW(unwind_info_27_packed) };
1352
1353 static const struct results_arm results_27[] =
1354 {
1355 /* offset fp handler pc frame offset registers */
1356 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1357 { 0x02, 0x10, 0, ORIG_LR, 0x00c, TRUE, { {-1,-1} }},
1358 { 0x04, 0x10, 0, ORIG_LR, 0x00c, TRUE, { {-1,-1} }},
1359 { 0x06, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1360 };
1361
1362 static const BYTE function_28[] =
1363 {
1364 0x0e, 0xb4, /* 00: push {r1-r3} */
1365 0x00, 0xbf, /* 02: nop */
1366 0x03, 0xb0, /* 04: add sp, sp, #12 */
1367 0x70, 0x47, /* 06: bx lr */
1368 };
1369
1370 static const DWORD unwind_info_28_packed =
1371 (1 << 0) | /* Flag, 01 has prologue, 10 (2) fragment (no prologue) */
1372 (sizeof(function_28)/2 << 2) | /* FunctionLength */
1373 (1 << 13) | /* Ret (00 pop, 01 16 bit branch, 10 32 bit branch, 11 no epilogue) */
1374 (0 << 15) | /* H (homing, 16 bytes push of r0-r3 at start) */
1375 (7 << 16) | /* Reg r4 - r(4+N), or d8 - d(8+N) */
1376 (1 << 19) | /* R (0 integer registers, 1 float registers, R=1, Reg=7 no registers */
1377 (0 << 20) | /* L, push LR */
1378 (0 << 21) | /* C - hook up r11 */
1379 (0x3fau << 22); /* StackAdjust, stack/4. 0x3F4 special, + (0-3) stack adjustment, 4 PF (prologue folding), 8 EF (epilogue folding) */
1380
1381 static const BYTE unwind_info_28[] = { DW(unwind_info_28_packed) };
1382
1383 static const struct results_arm results_28[] =
1384 {
1385 /* offset fp handler pc frame offset registers */
1386 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1387 { 0x02, 0x10, 0, ORIG_LR, 0x00c, TRUE, { {-1,-1} }},
1388 { 0x04, 0x10, 0, ORIG_LR, 0x00c, TRUE, { {-1,-1} }},
1389 { 0x06, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1390 };
1391
1392 static const BYTE function_29[] =
1393 {
1394 0x00, 0xbf, /* 00: nop */
1395 0x00, 0xbf, /* 02: nop */
1396 };
1397
1398 static const DWORD unwind_info_29_header =
1399 (sizeof(function_29)/2) | /* function length */
1400 (0 << 20) | /* X */
1401 (0 << 21) | /* E */
1402 (0 << 22) | /* F */
1403 (0 << 23) | /* epilog */
1404 (1 << 28); /* codes, (sizeof(unwind_info_29)-headers+3)/4 */
1405
1406 static const BYTE unwind_info_29[] =
1407 {
1408 DW(unwind_info_29_header),
1409 UWOP_MSFT_OP_CONTEXT,
1410 UWOP_END,
1411 };
1412
1413 static const struct results_arm results_29[] =
1414 {
1415 /* offset fp handler pc frame offset registers */
1416 { 0x00, 0x10, 0, 0x40, 0x38, FALSE, { {r0,0x04}, {r1,0x08}, {r2,0x0c}, {r3,0x10}, {r4,0x14}, {r5,0x18}, {r6,0x1c}, {r7,0x20}, {r8,0x24}, {r9,0x28}, {r10,0x2c}, {r11,0x30}, {r12,0x34}, {sp,0x38}, {lr,0x3c},
1417 {d0,0x5400000050}, {d1,0x5c00000058}, {d2,0x6400000060}, {d3,0x6c00000068}, {d4,0x7400000070}, {d5,0x7c00000078}, {d6,0x8400000080}, {d7,0x8c00000088},
1418 {d8,0x9400000090}, {d9,0x9c00000098}, {d10,0xa4000000a0}, {d11,0xac000000a8}, {d12,0xb4000000b0}, {d13,0xbc000000b8}, {d14,0xc4000000c0}, {d15,0xcc000000c8},
1419 {d16,0xd4000000d0}, {d17,0xdc000000d8}, {d18,0xe4000000e0}, {d19,0xec000000e8}, {d20,0xf4000000f0}, {d21,0xfc000000f8}, {d22,0x10400000100}, {d23,0x10c00000108},
1420 {d24,0x11400000110}, {d25,0x11c00000118}, {d26,0x12400000120}, {d27,0x12c00000128}, {d28,0x13400000130}, {d29,0x13c00000138}, {d30,0x14400000140}, {d31,0x14c00000148} }},
1421 };
1422
1423 static const BYTE function_30[] =
1424 {
1425 0x00, 0xbf, /* 00: nop */
1426 0x00, 0xbf, /* 02: nop */
1427 0x00, 0xbf, /* 04: nop */
1428 0x00, 0xbf, /* 06: nop */
1429 };
1430
1431 static const DWORD unwind_info_30_header =
1432 (sizeof(function_30)/2) | /* function length */
1433 (0 << 20) | /* X */
1434 (0 << 21) | /* E */
1435 (0 << 22) | /* F */
1436 (0 << 23) | /* epilog */
1437 (2 << 28); /* codes, (sizeof(unwind_info_30)-headers+3)/4 */
1438
1439 static const BYTE unwind_info_30[] =
1440 {
1441 DW(unwind_info_30_header),
1442 UWOP_ALLOC_SMALL(12), /* sub sp, sp, #12 */
1443 UWOP_SAVE_REGS((1<<lr)), /* push {lr} */
1444 UWOP_MSFT_OP_MACHINE_FRAME,
1445 UWOP_END,
1446 };
1447
1448 static const struct results_arm results_30[] =
1449 {
1450 /* offset fp handler pc frame offset registers */
1451 { 0x00, 0x10, 0, 0x04, 0x00, FALSE, { {sp,0x00}, {-1,-1} }},
1452 { 0x02, 0x10, 0, 0x08, 0x04, FALSE, { {lr,0x00}, {sp,0x04}, {-1,-1} }},
1453 { 0x04, 0x10, 0, 0x14, 0x10, FALSE, { {lr,0x0c}, {sp,0x10}, {-1,-1} }},
1454 };
1455
1456 static const BYTE function_31[] =
1457 {
1458 0x00, 0xbf, /* 00: nop */
1459 0x00, 0xbf, /* 02: nop */
1460 };
1461
1462 static const struct results_arm results_31[] =
1463 {
1464 /* offset fp handler pc frame offset registers */
1465 { 0x00, 0, -1, ORIG_LR, 0x00, TRUE, { {-1,-1} }},
1466 { 0x02, 0, -1, ORIG_LR, 0x00, TRUE, { {-1,-1} }},
1467 { 0x04, 0, -2, 0, 0xdeadbeef, FALSE, { {-1,-1} }},
1468 };
1469
1470 static const struct unwind_test_arm tests[] =
1471 {
1472#define TEST(func, unwind, size, results) \
1473 { func, sizeof(func), unwind, size, results, ARRAY_SIZE(results) }
1474 TEST(function_0, unwind_info_0, sizeof(unwind_info_0), results_0),
1475 TEST(function_1, unwind_info_1, sizeof(unwind_info_1), results_1),
1476 TEST(function_2, unwind_info_2, sizeof(unwind_info_2), results_2),
1477 TEST(function_3, unwind_info_3, sizeof(unwind_info_3), results_3),
1478 TEST(function_4, unwind_info_4, sizeof(unwind_info_4), results_4),
1479 TEST(function_5, unwind_info_5, sizeof(unwind_info_5), results_5),
1480 TEST(function_6, unwind_info_6, 0, results_6),
1481 TEST(function_7, unwind_info_7, 0, results_7),
1482 TEST(function_8, unwind_info_8, 0, results_8),
1483 TEST(function_9, unwind_info_9, 0, results_9),
1484 TEST(function_10, unwind_info_10, 0, results_10),
1485 TEST(function_11, unwind_info_11, 0, results_11),
1486 TEST(function_12, unwind_info_12, 0, results_12),
1487 TEST(function_13, unwind_info_13, 0, results_13),
1488 TEST(function_14, unwind_info_14, 0, results_14),
1489 TEST(function_15, unwind_info_15, 0, results_15),
1490 TEST(function_16, unwind_info_16, 0, results_16),
1491 TEST(function_17, unwind_info_17, 0, results_17),
1492 TEST(function_18, unwind_info_18, 0, results_18),
1493 TEST(function_19, unwind_info_19, 0, results_19),
1494 TEST(function_20, unwind_info_20, 0, results_20),
1495 TEST(function_21, unwind_info_21, 0, results_21),
1496 TEST(function_22, unwind_info_22, 0, results_22),
1497 TEST(function_23, unwind_info_23, 0, results_23),
1498 TEST(function_24, unwind_info_24, 0, results_24),
1499 TEST(function_25, unwind_info_25, 0, results_25),
1500 TEST(function_26, unwind_info_26, 0, results_26),
1501 TEST(function_27, unwind_info_27, 0, results_27),
1502 TEST(function_28, unwind_info_28, 0, results_28),
1503 TEST(function_29, unwind_info_29, sizeof(unwind_info_29), results_29),
1504 TEST(function_30, unwind_info_30, sizeof(unwind_info_30), results_30),
1505 TEST(function_31, NULL, 0, results_31),
1506#undef TEST
1507 };
1508 unsigned int i;
1509
1510 for (i = 0; i < ARRAY_SIZE(tests); i++)
1511 call_virtual_unwind_arm( i, &tests[i] );
1512}
1513
1514#endif /* __arm__ */
1515
1516#if defined(__aarch64__) || defined(__x86_64__)
1517
1518#define UWOP_TWOBYTES(x) (((x) >> 8) & 0xff), ((x) & 0xff)
1519
1520#define UWOP_ALLOC_SMALL(size) (0x00 | (size/16))
1521#define UWOP_SAVE_R19R20_X(offset) (0x20 | (offset/8))
1522#define UWOP_SAVE_FPLR(offset) (0x40 | (offset/8))
1523#define UWOP_SAVE_FPLR_X(offset) (0x80 | (offset/8 - 1))
1524#define UWOP_ALLOC_MEDIUM(size) UWOP_TWOBYTES((0xC0 << 8) | (size/16))
1525#define UWOP_SAVE_REGP(reg, offset) UWOP_TWOBYTES((0xC8 << 8) | ((reg - 19) << 6) | (offset/8))
1526#define UWOP_SAVE_REGP_X(reg, offset) UWOP_TWOBYTES((0xCC << 8) | ((reg - 19) << 6) | (offset/8 - 1))
1527#define UWOP_SAVE_REG(reg, offset) UWOP_TWOBYTES((0xD0 << 8) | ((reg - 19) << 6) | (offset/8))
1528#define UWOP_SAVE_REG_X(reg, offset) UWOP_TWOBYTES((0xD4 << 8) | ((reg - 19) << 5) | (offset/8 - 1))
1529#define UWOP_SAVE_LRP(reg, offset) UWOP_TWOBYTES((0xD6 << 8) | ((reg - 19)/2 << 6) | (offset/8))
1530#define UWOP_SAVE_FREGP(reg, offset) UWOP_TWOBYTES((0xD8 << 8) | ((reg - 8) << 6) | (offset/8))
1531#define UWOP_SAVE_FREGP_X(reg, offset) UWOP_TWOBYTES((0xDA << 8) | ((reg - 8) << 6) | (offset/8 - 1))
1532#define UWOP_SAVE_FREG(reg, offset) UWOP_TWOBYTES((0xDC << 8) | ((reg - 8) << 6) | (offset/8))
1533#define UWOP_SAVE_FREG_X(reg, offset) UWOP_TWOBYTES((0xDE << 8) | ((reg - 8) << 5) | (offset/8 - 1))
1534#define UWOP_ALLOC_LARGE(size) UWOP_TWOBYTES((0xE0 << 8) | ((size/16) >> 16)), UWOP_TWOBYTES(size/16)
1535#define UWOP_SET_FP 0xE1
1536#define UWOP_ADD_FP(offset) UWOP_TWOBYTES((0xE2 << 8) | (offset/8))
1537#define UWOP_NOP 0xE3
1538#define UWOP_END 0xE4
1539#define UWOP_END_C 0xE5
1540#define UWOP_SAVE_NEXT 0xE6
1541#define UWOP_SAVE_ANY_REG(reg,offset) 0xE7,(reg),(offset)
1542#define UWOP_TRAP_FRAME 0xE8
1543#define UWOP_MACHINE_FRAME 0xE9
1544#define UWOP_CONTEXT 0xEA
1545#define UWOP_EC_CONTEXT 0xEB
1546#define UWOP_CLEAR_UNWOUND_TO_CALL 0xEC
1547
1548struct results_arm64
1549{
1550 int pc_offset; /* pc offset from code start */
1551 int fp_offset; /* fp offset from stack pointer */
1552 int handler; /* expect handler to be set? */
1553 ULONG_PTR pc; /* expected final pc value */
1554 ULONG_PTR frame; /* expected frame return value */
1555 int frame_offset; /* whether the frame return value is an offset or an absolute value */
1556 ULONG_PTR regs[48][2]; /* expected values for registers */
1557};
1558
1559struct unwind_test_arm64
1560{
1561 const BYTE *function;
1562 size_t function_size;
1563 const BYTE *unwind_info;
1564 size_t unwind_size;
1565 const struct results_arm64 *results;
1566 unsigned int nb_results;
1567 int unwound_clear;
1568 int last_set_reg_ptr;
1569 int stack_value_index;
1570 ULONG64 stack_value;
1571};
1572
1573enum regs_arm64
1574{
1575 x0, x1, x2, x3, x4, x5, x6, x7,
1576 x8, x9, x10, x11, x12, x13, x14, x15,
1577 x16, x17, x18, x19, x20, x21, x22, x23,
1578 x24, x25, x26, x27, x28, x29, lr, sp,
1579 d0, d1, d2, d3, d4, d5, d6, d7,
1580 d8, d9, d10, d11, d12, d13, d14, d15
1581};
1582
1583static const char * const reg_names_arm64[48] =
1584{
1585 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
1586 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
1587 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
1588 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp",
1589 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
1590 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
1591};
1592
1593#define ORIG_LR 0xCCCCCCCC
1594
1595static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct unwind_test_arm64 *test )
1596{
1597 static const int code_offset = 1024;
1598 static const int unwind_offset = 2048;
1599 void *data;
1600#ifdef __x86_64__
1601 ARM64EC_NT_CONTEXT context, new_context;
1602#else
1603 ARM64_NT_CONTEXT context, new_context;
1604#endif
1606 ARM64_RUNTIME_FUNCTION runtime_func;
1607 KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
1608 UINT i, j, k;
1610 ULONG64 fake_stack[256];
1611 ULONG64 frame, orig_pc, orig_fp, unset_reg, sp_offset = 0, regval, *regptr;
1612 static const UINT nb_regs = ARRAY_SIZE(test->results[i].regs);
1613
1614 memcpy( (char *)code_mem + code_offset, test->function, test->function_size );
1615 if (test->unwind_info)
1616 {
1617 memcpy( (char *)code_mem + unwind_offset, test->unwind_info, test->unwind_size );
1618 runtime_func.BeginAddress = code_offset;
1619 if (test->unwind_size)
1620 runtime_func.UnwindData = unwind_offset;
1621 else
1622 memcpy(&runtime_func.UnwindData, test->unwind_info, 4);
1623 }
1624
1625 for (i = 0; i < test->nb_results; i++)
1626 {
1627#ifdef __x86_64__
1628 if (test->results[i].handler == -2) continue; /* skip invalid leaf function test */
1629#endif
1630 winetest_push_context( "%u/%u", testnum, i );
1631 memset( &ctx_ptr, 0x55, sizeof(ctx_ptr) );
1632 memset( &context, 0x55, sizeof(context) );
1633 memset( &unset_reg, 0x55, sizeof(unset_reg) );
1634 for (j = 0; j < 256; j++) fake_stack[j] = j * 8;
1635 if (test->stack_value_index != -1) fake_stack[test->stack_value_index] = test->stack_value;
1636
1637 context.Sp = (ULONG_PTR)fake_stack;
1638 context.Lr = (ULONG_PTR)ORIG_LR;
1639 context.Fp = (ULONG_PTR)fake_stack + test->results[i].fp_offset;
1640 context.ContextFlags = 0xcccc;
1641 if (test->unwound_clear) context.ContextFlags |= CONTEXT_ARM64_UNWOUND_TO_CALL;
1642
1643 orig_fp = context.Fp;
1644 orig_pc = (ULONG64)code_mem + code_offset + test->results[i].pc_offset;
1645
1646 trace( "pc=%p (%02x) fp=%p sp=%p\n", (void *)orig_pc, *(UINT *)orig_pc, (void *)orig_fp, (void *)context.Sp );
1647
1648 if (test->results[i].handler == -2) orig_pc = context.Lr;
1649
1650 if (pRtlVirtualUnwind2)
1651 {
1652 new_context = context;
1653 handler = (void *)0xdeadbeef;
1654 data = (void *)0xdeadbeef;
1655 frame = 0xdeadbeef;
1656 status = pRtlVirtualUnwind2( UNW_FLAG_EHANDLER, (ULONG_PTR)code_mem, orig_pc,
1657 test->unwind_info ? (RUNTIME_FUNCTION *)&runtime_func : NULL,
1658 (CONTEXT *)&new_context, NULL, &data,
1659 &frame, &ctx_ptr, NULL, NULL, &handler, 0 );
1660 if (test->results[i].handler > 0)
1661 {
1662 ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
1663 ok( (char *)handler == (char *)code_mem + 0x200,
1664 "wrong handler %p/%p\n", handler, (char *)code_mem + 0x200 );
1665 if (handler) ok( *(DWORD *)data == 0x08070605,
1666 "wrong handler data %lx\n", *(DWORD *)data );
1667 }
1668 else if (test->results[i].handler < -1)
1669 {
1670 ok( status == STATUS_BAD_FUNCTION_TABLE, "RtlVirtualUnwind2 failed %lx\n", status );
1671 ok( handler == (void *)0xdeadbeef, "handler set to %p\n", handler );
1672 ok( data == (void *)0xdeadbeef, "handler data set to %p\n", data );
1673 }
1674 else
1675 {
1676 ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
1677 ok( handler == NULL, "handler %p instead of NULL\n", handler );
1678 ok( data == NULL, "handler data set to %p\n", data );
1679 }
1680 }
1681
1682 data = (void *)0xdeadbeef;
1683 frame = 0xdeadbeef;
1684 handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)code_mem, orig_pc,
1685 test->unwind_info ? (RUNTIME_FUNCTION *)&runtime_func : NULL,
1686 (CONTEXT *)&context, &data, &frame, &ctx_ptr );
1687 if (test->results[i].handler > 0)
1688 {
1689 ok( (char *)handler == (char *)code_mem + 0x200,
1690 "wrong handler %p/%p\n", handler, (char *)code_mem + 0x200 );
1691 if (handler) ok( *(DWORD *)data == 0x08070605,
1692 "wrong handler data %lx\n", *(DWORD *)data );
1693 }
1694 else
1695 {
1696 ok( handler == NULL, "handler %p instead of NULL\n", handler );
1697 ok( data == (test->results[i].handler < -1 ? (void *)0xdeadbeef : NULL),
1698 "handler data set to %p/%p\n", data,
1699 (test->results[i].handler < 0 ? (void *)0xdeadbeef : NULL) );
1700 }
1701
1702 ok( context.Pc == test->results[i].pc, "wrong pc %p/%p\n",
1703 (void *)context.Pc, (void*)test->results[i].pc );
1704 ok( frame == (test->results[i].frame_offset ? (ULONG64)fake_stack : 0) + test->results[i].frame, "wrong frame %p/%p\n",
1705 (void *)frame, (char *)(test->results[i].frame_offset ? fake_stack : NULL) + test->results[i].frame );
1706 if (test->results[i].handler == -2) /* invalid leaf function */
1707 {
1708 ok( context.ContextFlags == 0xcccc, "wrong flags %lx\n", context.ContextFlags );
1709 ok( context.Sp == (ULONG_PTR)fake_stack, "wrong sp %p/%p\n", (void *)context.Sp, fake_stack);
1710 }
1711 else
1712 {
1713 if (!test->unwound_clear || i < test->unwound_clear)
1714 ok( context.ContextFlags == (0xcccc | CONTEXT_ARM64_UNWOUND_TO_CALL),
1715 "wrong flags %lx\n", context.ContextFlags );
1716 else
1717 ok( context.ContextFlags == 0xcccc,
1718 "wrong flags %lx\n", context.ContextFlags );
1719
1720 sp_offset = 0;
1721 for (k = 0; k < nb_regs; k++)
1722 {
1723 if (test->results[i].regs[k][0] == -1)
1724 break;
1725 if (test->results[i].regs[k][0] == sp) {
1726 /* If sp is part of the registers list, treat it as an offset
1727 * between the returned frame pointer and the sp register. */
1728 sp_offset = test->results[i].regs[k][1];
1729 break;
1730 }
1731 }
1732 ok( frame - sp_offset == context.Sp, "wrong sp %p/%p\n",
1733 (void *)(frame - sp_offset), (void *)context.Sp);
1734 }
1735
1736#ifdef __x86_64__
1737 for (j = 0; j < sizeof(ctx_ptr)/sizeof(void*); j++)
1738 ok( ((void **)&ctx_ptr)[j] == (void *)unset_reg,
1739 "ctx_ptr %u set to %p\n", j, ((void **)&ctx_ptr)[j] );
1740#endif
1741
1742 for (j = 0; j < 48; j++)
1743 {
1744 switch (j)
1745 {
1746#define GET(i) case i: regval = context.X##i; break
1747 GET(0); GET(1); GET(2); GET(3); GET(4); GET(5); GET(6); GET(7);
1748 GET(8); GET(9); GET(10); GET(11); GET(12);
1749 GET(15); GET(19); GET(20); GET(21); GET(22); GET(25); GET(26); GET(27);
1750#ifdef __x86_64__
1751 case x13: case x14: continue;
1752 case x16: regval = context.X16_0 | ((DWORD64)context.X16_1 << 16) | ((DWORD64)context.X16_2 << 32) | ((DWORD64)context.X16_3 << 48); break;
1753 case x17: regval = context.X17_0 | ((DWORD64)context.X17_1 << 16) | ((DWORD64)context.X17_2 << 32) | ((DWORD64)context.X17_3 << 48); break;
1754 case x18: case x23: case x24: case x28: continue;
1755#else
1756 GET(13); GET(14); GET(16); GET(17); GET(18); GET(23); GET(24); GET(28);
1757#endif
1758#undef GET
1759 case x29: regval = context.Fp; break;
1760 case lr: regval = context.Lr; break;
1761 case sp: continue; /* Handling sp separately above */
1762 default: regval = context.V[j - d0].Low; break;
1763 }
1764
1765 regptr = NULL;
1766#ifndef __x86_64__
1767 if (j >= 19 && j <= 30) regptr = (&ctx_ptr.X19)[j - 19];
1768 else if (j >= d8 && j <= d15) regptr = (&ctx_ptr.D8)[j - d8];
1769#endif
1770
1771 for (k = 0; k < nb_regs; k++)
1772 {
1773 if (test->results[i].regs[k][0] == -1)
1774 {
1775 k = nb_regs;
1776 break;
1777 }
1778 if (test->results[i].regs[k][0] == j) break;
1779 }
1780
1781 if (k < nb_regs)
1782 {
1783 ok( regval == test->results[i].regs[k][1],
1784 "register %s wrong %I64x/%I64x\n", reg_names_arm64[j], regval, test->results[i].regs[k][1] );
1785 if (regptr)
1786 {
1787 if (test->last_set_reg_ptr && j > test->last_set_reg_ptr && j <= 30)
1788 ok( regptr == (void *)unset_reg, "register %s should not have pointer set\n", reg_names_arm64[j] );
1789 else
1790 {
1791 ok( regptr != (void *)unset_reg, "register %s should have pointer set\n", reg_names_arm64[j] );
1792 if (regptr != (void *)unset_reg)
1793 ok( *regptr == regval, "register %s should have reg pointer to %I64x / %I64x\n",
1794 reg_names_arm64[j], *regptr, regval );
1795 }
1796 }
1797 }
1798 else
1799 {
1800 ok( k == nb_regs, "register %s should be set\n", reg_names_arm64[j] );
1801 ok( !regptr || regptr == (void *)unset_reg, "register %s should not have pointer set\n", reg_names_arm64[j] );
1802 if (j == lr)
1803 ok( context.Lr == ORIG_LR, "register lr wrong %I64x/unset\n", context.Lr );
1804 else if (j == x29)
1805 ok( context.Fp == orig_fp, "register fp wrong %I64x/unset\n", context.Fp );
1806 else
1807 ok( regval == unset_reg, "register %s wrong %I64x/unset\n", reg_names_arm64[j], regval);
1808 }
1809 }
1811 }
1812}
1813
1814#ifndef __REACTOS__
1815#define DW(dword) ((dword >> 0) & 0xff), ((dword >> 8) & 0xff), ((dword >> 16) & 0xff), ((dword >> 24) & 0xff)
1816
1817static void test_virtual_unwind_arm64(void)
1818{
1819 static const BYTE function_0[] =
1820 {
1821 0xff, 0x83, 0x00, 0xd1, /* 00: sub sp, sp, #32 */
1822 0xf3, 0x53, 0x01, 0xa9, /* 04: stp x19, x20, [sp, #16] */
1823 0x1f, 0x20, 0x03, 0xd5, /* 08: nop */
1824 0xf3, 0x53, 0x41, 0xa9, /* 0c: ldp x19, x20, [sp, #16] */
1825 0xff, 0x83, 0x00, 0x91, /* 10: add sp, sp, #32 */
1826 0xc0, 0x03, 0x5f, 0xd6, /* 14: ret */
1827 };
1828
1829 static const DWORD unwind_info_0_header =
1830 (sizeof(function_0)/4) | /* function length */
1831 (1 << 20) | /* X */
1832 (0 << 21) | /* E */
1833 (1 << 22) | /* epilog */
1834 (2 << 27); /* codes */
1835 static const DWORD unwind_info_0_epilog0 =
1836 (3 << 0) | /* offset */
1837 (4 << 22); /* index */
1838
1839 static const BYTE unwind_info_0[] =
1840 {
1841 DW(unwind_info_0_header),
1842 DW(unwind_info_0_epilog0),
1843
1844 UWOP_SAVE_REGP(19, 16), /* stp x19, x20, [sp, #16] */
1845 UWOP_ALLOC_SMALL(32), /* sub sp, sp, #32 */
1846 UWOP_END,
1847
1848 UWOP_SAVE_REGP(19, 16), /* stp x19, x20, [sp, #16] */
1849 UWOP_ALLOC_SMALL(32), /* sub sp, sp, #32 */
1850 UWOP_END,
1851
1852 0x00, 0x02, 0x00, 0x00, /* handler */
1853 0x05, 0x06, 0x07, 0x08, /* data */
1854 };
1855
1856 static const struct results_arm64 results_0[] =
1857 {
1858 /* offset fp handler pc frame offset registers */
1859 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1860 { 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {-1,-1} }},
1861 { 0x08, 0x00, 1, ORIG_LR, 0x020, TRUE, { {x19,0x10}, {x20,0x18}, {-1,-1} }},
1862 { 0x0c, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x10}, {x20,0x18}, {-1,-1} }},
1863 { 0x10, 0x00, 0, ORIG_LR, 0x020, TRUE, { {-1,-1} }},
1864 { 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1865 };
1866
1867
1868 static const BYTE function_1[] =
1869 {
1870 0xf3, 0x53, 0xbe, 0xa9, /* 00: stp x19, x20, [sp, #-32]! */
1871 0xfe, 0x0b, 0x00, 0xf9, /* 04: str x30, [sp, #16] */
1872 0xff, 0x43, 0x00, 0xd1, /* 08: sub sp, sp, #16 */
1873 0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
1874 0xff, 0x43, 0x00, 0x91, /* 10: add sp, sp, #16 */
1875 0xfe, 0x0b, 0x40, 0xf9, /* 14: ldr x30, [sp, #16] */
1876 0xf3, 0x53, 0xc2, 0xa8, /* 18: ldp x19, x20, [sp], #32 */
1877 0xc0, 0x03, 0x5f, 0xd6, /* 1c: ret */
1878 };
1879
1880 static const DWORD unwind_info_1_packed =
1881 (1 << 0) | /* Flag */
1882 (sizeof(function_1)/4 << 2) | /* FunctionLength */
1883 (0 << 13) | /* RegF */
1884 (2 << 16) | /* RegI */
1885 (0 << 20) | /* H */
1886 (1 << 21) | /* CR */
1887 (3 << 23); /* FrameSize */
1888
1889 static const BYTE unwind_info_1[] = { DW(unwind_info_1_packed) };
1890
1891 static const struct results_arm64 results_1[] =
1892 {
1893 /* offset fp handler pc frame offset registers */
1894 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1895 { 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
1896 { 0x08, 0x00, 0, 0x10, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }},
1897 { 0x0c, 0x00, 0, 0x20, 0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }},
1898 { 0x10, 0x00, 0, 0x20, 0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }},
1899 { 0x14, 0x00, 0, 0x10, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }},
1900 { 0x18, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
1901 { 0x1c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
1902 };
1903
1904 static const BYTE function_2[] =
1905 {
1906 0xff, 0x43, 0x00, 0xd1, /* 00: sub sp, sp, #16 */
1907 0x1f, 0x20, 0x03, 0xd5, /* 04: nop */
1908 0xff, 0x43, 0x00, 0xd1, /* 08: sub sp, sp, #16 */
1909 0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
1910 0xc0, 0x03, 0x5f, 0xd6, /* 10: ret */
1911 };
1912
1913 static const DWORD unwind_info_2_header =
1914 (sizeof(function_2)/4) | /* function length */
1915 (0 << 20) | /* X */
1916 (0 << 21) | /* E */
1917 (0 << 22) | /* epilog */
1918 (1 << 27); /* codes */
1919
1920 static const BYTE unwind_info_2[] =
1921 {
1922 DW(unwind_info_2_header),
1923
1924 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
1925 UWOP_MACHINE_FRAME,
1926 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
1927 UWOP_END,
1928 };
1929
1930 /* Partial prologues with the custom frame opcodes (machine frame,
1931 * context) behave like there's one less instruction to skip, because the
1932 * custom frame is set up externally without an explicit instruction. */
1933 static const struct results_arm64 results_2[] =
1934 {
1935 /* offset fp handler pc frame offset registers */
1936 { 0x00, 0x00, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1937 { 0x04, 0x00, 0, 0x0008, 0x010, FALSE, { {-1,-1} }},
1938 { 0x08, 0x00, 0, 0x0018, 0x020, FALSE, { {-1,-1} }},
1939 { 0x0c, 0x00, 0, 0x0018, 0x020, FALSE, { {-1,-1} }},
1940 { 0x10, 0x00, 0, 0x0018, 0x020, FALSE, { {-1,-1} }},
1941 };
1942
1943 static const BYTE function_3[] =
1944 {
1945 0xff, 0x43, 0x00, 0xd1, /* 00: sub sp, sp, #16 */
1946 0x1f, 0x20, 0x03, 0xd5, /* 04: nop */
1947 0xff, 0x43, 0x00, 0xd1, /* 08: sub sp, sp, #16 */
1948 0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
1949 0xc0, 0x03, 0x5f, 0xd6, /* 10: ret */
1950 };
1951
1952 static const DWORD unwind_info_3_header =
1953 (sizeof(function_3)/4) | /* function length */
1954 (0 << 20) | /* X */
1955 (0 << 21) | /* E */
1956 (0 << 22) | /* epilog */
1957 (1 << 27); /* codes */
1958
1959 static const BYTE unwind_info_3[] =
1960 {
1961 DW(unwind_info_3_header),
1962
1963 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
1964 UWOP_CONTEXT,
1965 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
1966 UWOP_END,
1967 };
1968
1969 static const struct results_arm64 results_3[] =
1970 {
1971 /* offset fp handler pc frame offset registers */
1972 { 0x00, 0x00, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
1973 { 0x04, 0x00, 0 , 0x0108, 0x110, FALSE, { {x0, 0x08}, {x1, 0x10}, {x2, 0x18}, {x3, 0x20}, {x4, 0x28}, {x5, 0x30}, {x6, 0x38}, {x7, 0x40}, {x8, 0x48}, {x9, 0x50}, {x10, 0x58}, {x11, 0x60}, {x12, 0x68}, {x13, 0x70}, {x14, 0x78}, {x15, 0x80}, {x16, 0x88}, {x17, 0x90}, {x18, 0x98}, {x19, 0xA0}, {x20, 0xA8}, {x21, 0xB0}, {x22, 0xB8}, {x23, 0xC0}, {x24, 0xC8}, {x25, 0xD0}, {x26, 0xD8}, {x27, 0xE0}, {x28, 0xE8}, {x29, 0xF0}, {lr, 0xF8}, {d0, 0x110}, {d1, 0x120}, {d2, 0x130}, {d3, 0x140}, {d4, 0x150}, {d5, 0x160}, {d6, 0x170}, {d7, 0x180}, {d8, 0x190}, {d9, 0x1a0}, {d10, 0x1b0}, {d11, 0x1c0}, {d12, 0x1d0}, {d13, 0x1e0}, {d14, 0x1f0}, {d15, 0x200}, {-1,-1} }},
1974 { 0x08, 0x00, 0 , 0x0118, 0x120, FALSE, { {x0, 0x18}, {x1, 0x20}, {x2, 0x28}, {x3, 0x30}, {x4, 0x38}, {x5, 0x40}, {x6, 0x48}, {x7, 0x50}, {x8, 0x58}, {x9, 0x60}, {x10, 0x68}, {x11, 0x70}, {x12, 0x78}, {x13, 0x80}, {x14, 0x88}, {x15, 0x90}, {x16, 0x98}, {x17, 0xA0}, {x18, 0xA8}, {x19, 0xB0}, {x20, 0xB8}, {x21, 0xC0}, {x22, 0xC8}, {x23, 0xD0}, {x24, 0xD8}, {x25, 0xE0}, {x26, 0xE8}, {x27, 0xF0}, {x28, 0xF8}, {x29, 0x100}, {lr, 0x108}, {d0, 0x120}, {d1, 0x130}, {d2, 0x140}, {d3, 0x150}, {d4, 0x160}, {d5, 0x170}, {d6, 0x180}, {d7, 0x190}, {d8, 0x1a0}, {d9, 0x1b0}, {d10, 0x1c0}, {d11, 0x1d0}, {d12, 0x1e0}, {d13, 0x1f0}, {d14, 0x200}, {d15, 0x210}, {-1,-1} }},
1975 { 0x0c, 0x00, 0 , 0x0118, 0x120, FALSE, { {x0, 0x18}, {x1, 0x20}, {x2, 0x28}, {x3, 0x30}, {x4, 0x38}, {x5, 0x40}, {x6, 0x48}, {x7, 0x50}, {x8, 0x58}, {x9, 0x60}, {x10, 0x68}, {x11, 0x70}, {x12, 0x78}, {x13, 0x80}, {x14, 0x88}, {x15, 0x90}, {x16, 0x98}, {x17, 0xA0}, {x18, 0xA8}, {x19, 0xB0}, {x20, 0xB8}, {x21, 0xC0}, {x22, 0xC8}, {x23, 0xD0}, {x24, 0xD8}, {x25, 0xE0}, {x26, 0xE8}, {x27, 0xF0}, {x28, 0xF8}, {x29, 0x100}, {lr, 0x108}, {d0, 0x120}, {d1, 0x130}, {d2, 0x140}, {d3, 0x150}, {d4, 0x160}, {d5, 0x170}, {d6, 0x180}, {d7, 0x190}, {d8, 0x1a0}, {d9, 0x1b0}, {d10, 0x1c0}, {d11, 0x1d0}, {d12, 0x1e0}, {d13, 0x1f0}, {d14, 0x200}, {d15, 0x210}, {-1,-1} }},
1976 { 0x10, 0x00, 0 , 0x0118, 0x120, FALSE, { {x0, 0x18}, {x1, 0x20}, {x2, 0x28}, {x3, 0x30}, {x4, 0x38}, {x5, 0x40}, {x6, 0x48}, {x7, 0x50}, {x8, 0x58}, {x9, 0x60}, {x10, 0x68}, {x11, 0x70}, {x12, 0x78}, {x13, 0x80}, {x14, 0x88}, {x15, 0x90}, {x16, 0x98}, {x17, 0xA0}, {x18, 0xA8}, {x19, 0xB0}, {x20, 0xB8}, {x21, 0xC0}, {x22, 0xC8}, {x23, 0xD0}, {x24, 0xD8}, {x25, 0xE0}, {x26, 0xE8}, {x27, 0xF0}, {x28, 0xF8}, {x29, 0x100}, {lr, 0x108}, {d0, 0x120}, {d1, 0x130}, {d2, 0x140}, {d3, 0x150}, {d4, 0x160}, {d5, 0x170}, {d6, 0x180}, {d7, 0x190}, {d8, 0x1a0}, {d9, 0x1b0}, {d10, 0x1c0}, {d11, 0x1d0}, {d12, 0x1e0}, {d13, 0x1f0}, {d14, 0x200}, {d15, 0x210}, {-1,-1} }},
1977 };
1978
1979 static const BYTE function_4[] =
1980 {
1981 0xff, 0x43, 0x00, 0xd1, /* 00: sub sp, sp, #16 */
1982 0xff, 0x03, 0x08, 0xd1, /* 04: sub sp, sp, #512 */
1983 0xff, 0x43, 0x40, 0xd1, /* 08: sub sp, sp, #65536 */
1984 0xfd, 0x03, 0x00, 0x91, /* 0c: mov x29, sp */
1985 0xf3, 0x53, 0xbe, 0xa9, /* 10: stp x19, x20, [sp, #-32]! */
1986 0xf5, 0x5b, 0x01, 0xa9, /* 14: stp x21, x22, [sp, #16] */
1987 0xf7, 0x0f, 0x1e, 0xf8, /* 18: str x23, [sp, #-32]! */
1988 0xf8, 0x07, 0x00, 0xf9, /* 1c: str x24, [sp, #8] */
1989 0xf9, 0x7b, 0x01, 0xa9, /* 20: stp x25, x30, [sp, #16] */
1990 0xfd, 0x7b, 0x03, 0xa9, /* 24: stp x29, x30, [sp, #48] */
1991 0xfd, 0x7b, 0xbe, 0xa9, /* 28: stp x29, x30, [sp, #-32]! */
1992 0xf3, 0x53, 0xbe, 0xa9, /* 2c: stp x19, x20, [sp, #-32]! */
1993 0xe8, 0x27, 0xbe, 0x6d, /* 30: stp d8, d9, [sp, #-32]! */
1994 0xea, 0x2f, 0x01, 0x6d, /* 34: stp d10, d11, [sp, #16] */
1995 0xec, 0x0f, 0x1e, 0xfc, /* 38: str d12, [sp, #-32]! */
1996 0xed, 0x07, 0x00, 0xfd, /* 3c: str d13, [sp, #8] */
1997 0xfd, 0x43, 0x00, 0x91, /* 40: add x29, sp, #16 */
1998 0xc0, 0x03, 0x5f, 0xd6, /* 44: ret */
1999 };
2000
2001 static const DWORD unwind_info_4_header =
2002 (sizeof(function_4)/4) | /* function length */
2003 (0 << 20) | /* X */
2004 (0 << 21) | /* E */
2005 (0 << 22) | /* epilog */
2006 (8 << 27); /* codes */
2007
2008 static const BYTE unwind_info_4[] =
2009 {
2010 DW(unwind_info_4_header),
2011
2012 UWOP_ADD_FP(16), /* 40: add x29, sp, #16 */
2013 UWOP_SAVE_FREG(13, 8), /* 3c: str d13, [sp, #8] */
2014 UWOP_SAVE_FREG_X(12, 32), /* 38: str d12, [sp, #-32]! */
2015 UWOP_SAVE_FREGP(10, 16), /* 34: stp d10, d11, [sp, #16] */
2016 UWOP_SAVE_FREGP_X(8, 32), /* 30: stp d8, d9, [sp, #-32]! */
2017 UWOP_SAVE_R19R20_X(32), /* 2c: stp x19, x20, [sp, #-32]! */
2018 UWOP_SAVE_FPLR_X(32), /* 28: stp x29, x30, [sp, #-32]! */
2019 UWOP_SAVE_FPLR(16), /* 24: stp x29, x30, [sp, #16] */
2020 UWOP_SAVE_LRP(25, 16), /* 20: stp x25, x30, [sp, #16] */
2021 UWOP_SAVE_REG(24, 8), /* 1c: str x24, [sp, #8] */
2022 UWOP_SAVE_REG_X(23, 32), /* 18: str x23, [sp, #-32]! */
2023 UWOP_SAVE_REGP(21, 16), /* 14: stp x21, x22, [sp, #16] */
2024 UWOP_SAVE_REGP_X(19, 32), /* 10: stp x19, x20, [sp, #-32]! */
2025 UWOP_SET_FP, /* 0c: mov x29, sp */
2026 UWOP_ALLOC_LARGE(65536), /* 08: sub sp, sp, #65536 */
2027 UWOP_ALLOC_MEDIUM(512), /* 04: sub sp, sp, #512 */
2028 UWOP_ALLOC_SMALL(16), /* 00: sub sp, sp, #16 */
2029 UWOP_END,
2030 };
2031
2032 static const struct results_arm64 results_4[] =
2033 {
2034 /* offset fp handler pc frame offset registers */
2035 { 0x00, 0x10, 0, ORIG_LR, 0x00000, TRUE, { {-1,-1} }},
2036 { 0x04, 0x10, 0, ORIG_LR, 0x00010, TRUE, { {-1,-1} }},
2037 { 0x08, 0x10, 0, ORIG_LR, 0x00210, TRUE, { {-1,-1} }},
2038 { 0x0c, 0x10, 0, ORIG_LR, 0x10210, TRUE, { {-1,-1} }},
2039 { 0x14, 0x00, 0, ORIG_LR, 0x10210, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2040 { 0x18, 0x00, 0, ORIG_LR, 0x10210, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {x22, 0x18}, {-1,-1} }},
2041 { 0x1c, 0x00, 0, ORIG_LR, 0x10210, TRUE, { {x19, 0x20}, {x20, 0x28}, {x21, 0x30}, {x22, 0x38}, {x23, 0x00}, {-1,-1} }},
2042 { 0x20, 0x00, 0, ORIG_LR, 0x10210, TRUE, { {x19, 0x20}, {x20, 0x28}, {x21, 0x30}, {x22, 0x38}, {x23, 0x00}, {x24, 0x08}, {-1,-1} }},
2043 { 0x24, 0x00, 0, 0x0018, 0x10210, TRUE, { {x19, 0x20}, {x20, 0x28}, {x21, 0x30}, {x22, 0x38}, {x23, 0x00}, {x24, 0x08}, {x25, 0x10}, {lr, 0x18}, {-1,-1} }},
2044 { 0x28, 0x00, 0, 0x0018, 0x10220, FALSE, { {x19, 0x20}, {x20, 0x28}, {x21, 0x30}, {x22, 0x38}, {x23, 0x00}, {x24, 0x08}, {x25, 0x10}, {lr, 0x18}, {x29, 0x10}, {-1,-1} }},
2045 { 0x2c, 0x00, 0, 0x0038, 0x10240, FALSE, { {x19, 0x40}, {x20, 0x48}, {x21, 0x50}, {x22, 0x58}, {x23, 0x20}, {x24, 0x28}, {x25, 0x30}, {lr, 0x38}, {x29, 0x30}, {-1,-1} }},
2046 { 0x30, 0x00, 0, 0x0058, 0x10260, FALSE, { {x19, 0x60}, {x20, 0x68}, {x21, 0x70}, {x22, 0x78}, {x23, 0x40}, {x24, 0x48}, {x25, 0x50}, {lr, 0x58}, {x29, 0x50}, {-1,-1} }},
2047 { 0x34, 0x00, 0, 0x0078, 0x10280, FALSE, { {x19, 0x80}, {x20, 0x88}, {x21, 0x90}, {x22, 0x98}, {x23, 0x60}, {x24, 0x68}, {x25, 0x70}, {lr, 0x78}, {x29, 0x70}, {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
2048 { 0x38, 0x00, 0, 0x0078, 0x10280, FALSE, { {x19, 0x80}, {x20, 0x88}, {x21, 0x90}, {x22, 0x98}, {x23, 0x60}, {x24, 0x68}, {x25, 0x70}, {lr, 0x78}, {x29, 0x70}, {d8, 0x00}, {d9, 0x08}, {d10, 0x10}, {d11, 0x18}, {-1,-1} }},
2049 { 0x3c, 0x00, 0, 0x0098, 0x102a0, FALSE, { {x19, 0xa0}, {x20, 0xa8}, {x21, 0xb0}, {x22, 0xb8}, {x23, 0x80}, {x24, 0x88}, {x25, 0x90}, {lr, 0x98}, {x29, 0x90}, {d8, 0x20}, {d9, 0x28}, {d10, 0x30}, {d11, 0x38}, {d12, 0x00}, {-1,-1} }},
2050 { 0x40, 0x00, 0, 0x0098, 0x102a0, FALSE, { {x19, 0xa0}, {x20, 0xa8}, {x21, 0xb0}, {x22, 0xb8}, {x23, 0x80}, {x24, 0x88}, {x25, 0x90}, {lr, 0x98}, {x29, 0x90}, {d8, 0x20}, {d9, 0x28}, {d10, 0x30}, {d11, 0x38}, {d12, 0x00}, {d13, 0x08}, {-1,-1} }},
2051 { 0x44, 0x20, 0, 0x00a8, 0x102b0, FALSE, { {x19, 0xb0}, {x20, 0xb8}, {x21, 0xc0}, {x22, 0xc8}, {x23, 0x90}, {x24, 0x98}, {x25, 0xa0}, {lr, 0xa8}, {x29, 0xa0}, {d8, 0x30}, {d9, 0x38}, {d10, 0x40}, {d11, 0x48}, {d12, 0x10}, {d13, 0x18}, {-1,-1} }},
2052 };
2053
2054 static const BYTE function_5[] =
2055 {
2056 0xf3, 0x53, 0xbe, 0xa9, /* 00: stp x19, x20, [sp, #-32]! */
2057 0xf5, 0x5b, 0x01, 0xa9, /* 04: stp x21, x22, [sp, #16] */
2058 0xf7, 0x63, 0xbc, 0xa9, /* 08: stp x23, x24, [sp, #-64]! */
2059 0xf9, 0x6b, 0x01, 0xa9, /* 0c: stp x25, x26, [sp, #16] */
2060 0xfb, 0x73, 0x02, 0xa9, /* 10: stp x27, x28, [sp, #32] */
2061 0xfd, 0x7b, 0x03, 0xa9, /* 14: stp x29, x30, [sp, #48] */
2062 0xe8, 0x27, 0xbc, 0x6d, /* 18: stp d8, d9, [sp, #-64]! */
2063 0xea, 0x2f, 0x01, 0x6d, /* 1c: stp d10, d11, [sp, #16] */
2064 0xec, 0x37, 0x02, 0x6d, /* 20: stp d12, d13, [sp, #32] */
2065 0xee, 0x3f, 0x03, 0x6d, /* 24: stp d14, d15, [sp, #48] */
2066 0xc0, 0x03, 0x5f, 0xd6, /* 28: ret */
2067 };
2068
2069 static const DWORD unwind_info_5_header =
2070 (sizeof(function_5)/4) | /* function length */
2071 (0 << 20) | /* X */
2072 (0 << 21) | /* E */
2073 (0 << 22) | /* epilog */
2074 (4 << 27); /* codes */
2075
2076 static const BYTE unwind_info_5[] =
2077 {
2078 DW(unwind_info_5_header),
2079
2080 UWOP_SAVE_NEXT, /* 24: stp d14, d15, [sp, #48] */
2081 UWOP_SAVE_FREGP(12, 32), /* 20: stp d12, d13, [sp, #32] */
2082 UWOP_SAVE_NEXT, /* 1c: stp d10, d11, [sp, #16] */
2083 UWOP_SAVE_FREGP_X(8, 64), /* 18: stp d8, d9, [sp, #-64]! */
2084 UWOP_SAVE_NEXT, /* 14: stp x29, x30, [sp, #48] */
2085 UWOP_SAVE_REGP(27, 32), /* 10: stp x27, x28, [sp, #32] */
2086 UWOP_SAVE_NEXT, /* 0c: stp x25, x26, [sp, #16] */
2087 UWOP_SAVE_REGP_X(23, 64), /* 08: stp x23, x24, [sp, #-64]! */
2088 UWOP_SAVE_NEXT, /* 04: stp x21, x22, [sp, #16] */
2089 UWOP_SAVE_R19R20_X(32), /* 00: stp x19, x20, [sp, #-32]! */
2090 UWOP_END,
2091 UWOP_NOP /* padding */
2092 };
2093
2094 /* Windows seems to only save one register for UWOP_SAVE_NEXT for
2095 * float registers, contrary to what the documentation says. The tests
2096 * for those cases are commented out; they succeed in wine but fail
2097 * on native windows. */
2098 static const struct results_arm64 results_5[] =
2099 {
2100 /* offset fp handler pc frame offset registers */
2101 { 0x00, 0x00, 0, ORIG_LR, 0x00000, TRUE, { {-1,-1} }},
2102 { 0x04, 0x00, 0, ORIG_LR, 0x00020, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2103 { 0x08, 0x00, 0, ORIG_LR, 0x00020, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {x22, 0x18}, {-1,-1} }},
2104 { 0x0c, 0x00, 0, ORIG_LR, 0x00060, TRUE, { {x19, 0x40}, {x20, 0x48}, {x21, 0x50}, {x22, 0x58}, {x23, 0x00}, {x24, 0x08}, {-1,-1} }},
2105 { 0x10, 0x00, 0, ORIG_LR, 0x00060, TRUE, { {x19, 0x40}, {x20, 0x48}, {x21, 0x50}, {x22, 0x58}, {x23, 0x00}, {x24, 0x08}, {x25, 0x10}, {x26, 0x18}, {-1,-1} }},
2106 { 0x14, 0x00, 0, ORIG_LR, 0x00060, TRUE, { {x19, 0x40}, {x20, 0x48}, {x21, 0x50}, {x22, 0x58}, {x23, 0x00}, {x24, 0x08}, {x25, 0x10}, {x26, 0x18}, {x27, 0x20}, {x28, 0x28}, {-1,-1} }},
2107 { 0x18, 0x00, 0, 0x38, 0x00060, TRUE, { {x19, 0x40}, {x20, 0x48}, {x21, 0x50}, {x22, 0x58}, {x23, 0x00}, {x24, 0x08}, {x25, 0x10}, {x26, 0x18}, {x27, 0x20}, {x28, 0x28}, {x29, 0x30}, {lr, 0x38}, {-1,-1} }},
2108 { 0x1c, 0x00, 0, 0x78, 0x000a0, TRUE, { {x19, 0x80}, {x20, 0x88}, {x21, 0x90}, {x22, 0x98}, {x23, 0x40}, {x24, 0x48}, {x25, 0x50}, {x26, 0x58}, {x27, 0x60}, {x28, 0x68}, {x29, 0x70}, {lr, 0x78}, {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
2109#if 0
2110 { 0x20, 0x00, 0, 0x78, 0x000a0, TRUE, { {x19, 0x80}, {x20, 0x88}, {x21, 0x90}, {x22, 0x98}, {x23, 0x40}, {x24, 0x48}, {x25, 0x50}, {x26, 0x58}, {x27, 0x60}, {x28, 0x68}, {x29, 0x70}, {lr, 0x78}, {d8, 0x00}, {d9, 0x08}, {d10, 0x10}, {d11, 0x18}, {-1,-1} }},
2111 { 0x24, 0x00, 0, 0x78, 0x000a0, TRUE, { {x19, 0x80}, {x20, 0x88}, {x21, 0x90}, {x22, 0x98}, {x23, 0x40}, {x24, 0x48}, {x25, 0x50}, {x26, 0x58}, {x27, 0x60}, {x28, 0x68}, {x29, 0x70}, {lr, 0x78}, {d8, 0x00}, {d9, 0x08}, {d10, 0x10}, {d11, 0x18}, {d12, 0x20}, {d13, 0x28}, {-1,-1} }},
2112 { 0x28, 0x00, 0, 0x78, 0x000a0, TRUE, { {x19, 0x80}, {x20, 0x88}, {x21, 0x90}, {x22, 0x98}, {x23, 0x40}, {x24, 0x48}, {x25, 0x50}, {x26, 0x58}, {x27, 0x60}, {x28, 0x68}, {x29, 0x70}, {lr, 0x78}, {d8, 0x00}, {d9, 0x08}, {d10, 0x10}, {d11, 0x18}, {d12, 0x20}, {d13, 0x28}, {d14, 0x30}, {d15, 0x38}, {-1,-1} }},
2113#endif
2114 };
2115
2116 static const BYTE function_6[] =
2117 {
2118 0xf3, 0x53, 0xbd, 0xa9, /* 00: stp x19, x20, [sp, #-48]! */
2119 0xf5, 0x0b, 0x00, 0xf9, /* 04: str x21, [sp, #16] */
2120 0xe8, 0xa7, 0x01, 0x6d, /* 08: stp d8, d9, [sp, #24] */
2121 0xea, 0x17, 0x00, 0xfd, /* 0c: str d10, [sp, #40] */
2122 0xff, 0x03, 0x00, 0xd1, /* 10: sub sp, sp, #0 */
2123 0x1f, 0x20, 0x03, 0xd5, /* 14: nop */
2124 0xff, 0x03, 0x00, 0x91, /* 18: add sp, sp, #0 */
2125 0xea, 0x17, 0x40, 0xfd, /* 1c: ldr d10, [sp, #40] */
2126 0xe8, 0xa7, 0x41, 0x6d, /* 20: ldp d8, d9, [sp, #24] */
2127 0xf5, 0x0b, 0x40, 0xf9, /* 24: ldr x21, [sp, #16] */
2128 0xf3, 0x53, 0xc3, 0xa8, /* 28: ldp x19, x20, [sp], #48 */
2129 0xc0, 0x03, 0x5f, 0xd6, /* 2c: ret */
2130 };
2131
2132 static const DWORD unwind_info_6_packed =
2133 (1 << 0) | /* Flag */
2134 (sizeof(function_6)/4 << 2) | /* FunctionLength */
2135 (2 << 13) | /* RegF */
2136 (3 << 16) | /* RegI */
2137 (0 << 20) | /* H */
2138 (0 << 21) | /* CR */
2139 (3 << 23); /* FrameSize */
2140
2141 static const BYTE unwind_info_6[] = { DW(unwind_info_6_packed) };
2142
2143 static const struct results_arm64 results_6[] =
2144 {
2145 /* offset fp handler pc frame offset registers */
2146 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2147 { 0x04, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
2148 { 0x08, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {-1,-1} }},
2149 { 0x0c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {-1,-1} }},
2150 { 0x10, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
2151 { 0x14, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
2152 { 0x18, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
2153 { 0x1c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
2154 { 0x20, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {-1,-1} }},
2155 { 0x24, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {-1,-1} }},
2156 { 0x28, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
2157 { 0x2c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2158 };
2159
2160 static const BYTE function_7[] =
2161 {
2162 0xf3, 0x0f, 0x1d, 0xf8, /* 00: str x19, [sp, #-48]! */
2163 0xe8, 0xa7, 0x00, 0x6d, /* 04: stp d8, d9, [sp, #8] */
2164 0xea, 0xaf, 0x01, 0x6d, /* 08: stp d10, d11, [sp, #24] */
2165 0xff, 0x03, 0x00, 0xd1, /* 0c: sub sp, sp, #0 */
2166 0x1f, 0x20, 0x03, 0xd5, /* 10: nop */
2167 0xff, 0x03, 0x00, 0x91, /* 14: add sp, sp, #0 */
2168 0xea, 0xaf, 0x41, 0x6d, /* 18: ldp d10, d11, [sp, #24] */
2169 0xe8, 0xa7, 0x40, 0x6d, /* 1c: ldp d8, d9, [sp, #8] */
2170 0xf3, 0x07, 0x43, 0xf8, /* 20: ldr x19, [sp], #48 */
2171 0xc0, 0x03, 0x5f, 0xd6, /* 24: ret */
2172 };
2173
2174 static const DWORD unwind_info_7_packed =
2175 (1 << 0) | /* Flag */
2176 (sizeof(function_7)/4 << 2) | /* FunctionLength */
2177 (3 << 13) | /* RegF */
2178 (1 << 16) | /* RegI */
2179 (0 << 20) | /* H */
2180 (0 << 21) | /* CR */
2181 (3 << 23); /* FrameSize */
2182
2183 static const BYTE unwind_info_7[] = { DW(unwind_info_7_packed) };
2184
2185 static const struct results_arm64 results_7[] =
2186 {
2187 /* offset fp handler pc frame offset registers */
2188 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2189 { 0x04, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {-1,-1} }},
2190 { 0x08, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {-1,-1} }},
2191 { 0x0c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
2192 { 0x10, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
2193 { 0x14, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
2194 { 0x18, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
2195 { 0x1c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {-1,-1} }},
2196 { 0x20, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {-1,-1} }},
2197 { 0x24, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2198 };
2199
2200 static const BYTE function_8[] =
2201 {
2202 0xe8, 0x27, 0xbf, 0x6d, /* 00: stp d8, d9, [sp, #-16]! */
2203 0xff, 0x83, 0x00, 0xd1, /* 04: sub sp, sp, #32 */
2204 0x1f, 0x20, 0x03, 0xd5, /* 08: nop */
2205 0xff, 0x83, 0x00, 0x91, /* 0c: add sp, sp, #32 */
2206 0xe8, 0x27, 0xc1, 0x6c, /* 10: ldp d8, d9, [sp], #16 */
2207 0xc0, 0x03, 0x5f, 0xd6, /* 14: ret */
2208 };
2209
2210 static const DWORD unwind_info_8_packed =
2211 (1 << 0) | /* Flag */
2212 (sizeof(function_8)/4 << 2) | /* FunctionLength */
2213 (1 << 13) | /* RegF */
2214 (0 << 16) | /* RegI */
2215 (0 << 20) | /* H */
2216 (0 << 21) | /* CR */
2217 (3 << 23); /* FrameSize */
2218
2219 static const BYTE unwind_info_8[] = { DW(unwind_info_8_packed) };
2220
2221 static const struct results_arm64 results_8[] =
2222 {
2223 /* offset fp handler pc frame offset registers */
2224 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2225 { 0x04, 0x00, 0, ORIG_LR, 0x010, TRUE, { {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
2226 { 0x08, 0x00, 0, ORIG_LR, 0x030, TRUE, { {d8, 0x20}, {d9, 0x28}, {-1,-1} }},
2227 { 0x0c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {d8, 0x20}, {d9, 0x28}, {-1,-1} }},
2228 { 0x10, 0x00, 0, ORIG_LR, 0x010, TRUE, { {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
2229 { 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2230 };
2231
2232 static const BYTE function_9[] =
2233 {
2234 0xf3, 0x0f, 0x1b, 0xf8, /* 00: str x19, [sp, #-80]! */
2235 0xe0, 0x87, 0x00, 0xa9, /* 04: stp x0, x1, [sp, #8] */
2236 0xe2, 0x8f, 0x01, 0xa9, /* 08: stp x2, x3, [sp, #24] */
2237 0xe4, 0x97, 0x02, 0xa9, /* 0c: stp x4, x5, [sp, #40] */
2238 0xe6, 0x9f, 0x03, 0xa9, /* 10: stp x6, x7, [sp, #56] */
2239 0xff, 0x83, 0x00, 0xd1, /* 14: sub sp, sp, #32 */
2240 0x1f, 0x20, 0x03, 0xd5, /* 18: nop */
2241 0xff, 0x83, 0x00, 0x91, /* 1c: add sp, sp, #32 */
2242 0x1f, 0x20, 0x03, 0xd5, /* 20: nop */
2243 0x1f, 0x20, 0x03, 0xd5, /* 24: nop */
2244 0x1f, 0x20, 0x03, 0xd5, /* 28: nop */
2245 0x1f, 0x20, 0x03, 0xd5, /* 2c: nop */
2246 0xf3, 0x0f, 0x1b, 0xf8, /* 30: ldr x19, [sp], #80 */
2247 0xc0, 0x03, 0x5f, 0xd6, /* 34: ret */
2248 };
2249
2250 static const DWORD unwind_info_9_packed =
2251 (1 << 0) | /* Flag */
2252 (sizeof(function_9)/4 << 2) | /* FunctionLength */
2253 (0 << 13) | /* RegF */
2254 (1 << 16) | /* RegI */
2255 (1 << 20) | /* H */
2256 (0 << 21) | /* CR */
2257 (7 << 23); /* FrameSize */
2258
2259 static const BYTE unwind_info_9[] = { DW(unwind_info_9_packed) };
2260
2261 static const struct results_arm64 results_9[] =
2262 {
2263 /* offset fp handler pc frame offset registers */
2264 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2265 { 0x04, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
2266 { 0x08, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
2267 { 0x0c, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
2268 { 0x10, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
2269 { 0x14, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
2270 { 0x18, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
2271 { 0x1c, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
2272 { 0x20, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
2273 { 0x24, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
2274 { 0x28, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
2275 { 0x2c, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
2276 { 0x30, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
2277 { 0x34, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2278 };
2279
2280 static const BYTE function_10[] =
2281 {
2282 0xfe, 0x0f, 0x1f, 0xf8, /* 00: str lr, [sp, #-16]! */
2283 0xff, 0x43, 0x00, 0xd1, /* 04: sub sp, sp, #16 */
2284 0x1f, 0x20, 0x03, 0xd5, /* 08: nop */
2285 0xff, 0x43, 0x00, 0x91, /* 0c: add sp, sp, #16 */
2286 0xfe, 0x07, 0x41, 0xf8, /* 10: ldr lr, [sp], #16 */
2287 0xc0, 0x03, 0x5f, 0xd6, /* 14: ret */
2288 };
2289
2290 static const DWORD unwind_info_10_packed =
2291 (1 << 0) | /* Flag */
2292 (sizeof(function_10)/4 << 2) | /* FunctionLength */
2293 (0 << 13) | /* RegF */
2294 (0 << 16) | /* RegI */
2295 (0 << 20) | /* H */
2296 (1 << 21) | /* CR */
2297 (2 << 23); /* FrameSize */
2298
2299 static const BYTE unwind_info_10[] = { DW(unwind_info_10_packed) };
2300
2301 static const struct results_arm64 results_10[] =
2302 {
2303 /* offset fp handler pc frame offset registers */
2304 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2305 { 0x04, 0x00, 0, 0x00, 0x010, TRUE, { {lr, 0x00}, {-1,-1} }},
2306 { 0x08, 0x00, 0, 0x10, 0x020, TRUE, { {lr, 0x10}, {-1,-1} }},
2307 { 0x0c, 0x00, 0, 0x10, 0x020, TRUE, { {lr, 0x10}, {-1,-1} }},
2308 { 0x10, 0x00, 0, 0x00, 0x010, TRUE, { {lr, 0x00}, {-1,-1} }},
2309 { 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2310 };
2311
2312 static const BYTE function_11[] =
2313 {
2314 0xf3, 0x53, 0xbe, 0xa9, /* 00: stp x19, x20, [sp, #-32]! */
2315 0xf5, 0x7b, 0x01, 0xa9, /* 04: stp x21, lr, [sp, #16] */
2316 0xff, 0x43, 0x00, 0xd1, /* 08: sub sp, sp, #16 */
2317 0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
2318 0xff, 0x43, 0x00, 0x91, /* 10: add sp, sp, #16 */
2319 0xf5, 0x7b, 0x41, 0xa9, /* 14: ldp x21, lr, [sp, #16] */
2320 0xf3, 0x53, 0xc2, 0xa8, /* 18: ldp x19, x20, [sp], #32 */
2321 0xc0, 0x03, 0x5f, 0xd6, /* 1c: ret */
2322 };
2323
2324 static const DWORD unwind_info_11_packed =
2325 (1 << 0) | /* Flag */
2326 (sizeof(function_11)/4 << 2) | /* FunctionLength */
2327 (0 << 13) | /* RegF */
2328 (3 << 16) | /* RegI */
2329 (0 << 20) | /* H */
2330 (1 << 21) | /* CR */
2331 (3 << 23); /* FrameSize */
2332
2333 static const BYTE unwind_info_11[] = { DW(unwind_info_11_packed) };
2334
2335 static const struct results_arm64 results_11[] =
2336 {
2337 /* offset fp handler pc frame offset registers */
2338 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2339 { 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2340 { 0x08, 0x00, 0, 0x18, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {lr, 0x18}, {-1,-1} }},
2341 { 0x0c, 0x00, 0, 0x28, 0x030, TRUE, { {x19, 0x10}, {x20, 0x18}, {x21, 0x20}, {lr, 0x28}, {-1,-1} }},
2342 { 0x10, 0x00, 0, 0x28, 0x030, TRUE, { {x19, 0x10}, {x20, 0x18}, {x21, 0x20}, {lr, 0x28}, {-1,-1} }},
2343 { 0x14, 0x00, 0, 0x18, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {lr, 0x18}, {-1,-1} }},
2344 { 0x18, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2345 { 0x1c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2346 };
2347
2348 static const BYTE function_12[] =
2349 {
2350 0xf3, 0x53, 0xbf, 0xa9, /* 00: stp x19, x20, [sp, #-16]! */
2351 0xfd, 0x7b, 0xbe, 0xa9, /* 04: stp x29, lr, [sp, #-32]! */
2352 0xfd, 0x03, 0x00, 0x91, /* 08: mov x29, sp */
2353 0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
2354 0xbf, 0x03, 0x00, 0x91, /* 10: mov sp, x29 */
2355 0xfd, 0x7b, 0xc2, 0xa8, /* 14: ldp x29, lr, [sp], #32 */
2356 0xf3, 0x53, 0xc1, 0xa8, /* 18: ldp x19, x20, [sp], #16 */
2357 0xc0, 0x03, 0x5f, 0xd6, /* 1c: ret */
2358 };
2359
2360 static const DWORD unwind_info_12_packed =
2361 (1 << 0) | /* Flag */
2362 (sizeof(function_12)/4 << 2) | /* FunctionLength */
2363 (0 << 13) | /* RegF */
2364 (2 << 16) | /* RegI */
2365 (0 << 20) | /* H */
2366 (3 << 21) | /* CR */
2367 (3 << 23); /* FrameSize */
2368
2369 static const BYTE unwind_info_12[] = { DW(unwind_info_12_packed) };
2370
2371 static const struct results_arm64 results_12[] =
2372 {
2373 /* offset fp handler pc frame offset registers */
2374 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2375 { 0x04, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2376 { 0x08, 0x10, 0, 0x08, 0x030, TRUE, { {x19, 0x20}, {x20, 0x28}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
2377 { 0x0c, 0x10, 0, 0x18, 0x040, TRUE, { {x19, 0x30}, {x20, 0x38}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
2378 { 0x10, 0x10, 0, 0x18, 0x040, TRUE, { {x19, 0x30}, {x20, 0x38}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
2379 { 0x14, 0x10, 0, 0x08, 0x030, TRUE, { {x19, 0x20}, {x20, 0x28}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
2380 { 0x18, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2381 { 0x1c, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2382 };
2383
2384 static const BYTE function_13[] =
2385 {
2386 0xf3, 0x53, 0xbf, 0xa9, /* 00: stp x19, x20, [sp, #-16]! */
2387 0xff, 0x43, 0x08, 0xd1, /* 04: sub sp, sp, #528 */
2388 0xfd, 0x7b, 0x00, 0xd1, /* 08: stp x29, lr, [sp] */
2389 0xfd, 0x03, 0x00, 0x91, /* 0c: mov x29, sp */
2390 0x1f, 0x20, 0x03, 0xd5, /* 10: nop */
2391 0xbf, 0x03, 0x00, 0x91, /* 14: mov sp, x29 */
2392 0xfd, 0x7b, 0x40, 0xa9, /* 18: ldp x29, lr, [sp] */
2393 0xff, 0x43, 0x08, 0x91, /* 1c: add sp, sp, #528 */
2394 0xf3, 0x53, 0xc1, 0xa8, /* 20: ldp x19, x20, [sp], #16 */
2395 0xc0, 0x03, 0x5f, 0xd6, /* 24: ret */
2396 };
2397
2398 static const DWORD unwind_info_13_packed =
2399 (1 << 0) | /* Flag */
2400 (sizeof(function_13)/4 << 2) | /* FunctionLength */
2401 (0 << 13) | /* RegF */
2402 (2 << 16) | /* RegI */
2403 (0 << 20) | /* H */
2404 (3 << 21) | /* CR */
2405 (34 << 23); /* FrameSize */
2406
2407 static const BYTE unwind_info_13[] = { DW(unwind_info_13_packed) };
2408
2409 static const struct results_arm64 results_13[] =
2410 {
2411 /* offset fp handler pc frame offset registers */
2412 { 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2413 { 0x04, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2414 { 0x08, 0x10, 0, ORIG_LR, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {-1,-1} }},
2415 { 0x0c, 0x10, 0, 0x08, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
2416 { 0x10, 0x10, 0, 0x18, 0x230, TRUE, { {x19, 0x220}, {x20, 0x228}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
2417 { 0x14, 0x10, 0, 0x18, 0x230, TRUE, { {x19, 0x220}, {x20, 0x228}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
2418 { 0x18, 0x10, 0, 0x08, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
2419 { 0x1c, 0x10, 0, ORIG_LR, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {-1,-1} }},
2420 { 0x20, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
2421 { 0x24, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2422 };
2423
2424 static const BYTE function_14[] =
2425 {
2426 0xe6, 0x9f, 0xba, 0xad, /* 00: stp q6, q7, [sp, #-0xb0]! */
2427 0xe8, 0x27, 0x01, 0xad, /* 04: stp q8, q9, [sp, #0x20] */
2428 0xea, 0x2f, 0x02, 0xad, /* 08: stp q10, q11, [sp, #0x40] */
2429 0xec, 0x37, 0x03, 0xad, /* 0c: stp q12, q13, [sp, #0x60] */
2430 0xee, 0x3f, 0x04, 0xad, /* 10: stp q14, q15, [sp, #0x80] */
2431 0xfd, 0x7b, 0x0a, 0xa9, /* 14: stp x29, x30, [sp, #0xa0] */
2432 0xfd, 0x83, 0x02, 0x91, /* 18: add x29, sp, #0xa0 */
2433 0x1f, 0x20, 0x03, 0xd5, /* 1c: nop */
2434 0xfd, 0x7b, 0x4a, 0xa9, /* 20: ldp x29, x30, [sp, #0xa0] */
2435 0xee, 0x3f, 0x44, 0xad, /* 24: ldp q14, q15, [sp, #0x80] */
2436 0xec, 0x37, 0x43, 0xad, /* 28: ldp q12, q13, [sp, #0x60] */
2437 0xea, 0x2f, 0x42, 0xad, /* 2c: ldp q10, q11, [sp, #0x40] */
2438 0xe8, 0x27, 0x41, 0xad, /* 30: ldp q8, q9, [sp, #0x20] */
2439 0xe6, 0x9f, 0xc5, 0xac, /* 34: ldp q6, q7, [sp], #0xb0 */
2440 0xc0, 0x03, 0x5f, 0xd6, /* 38: ret */
2441 };
2442
2443 static const DWORD unwind_info_14_header =
2444 (sizeof(function_14)/4) | /* function length */
2445 (0 << 20) | /* X */
2446 (1 << 21) | /* E */
2447 (2 << 22) | /* epilog */
2448 (5 << 27); /* codes */
2449
2450 static const BYTE unwind_info_14[] =
2451 {
2452 DW(unwind_info_14_header),
2453 UWOP_ADD_FP(0xa0), /* 18: add x29, sp, #0xa0 */
2454 UWOP_SAVE_FPLR(0xa0), /* 14: stp x29, x30, [sp, #0xa0] */
2455 UWOP_SAVE_ANY_REG(0x4e,0x88), /* 10: stp q14, q15, [sp, #0x80] */
2456 UWOP_SAVE_NEXT, /* 0c: stp q12, q13, [sp, #0x60] */
2457 UWOP_SAVE_ANY_REG(0x4a,0x84), /* 08: stp q10, q11, [sp, #0x40] */
2458 UWOP_SAVE_ANY_REG(0x48,0x82), /* 04: stp q8, q9, [sp, #0x20] */
2459 UWOP_SAVE_ANY_REG(0x66,0x8a), /* 00: stp q6, q7, [sp, #-0xb0]! */
2460 UWOP_END,
2461 UWOP_NOP /* padding */
2462 };
2463
2464 static const struct results_arm64 results_14[] =
2465 {
2466 /* offset fp handler pc frame offset registers */
2467 { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2468 { 0x04, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {-1,-1} }},
2469 { 0x08, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {-1,-1} }},
2470 { 0x0c, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {-1,-1} }},
2471 { 0x10, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {-1,-1} }},
2472 { 0x14, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {d14, 0x80}, {d15, 0x90}, {-1,-1} }},
2473 { 0x18, 0x00, 0, 0xa8, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {d14, 0x80}, {d15, 0x90}, {lr, 0xa8}, {x29, 0xa0}, {-1,-1} }},
2474 { 0x1c, 0xa0, 0, 0xa8, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {d14, 0x80}, {d15, 0x90}, {lr, 0xa8}, {x29, 0xa0}, {-1,-1} }},
2475 };
2476
2477 static const BYTE function_15[] =
2478 {
2479 0x1f, 0x20, 0x03, 0xd5, /* 00: nop */
2480 0x1f, 0x20, 0x03, 0xd5, /* 04: nop */
2481 0x1f, 0x20, 0x03, 0xd5, /* 08: nop */
2482 0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
2483 0x1f, 0x20, 0x03, 0xd5, /* 10: nop */
2484 0xc0, 0x03, 0x5f, 0xd6, /* 14: ret */
2485 };
2486
2487 static const DWORD unwind_info_15_header =
2488 (sizeof(function_15)/4) | /* function length */
2489 (0 << 20) | /* X */
2490 (0 << 21) | /* E */
2491 (0 << 22) | /* epilog */
2492 (2 << 27); /* codes */
2493
2494 static const BYTE unwind_info_15[] =
2495 {
2496 DW(unwind_info_15_header),
2497 UWOP_END_C,
2498 UWOP_SET_FP, /* mov x29, sp */
2499 UWOP_SAVE_REGP(19, 0x10), /* stp r19, r20, [sp, #0x10] */
2500 UWOP_SAVE_FPLR_X(0x20), /* stp r29, lr, [sp,-#0x20]! */
2501 UWOP_END,
2502 UWOP_NOP, /* padding */
2503 UWOP_NOP, /* padding */
2504 };
2505
2506 static const struct results_arm64 results_15[] =
2507 {
2508 /* offset fp handler pc frame offset registers */
2509 { 0x00, 0x00, 0, 0x08, 0x020, TRUE, { {x29, 0x00}, {lr, 0x08}, {x19,0x10}, {x20,0x18}, {-1,-1} }},
2510 { 0x04, 0x00, 0, 0x08, 0x020, TRUE, { {x29, 0x00}, {lr, 0x08}, {x19,0x10}, {x20,0x18}, {-1,-1} }},
2511 { 0x08, 0x00, 0, 0x08, 0x020, TRUE, { {x29, 0x00}, {lr, 0x08}, {x19,0x10}, {x20,0x18}, {-1,-1} }},
2512 { 0x0c, 0x00, 0, 0x08, 0x020, TRUE, { {x29, 0x00}, {lr, 0x08}, {x19,0x10}, {x20,0x18}, {-1,-1} }},
2513 { 0x10, 0x00, 0, 0x08, 0x020, TRUE, { {x29, 0x00}, {lr, 0x08}, {x19,0x10}, {x20,0x18}, {-1,-1} }},
2514 { 0x14, 0x00, 0, 0x08, 0x020, TRUE, { {x29, 0x00}, {lr, 0x08}, {x19,0x10}, {x20,0x18}, {-1,-1} }},
2515 };
2516
2517 static const BYTE function_16[] =
2518 {
2519 0xff, 0x43, 0x00, 0xd1, /* 00: sub sp, sp, #16 */
2520 0x1f, 0x20, 0x03, 0xd5, /* 04: nop */
2521 0xff, 0x43, 0x00, 0xd1, /* 08: sub sp, sp, #16 */
2522 0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
2523 0xc0, 0x03, 0x5f, 0xd6, /* 10: ret */
2524 };
2525
2526 static const DWORD unwind_info_16_header =
2527 (sizeof(function_16)/4) | /* function length */
2528 (0 << 20) | /* X */
2529 (0 << 21) | /* E */
2530 (0 << 22) | /* epilog */
2531 (1 << 27); /* codes */
2532
2533 static const BYTE unwind_info_16[] =
2534 {
2535 DW(unwind_info_16_header),
2536
2537 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
2538 UWOP_EC_CONTEXT,
2539 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
2540 UWOP_END,
2541 };
2542
2543 static const struct results_arm64 results_16[] =
2544 {
2545 /* offset fp handler pc frame offset registers */
2546 { 0x00, 0x00, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
2547 { 0x04, 0x00, 0 , 0x00f8, 0x0a8, FALSE, { {x0, 0x80}, {x1, 0x88}, {x2, 0xb8}, {x3, 0xc0}, {x4, 0xc8}, {x5, 0xd0}, {x6, 0x130}, {x7, 0x140}, {x8, 0x78}, {x9, 0x150}, {x10, 0x160}, {x11, 0x170}, {x12, 0x180}, {x13, 0}, {x14, 0}, {x15, 0x190}, {x16, 0x0158014801380128}, {x17, 0x0198018801780168}, {x18, 0}, {x19, 0xd8}, {x20, 0xe0}, {x21, 0xe8}, {x22, 0x0f0}, {x23, 0}, {x24, 0}, {x25, 0xa8}, {x26, 0xb0}, {x27, 0x90}, {x28, 0}, {x29, 0xa0}, {lr, 0x120}, {d0, 0x1a0}, {d1, 0x1b0}, {d2, 0x1c0}, {d3, 0x1d0}, {d4, 0x1e0}, {d5, 0x1f0}, {d6, 0x200}, {d7, 0x210}, {d8, 0x220}, {d9, 0x230}, {d10, 0x240}, {d11, 0x250}, {d12, 0x260}, {d13, 0x270}, {d14, 0x280}, {d15, 0x290}, {-1,-1} }},
2548 { 0x08, 0x00, 0 , 0x0108, 0x0b8, FALSE, { {x0, 0x90}, {x1, 0x98}, {x2, 0xc8}, {x3, 0xd0}, {x4, 0xd8}, {x5, 0xe0}, {x6, 0x140}, {x7, 0x150}, {x8, 0x88}, {x9, 0x160}, {x10, 0x170}, {x11, 0x180}, {x12, 0x190}, {x13, 0}, {x14, 0}, {x15, 0x1a0}, {x16, 0x0168015801480138}, {x17, 0x01a8019801880178}, {x18, 0}, {x19, 0xe8}, {x20, 0xf0}, {x21, 0xf8}, {x22, 0x100}, {x23, 0}, {x24, 0}, {x25, 0xb8}, {x26, 0xc0}, {x27, 0xa0}, {x28, 0}, {x29, 0xb0}, {lr, 0x130}, {d0, 0x1b0}, {d1, 0x1c0}, {d2, 0x1d0}, {d3, 0x1e0}, {d4, 0x1f0}, {d5, 0x200}, {d6, 0x210}, {d7, 0x220}, {d8, 0x230}, {d9, 0x240}, {d10, 0x250}, {d11, 0x260}, {d12, 0x270}, {d13, 0x280}, {d14, 0x290}, {d15, 0x2a0}, {-1,-1} }},
2549 { 0x0c, 0x00, 0 , 0x0108, 0x0b8, FALSE, { {x0, 0x90}, {x1, 0x98}, {x2, 0xc8}, {x3, 0xd0}, {x4, 0xd8}, {x5, 0xe0}, {x6, 0x140}, {x7, 0x150}, {x8, 0x88}, {x9, 0x160}, {x10, 0x170}, {x11, 0x180}, {x12, 0x190}, {x13, 0}, {x14, 0}, {x15, 0x1a0}, {x16, 0x0168015801480138}, {x17, 0x01a8019801880178}, {x18, 0}, {x19, 0xe8}, {x20, 0xf0}, {x21, 0xf8}, {x22, 0x100}, {x23, 0}, {x24, 0}, {x25, 0xb8}, {x26, 0xc0}, {x27, 0xa0}, {x28, 0}, {x29, 0xb0}, {lr, 0x130}, {d0, 0x1b0}, {d1, 0x1c0}, {d2, 0x1d0}, {d3, 0x1e0}, {d4, 0x1f0}, {d5, 0x200}, {d6, 0x210}, {d7, 0x220}, {d8, 0x230}, {d9, 0x240}, {d10, 0x250}, {d11, 0x260}, {d12, 0x270}, {d13, 0x280}, {d14, 0x290}, {d15, 0x2a0}, {-1,-1} }},
2550 { 0x10, 0x00, 0 , 0x0108, 0x0b8, FALSE, { {x0, 0x90}, {x1, 0x98}, {x2, 0xc8}, {x3, 0xd0}, {x4, 0xd8}, {x5, 0xe0}, {x6, 0x140}, {x7, 0x150}, {x8, 0x88}, {x9, 0x160}, {x10, 0x170}, {x11, 0x180}, {x12, 0x190}, {x13, 0}, {x14, 0}, {x15, 0x1a0}, {x16, 0x0168015801480138}, {x17, 0x01a8019801880178}, {x18, 0}, {x19, 0xe8}, {x20, 0xf0}, {x21, 0xf8}, {x22, 0x100}, {x23, 0}, {x24, 0}, {x25, 0xb8}, {x26, 0xc0}, {x27, 0xa0}, {x28, 0}, {x29, 0xb0}, {lr, 0x130}, {d0, 0x1b0}, {d1, 0x1c0}, {d2, 0x1d0}, {d3, 0x1e0}, {d4, 0x1f0}, {d5, 0x200}, {d6, 0x210}, {d7, 0x220}, {d8, 0x230}, {d9, 0x240}, {d10, 0x250}, {d11, 0x260}, {d12, 0x270}, {d13, 0x280}, {d14, 0x290}, {d15, 0x2a0}, {-1,-1} }},
2551 };
2552
2553 static const BYTE function_17[] =
2554 {
2555 0xff, 0x43, 0x00, 0xd1, /* 00: sub sp, sp, #16 */
2556 0xff, 0x43, 0x00, 0xd1, /* 04: sub sp, sp, #16 */
2557 0x1f, 0x20, 0x03, 0xd5, /* 08: nop */
2558 0xc0, 0x03, 0x5f, 0xd6, /* 0c: ret */
2559 };
2560
2561 static const DWORD unwind_info_17_header =
2562 (sizeof(function_17)/4) | /* function length */
2563 (0 << 20) | /* X */
2564 (0 << 21) | /* E */
2565 (0 << 22) | /* epilog */
2566 (1 << 27); /* codes */
2567
2568 static const BYTE unwind_info_17[] =
2569 {
2570 DW(unwind_info_17_header),
2571
2572 UWOP_CLEAR_UNWOUND_TO_CALL,
2573 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
2574 UWOP_ALLOC_SMALL(16), /* sub sp, sp, #16 */
2575 UWOP_END,
2576 };
2577
2578 static const struct results_arm64 results_17[] =
2579 {
2580 /* offset fp handler pc frame offset registers */
2581 { 0x00, 0x00, 0, ORIG_LR, 0x010, TRUE, { {-1,-1} }},
2582 { 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {-1,-1} }},
2583 { 0x08, 0x00, 0, ORIG_LR, 0x020, TRUE, { {-1,-1} }},
2584 { 0x0c, 0x00, 0, ORIG_LR, 0x020, TRUE, { {-1,-1} }},
2585 };
2586
2587 static const BYTE function_18[] =
2588 {
2589 0x1f, 0x20, 0x03, 0xd5, /* 00: nop */
2590 0x1f, 0x20, 0x03, 0xd5, /* 04: nop */
2591 0xc0, 0x03, 0x5f, 0xd6, /* 08: ret */
2592 };
2593
2594 static const struct results_arm64 results_18[] =
2595 {
2596 /* offset fp handler pc frame offset registers */
2597 { 0x00, 0x00, -1, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2598 { 0x04, 0x00, -1, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2599 { 0x08, 0x00, -1, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
2600 { 0x0c, 0x00, -2, 0, 0xdeadbeef, FALSE, { {-1,-1} }},
2601 };
2602
2603 static const struct unwind_test_arm64 tests[] =
2604 {
2605#define TEST(func, unwind, size, results, unwound_clear, last_ptr, stack_value_index, stack_value) \
2606 { func, sizeof(func), unwind, size, results, ARRAY_SIZE(results), unwound_clear, last_ptr, stack_value_index, stack_value }
2607 TEST(function_0, unwind_info_0, sizeof(unwind_info_0), results_0, 0, 0, -1, 0),
2608 TEST(function_1, unwind_info_1, 0, results_1, 0, 0, -1, 0),
2609 TEST(function_2, unwind_info_2, sizeof(unwind_info_2), results_2, 1, 0, -1, 0),
2610 TEST(function_3, unwind_info_3, sizeof(unwind_info_3), results_3, 2, x28, 0, CONTEXT_ARM64_UNWOUND_TO_CALL),
2611 TEST(function_4, unwind_info_4, sizeof(unwind_info_4), results_4, 0, 0, -1, 0),
2612 TEST(function_5, unwind_info_5, sizeof(unwind_info_5), results_5, 0, 0, -1, 0),
2613 TEST(function_6, unwind_info_6, 0, results_6, 0, 0, -1, 0),
2614 TEST(function_7, unwind_info_7, 0, results_7, 0, 0, -1, 0),
2615 TEST(function_8, unwind_info_8, 0, results_8, 0, 0, -1, 0),
2616 TEST(function_9, unwind_info_9, 0, results_9, 0, 0, -1, 0),
2617 TEST(function_10, unwind_info_10, 0, results_10, 0, 0, -1, 0),
2618 TEST(function_11, unwind_info_11, 0, results_11, 0, 0, -1, 0),
2619 TEST(function_12, unwind_info_12, 0, results_12, 0, 0, -1, 0),
2620 TEST(function_13, unwind_info_13, 0, results_13, 0, 0, -1, 0),
2621 TEST(function_14, unwind_info_14, sizeof(unwind_info_14), results_14, 0, 0, -1, 0),
2622 TEST(function_15, unwind_info_15, sizeof(unwind_info_15), results_15, 0, 0, -1, 0),
2623 TEST(function_16, unwind_info_16, sizeof(unwind_info_16), results_16, 2, x18, 6, CONTEXT_ARM64_UNWOUND_TO_CALL),
2624 TEST(function_17, unwind_info_17, sizeof(unwind_info_17), results_17, 2, 0, -1, 0),
2625 TEST(function_18, NULL, 0, results_18, 0, 0, -1, 0),
2626#undef TEST
2627 };
2628 unsigned int i;
2629
2630#ifdef __x86_64__
2631 void *code_mem = NULL;
2632 SIZE_T code_size = 0x10000;
2634
2637 if (!pNtAllocateVirtualMemoryEx ||
2638 pNtAllocateVirtualMemoryEx( GetCurrentProcess(), &code_mem, &code_size, MEM_RESERVE | MEM_COMMIT,
2640 return;
2641 trace( "running arm64ec tests\n" );
2642#endif
2643
2644 for (i = 0; i < ARRAY_SIZE(tests); i++)
2645 call_virtual_unwind_arm64( code_mem, i, &tests[i] );
2646}
2647
2648#endif // __REACTOS__
2649
2650#undef UWOP_ALLOC_SMALL
2651#undef UWOP_ALLOC_LARGE
2652
2653#endif /* __aarch64__ || __x86_64__ */
2654
2655#ifdef __x86_64__
2656
2657#define UWOP_PUSH_NONVOL 0
2658#define UWOP_ALLOC_LARGE 1
2659#define UWOP_ALLOC_SMALL 2
2660#define UWOP_SET_FPREG 3
2661#define UWOP_SAVE_NONVOL 4
2662#define UWOP_SAVE_NONVOL_FAR 5
2663#define UWOP_SAVE_XMM128 8
2664#define UWOP_SAVE_XMM128_FAR 9
2665#define UWOP_PUSH_MACHFRAME 10
2666
2667struct results_x86
2668{
2669 int rip_offset; /* rip offset from code start */
2670 int rbp_offset; /* rbp offset from stack pointer */
2671 int handler; /* expect handler to be set? */
2672 int rip; /* expected final rip value */
2673 int frame; /* expected frame return value */
2674 int regs[8][2]; /* expected values for registers */
2675};
2676
2677struct unwind_test_x86
2678{
2679 const BYTE *function;
2680 size_t function_size;
2681 const BYTE *unwind_info;
2682 const struct results_x86 *results;
2683 unsigned int nb_results;
2684 const struct results_x86 *broken_results;
2685};
2686
2687enum regs
2688{
2689 rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
2690 r8, r9, r10, r11, r12, r13, r14, r15
2691};
2692
2693static const char * const reg_names_x86[16] =
2694{
2695 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2696 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2697};
2698
2699#define UWOP(code,info) (UWOP_##code | ((info) << 4))
2700
2701static void call_virtual_unwind_x86( int testnum, const struct unwind_test_x86 *test )
2702{
2703 static const int code_offset = 1024;
2704 static const int unwind_offset = 2048;
2705 void *data;
2709 RUNTIME_FUNCTION runtime_func;
2710 KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
2711 UINT i, j, k, broken_k;
2712 ULONG64 fake_stack[256];
2713 ULONG64 frame, orig_rip, orig_rbp, unset_reg;
2714 void *expected_handler, *broken_handler;
2715
2716 memcpy( (char *)code_mem + code_offset, test->function, test->function_size );
2717 if (test->unwind_info)
2718 {
2719 UINT unwind_size = 4 + 2 * test->unwind_info[2] + 8;
2720 memcpy( (char *)code_mem + unwind_offset, test->unwind_info, unwind_size );
2721 runtime_func.BeginAddress = code_offset;
2722 runtime_func.EndAddress = code_offset + test->function_size;
2723 runtime_func.UnwindData = unwind_offset;
2724 }
2725
2726 trace( "code: %p stack: %p\n", code_mem, fake_stack );
2727
2728 for (i = 0; i < test->nb_results; i++)
2729 {
2730 memset( &ctx_ptr, 0, sizeof(ctx_ptr) );
2731 memset( &context, 0x55, sizeof(context) );
2732 memset( &unset_reg, 0x55, sizeof(unset_reg) );
2733 for (j = 0; j < 256; j++) fake_stack[j] = j * 8;
2734
2735 context.Rsp = (ULONG_PTR)fake_stack;
2736 context.Rbp = (ULONG_PTR)fake_stack + test->results[i].rbp_offset;
2737 orig_rbp = context.Rbp;
2738 orig_rip = (ULONG64)code_mem + code_offset + test->results[i].rip_offset;
2739
2740 trace( "%u/%u: rip=%p (%02x) rbp=%p rsp=%p\n", testnum, i,
2741 (void *)orig_rip, *(BYTE *)orig_rip, (void *)orig_rbp, (void *)context.Rsp );
2742
2743 if (!test->unwind_info) fake_stack[0] = 0x1234;
2744 expected_handler = test->results[i].handler ? (char *)code_mem + 0x200 : NULL;
2745 broken_handler = test->broken_results && test->broken_results[i].handler ? (char *)code_mem + 0x200 : NULL;
2746
2747 if (pRtlVirtualUnwind2)
2748 {
2749 CONTEXT new_context = context;
2750
2751 handler = (void *)0xdeadbeef;
2752 data = (void *)0xdeadbeef;
2753 status = pRtlVirtualUnwind2( UNW_FLAG_EHANDLER, (ULONG_PTR)code_mem, orig_rip,
2754 test->unwind_info ? &runtime_func : NULL, &new_context,
2755 NULL, &data, &frame, &ctx_ptr, NULL, NULL, &handler, 0 );
2756 ok( !status, "RtlVirtualUnwind2 failed %lx\n", status );
2757
2758 ok( handler == expected_handler || broken( test->broken_results && handler == broken_handler ),
2759 "%u/%u: wrong handler %p/%p\n", testnum, i, handler, expected_handler );
2760 if (handler)
2761 ok( *(DWORD *)data == 0x08070605, "%u/%u: wrong handler data %lx\n", testnum, i, *(DWORD *)data );
2762 else
2763 ok( data == (test->unwind_info ? (void *)0xdeadbeef : NULL),
2764 "%u/%u: handler data set to %p\n", testnum, i, data );
2765 }
2766
2767 data = (void *)0xdeadbeef;
2768 handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)code_mem, orig_rip,
2769 test->unwind_info ? &runtime_func : NULL,
2770 &context, &data, &frame, &ctx_ptr );
2771
2772 expected_handler = test->results[i].handler ? (char *)code_mem + 0x200 : NULL;
2773 broken_handler = test->broken_results && test->broken_results[i].handler ? (char *)code_mem + 0x200 : NULL;
2774
2775 ok( handler == expected_handler || broken( test->broken_results && handler == broken_handler ),
2776 "%u/%u: wrong handler %p/%p\n", testnum, i, handler, expected_handler );
2777 if (handler)
2778 ok( *(DWORD *)data == 0x08070605, "%u/%u: wrong handler data %lx\n", testnum, i, *(DWORD *)data );
2779 else
2780 ok( data == (test->unwind_info ? (void *)0xdeadbeef : NULL),
2781 "%u/%u: handler data set to %p\n", testnum, i, data );
2782
2783 ok( context.Rip == test->results[i].rip
2784 || broken( test->broken_results && context.Rip == test->broken_results[i].rip ),
2785 "%u/%u: wrong rip %p/%x\n", testnum, i, (void *)context.Rip, test->results[i].rip );
2786 ok( frame == (ULONG64)fake_stack + test->results[i].frame
2787 || broken( test->broken_results && frame == (ULONG64)fake_stack + test->broken_results[i].frame ),
2788 "%u/%u: wrong frame %p/%p\n",
2789 testnum, i, (void *)frame, (char *)fake_stack + test->results[i].frame );
2790
2791 for (j = 0; j < 16; j++)
2792 {
2793 static const UINT nb_regs = ARRAY_SIZE(test->results[i].regs);
2794
2795 for (k = 0; k < nb_regs; k++)
2796 {
2797 if (test->results[i].regs[k][0] == -1)
2798 {
2799 k = nb_regs;
2800 break;
2801 }
2802 if (test->results[i].regs[k][0] == j) break;
2803 }
2804
2805 if (test->broken_results)
2806 {
2807 for (broken_k = 0; broken_k < nb_regs; broken_k++)
2808 {
2809 if (test->broken_results[i].regs[broken_k][0] == -1)
2810 {
2811 broken_k = nb_regs;
2812 break;
2813 }
2814 if (test->broken_results[i].regs[broken_k][0] == j)
2815 break;
2816 }
2817 }
2818 else
2819 {
2820 broken_k = k;
2821 }
2822
2823 if (j == rsp) /* rsp is special */
2824 {
2825 ULONG64 expected_rsp, broken_rsp;
2826
2827 ok( !ctx_ptr.IntegerContext[j],
2828 "%u/%u: rsp should not be set in ctx_ptr\n", testnum, i );
2829 expected_rsp = test->results[i].regs[k][1] < 0
2830 ? -test->results[i].regs[k][1] : (ULONG64)fake_stack + test->results[i].regs[k][1];
2831 if (test->broken_results)
2832 broken_rsp = test->broken_results[i].regs[k][1] < 0
2833 ? -test->broken_results[i].regs[k][1]
2834 : (ULONG64)fake_stack + test->broken_results[i].regs[k][1];
2835 else
2836 broken_rsp = expected_rsp;
2837
2838 ok( context.Rsp == expected_rsp || broken( context.Rsp == broken_rsp ),
2839 "%u/%u: register rsp wrong %p/%p\n",
2840 testnum, i, (void *)context.Rsp, (void *)expected_rsp );
2841 continue;
2842 }
2843
2844 if (ctx_ptr.IntegerContext[j])
2845 {
2846 ok( k < nb_regs || broken( broken_k < nb_regs ), "%u/%u: register %s should not be set to %Ix\n",
2847 testnum, i, reg_names_x86[j], *(&context.Rax + j) );
2848 ok( k == nb_regs || *(&context.Rax + j) == test->results[i].regs[k][1]
2849 || broken( broken_k == nb_regs || *(&context.Rax + j)
2850 == test->broken_results[i].regs[broken_k][1] ),
2851 "%u/%u: register %s wrong %p/%x\n",
2852 testnum, i, reg_names_x86[j], (void *)*(&context.Rax + j), test->results[i].regs[k][1] );
2853 }
2854 else
2855 {
2856 ok( k == nb_regs || broken( broken_k == nb_regs ), "%u/%u: register %s should be set\n",
2857 testnum, i, reg_names_x86[j] );
2858 if (j == rbp)
2859 ok( context.Rbp == orig_rbp, "%u/%u: register rbp wrong %p/unset\n",
2860 testnum, i, (void *)context.Rbp );
2861 else
2862 ok( *(&context.Rax + j) == unset_reg,
2863 "%u/%u: register %s wrong %p/unset\n",
2864 testnum, i, reg_names_x86[j], (void *)*(&context.Rax + j));
2865 }
2866 }
2867 }
2868}
2869
2870static void test_virtual_unwind_x86(void)
2871{
2872 static const BYTE function_0[] =
2873 {
2874 0xff, 0xf5, /* 00: push %rbp */
2875 0x48, 0x81, 0xec, 0x10, 0x01, 0x00, 0x00, /* 02: sub $0x110,%rsp */
2876 0x48, 0x8d, 0x6c, 0x24, 0x30, /* 09: lea 0x30(%rsp),%rbp */
2877 0x48, 0x89, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 0e: mov %rbx,0xf0(%rbp) */
2878 0x48, 0x89, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 15: mov %rsi,0xf8(%rbp) */
2879 0x90, /* 1c: nop */
2880 0x48, 0x8b, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 1d: mov 0xf0(%rbp),%rbx */
2881 0x48, 0x8b, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 24: mov 0xf8(%rbp),%rsi */
2882 0x48, 0x8d, 0xa5, 0xe0, 0x00, 0x00, 0x00, /* 2b: lea 0xe0(%rbp),%rsp */
2883 0x5d, /* 32: pop %rbp */
2884 0xc3 /* 33: ret */
2885 };
2886
2887 static const BYTE unwind_info_0[] =
2888 {
2889 1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
2890 0x1c, /* prolog size */
2891 8, /* opcode count */
2892 (0x03 << 4) | rbp, /* frame reg rbp offset 0x30 */
2893
2894 0x1c, UWOP(SAVE_NONVOL, rsi), 0x25, 0, /* 1c: mov %rsi,0x128(%rsp) */
2895 0x15, UWOP(SAVE_NONVOL, rbx), 0x24, 0, /* 15: mov %rbx,0x120(%rsp) */
2896 0x0e, UWOP(SET_FPREG, rbp), /* 0e: lea 0x30(%rsp),rbp */
2897 0x09, UWOP(ALLOC_LARGE, 0), 0x22, 0, /* 09: sub $0x110,%rsp */
2898 0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
2899
2900 0x00, 0x02, 0x00, 0x00, /* handler */
2901 0x05, 0x06, 0x07, 0x08, /* data */
2902 };
2903
2904 static const struct results_x86 results_0[] =
2905 {
2906 /* offset rbp handler rip frame registers */
2907 { 0x00, 0x40, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
2908 { 0x02, 0x40, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbp,0x000}, {-1,-1} }},
2909 { 0x09, 0x40, FALSE, 0x118, 0x000, { {rsp,0x120}, {rbp,0x110}, {-1,-1} }},
2910 { 0x0e, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1} }},
2911 { 0x15, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {-1,-1} }},
2912 { 0x1c, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
2913 { 0x1d, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
2914 { 0x24, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
2915 { 0x2b, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1}}},
2916 { 0x32, 0x40, FALSE, 0x008, 0x010, { {rsp,0x010}, {rbp,0x000}, {-1,-1}}},
2917 { 0x33, 0x40, FALSE, 0x000, 0x010, { {rsp,0x008}, {-1,-1}}},
2918 };
2919
2920 static const struct results_x86 broken_results_0[] =
2921 {
2922 /* offset rbp handler rip frame registers */
2923 { 0x00, 0x40, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
2924 { 0x02, 0x40, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbp,0x000}, {-1,-1} }},
2925 { 0x09, 0x40, FALSE, 0x118, 0x000, { {rsp,0x120}, {rbp,0x110}, {-1,-1} }},
2926 { 0x0e, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1} }},
2927 { 0x15, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {-1,-1} }},
2928 { 0x1c, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
2929 { 0x1d, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
2930 { 0x24, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
2931 /* On Win11 output frame in epilogue corresponds to context->Rsp - 0x8 when fpreg is set. */
2932 { 0x2b, 0x40, FALSE, 0x128, 0x128, { {rsp,0x130}, {rbp,0x120}, {-1,-1}}},
2933 { 0x32, 0x40, FALSE, 0x008, 0x008, { {rsp,0x010}, {rbp,0x000}, {-1,-1}}},
2934 { 0x33, 0x40, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1}}},
2935 };
2936
2937 static const BYTE function_1[] =
2938 {
2939 0x53, /* 00: push %rbx */
2940 0x55, /* 01: push %rbp */
2941 0x56, /* 02: push %rsi */
2942 0x57, /* 03: push %rdi */
2943 0x41, 0x54, /* 04: push %r12 */
2944 0x48, 0x83, 0xec, 0x30, /* 06: sub $0x30,%rsp */
2945 0x90, 0x90, /* 0a: nop; nop */
2946 0x48, 0x83, 0xc4, 0x30, /* 0c: add $0x30,%rsp */
2947 0x41, 0x5c, /* 10: pop %r12 */
2948 0x5f, /* 12: pop %rdi */
2949 0x5e, /* 13: pop %rsi */
2950 0x5d, /* 14: pop %rbp */
2951 0x5b, /* 15: pop %rbx */
2952 0xc3 /* 16: ret */
2953 };
2954
2955 static const BYTE unwind_info_1[] =
2956 {
2957 1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
2958 0x0a, /* prolog size */
2959 6, /* opcode count */
2960 0, /* frame reg */
2961
2962 0x0a, UWOP(ALLOC_SMALL, 5), /* 0a: sub $0x30,%rsp */
2963 0x06, UWOP(PUSH_NONVOL, r12), /* 06: push %r12 */
2964 0x04, UWOP(PUSH_NONVOL, rdi), /* 04: push %rdi */
2965 0x03, UWOP(PUSH_NONVOL, rsi), /* 03: push %rsi */
2966 0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
2967 0x01, UWOP(PUSH_NONVOL, rbx), /* 01: push %rbx */
2968
2969 0x00, 0x02, 0x00, 0x00, /* handler */
2970 0x05, 0x06, 0x07, 0x08, /* data */
2971 };
2972
2973 static const struct results_x86 results_1[] =
2974 {
2975 /* offset rbp handler rip frame registers */
2976 { 0x00, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
2977 { 0x01, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }},
2978 { 0x02, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }},
2979 { 0x03, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }},
2980 { 0x04, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }},
2981 { 0x06, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }},
2982 { 0x0a, 0x50, TRUE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }},
2983 { 0x0c, 0x50, FALSE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }},
2984 { 0x10, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }},
2985 { 0x12, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }},
2986 { 0x13, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }},
2987 { 0x14, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }},
2988 { 0x15, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }},
2989 { 0x16, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
2990 };
2991
2992 static const BYTE function_2[] =
2993 {
2994 0x55, /* 00: push %rbp */
2995 0x90, 0x90, /* 01: nop; nop */
2996 0x5d, /* 03: pop %rbp */
2997 0xc3 /* 04: ret */
2998 };
2999
3000 static const BYTE unwind_info_2[] =
3001 {
3002 1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
3003 0x0, /* prolog size */
3004 2, /* opcode count */
3005 0, /* frame reg */
3006
3007 0x01, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
3008 0x00, UWOP(PUSH_MACHFRAME, 0), /* 00 */
3009
3010 0x00, 0x02, 0x00, 0x00, /* handler */
3011 0x05, 0x06, 0x07, 0x08, /* data */
3012 };
3013
3014 static const struct results_x86 results_2[] =
3015 {
3016 /* offset rbp handler rip frame registers */
3017 { 0x01, 0x50, TRUE, 0x008, 0x000, { {rsp,-0x020}, {rbp,0x000}, {-1,-1} }},
3018 };
3019
3020 static const BYTE unwind_info_3[] =
3021 {
3022 1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
3023 0x0, /* prolog size */
3024 2, /* opcode count */
3025 0, /* frame reg */
3026
3027 0x01, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
3028 0x00, UWOP(PUSH_MACHFRAME, 1), /* 00 */
3029
3030 0x00, 0x02, 0x00, 0x00, /* handler */
3031 0x05, 0x06, 0x07, 0x08, /* data */
3032 };
3033
3034 static const struct results_x86 results_3[] =
3035 {
3036 /* offset rbp handler rip frame registers */
3037 { 0x01, 0x50, TRUE, 0x010, 0x000, { {rsp,-0x028}, {rbp,0x000}, {-1,-1} }},
3038 };
3039
3040 static const BYTE function_4[] =
3041 {
3042 0x55, /* 00: push %rbp */
3043 0x5d, /* 01: pop %rbp */
3044 0xc3 /* 02: ret */
3045 };
3046
3047 static const BYTE unwind_info_4[] =
3048 {
3049 1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
3050 0x0, /* prolog size */
3051 0, /* opcode count */
3052 0, /* frame reg */
3053
3054 0x00, 0x02, 0x00, 0x00, /* handler */
3055 0x05, 0x06, 0x07, 0x08, /* data */
3056 };
3057
3058 static const struct results_x86 results_4[] =
3059 {
3060 /* offset rbp handler rip frame registers */
3061 { 0x01, 0x50, TRUE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
3062 };
3063
3064 static const struct results_x86 broken_results_4[] =
3065 {
3066 /* offset rbp handler rip frame registers */
3067 { 0x01, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbp,0x000}, {-1,-1} }},
3068 };
3069
3070#if 0
3071 static const BYTE function_5[] =
3072 {
3073 0x90, /* 00: nop */
3074 0x90, /* 01: nop */
3075 0xc3 /* 02: ret */
3076 };
3077
3078 static const struct results_x86 results_5[] =
3079 {
3080 /* offset rbp handler rip frame registers */
3081 { 0x01, 0x00, FALSE, 0x1234, 0x000, { {rsp,0x08}, {-1,-1} }},
3082 { 0x02, 0x00, FALSE, 0x1234, 0x000, { {rsp,0x08}, {-1,-1} }},
3083 };
3084#endif
3085
3086 static const struct unwind_test_x86 tests[] =
3087 {
3088 { function_0, sizeof(function_0), unwind_info_0, results_0, ARRAY_SIZE(results_0), broken_results_0 },
3089 { function_1, sizeof(function_1), unwind_info_1, results_1, ARRAY_SIZE(results_1) },
3090 { function_2, sizeof(function_2), unwind_info_2, results_2, ARRAY_SIZE(results_2) },
3091 { function_2, sizeof(function_2), unwind_info_3, results_3, ARRAY_SIZE(results_3) },
3092
3093 /* Broken before Win10 1809. */
3094 { function_4, sizeof(function_4), unwind_info_4, results_4, ARRAY_SIZE(results_4), broken_results_4 },
3095#if 0 /* crashes before Win10 21H2 */
3096 { function_5, sizeof(function_5), NULL, results_5, ARRAY_SIZE(results_5) },
3097#endif
3098 };
3099 unsigned int i;
3100
3101 for (i = 0; i < ARRAY_SIZE(tests); i++)
3102 call_virtual_unwind_x86( i, &tests[i] );
3103}
3104
3105#endif /* __x86_64__ */
3106
3107#ifdef __x86_64__
3108#define SET_RUNTIME_FUNC_LEN(func,len) do { (func)->EndAddress = (func)->BeginAddress + (len); } while(0)
3109#elif defined(__arm__)
3110#define SET_RUNTIME_FUNC_LEN(func,len) do { (func)->FunctionLength = len / 2; (func)->Flag = 1; } while(0)
3111#else
3112#define SET_RUNTIME_FUNC_LEN(func,len) do { (func)->FunctionLength = len / 4; (func)->Flag = 1; } while(0)
3113#endif
3114
3116{
3117 static const int code_offset = 1024;
3118 static RUNTIME_FUNCTION runtime_func;
3119 (*(DWORD *)context)++;
3120
3121 runtime_func.BeginAddress = code_offset + 16;
3122 runtime_func.UnwindData = 0;
3123 SET_RUNTIME_FUNC_LEN( &runtime_func, 16 );
3124 return &runtime_func;
3125}
3126
3127static void test_dynamic_unwind(void)
3128{
3129 static const int code_offset = 1024;
3130 char buf[2 * sizeof(RUNTIME_FUNCTION) + 4];
3132 RUNTIME_FUNCTION *runtime_func, *func;
3133 ULONG_PTR table, base, ec_code;
3134 void *growable_table, *ptr;
3136 SIZE_T size = 0x1000;
3137 DWORD count;
3138 ULONG len, len2;
3139
3140 if (!pRtlInstallFunctionTableCallback || !pRtlLookupFunctionEntry)
3141 {
3142 win_skip( "Dynamic unwind functions not found\n" );
3143 return;
3144 }
3145
3146 /* Test RtlAddFunctionTable with aligned RUNTIME_FUNCTION pointer */
3147 runtime_func = (RUNTIME_FUNCTION *)buf;
3148 runtime_func->BeginAddress = code_offset;
3149 runtime_func->UnwindData = 0;
3150 SET_RUNTIME_FUNC_LEN( runtime_func, 16 );
3151 ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
3152 "RtlAddFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
3153
3154 /* Lookup function outside of any function table */
3155 base = 0xdeadbeef;
3156 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
3157 ok( func == NULL,
3158 "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
3159 ok( !base || broken(base == 0xdeadbeef),
3160 "RtlLookupFunctionEntry modified base address, expected: 0, got: %Ix\n", base );
3161
3162 /* Test with pointer inside of our function */
3163 base = 0xdeadbeef;
3164 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
3165 ok( func == runtime_func,
3166 "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
3168 "RtlLookupFunctionEntry returned invalid base, expected: %Ix, got: %Ix\n", (ULONG_PTR)code_mem, base );
3169
3170 /* Test RtlDeleteFunctionTable */
3171 ok( pRtlDeleteFunctionTable( runtime_func ),
3172 "RtlDeleteFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
3173 ok( !pRtlDeleteFunctionTable( runtime_func ),
3174 "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
3175
3176 /* Unaligned RUNTIME_FUNCTION pointer */
3177 runtime_func = (RUNTIME_FUNCTION *)((ULONG_PTR)buf | 0x3);
3178 runtime_func->BeginAddress = code_offset;
3179 runtime_func->UnwindData = 0;
3180 SET_RUNTIME_FUNC_LEN( runtime_func, 16 );
3181 ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
3182 "RtlAddFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
3183 ok( pRtlDeleteFunctionTable( runtime_func ),
3184 "RtlDeleteFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
3185
3186 /* Attempt to insert the same entry twice */
3187 runtime_func = (RUNTIME_FUNCTION *)buf;
3188 runtime_func->BeginAddress = code_offset;
3189 runtime_func->UnwindData = 0;
3190 SET_RUNTIME_FUNC_LEN( runtime_func, 16 );
3191 ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
3192 "RtlAddFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
3193 ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
3194 "RtlAddFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
3195 ok( pRtlDeleteFunctionTable( runtime_func ),
3196 "RtlDeleteFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
3197 ok( pRtlDeleteFunctionTable( runtime_func ),
3198 "RtlDeleteFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
3199 ok( !pRtlDeleteFunctionTable( runtime_func ),
3200 "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
3201
3202 /* Empty table */
3203 ok( pRtlAddFunctionTable( runtime_func, 0, (ULONG_PTR)code_mem ),
3204 "RtlAddFunctionTable failed for empty table\n" );
3205 ok( pRtlDeleteFunctionTable( runtime_func ),
3206 "RtlDeleteFunctionTable failed for empty table\n" );
3207 ok( !pRtlDeleteFunctionTable( runtime_func ),
3208 "RtlDeleteFunctionTable succeeded twice for empty table\n" );
3209
3210 /* Test RtlInstallFunctionTableCallback with both low bits unset */
3212 ok( !pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ),
3213 "RtlInstallFunctionTableCallback returned success for table = %Ix\n", table );
3214
3215 /* Test RtlInstallFunctionTableCallback with both low bits set */
3216 table = (ULONG_PTR)code_mem | 0x3;
3217 ok( pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ),
3218 "RtlInstallFunctionTableCallback failed for table = %Ix\n", table );
3219
3220 /* Lookup function outside of any function table */
3221 count = 0;
3222 base = 0xdeadbeef;
3223 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 32, &base, NULL );
3224 ok( func == NULL,
3225 "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
3226 ok( !base || broken(base == 0xdeadbeef),
3227 "RtlLookupFunctionEntry modified base address, expected: 0, got: %Ix\n", base );
3228 ok( !count,
3229 "RtlLookupFunctionEntry issued %ld unexpected calls to dynamic_unwind_callback\n", count );
3230
3231 /* Test with pointer inside of our function */
3232 count = 0;
3233 base = 0xdeadbeef;
3234 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 24, &base, NULL );
3235 ok( count == 1 || broken(!count), /* win10 arm */
3236 "RtlLookupFunctionEntry issued %ld calls to dynamic_unwind_callback, expected: 1\n", count );
3237 if (count)
3238 {
3239 ok( func != NULL && func->BeginAddress == code_offset + 16,
3240 "RtlLookupFunctionEntry didn't return expected function, got: %p\n", func );
3242 "RtlLookupFunctionEntry returned invalid base: %Ix / %Ix\n", (ULONG_PTR)code_mem, base );
3243 }
3244
3245 /* Clean up again */
3246 ok( pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
3247 "RtlDeleteFunctionTable failed for table = %p\n", (PVOID)table );
3248 ok( !pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
3249 "RtlDeleteFunctionTable returned success for nonexistent table = %p\n", (PVOID)table );
3250
3251 if (!pRtlAddGrowableFunctionTable)
3252 {
3253 win_skip("Growable function tables are not supported.\n");
3254 return;
3255 }
3256
3257 runtime_func = (RUNTIME_FUNCTION *)buf;
3258 runtime_func->BeginAddress = code_offset;
3259 runtime_func->UnwindData = 0;
3260 SET_RUNTIME_FUNC_LEN( runtime_func, 16 );
3261 runtime_func++;
3262 runtime_func->BeginAddress = code_offset + 16;
3263 runtime_func->UnwindData = 0;
3264 SET_RUNTIME_FUNC_LEN( runtime_func, 16 );
3265 runtime_func = (RUNTIME_FUNCTION *)buf;
3266
3267 growable_table = NULL;
3268 status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 1, 1, (ULONG_PTR)code_mem, (ULONG_PTR)code_mem + 64 );
3269 ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#lx.\n", runtime_func, status );
3270 ok(growable_table != 0, "Unexpected table value.\n");
3271 pRtlDeleteGrowableFunctionTable( growable_table );
3272
3273 growable_table = NULL;
3274 status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 2, 2, (ULONG_PTR)code_mem, (ULONG_PTR)code_mem + 64 );
3275 ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#lx.\n", runtime_func, status );
3276 ok(growable_table != 0, "Unexpected table value.\n");
3277 pRtlDeleteGrowableFunctionTable( growable_table );
3278
3279 growable_table = NULL;
3280 status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 1, 2, (ULONG_PTR)code_mem, (ULONG_PTR)code_mem + 64 );
3281 ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#lx.\n", runtime_func, status );
3282 ok(growable_table != 0, "Unexpected table value.\n");
3283 pRtlDeleteGrowableFunctionTable( growable_table );
3284
3285 growable_table = NULL;
3286 status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 0, 2, (ULONG_PTR)code_mem,
3287 (ULONG_PTR)code_mem + code_offset + 64 );
3288 ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#lx.\n", runtime_func, status );
3289 ok(growable_table != 0, "Unexpected table value.\n");
3290
3291 /* Current count is 0. */
3292 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
3293 ok( func == NULL,
3294 "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
3295
3296 pRtlGrowFunctionTable( growable_table, 1 );
3297
3298 base = 0xdeadbeef;
3299 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
3300 ok( func == runtime_func,
3301 "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
3303 "RtlLookupFunctionEntry returned invalid base, expected: %Ix, got: %Ix\n", (ULONG_PTR)code_mem, base );
3304
3305 /* Second function is inaccessible yet. */
3306 base = 0xdeadbeef;
3307 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
3308 ok( func == NULL,
3309 "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
3310
3311 pRtlGrowFunctionTable( growable_table, 2 );
3312
3313 base = 0xdeadbeef;
3314 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
3315 ok( func == runtime_func + 1,
3316 "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
3318 "RtlLookupFunctionEntry returned invalid base, expected: %Ix, got: %Ix\n", (ULONG_PTR)code_mem, base );
3319
3320 base = 0xdeadbeef;
3321 func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 32, &base, NULL );
3322 ok( func == NULL, "RtlLookupFunctionEntry got %p\n", func );
3323 ok( base == 0xdeadbeef, "RtlLookupFunctionTable wrong base, got: %Ix\n", base );
3324
3325 base = 0xdeadbeef;
3326 func = pRtlLookupFunctionTable( (ULONG_PTR)code_mem + code_offset + 8, &base, &len );
3327 ok( func == NULL, "RtlLookupFunctionTable wrong table, got: %p\n", func );
3328 ok( base == 0xdeadbeef, "RtlLookupFunctionTable wrong base, got: %Ix\n", base );
3329
3330 base = 0xdeadbeef;
3331 len = 0xdeadbeef;
3332 func = pRtlLookupFunctionTable( (ULONG_PTR)pRtlLookupFunctionEntry, &base, &len );
3333 ok( base == (ULONG_PTR)GetModuleHandleA("ntdll.dll"),
3334 "RtlLookupFunctionTable wrong base, got: %Ix / %p\n", base, GetModuleHandleA("ntdll.dll") );
3336 ok( func == ptr, "RtlLookupFunctionTable wrong table, got: %p / %p\n", func, ptr );
3337 ok( len == len2 || !ptr, "RtlLookupFunctionTable wrong len, got: %lu / %lu\n", len, len2 );
3338
3339 pRtlDeleteGrowableFunctionTable( growable_table );
3340
3341#ifndef __REACTOS__
3344 ec_code = 0;
3345 if (pNtAllocateVirtualMemoryEx &&
3346 !pNtAllocateVirtualMemoryEx( GetCurrentProcess(), (void **)&ec_code, &size,
3348 {
3349 static const BYTE fast_forward[] = { 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x20, 0x55, 0x5d, 0xe9 };
3350 IMAGE_ARM64EC_METADATA *metadata;
3352
3353 trace( "running arm64ec tests\n" );
3354
3355 if (!memcmp( pRtlLookupFunctionEntry, fast_forward, sizeof(fast_forward) ))
3356 {
3357 ptr = (char *)pRtlLookupFunctionEntry + sizeof(fast_forward);
3358 ptr = (char *)ptr + 4 + *(int *)ptr;
3359 base = 0xdeadbeef;
3360 func = pRtlLookupFunctionTable( (ULONG_PTR)ptr, &base, &len );
3361 ok( base == (ULONG_PTR)GetModuleHandleA("ntdll.dll"),
3362 "RtlLookupFunctionTable wrong base, got: %Ix / %p\n", base, GetModuleHandleA("ntdll.dll") );
3364 ok( func != ptr, "RtlLookupFunctionTable wrong table, got: %p / %p\n", func, ptr );
3366 metadata = (void *)((IMAGE_LOAD_CONFIG_DIRECTORY *)ptr)->CHPEMetadataPointer;
3367 ok( (char *)func == (char *)base + metadata->ExtraRFETable,
3368 "RtlLookupFunctonTable wrong table, got: %p / %p\n", func, (char *)base + metadata->ExtraRFETable );
3369 ok( len == metadata->ExtraRFETableSize, "RtlLookupFunctionTable wrong len, got: %lu / %lu\n",
3370 len, metadata->ExtraRFETableSize );
3371 }
3372
3373 arm64func->BeginAddress = code_offset;
3374 arm64func->Flag = 1;
3375 arm64func->FunctionLength = 4;
3376 arm64func->RegF = 1;
3377 arm64func->RegI = 1;
3378 arm64func->H = 1;
3379 arm64func->CR = 1;
3380 arm64func->FrameSize = 1;
3381 arm64func++;
3382 arm64func->BeginAddress = code_offset + 16;
3383 arm64func->Flag = 1;
3384 arm64func->FunctionLength = 4;
3385 arm64func->RegF = 1;
3386 arm64func->RegI = 1;
3387 arm64func->H = 1;
3388 arm64func->CR = 1;
3389 arm64func->FrameSize = 1;
3390
3391 growable_table = NULL;
3392 status = pRtlAddGrowableFunctionTable( &growable_table, (RUNTIME_FUNCTION *)buf,
3393 2, 2, ec_code, ec_code + code_offset + 64 );
3394 ok( !status, "RtlAddGrowableFunctionTable failed %lx\n", status );
3395
3396 base = 0xdeadbeef;
3397 func = pRtlLookupFunctionEntry( ec_code + code_offset + 8, &base, NULL );
3398 ok( func == (RUNTIME_FUNCTION *)buf, "RtlLookupFunctionEntry expected func: %p, got: %p\n",
3399 buf, func );
3400 ok( base == ec_code, "RtlLookupFunctionEntry expected base: %Ix, got: %Ix\n",
3401 ec_code, base );
3402
3403 base = 0xdeadbeef;
3404 func = pRtlLookupFunctionEntry( ec_code + code_offset + 16, &base, NULL );
3405 ok( func == (RUNTIME_FUNCTION *)(buf + sizeof(*arm64func)),
3406 "RtlLookupFunctionEntry expected func: %p, got: %p\n", buf + sizeof(*arm64func), func );
3407 ok( base == ec_code, "RtlLookupFunctionEntry expected base: %Ix, got: %Ix\n", ec_code, base );
3408
3409 base = 0xdeadbeef;
3410 func = pRtlLookupFunctionEntry( ec_code + code_offset + 32, &base, NULL );
3411 ok( !func, "RtlLookupFunctionEntry got: %p\n", func );
3412 ok( base == 0xdeadbeef, "RtlLookupFunctionEntry got: %Ix\n", base );
3413
3414 pRtlDeleteGrowableFunctionTable( growable_table );
3415 VirtualFree( (void *)ec_code, 0, MEM_RELEASE );
3416 }
3417#endif // __REACTOS__
3418}
3419
3420
3422{
3423 ntdll = GetModuleHandleA("ntdll.dll");
3425
3426#define X(f) p##f = (void*)GetProcAddress(ntdll, #f)
3437#undef X
3438
3439#ifdef __arm__
3440 test_virtual_unwind_arm();
3441#elif defined(__aarch64__)
3442 test_virtual_unwind_arm64();
3443#elif defined(__x86_64__)
3444 test_virtual_unwind_x86();
3445#ifndef __REACTOS__
3446 test_virtual_unwind_arm64();
3447#endif // __REACTOS__
3448#endif
3449
3451}
3452
3453#else /* !__i386__ */
3454
3455START_TEST(unwind)
3456{
3457}
3458
3459#endif /* !__i386__ */
static struct _test_info results[8]
Definition: SetCursorPos.c:31
unsigned char BOOLEAN
Definition: actypes.h:127
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define broken(x)
Definition: atltest.h:178
#define START_TEST(x)
Definition: atltest.h:75
LONG NTSTATUS
Definition: precomp.h:26
#define ARRAY_SIZE(A)
Definition: main.h:20
INT testnum
Definition: capicon.c:26
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NTSTATUS
Definition: precomp.h:19
#define CDECL
Definition: compat.h:29
#define GetCurrentProcess()
Definition: compat.h:759
EXCEPTION_ROUTINE * PEXCEPTION_ROUTINE
Definition: compat.h:709
#define RtlImageDirectoryEntryToData
Definition: compat.h:809
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
Definition: compat.h:153
#define CALLBACK
Definition: compat.h:35
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
UINT(* handler)(MSIPACKAGE *)
Definition: action.c:7512
_ACRTIMP int __cdecl memcmp(const void *, const void *, size_t)
Definition: string.c:2802
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLenum func
Definition: glext.h:6028
GLsizeiptr size
Definition: glext.h:5919
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLfloat param
Definition: glext.h:5796
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define frame_offset
Definition: intsym.h:201
if(dx< 0)
Definition: linetemp.h:194
GLint x0
Definition: linetemp.h:95
#define GET(lzs, b)
Definition: lzexpand.c:123
#define win_skip
Definition: minitest.h:67
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl void winetest_pop_context(void)
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl winetest_push_context(const char *fmt,...) __WINE_PRINTF_ATTR(1
Definition: test.h:537
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
unsigned __int64 ULONG64
Definition: imports.h:198
static PVOID ptr
Definition: dispmode.c:27
static struct test_info tests[]
#define TEST(x)
Definition: precomp.h:20
static DNS_RECORDW r3
Definition: record.c:39
static DNS_RECORDW r1
Definition: record.c:37
static DNS_RECORDW r2
Definition: record.c:38
static const WCHAR sp[]
Definition: suminfo.c:287
static ULONG_PTR UNWIND_HISTORY_TABLE *static ULONG_PTR ULONG *static PVOID
Definition: unwind.c:43
static void * code_mem
Definition: unwind.c:38
#define X(f)
static RUNTIME_FUNCTION CONTEXT BOOLEAN void ULONG_PTR KNONVOLATILE_CONTEXT_POINTERS ULONG_PTR ULONG_PTR PEXCEPTION_ROUTINE ULONG
Definition: unwind.c:49
static ULONG_PTR UNWIND_HISTORY_TABLE *static ULONG_PTR ULONG *static DWORD64
Definition: unwind.c:43
static ULONG_PTR UNWIND_HISTORY_TABLE *static ULONG_PTR ULONG *static PGET_RUNTIME_FUNCTION_CALLBACK
Definition: unwind.c:43
static HMODULE ntdll
Definition: unwind.c:39
static ULONG_PTR UNWIND_HISTORY_TABLE *static ULONG_PTR ULONG *static DWORD
Definition: unwind.c:43
static void test_dynamic_unwind(void)
Definition: unwind.c:3127
static RUNTIME_FUNCTION ULONG_PTR
Definition: unwind.c:46
#define SET_RUNTIME_FUNC_LEN(func, len)
Definition: unwind.c:3112
static ULONG_PTR UNWIND_HISTORY_TABLE *static ULONG_PTR ULONG *static PCWSTR
Definition: unwind.c:43
static PRUNTIME_FUNCTION(WINAPI *pRtlLookupFunctionEntry)(ULONG_PTR
static RUNTIME_FUNCTION *CALLBACK dynamic_unwind_callback(DWORD_PTR pc, PVOID context)
Definition: unwind.c:3115
static float int float int float int x3
Definition: server.c:79
static float int float int float int float int x4
Definition: server.c:79
static int double int int double int int double int int double int int double int int double int int double int int double int int x17
Definition: server.c:83
static int double int int double int int double int int double int int double int int double int int double int int x15
Definition: server.c:83
static float int float int float int float int float int x5
Definition: server.c:79
static int double int int double int int double int int double int int double int int double int int x13
Definition: server.c:83
static float int float int float int float int float int float int x6
Definition: server.c:79
static int double int int double int int double int int double int int double int int x11
Definition: server.c:83
static double int double int double int double int double int double int double int double int x8
Definition: server.c:82
static double int double int double int double int double int double int double int x7
Definition: server.c:82
static int double int int double int int double int int double int int x9
Definition: server.c:83
static int double int int double int int double int int double int int double int int double int int double int x14
Definition: server.c:83
static int double int int double int int double int int double int int double int x10
Definition: server.c:83
static int double int int double int int double int int double int int double int int double int x12
Definition: server.c:83
static int double int int double int int double int int double int int double int int double int int double int int double int x16
Definition: server.c:83
int k
Definition: mpi.c:3369
unsigned int UINT
Definition: ndis.h:50
#define MEM_RESERVE
Definition: nt_native.h:1317
#define MEM_RELEASE
Definition: nt_native.h:1319
#define MEM_COMMIT
Definition: nt_native.h:1316
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1311
#define STATUS_BAD_FUNCTION_TABLE
Definition: ntstatus.h:585
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION
Definition: pedump.c:262
#define BOOLEAN
Definition: pedump.c:73
#define test
Definition: rosglue.h:37
NTSYSAPI NTSTATUS WINAPI RtlAddGrowableFunctionTable(void **, PRUNTIME_FUNCTION, ULONG, ULONG, ULONG_PTR, ULONG_PTR)
NTSYSAPI BOOLEAN CDECL RtlAddFunctionTable(RUNTIME_FUNCTION *, ULONG, ULONG_PTR)
NTSYSAPI PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind(ULONG, ULONG_PTR, ULONG_PTR, RUNTIME_FUNCTION *, CONTEXT *, void **, ULONG_PTR *, KNONVOLATILE_CONTEXT_POINTERS *)
NTSYSAPI void WINAPI RtlGrowFunctionTable(void *, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlVirtualUnwind2(ULONG, ULONG_PTR, ULONG_PTR, RUNTIME_FUNCTION *, CONTEXT *, BOOLEAN *, void **, ULONG_PTR *, KNONVOLATILE_CONTEXT_POINTERS *, ULONG_PTR *, ULONG_PTR *, PEXCEPTION_ROUTINE *, ULONG)
NTSYSAPI PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry(ULONG_PTR, ULONG_PTR *, UNWIND_HISTORY_TABLE *)
NTSYSAPI BOOLEAN CDECL RtlDeleteFunctionTable(RUNTIME_FUNCTION *)
NTSYSAPI void WINAPI RtlDeleteGrowableFunctionTable(void *)
NTSYSAPI BOOLEAN CDECL RtlInstallFunctionTableCallback(ULONG_PTR, ULONG_PTR, ULONG, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR)
NTSYSAPI PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable(ULONG_PTR, ULONG_PTR *, ULONG *)
#define memset(x, y, z)
Definition: compat.h:39
#define UWOP_ALLOC_LARGE
Definition: unwind.c:20
#define UWOP_ALLOC_SMALL
Definition: unwind.c:21
Definition: winnt_old.h:1280
DWORD BeginAddress
Definition: winnt_old.h:1281
DWORD UnwindData
Definition: winnt_old.h:1283
DWORD RegF
Definition: winnt_old.h:1287
DWORD FrameSize
Definition: winnt_old.h:1291
DWORD H
Definition: winnt_old.h:1289
DWORD RegI
Definition: winnt_old.h:1288
DWORD CR
Definition: winnt_old.h:1290
DWORD FunctionLength
Definition: winnt_old.h:1286
DWORD Flag
Definition: winnt_old.h:1285
Definition: http.c:7252
Definition: ps.c:97
uint32_t DWORD_PTR
Definition: typedefs.h:65
int64_t LONGLONG
Definition: typedefs.h:68
PVOID HANDLE
Definition: typedefs.h:73
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint64_t ULONGLONG
Definition: typedefs.h:67
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
LPVOID NTAPI VirtualAlloc(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flAllocationType, IN DWORD flProtect)
Definition: virtmem.c:65
BOOL NTAPI VirtualFree(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD dwFreeType)
Definition: virtmem.c:119
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3708
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3710
#define WINAPI
Definition: msvc.h:6
NTSYSAPI NTSTATUS WINAPI NtAllocateVirtualMemoryEx(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG, MEM_EXTENDED_PARAMETER *, ULONG)
ARM64EC_NT_CONTEXT
Definition: winnt_old.h:2476
MEM_EXTENDED_PARAMETER
Definition: winnt_old.h:1265
#define MEM_EXTENDED_PARAMETER_EC_CODE
Definition: winnt_old.h:597
#define CONTEXT_ARM64_UNWOUND_TO_CALL
Definition: winnt_old.h:2365
@ MemExtendedParameterAttributeFlags
Definition: winnt_old.h:1237
ARM64_NT_CONTEXT
Definition: ketypes.h:1262
unsigned char BYTE
Definition: xxhash.c:193