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
37 #include <sys/types.h>
40 #ifdef HAVE_SYS_TIMES_H
41 #include <sys/times.h>
43 #ifdef HAVE_SYS_SYSCALL_H
44 #include <sys/syscall.h>
46 #ifdef HAVE_SYS_SYSCTL_H
47 #include <sys/sysctl.h>
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h>
52 #ifdef HAVE_SYS_QUEUE_H
53 #include <sys/queue.h>
55 #ifdef HAVE_SYS_USER_H
58 #ifdef HAVE_LIBPROCSTAT_H
59 #include <libprocstat.h>
63 #include <mach/mach.h>
67 #define WIN32_NO_STATUS
70 #include "wine/server.h"
71 #include "wine/debug.h"
72 #include "unix_private.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(thread
);
75 WINE_DECLARE_DEBUG_CHANNEL(seh
);
76 WINE_DECLARE_DEBUG_CHANNEL(threadname
);
78 pthread_key_t teb_key
= 0;
80 static LONG nb_threads
= 1;
82 static inline int get_unix_exit_code( NTSTATUS status
)
84 /* prevent a nonzero exit code to end up truncated to zero in unix */
85 if (status
&& !(status
& 0xff)) return 1;
90 /***********************************************************************
93 * Build a standard i386 FPU context from an extended one.
95 void fpux_to_fpu( I386_FLOATING_SAVE_AREA
*fpu
, const XMM_SAVE_AREA32
*fpux
)
97 unsigned int i
, tag
, stack_top
;
99 fpu
->ControlWord
= fpux
->ControlWord
;
100 fpu
->StatusWord
= fpux
->StatusWord
;
101 fpu
->ErrorOffset
= fpux
->ErrorOffset
;
102 fpu
->ErrorSelector
= fpux
->ErrorSelector
| (fpux
->ErrorOpcode
<< 16);
103 fpu
->DataOffset
= fpux
->DataOffset
;
104 fpu
->DataSelector
= fpux
->DataSelector
;
105 fpu
->Cr0NpxState
= fpux
->StatusWord
| 0xffff0000;
107 stack_top
= (fpux
->StatusWord
>> 11) & 7;
108 fpu
->TagWord
= 0xffff0000;
109 for (i
= 0; i
< 8; i
++)
111 memcpy( &fpu
->RegisterArea
[10 * i
], &fpux
->FloatRegisters
[i
], 10 );
112 if (!(fpux
->TagWord
& (1 << i
))) tag
= 3; /* empty */
115 const M128A
*reg
= &fpux
->FloatRegisters
[(i
- stack_top
) & 7];
116 if ((reg
->High
& 0x7fff) == 0x7fff) /* exponent all ones */
118 tag
= 2; /* special */
120 else if (!(reg
->High
& 0x7fff)) /* exponent all zeroes */
122 if (reg
->Low
) tag
= 2; /* special */
123 else tag
= 1; /* zero */
127 if (reg
->Low
>> 63) tag
= 0; /* valid */
128 else tag
= 2; /* special */
131 fpu
->TagWord
|= tag
<< (2 * i
);
136 /***********************************************************************
139 * Fill extended i386 FPU context from standard one.
141 void fpu_to_fpux( XMM_SAVE_AREA32
*fpux
, const I386_FLOATING_SAVE_AREA
*fpu
)
145 fpux
->ControlWord
= fpu
->ControlWord
;
146 fpux
->StatusWord
= fpu
->StatusWord
;
147 fpux
->ErrorOffset
= fpu
->ErrorOffset
;
148 fpux
->ErrorSelector
= fpu
->ErrorSelector
;
149 fpux
->ErrorOpcode
= fpu
->ErrorSelector
>> 16;
150 fpux
->DataOffset
= fpu
->DataOffset
;
151 fpux
->DataSelector
= fpu
->DataSelector
;
153 for (i
= 0; i
< 8; i
++)
155 if (((fpu
->TagWord
>> (i
* 2)) & 3) != 3) fpux
->TagWord
|= 1 << i
;
156 memcpy( &fpux
->FloatRegisters
[i
], &fpu
->RegisterArea
[10 * i
], 10 );
161 /***********************************************************************
162 * get_server_context_flags
164 static unsigned int get_server_context_flags( const void *context
, USHORT machine
)
166 unsigned int flags
, ret
= 0;
170 case IMAGE_FILE_MACHINE_I386
:
171 flags
= ((const I386_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_i386
;
172 if (flags
& CONTEXT_I386_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
173 if (flags
& CONTEXT_I386_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
174 if (flags
& CONTEXT_I386_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
175 if (flags
& CONTEXT_I386_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
176 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
177 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
) ret
|= SERVER_CTX_EXTENDED_REGISTERS
| SERVER_CTX_FLOATING_POINT
;
178 if (flags
& CONTEXT_I386_XSTATE
) ret
|= SERVER_CTX_YMM_REGISTERS
;
180 case IMAGE_FILE_MACHINE_AMD64
:
181 flags
= ((const AMD64_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_AMD64
;
182 if (flags
& CONTEXT_AMD64_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
183 if (flags
& CONTEXT_AMD64_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
184 if (flags
& CONTEXT_AMD64_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
185 if (flags
& CONTEXT_AMD64_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
186 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
187 if (flags
& CONTEXT_AMD64_XSTATE
) ret
|= SERVER_CTX_YMM_REGISTERS
;
189 case IMAGE_FILE_MACHINE_ARMNT
:
190 flags
= ((const ARM_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_ARM
;
191 if (flags
& CONTEXT_ARM_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
192 if (flags
& CONTEXT_ARM_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
193 if (flags
& CONTEXT_ARM_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
194 if (flags
& CONTEXT_ARM_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
196 case IMAGE_FILE_MACHINE_ARM64
:
197 flags
= ((const ARM64_NT_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_ARM64
;
198 if (flags
& CONTEXT_ARM64_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
199 if (flags
& CONTEXT_ARM64_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
200 if (flags
& CONTEXT_ARM64_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
201 if (flags
& CONTEXT_ARM64_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
208 /***********************************************************************
209 * get_native_context_flags
211 * Get flags for registers that are set from the native context in WoW mode.
213 static unsigned int get_native_context_flags( USHORT native_machine
, USHORT wow_machine
)
215 switch (MAKELONG( native_machine
, wow_machine
))
217 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_I386
):
218 return SERVER_CTX_DEBUG_REGISTERS
| SERVER_CTX_FLOATING_POINT
| SERVER_CTX_YMM_REGISTERS
;
219 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_ARMNT
):
220 return SERVER_CTX_DEBUG_REGISTERS
| SERVER_CTX_FLOATING_POINT
;
227 /***********************************************************************
230 * Convert a register context to the server format.
232 static NTSTATUS
context_to_server( context_t
*to
, USHORT to_machine
, const void *src
, USHORT from_machine
)
236 memset( to
, 0, sizeof(*to
) );
237 to
->machine
= to_machine
;
239 switch (MAKELONG( from_machine
, to_machine
))
241 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_I386
):
243 const I386_CONTEXT
*from
= src
;
245 flags
= from
->ContextFlags
& ~CONTEXT_i386
;
246 if (flags
& CONTEXT_I386_CONTROL
)
248 to
->flags
|= SERVER_CTX_CONTROL
;
249 to
->ctl
.i386_regs
.ebp
= from
->Ebp
;
250 to
->ctl
.i386_regs
.esp
= from
->Esp
;
251 to
->ctl
.i386_regs
.eip
= from
->Eip
;
252 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
253 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
254 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
256 if (flags
& CONTEXT_I386_INTEGER
)
258 to
->flags
|= SERVER_CTX_INTEGER
;
259 to
->integer
.i386_regs
.eax
= from
->Eax
;
260 to
->integer
.i386_regs
.ebx
= from
->Ebx
;
261 to
->integer
.i386_regs
.ecx
= from
->Ecx
;
262 to
->integer
.i386_regs
.edx
= from
->Edx
;
263 to
->integer
.i386_regs
.esi
= from
->Esi
;
264 to
->integer
.i386_regs
.edi
= from
->Edi
;
266 if (flags
& CONTEXT_I386_SEGMENTS
)
268 to
->flags
|= SERVER_CTX_SEGMENTS
;
269 to
->seg
.i386_regs
.ds
= from
->SegDs
;
270 to
->seg
.i386_regs
.es
= from
->SegEs
;
271 to
->seg
.i386_regs
.fs
= from
->SegFs
;
272 to
->seg
.i386_regs
.gs
= from
->SegGs
;
274 if (flags
& CONTEXT_I386_FLOATING_POINT
)
276 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
277 to
->fp
.i386_regs
.ctrl
= from
->FloatSave
.ControlWord
;
278 to
->fp
.i386_regs
.status
= from
->FloatSave
.StatusWord
;
279 to
->fp
.i386_regs
.tag
= from
->FloatSave
.TagWord
;
280 to
->fp
.i386_regs
.err_off
= from
->FloatSave
.ErrorOffset
;
281 to
->fp
.i386_regs
.err_sel
= from
->FloatSave
.ErrorSelector
;
282 to
->fp
.i386_regs
.data_off
= from
->FloatSave
.DataOffset
;
283 to
->fp
.i386_regs
.data_sel
= from
->FloatSave
.DataSelector
;
284 to
->fp
.i386_regs
.cr0npx
= from
->FloatSave
.Cr0NpxState
;
285 memcpy( to
->fp
.i386_regs
.regs
, from
->FloatSave
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
287 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
)
289 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
290 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
291 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
292 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
293 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
294 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
295 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
297 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
299 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
;
300 memcpy( to
->ext
.i386_regs
, from
->ExtendedRegisters
, sizeof(to
->ext
.i386_regs
) );
302 if (flags
& CONTEXT_I386_XSTATE
)
304 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
305 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
307 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
308 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
310 return STATUS_SUCCESS
;
313 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_AMD64
):
315 const I386_CONTEXT
*from
= src
;
317 flags
= from
->ContextFlags
& ~CONTEXT_i386
;
318 if (flags
& CONTEXT_I386_CONTROL
)
320 to
->flags
|= SERVER_CTX_CONTROL
;
321 to
->ctl
.x86_64_regs
.rbp
= from
->Ebp
;
322 to
->ctl
.x86_64_regs
.rsp
= from
->Esp
;
323 to
->ctl
.x86_64_regs
.rip
= from
->Eip
;
324 to
->ctl
.x86_64_regs
.cs
= from
->SegCs
;
325 to
->ctl
.x86_64_regs
.ss
= from
->SegSs
;
326 to
->ctl
.x86_64_regs
.flags
= from
->EFlags
;
328 if (flags
& CONTEXT_I386_INTEGER
)
330 to
->flags
|= SERVER_CTX_INTEGER
;
331 to
->integer
.x86_64_regs
.rax
= from
->Eax
;
332 to
->integer
.x86_64_regs
.rbx
= from
->Ebx
;
333 to
->integer
.x86_64_regs
.rcx
= from
->Ecx
;
334 to
->integer
.x86_64_regs
.rdx
= from
->Edx
;
335 to
->integer
.x86_64_regs
.rsi
= from
->Esi
;
336 to
->integer
.x86_64_regs
.rdi
= from
->Edi
;
338 if (flags
& CONTEXT_I386_SEGMENTS
)
340 to
->flags
|= SERVER_CTX_SEGMENTS
;
341 to
->seg
.x86_64_regs
.ds
= from
->SegDs
;
342 to
->seg
.x86_64_regs
.es
= from
->SegEs
;
343 to
->seg
.x86_64_regs
.fs
= from
->SegFs
;
344 to
->seg
.x86_64_regs
.gs
= from
->SegGs
;
346 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
)
348 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
349 to
->debug
.x86_64_regs
.dr0
= from
->Dr0
;
350 to
->debug
.x86_64_regs
.dr1
= from
->Dr1
;
351 to
->debug
.x86_64_regs
.dr2
= from
->Dr2
;
352 to
->debug
.x86_64_regs
.dr3
= from
->Dr3
;
353 to
->debug
.x86_64_regs
.dr6
= from
->Dr6
;
354 to
->debug
.x86_64_regs
.dr7
= from
->Dr7
;
356 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
358 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
359 memcpy( to
->fp
.x86_64_regs
.fpregs
, from
->ExtendedRegisters
, sizeof(to
->fp
.x86_64_regs
.fpregs
) );
361 else if (flags
& CONTEXT_I386_FLOATING_POINT
)
363 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
364 fpu_to_fpux( (XMM_SAVE_AREA32
*)to
->fp
.x86_64_regs
.fpregs
, &from
->FloatSave
);
366 if (flags
& CONTEXT_I386_XSTATE
)
368 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
369 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
371 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
372 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
374 return STATUS_SUCCESS
;
377 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_AMD64
):
379 const AMD64_CONTEXT
*from
= src
;
381 flags
= from
->ContextFlags
& ~CONTEXT_AMD64
;
382 if (flags
& CONTEXT_AMD64_CONTROL
)
384 to
->flags
|= SERVER_CTX_CONTROL
;
385 to
->ctl
.x86_64_regs
.rbp
= from
->Rbp
;
386 to
->ctl
.x86_64_regs
.rip
= from
->Rip
;
387 to
->ctl
.x86_64_regs
.rsp
= from
->Rsp
;
388 to
->ctl
.x86_64_regs
.cs
= from
->SegCs
;
389 to
->ctl
.x86_64_regs
.ss
= from
->SegSs
;
390 to
->ctl
.x86_64_regs
.flags
= from
->EFlags
;
392 if (flags
& CONTEXT_AMD64_INTEGER
)
394 to
->flags
|= SERVER_CTX_INTEGER
;
395 to
->integer
.x86_64_regs
.rax
= from
->Rax
;
396 to
->integer
.x86_64_regs
.rcx
= from
->Rcx
;
397 to
->integer
.x86_64_regs
.rdx
= from
->Rdx
;
398 to
->integer
.x86_64_regs
.rbx
= from
->Rbx
;
399 to
->integer
.x86_64_regs
.rsi
= from
->Rsi
;
400 to
->integer
.x86_64_regs
.rdi
= from
->Rdi
;
401 to
->integer
.x86_64_regs
.r8
= from
->R8
;
402 to
->integer
.x86_64_regs
.r9
= from
->R9
;
403 to
->integer
.x86_64_regs
.r10
= from
->R10
;
404 to
->integer
.x86_64_regs
.r11
= from
->R11
;
405 to
->integer
.x86_64_regs
.r12
= from
->R12
;
406 to
->integer
.x86_64_regs
.r13
= from
->R13
;
407 to
->integer
.x86_64_regs
.r14
= from
->R14
;
408 to
->integer
.x86_64_regs
.r15
= from
->R15
;
410 if (flags
& CONTEXT_AMD64_SEGMENTS
)
412 to
->flags
|= SERVER_CTX_SEGMENTS
;
413 to
->seg
.x86_64_regs
.ds
= from
->SegDs
;
414 to
->seg
.x86_64_regs
.es
= from
->SegEs
;
415 to
->seg
.x86_64_regs
.fs
= from
->SegFs
;
416 to
->seg
.x86_64_regs
.gs
= from
->SegGs
;
418 if (flags
& CONTEXT_AMD64_FLOATING_POINT
)
420 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
421 memcpy( to
->fp
.x86_64_regs
.fpregs
, &from
->FltSave
, sizeof(to
->fp
.x86_64_regs
.fpregs
) );
423 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
)
425 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
426 to
->debug
.x86_64_regs
.dr0
= from
->Dr0
;
427 to
->debug
.x86_64_regs
.dr1
= from
->Dr1
;
428 to
->debug
.x86_64_regs
.dr2
= from
->Dr2
;
429 to
->debug
.x86_64_regs
.dr3
= from
->Dr3
;
430 to
->debug
.x86_64_regs
.dr6
= from
->Dr6
;
431 to
->debug
.x86_64_regs
.dr7
= from
->Dr7
;
433 if (flags
& CONTEXT_AMD64_XSTATE
)
435 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
436 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
438 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
439 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
441 return STATUS_SUCCESS
;
444 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_I386
):
446 const AMD64_CONTEXT
*from
= src
;
448 flags
= from
->ContextFlags
& ~CONTEXT_AMD64
;
449 if (flags
& CONTEXT_AMD64_CONTROL
)
451 to
->flags
|= SERVER_CTX_CONTROL
;
452 to
->ctl
.i386_regs
.ebp
= from
->Rbp
;
453 to
->ctl
.i386_regs
.eip
= from
->Rip
;
454 to
->ctl
.i386_regs
.esp
= from
->Rsp
;
455 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
456 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
457 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
459 if (flags
& CONTEXT_AMD64_INTEGER
)
461 to
->flags
|= SERVER_CTX_INTEGER
;
462 to
->integer
.i386_regs
.eax
= from
->Rax
;
463 to
->integer
.i386_regs
.ecx
= from
->Rcx
;
464 to
->integer
.i386_regs
.edx
= from
->Rdx
;
465 to
->integer
.i386_regs
.ebx
= from
->Rbx
;
466 to
->integer
.i386_regs
.esi
= from
->Rsi
;
467 to
->integer
.i386_regs
.edi
= from
->Rdi
;
469 if (flags
& CONTEXT_AMD64_SEGMENTS
)
471 to
->flags
|= SERVER_CTX_SEGMENTS
;
472 to
->seg
.i386_regs
.ds
= from
->SegDs
;
473 to
->seg
.i386_regs
.es
= from
->SegEs
;
474 to
->seg
.i386_regs
.fs
= from
->SegFs
;
475 to
->seg
.i386_regs
.gs
= from
->SegGs
;
477 if (flags
& CONTEXT_AMD64_FLOATING_POINT
)
479 I386_FLOATING_SAVE_AREA fpu
;
481 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
| SERVER_CTX_FLOATING_POINT
;
482 memcpy( to
->ext
.i386_regs
, &from
->FltSave
, sizeof(to
->ext
.i386_regs
) );
483 fpux_to_fpu( &fpu
, &from
->FltSave
);
484 to
->fp
.i386_regs
.ctrl
= fpu
.ControlWord
;
485 to
->fp
.i386_regs
.status
= fpu
.StatusWord
;
486 to
->fp
.i386_regs
.tag
= fpu
.TagWord
;
487 to
->fp
.i386_regs
.err_off
= fpu
.ErrorOffset
;
488 to
->fp
.i386_regs
.err_sel
= fpu
.ErrorSelector
;
489 to
->fp
.i386_regs
.data_off
= fpu
.DataOffset
;
490 to
->fp
.i386_regs
.data_sel
= fpu
.DataSelector
;
491 to
->fp
.i386_regs
.cr0npx
= fpu
.Cr0NpxState
;
492 memcpy( to
->fp
.i386_regs
.regs
, fpu
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
494 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
)
496 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
497 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
498 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
499 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
500 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
501 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
502 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
504 if (flags
& CONTEXT_AMD64_XSTATE
)
506 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
507 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
509 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
510 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
512 return STATUS_SUCCESS
;
515 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT
, IMAGE_FILE_MACHINE_ARMNT
):
517 const ARM_CONTEXT
*from
= src
;
519 flags
= from
->ContextFlags
& ~CONTEXT_ARM
;
520 if (flags
& CONTEXT_ARM_CONTROL
)
522 to
->flags
|= SERVER_CTX_CONTROL
;
523 to
->ctl
.arm_regs
.sp
= from
->Sp
;
524 to
->ctl
.arm_regs
.lr
= from
->Lr
;
525 to
->ctl
.arm_regs
.pc
= from
->Pc
;
526 to
->ctl
.arm_regs
.cpsr
= from
->Cpsr
;
528 if (flags
& CONTEXT_ARM_INTEGER
)
530 to
->flags
|= SERVER_CTX_INTEGER
;
531 to
->integer
.arm_regs
.r
[0] = from
->R0
;
532 to
->integer
.arm_regs
.r
[1] = from
->R1
;
533 to
->integer
.arm_regs
.r
[2] = from
->R2
;
534 to
->integer
.arm_regs
.r
[3] = from
->R3
;
535 to
->integer
.arm_regs
.r
[4] = from
->R4
;
536 to
->integer
.arm_regs
.r
[5] = from
->R5
;
537 to
->integer
.arm_regs
.r
[6] = from
->R6
;
538 to
->integer
.arm_regs
.r
[7] = from
->R7
;
539 to
->integer
.arm_regs
.r
[8] = from
->R8
;
540 to
->integer
.arm_regs
.r
[9] = from
->R9
;
541 to
->integer
.arm_regs
.r
[10] = from
->R10
;
542 to
->integer
.arm_regs
.r
[11] = from
->R11
;
543 to
->integer
.arm_regs
.r
[12] = from
->R12
;
545 if (flags
& CONTEXT_ARM_FLOATING_POINT
)
547 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
548 for (i
= 0; i
< 32; i
++) to
->fp
.arm_regs
.d
[i
] = from
->D
[i
];
549 to
->fp
.arm_regs
.fpscr
= from
->Fpscr
;
551 if (flags
& CONTEXT_ARM_DEBUG_REGISTERS
)
553 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
554 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->debug
.arm_regs
.bvr
[i
] = from
->Bvr
[i
];
555 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->debug
.arm_regs
.bcr
[i
] = from
->Bcr
[i
];
556 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->debug
.arm_regs
.wvr
[i
] = from
->Wvr
[i
];
557 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->debug
.arm_regs
.wcr
[i
] = from
->Wcr
[i
];
559 return STATUS_SUCCESS
;
562 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_ARM64
):
564 const ARM64_NT_CONTEXT
*from
= src
;
566 flags
= from
->ContextFlags
& ~CONTEXT_ARM64
;
567 if (flags
& CONTEXT_ARM64_CONTROL
)
569 to
->flags
|= SERVER_CTX_CONTROL
;
570 to
->integer
.arm64_regs
.x
[29] = from
->Fp
;
571 to
->integer
.arm64_regs
.x
[30] = from
->Lr
;
572 to
->ctl
.arm64_regs
.sp
= from
->Sp
;
573 to
->ctl
.arm64_regs
.pc
= from
->Pc
;
574 to
->ctl
.arm64_regs
.pstate
= from
->Cpsr
;
576 if (flags
& CONTEXT_ARM64_INTEGER
)
578 to
->flags
|= SERVER_CTX_INTEGER
;
579 for (i
= 0; i
<= 28; i
++) to
->integer
.arm64_regs
.x
[i
] = from
->X
[i
];
581 if (flags
& CONTEXT_ARM64_FLOATING_POINT
)
583 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
584 for (i
= 0; i
< 32; i
++)
586 to
->fp
.arm64_regs
.q
[i
].low
= from
->V
[i
].Low
;
587 to
->fp
.arm64_regs
.q
[i
].high
= from
->V
[i
].High
;
589 to
->fp
.arm64_regs
.fpcr
= from
->Fpcr
;
590 to
->fp
.arm64_regs
.fpsr
= from
->Fpsr
;
592 if (flags
& CONTEXT_ARM64_DEBUG_REGISTERS
)
594 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
595 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->debug
.arm64_regs
.bcr
[i
] = from
->Bcr
[i
];
596 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->debug
.arm64_regs
.bvr
[i
] = from
->Bvr
[i
];
597 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->debug
.arm64_regs
.wcr
[i
] = from
->Wcr
[i
];
598 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->debug
.arm64_regs
.wvr
[i
] = from
->Wvr
[i
];
600 return STATUS_SUCCESS
;
603 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_I386
):
604 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_ARM64
):
605 return STATUS_SUCCESS
;
608 return STATUS_INVALID_PARAMETER
;
613 /***********************************************************************
614 * context_from_server
616 * Convert a register context from the server format.
618 static NTSTATUS
context_from_server( void *dst
, const context_t
*from
, USHORT machine
)
622 switch (MAKELONG( from
->machine
, machine
))
624 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_I386
):
626 I386_CONTEXT
*to
= dst
;
628 to_flags
= to
->ContextFlags
& ~CONTEXT_i386
;
629 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_I386_CONTROL
))
631 to
->ContextFlags
|= CONTEXT_I386_CONTROL
;
632 to
->Ebp
= from
->ctl
.i386_regs
.ebp
;
633 to
->Esp
= from
->ctl
.i386_regs
.esp
;
634 to
->Eip
= from
->ctl
.i386_regs
.eip
;
635 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
636 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
637 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
639 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_I386_INTEGER
))
641 to
->ContextFlags
|= CONTEXT_I386_INTEGER
;
642 to
->Eax
= from
->integer
.i386_regs
.eax
;
643 to
->Ebx
= from
->integer
.i386_regs
.ebx
;
644 to
->Ecx
= from
->integer
.i386_regs
.ecx
;
645 to
->Edx
= from
->integer
.i386_regs
.edx
;
646 to
->Esi
= from
->integer
.i386_regs
.esi
;
647 to
->Edi
= from
->integer
.i386_regs
.edi
;
649 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_I386_SEGMENTS
))
651 to
->ContextFlags
|= CONTEXT_I386_SEGMENTS
;
652 to
->SegDs
= from
->seg
.i386_regs
.ds
;
653 to
->SegEs
= from
->seg
.i386_regs
.es
;
654 to
->SegFs
= from
->seg
.i386_regs
.fs
;
655 to
->SegGs
= from
->seg
.i386_regs
.gs
;
657 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_I386_FLOATING_POINT
))
659 to
->ContextFlags
|= CONTEXT_I386_FLOATING_POINT
;
660 to
->FloatSave
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
661 to
->FloatSave
.StatusWord
= from
->fp
.i386_regs
.status
;
662 to
->FloatSave
.TagWord
= from
->fp
.i386_regs
.tag
;
663 to
->FloatSave
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
664 to
->FloatSave
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
665 to
->FloatSave
.DataOffset
= from
->fp
.i386_regs
.data_off
;
666 to
->FloatSave
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
667 to
->FloatSave
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
668 memcpy( to
->FloatSave
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(to
->FloatSave
.RegisterArea
) );
670 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_I386_DEBUG_REGISTERS
))
672 to
->ContextFlags
|= CONTEXT_I386_DEBUG_REGISTERS
;
673 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
674 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
675 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
676 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
677 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
678 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
680 if ((from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
) && (to_flags
& CONTEXT_I386_EXTENDED_REGISTERS
))
682 to
->ContextFlags
|= CONTEXT_I386_EXTENDED_REGISTERS
;
683 memcpy( to
->ExtendedRegisters
, from
->ext
.i386_regs
, sizeof(to
->ExtendedRegisters
) );
685 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_I386_XSTATE
))
687 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
688 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
691 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
692 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
694 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
695 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
700 return STATUS_SUCCESS
;
703 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_I386
):
705 I386_CONTEXT
*to
= dst
;
707 to_flags
= to
->ContextFlags
& ~CONTEXT_i386
;
708 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_I386_CONTROL
))
710 to
->ContextFlags
|= CONTEXT_I386_CONTROL
;
711 to
->Ebp
= from
->ctl
.x86_64_regs
.rbp
;
712 to
->Esp
= from
->ctl
.x86_64_regs
.rsp
;
713 to
->Eip
= from
->ctl
.x86_64_regs
.rip
;
714 to
->SegCs
= from
->ctl
.x86_64_regs
.cs
;
715 to
->SegSs
= from
->ctl
.x86_64_regs
.ss
;
716 to
->EFlags
= from
->ctl
.x86_64_regs
.flags
;
718 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_I386_INTEGER
))
720 to
->ContextFlags
|= CONTEXT_I386_INTEGER
;
721 to
->Eax
= from
->integer
.x86_64_regs
.rax
;
722 to
->Ebx
= from
->integer
.x86_64_regs
.rbx
;
723 to
->Ecx
= from
->integer
.x86_64_regs
.rcx
;
724 to
->Edx
= from
->integer
.x86_64_regs
.rdx
;
725 to
->Esi
= from
->integer
.x86_64_regs
.rsi
;
726 to
->Edi
= from
->integer
.x86_64_regs
.rdi
;
728 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_I386_SEGMENTS
))
730 to
->ContextFlags
|= CONTEXT_I386_SEGMENTS
;
731 to
->SegDs
= from
->seg
.x86_64_regs
.ds
;
732 to
->SegEs
= from
->seg
.x86_64_regs
.es
;
733 to
->SegFs
= from
->seg
.x86_64_regs
.fs
;
734 to
->SegGs
= from
->seg
.x86_64_regs
.gs
;
736 if (from
->flags
& SERVER_CTX_FLOATING_POINT
)
738 if (to_flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
740 to
->ContextFlags
|= CONTEXT_I386_EXTENDED_REGISTERS
;
741 memcpy( to
->ExtendedRegisters
, from
->fp
.x86_64_regs
.fpregs
, sizeof(to
->ExtendedRegisters
) );
743 if (to_flags
& CONTEXT_I386_FLOATING_POINT
)
745 to
->ContextFlags
|= CONTEXT_I386_FLOATING_POINT
;
746 fpux_to_fpu( &to
->FloatSave
, (XMM_SAVE_AREA32
*)from
->fp
.x86_64_regs
.fpregs
);
749 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_I386_DEBUG_REGISTERS
))
751 to
->ContextFlags
|= CONTEXT_I386_DEBUG_REGISTERS
;
752 to
->Dr0
= from
->debug
.x86_64_regs
.dr0
;
753 to
->Dr1
= from
->debug
.x86_64_regs
.dr1
;
754 to
->Dr2
= from
->debug
.x86_64_regs
.dr2
;
755 to
->Dr3
= from
->debug
.x86_64_regs
.dr3
;
756 to
->Dr6
= from
->debug
.x86_64_regs
.dr6
;
757 to
->Dr7
= from
->debug
.x86_64_regs
.dr7
;
759 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_I386_XSTATE
))
761 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
762 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
765 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
766 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
768 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
769 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
774 return STATUS_SUCCESS
;
777 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_AMD64
):
779 AMD64_CONTEXT
*to
= dst
;
781 to_flags
= to
->ContextFlags
& ~CONTEXT_AMD64
;
782 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_AMD64_CONTROL
))
784 to
->ContextFlags
|= CONTEXT_AMD64_CONTROL
;
785 to
->Rbp
= from
->ctl
.x86_64_regs
.rbp
;
786 to
->Rip
= from
->ctl
.x86_64_regs
.rip
;
787 to
->Rsp
= from
->ctl
.x86_64_regs
.rsp
;
788 to
->SegCs
= from
->ctl
.x86_64_regs
.cs
;
789 to
->SegSs
= from
->ctl
.x86_64_regs
.ss
;
790 to
->EFlags
= from
->ctl
.x86_64_regs
.flags
;
792 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_AMD64_INTEGER
))
794 to
->ContextFlags
|= CONTEXT_AMD64_INTEGER
;
795 to
->Rax
= from
->integer
.x86_64_regs
.rax
;
796 to
->Rcx
= from
->integer
.x86_64_regs
.rcx
;
797 to
->Rdx
= from
->integer
.x86_64_regs
.rdx
;
798 to
->Rbx
= from
->integer
.x86_64_regs
.rbx
;
799 to
->Rsi
= from
->integer
.x86_64_regs
.rsi
;
800 to
->Rdi
= from
->integer
.x86_64_regs
.rdi
;
801 to
->R8
= from
->integer
.x86_64_regs
.r8
;
802 to
->R9
= from
->integer
.x86_64_regs
.r9
;
803 to
->R10
= from
->integer
.x86_64_regs
.r10
;
804 to
->R11
= from
->integer
.x86_64_regs
.r11
;
805 to
->R12
= from
->integer
.x86_64_regs
.r12
;
806 to
->R13
= from
->integer
.x86_64_regs
.r13
;
807 to
->R14
= from
->integer
.x86_64_regs
.r14
;
808 to
->R15
= from
->integer
.x86_64_regs
.r15
;
810 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_AMD64_SEGMENTS
))
812 to
->ContextFlags
|= CONTEXT_AMD64_SEGMENTS
;
813 to
->SegDs
= from
->seg
.x86_64_regs
.ds
;
814 to
->SegEs
= from
->seg
.x86_64_regs
.es
;
815 to
->SegFs
= from
->seg
.x86_64_regs
.fs
;
816 to
->SegGs
= from
->seg
.x86_64_regs
.gs
;
818 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
820 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
821 memcpy( &to
->FltSave
, from
->fp
.x86_64_regs
.fpregs
, sizeof(from
->fp
.x86_64_regs
.fpregs
) );
822 to
->MxCsr
= to
->FltSave
.MxCsr
;
824 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_AMD64_DEBUG_REGISTERS
))
826 to
->ContextFlags
|= CONTEXT_AMD64_DEBUG_REGISTERS
;
827 to
->Dr0
= from
->debug
.x86_64_regs
.dr0
;
828 to
->Dr1
= from
->debug
.x86_64_regs
.dr1
;
829 to
->Dr2
= from
->debug
.x86_64_regs
.dr2
;
830 to
->Dr3
= from
->debug
.x86_64_regs
.dr3
;
831 to
->Dr6
= from
->debug
.x86_64_regs
.dr6
;
832 to
->Dr7
= from
->debug
.x86_64_regs
.dr7
;
834 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_AMD64_XSTATE
))
836 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
837 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
840 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
841 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
843 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
844 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
849 return STATUS_SUCCESS
;
852 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_AMD64
):
854 AMD64_CONTEXT
*to
= dst
;
856 to_flags
= to
->ContextFlags
& ~CONTEXT_AMD64
;
857 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_AMD64_CONTROL
))
859 to
->ContextFlags
|= CONTEXT_AMD64_CONTROL
;
860 to
->Rbp
= from
->ctl
.i386_regs
.ebp
;
861 to
->Rip
= from
->ctl
.i386_regs
.eip
;
862 to
->Rsp
= from
->ctl
.i386_regs
.esp
;
863 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
864 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
865 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
867 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_AMD64_INTEGER
))
869 to
->ContextFlags
|= CONTEXT_AMD64_INTEGER
;
870 to
->Rax
= from
->integer
.i386_regs
.eax
;
871 to
->Rcx
= from
->integer
.i386_regs
.ecx
;
872 to
->Rdx
= from
->integer
.i386_regs
.edx
;
873 to
->Rbx
= from
->integer
.i386_regs
.ebx
;
874 to
->Rsi
= from
->integer
.i386_regs
.esi
;
875 to
->Rdi
= from
->integer
.i386_regs
.edi
;
877 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_AMD64_SEGMENTS
))
879 to
->ContextFlags
|= CONTEXT_AMD64_SEGMENTS
;
880 to
->SegDs
= from
->seg
.i386_regs
.ds
;
881 to
->SegEs
= from
->seg
.i386_regs
.es
;
882 to
->SegFs
= from
->seg
.i386_regs
.fs
;
883 to
->SegGs
= from
->seg
.i386_regs
.gs
;
885 if ((from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
887 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
888 memcpy( &to
->FltSave
, from
->ext
.i386_regs
, sizeof(to
->FltSave
) );
890 else if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
892 I386_FLOATING_SAVE_AREA fpu
;
894 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
895 fpu
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
896 fpu
.StatusWord
= from
->fp
.i386_regs
.status
;
897 fpu
.TagWord
= from
->fp
.i386_regs
.tag
;
898 fpu
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
899 fpu
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
900 fpu
.DataOffset
= from
->fp
.i386_regs
.data_off
;
901 fpu
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
902 fpu
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
903 memcpy( fpu
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(fpu
.RegisterArea
) );
904 fpu_to_fpux( &to
->FltSave
, &fpu
);
906 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_AMD64_DEBUG_REGISTERS
))
908 to
->ContextFlags
|= CONTEXT_AMD64_DEBUG_REGISTERS
;
909 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
910 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
911 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
912 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
913 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
914 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
916 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_AMD64_XSTATE
))
918 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
919 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
922 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
923 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
925 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
926 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
931 return STATUS_SUCCESS
;
934 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT
, IMAGE_FILE_MACHINE_ARMNT
):
936 ARM_CONTEXT
*to
= dst
;
938 to_flags
= to
->ContextFlags
& ~CONTEXT_ARM
;
939 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_ARM_CONTROL
))
941 to
->ContextFlags
|= CONTEXT_ARM_CONTROL
;
942 to
->Sp
= from
->ctl
.arm_regs
.sp
;
943 to
->Lr
= from
->ctl
.arm_regs
.lr
;
944 to
->Pc
= from
->ctl
.arm_regs
.pc
;
945 to
->Cpsr
= from
->ctl
.arm_regs
.cpsr
;
947 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_ARM_INTEGER
))
949 to
->ContextFlags
|= CONTEXT_ARM_INTEGER
;
950 to
->R0
= from
->integer
.arm_regs
.r
[0];
951 to
->R1
= from
->integer
.arm_regs
.r
[1];
952 to
->R2
= from
->integer
.arm_regs
.r
[2];
953 to
->R3
= from
->integer
.arm_regs
.r
[3];
954 to
->R4
= from
->integer
.arm_regs
.r
[4];
955 to
->R5
= from
->integer
.arm_regs
.r
[5];
956 to
->R6
= from
->integer
.arm_regs
.r
[6];
957 to
->R7
= from
->integer
.arm_regs
.r
[7];
958 to
->R8
= from
->integer
.arm_regs
.r
[8];
959 to
->R9
= from
->integer
.arm_regs
.r
[9];
960 to
->R10
= from
->integer
.arm_regs
.r
[10];
961 to
->R11
= from
->integer
.arm_regs
.r
[11];
962 to
->R12
= from
->integer
.arm_regs
.r
[12];
964 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_ARM_FLOATING_POINT
))
966 to
->ContextFlags
|= CONTEXT_ARM_FLOATING_POINT
;
967 for (i
= 0; i
< 32; i
++) to
->D
[i
] = from
->fp
.arm_regs
.d
[i
];
968 to
->Fpscr
= from
->fp
.arm_regs
.fpscr
;
970 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_ARM_DEBUG_REGISTERS
))
972 to
->ContextFlags
|= CONTEXT_ARM_DEBUG_REGISTERS
;
973 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->Bvr
[i
] = from
->debug
.arm_regs
.bvr
[i
];
974 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->Bcr
[i
] = from
->debug
.arm_regs
.bcr
[i
];
975 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->Wvr
[i
] = from
->debug
.arm_regs
.wvr
[i
];
976 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->Wcr
[i
] = from
->debug
.arm_regs
.wcr
[i
];
978 return STATUS_SUCCESS
;
981 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_ARM64
):
983 ARM64_NT_CONTEXT
*to
= dst
;
985 to_flags
= to
->ContextFlags
& ~CONTEXT_ARM64
;
986 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_ARM64_CONTROL
))
988 to
->ContextFlags
|= CONTEXT_ARM64_CONTROL
;
989 to
->Fp
= from
->integer
.arm64_regs
.x
[29];
990 to
->Lr
= from
->integer
.arm64_regs
.x
[30];
991 to
->Sp
= from
->ctl
.arm64_regs
.sp
;
992 to
->Pc
= from
->ctl
.arm64_regs
.pc
;
993 to
->Cpsr
= from
->ctl
.arm64_regs
.pstate
;
995 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_ARM64_INTEGER
))
997 to
->ContextFlags
|= CONTEXT_ARM64_INTEGER
;
998 for (i
= 0; i
<= 28; i
++) to
->X
[i
] = from
->integer
.arm64_regs
.x
[i
];
1000 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_ARM64_FLOATING_POINT
))
1002 to
->ContextFlags
|= CONTEXT_ARM64_FLOATING_POINT
;
1003 for (i
= 0; i
< 32; i
++)
1005 to
->V
[i
].Low
= from
->fp
.arm64_regs
.q
[i
].low
;
1006 to
->V
[i
].High
= from
->fp
.arm64_regs
.q
[i
].high
;
1008 to
->Fpcr
= from
->fp
.arm64_regs
.fpcr
;
1009 to
->Fpsr
= from
->fp
.arm64_regs
.fpsr
;
1011 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_ARM64_DEBUG_REGISTERS
))
1013 to
->ContextFlags
|= CONTEXT_ARM64_DEBUG_REGISTERS
;
1014 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->Bcr
[i
] = from
->debug
.arm64_regs
.bcr
[i
];
1015 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->Bvr
[i
] = from
->debug
.arm64_regs
.bvr
[i
];
1016 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->Wcr
[i
] = from
->debug
.arm64_regs
.wcr
[i
];
1017 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->Wvr
[i
] = from
->debug
.arm64_regs
.wvr
[i
];
1019 return STATUS_SUCCESS
;
1022 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_I386
):
1023 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_ARM64
):
1024 return STATUS_SUCCESS
;
1027 return STATUS_INVALID_PARAMETER
;
1032 /***********************************************************************
1033 * contexts_to_server
1035 static void contexts_to_server( context_t server_contexts
[2], CONTEXT
*context
)
1037 unsigned int count
= 0;
1038 void *native_context
= get_native_context( context
);
1039 void *wow_context
= get_wow_context( context
);
1043 context_to_server( &server_contexts
[count
++], native_machine
, native_context
, native_machine
);
1044 if (wow_context
) context_to_server( &server_contexts
[count
++], main_image_info
.Machine
,
1045 wow_context
, main_image_info
.Machine
);
1046 else if (native_machine
!= main_image_info
.Machine
)
1047 context_to_server( &server_contexts
[count
++], main_image_info
.Machine
,
1048 native_context
, native_machine
);
1051 context_to_server( &server_contexts
[count
++], native_machine
,
1052 wow_context
, main_image_info
.Machine
);
1054 if (count
< 2) memset( &server_contexts
[1], 0, sizeof(server_contexts
[1]) );
1058 /***********************************************************************
1059 * contexts_from_server
1061 static void contexts_from_server( CONTEXT
*context
, context_t server_contexts
[2] )
1063 void *native_context
= get_native_context( context
);
1064 void *wow_context
= get_wow_context( context
);
1068 context_from_server( native_context
, &server_contexts
[0], native_machine
);
1070 context_from_server( wow_context
, &server_contexts
[1], main_image_info
.Machine
);
1072 context_from_server( native_context
, &server_contexts
[1], native_machine
);
1074 else context_from_server( wow_context
, &server_contexts
[0], main_image_info
.Machine
);
1078 /***********************************************************************
1079 * pthread_exit_wrapper
1081 static void pthread_exit_wrapper( int status
)
1083 close( ntdll_get_thread_data()->wait_fd
[0] );
1084 close( ntdll_get_thread_data()->wait_fd
[1] );
1085 close( ntdll_get_thread_data()->reply_fd
);
1086 close( ntdll_get_thread_data()->request_fd
);
1087 pthread_exit( UIntToPtr(status
) );
1091 /***********************************************************************
1094 * Startup routine for a newly created thread.
1096 static void start_thread( TEB
*teb
)
1098 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1101 thread_data
->pthread_id
= pthread_self();
1102 pthread_setspecific( teb_key
, teb
);
1103 server_init_thread( thread_data
->start
, &suspend
);
1104 signal_start_thread( thread_data
->start
, thread_data
->param
, suspend
, teb
);
1108 /***********************************************************************
1109 * get_machine_context_size
1111 static SIZE_T
get_machine_context_size( USHORT machine
)
1115 case IMAGE_FILE_MACHINE_I386
: return sizeof(I386_CONTEXT
);
1116 case IMAGE_FILE_MACHINE_ARMNT
: return sizeof(ARM_CONTEXT
);
1117 case IMAGE_FILE_MACHINE_AMD64
: return sizeof(AMD64_CONTEXT
);
1118 case IMAGE_FILE_MACHINE_ARM64
: return sizeof(ARM64_NT_CONTEXT
);
1124 /***********************************************************************
1127 * cf. RtlWow64GetCurrentCpuArea
1129 void *get_cpu_area( USHORT machine
)
1131 WOW64_CPURESERVED
*cpu
;
1134 if (!is_wow64()) return NULL
;
1136 cpu
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_CPURESERVED
];
1138 cpu
= ULongToPtr( NtCurrentTeb64()->TlsSlots
[WOW64_TLS_CPURESERVED
] );
1140 if (cpu
->Machine
!= machine
) return NULL
;
1141 switch (cpu
->Machine
)
1143 case IMAGE_FILE_MACHINE_I386
: align
= TYPE_ALIGNMENT(I386_CONTEXT
); break;
1144 case IMAGE_FILE_MACHINE_AMD64
: align
= TYPE_ALIGNMENT(AMD64_CONTEXT
); break;
1145 case IMAGE_FILE_MACHINE_ARMNT
: align
= TYPE_ALIGNMENT(ARM_CONTEXT
); break;
1146 case IMAGE_FILE_MACHINE_ARM64
: align
= TYPE_ALIGNMENT(ARM64_NT_CONTEXT
); break;
1147 default: return NULL
;
1149 return (void *)(((ULONG_PTR
)(cpu
+ 1) + align
- 1) & ~((ULONG_PTR
)align
- 1));
1153 /***********************************************************************
1156 void set_thread_id( TEB
*teb
, DWORD pid
, DWORD tid
)
1158 WOW_TEB
*wow_teb
= get_wow_teb( teb
);
1160 teb
->ClientId
.UniqueProcess
= ULongToHandle( pid
);
1161 teb
->ClientId
.UniqueThread
= ULongToHandle( tid
);
1162 teb
->RealClientId
= teb
->ClientId
;
1165 wow_teb
->ClientId
.UniqueProcess
= pid
;
1166 wow_teb
->ClientId
.UniqueThread
= tid
;
1167 wow_teb
->RealClientId
= wow_teb
->ClientId
;
1172 /***********************************************************************
1175 NTSTATUS
init_thread_stack( TEB
*teb
, ULONG_PTR limit
, SIZE_T reserve_size
, SIZE_T commit_size
)
1177 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1178 WOW_TEB
*wow_teb
= get_wow_teb( teb
);
1183 if ((status
= virtual_alloc_thread_stack( &stack
, 0, kernel_stack_size
, kernel_stack_size
, FALSE
)))
1185 thread_data
->kernel_stack
= stack
.DeallocationStack
;
1189 WOW64_CPURESERVED
*cpu
;
1190 SIZE_T cpusize
= sizeof(WOW64_CPURESERVED
) +
1191 ((get_machine_context_size( main_image_info
.Machine
) + 7) & ~7) + sizeof(ULONG64
);
1194 if ((status
= virtual_alloc_thread_stack( &stack
, 0, 0x40000, 0x40000, TRUE
))) return status
;
1195 cpu
= (WOW64_CPURESERVED
*)(((ULONG_PTR
)stack
.StackBase
- cpusize
) & ~15);
1196 cpu
->Machine
= main_image_info
.Machine
;
1199 teb
->Tib
.StackBase
= teb
->TlsSlots
[WOW64_TLS_CPURESERVED
] = cpu
;
1200 teb
->Tib
.StackLimit
= stack
.StackLimit
;
1201 teb
->DeallocationStack
= stack
.DeallocationStack
;
1204 if ((status
= virtual_alloc_thread_stack( &stack
, limit
? limit
: 0x7fffffff,
1205 reserve_size
, commit_size
, TRUE
)))
1207 wow_teb
->Tib
.StackBase
= PtrToUlong( stack
.StackBase
);
1208 wow_teb
->Tib
.StackLimit
= PtrToUlong( stack
.StackLimit
);
1209 wow_teb
->DeallocationStack
= PtrToUlong( stack
.DeallocationStack
);
1210 return STATUS_SUCCESS
;
1212 wow_teb
->Tib
.StackBase
= wow_teb
->TlsSlots
[WOW64_TLS_CPURESERVED
] = PtrToUlong( cpu
);
1213 wow_teb
->Tib
.StackLimit
= PtrToUlong( stack
.StackLimit
);
1214 wow_teb
->DeallocationStack
= PtrToUlong( stack
.DeallocationStack
);
1219 if ((status
= virtual_alloc_thread_stack( &stack
, limit
, reserve_size
, commit_size
, TRUE
)))
1221 teb
->Tib
.StackBase
= stack
.StackBase
;
1222 teb
->Tib
.StackLimit
= stack
.StackLimit
;
1223 teb
->DeallocationStack
= stack
.DeallocationStack
;
1224 return STATUS_SUCCESS
;
1228 /***********************************************************************
1231 * Update the output attributes.
1233 static void update_attr_list( PS_ATTRIBUTE_LIST
*attr
, const CLIENT_ID
*id
, TEB
*teb
)
1235 SIZE_T i
, count
= (attr
->TotalLength
- sizeof(attr
->TotalLength
)) / sizeof(PS_ATTRIBUTE
);
1237 for (i
= 0; i
< count
; i
++)
1239 if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_CLIENT_ID
)
1241 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(*id
) );
1242 memcpy( attr
->Attributes
[i
].ValuePtr
, id
, size
);
1243 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
1245 else if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_TEB_ADDRESS
)
1247 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(teb
) );
1248 memcpy( attr
->Attributes
[i
].ValuePtr
, &teb
, size
);
1249 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
1254 /***********************************************************************
1255 * NtCreateThread (NTDLL.@)
1257 NTSTATUS WINAPI
NtCreateThread( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1258 HANDLE process
, CLIENT_ID
*id
, CONTEXT
*ctx
, INITIAL_TEB
*teb
,
1261 FIXME( "%p %d %p %p %p %p %p %d, stub!\n",
1262 handle
, (int)access
, attr
, process
, id
, ctx
, teb
, suspended
);
1263 return STATUS_NOT_IMPLEMENTED
;
1266 /***********************************************************************
1267 * NtCreateThreadEx (NTDLL.@)
1269 NTSTATUS WINAPI
NtCreateThreadEx( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1270 HANDLE process
, PRTL_THREAD_START_ROUTINE start
, void *param
,
1271 ULONG flags
, ULONG_PTR zero_bits
, SIZE_T stack_commit
,
1272 SIZE_T stack_reserve
, PS_ATTRIBUTE_LIST
*attr_list
)
1274 static const ULONG supported_flags
= THREAD_CREATE_FLAGS_CREATE_SUSPENDED
| THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER
;
1276 pthread_t pthread_id
;
1277 pthread_attr_t pthread_attr
;
1279 struct object_attributes
*objattr
;
1280 struct ntdll_thread_data
*thread_data
;
1282 int request_pipe
[2];
1284 unsigned int status
;
1286 if (flags
& ~supported_flags
)
1287 FIXME( "Unsupported flags %#x.\n", (int)flags
);
1289 if (zero_bits
> 21 && zero_bits
< 32) return STATUS_INVALID_PARAMETER_3
;
1291 if (!is_old_wow64() && zero_bits
>= 32) return STATUS_INVALID_PARAMETER_3
;
1294 if (process
!= NtCurrentProcess())
1297 apc_result_t result
;
1299 memset( &call
, 0, sizeof(call
) );
1301 call
.create_thread
.type
= APC_CREATE_THREAD
;
1302 call
.create_thread
.flags
= flags
;
1303 call
.create_thread
.func
= wine_server_client_ptr( start
);
1304 call
.create_thread
.arg
= wine_server_client_ptr( param
);
1305 call
.create_thread
.zero_bits
= zero_bits
;
1306 call
.create_thread
.reserve
= stack_reserve
;
1307 call
.create_thread
.commit
= stack_commit
;
1308 status
= server_queue_process_apc( process
, &call
, &result
);
1309 if (status
!= STATUS_SUCCESS
) return status
;
1311 if (result
.create_thread
.status
== STATUS_SUCCESS
)
1313 CLIENT_ID client_id
;
1314 TEB
*teb
= wine_server_get_ptr( result
.create_thread
.teb
);
1315 *handle
= wine_server_ptr_handle( result
.create_thread
.handle
);
1316 client_id
.UniqueProcess
= ULongToHandle( result
.create_thread
.pid
);
1317 client_id
.UniqueThread
= ULongToHandle( result
.create_thread
.tid
);
1318 if (attr_list
) update_attr_list( attr_list
, &client_id
, teb
);
1320 return result
.create_thread
.status
;
1323 if ((status
= alloc_object_attributes( attr
, &objattr
, &len
))) return status
;
1325 if (server_pipe( request_pipe
) == -1)
1328 return STATUS_TOO_MANY_OPENED_FILES
;
1330 wine_server_send_fd( request_pipe
[0] );
1332 if (!access
) access
= THREAD_ALL_ACCESS
;
1334 SERVER_START_REQ( new_thread
)
1336 req
->process
= wine_server_obj_handle( process
);
1337 req
->access
= access
;
1339 req
->request_fd
= request_pipe
[0];
1340 wine_server_add_data( req
, objattr
, len
);
1341 if (!(status
= wine_server_call( req
)))
1343 *handle
= wine_server_ptr_handle( reply
->handle
);
1346 close( request_pipe
[0] );
1353 close( request_pipe
[1] );
1357 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &sigset
);
1359 if ((status
= virtual_alloc_teb( &teb
))) goto done
;
1361 if ((status
= init_thread_stack( teb
, get_zero_bits_limit( zero_bits
), stack_reserve
, stack_commit
)))
1363 virtual_free_teb( teb
);
1367 set_thread_id( teb
, GetCurrentProcessId(), tid
);
1369 thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1370 thread_data
->request_fd
= request_pipe
[1];
1371 thread_data
->start
= start
;
1372 thread_data
->param
= param
;
1374 pthread_attr_init( &pthread_attr
);
1375 pthread_attr_setstack( &pthread_attr
, thread_data
->kernel_stack
, kernel_stack_size
);
1376 pthread_attr_setguardsize( &pthread_attr
, 0 );
1377 pthread_attr_setscope( &pthread_attr
, PTHREAD_SCOPE_SYSTEM
); /* force creating a kernel thread */
1378 InterlockedIncrement( &nb_threads
);
1379 if (pthread_create( &pthread_id
, &pthread_attr
, (void * (*)(void *))start_thread
, teb
))
1381 InterlockedDecrement( &nb_threads
);
1382 virtual_free_teb( teb
);
1383 status
= STATUS_NO_MEMORY
;
1385 pthread_attr_destroy( &pthread_attr
);
1388 pthread_sigmask( SIG_SETMASK
, &sigset
, NULL
);
1392 close( request_pipe
[1] );
1395 if (attr_list
) update_attr_list( attr_list
, &teb
->ClientId
, teb
);
1396 return STATUS_SUCCESS
;
1400 /***********************************************************************
1403 void abort_thread( int status
)
1405 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1406 if (InterlockedDecrement( &nb_threads
) <= 0) abort_process( status
);
1407 signal_exit_thread( status
, pthread_exit_wrapper
, NtCurrentTeb() );
1411 /***********************************************************************
1414 void abort_process( int status
)
1416 _exit( get_unix_exit_code( status
));
1420 /***********************************************************************
1423 static DECLSPEC_NORETURN
void exit_thread( int status
)
1425 static void *prev_teb
;
1428 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1430 if (InterlockedDecrement( &nb_threads
) <= 0) exit_process( status
);
1432 if ((teb
= InterlockedExchangePointer( &prev_teb
, NtCurrentTeb() )))
1434 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1436 if (thread_data
->pthread_id
)
1438 pthread_join( thread_data
->pthread_id
, NULL
);
1439 virtual_free_teb( teb
);
1442 signal_exit_thread( status
, pthread_exit_wrapper
, NtCurrentTeb() );
1446 /***********************************************************************
1449 void exit_process( int status
)
1451 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1452 signal_exit_thread( get_unix_exit_code( status
), process_exit_wrapper
, NtCurrentTeb() );
1456 /**********************************************************************
1459 * Wait until the thread is no longer suspended.
1461 void wait_suspend( CONTEXT
*context
)
1463 int saved_errno
= errno
;
1464 context_t server_contexts
[2];
1466 contexts_to_server( server_contexts
, context
);
1467 /* wait with 0 timeout, will only return once the thread is no longer suspended */
1468 server_select( NULL
, 0, SELECT_INTERRUPTIBLE
, 0, server_contexts
, NULL
);
1469 contexts_from_server( context
, server_contexts
);
1470 errno
= saved_errno
;
1474 /**********************************************************************
1477 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
1479 NTSTATUS
send_debug_event( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
1483 obj_handle_t handle
= 0;
1484 client_ptr_t params
[EXCEPTION_MAXIMUM_PARAMETERS
];
1485 select_op_t select_op
;
1488 if (!peb
->BeingDebugged
) return 0; /* no debugger present */
1490 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &old_set
);
1492 for (i
= 0; i
< min( rec
->NumberParameters
, EXCEPTION_MAXIMUM_PARAMETERS
); i
++)
1493 params
[i
] = rec
->ExceptionInformation
[i
];
1495 SERVER_START_REQ( queue_exception_event
)
1497 req
->first
= first_chance
;
1498 req
->code
= rec
->ExceptionCode
;
1499 req
->flags
= rec
->ExceptionFlags
;
1500 req
->record
= wine_server_client_ptr( rec
->ExceptionRecord
);
1501 req
->address
= wine_server_client_ptr( rec
->ExceptionAddress
);
1502 req
->len
= i
* sizeof(params
[0]);
1503 wine_server_add_data( req
, params
, req
->len
);
1504 if (!(ret
= wine_server_call( req
))) handle
= reply
->handle
;
1510 context_t server_contexts
[2];
1512 select_op
.wait
.op
= SELECT_WAIT
;
1513 select_op
.wait
.handles
[0] = handle
;
1515 contexts_to_server( server_contexts
, context
);
1516 server_select( &select_op
, offsetof( select_op_t
, wait
.handles
[1] ), SELECT_INTERRUPTIBLE
,
1517 TIMEOUT_INFINITE
, server_contexts
, NULL
);
1519 SERVER_START_REQ( get_exception_status
)
1521 req
->handle
= handle
;
1522 ret
= wine_server_call( req
);
1525 if (NT_SUCCESS(ret
)) contexts_from_server( context
, server_contexts
);
1528 pthread_sigmask( SIG_SETMASK
, &old_set
, NULL
);
1533 /*******************************************************************
1534 * NtRaiseException (NTDLL.@)
1536 NTSTATUS WINAPI
NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
1538 NTSTATUS status
= send_debug_event( rec
, context
, first_chance
);
1540 if (status
== DBG_CONTINUE
|| status
== DBG_EXCEPTION_HANDLED
)
1541 return NtContinue( context
, FALSE
);
1543 if (first_chance
) return call_user_exception_dispatcher( rec
, context
);
1545 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
1546 ERR_(seh
)("Exception frame is not in stack limits => unable to dispatch exception.\n");
1547 else if (rec
->ExceptionCode
== STATUS_NONCONTINUABLE_EXCEPTION
)
1548 ERR_(seh
)("Process attempted to continue execution after noncontinuable exception.\n");
1550 ERR_(seh
)("Unhandled exception code %x flags %x addr %p\n",
1551 (int)rec
->ExceptionCode
, (int)rec
->ExceptionFlags
, rec
->ExceptionAddress
);
1553 NtTerminateProcess( NtCurrentProcess(), rec
->ExceptionCode
);
1554 return STATUS_SUCCESS
;
1558 /**********************************************************************
1559 * NtCurrentTeb (NTDLL.@)
1561 TEB
* WINAPI
NtCurrentTeb(void)
1563 return pthread_getspecific( teb_key
);
1567 /***********************************************************************
1568 * NtOpenThread (NTDLL.@)
1570 NTSTATUS WINAPI
NtOpenThread( HANDLE
*handle
, ACCESS_MASK access
,
1571 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
1577 SERVER_START_REQ( open_thread
)
1579 req
->tid
= HandleToULong(id
->UniqueThread
);
1580 req
->access
= access
;
1581 req
->attributes
= attr
? attr
->Attributes
: 0;
1582 ret
= wine_server_call( req
);
1583 *handle
= wine_server_ptr_handle( reply
->handle
);
1590 /******************************************************************************
1591 * NtSuspendThread (NTDLL.@)
1593 NTSTATUS WINAPI
NtSuspendThread( HANDLE handle
, ULONG
*count
)
1597 SERVER_START_REQ( suspend_thread
)
1599 req
->handle
= wine_server_obj_handle( handle
);
1600 if (!(ret
= wine_server_call( req
)))
1602 if (count
) *count
= reply
->count
;
1610 /******************************************************************************
1611 * NtResumeThread (NTDLL.@)
1613 NTSTATUS WINAPI
NtResumeThread( HANDLE handle
, ULONG
*count
)
1617 SERVER_START_REQ( resume_thread
)
1619 req
->handle
= wine_server_obj_handle( handle
);
1620 if (!(ret
= wine_server_call( req
)))
1622 if (count
) *count
= reply
->count
;
1630 /******************************************************************************
1631 * NtAlertResumeThread (NTDLL.@)
1633 NTSTATUS WINAPI
NtAlertResumeThread( HANDLE handle
, ULONG
*count
)
1635 FIXME( "stub: should alert thread %p\n", handle
);
1636 return NtResumeThread( handle
, count
);
1640 /******************************************************************************
1641 * NtAlertThread (NTDLL.@)
1643 NTSTATUS WINAPI
NtAlertThread( HANDLE handle
)
1645 FIXME( "stub: %p\n", handle
);
1646 return STATUS_NOT_IMPLEMENTED
;
1650 /******************************************************************************
1651 * NtTerminateThread (NTDLL.@)
1653 NTSTATUS WINAPI
NtTerminateThread( HANDLE handle
, LONG exit_code
)
1658 SERVER_START_REQ( terminate_thread
)
1660 req
->handle
= wine_server_obj_handle( handle
);
1661 req
->exit_code
= exit_code
;
1662 ret
= wine_server_call( req
);
1663 self
= !ret
&& reply
->self
;
1669 server_select( NULL
, 0, SELECT_INTERRUPTIBLE
, 0, NULL
, NULL
);
1670 exit_thread( exit_code
);
1676 /******************************************************************************
1677 * NtQueueApcThread (NTDLL.@)
1679 NTSTATUS WINAPI
NtQueueApcThread( HANDLE handle
, PNTAPCFUNC func
, ULONG_PTR arg1
,
1680 ULONG_PTR arg2
, ULONG_PTR arg3
)
1684 SERVER_START_REQ( queue_apc
)
1686 req
->handle
= wine_server_obj_handle( handle
);
1689 req
->call
.type
= APC_USER
;
1690 req
->call
.user
.func
= wine_server_client_ptr( func
);
1691 req
->call
.user
.args
[0] = arg1
;
1692 req
->call
.user
.args
[1] = arg2
;
1693 req
->call
.user
.args
[2] = arg3
;
1695 else req
->call
.type
= APC_NONE
; /* wake up only */
1696 ret
= wine_server_call( req
);
1703 /***********************************************************************
1704 * set_thread_context
1706 NTSTATUS
set_thread_context( HANDLE handle
, const void *context
, BOOL
*self
, USHORT machine
)
1708 context_t server_contexts
[2];
1709 unsigned int count
= 0;
1712 context_to_server( &server_contexts
[count
++], native_machine
, context
, machine
);
1713 if (machine
!= native_machine
)
1714 context_to_server( &server_contexts
[count
++], machine
, context
, machine
);
1716 SERVER_START_REQ( set_thread_context
)
1718 req
->handle
= wine_server_obj_handle( handle
);
1719 req
->native_flags
= server_contexts
[0].flags
& get_native_context_flags( native_machine
, machine
);
1720 wine_server_add_data( req
, server_contexts
, count
* sizeof(server_contexts
[0]) );
1721 ret
= wine_server_call( req
);
1722 *self
= reply
->self
;
1730 /***********************************************************************
1731 * get_thread_context
1733 NTSTATUS
get_thread_context( HANDLE handle
, void *context
, BOOL
*self
, USHORT machine
)
1736 HANDLE context_handle
;
1737 context_t server_contexts
[2];
1739 unsigned int flags
= get_server_context_flags( context
, machine
);
1741 SERVER_START_REQ( get_thread_context
)
1743 req
->handle
= wine_server_obj_handle( handle
);
1745 req
->machine
= machine
;
1746 req
->native_flags
= flags
& get_native_context_flags( native_machine
, machine
);
1747 wine_server_set_reply( req
, server_contexts
, sizeof(server_contexts
) );
1748 ret
= wine_server_call( req
);
1749 *self
= reply
->self
;
1750 context_handle
= wine_server_ptr_handle( reply
->handle
);
1751 count
= wine_server_reply_size( reply
) / sizeof(server_contexts
[0]);
1755 if (ret
== STATUS_PENDING
)
1757 NtWaitForSingleObject( context_handle
, FALSE
, NULL
);
1759 SERVER_START_REQ( get_thread_context
)
1761 req
->context
= wine_server_obj_handle( context_handle
);
1763 req
->machine
= machine
;
1764 req
->native_flags
= flags
& get_native_context_flags( native_machine
, machine
);
1765 wine_server_set_reply( req
, server_contexts
, sizeof(server_contexts
) );
1766 ret
= wine_server_call( req
);
1767 count
= wine_server_reply_size( reply
) / sizeof(server_contexts
[0]);
1773 ret
= context_from_server( context
, &server_contexts
[0], machine
);
1774 if (!ret
&& count
> 1) ret
= context_from_server( context
, &server_contexts
[1], machine
);
1780 /***********************************************************************
1781 * ntdll_set_exception_jmp_buf
1783 void ntdll_set_exception_jmp_buf( __wine_jmp_buf
*jmp
)
1785 assert( !jmp
|| !ntdll_get_thread_data()->jmp_buf );
1786 ntdll_get_thread_data()->jmp_buf = jmp
;
1790 BOOL
get_thread_times(int unix_pid
, int unix_tid
, LARGE_INTEGER
*kernel_time
, LARGE_INTEGER
*user_time
)
1793 unsigned long clocks_per_sec
= sysconf( _SC_CLK_TCK
);
1794 unsigned long usr
, sys
;
1801 sprintf( buf
, "/proc/%u/stat", unix_pid
);
1803 sprintf( buf
, "/proc/%u/task/%u/stat", unix_pid
, unix_tid
);
1804 if (!(f
= fopen( buf
, "r" )))
1806 WARN("Failed to open %s: %s\n", buf
, strerror(errno
));
1810 pos
= fgets( buf
, sizeof(buf
), f
);
1813 /* the process name is printed unescaped, so we have to skip to the last ')'
1814 * to avoid misinterpreting the string */
1815 if (pos
) pos
= strrchr( pos
, ')' );
1816 if (pos
) pos
= strchr( pos
+ 1, ' ' );
1819 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
1820 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
1821 for (i
= 0; i
< 11 && pos
; i
++)
1823 pos
= strchr( pos
+ 1, ' ' );
1827 /* the next two values are user and system time */
1828 if (pos
&& (sscanf( pos
, "%lu %lu", &usr
, &sys
) == 2))
1830 kernel_time
->QuadPart
= (ULONGLONG
)sys
* 10000000 / clocks_per_sec
;
1831 user_time
->QuadPart
= (ULONGLONG
)usr
* 10000000 / clocks_per_sec
;
1835 ERR("Failed to parse %s\n", debugstr_a(buf
));
1837 #elif defined(HAVE_LIBPROCSTAT)
1838 struct procstat
*pstat
;
1839 struct kinfo_proc
*kip
;
1840 unsigned int proc_count
;
1843 pstat
= procstat_open_sysctl();
1847 kip
= procstat_getprocs(pstat
, KERN_PROC_PID
, unix_pid
, &proc_count
);
1849 kip
= procstat_getprocs(pstat
, KERN_PROC_PID
| KERN_PROC_INC_THREAD
, unix_pid
, &proc_count
);
1853 for (i
= 0; i
< proc_count
; i
++)
1855 if (unix_tid
== -1 || kip
[i
].ki_tid
== unix_tid
)
1857 kernel_time
->QuadPart
= 10000000 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_stime
.tv_sec
+
1858 10 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_stime
.tv_usec
;
1859 user_time
->QuadPart
= 10000000 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_utime
.tv_sec
+
1860 10 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_utime
.tv_usec
;
1865 procstat_freeprocs(pstat
, kip
);
1867 procstat_close(pstat
);
1871 if (!once
++) FIXME("not implemented on this platform\n");
1876 static void set_native_thread_name( HANDLE handle
, const UNICODE_STRING
*name
)
1879 unsigned int status
;
1880 char path
[64], nameA
[64];
1881 int unix_pid
, unix_tid
, len
, fd
;
1883 SERVER_START_REQ( get_thread_times
)
1885 req
->handle
= wine_server_obj_handle( handle
);
1886 status
= wine_server_call( req
);
1887 if (status
== STATUS_SUCCESS
)
1889 unix_pid
= reply
->unix_pid
;
1890 unix_tid
= reply
->unix_tid
;
1895 if (status
!= STATUS_SUCCESS
|| unix_pid
== -1 || unix_tid
== -1)
1898 if (unix_pid
!= getpid())
1901 if (!once
++) FIXME("cross-process native thread naming not supported\n");
1905 len
= ntdll_wcstoumbs( name
->Buffer
, name
->Length
/ sizeof(WCHAR
), nameA
, sizeof(nameA
), FALSE
);
1906 sprintf(path
, "/proc/%u/task/%u/comm", unix_pid
, unix_tid
);
1907 if ((fd
= open( path
, O_WRONLY
)) != -1)
1909 write( fd
, nameA
, len
);
1912 #elif defined(__APPLE__)
1913 /* pthread_setname_np() silently fails if the name is longer than 63 characters + null terminator */
1916 int unix_pid
, unix_tid
, len
, current_tid
;
1918 SERVER_START_REQ( get_thread_times
)
1920 req
->handle
= wine_server_obj_handle( handle
);
1921 status
= wine_server_call( req
);
1922 if (status
== STATUS_SUCCESS
)
1924 unix_pid
= reply
->unix_pid
;
1925 unix_tid
= reply
->unix_tid
;
1930 if (status
!= STATUS_SUCCESS
|| unix_pid
== -1 || unix_tid
== -1)
1933 current_tid
= mach_thread_self();
1934 mach_port_deallocate(mach_task_self(), current_tid
);
1936 if (unix_tid
!= current_tid
)
1939 if (!once
++) FIXME("setting other thread name not supported\n");
1943 len
= ntdll_wcstoumbs( name
->Buffer
, name
->Length
/ sizeof(WCHAR
), nameA
, sizeof(nameA
) - 1, FALSE
);
1945 pthread_setname_np(nameA
);
1948 if (!once
++) FIXME("not implemented on this platform\n");
1952 static BOOL
is_process_wow64( const CLIENT_ID
*id
)
1958 if (id
->UniqueProcess
== ULongToHandle(GetCurrentProcessId())) return is_old_wow64();
1959 if (!NtOpenProcess( &handle
, PROCESS_QUERY_LIMITED_INFORMATION
, NULL
, id
))
1961 if (!NtQueryInformationProcess( handle
, ProcessWow64Information
, &info
, sizeof(info
), NULL
))
1968 /******************************************************************************
1969 * NtQueryInformationThread (NTDLL.@)
1971 NTSTATUS WINAPI
NtQueryInformationThread( HANDLE handle
, THREADINFOCLASS
class,
1972 void *data
, ULONG length
, ULONG
*ret_len
)
1974 unsigned int status
;
1976 TRACE("(%p,%d,%p,%x,%p)\n", handle
, class, data
, (int)length
, ret_len
);
1980 case ThreadBasicInformation
:
1982 THREAD_BASIC_INFORMATION info
;
1983 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1985 SERVER_START_REQ( get_thread_info
)
1987 req
->handle
= wine_server_obj_handle( handle
);
1988 if (!(status
= wine_server_call( req
)))
1990 info
.ExitStatus
= reply
->exit_code
;
1991 info
.TebBaseAddress
= wine_server_get_ptr( reply
->teb
);
1992 info
.ClientId
.UniqueProcess
= ULongToHandle(reply
->pid
);
1993 info
.ClientId
.UniqueThread
= ULongToHandle(reply
->tid
);
1994 info
.AffinityMask
= reply
->affinity
& affinity_mask
;
1995 info
.Priority
= reply
->priority
;
1996 info
.BasePriority
= reply
->priority
; /* FIXME */
2000 if (status
== STATUS_SUCCESS
)
2004 if (is_process_wow64( &info
.ClientId
))
2005 info
.TebBaseAddress
= (char *)info
.TebBaseAddress
+ teb_offset
;
2007 info
.TebBaseAddress
= NULL
;
2009 if (data
) memcpy( data
, &info
, min( length
, sizeof(info
) ));
2010 if (ret_len
) *ret_len
= min( length
, sizeof(info
) );
2015 case ThreadAffinityMask
:
2017 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2018 ULONG_PTR affinity
= 0;
2020 SERVER_START_REQ( get_thread_info
)
2022 req
->handle
= wine_server_obj_handle( handle
);
2023 req
->access
= THREAD_QUERY_INFORMATION
;
2024 if (!(status
= wine_server_call( req
))) affinity
= reply
->affinity
& affinity_mask
;
2027 if (status
== STATUS_SUCCESS
)
2029 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
2030 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
2037 KERNEL_USER_TIMES kusrt
;
2038 int unix_pid
, unix_tid
;
2040 SERVER_START_REQ( get_thread_times
)
2042 req
->handle
= wine_server_obj_handle( handle
);
2043 status
= wine_server_call( req
);
2044 if (status
== STATUS_SUCCESS
)
2046 kusrt
.CreateTime
.QuadPart
= reply
->creation_time
;
2047 kusrt
.ExitTime
.QuadPart
= reply
->exit_time
;
2048 unix_pid
= reply
->unix_pid
;
2049 unix_tid
= reply
->unix_tid
;
2053 if (status
== STATUS_SUCCESS
)
2057 kusrt
.KernelTime
.QuadPart
= kusrt
.UserTime
.QuadPart
= 0;
2058 if (unix_pid
!= -1 && unix_tid
!= -1)
2059 ret
= get_thread_times( unix_pid
, unix_tid
, &kusrt
.KernelTime
, &kusrt
.UserTime
);
2060 if (!ret
&& handle
== GetCurrentThread())
2062 /* fall back to process times */
2063 struct tms time_buf
;
2064 long clocks_per_sec
= sysconf(_SC_CLK_TCK
);
2067 kusrt
.KernelTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_stime
* 10000000 / clocks_per_sec
;
2068 kusrt
.UserTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_utime
* 10000000 / clocks_per_sec
;
2070 if (data
) memcpy( data
, &kusrt
, min( length
, sizeof(kusrt
) ));
2071 if (ret_len
) *ret_len
= min( length
, sizeof(kusrt
) );
2076 case ThreadDescriptorTableEntry
:
2077 return get_thread_ldt_entry( handle
, data
, length
, ret_len
);
2079 case ThreadAmILastThread
:
2081 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
2082 SERVER_START_REQ( get_thread_info
)
2084 req
->handle
= wine_server_obj_handle( handle
);
2085 status
= wine_server_call( req
);
2086 if (status
== STATUS_SUCCESS
)
2088 ULONG last
= reply
->last
;
2089 if (data
) memcpy( data
, &last
, sizeof(last
) );
2090 if (ret_len
) *ret_len
= sizeof(last
);
2097 case ThreadQuerySetWin32StartAddress
:
2099 SERVER_START_REQ( get_thread_info
)
2101 req
->handle
= wine_server_obj_handle( handle
);
2102 req
->access
= THREAD_QUERY_INFORMATION
;
2103 status
= wine_server_call( req
);
2104 if (status
== STATUS_SUCCESS
)
2106 PRTL_THREAD_START_ROUTINE entry
= wine_server_get_ptr( reply
->entry_point
);
2107 if (data
) memcpy( data
, &entry
, min( length
, sizeof(entry
) ) );
2108 if (ret_len
) *ret_len
= min( length
, sizeof(entry
) );
2115 case ThreadGroupInformation
:
2117 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2118 GROUP_AFFINITY affinity
;
2120 memset( &affinity
, 0, sizeof(affinity
) );
2121 affinity
.Group
= 0; /* Wine only supports max 64 processors */
2123 SERVER_START_REQ( get_thread_info
)
2125 req
->handle
= wine_server_obj_handle( handle
);
2126 if (!(status
= wine_server_call( req
))) affinity
.Mask
= reply
->affinity
& affinity_mask
;
2129 if (status
== STATUS_SUCCESS
)
2131 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
2132 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
2137 case ThreadIsIoPending
:
2138 FIXME( "ThreadIsIoPending info class not supported yet\n" );
2139 if (length
!= sizeof(BOOL
)) return STATUS_INFO_LENGTH_MISMATCH
;
2140 if (!data
) return STATUS_ACCESS_DENIED
;
2141 *(BOOL
*)data
= FALSE
;
2142 if (ret_len
) *ret_len
= sizeof(BOOL
);
2143 return STATUS_SUCCESS
;
2145 case ThreadSuspendCount
:
2146 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
2147 if (!data
) return STATUS_ACCESS_VIOLATION
;
2149 SERVER_START_REQ( get_thread_info
)
2151 req
->handle
= wine_server_obj_handle( handle
);
2152 if (!(status
= wine_server_call( req
))) *(ULONG
*)data
= reply
->suspend_count
;
2157 case ThreadNameInformation
:
2159 THREAD_NAME_INFORMATION
*info
= data
;
2160 data_size_t len
, desc_len
= 0;
2163 len
= length
>= sizeof(*info
) ? length
- sizeof(*info
) : 0;
2164 ptr
= info
? (WCHAR
*)(info
+ 1) : NULL
;
2166 SERVER_START_REQ( get_thread_info
)
2168 req
->handle
= wine_server_obj_handle( handle
);
2169 if (ptr
) wine_server_set_reply( req
, ptr
, len
);
2170 status
= wine_server_call( req
);
2171 desc_len
= reply
->desc_len
;
2175 if (!info
) status
= STATUS_BUFFER_TOO_SMALL
;
2176 else if (status
== STATUS_SUCCESS
)
2178 info
->ThreadName
.Length
= info
->ThreadName
.MaximumLength
= desc_len
;
2179 info
->ThreadName
.Buffer
= ptr
;
2182 if (ret_len
&& (status
== STATUS_SUCCESS
|| status
== STATUS_BUFFER_TOO_SMALL
))
2183 *ret_len
= sizeof(*info
) + desc_len
;
2187 case ThreadWow64Context
:
2188 return get_thread_wow64_context( handle
, data
, length
);
2190 case ThreadHideFromDebugger
:
2191 if (length
!= sizeof(BOOLEAN
)) return STATUS_INFO_LENGTH_MISMATCH
;
2192 if (!data
) return STATUS_ACCESS_VIOLATION
;
2193 SERVER_START_REQ( get_thread_info
)
2195 req
->handle
= wine_server_obj_handle( handle
);
2196 req
->access
= THREAD_QUERY_INFORMATION
;
2197 if ((status
= wine_server_call( req
))) return status
;
2198 *(BOOLEAN
*)data
= reply
->dbg_hidden
;
2201 if (ret_len
) *ret_len
= sizeof(BOOLEAN
);
2202 return STATUS_SUCCESS
;
2204 case ThreadPriorityBoost
:
2206 DWORD
*value
= data
;
2208 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
2209 if (ret_len
) *ret_len
= sizeof(ULONG
);
2211 return STATUS_SUCCESS
;
2214 case ThreadIdealProcessor
:
2215 case ThreadEnableAlignmentFaultFixup
:
2216 return STATUS_INVALID_INFO_CLASS
;
2218 case ThreadPriority
:
2219 case ThreadBasePriority
:
2220 case ThreadImpersonationToken
:
2221 case ThreadEventPair_Reusable
:
2222 case ThreadZeroTlsCell
:
2223 case ThreadPerformanceCount
:
2224 case ThreadSetTlsArrayAddress
:
2226 FIXME( "info class %d not supported yet\n", class );
2227 return STATUS_NOT_IMPLEMENTED
;
2232 /******************************************************************************
2233 * NtSetInformationThread (NTDLL.@)
2235 NTSTATUS WINAPI
NtSetInformationThread( HANDLE handle
, THREADINFOCLASS
class,
2236 const void *data
, ULONG length
)
2238 unsigned int status
;
2240 TRACE("(%p,%d,%p,%x)\n", handle
, class, data
, (int)length
);
2244 case ThreadZeroTlsCell
:
2245 if (handle
== GetCurrentThread())
2247 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
2248 return virtual_clear_tls_index( *(const ULONG
*)data
);
2250 FIXME( "ZeroTlsCell not supported on other threads\n" );
2251 return STATUS_NOT_IMPLEMENTED
;
2253 case ThreadImpersonationToken
:
2255 const HANDLE
*token
= data
;
2257 if (length
!= sizeof(HANDLE
)) return STATUS_INVALID_PARAMETER
;
2258 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token
);
2259 SERVER_START_REQ( set_thread_info
)
2261 req
->handle
= wine_server_obj_handle( handle
);
2262 req
->token
= wine_server_obj_handle( *token
);
2263 req
->mask
= SET_THREAD_INFO_TOKEN
;
2264 status
= wine_server_call( req
);
2270 case ThreadBasePriority
:
2272 const DWORD
*pprio
= data
;
2273 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
2274 SERVER_START_REQ( set_thread_info
)
2276 req
->handle
= wine_server_obj_handle( handle
);
2277 req
->priority
= *pprio
;
2278 req
->mask
= SET_THREAD_INFO_PRIORITY
;
2279 status
= wine_server_call( req
);
2285 case ThreadAffinityMask
:
2287 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2290 if (length
!= sizeof(ULONG_PTR
)) return STATUS_INVALID_PARAMETER
;
2291 req_aff
= *(const ULONG_PTR
*)data
& affinity_mask
;
2292 if (!req_aff
) return STATUS_INVALID_PARAMETER
;
2294 SERVER_START_REQ( set_thread_info
)
2296 req
->handle
= wine_server_obj_handle( handle
);
2297 req
->affinity
= req_aff
;
2298 req
->mask
= SET_THREAD_INFO_AFFINITY
;
2299 status
= wine_server_call( req
);
2305 case ThreadHideFromDebugger
:
2306 if (length
) return STATUS_INFO_LENGTH_MISMATCH
;
2307 SERVER_START_REQ( set_thread_info
)
2309 req
->handle
= wine_server_obj_handle( handle
);
2310 req
->mask
= SET_THREAD_INFO_DBG_HIDDEN
;
2311 status
= wine_server_call( req
);
2316 case ThreadQuerySetWin32StartAddress
:
2318 const PRTL_THREAD_START_ROUTINE
*entry
= data
;
2319 if (length
!= sizeof(PRTL_THREAD_START_ROUTINE
)) return STATUS_INVALID_PARAMETER
;
2320 SERVER_START_REQ( set_thread_info
)
2322 req
->handle
= wine_server_obj_handle( handle
);
2323 req
->mask
= SET_THREAD_INFO_ENTRYPOINT
;
2324 req
->entry_point
= wine_server_client_ptr( *entry
);
2325 status
= wine_server_call( req
);
2331 case ThreadGroupInformation
:
2333 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2334 const GROUP_AFFINITY
*req_aff
;
2336 if (length
!= sizeof(*req_aff
)) return STATUS_INVALID_PARAMETER
;
2337 if (!data
) return STATUS_ACCESS_VIOLATION
;
2340 /* On Windows the request fails if the reserved fields are set */
2341 if (req_aff
->Reserved
[0] || req_aff
->Reserved
[1] || req_aff
->Reserved
[2])
2342 return STATUS_INVALID_PARAMETER
;
2344 /* Wine only supports max 64 processors */
2345 if (req_aff
->Group
) return STATUS_INVALID_PARAMETER
;
2346 if (req_aff
->Mask
& ~affinity_mask
) return STATUS_INVALID_PARAMETER
;
2347 if (!req_aff
->Mask
) return STATUS_INVALID_PARAMETER
;
2348 SERVER_START_REQ( set_thread_info
)
2350 req
->handle
= wine_server_obj_handle( handle
);
2351 req
->affinity
= req_aff
->Mask
;
2352 req
->mask
= SET_THREAD_INFO_AFFINITY
;
2353 status
= wine_server_call( req
);
2359 case ThreadNameInformation
:
2361 const THREAD_NAME_INFORMATION
*info
= data
;
2362 THREAD_BASIC_INFORMATION tbi
;
2364 if (length
!= sizeof(*info
)) return STATUS_INFO_LENGTH_MISMATCH
;
2365 if (!info
) return STATUS_ACCESS_VIOLATION
;
2366 if (info
->ThreadName
.Length
&& !info
->ThreadName
.Buffer
) return STATUS_ACCESS_VIOLATION
;
2368 status
= NtQueryInformationThread( handle
, ThreadBasicInformation
, &tbi
, sizeof(tbi
), NULL
);
2369 if (handle
== GetCurrentThread() || (!status
&& (HandleToULong(tbi
.ClientId
.UniqueThread
) == GetCurrentThreadId())))
2370 WARN_(threadname
)( "Thread renamed to %s\n", debugstr_us(&info
->ThreadName
) );
2372 WARN_(threadname
)( "Thread ID %04x renamed to %s\n", (int)HandleToULong( tbi
.ClientId
.UniqueThread
), debugstr_us(&info
->ThreadName
) );
2374 WARN_(threadname
)( "Thread handle %p renamed to %s\n", handle
, debugstr_us(&info
->ThreadName
) );
2376 SERVER_START_REQ( set_thread_info
)
2378 req
->handle
= wine_server_obj_handle( handle
);
2379 req
->mask
= SET_THREAD_INFO_DESCRIPTION
;
2380 wine_server_add_data( req
, info
->ThreadName
.Buffer
, info
->ThreadName
.Length
);
2381 status
= wine_server_call( req
);
2385 set_native_thread_name( handle
, &info
->ThreadName
);
2390 case ThreadWineNativeThreadName
:
2392 const THREAD_NAME_INFORMATION
*info
= data
;
2394 if (length
!= sizeof(*info
)) return STATUS_INFO_LENGTH_MISMATCH
;
2396 set_native_thread_name( handle
, &info
->ThreadName
);
2397 return STATUS_SUCCESS
;
2400 case ThreadWow64Context
:
2401 return set_thread_wow64_context( handle
, data
, length
);
2403 case ThreadEnableAlignmentFaultFixup
:
2404 if (length
!= sizeof(BOOLEAN
)) return STATUS_INFO_LENGTH_MISMATCH
;
2405 if (!data
) return STATUS_ACCESS_VIOLATION
;
2406 FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" );
2407 return STATUS_SUCCESS
;
2409 case ThreadPowerThrottlingState
:
2410 if (length
!= sizeof(THREAD_POWER_THROTTLING_STATE
)) return STATUS_INFO_LENGTH_MISMATCH
;
2411 if (!data
) return STATUS_ACCESS_VIOLATION
;
2412 FIXME( "ThreadPowerThrottling stub!\n" );
2413 return STATUS_SUCCESS
;
2415 case ThreadIdealProcessor
:
2417 const ULONG
*number
= data
;
2419 if (length
!= sizeof(*number
)) return STATUS_INFO_LENGTH_MISMATCH
;
2420 if (*number
> MAXIMUM_PROCESSORS
) return STATUS_INVALID_PARAMETER
;
2421 FIXME( "ThreadIdealProcessor stub!\n" );
2422 return STATUS_SUCCESS
;
2425 case ThreadPriorityBoost
:
2426 WARN("Unimplemented class ThreadPriorityBoost.\n");
2427 return STATUS_SUCCESS
;
2429 case ThreadBasicInformation
:
2431 case ThreadPriority
:
2432 case ThreadDescriptorTableEntry
:
2433 case ThreadEventPair_Reusable
:
2434 case ThreadPerformanceCount
:
2435 case ThreadAmILastThread
:
2436 case ThreadSetTlsArrayAddress
:
2437 case ThreadIsIoPending
:
2439 FIXME( "info class %d not supported yet\n", class );
2440 return STATUS_NOT_IMPLEMENTED
;
2445 /******************************************************************************
2446 * NtGetCurrentProcessorNumber (NTDLL.@)
2448 ULONG WINAPI
NtGetCurrentProcessorNumber(void)
2452 #if defined(__linux__) && defined(__NR_getcpu)
2453 int res
= syscall(__NR_getcpu
, &processor
, NULL
, NULL
);
2454 if (res
!= -1) return processor
;
2457 if (peb
->NumberOfProcessors
> 1)
2459 ULONG_PTR thread_mask
, processor_mask
;
2461 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask
,
2462 &thread_mask
, sizeof(thread_mask
), NULL
))
2464 for (processor
= 0; processor
< peb
->NumberOfProcessors
; processor
++)
2466 processor_mask
= (1 << processor
);
2467 if (thread_mask
& processor_mask
)
2469 if (thread_mask
!= processor_mask
)
2470 FIXME( "need multicore support (%d processors)\n",
2471 (int)peb
->NumberOfProcessors
);
2477 /* fallback to the first processor */
2482 /******************************************************************************
2483 * NtGetNextThread (NTDLL.@)
2485 NTSTATUS WINAPI
NtGetNextThread( HANDLE process
, HANDLE thread
, ACCESS_MASK access
, ULONG attributes
,
2486 ULONG flags
, HANDLE
*handle
)
2488 HANDLE ret_handle
= 0;
2491 TRACE( "process %p, thread %p, access %#x, attributes %#x, flags %#x, handle %p.\n",
2492 process
, thread
, (int)access
, (int)attributes
, (int)flags
, handle
);
2494 SERVER_START_REQ( get_next_thread
)
2496 req
->process
= wine_server_obj_handle( process
);
2497 req
->last
= wine_server_obj_handle( thread
);
2498 req
->access
= access
;
2499 req
->attributes
= attributes
;
2501 if (!(ret
= wine_server_call( req
))) ret_handle
= wine_server_ptr_handle( reply
->handle
);
2505 *handle
= ret_handle
;