2 * NT exception handling routines
4 * Copyright 1999 Turchanov Sergey
5 * Copyright 1999 Alexandre Julliard
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
34 #include "wine/exception.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
38 #include "ntdll_misc.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
45 PVECTORED_EXCEPTION_HANDLER func
;
49 static struct list vectored_exception_handlers
= LIST_INIT(vectored_exception_handlers
);
50 static struct list vectored_continue_handlers
= LIST_INIT(vectored_continue_handlers
);
52 static RTL_CRITICAL_SECTION vectored_handlers_section
;
53 static RTL_CRITICAL_SECTION_DEBUG critsect_debug
=
55 0, 0, &vectored_handlers_section
,
56 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
57 0, 0, { (DWORD_PTR
)(__FILE__
": vectored_handlers_section") }
59 static RTL_CRITICAL_SECTION vectored_handlers_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
61 static PRTL_EXCEPTION_FILTER unhandled_exception_filter
;
63 const char *debugstr_exception_code( DWORD code
)
67 case CONTROL_C_EXIT
: return "CONTROL_C_EXIT";
68 case DBG_CONTROL_C
: return "DBG_CONTROL_C";
69 case DBG_PRINTEXCEPTION_C
: return "DBG_PRINTEXCEPTION_C";
70 case DBG_PRINTEXCEPTION_WIDE_C
: return "DBG_PRINTEXCEPTION_WIDE_C";
71 case EXCEPTION_ACCESS_VIOLATION
: return "EXCEPTION_ACCESS_VIOLATION";
72 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
73 case EXCEPTION_BREAKPOINT
: return "EXCEPTION_BREAKPOINT";
74 case EXCEPTION_DATATYPE_MISALIGNMENT
: return "EXCEPTION_DATATYPE_MISALIGNMENT";
75 case EXCEPTION_FLT_DENORMAL_OPERAND
: return "EXCEPTION_FLT_DENORMAL_OPERAND";
76 case EXCEPTION_FLT_DIVIDE_BY_ZERO
: return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
77 case EXCEPTION_FLT_INEXACT_RESULT
: return "EXCEPTION_FLT_INEXACT_RESULT";
78 case EXCEPTION_FLT_INVALID_OPERATION
: return "EXCEPTION_FLT_INVALID_OPERATION";
79 case EXCEPTION_FLT_OVERFLOW
: return "EXCEPTION_FLT_OVERFLOW";
80 case EXCEPTION_FLT_STACK_CHECK
: return "EXCEPTION_FLT_STACK_CHECK";
81 case EXCEPTION_FLT_UNDERFLOW
: return "EXCEPTION_FLT_UNDERFLOW";
82 case EXCEPTION_GUARD_PAGE
: return "EXCEPTION_GUARD_PAGE";
83 case EXCEPTION_ILLEGAL_INSTRUCTION
: return "EXCEPTION_ILLEGAL_INSTRUCTION";
84 case EXCEPTION_IN_PAGE_ERROR
: return "EXCEPTION_IN_PAGE_ERROR";
85 case EXCEPTION_INT_DIVIDE_BY_ZERO
: return "EXCEPTION_INT_DIVIDE_BY_ZERO";
86 case EXCEPTION_INT_OVERFLOW
: return "EXCEPTION_INT_OVERFLOW";
87 case EXCEPTION_INVALID_DISPOSITION
: return "EXCEPTION_INVALID_DISPOSITION";
88 case EXCEPTION_INVALID_HANDLE
: return "EXCEPTION_INVALID_HANDLE";
89 case EXCEPTION_NONCONTINUABLE_EXCEPTION
: return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
90 case EXCEPTION_PRIV_INSTRUCTION
: return "EXCEPTION_PRIV_INSTRUCTION";
91 case EXCEPTION_SINGLE_STEP
: return "EXCEPTION_SINGLE_STEP";
92 case EXCEPTION_STACK_OVERFLOW
: return "EXCEPTION_STACK_OVERFLOW";
93 case EXCEPTION_WINE_ASSERTION
: return "EXCEPTION_WINE_ASSERTION";
94 case EXCEPTION_WINE_CXX_EXCEPTION
: return "EXCEPTION_WINE_CXX_EXCEPTION";
95 case EXCEPTION_WINE_NAME_THREAD
: return "EXCEPTION_WINE_NAME_THREAD";
96 case EXCEPTION_WINE_STUB
: return "EXCEPTION_WINE_STUB";
102 static VECTORED_HANDLER
*add_vectored_handler( struct list
*handler_list
, ULONG first
,
103 PVECTORED_EXCEPTION_HANDLER func
)
105 VECTORED_HANDLER
*handler
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler
) );
108 handler
->func
= RtlEncodePointer( func
);
110 RtlEnterCriticalSection( &vectored_handlers_section
);
111 if (first
) list_add_head( handler_list
, &handler
->entry
);
112 else list_add_tail( handler_list
, &handler
->entry
);
113 RtlLeaveCriticalSection( &vectored_handlers_section
);
119 static ULONG
remove_vectored_handler( struct list
*handler_list
, VECTORED_HANDLER
*handler
)
124 RtlEnterCriticalSection( &vectored_handlers_section
);
125 LIST_FOR_EACH( ptr
, handler_list
)
127 VECTORED_HANDLER
*curr_handler
= LIST_ENTRY( ptr
, VECTORED_HANDLER
, entry
);
128 if (curr_handler
== handler
)
130 if (!--curr_handler
->count
) list_remove( ptr
);
131 else handler
= NULL
; /* don't free it yet */
136 RtlLeaveCriticalSection( &vectored_handlers_section
);
137 if (ret
) RtlFreeHeap( GetProcessHeap(), 0, handler
);
142 /**********************************************************************
143 * call_vectored_handlers
145 * Call the vectored handlers chain.
147 LONG
call_vectored_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
150 LONG ret
= EXCEPTION_CONTINUE_SEARCH
;
151 EXCEPTION_POINTERS except_ptrs
;
152 PVECTORED_EXCEPTION_HANDLER func
;
153 VECTORED_HANDLER
*handler
, *to_free
= NULL
;
155 except_ptrs
.ExceptionRecord
= rec
;
156 except_ptrs
.ContextRecord
= context
;
158 RtlEnterCriticalSection( &vectored_handlers_section
);
159 ptr
= list_head( &vectored_exception_handlers
);
162 handler
= LIST_ENTRY( ptr
, VECTORED_HANDLER
, entry
);
164 func
= RtlDecodePointer( handler
->func
);
165 RtlLeaveCriticalSection( &vectored_handlers_section
);
166 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
169 TRACE( "calling handler at %p code=%x flags=%x\n",
170 func
, rec
->ExceptionCode
, rec
->ExceptionFlags
);
171 ret
= func( &except_ptrs
);
172 TRACE( "handler at %p returned %x\n", func
, ret
);
174 RtlEnterCriticalSection( &vectored_handlers_section
);
175 ptr
= list_next( &vectored_exception_handlers
, ptr
);
176 if (!--handler
->count
) /* removed during execution */
178 list_remove( &handler
->entry
);
181 if (ret
== EXCEPTION_CONTINUE_EXECUTION
) break;
183 RtlLeaveCriticalSection( &vectored_handlers_section
);
184 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
189 /*******************************************************************
192 * Implementation of RtlRaiseStatus with a specific exception record.
194 void raise_status( NTSTATUS status
, EXCEPTION_RECORD
*rec
)
196 EXCEPTION_RECORD ExceptionRec
;
198 ExceptionRec
.ExceptionCode
= status
;
199 ExceptionRec
.ExceptionFlags
= EH_NONCONTINUABLE
;
200 ExceptionRec
.ExceptionRecord
= rec
;
201 ExceptionRec
.NumberParameters
= 0;
202 for (;;) RtlRaiseException( &ExceptionRec
); /* never returns */
206 /***********************************************************************
207 * RtlRaiseStatus (NTDLL.@)
209 * Raise an exception with ExceptionCode = status
211 void WINAPI
RtlRaiseStatus( NTSTATUS status
)
213 raise_status( status
, NULL
);
217 /*******************************************************************
218 * KiRaiseUserExceptionDispatcher (NTDLL.@)
220 NTSTATUS WINAPI
KiRaiseUserExceptionDispatcher(void)
222 DWORD code
= NtCurrentTeb()->ExceptionCode
;
223 EXCEPTION_RECORD rec
= { code
};
224 RtlRaiseException( &rec
);
229 /*******************************************************************
230 * RtlAddVectoredContinueHandler (NTDLL.@)
232 PVOID WINAPI
RtlAddVectoredContinueHandler( ULONG first
, PVECTORED_EXCEPTION_HANDLER func
)
234 return add_vectored_handler( &vectored_continue_handlers
, first
, func
);
238 /*******************************************************************
239 * RtlRemoveVectoredContinueHandler (NTDLL.@)
241 ULONG WINAPI
RtlRemoveVectoredContinueHandler( PVOID handler
)
243 return remove_vectored_handler( &vectored_continue_handlers
, handler
);
247 /*******************************************************************
248 * RtlAddVectoredExceptionHandler (NTDLL.@)
250 PVOID WINAPI DECLSPEC_HOTPATCH
RtlAddVectoredExceptionHandler( ULONG first
, PVECTORED_EXCEPTION_HANDLER func
)
252 return add_vectored_handler( &vectored_exception_handlers
, first
, func
);
256 /*******************************************************************
257 * RtlRemoveVectoredExceptionHandler (NTDLL.@)
259 ULONG WINAPI
RtlRemoveVectoredExceptionHandler( PVOID handler
)
261 return remove_vectored_handler( &vectored_exception_handlers
, handler
);
265 /*******************************************************************
266 * RtlSetUnhandledExceptionFilter (NTDLL.@)
268 void WINAPI
RtlSetUnhandledExceptionFilter( PRTL_EXCEPTION_FILTER filter
)
270 unhandled_exception_filter
= filter
;
274 /*******************************************************************
275 * call_unhandled_exception_filter
277 LONG WINAPI
call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr
)
279 if (!unhandled_exception_filter
) return EXCEPTION_CONTINUE_SEARCH
;
280 return unhandled_exception_filter( eptr
);
284 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
286 struct dynamic_unwind_entry
291 RUNTIME_FUNCTION
*table
;
294 PGET_RUNTIME_FUNCTION_CALLBACK callback
;
298 static struct list dynamic_unwind_list
= LIST_INIT(dynamic_unwind_list
);
300 static RTL_CRITICAL_SECTION dynamic_unwind_section
;
301 static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug
=
303 0, 0, &dynamic_unwind_section
,
304 { &dynamic_unwind_debug
.ProcessLocksList
, &dynamic_unwind_debug
.ProcessLocksList
},
305 0, 0, { (DWORD_PTR
)(__FILE__
": dynamic_unwind_section") }
307 static RTL_CRITICAL_SECTION dynamic_unwind_section
= { &dynamic_unwind_debug
, -1, 0, 0, 0, 0 };
309 static ULONG_PTR
get_runtime_function_end( RUNTIME_FUNCTION
*func
, ULONG_PTR addr
)
312 return func
->EndAddress
;
313 #elif defined(__arm__)
314 if (func
->u
.s
.Flag
) return func
->BeginAddress
+ func
->u
.s
.FunctionLength
* 2;
319 DWORD function_length
: 18;
326 } *info
= (struct unwind_info
*)(addr
+ func
->u
.UnwindData
);
327 return func
->BeginAddress
+ info
->function_length
* 2;
329 #else /* __aarch64__ */
330 if (func
->u
.s
.Flag
) return func
->BeginAddress
+ func
->u
.s
.FunctionLength
* 4;
335 DWORD function_length
: 18;
341 } *info
= (struct unwind_info
*)(addr
+ func
->u
.UnwindData
);
342 return func
->BeginAddress
+ info
->function_length
* 4;
347 /**********************************************************************
348 * RtlAddFunctionTable (NTDLL.@)
350 BOOLEAN CDECL
RtlAddFunctionTable( RUNTIME_FUNCTION
*table
, DWORD count
, ULONG_PTR addr
)
352 struct dynamic_unwind_entry
*entry
;
354 TRACE( "%p %u %lx\n", table
, count
, addr
);
356 /* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
358 entry
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry
) );
363 entry
->end
= addr
+ (count
? get_runtime_function_end( &table
[count
- 1], addr
) : 0);
364 entry
->table
= table
;
365 entry
->count
= count
;
366 entry
->max_count
= 0;
367 entry
->callback
= NULL
;
368 entry
->context
= NULL
;
370 RtlEnterCriticalSection( &dynamic_unwind_section
);
371 list_add_tail( &dynamic_unwind_list
, &entry
->entry
);
372 RtlLeaveCriticalSection( &dynamic_unwind_section
);
377 /**********************************************************************
378 * RtlInstallFunctionTableCallback (NTDLL.@)
380 BOOLEAN CDECL
RtlInstallFunctionTableCallback( ULONG_PTR table
, ULONG_PTR base
, DWORD length
,
381 PGET_RUNTIME_FUNCTION_CALLBACK callback
, PVOID context
,
384 struct dynamic_unwind_entry
*entry
;
386 TRACE( "%lx %lx %d %p %p %s\n", table
, base
, length
, callback
, context
, wine_dbgstr_w(dll
) );
388 /* NOTE: Windows doesn't check if the provided callback is a NULL pointer */
390 /* both low-order bits must be set */
391 if ((table
& 0x3) != 0x3)
394 entry
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry
) );
399 entry
->end
= base
+ length
;
400 entry
->table
= (RUNTIME_FUNCTION
*)table
;
402 entry
->max_count
= 0;
403 entry
->callback
= callback
;
404 entry
->context
= context
;
406 RtlEnterCriticalSection( &dynamic_unwind_section
);
407 list_add_tail( &dynamic_unwind_list
, &entry
->entry
);
408 RtlLeaveCriticalSection( &dynamic_unwind_section
);
414 /*************************************************************************
415 * RtlAddGrowableFunctionTable (NTDLL.@)
417 DWORD WINAPI
RtlAddGrowableFunctionTable( void **table
, RUNTIME_FUNCTION
*functions
, DWORD count
,
418 DWORD max_count
, ULONG_PTR base
, ULONG_PTR end
)
420 struct dynamic_unwind_entry
*entry
;
422 TRACE( "%p, %p, %u, %u, %lx, %lx\n", table
, functions
, count
, max_count
, base
, end
);
424 entry
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry
) );
426 return STATUS_NO_MEMORY
;
430 entry
->table
= functions
;
431 entry
->count
= count
;
432 entry
->max_count
= max_count
;
433 entry
->callback
= NULL
;
434 entry
->context
= NULL
;
436 RtlEnterCriticalSection( &dynamic_unwind_section
);
437 list_add_tail( &dynamic_unwind_list
, &entry
->entry
);
438 RtlLeaveCriticalSection( &dynamic_unwind_section
);
442 return STATUS_SUCCESS
;
446 /*************************************************************************
447 * RtlGrowFunctionTable (NTDLL.@)
449 void WINAPI
RtlGrowFunctionTable( void *table
, DWORD count
)
451 struct dynamic_unwind_entry
*entry
;
453 TRACE( "%p, %u\n", table
, count
);
455 RtlEnterCriticalSection( &dynamic_unwind_section
);
456 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
460 if (count
> entry
->count
&& count
<= entry
->max_count
)
461 entry
->count
= count
;
465 RtlLeaveCriticalSection( &dynamic_unwind_section
);
469 /*************************************************************************
470 * RtlDeleteGrowableFunctionTable (NTDLL.@)
472 void WINAPI
RtlDeleteGrowableFunctionTable( void *table
)
474 struct dynamic_unwind_entry
*entry
, *to_free
= NULL
;
476 TRACE( "%p\n", table
);
478 RtlEnterCriticalSection( &dynamic_unwind_section
);
479 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
484 list_remove( &entry
->entry
);
488 RtlLeaveCriticalSection( &dynamic_unwind_section
);
490 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
494 /**********************************************************************
495 * RtlDeleteFunctionTable (NTDLL.@)
497 BOOLEAN CDECL
RtlDeleteFunctionTable( RUNTIME_FUNCTION
*table
)
499 struct dynamic_unwind_entry
*entry
, *to_free
= NULL
;
501 TRACE( "%p\n", table
);
503 RtlEnterCriticalSection( &dynamic_unwind_section
);
504 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
506 if (entry
->table
== table
)
509 list_remove( &entry
->entry
);
513 RtlLeaveCriticalSection( &dynamic_unwind_section
);
515 if (!to_free
) return FALSE
;
517 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
522 /* helper for lookup_function_info() */
523 static RUNTIME_FUNCTION
*find_function_info( ULONG_PTR pc
, ULONG_PTR base
,
524 RUNTIME_FUNCTION
*func
, ULONG size
)
532 int pos
= (min
+ max
) / 2;
533 if (pc
< base
+ func
[pos
].BeginAddress
) max
= pos
- 1;
534 else if (pc
>= base
+ func
[pos
].EndAddress
) min
= pos
+ 1;
538 while (func
->UnwindData
& 1) /* follow chained entry */
539 func
= (RUNTIME_FUNCTION
*)(base
+ (func
->UnwindData
& ~1));
542 #elif defined(__arm__)
543 int pos
= (min
+ max
) / 2;
544 if (pc
< base
+ (func
[pos
].BeginAddress
& ~1)) max
= pos
- 1;
545 else if (pc
>= base
+ get_runtime_function_end( &func
[pos
], base
)) min
= pos
+ 1;
546 else return func
+ pos
;
547 #else /* __aarch64__ */
548 int pos
= (min
+ max
) / 2;
549 if (pc
< base
+ func
[pos
].BeginAddress
) max
= pos
- 1;
550 else if (pc
>= base
+ get_runtime_function_end( &func
[pos
], base
)) min
= pos
+ 1;
551 else return func
+ pos
;
557 /**********************************************************************
558 * lookup_function_info
560 RUNTIME_FUNCTION
*lookup_function_info( ULONG_PTR pc
, ULONG_PTR
*base
, LDR_DATA_TABLE_ENTRY
**module
)
562 RUNTIME_FUNCTION
*func
= NULL
;
563 struct dynamic_unwind_entry
*entry
;
566 /* PE module or wine module */
567 if (!LdrFindEntryForAddress( (void *)pc
, module
))
569 *base
= (ULONG_PTR
)(*module
)->DllBase
;
570 if ((func
= RtlImageDirectoryEntryToData( (*module
)->DllBase
, TRUE
,
571 IMAGE_DIRECTORY_ENTRY_EXCEPTION
, &size
)))
573 /* lookup in function table */
574 func
= find_function_info( pc
, (ULONG_PTR
)(*module
)->DllBase
, func
, size
/sizeof(*func
) );
581 RtlEnterCriticalSection( &dynamic_unwind_section
);
582 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
584 if (pc
>= entry
->base
&& pc
< entry
->end
)
587 /* use callback or lookup in function table */
589 func
= entry
->callback( pc
, entry
->context
);
591 func
= find_function_info( pc
, entry
->base
, entry
->table
, entry
->count
);
595 RtlLeaveCriticalSection( &dynamic_unwind_section
);
601 /**********************************************************************
602 * RtlLookupFunctionEntry (NTDLL.@)
604 PRUNTIME_FUNCTION WINAPI
RtlLookupFunctionEntry( ULONG_PTR pc
, ULONG_PTR
*base
,
605 UNWIND_HISTORY_TABLE
*table
)
607 LDR_DATA_TABLE_ENTRY
*module
;
608 RUNTIME_FUNCTION
*func
;
610 /* FIXME: should use the history table to make things faster */
612 if (!(func
= lookup_function_info( pc
, base
, &module
)))
615 WARN( "no exception table found for %lx\n", pc
);
620 #endif /* __x86_64__ || __arm__ || __aarch64__ */
623 /*************************************************************
626 void __cdecl
_assert( const char *str
, const char *file
, unsigned int line
)
628 ERR( "%s:%u: Assertion failed %s\n", file
, line
, debugstr_a(str
) );
629 RtlRaiseStatus( EXCEPTION_WINE_ASSERTION
);
633 /*************************************************************
634 * __wine_spec_unimplemented_stub
636 * ntdll-specific implementation to avoid depending on kernel functions.
637 * Can be removed once ntdll.spec no longer contains stubs.
639 void __cdecl
__wine_spec_unimplemented_stub( const char *module
, const char *function
)
641 EXCEPTION_RECORD record
;
643 record
.ExceptionCode
= EXCEPTION_WINE_STUB
;
644 record
.ExceptionFlags
= EH_NONCONTINUABLE
;
645 record
.ExceptionRecord
= NULL
;
646 record
.ExceptionAddress
= __wine_spec_unimplemented_stub
;
647 record
.NumberParameters
= 2;
648 record
.ExceptionInformation
[0] = (ULONG_PTR
)module
;
649 record
.ExceptionInformation
[1] = (ULONG_PTR
)function
;
650 for (;;) RtlRaiseException( &record
);
654 /*************************************************************
657 * IsBadStringPtrA replacement for ntdll, to catch exception in debug traces.
659 BOOL WINAPI
IsBadStringPtrA( LPCSTR str
, UINT_PTR max
)
661 if (!str
) return TRUE
;
664 volatile const char *p
= str
;
665 while (p
!= str
+ max
) if (!*p
++) break;
674 __ASM_STDCALL_IMPORT(IsBadStringPtrA
,8)
676 /*************************************************************
679 * IsBadStringPtrW replacement for ntdll, to catch exception in debug traces.
681 BOOL WINAPI
IsBadStringPtrW( LPCWSTR str
, UINT_PTR max
)
683 if (!str
) return TRUE
;
686 volatile const WCHAR
*p
= str
;
687 while (p
!= str
+ max
) if (!*p
++) break;
696 __ASM_STDCALL_IMPORT(IsBadStringPtrW
,8)
699 /**********************************************************************
700 * RtlGetEnabledExtendedFeatures (NTDLL.@)
702 ULONG64 WINAPI
RtlGetEnabledExtendedFeatures(ULONG64 feature_mask
)
704 return user_shared_data
->XState
.EnabledFeatures
& feature_mask
;
707 struct context_copy_range
713 static const struct context_copy_range copy_ranges_amd64
[] =
715 {0x38, 0x1}, {0x3a, 0x4}, { 0x42, 0x1}, { 0x48, 0x10}, { 0x78, 0x2}, { 0x98, 0x1},
716 {0xa0, 0x2}, {0xf8, 0x1}, {0x100, 0x8}, {0x2a0, 0}, {0x4b0, 0x10}, {0x4d0, 0}
719 static const struct context_copy_range copy_ranges_x86
[] =
721 { 0x4, 0x10}, {0x1c, 0x8}, {0x8c, 0x4}, {0x9c, 0x2}, {0xb4, 0x1}, {0xcc, 0x20}, {0x1ec, 0},
725 static const struct context_parameters
728 ULONG supported_flags
;
729 ULONG context_size
; /* sizeof(CONTEXT) */
730 ULONG legacy_size
; /* Legacy context size */
731 ULONG context_ex_size
; /* sizeof(CONTEXT_EX) */
732 ULONG alignment
; /* Used when computing size of context. */
733 ULONG true_alignment
; /* Used for actual alignment. */
735 const struct context_copy_range
*copy_ranges
;
737 arch_context_parameters
[] =
739 {0x00100000, 0xd810005f, 0x4d0, 0x4d0, 0x20, 7, 0xf, 0x30, copy_ranges_amd64
},
740 {0x00010000, 0xd801007f, 0x2cc, 0xcc, 0x18, 3, 0x3, 0, copy_ranges_x86
},
743 static const struct context_parameters
*context_get_parameters( ULONG context_flags
)
747 for (i
= 0; i
< ARRAY_SIZE(arch_context_parameters
); ++i
)
749 if (context_flags
& arch_context_parameters
[i
].arch_flag
)
750 return context_flags
& ~arch_context_parameters
[i
].supported_flags
? NULL
: &arch_context_parameters
[i
];
756 /**********************************************************************
757 * RtlGetExtendedContextLength2 (NTDLL.@)
759 NTSTATUS WINAPI
RtlGetExtendedContextLength2( ULONG context_flags
, ULONG
*length
, ULONG64 compaction_mask
)
761 const struct context_parameters
*p
;
762 ULONG64 supported_mask
;
765 TRACE( "context_flags %#x, length %p, compaction_mask %s.\n", context_flags
, length
,
766 wine_dbgstr_longlong(compaction_mask
) );
768 if (!(p
= context_get_parameters( context_flags
)))
769 return STATUS_INVALID_PARAMETER
;
771 if (!(context_flags
& 0x40))
773 *length
= p
->context_size
+ p
->context_ex_size
+ p
->alignment
;
774 return STATUS_SUCCESS
;
777 if (!(supported_mask
= RtlGetEnabledExtendedFeatures( ~(ULONG64
)0) ))
778 return STATUS_NOT_SUPPORTED
;
780 compaction_mask
&= supported_mask
;
782 size
= p
->context_size
+ p
->context_ex_size
+ offsetof(XSTATE
, YmmContext
) + 63;
784 if (compaction_mask
& supported_mask
& (1 << XSTATE_AVX
))
785 size
+= sizeof(YMMCONTEXT
);
788 return STATUS_SUCCESS
;
792 /**********************************************************************
793 * RtlGetExtendedContextLength (NTDLL.@)
795 NTSTATUS WINAPI
RtlGetExtendedContextLength( ULONG context_flags
, ULONG
*length
)
797 return RtlGetExtendedContextLength2( context_flags
, length
, ~(ULONG64
)0 );
801 /**********************************************************************
802 * RtlInitializeExtendedContext2 (NTDLL.@)
804 NTSTATUS WINAPI
RtlInitializeExtendedContext2( void *context
, ULONG context_flags
, CONTEXT_EX
**context_ex
,
805 ULONG64 compaction_mask
)
807 const struct context_parameters
*p
;
808 ULONG64 supported_mask
= 0;
811 TRACE( "context %p, context_flags %#x, context_ex %p, compaction_mask %s.\n",
812 context
, context_flags
, context_ex
, wine_dbgstr_longlong(compaction_mask
));
814 if (!(p
= context_get_parameters( context_flags
)))
815 return STATUS_INVALID_PARAMETER
;
817 if ((context_flags
& 0x40) && !(supported_mask
= RtlGetEnabledExtendedFeatures( ~(ULONG64
)0 )))
818 return STATUS_NOT_SUPPORTED
;
820 context
= (void *)(((ULONG_PTR
)context
+ p
->true_alignment
) & ~p
->true_alignment
);
821 *(ULONG
*)((BYTE
*)context
+ p
->flags_offset
) = context_flags
;
823 *context_ex
= c_ex
= (CONTEXT_EX
*)((BYTE
*)context
+ p
->context_size
);
824 c_ex
->Legacy
.Offset
= c_ex
->All
.Offset
= -(LONG
)p
->context_size
;
825 c_ex
->Legacy
.Length
= context_flags
& 0x20 ? p
->context_size
: p
->legacy_size
;
827 if (context_flags
& 0x40)
831 compaction_mask
&= supported_mask
;
833 xs
= (XSTATE
*)(((ULONG_PTR
)c_ex
+ p
->context_ex_size
+ 63) & ~(ULONG_PTR
)63);
835 c_ex
->XState
.Offset
= (ULONG_PTR
)xs
- (ULONG_PTR
)c_ex
;
836 c_ex
->XState
.Length
= offsetof(XSTATE
, YmmContext
);
837 compaction_mask
&= supported_mask
;
839 if (compaction_mask
& (1 << XSTATE_AVX
))
840 c_ex
->XState
.Length
+= sizeof(YMMCONTEXT
);
842 memset( xs
, 0, c_ex
->XState
.Length
);
843 if (user_shared_data
->XState
.CompactionEnabled
)
844 xs
->CompactionMask
= ((ULONG64
)1 << 63) | compaction_mask
;
846 c_ex
->All
.Length
= p
->context_size
+ c_ex
->XState
.Offset
+ c_ex
->XState
.Length
;
850 c_ex
->XState
.Offset
= 25; /* According to the tests, it is just 25 if CONTEXT_XSTATE is not specified. */
851 c_ex
->XState
.Length
= 0;
852 c_ex
->All
.Length
= p
->context_size
+ 24; /* sizeof(CONTEXT_EX) minus 8 alignment bytes on x64. */
855 return STATUS_SUCCESS
;
859 /**********************************************************************
860 * RtlInitializeExtendedContext (NTDLL.@)
862 NTSTATUS WINAPI
RtlInitializeExtendedContext( void *context
, ULONG context_flags
, CONTEXT_EX
**context_ex
)
864 return RtlInitializeExtendedContext2( context
, context_flags
, context_ex
, ~(ULONG64
)0 );
868 /**********************************************************************
869 * RtlLocateExtendedFeature2 (NTDLL.@)
871 void * WINAPI
RtlLocateExtendedFeature2( CONTEXT_EX
*context_ex
, ULONG feature_id
,
872 XSTATE_CONFIGURATION
*xstate_config
, ULONG
*length
)
874 TRACE( "context_ex %p, feature_id %u, xstate_config %p, length %p.\n",
875 context_ex
, feature_id
, xstate_config
, length
);
879 FIXME( "NULL xstate_config.\n" );
883 if (xstate_config
!= &user_shared_data
->XState
)
885 FIXME( "Custom xstate configuration is not supported.\n" );
889 if (feature_id
!= XSTATE_AVX
)
893 *length
= sizeof(YMMCONTEXT
);
895 if (context_ex
->XState
.Length
< sizeof(XSTATE
))
898 return (BYTE
*)context_ex
+ context_ex
->XState
.Offset
+ offsetof(XSTATE
, YmmContext
);
902 /**********************************************************************
903 * RtlLocateExtendedFeature (NTDLL.@)
905 void * WINAPI
RtlLocateExtendedFeature( CONTEXT_EX
*context_ex
, ULONG feature_id
,
908 return RtlLocateExtendedFeature2( context_ex
, feature_id
, &user_shared_data
->XState
, length
);
911 /**********************************************************************
912 * RtlLocateLegacyContext (NTDLL.@)
914 void * WINAPI
RtlLocateLegacyContext( CONTEXT_EX
*context_ex
, ULONG
*length
)
917 *length
= context_ex
->Legacy
.Length
;
919 return (BYTE
*)context_ex
+ context_ex
->Legacy
.Offset
;
922 /**********************************************************************
923 * RtlSetExtendedFeaturesMask (NTDLL.@)
925 void WINAPI
RtlSetExtendedFeaturesMask( CONTEXT_EX
*context_ex
, ULONG64 feature_mask
)
927 XSTATE
*xs
= (XSTATE
*)((BYTE
*)context_ex
+ context_ex
->XState
.Offset
);
929 xs
->Mask
= RtlGetEnabledExtendedFeatures( feature_mask
) & ~(ULONG64
)3;
933 /**********************************************************************
934 * RtlGetExtendedFeaturesMask (NTDLL.@)
936 ULONG64 WINAPI
RtlGetExtendedFeaturesMask( CONTEXT_EX
*context_ex
)
938 XSTATE
*xs
= (XSTATE
*)((BYTE
*)context_ex
+ context_ex
->XState
.Offset
);
940 return xs
->Mask
& ~(ULONG64
)3;
944 /**********************************************************************
945 * RtlCopyExtendedContext (NTDLL.@)
947 NTSTATUS WINAPI
RtlCopyExtendedContext( CONTEXT_EX
*dst
, ULONG context_flags
, CONTEXT_EX
*src
)
949 const struct context_copy_range
*range
;
950 const struct context_parameters
*p
;
951 XSTATE
*dst_xs
, *src_xs
;
952 ULONG64 feature_mask
;
956 TRACE( "dst %p, context_flags %#x, src %p.\n", dst
, context_flags
, src
);
958 if (!(p
= context_get_parameters( context_flags
)))
959 return STATUS_INVALID_PARAMETER
;
961 if (!(feature_mask
= RtlGetEnabledExtendedFeatures( ~(ULONG64
)0 )) && context_flags
& 0x40)
962 return STATUS_NOT_SUPPORTED
;
964 d
= RtlLocateLegacyContext( dst
, NULL
);
965 s
= RtlLocateLegacyContext( src
, NULL
);
967 *((ULONG
*)(d
+ p
->flags_offset
)) |= context_flags
;
970 range
= p
->copy_ranges
;
973 if (range
->flag
& context_flags
)
976 start
= range
->start
;
980 memcpy( d
+ start
, s
+ start
, range
->start
- start
);
984 while (range
++->start
!= p
->context_size
);
986 if (!(context_flags
& 0x40))
987 return STATUS_SUCCESS
;
989 if (dst
->XState
.Length
< offsetof(XSTATE
, YmmContext
))
990 return STATUS_BUFFER_OVERFLOW
;
992 dst_xs
= (XSTATE
*)((BYTE
*)dst
+ dst
->XState
.Offset
);
993 src_xs
= (XSTATE
*)((BYTE
*)src
+ src
->XState
.Offset
);
995 memset(dst_xs
, 0, offsetof(XSTATE
, YmmContext
));
996 dst_xs
->Mask
= (src_xs
->Mask
& ~(ULONG64
)3) & feature_mask
;
997 dst_xs
->CompactionMask
= user_shared_data
->XState
.CompactionEnabled
998 ? ((ULONG64
)1 << 63) | (src_xs
->CompactionMask
& feature_mask
) : 0;
1000 if (dst_xs
->Mask
& 4 && src
->XState
.Length
>= sizeof(XSTATE
) && dst
->XState
.Length
>= sizeof(XSTATE
))
1001 memcpy( &dst_xs
->YmmContext
, &src_xs
->YmmContext
, sizeof(dst_xs
->YmmContext
) );
1002 return STATUS_SUCCESS
;