kernelbase: Use the correct machine type for ARM.
[wine/zf.git] / dlls / ntdll / exception.c
blobd5b3042c4910c0fae36d3950a332b2e66f26a274
1 /*
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
22 #include <assert.h>
23 #include <errno.h>
24 #include <signal.h>
25 #include <stdarg.h>
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "windef.h"
32 #include "winternl.h"
33 #include "ddk/wdm.h"
34 #include "wine/exception.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "excpt.h"
38 #include "ntdll_misc.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(seh);
42 typedef struct
44 struct list entry;
45 PVECTORED_EXCEPTION_HANDLER func;
46 ULONG count;
47 } VECTORED_HANDLER;
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 )
65 switch (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";
98 return "unknown";
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) );
106 if (handler)
108 handler->func = RtlEncodePointer( func );
109 handler->count = 1;
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 );
115 return handler;
119 static ULONG remove_vectored_handler( struct list *handler_list, VECTORED_HANDLER *handler )
121 struct list *ptr;
122 ULONG ret = FALSE;
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 */
132 ret = TRUE;
133 break;
136 RtlLeaveCriticalSection( &vectored_handlers_section );
137 if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
138 return ret;
142 /**********************************************************************
143 * call_vectored_handlers
145 * Call the vectored handlers chain.
147 LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
149 struct list *ptr;
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 );
160 while (ptr)
162 handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
163 handler->count++;
164 func = RtlDecodePointer( handler->func );
165 RtlLeaveCriticalSection( &vectored_handlers_section );
166 RtlFreeHeap( GetProcessHeap(), 0, to_free );
167 to_free = NULL;
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 );
179 to_free = handler;
181 if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
183 RtlLeaveCriticalSection( &vectored_handlers_section );
184 RtlFreeHeap( GetProcessHeap(), 0, to_free );
185 return ret;
189 /*******************************************************************
190 * raise_status
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 );
225 return code;
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
288 struct list entry;
289 ULONG_PTR base;
290 ULONG_PTR end;
291 RUNTIME_FUNCTION *table;
292 DWORD count;
293 DWORD max_count;
294 PGET_RUNTIME_FUNCTION_CALLBACK callback;
295 PVOID context;
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 )
311 #ifdef __x86_64__
312 return func->EndAddress;
313 #elif defined(__arm__)
314 if (func->u.s.Flag) return func->BeginAddress + func->u.s.FunctionLength * 2;
315 else
317 struct unwind_info
319 DWORD function_length : 18;
320 DWORD version : 2;
321 DWORD x : 1;
322 DWORD e : 1;
323 DWORD f : 1;
324 DWORD count : 5;
325 DWORD words : 4;
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;
331 else
333 struct unwind_info
335 DWORD function_length : 18;
336 DWORD version : 2;
337 DWORD x : 1;
338 DWORD e : 1;
339 DWORD epilog : 5;
340 DWORD codes : 5;
341 } *info = (struct unwind_info *)(addr + func->u.UnwindData);
342 return func->BeginAddress + info->function_length * 4;
344 #endif
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) );
359 if (!entry)
360 return FALSE;
362 entry->base = addr;
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 );
373 return TRUE;
377 /**********************************************************************
378 * RtlInstallFunctionTableCallback (NTDLL.@)
380 BOOLEAN CDECL RtlInstallFunctionTableCallback( ULONG_PTR table, ULONG_PTR base, DWORD length,
381 PGET_RUNTIME_FUNCTION_CALLBACK callback, PVOID context,
382 PCWSTR dll )
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)
392 return FALSE;
394 entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
395 if (!entry)
396 return FALSE;
398 entry->base = base;
399 entry->end = base + length;
400 entry->table = (RUNTIME_FUNCTION *)table;
401 entry->count = 0;
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 );
410 return TRUE;
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) );
425 if (!entry)
426 return STATUS_NO_MEMORY;
428 entry->base = base;
429 entry->end = end;
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 );
440 *table = entry;
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 )
458 if (entry == table)
460 if (count > entry->count && count <= entry->max_count)
461 entry->count = count;
462 break;
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 )
481 if (entry == table)
483 to_free = entry;
484 list_remove( &entry->entry );
485 break;
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)
508 to_free = entry;
509 list_remove( &entry->entry );
510 break;
513 RtlLeaveCriticalSection( &dynamic_unwind_section );
515 if (!to_free) return FALSE;
517 RtlFreeHeap( GetProcessHeap(), 0, to_free );
518 return TRUE;
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 )
526 int min = 0;
527 int max = size - 1;
529 while (min <= max)
531 #ifdef __x86_64__
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;
535 else
537 func += pos;
538 while (func->UnwindData & 1) /* follow chained entry */
539 func = (RUNTIME_FUNCTION *)(base + (func->UnwindData & ~1));
540 return func;
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;
552 #endif
554 return NULL;
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;
564 ULONG size;
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) );
577 else
579 *module = NULL;
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)
586 *base = entry->base;
587 /* use callback or lookup in function table */
588 if (entry->callback)
589 func = entry->callback( pc, entry->context );
590 else
591 func = find_function_info( pc, entry->base, entry->table, entry->count );
592 break;
595 RtlLeaveCriticalSection( &dynamic_unwind_section );
598 return func;
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 )))
614 *base = 0;
615 WARN( "no exception table found for %lx\n", pc );
617 return func;
620 #endif /* __x86_64__ || __arm__ || __aarch64__ */
623 /*************************************************************
624 * _assert
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 /*************************************************************
655 * IsBadStringPtrA
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;
662 __TRY
664 volatile const char *p = str;
665 while (p != str + max) if (!*p++) break;
667 __EXCEPT_PAGE_FAULT
669 return TRUE;
671 __ENDTRY
672 return FALSE;
674 __ASM_STDCALL_IMPORT(IsBadStringPtrA,8)
676 /*************************************************************
677 * IsBadStringPtrW
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;
684 __TRY
686 volatile const WCHAR *p = str;
687 while (p != str + max) if (!*p++) break;
689 __EXCEPT_PAGE_FAULT
691 return TRUE;
693 __ENDTRY
694 return FALSE;
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
709 ULONG start;
710 ULONG flag;
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},
722 {0x2cc, 0},
725 static const struct context_parameters
727 ULONG arch_flag;
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. */
734 ULONG flags_offset;
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 )
745 unsigned int i;
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];
752 return NULL;
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;
763 ULONG64 size;
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);
787 *length = size;
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;
809 CONTEXT_EX *c_ex;
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)
829 XSTATE *xs;
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;
848 else
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 );
877 if (!xstate_config)
879 FIXME( "NULL xstate_config.\n" );
880 return NULL;
883 if (xstate_config != &user_shared_data->XState)
885 FIXME( "Custom xstate configuration is not supported.\n" );
886 return NULL;
889 if (feature_id != XSTATE_AVX)
890 return NULL;
892 if (length)
893 *length = sizeof(YMMCONTEXT);
895 if (context_ex->XState.Length < sizeof(XSTATE))
896 return NULL;
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,
906 ULONG *length )
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 )
916 if (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;
953 unsigned int start;
954 BYTE *d, *s;
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;
969 start = 0;
970 range = p->copy_ranges;
973 if (range->flag & context_flags)
975 if (!start)
976 start = range->start;
978 else if (start)
980 memcpy( d + start, s + start, range->start - start );
981 start = 0;
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;