4 * Copyright 1996, 2003 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <sys/types.h>
26 #define NONAMELESSUNION
28 #define WIN32_NO_STATUS
30 #include "wine/debug.h"
31 #include "ntdll_misc.h"
33 #include "wine/exception.h"
35 WINE_DECLARE_DEBUG_CHANNEL(relay
);
36 WINE_DECLARE_DEBUG_CHANNEL(thread
);
37 WINE_DECLARE_DEBUG_CHANNEL(pid
);
38 WINE_DECLARE_DEBUG_CHANNEL(timestamp
);
40 struct _KUSER_SHARED_DATA
*user_shared_data
= (void *)0x7ffe0000;
44 unsigned int str_pos
; /* current position in strings buffer */
45 unsigned int out_pos
; /* current position in output buffer */
46 char strings
[1020]; /* buffer for temporary strings */
47 char output
[1020]; /* current output line */
50 C_ASSERT( sizeof(struct debug_info
) == 0x800 );
52 static int nb_debug_options
;
53 static struct __wine_debug_channel
*debug_options
;
55 static inline struct debug_info
*get_info(void)
58 return (struct debug_info
*)((TEB32
*)((char *)NtCurrentTeb() + 0x2000) + 1);
60 return (struct debug_info
*)(NtCurrentTeb() + 1);
64 static void init_options(void)
66 unsigned int offset
= page_size
* (sizeof(void *) / 4);
68 debug_options
= (struct __wine_debug_channel
*)((char *)NtCurrentTeb()->Peb
+ offset
);
69 while (debug_options
[nb_debug_options
].name
[0]) nb_debug_options
++;
72 /* add a string to the output buffer */
73 static int append_output( struct debug_info
*info
, const char *str
, size_t len
)
75 if (len
>= sizeof(info
->output
) - info
->out_pos
)
77 __wine_dbg_write( info
->output
, info
->out_pos
);
79 ERR_(thread
)( "debug buffer overflow:\n" );
80 __wine_dbg_write( str
, len
);
81 RtlRaiseStatus( STATUS_BUFFER_OVERFLOW
);
83 memcpy( info
->output
+ info
->out_pos
, str
, len
);
88 /***********************************************************************
89 * __wine_dbg_get_channel_flags (NTDLL.@)
91 * Get the flags to use for a given channel, possibly setting them too in case of lazy init
93 unsigned char __cdecl
__wine_dbg_get_channel_flags( struct __wine_debug_channel
*channel
)
95 int min
, max
, pos
, res
;
96 unsigned char default_flags
;
98 if (!debug_options
) init_options();
101 max
= nb_debug_options
- 1;
104 pos
= (min
+ max
) / 2;
105 res
= strcmp( channel
->name
, debug_options
[pos
].name
);
106 if (!res
) return debug_options
[pos
].flags
;
107 if (res
< 0) max
= pos
- 1;
110 /* no option for this channel */
111 default_flags
= debug_options
[nb_debug_options
].flags
;
112 if (channel
->flags
& (1 << __WINE_DBCL_INIT
)) channel
->flags
= default_flags
;
113 return default_flags
;
116 /***********************************************************************
117 * __wine_dbg_strdup (NTDLL.@)
119 const char * __cdecl
__wine_dbg_strdup( const char *str
)
121 struct debug_info
*info
= get_info();
122 unsigned int pos
= info
->str_pos
;
123 size_t n
= strlen( str
) + 1;
125 assert( n
<= sizeof(info
->strings
) );
126 if (pos
+ n
> sizeof(info
->strings
)) pos
= 0;
127 info
->str_pos
= pos
+ n
;
128 return memcpy( info
->strings
+ pos
, str
, n
);
131 /***********************************************************************
132 * __wine_dbg_header (NTDLL.@)
134 int __cdecl
__wine_dbg_header( enum __wine_debug_class cls
, struct __wine_debug_channel
*channel
,
135 const char *function
)
137 static const char * const classes
[] = { "fixme", "err", "warn", "trace" };
138 struct debug_info
*info
= get_info();
139 char *pos
= info
->output
;
141 if (!(__wine_dbg_get_channel_flags( channel
) & (1 << cls
))) return -1;
143 /* only print header if we are at the beginning of the line */
144 if (info
->out_pos
) return 0;
146 if (TRACE_ON(timestamp
))
148 ULONG ticks
= NtGetTickCount();
149 pos
+= sprintf( pos
, "%3u.%03u:", ticks
/ 1000, ticks
% 1000 );
151 if (TRACE_ON(pid
)) pos
+= sprintf( pos
, "%04x:", GetCurrentProcessId() );
152 pos
+= sprintf( pos
, "%04x:", GetCurrentThreadId() );
153 if (function
&& cls
< ARRAY_SIZE( classes
))
154 pos
+= snprintf( pos
, sizeof(info
->output
) - (pos
- info
->output
), "%s:%s:%s ",
155 classes
[cls
], channel
->name
, function
);
156 info
->out_pos
= pos
- info
->output
;
157 return info
->out_pos
;
160 /***********************************************************************
161 * __wine_dbg_output (NTDLL.@)
163 int __cdecl
__wine_dbg_output( const char *str
)
165 struct debug_info
*info
= get_info();
166 const char *end
= strrchr( str
, '\n' );
171 ret
+= append_output( info
, str
, end
+ 1 - str
);
172 __wine_dbg_write( info
->output
, info
->out_pos
);
176 if (*str
) ret
+= append_output( info
, str
, strlen( str
));
181 /***********************************************************************
182 * RtlExitUserThread (NTDLL.@)
184 void WINAPI
RtlExitUserThread( ULONG status
)
188 NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread
, &last
, sizeof(last
), NULL
);
189 if (last
) RtlExitUserProcess( status
);
191 for (;;) NtTerminateThread( GetCurrentThread(), status
);
195 /***********************************************************************
196 * RtlUserThreadStart (NTDLL.@)
199 __ASM_STDCALL_FUNC( RtlUserThreadStart
, 8,
200 "movl %ebx,8(%esp)\n\t" /* arg */
201 "movl %eax,4(%esp)\n\t" /* entry */
202 "jmp " __ASM_NAME("call_thread_func") )
204 /* wrapper to call BaseThreadInitThunk */
205 extern void DECLSPEC_NORETURN
call_thread_func_wrapper( void *thunk
, PRTL_THREAD_START_ROUTINE entry
, void *arg
);
206 __ASM_GLOBAL_FUNC( call_thread_func_wrapper
,
208 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
209 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
211 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
213 "andl $~0xf,%esp\n\t"
215 "movl 12(%ebp),%edx\n\t"
216 "movl 16(%ebp),%eax\n\t"
217 "movl %eax,(%esp)\n\t"
220 void DECLSPEC_HIDDEN
call_thread_func( PRTL_THREAD_START_ROUTINE entry
, void *arg
)
224 TRACE_(relay
)( "\1Starting thread proc %p (arg=%p)\n", entry
, arg
);
225 call_thread_func_wrapper( pBaseThreadInitThunk
, entry
, arg
);
227 __EXCEPT(call_unhandled_exception_filter
)
229 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
236 void WINAPI
RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry
, void *arg
)
240 TRACE_(relay
)( "\1Starting thread proc %p (arg=%p)\n", entry
, arg
);
241 pBaseThreadInitThunk( 0, (LPTHREAD_START_ROUTINE
)entry
, arg
);
243 __EXCEPT(call_unhandled_exception_filter
)
245 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
250 #endif /* __i386__ */
253 /***********************************************************************
254 * RtlCreateUserThread (NTDLL.@)
256 NTSTATUS WINAPI
RtlCreateUserThread( HANDLE process
, SECURITY_DESCRIPTOR
*descr
,
257 BOOLEAN suspended
, ULONG zero_bits
,
258 SIZE_T stack_reserve
, SIZE_T stack_commit
,
259 PRTL_THREAD_START_ROUTINE start
, void *param
,
260 HANDLE
*handle_ptr
, CLIENT_ID
*id
)
262 ULONG flags
= suspended
? THREAD_CREATE_FLAGS_CREATE_SUSPENDED
: 0;
263 ULONG_PTR buffer
[offsetof( PS_ATTRIBUTE_LIST
, Attributes
[2] ) / sizeof(ULONG_PTR
)];
264 PS_ATTRIBUTE_LIST
*attr_list
= (PS_ATTRIBUTE_LIST
*)buffer
;
265 HANDLE handle
, actctx
;
270 OBJECT_ATTRIBUTES attr
;
272 attr_list
->TotalLength
= sizeof(buffer
);
273 attr_list
->Attributes
[0].Attribute
= PS_ATTRIBUTE_CLIENT_ID
;
274 attr_list
->Attributes
[0].Size
= sizeof(client_id
);
275 attr_list
->Attributes
[0].ValuePtr
= &client_id
;
276 attr_list
->Attributes
[0].ReturnLength
= NULL
;
277 attr_list
->Attributes
[1].Attribute
= PS_ATTRIBUTE_TEB_ADDRESS
;
278 attr_list
->Attributes
[1].Size
= sizeof(teb
);
279 attr_list
->Attributes
[1].ValuePtr
= &teb
;
280 attr_list
->Attributes
[1].ReturnLength
= NULL
;
282 InitializeObjectAttributes( &attr
, NULL
, 0, NULL
, descr
);
284 RtlGetActiveActivationContext( &actctx
);
285 if (actctx
) flags
|= THREAD_CREATE_FLAGS_CREATE_SUSPENDED
;
287 status
= NtCreateThreadEx( &handle
, THREAD_ALL_ACCESS
, &attr
, process
, start
, param
,
288 flags
, zero_bits
, stack_commit
, stack_reserve
, attr_list
);
294 RtlActivateActivationContextEx( 0, teb
, actctx
, &cookie
);
295 if (!suspended
) NtResumeThread( handle
, &ret
);
297 if (id
) *id
= client_id
;
298 if (handle_ptr
) *handle_ptr
= handle
;
299 else NtClose( handle
);
301 if (actctx
) RtlReleaseActivationContext( actctx
);
306 /******************************************************************************
307 * RtlGetNtGlobalFlags (NTDLL.@)
309 ULONG WINAPI
RtlGetNtGlobalFlags(void)
311 return NtCurrentTeb()->Peb
->NtGlobalFlag
;
315 /******************************************************************************
316 * RtlPushFrame (NTDLL.@)
318 void WINAPI
RtlPushFrame( TEB_ACTIVE_FRAME
*frame
)
320 frame
->Previous
= NtCurrentTeb()->ActiveFrame
;
321 NtCurrentTeb()->ActiveFrame
= frame
;
325 /******************************************************************************
326 * RtlPopFrame (NTDLL.@)
328 void WINAPI
RtlPopFrame( TEB_ACTIVE_FRAME
*frame
)
330 NtCurrentTeb()->ActiveFrame
= frame
->Previous
;
334 /******************************************************************************
335 * RtlGetFrame (NTDLL.@)
337 TEB_ACTIVE_FRAME
* WINAPI
RtlGetFrame(void)
339 return NtCurrentTeb()->ActiveFrame
;
343 /***********************************************************************
345 ***********************************************************************/
348 static GLOBAL_FLS_DATA fls_data
= { { NULL
}, { &fls_data
.fls_list_head
, &fls_data
.fls_list_head
} };
350 static RTL_CRITICAL_SECTION fls_section
;
351 static RTL_CRITICAL_SECTION_DEBUG fls_critsect_debug
=
354 { &fls_critsect_debug
.ProcessLocksList
, &fls_critsect_debug
.ProcessLocksList
},
355 0, 0, { (DWORD_PTR
)(__FILE__
": fls_section") }
357 static RTL_CRITICAL_SECTION fls_section
= { &fls_critsect_debug
, -1, 0, 0, 0, 0 };
359 #define MAX_FLS_DATA_COUNT 0xff0
361 static void lock_fls_data(void)
363 RtlEnterCriticalSection( &fls_section
);
366 static void unlock_fls_data(void)
368 RtlLeaveCriticalSection( &fls_section
);
371 static unsigned int fls_chunk_size( unsigned int chunk_index
)
373 return 0x10 << chunk_index
;
376 static unsigned int fls_index_from_chunk_index( unsigned int chunk_index
, unsigned int index
)
378 return 0x10 * ((1 << chunk_index
) - 1) + index
;
381 static unsigned int fls_chunk_index_from_index( unsigned int index
, unsigned int *index_in_chunk
)
383 unsigned int chunk_index
= 0;
385 while (index
>= fls_chunk_size( chunk_index
))
386 index
-= fls_chunk_size( chunk_index
++ );
388 *index_in_chunk
= index
;
392 TEB_FLS_DATA
*fls_alloc_data(void)
396 if (!(fls
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*fls
) )))
400 InsertTailList( &fls_data
.fls_list_head
, &fls
->fls_list_entry
);
407 /***********************************************************************
408 * RtlFlsAlloc (NTDLL.@)
410 NTSTATUS WINAPI DECLSPEC_HOTPATCH
RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback
, ULONG
*ret_index
)
412 unsigned int chunk_index
, index
, i
;
413 FLS_INFO_CHUNK
*chunk
;
416 if (!(fls
= NtCurrentTeb()->FlsSlots
)
417 && !(NtCurrentTeb()->FlsSlots
= fls
= fls_alloc_data()))
418 return STATUS_NO_MEMORY
;
421 for (i
= 0; i
< ARRAY_SIZE(fls_data
.fls_callback_chunks
); ++i
)
423 if (!fls_data
.fls_callback_chunks
[i
] || fls_data
.fls_callback_chunks
[i
]->count
< fls_chunk_size( i
))
427 if ((chunk_index
= i
) == ARRAY_SIZE(fls_data
.fls_callback_chunks
))
430 return STATUS_NO_MEMORY
;
433 if ((chunk
= fls_data
.fls_callback_chunks
[chunk_index
]))
435 for (index
= 0; index
< fls_chunk_size( chunk_index
); ++index
)
436 if (!chunk
->callbacks
[index
].callback
)
438 assert( index
< fls_chunk_size( chunk_index
));
442 fls_data
.fls_callback_chunks
[chunk_index
] = chunk
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
,
443 offsetof(FLS_INFO_CHUNK
, callbacks
) + sizeof(*chunk
->callbacks
) * fls_chunk_size( chunk_index
));
447 return STATUS_NO_MEMORY
;
456 chunk
->count
= 1; /* FLS index 0 is prohibited. */
457 chunk
->callbacks
[0].callback
= (void *)~(ULONG_PTR
)0;
463 chunk
->callbacks
[index
].callback
= callback
? callback
: (PFLS_CALLBACK_FUNCTION
)~(ULONG_PTR
)0;
465 if ((*ret_index
= fls_index_from_chunk_index( chunk_index
, index
)) > fls_data
.fls_high_index
)
466 fls_data
.fls_high_index
= *ret_index
;
470 return STATUS_SUCCESS
;
474 /***********************************************************************
475 * RtlFlsFree (NTDLL.@)
477 NTSTATUS WINAPI DECLSPEC_HOTPATCH
RtlFlsFree( ULONG index
)
479 PFLS_CALLBACK_FUNCTION callback
;
480 unsigned int chunk_index
, idx
;
481 FLS_INFO_CHUNK
*chunk
;
486 if (!index
|| index
> fls_data
.fls_high_index
)
489 return STATUS_INVALID_PARAMETER
;
492 chunk_index
= fls_chunk_index_from_index( index
, &idx
);
493 if (!(chunk
= fls_data
.fls_callback_chunks
[chunk_index
])
494 || !(callback
= chunk
->callbacks
[idx
].callback
))
497 return STATUS_INVALID_PARAMETER
;
500 for (entry
= fls_data
.fls_list_head
.Flink
; entry
!= &fls_data
.fls_list_head
; entry
= entry
->Flink
)
502 TEB_FLS_DATA
*fls
= CONTAINING_RECORD(entry
, TEB_FLS_DATA
, fls_list_entry
);
504 if (fls
->fls_data_chunks
[chunk_index
] && fls
->fls_data_chunks
[chunk_index
][idx
+ 1])
506 if (callback
!= (void *)~(ULONG_PTR
)0)
508 TRACE_(relay
)("Calling FLS callback %p, arg %p.\n", callback
,
509 fls
->fls_data_chunks
[chunk_index
][idx
+ 1]);
511 callback( fls
->fls_data_chunks
[chunk_index
][idx
+ 1] );
513 fls
->fls_data_chunks
[chunk_index
][idx
+ 1] = NULL
;
518 chunk
->callbacks
[idx
].callback
= NULL
;
521 return STATUS_SUCCESS
;
525 /***********************************************************************
526 * RtlFlsSetValue (NTDLL.@)
528 NTSTATUS WINAPI DECLSPEC_HOTPATCH
RtlFlsSetValue( ULONG index
, void *data
)
530 unsigned int chunk_index
, idx
;
533 if (!index
|| index
>= MAX_FLS_DATA_COUNT
)
534 return STATUS_INVALID_PARAMETER
;
536 if (!(fls
= NtCurrentTeb()->FlsSlots
)
537 && !(NtCurrentTeb()->FlsSlots
= fls
= fls_alloc_data()))
538 return STATUS_NO_MEMORY
;
540 chunk_index
= fls_chunk_index_from_index( index
, &idx
);
542 if (!fls
->fls_data_chunks
[chunk_index
] &&
543 !(fls
->fls_data_chunks
[chunk_index
] = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
,
544 (fls_chunk_size( chunk_index
) + 1) * sizeof(*fls
->fls_data_chunks
[chunk_index
]) )))
545 return STATUS_NO_MEMORY
;
547 fls
->fls_data_chunks
[chunk_index
][idx
+ 1] = data
;
549 return STATUS_SUCCESS
;
553 /***********************************************************************
554 * RtlFlsGetValue (NTDLL.@)
556 NTSTATUS WINAPI DECLSPEC_HOTPATCH
RtlFlsGetValue( ULONG index
, void **data
)
558 unsigned int chunk_index
, idx
;
561 if (!index
|| index
>= MAX_FLS_DATA_COUNT
|| !(fls
= NtCurrentTeb()->FlsSlots
))
562 return STATUS_INVALID_PARAMETER
;
564 chunk_index
= fls_chunk_index_from_index( index
, &idx
);
566 *data
= fls
->fls_data_chunks
[chunk_index
] ? fls
->fls_data_chunks
[chunk_index
][idx
+ 1] : NULL
;
567 return STATUS_SUCCESS
;
571 /***********************************************************************
572 * RtlProcessFlsData (NTDLL.@)
574 void WINAPI DECLSPEC_HOTPATCH
RtlProcessFlsData( void *teb_fls_data
, ULONG flags
)
576 TEB_FLS_DATA
*fls
= teb_fls_data
;
577 unsigned int i
, index
;
579 TRACE_(thread
)( "teb_fls_data %p, flags %#x.\n", teb_fls_data
, flags
);
582 FIXME_(thread
)( "Unknown flags %#x.\n", flags
);
590 for (i
= 0; i
< ARRAY_SIZE(fls
->fls_data_chunks
); ++i
)
592 if (!fls
->fls_data_chunks
[i
] || !fls_data
.fls_callback_chunks
[i
]
593 || !fls_data
.fls_callback_chunks
[i
]->count
)
596 for (index
= 0; index
< fls_chunk_size( i
); ++index
)
598 PFLS_CALLBACK_FUNCTION callback
= fls_data
.fls_callback_chunks
[i
]->callbacks
[index
].callback
;
600 if (!fls
->fls_data_chunks
[i
][index
+ 1])
603 if (callback
&& callback
!= (void *)~(ULONG_PTR
)0)
605 TRACE_(relay
)("Calling FLS callback %p, arg %p.\n", callback
,
606 fls
->fls_data_chunks
[i
][index
+ 1]);
608 callback( fls
->fls_data_chunks
[i
][index
+ 1] );
610 fls
->fls_data_chunks
[i
][index
+ 1] = NULL
;
613 /* Not using RemoveEntryList() as Windows does not zero list entry here. */
614 fls
->fls_list_entry
.Flink
->Blink
= fls
->fls_list_entry
.Blink
;
615 fls
->fls_list_entry
.Blink
->Flink
= fls
->fls_list_entry
.Flink
;
621 for (i
= 0; i
< ARRAY_SIZE(fls
->fls_data_chunks
); ++i
)
622 RtlFreeHeap( GetProcessHeap(), 0, fls
->fls_data_chunks
[i
] );
624 RtlFreeHeap( GetProcessHeap(), 0, fls
);