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/server.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
39 #include "ntdll_misc.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
46 PVECTORED_EXCEPTION_HANDLER func
;
50 static struct list vectored_exception_handlers
= LIST_INIT(vectored_exception_handlers
);
51 static struct list vectored_continue_handlers
= LIST_INIT(vectored_continue_handlers
);
53 static RTL_CRITICAL_SECTION vectored_handlers_section
;
54 static RTL_CRITICAL_SECTION_DEBUG critsect_debug
=
56 0, 0, &vectored_handlers_section
,
57 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
58 0, 0, { (DWORD_PTR
)(__FILE__
": vectored_handlers_section") }
60 static RTL_CRITICAL_SECTION vectored_handlers_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
62 static PRTL_EXCEPTION_FILTER unhandled_exception_filter
;
65 static VECTORED_HANDLER
*add_vectored_handler( struct list
*handler_list
, ULONG first
,
66 PVECTORED_EXCEPTION_HANDLER func
)
68 VECTORED_HANDLER
*handler
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler
) );
71 handler
->func
= RtlEncodePointer( func
);
73 RtlEnterCriticalSection( &vectored_handlers_section
);
74 if (first
) list_add_head( handler_list
, &handler
->entry
);
75 else list_add_tail( handler_list
, &handler
->entry
);
76 RtlLeaveCriticalSection( &vectored_handlers_section
);
82 static ULONG
remove_vectored_handler( struct list
*handler_list
, VECTORED_HANDLER
*handler
)
87 RtlEnterCriticalSection( &vectored_handlers_section
);
88 LIST_FOR_EACH( ptr
, handler_list
)
90 VECTORED_HANDLER
*curr_handler
= LIST_ENTRY( ptr
, VECTORED_HANDLER
, entry
);
91 if (curr_handler
== handler
)
93 if (!--curr_handler
->count
) list_remove( ptr
);
94 else handler
= NULL
; /* don't free it yet */
99 RtlLeaveCriticalSection( &vectored_handlers_section
);
100 if (ret
) RtlFreeHeap( GetProcessHeap(), 0, handler
);
105 /**********************************************************************
106 * call_vectored_handlers
108 * Call the vectored handlers chain.
110 LONG
call_vectored_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
113 LONG ret
= EXCEPTION_CONTINUE_SEARCH
;
114 EXCEPTION_POINTERS except_ptrs
;
115 PVECTORED_EXCEPTION_HANDLER func
;
116 VECTORED_HANDLER
*handler
, *to_free
= NULL
;
118 except_ptrs
.ExceptionRecord
= rec
;
119 except_ptrs
.ContextRecord
= context
;
121 RtlEnterCriticalSection( &vectored_handlers_section
);
122 ptr
= list_head( &vectored_exception_handlers
);
125 handler
= LIST_ENTRY( ptr
, VECTORED_HANDLER
, entry
);
127 func
= RtlDecodePointer( handler
->func
);
128 RtlLeaveCriticalSection( &vectored_handlers_section
);
129 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
132 TRACE( "calling handler at %p code=%x flags=%x\n",
133 func
, rec
->ExceptionCode
, rec
->ExceptionFlags
);
134 ret
= func( &except_ptrs
);
135 TRACE( "handler at %p returned %x\n", func
, ret
);
137 RtlEnterCriticalSection( &vectored_handlers_section
);
138 ptr
= list_next( &vectored_exception_handlers
, ptr
);
139 if (!--handler
->count
) /* removed during execution */
141 list_remove( &handler
->entry
);
144 if (ret
== EXCEPTION_CONTINUE_EXECUTION
) break;
146 RtlLeaveCriticalSection( &vectored_handlers_section
);
147 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
152 /*******************************************************************
155 * Implementation of RtlRaiseStatus with a specific exception record.
157 void raise_status( NTSTATUS status
, EXCEPTION_RECORD
*rec
)
159 EXCEPTION_RECORD ExceptionRec
;
161 ExceptionRec
.ExceptionCode
= status
;
162 ExceptionRec
.ExceptionFlags
= EH_NONCONTINUABLE
;
163 ExceptionRec
.ExceptionRecord
= rec
;
164 ExceptionRec
.NumberParameters
= 0;
165 for (;;) RtlRaiseException( &ExceptionRec
); /* never returns */
169 /***********************************************************************
170 * RtlRaiseStatus (NTDLL.@)
172 * Raise an exception with ExceptionCode = status
174 void WINAPI
RtlRaiseStatus( NTSTATUS status
)
176 raise_status( status
, NULL
);
180 /*******************************************************************
181 * KiRaiseUserExceptionDispatcher (NTDLL.@)
183 NTSTATUS WINAPI
KiRaiseUserExceptionDispatcher(void)
185 DWORD code
= NtCurrentTeb()->ExceptionCode
;
186 EXCEPTION_RECORD rec
= { code
};
187 RtlRaiseException( &rec
);
192 /*******************************************************************
193 * RtlAddVectoredContinueHandler (NTDLL.@)
195 PVOID WINAPI
RtlAddVectoredContinueHandler( ULONG first
, PVECTORED_EXCEPTION_HANDLER func
)
197 return add_vectored_handler( &vectored_continue_handlers
, first
, func
);
201 /*******************************************************************
202 * RtlRemoveVectoredContinueHandler (NTDLL.@)
204 ULONG WINAPI
RtlRemoveVectoredContinueHandler( PVOID handler
)
206 return remove_vectored_handler( &vectored_continue_handlers
, handler
);
210 /*******************************************************************
211 * RtlAddVectoredExceptionHandler (NTDLL.@)
213 PVOID WINAPI DECLSPEC_HOTPATCH
RtlAddVectoredExceptionHandler( ULONG first
, PVECTORED_EXCEPTION_HANDLER func
)
215 return add_vectored_handler( &vectored_exception_handlers
, first
, func
);
219 /*******************************************************************
220 * RtlRemoveVectoredExceptionHandler (NTDLL.@)
222 ULONG WINAPI
RtlRemoveVectoredExceptionHandler( PVOID handler
)
224 return remove_vectored_handler( &vectored_exception_handlers
, handler
);
228 /*******************************************************************
229 * RtlSetUnhandledExceptionFilter (NTDLL.@)
231 void WINAPI
RtlSetUnhandledExceptionFilter( PRTL_EXCEPTION_FILTER filter
)
233 unhandled_exception_filter
= filter
;
237 /*******************************************************************
238 * call_unhandled_exception_filter
240 LONG WINAPI
call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr
)
242 if (!unhandled_exception_filter
) return EXCEPTION_CONTINUE_SEARCH
;
243 return unhandled_exception_filter( eptr
);
247 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
249 struct dynamic_unwind_entry
254 RUNTIME_FUNCTION
*table
;
257 PGET_RUNTIME_FUNCTION_CALLBACK callback
;
261 static struct list dynamic_unwind_list
= LIST_INIT(dynamic_unwind_list
);
263 static RTL_CRITICAL_SECTION dynamic_unwind_section
;
264 static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug
=
266 0, 0, &dynamic_unwind_section
,
267 { &dynamic_unwind_debug
.ProcessLocksList
, &dynamic_unwind_debug
.ProcessLocksList
},
268 0, 0, { (DWORD_PTR
)(__FILE__
": dynamic_unwind_section") }
270 static RTL_CRITICAL_SECTION dynamic_unwind_section
= { &dynamic_unwind_debug
, -1, 0, 0, 0, 0 };
272 static ULONG_PTR
get_runtime_function_end( RUNTIME_FUNCTION
*func
, ULONG_PTR addr
)
275 return func
->EndAddress
;
276 #elif defined(__arm__)
277 if (func
->u
.s
.Flag
) return func
->BeginAddress
+ func
->u
.s
.FunctionLength
* 2;
282 DWORD function_length
: 18;
289 } *info
= (struct unwind_info
*)(addr
+ func
->u
.UnwindData
);
290 return func
->BeginAddress
+ info
->function_length
* 2;
292 #else /* __aarch64__ */
293 if (func
->u
.s
.Flag
) return func
->BeginAddress
+ func
->u
.s
.FunctionLength
* 4;
298 DWORD function_length
: 18;
304 } *info
= (struct unwind_info
*)(addr
+ func
->u
.UnwindData
);
305 return func
->BeginAddress
+ info
->function_length
* 4;
310 /**********************************************************************
311 * RtlAddFunctionTable (NTDLL.@)
313 BOOLEAN CDECL
RtlAddFunctionTable( RUNTIME_FUNCTION
*table
, DWORD count
, ULONG_PTR addr
)
315 struct dynamic_unwind_entry
*entry
;
317 TRACE( "%p %u %lx\n", table
, count
, addr
);
319 /* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
321 entry
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry
) );
326 entry
->end
= addr
+ (count
? get_runtime_function_end( &table
[count
- 1], addr
) : 0);
327 entry
->table
= table
;
328 entry
->count
= count
;
329 entry
->max_count
= 0;
330 entry
->callback
= NULL
;
331 entry
->context
= NULL
;
333 RtlEnterCriticalSection( &dynamic_unwind_section
);
334 list_add_tail( &dynamic_unwind_list
, &entry
->entry
);
335 RtlLeaveCriticalSection( &dynamic_unwind_section
);
340 /**********************************************************************
341 * RtlInstallFunctionTableCallback (NTDLL.@)
343 BOOLEAN CDECL
RtlInstallFunctionTableCallback( ULONG_PTR table
, ULONG_PTR base
, DWORD length
,
344 PGET_RUNTIME_FUNCTION_CALLBACK callback
, PVOID context
,
347 struct dynamic_unwind_entry
*entry
;
349 TRACE( "%lx %lx %d %p %p %s\n", table
, base
, length
, callback
, context
, wine_dbgstr_w(dll
) );
351 /* NOTE: Windows doesn't check if the provided callback is a NULL pointer */
353 /* both low-order bits must be set */
354 if ((table
& 0x3) != 0x3)
357 entry
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry
) );
362 entry
->end
= base
+ length
;
363 entry
->table
= (RUNTIME_FUNCTION
*)table
;
365 entry
->max_count
= 0;
366 entry
->callback
= callback
;
367 entry
->context
= context
;
369 RtlEnterCriticalSection( &dynamic_unwind_section
);
370 list_add_tail( &dynamic_unwind_list
, &entry
->entry
);
371 RtlLeaveCriticalSection( &dynamic_unwind_section
);
377 /*************************************************************************
378 * RtlAddGrowableFunctionTable (NTDLL.@)
380 DWORD WINAPI
RtlAddGrowableFunctionTable( void **table
, RUNTIME_FUNCTION
*functions
, DWORD count
,
381 DWORD max_count
, ULONG_PTR base
, ULONG_PTR end
)
383 struct dynamic_unwind_entry
*entry
;
385 TRACE( "%p, %p, %u, %u, %lx, %lx\n", table
, functions
, count
, max_count
, base
, end
);
387 entry
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry
) );
389 return STATUS_NO_MEMORY
;
393 entry
->table
= functions
;
394 entry
->count
= count
;
395 entry
->max_count
= max_count
;
396 entry
->callback
= NULL
;
397 entry
->context
= NULL
;
399 RtlEnterCriticalSection( &dynamic_unwind_section
);
400 list_add_tail( &dynamic_unwind_list
, &entry
->entry
);
401 RtlLeaveCriticalSection( &dynamic_unwind_section
);
405 return STATUS_SUCCESS
;
409 /*************************************************************************
410 * RtlGrowFunctionTable (NTDLL.@)
412 void WINAPI
RtlGrowFunctionTable( void *table
, DWORD count
)
414 struct dynamic_unwind_entry
*entry
;
416 TRACE( "%p, %u\n", table
, count
);
418 RtlEnterCriticalSection( &dynamic_unwind_section
);
419 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
423 if (count
> entry
->count
&& count
<= entry
->max_count
)
424 entry
->count
= count
;
428 RtlLeaveCriticalSection( &dynamic_unwind_section
);
432 /*************************************************************************
433 * RtlDeleteGrowableFunctionTable (NTDLL.@)
435 void WINAPI
RtlDeleteGrowableFunctionTable( void *table
)
437 struct dynamic_unwind_entry
*entry
, *to_free
= NULL
;
439 TRACE( "%p\n", table
);
441 RtlEnterCriticalSection( &dynamic_unwind_section
);
442 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
447 list_remove( &entry
->entry
);
451 RtlLeaveCriticalSection( &dynamic_unwind_section
);
453 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
457 /**********************************************************************
458 * RtlDeleteFunctionTable (NTDLL.@)
460 BOOLEAN CDECL
RtlDeleteFunctionTable( RUNTIME_FUNCTION
*table
)
462 struct dynamic_unwind_entry
*entry
, *to_free
= NULL
;
464 TRACE( "%p\n", table
);
466 RtlEnterCriticalSection( &dynamic_unwind_section
);
467 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
469 if (entry
->table
== table
)
472 list_remove( &entry
->entry
);
476 RtlLeaveCriticalSection( &dynamic_unwind_section
);
478 if (!to_free
) return FALSE
;
480 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
485 /* helper for lookup_function_info() */
486 static RUNTIME_FUNCTION
*find_function_info( ULONG_PTR pc
, ULONG_PTR base
,
487 RUNTIME_FUNCTION
*func
, ULONG size
)
495 int pos
= (min
+ max
) / 2;
496 if (pc
< base
+ func
[pos
].BeginAddress
) max
= pos
- 1;
497 else if (pc
>= base
+ func
[pos
].EndAddress
) min
= pos
+ 1;
501 while (func
->UnwindData
& 1) /* follow chained entry */
502 func
= (RUNTIME_FUNCTION
*)(base
+ (func
->UnwindData
& ~1));
505 #elif defined(__arm__)
506 int pos
= (min
+ max
) / 2;
507 if (pc
< base
+ (func
[pos
].BeginAddress
& ~1)) max
= pos
- 1;
508 else if (pc
>= base
+ get_runtime_function_end( &func
[pos
], base
)) min
= pos
+ 1;
509 else return func
+ pos
;
510 #else /* __aarch64__ */
511 int pos
= (min
+ max
) / 2;
512 if (pc
< base
+ func
[pos
].BeginAddress
) max
= pos
- 1;
513 else if (pc
>= base
+ get_runtime_function_end( &func
[pos
], base
)) min
= pos
+ 1;
514 else return func
+ pos
;
520 /**********************************************************************
521 * lookup_function_info
523 RUNTIME_FUNCTION
*lookup_function_info( ULONG_PTR pc
, ULONG_PTR
*base
, LDR_DATA_TABLE_ENTRY
**module
)
525 RUNTIME_FUNCTION
*func
= NULL
;
526 struct dynamic_unwind_entry
*entry
;
529 /* PE module or wine module */
530 if (!LdrFindEntryForAddress( (void *)pc
, module
))
532 *base
= (ULONG_PTR
)(*module
)->DllBase
;
533 if ((func
= RtlImageDirectoryEntryToData( (*module
)->DllBase
, TRUE
,
534 IMAGE_DIRECTORY_ENTRY_EXCEPTION
, &size
)))
536 /* lookup in function table */
537 func
= find_function_info( pc
, (ULONG_PTR
)(*module
)->DllBase
, func
, size
/sizeof(*func
) );
544 RtlEnterCriticalSection( &dynamic_unwind_section
);
545 LIST_FOR_EACH_ENTRY( entry
, &dynamic_unwind_list
, struct dynamic_unwind_entry
, entry
)
547 if (pc
>= entry
->base
&& pc
< entry
->end
)
550 /* use callback or lookup in function table */
552 func
= entry
->callback( pc
, entry
->context
);
554 func
= find_function_info( pc
, entry
->base
, entry
->table
, entry
->count
);
558 RtlLeaveCriticalSection( &dynamic_unwind_section
);
564 /**********************************************************************
565 * RtlLookupFunctionEntry (NTDLL.@)
567 PRUNTIME_FUNCTION WINAPI
RtlLookupFunctionEntry( ULONG_PTR pc
, ULONG_PTR
*base
,
568 UNWIND_HISTORY_TABLE
*table
)
570 LDR_DATA_TABLE_ENTRY
*module
;
571 RUNTIME_FUNCTION
*func
;
573 /* FIXME: should use the history table to make things faster */
575 if (!(func
= lookup_function_info( pc
, base
, &module
)))
578 WARN( "no exception table found for %lx\n", pc
);
583 #endif /* __x86_64__ || __arm__ || __aarch64__ */
586 /*************************************************************
589 void __cdecl
_assert( const char *str
, const char *file
, unsigned int line
)
591 ERR( "%s:%u: Assertion failed %s\n", file
, line
, debugstr_a(str
) );
592 RtlRaiseStatus( EXCEPTION_WINE_ASSERTION
);
596 /*************************************************************
597 * __wine_spec_unimplemented_stub
599 * ntdll-specific implementation to avoid depending on kernel functions.
600 * Can be removed once ntdll.spec no longer contains stubs.
602 void __cdecl
__wine_spec_unimplemented_stub( const char *module
, const char *function
)
604 EXCEPTION_RECORD record
;
606 record
.ExceptionCode
= EXCEPTION_WINE_STUB
;
607 record
.ExceptionFlags
= EH_NONCONTINUABLE
;
608 record
.ExceptionRecord
= NULL
;
609 record
.ExceptionAddress
= __wine_spec_unimplemented_stub
;
610 record
.NumberParameters
= 2;
611 record
.ExceptionInformation
[0] = (ULONG_PTR
)module
;
612 record
.ExceptionInformation
[1] = (ULONG_PTR
)function
;
613 for (;;) RtlRaiseException( &record
);
617 /*************************************************************
620 * IsBadStringPtrA replacement for ntdll, to catch exception in debug traces.
622 BOOL WINAPI
IsBadStringPtrA( LPCSTR str
, UINT_PTR max
)
624 if (!str
) return TRUE
;
627 volatile const char *p
= str
;
628 while (p
!= str
+ max
) if (!*p
++) break;
637 __ASM_STDCALL_IMPORT(IsBadStringPtrA
,8)
639 /*************************************************************
642 * IsBadStringPtrW replacement for ntdll, to catch exception in debug traces.
644 BOOL WINAPI
IsBadStringPtrW( LPCWSTR str
, UINT_PTR max
)
646 if (!str
) return TRUE
;
649 volatile const WCHAR
*p
= str
;
650 while (p
!= str
+ max
) if (!*p
++) break;
659 __ASM_STDCALL_IMPORT(IsBadStringPtrW
,8)
662 /**********************************************************************
663 * RtlGetEnabledExtendedFeatures (NTDLL.@)
665 ULONG64 WINAPI
RtlGetEnabledExtendedFeatures(ULONG64 feature_mask
)
667 return user_shared_data
->XState
.EnabledFeatures
& feature_mask
;
670 struct context_copy_range
676 static const struct context_copy_range copy_ranges_amd64
[] =
678 {0x38, 0x1}, {0x3a, 0x4}, { 0x42, 0x1}, { 0x48, 0x10}, { 0x78, 0x2}, { 0x98, 0x1},
679 {0xa0, 0x2}, {0xf8, 0x1}, {0x100, 0x8}, {0x2a0, 0}, {0x4b0, 0x10}, {0x4d0, 0}
682 static const struct context_copy_range copy_ranges_x86
[] =
684 { 0x4, 0x10}, {0x1c, 0x8}, {0x8c, 0x4}, {0x9c, 0x2}, {0xb4, 0x1}, {0xcc, 0x20}, {0x1ec, 0},
688 static const struct context_parameters
691 ULONG supported_flags
;
692 ULONG context_size
; /* sizeof(CONTEXT) */
693 ULONG legacy_size
; /* Legacy context size */
694 ULONG context_ex_size
; /* sizeof(CONTEXT_EX) */
695 ULONG alignment
; /* Used when computing size of context. */
696 ULONG true_alignment
; /* Used for actual alignment. */
698 const struct context_copy_range
*copy_ranges
;
700 arch_context_parameters
[] =
702 {0x00100000, 0xd810005f, 0x4d0, 0x4d0, 0x20, 7, 0xf, 0x30, copy_ranges_amd64
},
703 {0x00010000, 0xd801007f, 0x2cc, 0xcc, 0x18, 3, 0x3, 0, copy_ranges_x86
},
706 static const struct context_parameters
*context_get_parameters( ULONG context_flags
)
710 for (i
= 0; i
< ARRAY_SIZE(arch_context_parameters
); ++i
)
712 if (context_flags
& arch_context_parameters
[i
].arch_flag
)
713 return context_flags
& ~arch_context_parameters
[i
].supported_flags
? NULL
: &arch_context_parameters
[i
];
719 /**********************************************************************
720 * RtlGetExtendedContextLength2 (NTDLL.@)
722 NTSTATUS WINAPI
RtlGetExtendedContextLength2( ULONG context_flags
, ULONG
*length
, ULONG64 compaction_mask
)
724 const struct context_parameters
*p
;
725 ULONG64 supported_mask
;
728 TRACE( "context_flags %#x, length %p, compaction_mask %s.\n", context_flags
, length
,
729 wine_dbgstr_longlong(compaction_mask
) );
731 if (!(p
= context_get_parameters( context_flags
)))
732 return STATUS_INVALID_PARAMETER
;
734 if (!(context_flags
& 0x40))
736 *length
= p
->context_size
+ p
->context_ex_size
+ p
->alignment
;
737 return STATUS_SUCCESS
;
740 if (!(supported_mask
= RtlGetEnabledExtendedFeatures( ~(ULONG64
)0) ))
741 return STATUS_NOT_SUPPORTED
;
743 compaction_mask
&= supported_mask
;
745 size
= p
->context_size
+ p
->context_ex_size
+ offsetof(XSTATE
, YmmContext
) + 63;
747 if (compaction_mask
& supported_mask
& (1 << XSTATE_AVX
))
748 size
+= sizeof(YMMCONTEXT
);
751 return STATUS_SUCCESS
;
755 /**********************************************************************
756 * RtlGetExtendedContextLength (NTDLL.@)
758 NTSTATUS WINAPI
RtlGetExtendedContextLength( ULONG context_flags
, ULONG
*length
)
760 return RtlGetExtendedContextLength2( context_flags
, length
, ~(ULONG64
)0 );
764 /**********************************************************************
765 * RtlInitializeExtendedContext2 (NTDLL.@)
767 NTSTATUS WINAPI
RtlInitializeExtendedContext2( void *context
, ULONG context_flags
, CONTEXT_EX
**context_ex
,
768 ULONG64 compaction_mask
)
770 const struct context_parameters
*p
;
771 ULONG64 supported_mask
= 0;
774 TRACE( "context %p, context_flags %#x, context_ex %p, compaction_mask %s.\n",
775 context
, context_flags
, context_ex
, wine_dbgstr_longlong(compaction_mask
));
777 if (!(p
= context_get_parameters( context_flags
)))
778 return STATUS_INVALID_PARAMETER
;
780 if ((context_flags
& 0x40) && !(supported_mask
= RtlGetEnabledExtendedFeatures( ~(ULONG64
)0 )))
781 return STATUS_NOT_SUPPORTED
;
783 context
= (void *)(((ULONG_PTR
)context
+ p
->true_alignment
) & ~p
->true_alignment
);
784 *(ULONG
*)((BYTE
*)context
+ p
->flags_offset
) = context_flags
;
786 *context_ex
= c_ex
= (CONTEXT_EX
*)((BYTE
*)context
+ p
->context_size
);
787 c_ex
->Legacy
.Offset
= c_ex
->All
.Offset
= -(LONG
)p
->context_size
;
788 c_ex
->Legacy
.Length
= context_flags
& 0x20 ? p
->context_size
: p
->legacy_size
;
790 if (context_flags
& 0x40)
794 compaction_mask
&= supported_mask
;
796 xs
= (XSTATE
*)(((ULONG_PTR
)c_ex
+ p
->context_ex_size
+ 63) & ~(ULONG_PTR
)63);
798 c_ex
->XState
.Offset
= (ULONG_PTR
)xs
- (ULONG_PTR
)c_ex
;
799 c_ex
->XState
.Length
= offsetof(XSTATE
, YmmContext
);
800 compaction_mask
&= supported_mask
;
802 if (compaction_mask
& (1 << XSTATE_AVX
))
803 c_ex
->XState
.Length
+= sizeof(YMMCONTEXT
);
805 memset( xs
, 0, c_ex
->XState
.Length
);
806 if (user_shared_data
->XState
.CompactionEnabled
)
807 xs
->CompactionMask
= ((ULONG64
)1 << 63) | compaction_mask
;
809 c_ex
->All
.Length
= p
->context_size
+ c_ex
->XState
.Offset
+ c_ex
->XState
.Length
;
813 c_ex
->XState
.Offset
= 25; /* According to the tests, it is just 25 if CONTEXT_XSTATE is not specified. */
814 c_ex
->XState
.Length
= 0;
815 c_ex
->All
.Length
= p
->context_size
+ 24; /* sizeof(CONTEXT_EX) minus 8 alignment bytes on x64. */
818 return STATUS_SUCCESS
;
822 /**********************************************************************
823 * RtlInitializeExtendedContext (NTDLL.@)
825 NTSTATUS WINAPI
RtlInitializeExtendedContext( void *context
, ULONG context_flags
, CONTEXT_EX
**context_ex
)
827 return RtlInitializeExtendedContext2( context
, context_flags
, context_ex
, ~(ULONG64
)0 );
831 /**********************************************************************
832 * RtlLocateExtendedFeature2 (NTDLL.@)
834 void * WINAPI
RtlLocateExtendedFeature2( CONTEXT_EX
*context_ex
, ULONG feature_id
,
835 XSTATE_CONFIGURATION
*xstate_config
, ULONG
*length
)
837 TRACE( "context_ex %p, feature_id %u, xstate_config %p, length %p.\n",
838 context_ex
, feature_id
, xstate_config
, length
);
842 FIXME( "NULL xstate_config.\n" );
846 if (xstate_config
!= &user_shared_data
->XState
)
848 FIXME( "Custom xstate configuration is not supported.\n" );
852 if (feature_id
!= XSTATE_AVX
)
856 *length
= sizeof(YMMCONTEXT
);
858 if (context_ex
->XState
.Length
< sizeof(XSTATE
))
861 return (BYTE
*)context_ex
+ context_ex
->XState
.Offset
+ offsetof(XSTATE
, YmmContext
);
865 /**********************************************************************
866 * RtlLocateExtendedFeature (NTDLL.@)
868 void * WINAPI
RtlLocateExtendedFeature( CONTEXT_EX
*context_ex
, ULONG feature_id
,
871 return RtlLocateExtendedFeature2( context_ex
, feature_id
, &user_shared_data
->XState
, length
);
874 /**********************************************************************
875 * RtlLocateLegacyContext (NTDLL.@)
877 void * WINAPI
RtlLocateLegacyContext( CONTEXT_EX
*context_ex
, ULONG
*length
)
880 *length
= context_ex
->Legacy
.Length
;
882 return (BYTE
*)context_ex
+ context_ex
->Legacy
.Offset
;
885 /**********************************************************************
886 * RtlSetExtendedFeaturesMask (NTDLL.@)
888 void WINAPI
RtlSetExtendedFeaturesMask( CONTEXT_EX
*context_ex
, ULONG64 feature_mask
)
890 XSTATE
*xs
= (XSTATE
*)((BYTE
*)context_ex
+ context_ex
->XState
.Offset
);
892 xs
->Mask
= RtlGetEnabledExtendedFeatures( feature_mask
) & ~(ULONG64
)3;
896 /**********************************************************************
897 * RtlGetExtendedFeaturesMask (NTDLL.@)
899 ULONG64 WINAPI
RtlGetExtendedFeaturesMask( CONTEXT_EX
*context_ex
)
901 XSTATE
*xs
= (XSTATE
*)((BYTE
*)context_ex
+ context_ex
->XState
.Offset
);
903 return xs
->Mask
& ~(ULONG64
)3;
907 /**********************************************************************
908 * RtlCopyExtendedContext (NTDLL.@)
910 NTSTATUS WINAPI
RtlCopyExtendedContext( CONTEXT_EX
*dst
, ULONG context_flags
, CONTEXT_EX
*src
)
912 const struct context_copy_range
*range
;
913 const struct context_parameters
*p
;
914 XSTATE
*dst_xs
, *src_xs
;
915 ULONG64 feature_mask
;
919 TRACE( "dst %p, context_flags %#x, src %p.\n", dst
, context_flags
, src
);
921 if (!(p
= context_get_parameters( context_flags
)))
922 return STATUS_INVALID_PARAMETER
;
924 if (!(feature_mask
= RtlGetEnabledExtendedFeatures( ~(ULONG64
)0 )) && context_flags
& 0x40)
925 return STATUS_NOT_SUPPORTED
;
927 d
= RtlLocateLegacyContext( dst
, NULL
);
928 s
= RtlLocateLegacyContext( src
, NULL
);
930 *((ULONG
*)(d
+ p
->flags_offset
)) |= context_flags
;
933 range
= p
->copy_ranges
;
936 if (range
->flag
& context_flags
)
939 start
= range
->start
;
943 memcpy( d
+ start
, s
+ start
, range
->start
- start
);
947 while (range
++->start
!= p
->context_size
);
949 if (!(context_flags
& 0x40))
950 return STATUS_SUCCESS
;
952 if (dst
->XState
.Length
< offsetof(XSTATE
, YmmContext
))
953 return STATUS_BUFFER_OVERFLOW
;
955 dst_xs
= (XSTATE
*)((BYTE
*)dst
+ dst
->XState
.Offset
);
956 src_xs
= (XSTATE
*)((BYTE
*)src
+ src
->XState
.Offset
);
958 memset(dst_xs
, 0, offsetof(XSTATE
, YmmContext
));
959 dst_xs
->Mask
= (src_xs
->Mask
& ~(ULONG64
)3) & feature_mask
;
960 dst_xs
->CompactionMask
= user_shared_data
->XState
.CompactionEnabled
961 ? ((ULONG64
)1 << 63) | (src_xs
->CompactionMask
& feature_mask
) : 0;
963 if (dst_xs
->Mask
& 4 && src
->XState
.Length
>= sizeof(XSTATE
) && dst
->XState
.Length
>= sizeof(XSTATE
))
964 memcpy( &dst_xs
->YmmContext
, &src_xs
->YmmContext
, sizeof(dst_xs
->YmmContext
) );
965 return STATUS_SUCCESS
;