2 * i386 signal handling routines
4 * Copyright 1999 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include <sys/types.h>
31 #define WIN32_NO_STATUS
33 #include "ntdll_misc.h"
34 #include "wine/exception.h"
35 #include "wine/debug.h"
36 #include "ntsyscalls.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
39 WINE_DECLARE_DEBUG_CHANNEL(relay
);
40 WINE_DECLARE_DEBUG_CHANNEL(threadname
);
42 struct x86_thread_data
44 DWORD fs
; /* 1d4 TEB selector */
45 DWORD gs
; /* 1d8 libc selector; update winebuild if you move this! */
46 DWORD dr0
; /* 1dc debug registers */
52 void *exit_frame
; /* 1f4 exit frame pointer */
55 C_ASSERT( sizeof(struct x86_thread_data
) <= 16 * sizeof(void *) );
56 C_ASSERT( offsetof( TEB
, GdiTebBatch
) + offsetof( struct x86_thread_data
, gs
) == 0x1d8 );
57 C_ASSERT( offsetof( TEB
, GdiTebBatch
) + offsetof( struct x86_thread_data
, exit_frame
) == 0x1f4 );
59 static inline struct x86_thread_data
*x86_thread_data(void)
61 return (struct x86_thread_data
*)&NtCurrentTeb()->GdiTebBatch
;
64 /* Exception record for handling exceptions happening inside exception handlers */
67 EXCEPTION_REGISTRATION_RECORD frame
;
68 EXCEPTION_REGISTRATION_RECORD
*prevFrame
;
71 extern DWORD
EXC_CallHandler( EXCEPTION_RECORD
*record
, EXCEPTION_REGISTRATION_RECORD
*frame
,
72 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**dispatcher
,
73 PEXCEPTION_HANDLER handler
, PEXCEPTION_HANDLER nested_handler
);
76 /*******************************************************************
79 #define SYSCALL_ENTRY(id,name,args) __ASM_SYSCALL_FUNC( id, name, args )
81 DEFINE_SYSCALL_HELPER32()
85 /*******************************************************************
88 static inline BOOL
is_valid_frame( void *frame
)
90 if ((ULONG_PTR
)frame
& 3) return FALSE
;
91 return (frame
>= NtCurrentTeb()->Tib
.StackLimit
&&
92 (void **)frame
< (void **)NtCurrentTeb()->Tib
.StackBase
- 1);
95 /*******************************************************************
98 * Handler for exceptions happening inside a handler.
100 static DWORD
raise_handler( EXCEPTION_RECORD
*rec
, EXCEPTION_REGISTRATION_RECORD
*frame
,
101 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**dispatcher
)
103 if (rec
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
))
104 return ExceptionContinueSearch
;
105 /* We shouldn't get here so we store faulty frame in dispatcher */
106 *dispatcher
= ((EXC_NESTED_FRAME
*)frame
)->prevFrame
;
107 return ExceptionNestedException
;
111 /*******************************************************************
114 * Handler for exceptions happening inside an unwind handler.
116 static DWORD
unwind_handler( EXCEPTION_RECORD
*rec
, EXCEPTION_REGISTRATION_RECORD
*frame
,
117 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**dispatcher
)
119 if (!(rec
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
)))
120 return ExceptionContinueSearch
;
121 /* We shouldn't get here so we store faulty frame in dispatcher */
122 *dispatcher
= ((EXC_NESTED_FRAME
*)frame
)->prevFrame
;
123 return ExceptionCollidedUnwind
;
127 /**********************************************************************
128 * call_stack_handlers
130 * Call the stack handlers chain.
132 static NTSTATUS
call_stack_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
134 EXCEPTION_REGISTRATION_RECORD
*frame
, *dispatch
, *nested_frame
;
137 frame
= NtCurrentTeb()->Tib
.ExceptionList
;
139 while (frame
!= (EXCEPTION_REGISTRATION_RECORD
*)~0UL)
141 /* Check frame address */
142 if (!is_valid_frame( frame
))
144 rec
->ExceptionFlags
|= EH_STACK_INVALID
;
149 TRACE( "calling handler at %p code=%lx flags=%lx\n",
150 frame
->Handler
, rec
->ExceptionCode
, rec
->ExceptionFlags
);
151 res
= EXC_CallHandler( rec
, frame
, context
, &dispatch
, frame
->Handler
, raise_handler
);
152 TRACE( "handler at %p returned %lx\n", frame
->Handler
, res
);
154 if (frame
== nested_frame
)
156 /* no longer nested */
158 rec
->ExceptionFlags
&= ~EH_NESTED_CALL
;
163 case ExceptionContinueExecution
:
164 if (!(rec
->ExceptionFlags
& EH_NONCONTINUABLE
)) return STATUS_SUCCESS
;
165 return STATUS_NONCONTINUABLE_EXCEPTION
;
166 case ExceptionContinueSearch
:
168 case ExceptionNestedException
:
169 if (nested_frame
< dispatch
) nested_frame
= dispatch
;
170 rec
->ExceptionFlags
|= EH_NESTED_CALL
;
173 return STATUS_INVALID_DISPOSITION
;
177 return STATUS_UNHANDLED_EXCEPTION
;
181 /*******************************************************************
182 * KiUserExceptionDispatcher (NTDLL.@)
184 NTSTATUS WINAPI
dispatch_exception( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
189 TRACE( "code=%lx flags=%lx addr=%p ip=%08lx\n",
190 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
, context
->Eip
);
191 for (c
= 0; c
< rec
->NumberParameters
; c
++)
192 TRACE( " info[%ld]=%08Ix\n", c
, rec
->ExceptionInformation
[c
] );
194 if (rec
->ExceptionCode
== EXCEPTION_WINE_STUB
)
196 if (rec
->ExceptionInformation
[1] >> 16)
197 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
198 rec
->ExceptionAddress
,
199 (char*)rec
->ExceptionInformation
[0], (char*)rec
->ExceptionInformation
[1] );
201 MESSAGE( "wine: Call from %p to unimplemented function %s.%Id, aborting\n",
202 rec
->ExceptionAddress
,
203 (char*)rec
->ExceptionInformation
[0], rec
->ExceptionInformation
[1] );
205 else if (rec
->ExceptionCode
== EXCEPTION_WINE_NAME_THREAD
&& rec
->ExceptionInformation
[0] == 0x1000)
207 if ((DWORD
)rec
->ExceptionInformation
[2] == -1 || (DWORD
)rec
->ExceptionInformation
[2] == GetCurrentThreadId())
208 WARN_(threadname
)( "Thread renamed to %s\n", debugstr_a((char *)rec
->ExceptionInformation
[1]) );
210 WARN_(threadname
)( "Thread ID %04lx renamed to %s\n", (DWORD
)rec
->ExceptionInformation
[2],
211 debugstr_a((char *)rec
->ExceptionInformation
[1]) );
213 set_native_thread_name((DWORD
)rec
->ExceptionInformation
[2], (char *)rec
->ExceptionInformation
[1]);
215 else if (rec
->ExceptionCode
== DBG_PRINTEXCEPTION_C
)
217 WARN( "%s\n", debugstr_an((char *)rec
->ExceptionInformation
[1], rec
->ExceptionInformation
[0] - 1) );
219 else if (rec
->ExceptionCode
== DBG_PRINTEXCEPTION_WIDE_C
)
221 WARN( "%s\n", debugstr_wn((WCHAR
*)rec
->ExceptionInformation
[1], rec
->ExceptionInformation
[0] - 1) );
225 if (rec
->ExceptionCode
== STATUS_ASSERTION_FAILURE
)
226 ERR( "%s exception (code=%lx) raised\n", debugstr_exception_code(rec
->ExceptionCode
), rec
->ExceptionCode
);
228 WARN( "%s exception (code=%lx) raised\n", debugstr_exception_code(rec
->ExceptionCode
), rec
->ExceptionCode
);
230 TRACE(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
231 context
->Eax
, context
->Ebx
, context
->Ecx
,
232 context
->Edx
, context
->Esi
, context
->Edi
);
233 TRACE(" ebp=%08lx esp=%08lx cs=%04lx ss=%04lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
234 context
->Ebp
, context
->Esp
, context
->SegCs
, context
->SegSs
, context
->SegDs
,
235 context
->SegEs
, context
->SegFs
, context
->SegGs
, context
->EFlags
);
238 if (call_vectored_handlers( rec
, context
) == EXCEPTION_CONTINUE_EXECUTION
)
239 NtContinue( context
, FALSE
);
241 if ((status
= call_stack_handlers( rec
, context
)) == STATUS_SUCCESS
)
242 NtContinue( context
, FALSE
);
244 if (status
!= STATUS_UNHANDLED_EXCEPTION
) RtlRaiseStatus( status
);
245 return NtRaiseException( rec
, context
, FALSE
);
248 __ASM_STDCALL_FUNC( KiUserExceptionDispatcher
, 8,
251 "call " __ASM_STDCALL("dispatch_exception", 8) "\n\t"
255 /*******************************************************************
256 * KiUserApcDispatcher (NTDLL.@)
258 void WINAPI
KiUserApcDispatcher( CONTEXT
*context
, ULONG_PTR ctx
, ULONG_PTR arg1
, ULONG_PTR arg2
,
261 func( ctx
, arg1
, arg2
);
262 NtContinue( context
, TRUE
);
266 /*******************************************************************
267 * KiUserCallbackDispatcher (NTDLL.@)
269 void WINAPI
KiUserCallbackDispatcher( ULONG id
, void *args
, ULONG len
)
275 NTSTATUS (WINAPI
*func
)(void *, ULONG
) = ((void **)NtCurrentTeb()->Peb
->KernelCallbackTable
)[id
];
276 status
= NtCallbackReturn( NULL
, 0, func( args
, len
));
280 ERR_(seh
)( "ignoring exception\n" );
281 status
= NtCallbackReturn( 0, 0, 0 );
285 RtlRaiseStatus( status
);
289 /***********************************************************************
292 * Save the thread FPU context.
294 static inline void save_fpu( CONTEXT
*context
)
309 context
->ContextFlags
|= CONTEXT_FLOATING_POINT
;
310 __asm__
__volatile__( "fnsave %0; fwait" : "=m" (context
->FloatSave
) );
312 /* Reset unmasked exceptions status to avoid firing an exception. */
313 memcpy(&float_status
, &context
->FloatSave
, sizeof(float_status
));
314 float_status
.StatusWord
&= float_status
.ControlWord
| 0xffffff80;
316 __asm__
__volatile__( "fldenv %0" : : "m" (float_status
) );
321 /***********************************************************************
324 * Save the thread FPU extended context.
326 static inline void save_fpux( CONTEXT
*context
)
329 /* we have to enforce alignment by hand */
330 char buffer
[sizeof(XSAVE_FORMAT
) + 16];
331 XSAVE_FORMAT
*state
= (XSAVE_FORMAT
*)(((ULONG_PTR
)buffer
+ 15) & ~15);
333 context
->ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
334 __asm__
__volatile__( "fxsave %0" : "=m" (*state
) );
335 memcpy( context
->ExtendedRegisters
, state
, sizeof(*state
) );
340 /***********************************************************************
341 * RtlCaptureContext (NTDLL.@)
343 __ASM_STDCALL_FUNC( RtlCaptureContext
, 4,
345 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
346 "movl 8(%esp),%eax\n\t" /* context */
347 "movl $0x10007,(%eax)\n\t" /* context->ContextFlags */
348 "movw %gs,0x8c(%eax)\n\t" /* context->SegGs */
349 "movw %fs,0x90(%eax)\n\t" /* context->SegFs */
350 "movw %es,0x94(%eax)\n\t" /* context->SegEs */
351 "movw %ds,0x98(%eax)\n\t" /* context->SegDs */
352 "movl %edi,0x9c(%eax)\n\t" /* context->Edi */
353 "movl %esi,0xa0(%eax)\n\t" /* context->Esi */
354 "movl %ebx,0xa4(%eax)\n\t" /* context->Ebx */
355 "movl %edx,0xa8(%eax)\n\t" /* context->Edx */
356 "movl %ecx,0xac(%eax)\n\t" /* context->Ecx */
357 "movl 0(%ebp),%edx\n\t"
358 "movl %edx,0xb4(%eax)\n\t" /* context->Ebp */
359 "movl 4(%ebp),%edx\n\t"
360 "movl %edx,0xb8(%eax)\n\t" /* context->Eip */
361 "movw %cs,0xbc(%eax)\n\t" /* context->SegCs */
363 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
364 "popl 0xc0(%eax)\n\t" /* context->EFlags */
365 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
366 "leal 8(%ebp),%edx\n\t"
367 "movl %edx,0xc4(%eax)\n\t" /* context->Esp */
368 "movw %ss,0xc8(%eax)\n\t" /* context->SegSs */
369 "popl 0xb0(%eax)\n\t" /* context->Eax */
370 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
373 /*******************************************************************
374 * RtlRestoreContext (NTDLL.@)
376 void CDECL
RtlRestoreContext( CONTEXT
*context
, EXCEPTION_RECORD
*rec
)
378 TRACE( "returning to %p stack %p\n", (void *)context
->Eip
, (void *)context
->Esp
);
379 NtContinue( context
, FALSE
);
382 /*******************************************************************
383 * RtlUnwind (NTDLL.@)
385 void WINAPI
__regs_RtlUnwind( EXCEPTION_REGISTRATION_RECORD
* pEndFrame
, PVOID targetIp
,
386 PEXCEPTION_RECORD pRecord
, PVOID retval
, CONTEXT
*context
)
388 EXCEPTION_RECORD record
;
389 EXCEPTION_REGISTRATION_RECORD
*frame
, *dispatch
;
392 context
->Eax
= (DWORD
)retval
;
394 /* build an exception record, if we do not have one */
397 record
.ExceptionCode
= STATUS_UNWIND
;
398 record
.ExceptionFlags
= 0;
399 record
.ExceptionRecord
= NULL
;
400 record
.ExceptionAddress
= (void *)context
->Eip
;
401 record
.NumberParameters
= 0;
405 pRecord
->ExceptionFlags
|= EH_UNWINDING
| (pEndFrame
? 0 : EH_EXIT_UNWIND
);
407 TRACE( "code=%lx flags=%lx\n", pRecord
->ExceptionCode
, pRecord
->ExceptionFlags
);
408 TRACE( "eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
409 context
->Eax
, context
->Ebx
, context
->Ecx
, context
->Edx
, context
->Esi
, context
->Edi
);
410 TRACE( "ebp=%08lx esp=%08lx eip=%08lx cs=%04x ds=%04x fs=%04x gs=%04x flags=%08lx\n",
411 context
->Ebp
, context
->Esp
, context
->Eip
, LOWORD(context
->SegCs
), LOWORD(context
->SegDs
),
412 LOWORD(context
->SegFs
), LOWORD(context
->SegGs
), context
->EFlags
);
414 /* get chain of exception frames */
415 frame
= NtCurrentTeb()->Tib
.ExceptionList
;
416 while ((frame
!= (EXCEPTION_REGISTRATION_RECORD
*)~0UL) && (frame
!= pEndFrame
))
418 /* Check frame address */
419 if (pEndFrame
&& (frame
> pEndFrame
))
420 raise_status( STATUS_INVALID_UNWIND_TARGET
, pRecord
);
422 if (!is_valid_frame( frame
)) raise_status( STATUS_BAD_STACK
, pRecord
);
425 TRACE( "calling handler at %p code=%lx flags=%lx\n",
426 frame
->Handler
, pRecord
->ExceptionCode
, pRecord
->ExceptionFlags
);
427 res
= EXC_CallHandler( pRecord
, frame
, context
, &dispatch
, frame
->Handler
, unwind_handler
);
428 TRACE( "handler at %p returned %lx\n", frame
->Handler
, res
);
432 case ExceptionContinueSearch
:
434 case ExceptionCollidedUnwind
:
438 raise_status( STATUS_INVALID_DISPOSITION
, pRecord
);
441 frame
= __wine_pop_frame( frame
);
443 NtContinue( context
, FALSE
);
445 __ASM_STDCALL_FUNC( RtlUnwind
, 16,
447 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
448 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
450 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
451 "leal -(0x2cc+8)(%esp),%esp\n\t" /* sizeof(CONTEXT) + alignment */
453 "leal 4(%esp),%eax\n\t" /* context */
454 "xchgl %eax,(%esp)\n\t"
455 "call " __ASM_STDCALL("RtlCaptureContext",4) "\n\t"
456 "leal 24(%ebp),%eax\n\t"
457 "movl %eax,0xc4(%esp)\n\t" /* context->Esp */
463 "call " __ASM_STDCALL("__regs_RtlUnwind",20) "\n\t"
465 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
466 __ASM_CFI(".cfi_same_value %ebp\n\t")
467 "ret $16" ) /* actually never returns */
470 /*******************************************************************
471 * raise_exception_full_context
473 * Raise an exception with the full CPU context.
475 void raise_exception_full_context( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
478 save_fpux( context
);
480 context
->Dr0
= x86_thread_data()->dr0
;
481 context
->Dr1
= x86_thread_data()->dr1
;
482 context
->Dr2
= x86_thread_data()->dr2
;
483 context
->Dr3
= x86_thread_data()->dr3
;
484 context
->Dr6
= x86_thread_data()->dr6
;
485 context
->Dr7
= x86_thread_data()->dr7
;
486 context
->ContextFlags
|= CONTEXT_DEBUG_REGISTERS
;
488 RtlRaiseStatus( NtRaiseException( rec
, context
, TRUE
));
492 /***********************************************************************
493 * RtlRaiseException (NTDLL.@)
495 __ASM_STDCALL_FUNC( RtlRaiseException
, 4,
497 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
498 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
500 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
501 "leal -0x2cc(%esp),%esp\n\t" /* sizeof(CONTEXT) */
502 "pushl %esp\n\t" /* context */
503 "call " __ASM_STDCALL("RtlCaptureContext",4) "\n\t"
504 "movl 4(%ebp),%eax\n\t" /* return address */
505 "movl 8(%ebp),%ecx\n\t" /* rec */
506 "movl %eax,12(%ecx)\n\t" /* rec->ExceptionAddress */
507 "leal 12(%ebp),%eax\n\t"
508 "movl %eax,0xc4(%esp)\n\t" /* context->Esp */
512 "call " __ASM_NAME("raise_exception_full_context") "\n\t"
514 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
515 __ASM_CFI(".cfi_same_value %ebp\n\t")
516 "ret $4" ) /* actually never returns */
519 /*************************************************************************
520 * RtlCaptureStackBackTrace (NTDLL.@)
522 USHORT WINAPI
RtlCaptureStackBackTrace( ULONG skip
, ULONG count
, PVOID
*buffer
, ULONG
*hash
)
528 RtlCaptureContext( &context
);
530 frame
= (ULONG
*)context
.Ebp
;
534 if (!is_valid_frame( frame
)) return 0;
535 frame
= (ULONG
*)*frame
;
538 for (i
= 0; i
< count
; i
++)
540 if (!is_valid_frame( frame
)) break;
541 buffer
[i
] = (void *)frame
[1];
542 if (hash
) *hash
+= frame
[1];
543 frame
= (ULONG
*)*frame
;
549 /***********************************************************************
550 * RtlUserThreadStart (NTDLL.@)
552 __ASM_STDCALL_FUNC( RtlUserThreadStart
, 8,
553 "movl %ebx,8(%esp)\n\t" /* arg */
554 "movl %eax,4(%esp)\n\t" /* entry */
555 "jmp " __ASM_NAME("call_thread_func") )
557 /* wrapper to call BaseThreadInitThunk */
558 extern void DECLSPEC_NORETURN
call_thread_func_wrapper( void *thunk
, PRTL_THREAD_START_ROUTINE entry
, void *arg
);
559 __ASM_GLOBAL_FUNC( call_thread_func_wrapper
,
561 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
562 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
564 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
566 "andl $~0xf,%esp\n\t"
568 "movl 12(%ebp),%edx\n\t"
569 "movl 16(%ebp),%eax\n\t"
570 "movl %eax,(%esp)\n\t"
573 void call_thread_func( PRTL_THREAD_START_ROUTINE entry
, void *arg
)
577 call_thread_func_wrapper( pBaseThreadInitThunk
, entry
, arg
);
579 __EXCEPT(call_unhandled_exception_filter
)
581 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
586 /***********************************************************************
587 * signal_start_thread
589 extern void CDECL DECLSPEC_NORETURN
signal_start_thread( CONTEXT
*ctx
);
590 __ASM_GLOBAL_FUNC( signal_start_thread
,
591 "movl 4(%esp),%esi\n\t" /* context */
592 "leal -12(%esi),%edi\n\t"
593 /* clear the thread stack */
594 "andl $~0xfff,%edi\n\t" /* round down to page size */
595 "movl $0xf0000,%ecx\n\t"
601 /* switch to the initial context */
602 "leal -12(%esi),%esp\n\t"
603 "movl $1,4(%esp)\n\t"
604 "movl %esi,(%esp)\n\t"
605 "call " __ASM_STDCALL("NtContinue", 8) )
607 /******************************************************************
608 * LdrInitializeThunk (NTDLL.@)
610 void WINAPI
LdrInitializeThunk( CONTEXT
*context
, ULONG_PTR unk2
, ULONG_PTR unk3
, ULONG_PTR unk4
)
612 loader_init( context
, (void **)&context
->Eax
);
613 TRACE_(relay
)( "\1Starting thread proc %p (arg=%p)\n", (void *)context
->Eax
, (void *)context
->Ebx
);
614 signal_start_thread( context
);
618 /**********************************************************************
619 * DbgBreakPoint (NTDLL.@)
621 __ASM_STDCALL_FUNC( DbgBreakPoint
, 0, "int $3; ret"
622 "\n\tnop; nop; nop; nop; nop; nop; nop; nop"
623 "\n\tnop; nop; nop; nop; nop; nop" );
625 /**********************************************************************
626 * DbgUserBreakPoint (NTDLL.@)
628 __ASM_STDCALL_FUNC( DbgUserBreakPoint
, 0, "int $3; ret"
629 "\n\tnop; nop; nop; nop; nop; nop; nop; nop"
630 "\n\tnop; nop; nop; nop; nop; nop" );
632 /**********************************************************************
633 * NtCurrentTeb (NTDLL.@)
635 __ASM_STDCALL_FUNC( NtCurrentTeb
, 0, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" )
638 /**************************************************************************
641 __ASM_GLOBAL_FUNC( _chkstk
,
644 "xchgl %esp,%eax\n\t"
645 "movl 0(%eax),%eax\n\t" /* copy return address from old location */
646 "movl %eax,0(%esp)\n\t"
649 /**************************************************************************
650 * _alloca_probe (NTDLL.@)
652 __ASM_GLOBAL_FUNC( _alloca_probe
,
655 "xchgl %esp,%eax\n\t"
656 "movl 0(%eax),%eax\n\t" /* copy return address from old location */
657 "movl %eax,0(%esp)\n\t"
661 /**********************************************************************
662 * EXC_CallHandler (internal)
664 * Some exception handlers depend on EBP to have a fixed position relative to
665 * the exception frame.
666 * Shrinker depends on (*1) doing what it does,
667 * (*2) being the exact instruction it is and (*3) beginning with 0x64
668 * (i.e. the %fs prefix to the movl instruction). It also depends on the
669 * function calling the handler having only 5 parameters (*4).
671 __ASM_GLOBAL_FUNC( EXC_CallHandler
,
673 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
674 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
676 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
678 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
679 "movl 28(%ebp), %edx\n\t" /* ugly hack to pass the 6th param needed because of Shrinker */
685 "call " __ASM_NAME("call_exception_handler") "\n\t"
687 __ASM_CFI(".cfi_same_value %ebx\n\t")
689 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
690 __ASM_CFI(".cfi_same_value %ebp\n\t")
692 __ASM_GLOBAL_FUNC(call_exception_handler
,
694 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
695 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
697 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
699 "pushl 12(%ebp)\n\t" /* make any exceptions in this... */
700 "pushl %edx\n\t" /* handler be handled by... */
702 "pushl (0)\n\t" /* nested_handler (passed in edx). */
704 "movl %esp,(0)\n\t" /* push the new exception frame onto the exception stack. */
709 "movl 24(%ebp), %ecx\n\t" /* (*1) */
710 "call *%ecx\n\t" /* call handler. (*2) */
712 "movl (0), %esp\n\t" /* restore previous... (*3) */
714 "popl (0)\n\t" /* exception frame. */
715 "movl %ebp, %esp\n\t" /* restore saved stack, in case it was corrupted */
717 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
718 __ASM_CFI(".cfi_same_value %ebp\n\t")
719 "ret $20" ) /* (*4) */
721 #endif /* __i386__ */