include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / ntdll / signal_arm.c
blob595eb71a81ee4ecc3a026e0837802727dce786b5
1 /*
2 * ARM signal handling routines
4 * Copyright 2002 Marcus Meissner, SuSE Linux AG
5 * Copyright 2010-2013, 2015 André Hentschel
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.
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.
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
22 #ifdef __arm__
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <setjmp.h>
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "winternl.h"
32 #include "wine/exception.h"
33 #include "ntdll_misc.h"
34 #include "wine/debug.h"
35 #include "ntsyscalls.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(seh);
38 WINE_DECLARE_DEBUG_CHANNEL(relay);
41 /* undocumented, copied from the corresponding ARM64 structure */
42 typedef union _DISPATCHER_CONTEXT_NONVOLREG_ARM
44 BYTE Buffer[8 * sizeof(DWORD) + 8 * sizeof(double)];
45 struct
47 DWORD GpNvRegs[8];
48 double FpNvRegs[8];
49 } DUMMYSTRUCTNAME;
50 } DISPATCHER_CONTEXT_NONVOLREG_ARM;
53 /*******************************************************************
54 * syscalls
56 #define SYSCALL_ENTRY(id,name,args) __ASM_SYSCALL_FUNC( id, name, args )
57 ALL_SYSCALLS32
58 DEFINE_SYSCALL_HELPER32()
59 #undef SYSCALL_ENTRY
62 /**************************************************************************
63 * __chkstk (NTDLL.@)
65 * Incoming r4 contains words to allocate, converting to bytes then return
67 __ASM_GLOBAL_FUNC( __chkstk, "lsl r4, r4, #2\n\t"
68 "bx lr" )
70 /***********************************************************************
71 * RtlCaptureContext (NTDLL.@)
73 __ASM_GLOBAL_FUNC( RtlCaptureContext,
74 "str r1, [r0, #0x8]\n\t" /* context->R1 */
75 "mov r1, #0x0200000\n\t" /* CONTEXT_ARM */
76 "add r1, r1, #0x7\n\t" /* CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT */
77 "str r1, [r0]\n\t" /* context->ContextFlags */
78 "str SP, [r0, #0x38]\n\t" /* context->Sp */
79 "str LR, [r0, #0x40]\n\t" /* context->Pc */
80 "mrs r1, CPSR\n\t"
81 "bfi r1, lr, #5, #1\n\t" /* Thumb bit */
82 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
83 "mov r1, #0\n\t"
84 "str r1, [r0, #0x4]\n\t" /* context->R0 */
85 "str r1, [r0, #0x3c]\n\t" /* context->Lr */
86 "add r0, #0x0c\n\t"
87 "stm r0, {r2-r12}\n\t" /* context->R2..R12 */
88 "add r0, #0x44\n\t" /* 0x50 - 0x0c */
89 "vstm r0, {d0-d15}\n\t" /* context->D0-D15 */
90 "bx lr" )
93 /**********************************************************************
94 * virtual_unwind
96 static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context )
98 DISPATCHER_CONTEXT_NONVOLREG_ARM *nonvol_regs;
99 DWORD pc = context->Pc;
101 dispatch->ScopeIndex = 0;
102 dispatch->ControlPc = pc;
103 dispatch->ControlPcIsUnwound = (context->ContextFlags & CONTEXT_UNWOUND_TO_CALL) != 0;
104 if (dispatch->ControlPcIsUnwound) pc -= 2;
106 nonvol_regs = (DISPATCHER_CONTEXT_NONVOLREG_ARM *)dispatch->NonVolatileRegisters;
107 memcpy( nonvol_regs->GpNvRegs, &context->R4, sizeof(nonvol_regs->GpNvRegs) );
108 memcpy( nonvol_regs->FpNvRegs, &context->D[8], sizeof(nonvol_regs->FpNvRegs) );
110 dispatch->FunctionEntry = RtlLookupFunctionEntry( pc, (DWORD_PTR *)&dispatch->ImageBase,
111 dispatch->HistoryTable );
112 if (RtlVirtualUnwind2( type, dispatch->ImageBase, pc, dispatch->FunctionEntry, context,
113 NULL, &dispatch->HandlerData, (ULONG_PTR *)&dispatch->EstablisherFrame,
114 NULL, NULL, NULL, &dispatch->LanguageHandler, 0 ))
116 WARN( "exception data not found for pc %p, lr %p\n", (void *)pc, (void *)context->Lr );
117 return STATUS_INVALID_DISPOSITION;
119 return STATUS_SUCCESS;
123 /**********************************************************************
124 * unwind_exception_handler
126 * Handler for exceptions happening while calling an unwind handler.
128 EXCEPTION_DISPOSITION WINAPI unwind_exception_handler( EXCEPTION_RECORD *record, void *frame,
129 CONTEXT *context, DISPATCHER_CONTEXT *dispatch )
131 DISPATCHER_CONTEXT *orig_dispatch = ((DISPATCHER_CONTEXT **)frame)[-2];
133 /* copy the original dispatcher into the current one, except for the TargetIp */
134 dispatch->ControlPc = orig_dispatch->ControlPc;
135 dispatch->ImageBase = orig_dispatch->ImageBase;
136 dispatch->FunctionEntry = orig_dispatch->FunctionEntry;
137 dispatch->EstablisherFrame = orig_dispatch->EstablisherFrame;
138 dispatch->LanguageHandler = orig_dispatch->LanguageHandler;
139 dispatch->HandlerData = orig_dispatch->HandlerData;
140 dispatch->HistoryTable = orig_dispatch->HistoryTable;
141 dispatch->ScopeIndex = orig_dispatch->ScopeIndex;
142 dispatch->ControlPcIsUnwound = orig_dispatch->ControlPcIsUnwound;
143 *dispatch->ContextRecord = *orig_dispatch->ContextRecord;
144 memcpy( dispatch->NonVolatileRegisters, orig_dispatch->NonVolatileRegisters,
145 sizeof(DISPATCHER_CONTEXT_NONVOLREG_ARM) );
146 TRACE( "detected collided unwind\n" );
147 return ExceptionCollidedUnwind;
151 /**********************************************************************
152 * call_unwind_handler
154 DWORD WINAPI call_unwind_handler( EXCEPTION_RECORD *rec, ULONG_PTR frame,
155 CONTEXT *context, void *dispatch, PEXCEPTION_ROUTINE handler );
156 __ASM_GLOBAL_FUNC( call_unwind_handler,
157 "push {r3,lr}\n\t"
158 ".seh_save_regs {r3,lr}\n\t"
159 ".seh_endprologue\n\t"
160 ".seh_handler unwind_exception_handler, %except\n\t"
161 "ldr ip, [sp, #8]\n\t" /* handler */
162 "blx ip\n\t"
163 "pop {r3,pc}\n\t" )
166 /***********************************************************************
167 * call_seh_handler
169 DWORD WINAPI call_seh_handler( EXCEPTION_RECORD *rec, ULONG_PTR frame,
170 CONTEXT *context, void *dispatch, PEXCEPTION_ROUTINE handler );
171 __ASM_GLOBAL_FUNC( call_seh_handler,
172 "push {r4,lr}\n\t"
173 ".seh_save_regs {r4,lr}\n\t"
174 ".seh_endprologue\n\t"
175 ".seh_handler nested_exception_handler, %except\n\t"
176 "ldr ip, [sp, #8]\n\t" /* handler */
177 "blx ip\n\t"
178 "pop {r4,pc}\n\t" )
181 /**********************************************************************
182 * call_seh_handlers
184 * Call the SEH handlers.
186 NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
188 EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
189 DISPATCHER_CONTEXT_NONVOLREG_ARM nonvol_regs;
190 UNWIND_HISTORY_TABLE table;
191 DISPATCHER_CONTEXT dispatch;
192 CONTEXT context;
193 NTSTATUS status;
194 ULONG_PTR frame;
195 DWORD res;
197 context = *orig_context;
198 dispatch.TargetPc = 0;
199 dispatch.ContextRecord = &context;
200 dispatch.HistoryTable = &table;
201 dispatch.NonVolatileRegisters = nonvol_regs.Buffer;
203 for (;;)
205 status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context );
206 if (status != STATUS_SUCCESS) return status;
208 unwind_done:
209 if (!dispatch.EstablisherFrame) break;
211 if (!is_valid_frame( dispatch.EstablisherFrame ))
213 ERR( "invalid frame %lx (%p-%p)\n", dispatch.EstablisherFrame,
214 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
215 rec->ExceptionFlags |= EXCEPTION_STACK_INVALID;
216 break;
219 if (dispatch.LanguageHandler)
221 TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
222 dispatch.LanguageHandler, rec, dispatch.EstablisherFrame, orig_context, &dispatch );
223 res = call_seh_handler( rec, dispatch.EstablisherFrame, orig_context,
224 &dispatch, dispatch.LanguageHandler );
225 rec->ExceptionFlags &= EXCEPTION_NONCONTINUABLE;
226 TRACE( "handler at %p returned %lu\n", dispatch.LanguageHandler, res );
228 switch (res)
230 case ExceptionContinueExecution:
231 if (rec->ExceptionFlags & EXCEPTION_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
232 return STATUS_SUCCESS;
233 case ExceptionContinueSearch:
234 break;
235 case ExceptionNestedException:
236 rec->ExceptionFlags |= EXCEPTION_NESTED_CALL;
237 TRACE( "nested exception\n" );
238 break;
239 case ExceptionCollidedUnwind:
240 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
241 dispatch.ControlPc, dispatch.FunctionEntry,
242 &context, (PVOID *)&dispatch.HandlerData, &frame, NULL );
243 goto unwind_done;
244 default:
245 return STATUS_INVALID_DISPOSITION;
248 /* hack: call wine handlers registered in the tib list */
249 else while (is_valid_frame( (ULONG_PTR)teb_frame ) && (DWORD)teb_frame < context.Sp)
251 TRACE( "calling TEB handler %p (rec=%p frame=%p context=%p dispatch=%p) sp=%lx\n",
252 teb_frame->Handler, rec, teb_frame, orig_context, &dispatch, context.Sp );
253 res = call_seh_handler( rec, (ULONG_PTR)teb_frame, orig_context,
254 &dispatch, (PEXCEPTION_ROUTINE)teb_frame->Handler );
255 TRACE( "TEB handler at %p returned %lu\n", teb_frame->Handler, res );
257 switch (res)
259 case ExceptionContinueExecution:
260 if (rec->ExceptionFlags & EXCEPTION_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
261 return STATUS_SUCCESS;
262 case ExceptionContinueSearch:
263 break;
264 case ExceptionNestedException:
265 rec->ExceptionFlags |= EXCEPTION_NESTED_CALL;
266 TRACE( "nested exception\n" );
267 break;
268 case ExceptionCollidedUnwind:
269 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
270 dispatch.ControlPc, dispatch.FunctionEntry,
271 &context, (PVOID *)&dispatch.HandlerData, &frame, NULL );
272 teb_frame = teb_frame->Prev;
273 goto unwind_done;
274 default:
275 return STATUS_INVALID_DISPOSITION;
277 teb_frame = teb_frame->Prev;
280 if (context.Sp == (DWORD)NtCurrentTeb()->Tib.StackBase) break;
282 return STATUS_UNHANDLED_EXCEPTION;
286 /*******************************************************************
287 * KiUserExceptionDispatcher (NTDLL.@)
289 __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
290 ".seh_custom 0xee,0x02\n\t" /* MSFT_OP_CONTEXT */
291 ".seh_endprologue\n\t"
292 "add r0, sp, #0x1a0\n\t" /* rec (context + 1) */
293 "mov r1, sp\n\t" /* context */
294 "bl dispatch_exception\n\t"
295 "udf #1" )
298 /*******************************************************************
299 * KiUserApcDispatcher (NTDLL.@)
301 __ASM_GLOBAL_FUNC( KiUserApcDispatcher,
302 ".seh_custom 0xee,0x02\n\t" /* MSFT_OP_CONTEXT */
303 "nop\n\t"
304 ".seh_stackalloc 0x18\n\t"
305 ".seh_endprologue\n\t"
306 "ldr r0, [sp, #0x04]\n\t" /* arg1 */
307 "ldr r1, [sp, #0x08]\n\t" /* arg2 */
308 "ldr r2, [sp, #0x0c]\n\t" /* arg3 */
309 "ldr ip, [sp]\n\t" /* func */
310 "blx ip\n\t"
311 "add r0, sp, #0x18\n\t" /* context */
312 "ldr r1, [sp, #0x10]\n\t" /* alertable */
313 "bl NtContinue\n\t"
314 "udf #1" )
317 /*******************************************************************
318 * KiUserCallbackDispatcher (NTDLL.@)
320 __ASM_GLOBAL_FUNC( KiUserCallbackDispatcher,
321 ".seh_custom 0xee,0x01\n\t" /* MSFT_OP_MACHINE_FRAME */
322 "nop\n\t"
323 ".seh_save_regs {lr}\n\t"
324 "nop\n\t"
325 ".seh_stackalloc 0xc\n\t"
326 ".seh_endprologue\n\t"
327 "ldr r0, [sp]\n\t" /* args */
328 "ldr r1, [sp, #0x04]\n\t" /* len */
329 "ldr r2, [sp, #0x08]\n\t" /* id */
330 "mrc p15, 0, r3, c13, c0, 2\n\t" /* NtCurrentTeb() */
331 "ldr r3, [r3, 0x30]\n\t" /* peb */
332 "ldr r3, [r3, 0x2c]\n\t" /* peb->KernelCallbackTable */
333 "ldr ip, [r3, r2, lsl #2]\n\t"
334 "blx ip\n\t"
335 ".seh_handler user_callback_handler, %except\n\t"
336 ".globl KiUserCallbackDispatcherReturn\n"
337 "KiUserCallbackDispatcherReturn:\n\t"
338 "mov r2, r0\n\t" /* status */
339 "mov r1, #0\n\t" /* ret_len */
340 "mov r0, r1\n\t" /* ret_ptr */
341 "bl NtCallbackReturn\n\t"
342 "bl RtlRaiseStatus\n\t"
343 "udf #1" )
347 /**********************************************************************
348 * consolidate_callback
350 * Wrapper function to call a consolidate callback from a fake frame.
351 * If the callback executes RtlUnwindEx (like for example done in C++ handlers),
352 * we have to skip all frames which were already processed. To do that we
353 * trick the unwinding functions into thinking the call came from somewhere
354 * else.
356 void WINAPI DECLSPEC_NORETURN consolidate_callback( CONTEXT *context,
357 void *(CALLBACK *callback)(EXCEPTION_RECORD *),
358 EXCEPTION_RECORD *rec );
359 __ASM_GLOBAL_FUNC( consolidate_callback,
360 "push {r0-r2,lr}\n\t"
361 ".seh_nop\n\t"
362 "sub sp, sp, #0x1a0\n\t"
363 ".seh_nop\n\t"
364 "mov r1, r0\n\t"
365 ".seh_nop\n\t"
366 "mov r0, sp\n\t"
367 ".seh_nop\n\t"
368 "mov r2, #0x1a0\n\t"
369 ".seh_nop_w\n\t"
370 "bl memcpy\n\t"
371 ".seh_custom 0xee,0x02\n\t" /* MSFT_OP_CONTEXT */
372 ".seh_endprologue\n\t"
373 "ldrd r1, r2, [sp, #0x1a4]\n\t"
374 "mov r0, r2\n\t"
375 "blx r1\n\t"
376 "str r0, [sp, #0x40]\n\t" /* context->Pc */
377 "mov r0, sp\n\t"
378 "mov r1, #1\n\t"
379 "b NtContinue" )
383 /*******************************************************************
384 * RtlRestoreContext (NTDLL.@)
386 void CDECL RtlRestoreContext( CONTEXT *context, EXCEPTION_RECORD *rec )
388 EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
390 if (rec && rec->ExceptionCode == STATUS_LONGJUMP && rec->NumberParameters >= 1)
392 struct _JUMP_BUFFER *jmp = (struct _JUMP_BUFFER *)rec->ExceptionInformation[0];
394 memcpy( &context->R4, &jmp->R4, 8 * sizeof(DWORD) );
395 memcpy( &context->D[8], &jmp->D[0], 8 * sizeof(ULONGLONG) );
396 context->Pc = jmp->Pc;
397 context->Sp = jmp->Sp;
398 context->Fpscr = jmp->Fpscr;
400 else if (rec && rec->ExceptionCode == STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters >= 1)
402 PVOID (CALLBACK *consolidate)(EXCEPTION_RECORD *) = (void *)rec->ExceptionInformation[0];
403 TRACE( "calling consolidate callback %p (rec=%p)\n", consolidate, rec );
404 consolidate_callback( context, consolidate, rec );
407 /* hack: remove no longer accessible TEB frames */
408 while (is_valid_frame( (ULONG_PTR)teb_frame ) && (DWORD)teb_frame < context->Sp)
410 TRACE( "removing TEB frame: %p\n", teb_frame );
411 teb_frame = __wine_pop_frame( teb_frame );
414 TRACE( "returning to %lx stack %lx\n", context->Pc, context->Sp );
415 NtContinue( context, FALSE );
419 /***********************************************************************
420 * RtlUnwindEx (NTDLL.@)
422 void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec,
423 PVOID retval, CONTEXT *context, UNWIND_HISTORY_TABLE *table )
425 EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
426 DISPATCHER_CONTEXT_NONVOLREG_ARM nonvol_regs;
427 EXCEPTION_RECORD record;
428 DISPATCHER_CONTEXT dispatch;
429 CONTEXT new_context;
430 NTSTATUS status;
431 ULONG_PTR frame;
432 DWORD i, res;
434 RtlCaptureContext( context );
435 new_context = *context;
437 /* build an exception record, if we do not have one */
438 if (!rec)
440 record.ExceptionCode = STATUS_UNWIND;
441 record.ExceptionFlags = 0;
442 record.ExceptionRecord = NULL;
443 record.ExceptionAddress = (void *)context->Pc;
444 record.NumberParameters = 0;
445 rec = &record;
448 rec->ExceptionFlags |= EXCEPTION_UNWINDING | (end_frame ? 0 : EXCEPTION_EXIT_UNWIND);
450 TRACE( "code=%lx flags=%lx end_frame=%p target_ip=%p\n",
451 rec->ExceptionCode, rec->ExceptionFlags, end_frame, target_ip );
452 for (i = 0; i < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); i++)
453 TRACE( " info[%ld]=%08Ix\n", i, rec->ExceptionInformation[i] );
454 TRACE_CONTEXT( context );
456 dispatch.TargetPc = (ULONG_PTR)target_ip;
457 dispatch.ContextRecord = context;
458 dispatch.HistoryTable = table;
459 dispatch.NonVolatileRegisters = nonvol_regs.Buffer;
461 for (;;)
463 status = virtual_unwind( UNW_FLAG_UHANDLER, &dispatch, &new_context );
464 if (status != STATUS_SUCCESS) raise_status( status, rec );
466 unwind_done:
467 if (!dispatch.EstablisherFrame) break;
469 if (!is_valid_frame( dispatch.EstablisherFrame ))
471 ERR( "invalid frame %lx (%p-%p)\n", dispatch.EstablisherFrame,
472 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
473 rec->ExceptionFlags |= EXCEPTION_STACK_INVALID;
474 break;
477 if (dispatch.LanguageHandler)
479 if (end_frame && (dispatch.EstablisherFrame > (DWORD)end_frame))
481 ERR( "invalid end frame %lx/%p\n", dispatch.EstablisherFrame, end_frame );
482 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
484 if (dispatch.EstablisherFrame == (DWORD)end_frame) rec->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
486 TRACE( "calling handler %p (rec=%p, frame=0x%lx context=%p, dispatch=%p)\n",
487 dispatch.LanguageHandler, rec, dispatch.EstablisherFrame,
488 dispatch.ContextRecord, &dispatch );
489 res = call_unwind_handler( rec, dispatch.EstablisherFrame, dispatch.ContextRecord,
490 &dispatch, dispatch.LanguageHandler );
491 TRACE( "handler %p returned %lx\n", dispatch.LanguageHandler, res );
493 switch (res)
495 case ExceptionContinueSearch:
496 rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
497 break;
498 case ExceptionCollidedUnwind:
499 new_context = *context;
500 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
501 dispatch.ControlPc, dispatch.FunctionEntry,
502 &new_context, &dispatch.HandlerData, &frame,
503 NULL );
504 rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
505 goto unwind_done;
506 default:
507 raise_status( STATUS_INVALID_DISPOSITION, rec );
508 break;
511 else /* hack: call builtin handlers registered in the tib list */
513 while (is_valid_frame( (ULONG_PTR)teb_frame ) &&
514 (DWORD)teb_frame < new_context.Sp &&
515 (DWORD)teb_frame < (DWORD)end_frame)
517 TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
518 teb_frame->Handler, rec, teb_frame, dispatch.ContextRecord, &dispatch );
519 res = call_unwind_handler( rec, (ULONG_PTR)teb_frame, dispatch.ContextRecord, &dispatch,
520 (PEXCEPTION_ROUTINE)teb_frame->Handler );
521 TRACE( "handler at %p returned %lu\n", teb_frame->Handler, res );
522 teb_frame = __wine_pop_frame( teb_frame );
524 switch (res)
526 case ExceptionContinueSearch:
527 rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
528 break;
529 case ExceptionCollidedUnwind:
530 new_context = *context;
531 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
532 dispatch.ControlPc, dispatch.FunctionEntry,
533 &new_context, &dispatch.HandlerData,
534 &frame, NULL );
535 rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
536 goto unwind_done;
537 default:
538 raise_status( STATUS_INVALID_DISPOSITION, rec );
539 break;
542 if ((DWORD)teb_frame == (DWORD)end_frame && (DWORD)end_frame < new_context.Sp) break;
545 if (dispatch.EstablisherFrame == (DWORD)end_frame) break;
546 *context = new_context;
549 if (rec->ExceptionCode != STATUS_UNWIND_CONSOLIDATE)
550 context->Pc = (DWORD)target_ip;
551 else if (rec->ExceptionInformation[10] == -1)
552 rec->ExceptionInformation[10] = (ULONG_PTR)&nonvol_regs;
554 context->R0 = (DWORD)retval;
555 RtlRestoreContext(context, rec);
559 /*************************************************************************
560 * RtlGetNativeSystemInformation (NTDLL.@)
562 NTSTATUS WINAPI RtlGetNativeSystemInformation( SYSTEM_INFORMATION_CLASS class,
563 void *info, ULONG size, ULONG *ret_size )
565 return NtWow64GetNativeSystemInformation( class, info, size, ret_size );
569 /***********************************************************************
570 * RtlIsProcessorFeaturePresent [NTDLL.@]
572 BOOLEAN WINAPI RtlIsProcessorFeaturePresent( UINT feature )
574 return NtWow64IsProcessorFeaturePresent( feature );
578 /*************************************************************************
579 * RtlWalkFrameChain (NTDLL.@)
581 ULONG WINAPI RtlWalkFrameChain( void **buffer, ULONG count, ULONG flags )
583 UNWIND_HISTORY_TABLE table;
584 RUNTIME_FUNCTION *func;
585 PEXCEPTION_ROUTINE handler;
586 ULONG_PTR pc, frame, base;
587 CONTEXT context;
588 void *data;
589 ULONG i, skip = flags >> 8, num_entries = 0;
591 RtlCaptureContext( &context );
593 for (i = 0; i < count; i++)
595 pc = context.Pc;
596 if (context.ContextFlags & CONTEXT_UNWOUND_TO_CALL) pc -= 2;
597 func = RtlLookupFunctionEntry( pc, &base, &table );
598 if (RtlVirtualUnwind2( UNW_FLAG_NHANDLER, base, pc, func, &context, NULL,
599 &data, &frame, NULL, NULL, NULL, &handler, 0 ))
600 break;
601 if (!context.Pc) break;
602 if (!frame || !is_valid_frame( frame )) break;
603 if (context.Sp == (ULONG_PTR)NtCurrentTeb()->Tib.StackBase) break;
604 if (i >= skip) buffer[num_entries++] = (void *)context.Pc;
606 return num_entries;
610 /*******************************************************************
611 * __C_ExecuteExceptionFilter
613 __ASM_GLOBAL_FUNC( __C_ExecuteExceptionFilter,
614 "push {r3-r11,lr}\n\t"
615 ".seh_save_regs_w {r3-r11,lr}\n\t"
616 ".seh_endprologue\n\t"
617 "ldm r3, {r4-r11}\n\t"
618 "blx r2\n\t"
619 "pop {r3-r11,pc}\n\t" )
622 /***********************************************************************
623 * RtlRaiseException (NTDLL.@)
625 __ASM_GLOBAL_FUNC( RtlRaiseException,
626 "push {r0, lr}\n\t"
627 ".seh_save_regs {r0, lr}\n\t"
628 "sub sp, sp, #0x1a0\n\t" /* sizeof(CONTEXT) */
629 ".seh_stackalloc 0x1a0\n\t"
630 ".seh_endprologue\n\t"
631 "mov r0, sp\n\t" /* context */
632 "bl RtlCaptureContext\n\t"
633 "ldr r0, [sp, #0x1a0]\n\t" /* rec */
634 "ldr r1, [sp, #0x1a4]\n\t"
635 "str r1, [sp, #0x3c]\n\t" /* context->Lr */
636 "str r1, [sp, #0x40]\n\t" /* context->Pc */
637 "mrs r2, CPSR\n\t"
638 "bfi r2, r1, #5, #1\n\t" /* Thumb bit */
639 "str r2, [sp, #0x44]\n\t" /* context->Cpsr */
640 "str r1, [r0, #12]\n\t" /* rec->ExceptionAddress */
641 "add r1, sp, #0x1a8\n\t"
642 "str r1, [sp, #0x38]\n\t" /* context->Sp */
643 "ldr r1, [sp]\n\t" /* context->ContextFlags */
644 "orr r1, r1, #0x20000000\n\t" /* CONTEXT_UNWOUND_TO_CALL */
645 "str r1, [sp]\n\t"
646 "mov r1, sp\n\t"
647 "mrc p15, 0, r3, c13, c0, 2\n\t" /* NtCurrentTeb() */
648 "ldr r3, [r3, #0x30]\n\t" /* peb */
649 "ldrb r2, [r3, #2]\n\t" /* peb->BeingDebugged */
650 "cbnz r2, 1f\n\t"
651 "bl dispatch_exception\n"
652 "1:\tmov r2, #1\n\t"
653 "bl NtRaiseException\n\t"
654 "bl RtlRaiseStatus" )
657 /***********************************************************************
658 * _setjmp (NTDLL.@)
659 * _setjmpex (NTDLL.@)
661 __ASM_GLOBAL_FUNC( NTDLL__setjmpex,
662 ".seh_endprologue\n\t"
663 "stm r0, {r1,r4-r11}\n" /* jmp_buf->Frame,R4..R11 */
664 "str sp, [r0, #0x24]\n\t" /* jmp_buf->Sp */
665 "str lr, [r0, #0x28]\n\t" /* jmp_buf->Pc */
666 "vmrs r2, fpscr\n\t"
667 "str r2, [r0, #0x2c]\n\t" /* jmp_buf->Fpscr */
668 "add r0, r0, #0x30\n\t"
669 "vstm r0, {d8-d15}\n\t" /* jmp_buf->D[0..7] */
670 "mov r0, #0\n\t"
671 "bx lr" )
674 /*******************************************************************
675 * longjmp (NTDLL.@)
677 void __cdecl NTDLL_longjmp( _JUMP_BUFFER *buf, int retval )
679 EXCEPTION_RECORD rec;
681 if (!retval) retval = 1;
683 rec.ExceptionCode = STATUS_LONGJUMP;
684 rec.ExceptionFlags = 0;
685 rec.ExceptionRecord = NULL;
686 rec.ExceptionAddress = NULL;
687 rec.NumberParameters = 1;
688 rec.ExceptionInformation[0] = (DWORD_PTR)buf;
689 RtlUnwind( (void *)buf->Frame, (void *)buf->Pc, &rec, IntToPtr(retval) );
693 /***********************************************************************
694 * RtlUserThreadStart (NTDLL.@)
696 __ASM_GLOBAL_FUNC( RtlUserThreadStart,
697 "push {r4, lr}\n\t"
698 ".seh_save_regs {r4, lr}\n\t"
699 ".seh_endprologue\n\t"
700 "mov r2, r1\n\t"
701 "mov r1, r0\n\t"
702 "mov r0, #0\n\t"
703 "ldr ip, 1f\n\t"
704 "ldr ip, [ip]\n\t"
705 "blx ip\n\t"
706 "nop\n"
707 "1:\t.long pBaseThreadInitThunk\n\t"
708 ".seh_handler call_unhandled_exception_handler, %except" )
710 /******************************************************************
711 * LdrInitializeThunk (NTDLL.@)
713 void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unk2, ULONG_PTR unk3, ULONG_PTR unk4 )
715 loader_init( context, (void **)&context->R0 );
716 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", (void *)context->R0, (void *)context->R1 );
717 NtContinue( context, TRUE );
720 /***********************************************************************
721 * process_breakpoint
723 __ASM_GLOBAL_FUNC( process_breakpoint,
724 ".seh_endprologue\n\t"
725 ".seh_handler process_breakpoint_handler, %except\n\t"
726 "udf #0xfe\n\t"
727 "bx lr\n"
728 "process_breakpoint_handler:\n\t"
729 "ldr r0, [r2, #0x40]\n\t" /* context->Pc */
730 "add r0, r0, #2\n\t"
731 "str r0, [r2, #0x40]\n\t"
732 "mov r0, #0\n\t" /* ExceptionContinueExecution */
733 "bx lr" )
735 /***********************************************************************
736 * DbgUiRemoteBreakin (NTDLL.@)
738 __ASM_GLOBAL_FUNC( DbgUiRemoteBreakin,
739 ".seh_endprologue\n\t"
740 ".seh_handler DbgUiRemoteBreakin_handler, %except\n\t"
741 "mrc p15, 0, r0, c13, c0, 2\n\t" /* NtCurrentTeb() */
742 "ldr r0, [r0, #0x30]\n\t" /* NtCurrentTeb()->Peb */
743 "ldrb r0, [r0, 0x02]\n\t" /* peb->BeingDebugged */
744 "cbz r0, 1f\n\t"
745 "bl DbgBreakPoint\n"
746 "1:\tmov r0, #0\n\t"
747 "bl RtlExitUserThread\n"
748 "DbgUiRemoteBreakin_handler:\n\t"
749 "mov sp, r1\n\t" /* frame */
750 "b 1b" )
752 /**********************************************************************
753 * DbgBreakPoint (NTDLL.@)
755 __ASM_GLOBAL_FUNC( DbgBreakPoint, "udf #0xfe; bx lr; nop; nop; nop; nop" );
757 /**********************************************************************
758 * DbgUserBreakPoint (NTDLL.@)
760 __ASM_GLOBAL_FUNC( DbgUserBreakPoint, "udf #0xfe; bx lr; nop; nop; nop; nop" );
762 #endif /* __arm__ */