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
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
30 #define WIN32_NO_STATUS
33 #include "wine/exception.h"
34 #include "ntdll_misc.h"
35 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
41 /*******************************************************************
44 static inline BOOL
is_valid_frame( void *frame
)
46 if ((ULONG_PTR
)frame
& 3) return FALSE
;
47 return (frame
>= NtCurrentTeb()->Tib
.StackLimit
&&
48 (void **)frame
< (void **)NtCurrentTeb()->Tib
.StackBase
- 1);
52 /**************************************************************************
55 * Incoming r4 contains words to allocate, converting to bytes then return
57 __ASM_GLOBAL_FUNC( __chkstk
, "lsl r4, r4, #2\n\t"
60 /***********************************************************************
61 * RtlCaptureContext (NTDLL.@)
63 __ASM_STDCALL_FUNC( RtlCaptureContext
, 4,
64 "str r0, [r0, #0x4]\n\t" /* context->R0 */
65 "str r1, [r0, #0x8]\n\t" /* context->R1 */
66 "mov r1, #0x0200000\n\t" /* CONTEXT_ARM */
67 "add r1, r1, #0x3\n\t" /* CONTEXT_FULL */
68 "str r1, [r0]\n\t" /* context->ContextFlags */
69 "str SP, [r0, #0x38]\n\t" /* context->Sp */
70 "str LR, [r0, #0x3c]\n\t" /* context->Lr */
71 "str LR, [r0, #0x40]\n\t" /* context->Pc */
73 "tst lr, #1\n\t" /* Thumb? */
75 "orrne r1, r1, #0x20\n\t"
76 "biceq r1, r1, #0x20\n\t"
77 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
79 "stm r0, {r2-r12}\n\t" /* context->R2..R12 */
84 /**********************************************************************
87 * Call the stack handlers chain.
89 static NTSTATUS
call_stack_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
91 EXCEPTION_REGISTRATION_RECORD
*frame
, *dispatch
, *nested_frame
;
94 frame
= NtCurrentTeb()->Tib
.ExceptionList
;
96 while (frame
!= (EXCEPTION_REGISTRATION_RECORD
*)~0UL)
98 /* Check frame address */
99 if (!is_valid_frame( frame
))
101 rec
->ExceptionFlags
|= EH_STACK_INVALID
;
106 TRACE( "calling handler at %p code=%x flags=%x\n",
107 frame
->Handler
, rec
->ExceptionCode
, rec
->ExceptionFlags
);
108 res
= frame
->Handler( rec
, frame
, context
, &dispatch
);
109 TRACE( "handler at %p returned %x\n", frame
->Handler
, res
);
111 if (frame
== nested_frame
)
113 /* no longer nested */
115 rec
->ExceptionFlags
&= ~EH_NESTED_CALL
;
120 case ExceptionContinueExecution
:
121 if (!(rec
->ExceptionFlags
& EH_NONCONTINUABLE
)) return STATUS_SUCCESS
;
122 return STATUS_NONCONTINUABLE_EXCEPTION
;
123 case ExceptionContinueSearch
:
125 case ExceptionNestedException
:
126 if (nested_frame
< dispatch
) nested_frame
= dispatch
;
127 rec
->ExceptionFlags
|= EH_NESTED_CALL
;
130 return STATUS_INVALID_DISPOSITION
;
134 return STATUS_UNHANDLED_EXCEPTION
;
138 /*******************************************************************
139 * KiUserExceptionDispatcher (NTDLL.@)
141 NTSTATUS WINAPI
KiUserExceptionDispatcher( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
146 TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n",
147 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
,
148 context
->Pc
, GetCurrentThreadId() );
149 for (c
= 0; c
< rec
->NumberParameters
; c
++)
150 TRACE( " info[%d]=%08lx\n", c
, rec
->ExceptionInformation
[c
] );
152 if (rec
->ExceptionCode
== EXCEPTION_WINE_STUB
)
154 if (rec
->ExceptionInformation
[1] >> 16)
155 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
156 rec
->ExceptionAddress
,
157 (char*)rec
->ExceptionInformation
[0], (char*)rec
->ExceptionInformation
[1] );
159 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
160 rec
->ExceptionAddress
,
161 (char*)rec
->ExceptionInformation
[0], rec
->ExceptionInformation
[1] );
163 else if (rec
->ExceptionCode
== EXCEPTION_WINE_NAME_THREAD
&& rec
->ExceptionInformation
[0] == 0x1000)
165 WARN( "Thread %04x renamed to %s\n", (DWORD
)rec
->ExceptionInformation
[2], debugstr_a((char *)rec
->ExceptionInformation
[1]) );
167 else if (rec
->ExceptionCode
== DBG_PRINTEXCEPTION_C
)
169 WARN( "%s\n", debugstr_an((char *)rec
->ExceptionInformation
[1], rec
->ExceptionInformation
[0] - 1) );
171 else if (rec
->ExceptionCode
== DBG_PRINTEXCEPTION_WIDE_C
)
173 WARN( "%s\n", debugstr_wn((WCHAR
*)rec
->ExceptionInformation
[1], rec
->ExceptionInformation
[0] - 1) );
177 if (rec
->ExceptionCode
== STATUS_ASSERTION_FAILURE
)
178 ERR( "%s exception (code=%x) raised\n", debugstr_exception_code(rec
->ExceptionCode
), rec
->ExceptionCode
);
180 WARN( "%s exception (code=%x) raised\n", debugstr_exception_code(rec
->ExceptionCode
), rec
->ExceptionCode
);
182 TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n",
183 context
->R0
, context
->R1
, context
->R2
, context
->R3
, context
->R4
, context
->R5
);
184 TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x r11=%08x\n",
185 context
->R6
, context
->R7
, context
->R8
, context
->R9
, context
->R10
, context
->R11
);
186 TRACE( " r12=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n",
187 context
->R12
, context
->Sp
, context
->Lr
, context
->Pc
, context
->Cpsr
);
190 if (call_vectored_handlers( rec
, context
) == EXCEPTION_CONTINUE_EXECUTION
)
191 NtContinue( context
, FALSE
);
193 if ((status
= call_stack_handlers( rec
, context
)) == STATUS_SUCCESS
)
194 NtContinue( context
, FALSE
);
196 if (status
!= STATUS_UNHANDLED_EXCEPTION
) RtlRaiseStatus( status
);
197 return NtRaiseException( rec
, context
, FALSE
);
201 /*******************************************************************
202 * KiUserApcDispatcher (NTDLL.@)
204 void WINAPI
KiUserApcDispatcher( CONTEXT
*context
, ULONG_PTR ctx
, ULONG_PTR arg1
, ULONG_PTR arg2
,
207 func( ctx
, arg1
, arg2
);
208 NtContinue( context
, TRUE
);
212 /***********************************************************************
213 * RtlUnwind (NTDLL.@)
215 void WINAPI
RtlUnwind( void *endframe
, void *target_ip
, EXCEPTION_RECORD
*rec
, void *retval
)
218 EXCEPTION_RECORD record
;
219 EXCEPTION_REGISTRATION_RECORD
*frame
, *dispatch
;
222 RtlCaptureContext( &context
);
223 context
.R0
= (DWORD
)retval
;
225 /* build an exception record, if we do not have one */
228 record
.ExceptionCode
= STATUS_UNWIND
;
229 record
.ExceptionFlags
= 0;
230 record
.ExceptionRecord
= NULL
;
231 record
.ExceptionAddress
= (void *)context
.Pc
;
232 record
.NumberParameters
= 0;
236 rec
->ExceptionFlags
|= EH_UNWINDING
| (endframe
? 0 : EH_EXIT_UNWIND
);
238 TRACE( "code=%x flags=%x\n", rec
->ExceptionCode
, rec
->ExceptionFlags
);
240 /* get chain of exception frames */
241 frame
= NtCurrentTeb()->Tib
.ExceptionList
;
242 while ((frame
!= (EXCEPTION_REGISTRATION_RECORD
*)~0UL) && (frame
!= endframe
))
244 /* Check frame address */
245 if (endframe
&& ((void*)frame
> endframe
))
246 raise_status( STATUS_INVALID_UNWIND_TARGET
, rec
);
248 if (!is_valid_frame( frame
)) raise_status( STATUS_BAD_STACK
, rec
);
251 TRACE( "calling handler at %p code=%x flags=%x\n",
252 frame
->Handler
, rec
->ExceptionCode
, rec
->ExceptionFlags
);
253 res
= frame
->Handler(rec
, frame
, &context
, &dispatch
);
254 TRACE( "handler at %p returned %x\n", frame
->Handler
, res
);
258 case ExceptionContinueSearch
:
260 case ExceptionCollidedUnwind
:
264 raise_status( STATUS_INVALID_DISPOSITION
, rec
);
267 frame
= __wine_pop_frame( frame
);
272 /***********************************************************************
273 * RtlRaiseException (NTDLL.@)
275 __ASM_STDCALL_FUNC( RtlRaiseException
, 4,
277 "sub sp, sp, #0x1a0\n\t" /* sizeof(CONTEXT) */
278 "mov r0, sp\n\t" /* context */
279 "bl " __ASM_NAME("RtlCaptureContext") "\n\t"
280 "ldr r0, [sp, #0x1a0]\n\t" /* rec */
281 "ldr r1, [sp, #0x1a4]\n\t"
282 "str r1, [sp, #0x40]\n\t" /* context->Pc */
283 "ldr r2, [sp, #0x44]\n\t" /* context->Cpsr */
284 "tst r1, #1\n\t" /* Thumb? */
286 "orrne r2, r2, #0x20\n\t"
287 "biceq r2, r2, #0x20\n\t"
288 "str r2, [sp, #0x44]\n\t" /* context->Cpsr */
289 "str r1, [r0, #12]\n\t" /* rec->ExceptionAddress */
290 "add r1, sp, #0x1a8\n\t"
291 "str r1, [sp, #0x38]\n\t" /* context->Sp */
294 "bl " __ASM_NAME("NtRaiseException") "\n\t"
295 "bl " __ASM_NAME("RtlRaiseStatus") )
297 /*************************************************************************
298 * RtlCaptureStackBackTrace (NTDLL.@)
300 USHORT WINAPI
RtlCaptureStackBackTrace( ULONG skip
, ULONG count
, PVOID
*buffer
, ULONG
*hash
)
302 FIXME( "(%d, %d, %p, %p) stub!\n", skip
, count
, buffer
, hash
);
306 /***********************************************************************
307 * signal_start_thread
309 __ASM_GLOBAL_FUNC( signal_start_thread
,
310 "mov sp, r0\n\t" /* context */
312 "b " __ASM_NAME("NtContinue") )
314 /**********************************************************************
315 * DbgBreakPoint (NTDLL.@)
317 __ASM_STDCALL_FUNC( DbgBreakPoint
, 0, "bkpt #0; bx lr; nop; nop; nop; nop" );
319 /**********************************************************************
320 * DbgUserBreakPoint (NTDLL.@)
322 __ASM_STDCALL_FUNC( DbgUserBreakPoint
, 0, "bkpt #0; bx lr; nop; nop; nop; nop" );