windows.networking.hostname/tests: Add IHostNameFactory::CreateHostName() tests.
[wine.git] / dlls / ntdll / exception.c
blob48d79c0cd18f2b0d730a8aeaa0cf3567648827f6
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 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winternl.h"
31 #include "ddk/wdm.h"
32 #include "wine/exception.h"
33 #include "wine/list.h"
34 #include "wine/debug.h"
35 #include "excpt.h"
36 #include "ntdll_misc.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(seh);
40 typedef struct
42 struct list entry;
43 PVECTORED_EXCEPTION_HANDLER func;
44 ULONG count;
45 } VECTORED_HANDLER;
47 static struct list vectored_exception_handlers = LIST_INIT(vectored_exception_handlers);
48 static struct list vectored_continue_handlers = LIST_INIT(vectored_continue_handlers);
50 static RTL_CRITICAL_SECTION vectored_handlers_section;
51 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
53 0, 0, &vectored_handlers_section,
54 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
55 0, 0, { (DWORD_PTR)(__FILE__ ": vectored_handlers_section") }
57 static RTL_CRITICAL_SECTION vectored_handlers_section = { &critsect_debug, -1, 0, 0, 0, 0 };
59 static PRTL_EXCEPTION_FILTER unhandled_exception_filter;
61 const char *debugstr_exception_code( DWORD code )
63 switch (code)
65 case CONTROL_C_EXIT: return "CONTROL_C_EXIT";
66 case DBG_CONTROL_C: return "DBG_CONTROL_C";
67 case DBG_PRINTEXCEPTION_C: return "DBG_PRINTEXCEPTION_C";
68 case DBG_PRINTEXCEPTION_WIDE_C: return "DBG_PRINTEXCEPTION_WIDE_C";
69 case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION";
70 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
71 case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT";
72 case EXCEPTION_DATATYPE_MISALIGNMENT: return "EXCEPTION_DATATYPE_MISALIGNMENT";
73 case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND";
74 case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
75 case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT";
76 case EXCEPTION_FLT_INVALID_OPERATION: return "EXCEPTION_FLT_INVALID_OPERATION";
77 case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW";
78 case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK";
79 case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW";
80 case EXCEPTION_GUARD_PAGE: return "EXCEPTION_GUARD_PAGE";
81 case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION";
82 case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR";
83 case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO";
84 case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW";
85 case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION";
86 case EXCEPTION_INVALID_HANDLE: return "EXCEPTION_INVALID_HANDLE";
87 case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
88 case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION";
89 case EXCEPTION_SINGLE_STEP: return "EXCEPTION_SINGLE_STEP";
90 case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW";
91 case EXCEPTION_WINE_ASSERTION: return "EXCEPTION_WINE_ASSERTION";
92 case EXCEPTION_WINE_CXX_EXCEPTION: return "EXCEPTION_WINE_CXX_EXCEPTION";
93 case EXCEPTION_WINE_NAME_THREAD: return "EXCEPTION_WINE_NAME_THREAD";
94 case EXCEPTION_WINE_STUB: return "EXCEPTION_WINE_STUB";
95 case RPC_S_SERVER_UNAVAILABLE: return "RPC_S_SERVER_UNAVAILABLE";
97 return "unknown";
101 static VECTORED_HANDLER *add_vectored_handler( struct list *handler_list, ULONG first,
102 PVECTORED_EXCEPTION_HANDLER func )
104 VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
105 if (handler)
107 handler->func = RtlEncodePointer( func );
108 handler->count = 1;
109 RtlEnterCriticalSection( &vectored_handlers_section );
110 if (first) list_add_head( handler_list, &handler->entry );
111 else list_add_tail( handler_list, &handler->entry );
112 RtlLeaveCriticalSection( &vectored_handlers_section );
114 return handler;
118 static ULONG remove_vectored_handler( struct list *handler_list, VECTORED_HANDLER *handler )
120 struct list *ptr;
121 ULONG ret = FALSE;
123 RtlEnterCriticalSection( &vectored_handlers_section );
124 LIST_FOR_EACH( ptr, handler_list )
126 VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
127 if (curr_handler == handler)
129 if (!--curr_handler->count) list_remove( ptr );
130 else handler = NULL; /* don't free it yet */
131 ret = TRUE;
132 break;
135 RtlLeaveCriticalSection( &vectored_handlers_section );
136 if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
137 return ret;
141 /**********************************************************************
142 * call_vectored_handlers
144 * Call the vectored handlers chain.
146 LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
148 struct list *ptr;
149 LONG ret = EXCEPTION_CONTINUE_SEARCH;
150 EXCEPTION_POINTERS except_ptrs;
151 PVECTORED_EXCEPTION_HANDLER func;
152 VECTORED_HANDLER *handler, *to_free = NULL;
154 except_ptrs.ExceptionRecord = rec;
155 except_ptrs.ContextRecord = context;
157 RtlEnterCriticalSection( &vectored_handlers_section );
158 ptr = list_head( &vectored_exception_handlers );
159 while (ptr)
161 handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
162 handler->count++;
163 func = RtlDecodePointer( handler->func );
164 RtlLeaveCriticalSection( &vectored_handlers_section );
165 RtlFreeHeap( GetProcessHeap(), 0, to_free );
166 to_free = NULL;
168 TRACE( "calling handler at %p code=%lx flags=%lx\n",
169 func, rec->ExceptionCode, rec->ExceptionFlags );
170 ret = func( &except_ptrs );
171 TRACE( "handler at %p returned %lx\n", func, ret );
173 RtlEnterCriticalSection( &vectored_handlers_section );
174 ptr = list_next( &vectored_exception_handlers, ptr );
175 if (!--handler->count) /* removed during execution */
177 list_remove( &handler->entry );
178 to_free = handler;
180 if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
182 RtlLeaveCriticalSection( &vectored_handlers_section );
183 RtlFreeHeap( GetProcessHeap(), 0, to_free );
184 return ret;
188 /*******************************************************************
189 * raise_status
191 * Implementation of RtlRaiseStatus with a specific exception record.
193 void DECLSPEC_NORETURN raise_status( NTSTATUS status, EXCEPTION_RECORD *rec )
195 EXCEPTION_RECORD ExceptionRec;
197 ExceptionRec.ExceptionCode = status;
198 ExceptionRec.ExceptionFlags = EH_NONCONTINUABLE;
199 ExceptionRec.ExceptionRecord = rec;
200 ExceptionRec.NumberParameters = 0;
201 for (;;) RtlRaiseException( &ExceptionRec ); /* never returns */
205 /***********************************************************************
206 * RtlRaiseStatus (NTDLL.@)
208 * Raise an exception with ExceptionCode = status
210 void DECLSPEC_NORETURN WINAPI RtlRaiseStatus( NTSTATUS status )
212 raise_status( status, NULL );
216 /*******************************************************************
217 * KiRaiseUserExceptionDispatcher (NTDLL.@)
219 NTSTATUS WINAPI KiRaiseUserExceptionDispatcher(void)
221 DWORD code = NtCurrentTeb()->ExceptionCode;
222 EXCEPTION_RECORD rec = { code };
223 RtlRaiseException( &rec );
224 return code;
228 /*******************************************************************
229 * RtlAddVectoredContinueHandler (NTDLL.@)
231 PVOID WINAPI RtlAddVectoredContinueHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
233 return add_vectored_handler( &vectored_continue_handlers, first, func );
237 /*******************************************************************
238 * RtlRemoveVectoredContinueHandler (NTDLL.@)
240 ULONG WINAPI RtlRemoveVectoredContinueHandler( PVOID handler )
242 return remove_vectored_handler( &vectored_continue_handlers, handler );
246 /*******************************************************************
247 * RtlAddVectoredExceptionHandler (NTDLL.@)
249 PVOID WINAPI DECLSPEC_HOTPATCH RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
251 return add_vectored_handler( &vectored_exception_handlers, first, func );
255 /*******************************************************************
256 * RtlRemoveVectoredExceptionHandler (NTDLL.@)
258 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
260 return remove_vectored_handler( &vectored_exception_handlers, handler );
264 /*******************************************************************
265 * RtlSetUnhandledExceptionFilter (NTDLL.@)
267 void WINAPI RtlSetUnhandledExceptionFilter( PRTL_EXCEPTION_FILTER filter )
269 unhandled_exception_filter = filter;
273 /*******************************************************************
274 * call_unhandled_exception_filter
276 LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr )
278 if (!unhandled_exception_filter) return EXCEPTION_CONTINUE_SEARCH;
279 return unhandled_exception_filter( eptr );
283 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
285 struct dynamic_unwind_entry
287 struct list entry;
288 ULONG_PTR base;
289 ULONG_PTR end;
290 RUNTIME_FUNCTION *table;
291 DWORD count;
292 DWORD max_count;
293 PGET_RUNTIME_FUNCTION_CALLBACK callback;
294 PVOID context;
297 static struct list dynamic_unwind_list = LIST_INIT(dynamic_unwind_list);
299 static RTL_CRITICAL_SECTION dynamic_unwind_section;
300 static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug =
302 0, 0, &dynamic_unwind_section,
303 { &dynamic_unwind_debug.ProcessLocksList, &dynamic_unwind_debug.ProcessLocksList },
304 0, 0, { (DWORD_PTR)(__FILE__ ": dynamic_unwind_section") }
306 static RTL_CRITICAL_SECTION dynamic_unwind_section = { &dynamic_unwind_debug, -1, 0, 0, 0, 0 };
308 static ULONG_PTR get_runtime_function_end( RUNTIME_FUNCTION *func, ULONG_PTR addr )
310 #ifdef __x86_64__
311 return func->EndAddress;
312 #elif defined(__arm__)
313 if (func->Flag) return func->BeginAddress + func->FunctionLength * 2;
314 else
316 struct unwind_info
318 DWORD function_length : 18;
319 DWORD version : 2;
320 DWORD x : 1;
321 DWORD e : 1;
322 DWORD f : 1;
323 DWORD count : 5;
324 DWORD words : 4;
325 } *info = (struct unwind_info *)(addr + func->UnwindData);
326 return func->BeginAddress + info->function_length * 2;
328 #else /* __aarch64__ */
329 if (func->Flag) return func->BeginAddress + func->FunctionLength * 4;
330 else
332 struct unwind_info
334 DWORD function_length : 18;
335 DWORD version : 2;
336 DWORD x : 1;
337 DWORD e : 1;
338 DWORD epilog : 5;
339 DWORD codes : 5;
340 } *info = (struct unwind_info *)(addr + func->UnwindData);
341 return func->BeginAddress + info->function_length * 4;
343 #endif
346 /**********************************************************************
347 * RtlAddFunctionTable (NTDLL.@)
349 BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, ULONG_PTR addr )
351 struct dynamic_unwind_entry *entry;
353 TRACE( "%p %lu %Ix\n", table, count, addr );
355 /* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
357 entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
358 if (!entry)
359 return FALSE;
361 entry->base = addr;
362 entry->end = addr + (count ? get_runtime_function_end( &table[count - 1], addr ) : 0);
363 entry->table = table;
364 entry->count = count;
365 entry->max_count = 0;
366 entry->callback = NULL;
367 entry->context = NULL;
369 RtlEnterCriticalSection( &dynamic_unwind_section );
370 list_add_tail( &dynamic_unwind_list, &entry->entry );
371 RtlLeaveCriticalSection( &dynamic_unwind_section );
372 return TRUE;
376 /**********************************************************************
377 * RtlInstallFunctionTableCallback (NTDLL.@)
379 BOOLEAN CDECL RtlInstallFunctionTableCallback( ULONG_PTR table, ULONG_PTR base, DWORD length,
380 PGET_RUNTIME_FUNCTION_CALLBACK callback, PVOID context,
381 PCWSTR dll )
383 struct dynamic_unwind_entry *entry;
385 TRACE( "%Ix %Ix %ld %p %p %s\n", table, base, length, callback, context, wine_dbgstr_w(dll) );
387 /* NOTE: Windows doesn't check if the provided callback is a NULL pointer */
389 /* both low-order bits must be set */
390 if ((table & 0x3) != 0x3)
391 return FALSE;
393 entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
394 if (!entry)
395 return FALSE;
397 entry->base = base;
398 entry->end = base + length;
399 entry->table = (RUNTIME_FUNCTION *)table;
400 entry->count = 0;
401 entry->max_count = 0;
402 entry->callback = callback;
403 entry->context = context;
405 RtlEnterCriticalSection( &dynamic_unwind_section );
406 list_add_tail( &dynamic_unwind_list, &entry->entry );
407 RtlLeaveCriticalSection( &dynamic_unwind_section );
409 return TRUE;
413 /*************************************************************************
414 * RtlAddGrowableFunctionTable (NTDLL.@)
416 DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functions, DWORD count,
417 DWORD max_count, ULONG_PTR base, ULONG_PTR end )
419 struct dynamic_unwind_entry *entry;
421 TRACE( "%p, %p, %lu, %lu, %Ix, %Ix\n", table, functions, count, max_count, base, end );
423 entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
424 if (!entry)
425 return STATUS_NO_MEMORY;
427 entry->base = base;
428 entry->end = end;
429 entry->table = functions;
430 entry->count = count;
431 entry->max_count = max_count;
432 entry->callback = NULL;
433 entry->context = NULL;
435 RtlEnterCriticalSection( &dynamic_unwind_section );
436 list_add_tail( &dynamic_unwind_list, &entry->entry );
437 RtlLeaveCriticalSection( &dynamic_unwind_section );
439 *table = entry;
441 return STATUS_SUCCESS;
445 /*************************************************************************
446 * RtlGrowFunctionTable (NTDLL.@)
448 void WINAPI RtlGrowFunctionTable( void *table, DWORD count )
450 struct dynamic_unwind_entry *entry;
452 TRACE( "%p, %lu\n", table, count );
454 RtlEnterCriticalSection( &dynamic_unwind_section );
455 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
457 if (entry == table)
459 if (count > entry->count && count <= entry->max_count)
460 entry->count = count;
461 break;
464 RtlLeaveCriticalSection( &dynamic_unwind_section );
468 /*************************************************************************
469 * RtlDeleteGrowableFunctionTable (NTDLL.@)
471 void WINAPI RtlDeleteGrowableFunctionTable( void *table )
473 struct dynamic_unwind_entry *entry, *to_free = NULL;
475 TRACE( "%p\n", table );
477 RtlEnterCriticalSection( &dynamic_unwind_section );
478 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
480 if (entry == table)
482 to_free = entry;
483 list_remove( &entry->entry );
484 break;
487 RtlLeaveCriticalSection( &dynamic_unwind_section );
489 RtlFreeHeap( GetProcessHeap(), 0, to_free );
493 /**********************************************************************
494 * RtlDeleteFunctionTable (NTDLL.@)
496 BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
498 struct dynamic_unwind_entry *entry, *to_free = NULL;
500 TRACE( "%p\n", table );
502 RtlEnterCriticalSection( &dynamic_unwind_section );
503 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
505 if (entry->table == table)
507 to_free = entry;
508 list_remove( &entry->entry );
509 break;
512 RtlLeaveCriticalSection( &dynamic_unwind_section );
514 if (!to_free) return FALSE;
516 RtlFreeHeap( GetProcessHeap(), 0, to_free );
517 return TRUE;
521 /* helper for lookup_function_info() */
522 static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base,
523 RUNTIME_FUNCTION *func, ULONG size )
525 int min = 0;
526 int max = size - 1;
528 while (min <= max)
530 #ifdef __x86_64__
531 int pos = (min + max) / 2;
532 if (pc < base + func[pos].BeginAddress) max = pos - 1;
533 else if (pc >= base + func[pos].EndAddress) min = pos + 1;
534 else
536 func += pos;
537 while (func->UnwindData & 1) /* follow chained entry */
538 func = (RUNTIME_FUNCTION *)(base + (func->UnwindData & ~1));
539 return func;
541 #elif defined(__arm__)
542 int pos = (min + max) / 2;
543 if (pc < base + (func[pos].BeginAddress & ~1)) max = pos - 1;
544 else if (pc >= base + get_runtime_function_end( &func[pos], base )) min = pos + 1;
545 else return func + pos;
546 #else /* __aarch64__ */
547 int pos = (min + max) / 2;
548 if (pc < base + func[pos].BeginAddress) max = pos - 1;
549 else if (pc >= base + get_runtime_function_end( &func[pos], base )) min = pos + 1;
550 else return func + pos;
551 #endif
553 return NULL;
556 /**********************************************************************
557 * lookup_function_info
559 RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_DATA_TABLE_ENTRY **module )
561 RUNTIME_FUNCTION *func = NULL;
562 struct dynamic_unwind_entry *entry;
563 ULONG size;
565 /* PE module or wine module */
566 if (!LdrFindEntryForAddress( (void *)pc, module ))
568 *base = (ULONG_PTR)(*module)->DllBase;
569 if ((func = RtlImageDirectoryEntryToData( (*module)->DllBase, TRUE,
570 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
572 /* lookup in function table */
573 func = find_function_info( pc, (ULONG_PTR)(*module)->DllBase, func, size/sizeof(*func) );
576 else
578 *module = NULL;
580 RtlEnterCriticalSection( &dynamic_unwind_section );
581 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
583 if (pc >= entry->base && pc < entry->end)
585 *base = entry->base;
586 /* use callback or lookup in function table */
587 if (entry->callback)
588 func = entry->callback( pc, entry->context );
589 else
590 func = find_function_info( pc, entry->base, entry->table, entry->count );
591 break;
594 RtlLeaveCriticalSection( &dynamic_unwind_section );
597 return func;
600 /**********************************************************************
601 * RtlLookupFunctionEntry (NTDLL.@)
603 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base,
604 UNWIND_HISTORY_TABLE *table )
606 LDR_DATA_TABLE_ENTRY *module;
607 RUNTIME_FUNCTION *func;
609 /* FIXME: should use the history table to make things faster */
611 if (!(func = lookup_function_info( pc, base, &module )))
613 *base = 0;
614 WARN( "no exception table found for %Ix\n", pc );
616 return func;
619 #endif /* __x86_64__ || __arm__ || __aarch64__ */
622 /*************************************************************
623 * _assert
625 void DECLSPEC_NORETURN __cdecl _assert( const char *str, const char *file, unsigned int line )
627 ERR( "%s:%u: Assertion failed %s\n", file, line, debugstr_a(str) );
628 RtlRaiseStatus( EXCEPTION_WINE_ASSERTION );
632 /*************************************************************
633 * __wine_spec_unimplemented_stub
635 * ntdll-specific implementation to avoid depending on kernel functions.
636 * Can be removed once ntdll.spec no longer contains stubs.
638 void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
640 EXCEPTION_RECORD record;
642 record.ExceptionCode = EXCEPTION_WINE_STUB;
643 record.ExceptionFlags = EH_NONCONTINUABLE;
644 record.ExceptionRecord = NULL;
645 record.ExceptionAddress = __wine_spec_unimplemented_stub;
646 record.NumberParameters = 2;
647 record.ExceptionInformation[0] = (ULONG_PTR)module;
648 record.ExceptionInformation[1] = (ULONG_PTR)function;
649 for (;;) RtlRaiseException( &record );
653 /*************************************************************
654 * IsBadStringPtrA
656 * IsBadStringPtrA replacement for ntdll, to catch exception in debug traces.
658 BOOL WINAPI IsBadStringPtrA( LPCSTR str, UINT_PTR max )
660 if (!str) return TRUE;
661 __TRY
663 volatile const char *p = str;
664 while (p != str + max) if (!*p++) break;
666 __EXCEPT_PAGE_FAULT
668 return TRUE;
670 __ENDTRY
671 return FALSE;
674 /*************************************************************
675 * IsBadStringPtrW
677 * IsBadStringPtrW replacement for ntdll, to catch exception in debug traces.
679 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT_PTR max )
681 if (!str) return TRUE;
682 __TRY
684 volatile const WCHAR *p = str;
685 while (p != str + max) if (!*p++) break;
687 __EXCEPT_PAGE_FAULT
689 return TRUE;
691 __ENDTRY
692 return FALSE;
695 #ifdef __i386__
696 __ASM_STDCALL_IMPORT(IsBadStringPtrA,8)
697 __ASM_STDCALL_IMPORT(IsBadStringPtrW,8)
698 #else
699 __ASM_GLOBAL_IMPORT(IsBadStringPtrA)
700 __ASM_GLOBAL_IMPORT(IsBadStringPtrW)
701 #endif
703 /**********************************************************************
704 * RtlGetEnabledExtendedFeatures (NTDLL.@)
706 ULONG64 WINAPI RtlGetEnabledExtendedFeatures(ULONG64 feature_mask)
708 return user_shared_data->XState.EnabledFeatures & feature_mask;
711 struct context_copy_range
713 ULONG start;
714 ULONG flag;
717 static const struct context_copy_range copy_ranges_amd64[] =
719 {0x38, 0x1}, {0x3a, 0x4}, { 0x42, 0x1}, { 0x48, 0x10}, { 0x78, 0x2}, { 0x98, 0x1},
720 {0xa0, 0x2}, {0xf8, 0x1}, {0x100, 0x8}, {0x2a0, 0}, {0x4b0, 0x10}, {0x4d0, 0}
723 static const struct context_copy_range copy_ranges_x86[] =
725 { 0x4, 0x10}, {0x1c, 0x8}, {0x8c, 0x4}, {0x9c, 0x2}, {0xb4, 0x1}, {0xcc, 0x20}, {0x1ec, 0},
726 {0x2cc, 0},
729 static const struct context_parameters
731 ULONG arch_flag;
732 ULONG supported_flags;
733 ULONG context_size; /* sizeof(CONTEXT) */
734 ULONG legacy_size; /* Legacy context size */
735 ULONG context_ex_size; /* sizeof(CONTEXT_EX) */
736 ULONG alignment; /* Used when computing size of context. */
737 ULONG true_alignment; /* Used for actual alignment. */
738 ULONG flags_offset;
739 const struct context_copy_range *copy_ranges;
741 arch_context_parameters[] =
744 CONTEXT_AMD64,
745 0xd8000000 | CONTEXT_AMD64_ALL | CONTEXT_AMD64_XSTATE,
746 sizeof(AMD64_CONTEXT),
747 sizeof(AMD64_CONTEXT),
748 0x20,
750 TYPE_ALIGNMENT(AMD64_CONTEXT) - 1,
751 offsetof(AMD64_CONTEXT,ContextFlags),
752 copy_ranges_amd64
755 CONTEXT_i386,
756 0xd8000000 | CONTEXT_I386_ALL | CONTEXT_I386_XSTATE,
757 sizeof(I386_CONTEXT),
758 offsetof(I386_CONTEXT,ExtendedRegisters),
759 0x18,
761 TYPE_ALIGNMENT(I386_CONTEXT) - 1,
762 offsetof(I386_CONTEXT,ContextFlags),
763 copy_ranges_x86
767 static const struct context_parameters *context_get_parameters( ULONG context_flags )
769 unsigned int i;
771 for (i = 0; i < ARRAY_SIZE(arch_context_parameters); ++i)
773 if (context_flags & arch_context_parameters[i].arch_flag)
774 return context_flags & ~arch_context_parameters[i].supported_flags ? NULL : &arch_context_parameters[i];
776 return NULL;
780 /**********************************************************************
781 * RtlGetExtendedContextLength2 (NTDLL.@)
783 NTSTATUS WINAPI RtlGetExtendedContextLength2( ULONG context_flags, ULONG *length, ULONG64 compaction_mask )
785 const struct context_parameters *p;
786 ULONG64 supported_mask;
787 ULONG64 size;
789 TRACE( "context_flags %#lx, length %p, compaction_mask %s.\n", context_flags, length,
790 wine_dbgstr_longlong(compaction_mask) );
792 if (!(p = context_get_parameters( context_flags )))
793 return STATUS_INVALID_PARAMETER;
795 if (!(context_flags & 0x40))
797 *length = p->context_size + p->context_ex_size + p->alignment;
798 return STATUS_SUCCESS;
801 if (!(supported_mask = RtlGetEnabledExtendedFeatures( ~(ULONG64)0) ))
802 return STATUS_NOT_SUPPORTED;
804 compaction_mask &= supported_mask;
806 size = p->context_size + p->context_ex_size + offsetof(XSTATE, YmmContext) + 63;
808 if (compaction_mask & supported_mask & (1 << XSTATE_AVX))
809 size += sizeof(YMMCONTEXT);
811 *length = size;
812 return STATUS_SUCCESS;
816 /**********************************************************************
817 * RtlGetExtendedContextLength (NTDLL.@)
819 NTSTATUS WINAPI RtlGetExtendedContextLength( ULONG context_flags, ULONG *length )
821 return RtlGetExtendedContextLength2( context_flags, length, ~(ULONG64)0 );
825 /**********************************************************************
826 * RtlInitializeExtendedContext2 (NTDLL.@)
828 NTSTATUS WINAPI RtlInitializeExtendedContext2( void *context, ULONG context_flags, CONTEXT_EX **context_ex,
829 ULONG64 compaction_mask )
831 const struct context_parameters *p;
832 ULONG64 supported_mask = 0;
833 CONTEXT_EX *c_ex;
835 TRACE( "context %p, context_flags %#lx, context_ex %p, compaction_mask %s.\n",
836 context, context_flags, context_ex, wine_dbgstr_longlong(compaction_mask));
838 if (!(p = context_get_parameters( context_flags )))
839 return STATUS_INVALID_PARAMETER;
841 if ((context_flags & 0x40) && !(supported_mask = RtlGetEnabledExtendedFeatures( ~(ULONG64)0 )))
842 return STATUS_NOT_SUPPORTED;
844 context = (void *)(((ULONG_PTR)context + p->true_alignment) & ~(ULONG_PTR)p->true_alignment);
845 *(ULONG *)((BYTE *)context + p->flags_offset) = context_flags;
847 *context_ex = c_ex = (CONTEXT_EX *)((BYTE *)context + p->context_size);
848 c_ex->Legacy.Offset = c_ex->All.Offset = -(LONG)p->context_size;
849 c_ex->Legacy.Length = context_flags & 0x20 ? p->context_size : p->legacy_size;
851 if (context_flags & 0x40)
853 XSTATE *xs;
855 compaction_mask &= supported_mask;
857 xs = (XSTATE *)(((ULONG_PTR)c_ex + p->context_ex_size + 63) & ~(ULONG_PTR)63);
859 c_ex->XState.Offset = (ULONG_PTR)xs - (ULONG_PTR)c_ex;
860 c_ex->XState.Length = offsetof(XSTATE, YmmContext);
861 compaction_mask &= supported_mask;
863 if (compaction_mask & (1 << XSTATE_AVX))
864 c_ex->XState.Length += sizeof(YMMCONTEXT);
866 memset( xs, 0, c_ex->XState.Length );
867 if (user_shared_data->XState.CompactionEnabled)
868 xs->CompactionMask = ((ULONG64)1 << 63) | compaction_mask;
870 c_ex->All.Length = p->context_size + c_ex->XState.Offset + c_ex->XState.Length;
872 else
874 c_ex->XState.Offset = 25; /* According to the tests, it is just 25 if CONTEXT_XSTATE is not specified. */
875 c_ex->XState.Length = 0;
876 c_ex->All.Length = p->context_size + 24; /* sizeof(CONTEXT_EX) minus 8 alignment bytes on x64. */
879 return STATUS_SUCCESS;
883 /**********************************************************************
884 * RtlInitializeExtendedContext (NTDLL.@)
886 NTSTATUS WINAPI RtlInitializeExtendedContext( void *context, ULONG context_flags, CONTEXT_EX **context_ex )
888 return RtlInitializeExtendedContext2( context, context_flags, context_ex, ~(ULONG64)0 );
892 /**********************************************************************
893 * RtlLocateExtendedFeature2 (NTDLL.@)
895 void * WINAPI RtlLocateExtendedFeature2( CONTEXT_EX *context_ex, ULONG feature_id,
896 XSTATE_CONFIGURATION *xstate_config, ULONG *length )
898 TRACE( "context_ex %p, feature_id %lu, xstate_config %p, length %p.\n",
899 context_ex, feature_id, xstate_config, length );
901 if (!xstate_config)
903 FIXME( "NULL xstate_config.\n" );
904 return NULL;
907 if (xstate_config != &user_shared_data->XState)
909 FIXME( "Custom xstate configuration is not supported.\n" );
910 return NULL;
913 if (feature_id != XSTATE_AVX)
914 return NULL;
916 if (length)
917 *length = sizeof(YMMCONTEXT);
919 if (context_ex->XState.Length < sizeof(XSTATE))
920 return NULL;
922 return (BYTE *)context_ex + context_ex->XState.Offset + offsetof(XSTATE, YmmContext);
926 /**********************************************************************
927 * RtlLocateExtendedFeature (NTDLL.@)
929 void * WINAPI RtlLocateExtendedFeature( CONTEXT_EX *context_ex, ULONG feature_id,
930 ULONG *length )
932 return RtlLocateExtendedFeature2( context_ex, feature_id, &user_shared_data->XState, length );
935 /**********************************************************************
936 * RtlLocateLegacyContext (NTDLL.@)
938 void * WINAPI RtlLocateLegacyContext( CONTEXT_EX *context_ex, ULONG *length )
940 if (length)
941 *length = context_ex->Legacy.Length;
943 return (BYTE *)context_ex + context_ex->Legacy.Offset;
946 /**********************************************************************
947 * RtlSetExtendedFeaturesMask (NTDLL.@)
949 void WINAPI RtlSetExtendedFeaturesMask( CONTEXT_EX *context_ex, ULONG64 feature_mask )
951 XSTATE *xs = (XSTATE *)((BYTE *)context_ex + context_ex->XState.Offset);
953 xs->Mask = RtlGetEnabledExtendedFeatures( feature_mask ) & ~(ULONG64)3;
957 /**********************************************************************
958 * RtlGetExtendedFeaturesMask (NTDLL.@)
960 ULONG64 WINAPI RtlGetExtendedFeaturesMask( CONTEXT_EX *context_ex )
962 XSTATE *xs = (XSTATE *)((BYTE *)context_ex + context_ex->XState.Offset);
964 return xs->Mask & ~(ULONG64)3;
968 static void context_copy_ranges( BYTE *d, DWORD context_flags, BYTE *s, const struct context_parameters *p )
970 const struct context_copy_range *range;
971 unsigned int start;
973 *((ULONG *)(d + p->flags_offset)) |= context_flags;
975 start = 0;
976 range = p->copy_ranges;
979 if (range->flag & context_flags)
981 if (!start)
982 start = range->start;
984 else if (start)
986 memcpy( d + start, s + start, range->start - start );
987 start = 0;
990 while (range++->start != p->context_size);
994 /***********************************************************************
995 * RtlCopyContext (NTDLL.@)
997 NTSTATUS WINAPI RtlCopyContext( CONTEXT *dst, DWORD context_flags, CONTEXT *src )
999 DWORD context_size, arch_flag, flags_offset, dst_flags, src_flags;
1000 static const DWORD arch_mask = CONTEXT_i386 | CONTEXT_AMD64;
1001 const struct context_parameters *p;
1002 BYTE *d, *s;
1004 TRACE("dst %p, context_flags %#lx, src %p.\n", dst, context_flags, src);
1006 if (context_flags & 0x40 && !RtlGetEnabledExtendedFeatures( ~(ULONG64)0 )) return STATUS_NOT_SUPPORTED;
1008 arch_flag = context_flags & arch_mask;
1009 switch (arch_flag)
1011 case CONTEXT_i386:
1012 context_size = sizeof( I386_CONTEXT );
1013 flags_offset = offsetof( I386_CONTEXT, ContextFlags );
1014 break;
1015 case CONTEXT_AMD64:
1016 context_size = sizeof( AMD64_CONTEXT );
1017 flags_offset = offsetof( AMD64_CONTEXT, ContextFlags );
1018 break;
1019 default:
1020 return STATUS_INVALID_PARAMETER;
1023 d = (BYTE *)dst;
1024 s = (BYTE *)src;
1025 dst_flags = *(DWORD *)(d + flags_offset);
1026 src_flags = *(DWORD *)(s + flags_offset);
1028 if ((dst_flags & arch_mask) != arch_flag || (src_flags & arch_mask) != arch_flag)
1029 return STATUS_INVALID_PARAMETER;
1031 context_flags &= src_flags;
1032 if (context_flags & ~dst_flags & 0x40) return STATUS_BUFFER_OVERFLOW;
1034 if (context_flags & 0x40)
1035 return RtlCopyExtendedContext( (CONTEXT_EX *)(d + context_size), context_flags,
1036 (CONTEXT_EX *)(s + context_size) );
1038 if (!(p = context_get_parameters( context_flags )))
1039 return STATUS_INVALID_PARAMETER;
1041 context_copy_ranges( d, context_flags, s, p );
1042 return STATUS_SUCCESS;
1046 /**********************************************************************
1047 * RtlCopyExtendedContext (NTDLL.@)
1049 NTSTATUS WINAPI RtlCopyExtendedContext( CONTEXT_EX *dst, ULONG context_flags, CONTEXT_EX *src )
1051 const struct context_parameters *p;
1052 XSTATE *dst_xs, *src_xs;
1053 ULONG64 feature_mask;
1055 TRACE( "dst %p, context_flags %#lx, src %p.\n", dst, context_flags, src );
1057 if (!(p = context_get_parameters( context_flags )))
1058 return STATUS_INVALID_PARAMETER;
1060 if (!(feature_mask = RtlGetEnabledExtendedFeatures( ~(ULONG64)0 )) && context_flags & 0x40)
1061 return STATUS_NOT_SUPPORTED;
1063 context_copy_ranges( RtlLocateLegacyContext( dst, NULL ), context_flags, RtlLocateLegacyContext( src, NULL ), p );
1065 if (!(context_flags & 0x40))
1066 return STATUS_SUCCESS;
1068 if (dst->XState.Length < offsetof(XSTATE, YmmContext))
1069 return STATUS_BUFFER_OVERFLOW;
1071 dst_xs = (XSTATE *)((BYTE *)dst + dst->XState.Offset);
1072 src_xs = (XSTATE *)((BYTE *)src + src->XState.Offset);
1074 memset(dst_xs, 0, offsetof(XSTATE, YmmContext));
1075 dst_xs->Mask = (src_xs->Mask & ~(ULONG64)3) & feature_mask;
1076 dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled
1077 ? ((ULONG64)1 << 63) | (src_xs->CompactionMask & feature_mask) : 0;
1079 if (dst_xs->Mask & 4 && src->XState.Length >= sizeof(XSTATE) && dst->XState.Length >= sizeof(XSTATE))
1080 memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
1081 return STATUS_SUCCESS;