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
36 #include <sys/types.h>
39 #ifdef HAVE_SYS_TIMES_H
40 #include <sys/times.h>
42 #ifdef HAVE_SYS_SYSCALL_H
43 #include <sys/syscall.h>
45 #ifdef HAVE_SYS_SYSCTL_H
46 #include <sys/sysctl.h>
48 #ifdef HAVE_SYS_PARAM_H
49 #include <sys/param.h>
51 #ifdef HAVE_SYS_QUEUE_H
52 #include <sys/queue.h>
54 #ifdef HAVE_SYS_USER_H
57 #ifdef HAVE_LIBPROCSTAT_H
58 #include <libprocstat.h>
61 #define NONAMELESSUNION
62 #define NONAMELESSSTRUCT
64 #define WIN32_NO_STATUS
67 #include "wine/server.h"
68 #include "wine/debug.h"
69 #include "unix_private.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(thread
);
72 WINE_DECLARE_DEBUG_CHANNEL(seh
);
73 WINE_DECLARE_DEBUG_CHANNEL(threadname
);
75 static int nb_threads
= 1;
77 static inline int get_unix_exit_code( NTSTATUS status
)
79 /* prevent a nonzero exit code to end up truncated to zero in unix */
80 if (status
&& !(status
& 0xff)) return 1;
85 /***********************************************************************
88 * Build a standard i386 FPU context from an extended one.
90 void fpux_to_fpu( I386_FLOATING_SAVE_AREA
*fpu
, const XMM_SAVE_AREA32
*fpux
)
92 unsigned int i
, tag
, stack_top
;
94 fpu
->ControlWord
= fpux
->ControlWord
;
95 fpu
->StatusWord
= fpux
->StatusWord
;
96 fpu
->ErrorOffset
= fpux
->ErrorOffset
;
97 fpu
->ErrorSelector
= fpux
->ErrorSelector
| (fpux
->ErrorOpcode
<< 16);
98 fpu
->DataOffset
= fpux
->DataOffset
;
99 fpu
->DataSelector
= fpux
->DataSelector
;
100 fpu
->Cr0NpxState
= fpux
->StatusWord
| 0xffff0000;
102 stack_top
= (fpux
->StatusWord
>> 11) & 7;
103 fpu
->TagWord
= 0xffff0000;
104 for (i
= 0; i
< 8; i
++)
106 memcpy( &fpu
->RegisterArea
[10 * i
], &fpux
->FloatRegisters
[i
], 10 );
107 if (!(fpux
->TagWord
& (1 << i
))) tag
= 3; /* empty */
110 const M128A
*reg
= &fpux
->FloatRegisters
[(i
- stack_top
) & 7];
111 if ((reg
->High
& 0x7fff) == 0x7fff) /* exponent all ones */
113 tag
= 2; /* special */
115 else if (!(reg
->High
& 0x7fff)) /* exponent all zeroes */
117 if (reg
->Low
) tag
= 2; /* special */
118 else tag
= 1; /* zero */
122 if (reg
->Low
>> 63) tag
= 0; /* valid */
123 else tag
= 2; /* special */
126 fpu
->TagWord
|= tag
<< (2 * i
);
131 /***********************************************************************
134 * Fill extended i386 FPU context from standard one.
136 void fpu_to_fpux( XMM_SAVE_AREA32
*fpux
, const I386_FLOATING_SAVE_AREA
*fpu
)
140 fpux
->ControlWord
= fpu
->ControlWord
;
141 fpux
->StatusWord
= fpu
->StatusWord
;
142 fpux
->ErrorOffset
= fpu
->ErrorOffset
;
143 fpux
->ErrorSelector
= fpu
->ErrorSelector
;
144 fpux
->ErrorOpcode
= fpu
->ErrorSelector
>> 16;
145 fpux
->DataOffset
= fpu
->DataOffset
;
146 fpux
->DataSelector
= fpu
->DataSelector
;
148 for (i
= 0; i
< 8; i
++)
150 if (((fpu
->TagWord
>> (i
* 2)) & 3) != 3) fpux
->TagWord
|= 1 << i
;
151 memcpy( &fpux
->FloatRegisters
[i
], &fpu
->RegisterArea
[10 * i
], 10 );
156 /***********************************************************************
157 * get_server_context_flags
159 static unsigned int get_server_context_flags( const void *context
, USHORT machine
)
161 unsigned int flags
, ret
= 0;
165 case IMAGE_FILE_MACHINE_I386
:
166 flags
= ((const I386_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_i386
;
167 if (flags
& CONTEXT_I386_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
168 if (flags
& CONTEXT_I386_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
169 if (flags
& CONTEXT_I386_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
170 if (flags
& CONTEXT_I386_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
171 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
172 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
) ret
|= SERVER_CTX_EXTENDED_REGISTERS
| SERVER_CTX_FLOATING_POINT
;
173 if (flags
& CONTEXT_I386_XSTATE
) ret
|= SERVER_CTX_YMM_REGISTERS
;
175 case IMAGE_FILE_MACHINE_AMD64
:
176 flags
= ((const AMD64_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_AMD64
;
177 if (flags
& CONTEXT_AMD64_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
178 if (flags
& CONTEXT_AMD64_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
179 if (flags
& CONTEXT_AMD64_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
180 if (flags
& CONTEXT_AMD64_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
181 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
182 if (flags
& CONTEXT_AMD64_XSTATE
) ret
|= SERVER_CTX_YMM_REGISTERS
;
184 case IMAGE_FILE_MACHINE_ARMNT
:
185 flags
= ((const ARM_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_ARM
;
186 if (flags
& CONTEXT_ARM_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
187 if (flags
& CONTEXT_ARM_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
188 if (flags
& CONTEXT_ARM_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
189 if (flags
& CONTEXT_ARM_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
191 case IMAGE_FILE_MACHINE_ARM64
:
192 flags
= ((const ARM64_NT_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_ARM64
;
193 if (flags
& CONTEXT_ARM64_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
194 if (flags
& CONTEXT_ARM64_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
195 if (flags
& CONTEXT_ARM64_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
196 if (flags
& CONTEXT_ARM64_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
203 /***********************************************************************
206 * Convert a register context to the server format.
208 static NTSTATUS
context_to_server( context_t
*to
, USHORT to_machine
, const void *src
, USHORT from_machine
)
212 memset( to
, 0, sizeof(*to
) );
213 to
->machine
= to_machine
;
215 switch (MAKELONG( from_machine
, to_machine
))
217 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_I386
):
219 const I386_CONTEXT
*from
= src
;
221 flags
= from
->ContextFlags
& ~CONTEXT_i386
;
222 if (flags
& CONTEXT_I386_CONTROL
)
224 to
->flags
|= SERVER_CTX_CONTROL
;
225 to
->ctl
.i386_regs
.ebp
= from
->Ebp
;
226 to
->ctl
.i386_regs
.esp
= from
->Esp
;
227 to
->ctl
.i386_regs
.eip
= from
->Eip
;
228 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
229 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
230 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
232 if (flags
& CONTEXT_I386_INTEGER
)
234 to
->flags
|= SERVER_CTX_INTEGER
;
235 to
->integer
.i386_regs
.eax
= from
->Eax
;
236 to
->integer
.i386_regs
.ebx
= from
->Ebx
;
237 to
->integer
.i386_regs
.ecx
= from
->Ecx
;
238 to
->integer
.i386_regs
.edx
= from
->Edx
;
239 to
->integer
.i386_regs
.esi
= from
->Esi
;
240 to
->integer
.i386_regs
.edi
= from
->Edi
;
242 if (flags
& CONTEXT_I386_SEGMENTS
)
244 to
->flags
|= SERVER_CTX_SEGMENTS
;
245 to
->seg
.i386_regs
.ds
= from
->SegDs
;
246 to
->seg
.i386_regs
.es
= from
->SegEs
;
247 to
->seg
.i386_regs
.fs
= from
->SegFs
;
248 to
->seg
.i386_regs
.gs
= from
->SegGs
;
250 if (flags
& CONTEXT_I386_FLOATING_POINT
)
252 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
253 to
->fp
.i386_regs
.ctrl
= from
->FloatSave
.ControlWord
;
254 to
->fp
.i386_regs
.status
= from
->FloatSave
.StatusWord
;
255 to
->fp
.i386_regs
.tag
= from
->FloatSave
.TagWord
;
256 to
->fp
.i386_regs
.err_off
= from
->FloatSave
.ErrorOffset
;
257 to
->fp
.i386_regs
.err_sel
= from
->FloatSave
.ErrorSelector
;
258 to
->fp
.i386_regs
.data_off
= from
->FloatSave
.DataOffset
;
259 to
->fp
.i386_regs
.data_sel
= from
->FloatSave
.DataSelector
;
260 to
->fp
.i386_regs
.cr0npx
= from
->FloatSave
.Cr0NpxState
;
261 memcpy( to
->fp
.i386_regs
.regs
, from
->FloatSave
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
263 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
)
265 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
266 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
267 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
268 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
269 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
270 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
271 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
273 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
275 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
;
276 memcpy( to
->ext
.i386_regs
, from
->ExtendedRegisters
, sizeof(to
->ext
.i386_regs
) );
278 if (flags
& CONTEXT_I386_XSTATE
)
280 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
281 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
283 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
284 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
286 return STATUS_SUCCESS
;
289 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_AMD64
):
291 const I386_CONTEXT
*from
= src
;
293 flags
= from
->ContextFlags
& ~CONTEXT_i386
;
294 if (flags
& CONTEXT_I386_CONTROL
)
296 to
->flags
|= SERVER_CTX_CONTROL
;
297 to
->ctl
.x86_64_regs
.rbp
= from
->Ebp
;
298 to
->ctl
.x86_64_regs
.rsp
= from
->Esp
;
299 to
->ctl
.x86_64_regs
.rip
= from
->Eip
;
300 to
->ctl
.x86_64_regs
.cs
= from
->SegCs
;
301 to
->ctl
.x86_64_regs
.ss
= from
->SegSs
;
302 to
->ctl
.x86_64_regs
.flags
= from
->EFlags
;
304 if (flags
& CONTEXT_I386_INTEGER
)
306 to
->flags
|= SERVER_CTX_INTEGER
;
307 to
->integer
.x86_64_regs
.rax
= from
->Eax
;
308 to
->integer
.x86_64_regs
.rbx
= from
->Ebx
;
309 to
->integer
.x86_64_regs
.rcx
= from
->Ecx
;
310 to
->integer
.x86_64_regs
.rdx
= from
->Edx
;
311 to
->integer
.x86_64_regs
.rsi
= from
->Esi
;
312 to
->integer
.x86_64_regs
.rdi
= from
->Edi
;
314 if (flags
& CONTEXT_I386_SEGMENTS
)
316 to
->flags
|= SERVER_CTX_SEGMENTS
;
317 to
->seg
.x86_64_regs
.ds
= from
->SegDs
;
318 to
->seg
.x86_64_regs
.es
= from
->SegEs
;
319 to
->seg
.x86_64_regs
.fs
= from
->SegFs
;
320 to
->seg
.x86_64_regs
.gs
= from
->SegGs
;
322 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
)
324 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
325 to
->debug
.x86_64_regs
.dr0
= from
->Dr0
;
326 to
->debug
.x86_64_regs
.dr1
= from
->Dr1
;
327 to
->debug
.x86_64_regs
.dr2
= from
->Dr2
;
328 to
->debug
.x86_64_regs
.dr3
= from
->Dr3
;
329 to
->debug
.x86_64_regs
.dr6
= from
->Dr6
;
330 to
->debug
.x86_64_regs
.dr7
= from
->Dr7
;
332 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
334 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
335 memcpy( to
->fp
.x86_64_regs
.fpregs
, from
->ExtendedRegisters
, sizeof(to
->fp
.x86_64_regs
.fpregs
) );
337 else if (flags
& CONTEXT_I386_FLOATING_POINT
)
339 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
340 fpu_to_fpux( (XMM_SAVE_AREA32
*)to
->fp
.x86_64_regs
.fpregs
, &from
->FloatSave
);
342 if (flags
& CONTEXT_I386_XSTATE
)
344 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
345 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
347 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
348 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
350 return STATUS_SUCCESS
;
353 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_AMD64
):
355 const AMD64_CONTEXT
*from
= src
;
357 flags
= from
->ContextFlags
& ~CONTEXT_AMD64
;
358 if (flags
& CONTEXT_AMD64_CONTROL
)
360 to
->flags
|= SERVER_CTX_CONTROL
;
361 to
->ctl
.x86_64_regs
.rbp
= from
->Rbp
;
362 to
->ctl
.x86_64_regs
.rip
= from
->Rip
;
363 to
->ctl
.x86_64_regs
.rsp
= from
->Rsp
;
364 to
->ctl
.x86_64_regs
.cs
= from
->SegCs
;
365 to
->ctl
.x86_64_regs
.ss
= from
->SegSs
;
366 to
->ctl
.x86_64_regs
.flags
= from
->EFlags
;
368 if (flags
& CONTEXT_AMD64_INTEGER
)
370 to
->flags
|= SERVER_CTX_INTEGER
;
371 to
->integer
.x86_64_regs
.rax
= from
->Rax
;
372 to
->integer
.x86_64_regs
.rcx
= from
->Rcx
;
373 to
->integer
.x86_64_regs
.rdx
= from
->Rdx
;
374 to
->integer
.x86_64_regs
.rbx
= from
->Rbx
;
375 to
->integer
.x86_64_regs
.rsi
= from
->Rsi
;
376 to
->integer
.x86_64_regs
.rdi
= from
->Rdi
;
377 to
->integer
.x86_64_regs
.r8
= from
->R8
;
378 to
->integer
.x86_64_regs
.r9
= from
->R9
;
379 to
->integer
.x86_64_regs
.r10
= from
->R10
;
380 to
->integer
.x86_64_regs
.r11
= from
->R11
;
381 to
->integer
.x86_64_regs
.r12
= from
->R12
;
382 to
->integer
.x86_64_regs
.r13
= from
->R13
;
383 to
->integer
.x86_64_regs
.r14
= from
->R14
;
384 to
->integer
.x86_64_regs
.r15
= from
->R15
;
386 if (flags
& CONTEXT_AMD64_SEGMENTS
)
388 to
->flags
|= SERVER_CTX_SEGMENTS
;
389 to
->seg
.x86_64_regs
.ds
= from
->SegDs
;
390 to
->seg
.x86_64_regs
.es
= from
->SegEs
;
391 to
->seg
.x86_64_regs
.fs
= from
->SegFs
;
392 to
->seg
.x86_64_regs
.gs
= from
->SegGs
;
394 if (flags
& CONTEXT_AMD64_FLOATING_POINT
)
396 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
397 memcpy( to
->fp
.x86_64_regs
.fpregs
, &from
->u
.FltSave
, sizeof(to
->fp
.x86_64_regs
.fpregs
) );
399 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
)
401 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
402 to
->debug
.x86_64_regs
.dr0
= from
->Dr0
;
403 to
->debug
.x86_64_regs
.dr1
= from
->Dr1
;
404 to
->debug
.x86_64_regs
.dr2
= from
->Dr2
;
405 to
->debug
.x86_64_regs
.dr3
= from
->Dr3
;
406 to
->debug
.x86_64_regs
.dr6
= from
->Dr6
;
407 to
->debug
.x86_64_regs
.dr7
= from
->Dr7
;
409 if (flags
& CONTEXT_AMD64_XSTATE
)
411 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
412 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
414 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
415 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
417 return STATUS_SUCCESS
;
420 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_I386
):
422 const AMD64_CONTEXT
*from
= src
;
424 flags
= from
->ContextFlags
& ~CONTEXT_AMD64
;
425 if (flags
& CONTEXT_AMD64_CONTROL
)
427 to
->flags
|= SERVER_CTX_CONTROL
;
428 to
->ctl
.i386_regs
.ebp
= from
->Rbp
;
429 to
->ctl
.i386_regs
.eip
= from
->Rip
;
430 to
->ctl
.i386_regs
.esp
= from
->Rsp
;
431 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
432 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
433 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
435 if (flags
& CONTEXT_AMD64_INTEGER
)
437 to
->flags
|= SERVER_CTX_INTEGER
;
438 to
->integer
.i386_regs
.eax
= from
->Rax
;
439 to
->integer
.i386_regs
.ecx
= from
->Rcx
;
440 to
->integer
.i386_regs
.edx
= from
->Rdx
;
441 to
->integer
.i386_regs
.ebx
= from
->Rbx
;
442 to
->integer
.i386_regs
.esi
= from
->Rsi
;
443 to
->integer
.i386_regs
.edi
= from
->Rdi
;
445 if (flags
& CONTEXT_AMD64_SEGMENTS
)
447 to
->flags
|= SERVER_CTX_SEGMENTS
;
448 to
->seg
.i386_regs
.ds
= from
->SegDs
;
449 to
->seg
.i386_regs
.es
= from
->SegEs
;
450 to
->seg
.i386_regs
.fs
= from
->SegFs
;
451 to
->seg
.i386_regs
.gs
= from
->SegGs
;
453 if (flags
& CONTEXT_AMD64_FLOATING_POINT
)
455 I386_FLOATING_SAVE_AREA fpu
;
457 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
| SERVER_CTX_FLOATING_POINT
;
458 memcpy( to
->ext
.i386_regs
, &from
->u
.FltSave
, sizeof(to
->ext
.i386_regs
) );
459 fpux_to_fpu( &fpu
, &from
->u
.FltSave
);
460 to
->fp
.i386_regs
.ctrl
= fpu
.ControlWord
;
461 to
->fp
.i386_regs
.status
= fpu
.StatusWord
;
462 to
->fp
.i386_regs
.tag
= fpu
.TagWord
;
463 to
->fp
.i386_regs
.err_off
= fpu
.ErrorOffset
;
464 to
->fp
.i386_regs
.err_sel
= fpu
.ErrorSelector
;
465 to
->fp
.i386_regs
.data_off
= fpu
.DataOffset
;
466 to
->fp
.i386_regs
.data_sel
= fpu
.DataSelector
;
467 to
->fp
.i386_regs
.cr0npx
= fpu
.Cr0NpxState
;
468 memcpy( to
->fp
.i386_regs
.regs
, fpu
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
470 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
)
472 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
473 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
474 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
475 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
476 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
477 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
478 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
480 if (flags
& CONTEXT_AMD64_XSTATE
)
482 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
483 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
485 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
486 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
488 return STATUS_SUCCESS
;
491 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT
, IMAGE_FILE_MACHINE_ARMNT
):
493 const ARM_CONTEXT
*from
= src
;
495 flags
= from
->ContextFlags
& ~CONTEXT_ARM
;
496 if (flags
& CONTEXT_ARM_CONTROL
)
498 to
->flags
|= SERVER_CTX_CONTROL
;
499 to
->ctl
.arm_regs
.sp
= from
->Sp
;
500 to
->ctl
.arm_regs
.lr
= from
->Lr
;
501 to
->ctl
.arm_regs
.pc
= from
->Pc
;
502 to
->ctl
.arm_regs
.cpsr
= from
->Cpsr
;
504 if (flags
& CONTEXT_ARM_INTEGER
)
506 to
->flags
|= SERVER_CTX_INTEGER
;
507 to
->integer
.arm_regs
.r
[0] = from
->R0
;
508 to
->integer
.arm_regs
.r
[1] = from
->R1
;
509 to
->integer
.arm_regs
.r
[2] = from
->R2
;
510 to
->integer
.arm_regs
.r
[3] = from
->R3
;
511 to
->integer
.arm_regs
.r
[4] = from
->R4
;
512 to
->integer
.arm_regs
.r
[5] = from
->R5
;
513 to
->integer
.arm_regs
.r
[6] = from
->R6
;
514 to
->integer
.arm_regs
.r
[7] = from
->R7
;
515 to
->integer
.arm_regs
.r
[8] = from
->R8
;
516 to
->integer
.arm_regs
.r
[9] = from
->R9
;
517 to
->integer
.arm_regs
.r
[10] = from
->R10
;
518 to
->integer
.arm_regs
.r
[11] = from
->R11
;
519 to
->integer
.arm_regs
.r
[12] = from
->R12
;
521 if (flags
& CONTEXT_ARM_FLOATING_POINT
)
523 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
524 for (i
= 0; i
< 32; i
++) to
->fp
.arm_regs
.d
[i
] = from
->u
.D
[i
];
525 to
->fp
.arm_regs
.fpscr
= from
->Fpscr
;
527 if (flags
& CONTEXT_ARM_DEBUG_REGISTERS
)
529 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
530 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->debug
.arm_regs
.bvr
[i
] = from
->Bvr
[i
];
531 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->debug
.arm_regs
.bcr
[i
] = from
->Bcr
[i
];
532 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->debug
.arm_regs
.wvr
[i
] = from
->Wvr
[i
];
533 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->debug
.arm_regs
.wcr
[i
] = from
->Wcr
[i
];
535 return STATUS_SUCCESS
;
538 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_ARM64
):
540 const ARM64_NT_CONTEXT
*from
= src
;
542 flags
= from
->ContextFlags
& ~CONTEXT_ARM64
;
543 if (flags
& CONTEXT_ARM64_CONTROL
)
545 to
->flags
|= SERVER_CTX_CONTROL
;
546 to
->integer
.arm64_regs
.x
[29] = from
->u
.s
.Fp
;
547 to
->integer
.arm64_regs
.x
[30] = from
->u
.s
.Lr
;
548 to
->ctl
.arm64_regs
.sp
= from
->Sp
;
549 to
->ctl
.arm64_regs
.pc
= from
->Pc
;
550 to
->ctl
.arm64_regs
.pstate
= from
->Cpsr
;
552 if (flags
& CONTEXT_ARM64_INTEGER
)
554 to
->flags
|= SERVER_CTX_INTEGER
;
555 for (i
= 0; i
<= 28; i
++) to
->integer
.arm64_regs
.x
[i
] = from
->u
.X
[i
];
557 if (flags
& CONTEXT_ARM64_FLOATING_POINT
)
559 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
560 for (i
= 0; i
< 32; i
++)
562 to
->fp
.arm64_regs
.q
[i
].low
= from
->V
[i
].s
.Low
;
563 to
->fp
.arm64_regs
.q
[i
].high
= from
->V
[i
].s
.High
;
565 to
->fp
.arm64_regs
.fpcr
= from
->Fpcr
;
566 to
->fp
.arm64_regs
.fpsr
= from
->Fpsr
;
568 if (flags
& CONTEXT_ARM64_DEBUG_REGISTERS
)
570 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
571 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->debug
.arm64_regs
.bcr
[i
] = from
->Bcr
[i
];
572 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->debug
.arm64_regs
.bvr
[i
] = from
->Bvr
[i
];
573 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->debug
.arm64_regs
.wcr
[i
] = from
->Wcr
[i
];
574 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->debug
.arm64_regs
.wvr
[i
] = from
->Wvr
[i
];
576 return STATUS_SUCCESS
;
580 return STATUS_INVALID_PARAMETER
;
585 /***********************************************************************
586 * context_from_server
588 * Convert a register context from the server format.
590 static NTSTATUS
context_from_server( void *dst
, const context_t
*from
, USHORT machine
)
594 switch (MAKELONG( from
->machine
, machine
))
596 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_I386
):
598 I386_CONTEXT
*to
= dst
;
600 to_flags
= to
->ContextFlags
& ~CONTEXT_i386
;
601 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_I386_CONTROL
))
603 to
->ContextFlags
|= CONTEXT_I386_CONTROL
;
604 to
->Ebp
= from
->ctl
.i386_regs
.ebp
;
605 to
->Esp
= from
->ctl
.i386_regs
.esp
;
606 to
->Eip
= from
->ctl
.i386_regs
.eip
;
607 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
608 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
609 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
611 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_I386_INTEGER
))
613 to
->ContextFlags
|= CONTEXT_I386_INTEGER
;
614 to
->Eax
= from
->integer
.i386_regs
.eax
;
615 to
->Ebx
= from
->integer
.i386_regs
.ebx
;
616 to
->Ecx
= from
->integer
.i386_regs
.ecx
;
617 to
->Edx
= from
->integer
.i386_regs
.edx
;
618 to
->Esi
= from
->integer
.i386_regs
.esi
;
619 to
->Edi
= from
->integer
.i386_regs
.edi
;
621 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_I386_SEGMENTS
))
623 to
->ContextFlags
|= CONTEXT_I386_SEGMENTS
;
624 to
->SegDs
= from
->seg
.i386_regs
.ds
;
625 to
->SegEs
= from
->seg
.i386_regs
.es
;
626 to
->SegFs
= from
->seg
.i386_regs
.fs
;
627 to
->SegGs
= from
->seg
.i386_regs
.gs
;
629 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_I386_FLOATING_POINT
))
631 to
->ContextFlags
|= CONTEXT_I386_FLOATING_POINT
;
632 to
->FloatSave
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
633 to
->FloatSave
.StatusWord
= from
->fp
.i386_regs
.status
;
634 to
->FloatSave
.TagWord
= from
->fp
.i386_regs
.tag
;
635 to
->FloatSave
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
636 to
->FloatSave
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
637 to
->FloatSave
.DataOffset
= from
->fp
.i386_regs
.data_off
;
638 to
->FloatSave
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
639 to
->FloatSave
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
640 memcpy( to
->FloatSave
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(to
->FloatSave
.RegisterArea
) );
642 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_I386_DEBUG_REGISTERS
))
644 to
->ContextFlags
|= CONTEXT_I386_DEBUG_REGISTERS
;
645 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
646 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
647 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
648 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
649 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
650 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
652 if ((from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
) && (to_flags
& CONTEXT_I386_EXTENDED_REGISTERS
))
654 to
->ContextFlags
|= CONTEXT_I386_EXTENDED_REGISTERS
;
655 memcpy( to
->ExtendedRegisters
, from
->ext
.i386_regs
, sizeof(to
->ExtendedRegisters
) );
657 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_I386_XSTATE
))
659 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
660 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
663 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
664 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
666 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
667 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
672 return STATUS_SUCCESS
;
675 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_I386
):
677 I386_CONTEXT
*to
= dst
;
679 to_flags
= to
->ContextFlags
& ~CONTEXT_i386
;
680 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_I386_CONTROL
))
682 to
->ContextFlags
|= CONTEXT_I386_CONTROL
;
683 to
->Ebp
= from
->ctl
.x86_64_regs
.rbp
;
684 to
->Esp
= from
->ctl
.x86_64_regs
.rsp
;
685 to
->Eip
= from
->ctl
.x86_64_regs
.rip
;
686 to
->SegCs
= from
->ctl
.x86_64_regs
.cs
;
687 to
->SegSs
= from
->ctl
.x86_64_regs
.ss
;
688 to
->EFlags
= from
->ctl
.x86_64_regs
.flags
;
690 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_I386_INTEGER
))
692 to
->ContextFlags
|= CONTEXT_I386_INTEGER
;
693 to
->Eax
= from
->integer
.x86_64_regs
.rax
;
694 to
->Ebx
= from
->integer
.x86_64_regs
.rbx
;
695 to
->Ecx
= from
->integer
.x86_64_regs
.rcx
;
696 to
->Edx
= from
->integer
.x86_64_regs
.rdx
;
697 to
->Esi
= from
->integer
.x86_64_regs
.rsi
;
698 to
->Edi
= from
->integer
.x86_64_regs
.rdi
;
700 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_I386_SEGMENTS
))
702 to
->ContextFlags
|= CONTEXT_I386_SEGMENTS
;
703 to
->SegDs
= from
->seg
.x86_64_regs
.ds
;
704 to
->SegEs
= from
->seg
.x86_64_regs
.es
;
705 to
->SegFs
= from
->seg
.x86_64_regs
.fs
;
706 to
->SegGs
= from
->seg
.x86_64_regs
.gs
;
708 if (from
->flags
& SERVER_CTX_FLOATING_POINT
)
710 if (to_flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
712 to
->ContextFlags
|= CONTEXT_I386_EXTENDED_REGISTERS
;
713 memcpy( to
->ExtendedRegisters
, from
->fp
.x86_64_regs
.fpregs
, sizeof(to
->ExtendedRegisters
) );
715 if (to_flags
& CONTEXT_I386_FLOATING_POINT
)
717 to
->ContextFlags
|= CONTEXT_I386_FLOATING_POINT
;
718 fpux_to_fpu( &to
->FloatSave
, (XMM_SAVE_AREA32
*)from
->fp
.x86_64_regs
.fpregs
);
721 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_I386_DEBUG_REGISTERS
))
723 to
->ContextFlags
|= CONTEXT_I386_DEBUG_REGISTERS
;
724 to
->Dr0
= from
->debug
.x86_64_regs
.dr0
;
725 to
->Dr1
= from
->debug
.x86_64_regs
.dr1
;
726 to
->Dr2
= from
->debug
.x86_64_regs
.dr2
;
727 to
->Dr3
= from
->debug
.x86_64_regs
.dr3
;
728 to
->Dr6
= from
->debug
.x86_64_regs
.dr6
;
729 to
->Dr7
= from
->debug
.x86_64_regs
.dr7
;
731 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_I386_XSTATE
))
733 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
734 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
737 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
738 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
740 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
741 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
746 return STATUS_SUCCESS
;
749 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_AMD64
):
751 AMD64_CONTEXT
*to
= dst
;
753 to_flags
= to
->ContextFlags
& ~CONTEXT_AMD64
;
754 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_AMD64_CONTROL
))
756 to
->ContextFlags
|= CONTEXT_AMD64_CONTROL
;
757 to
->Rbp
= from
->ctl
.x86_64_regs
.rbp
;
758 to
->Rip
= from
->ctl
.x86_64_regs
.rip
;
759 to
->Rsp
= from
->ctl
.x86_64_regs
.rsp
;
760 to
->SegCs
= from
->ctl
.x86_64_regs
.cs
;
761 to
->SegSs
= from
->ctl
.x86_64_regs
.ss
;
762 to
->EFlags
= from
->ctl
.x86_64_regs
.flags
;
764 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_AMD64_INTEGER
))
766 to
->ContextFlags
|= CONTEXT_AMD64_INTEGER
;
767 to
->Rax
= from
->integer
.x86_64_regs
.rax
;
768 to
->Rcx
= from
->integer
.x86_64_regs
.rcx
;
769 to
->Rdx
= from
->integer
.x86_64_regs
.rdx
;
770 to
->Rbx
= from
->integer
.x86_64_regs
.rbx
;
771 to
->Rsi
= from
->integer
.x86_64_regs
.rsi
;
772 to
->Rdi
= from
->integer
.x86_64_regs
.rdi
;
773 to
->R8
= from
->integer
.x86_64_regs
.r8
;
774 to
->R9
= from
->integer
.x86_64_regs
.r9
;
775 to
->R10
= from
->integer
.x86_64_regs
.r10
;
776 to
->R11
= from
->integer
.x86_64_regs
.r11
;
777 to
->R12
= from
->integer
.x86_64_regs
.r12
;
778 to
->R13
= from
->integer
.x86_64_regs
.r13
;
779 to
->R14
= from
->integer
.x86_64_regs
.r14
;
780 to
->R15
= from
->integer
.x86_64_regs
.r15
;
782 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_AMD64_SEGMENTS
))
784 to
->ContextFlags
|= CONTEXT_AMD64_SEGMENTS
;
785 to
->SegDs
= from
->seg
.x86_64_regs
.ds
;
786 to
->SegEs
= from
->seg
.x86_64_regs
.es
;
787 to
->SegFs
= from
->seg
.x86_64_regs
.fs
;
788 to
->SegGs
= from
->seg
.x86_64_regs
.gs
;
790 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
792 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
793 memcpy( &to
->u
.FltSave
, from
->fp
.x86_64_regs
.fpregs
, sizeof(from
->fp
.x86_64_regs
.fpregs
) );
794 to
->MxCsr
= to
->u
.FltSave
.MxCsr
;
796 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_AMD64_DEBUG_REGISTERS
))
798 to
->ContextFlags
|= CONTEXT_AMD64_DEBUG_REGISTERS
;
799 to
->Dr0
= from
->debug
.x86_64_regs
.dr0
;
800 to
->Dr1
= from
->debug
.x86_64_regs
.dr1
;
801 to
->Dr2
= from
->debug
.x86_64_regs
.dr2
;
802 to
->Dr3
= from
->debug
.x86_64_regs
.dr3
;
803 to
->Dr6
= from
->debug
.x86_64_regs
.dr6
;
804 to
->Dr7
= from
->debug
.x86_64_regs
.dr7
;
806 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_AMD64_XSTATE
))
808 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
809 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
812 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
813 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
815 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
816 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
821 return STATUS_SUCCESS
;
824 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_AMD64
):
826 AMD64_CONTEXT
*to
= dst
;
828 to_flags
= to
->ContextFlags
& ~CONTEXT_AMD64
;
829 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_AMD64_CONTROL
))
831 to
->ContextFlags
|= CONTEXT_AMD64_CONTROL
;
832 to
->Rbp
= from
->ctl
.i386_regs
.ebp
;
833 to
->Rip
= from
->ctl
.i386_regs
.eip
;
834 to
->Rsp
= from
->ctl
.i386_regs
.esp
;
835 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
836 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
837 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
839 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_AMD64_INTEGER
))
841 to
->ContextFlags
|= CONTEXT_AMD64_INTEGER
;
842 to
->Rax
= from
->integer
.i386_regs
.eax
;
843 to
->Rcx
= from
->integer
.i386_regs
.ecx
;
844 to
->Rdx
= from
->integer
.i386_regs
.edx
;
845 to
->Rbx
= from
->integer
.i386_regs
.ebx
;
846 to
->Rsi
= from
->integer
.i386_regs
.esi
;
847 to
->Rdi
= from
->integer
.i386_regs
.edi
;
849 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_AMD64_SEGMENTS
))
851 to
->ContextFlags
|= CONTEXT_AMD64_SEGMENTS
;
852 to
->SegDs
= from
->seg
.i386_regs
.ds
;
853 to
->SegEs
= from
->seg
.i386_regs
.es
;
854 to
->SegFs
= from
->seg
.i386_regs
.fs
;
855 to
->SegGs
= from
->seg
.i386_regs
.gs
;
857 if ((from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
859 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
860 memcpy( &to
->u
.FltSave
, from
->ext
.i386_regs
, sizeof(to
->u
.FltSave
) );
862 else if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
864 I386_FLOATING_SAVE_AREA fpu
;
866 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
867 fpu
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
868 fpu
.StatusWord
= from
->fp
.i386_regs
.status
;
869 fpu
.TagWord
= from
->fp
.i386_regs
.tag
;
870 fpu
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
871 fpu
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
872 fpu
.DataOffset
= from
->fp
.i386_regs
.data_off
;
873 fpu
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
874 fpu
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
875 memcpy( fpu
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(fpu
.RegisterArea
) );
876 fpu_to_fpux( &to
->u
.FltSave
, &fpu
);
878 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_AMD64_DEBUG_REGISTERS
))
880 to
->ContextFlags
|= CONTEXT_AMD64_DEBUG_REGISTERS
;
881 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
882 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
883 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
884 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
885 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
886 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
888 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_AMD64_XSTATE
))
890 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
891 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
894 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
895 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
897 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
898 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
903 return STATUS_SUCCESS
;
906 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT
, IMAGE_FILE_MACHINE_ARMNT
):
908 ARM_CONTEXT
*to
= dst
;
910 to_flags
= to
->ContextFlags
& ~CONTEXT_ARM
;
911 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_ARM_CONTROL
))
913 to
->ContextFlags
|= CONTEXT_ARM_CONTROL
;
914 to
->Sp
= from
->ctl
.arm_regs
.sp
;
915 to
->Lr
= from
->ctl
.arm_regs
.lr
;
916 to
->Pc
= from
->ctl
.arm_regs
.pc
;
917 to
->Cpsr
= from
->ctl
.arm_regs
.cpsr
;
919 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_ARM_INTEGER
))
921 to
->ContextFlags
|= CONTEXT_ARM_INTEGER
;
922 to
->R0
= from
->integer
.arm_regs
.r
[0];
923 to
->R1
= from
->integer
.arm_regs
.r
[1];
924 to
->R2
= from
->integer
.arm_regs
.r
[2];
925 to
->R3
= from
->integer
.arm_regs
.r
[3];
926 to
->R4
= from
->integer
.arm_regs
.r
[4];
927 to
->R5
= from
->integer
.arm_regs
.r
[5];
928 to
->R6
= from
->integer
.arm_regs
.r
[6];
929 to
->R7
= from
->integer
.arm_regs
.r
[7];
930 to
->R8
= from
->integer
.arm_regs
.r
[8];
931 to
->R9
= from
->integer
.arm_regs
.r
[9];
932 to
->R10
= from
->integer
.arm_regs
.r
[10];
933 to
->R11
= from
->integer
.arm_regs
.r
[11];
934 to
->R12
= from
->integer
.arm_regs
.r
[12];
936 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_ARM_FLOATING_POINT
))
938 to
->ContextFlags
|= CONTEXT_ARM_FLOATING_POINT
;
939 for (i
= 0; i
< 32; i
++) to
->u
.D
[i
] = from
->fp
.arm_regs
.d
[i
];
940 to
->Fpscr
= from
->fp
.arm_regs
.fpscr
;
942 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_ARM_DEBUG_REGISTERS
))
944 to
->ContextFlags
|= CONTEXT_ARM_DEBUG_REGISTERS
;
945 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->Bvr
[i
] = from
->debug
.arm_regs
.bvr
[i
];
946 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->Bcr
[i
] = from
->debug
.arm_regs
.bcr
[i
];
947 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->Wvr
[i
] = from
->debug
.arm_regs
.wvr
[i
];
948 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->Wcr
[i
] = from
->debug
.arm_regs
.wcr
[i
];
950 return STATUS_SUCCESS
;
953 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_ARM64
):
955 ARM64_NT_CONTEXT
*to
= dst
;
957 to_flags
= to
->ContextFlags
& ~CONTEXT_ARM64
;
958 to
->ContextFlags
= CONTEXT_ARM64
;
959 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_ARM64_CONTROL
))
961 to
->ContextFlags
|= CONTEXT_ARM64_CONTROL
;
962 to
->u
.s
.Fp
= from
->integer
.arm64_regs
.x
[29];
963 to
->u
.s
.Lr
= from
->integer
.arm64_regs
.x
[30];
964 to
->Sp
= from
->ctl
.arm64_regs
.sp
;
965 to
->Pc
= from
->ctl
.arm64_regs
.pc
;
966 to
->Cpsr
= from
->ctl
.arm64_regs
.pstate
;
968 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_ARM64_INTEGER
))
970 to
->ContextFlags
|= CONTEXT_ARM64_INTEGER
;
971 for (i
= 0; i
<= 28; i
++) to
->u
.X
[i
] = from
->integer
.arm64_regs
.x
[i
];
973 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_ARM64_FLOATING_POINT
))
975 to
->ContextFlags
|= CONTEXT_ARM64_FLOATING_POINT
;
976 for (i
= 0; i
< 32; i
++)
978 to
->V
[i
].s
.Low
= from
->fp
.arm64_regs
.q
[i
].low
;
979 to
->V
[i
].s
.High
= from
->fp
.arm64_regs
.q
[i
].high
;
981 to
->Fpcr
= from
->fp
.arm64_regs
.fpcr
;
982 to
->Fpsr
= from
->fp
.arm64_regs
.fpsr
;
984 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_ARM64_DEBUG_REGISTERS
))
986 to
->ContextFlags
|= CONTEXT_ARM64_DEBUG_REGISTERS
;
987 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->Bcr
[i
] = from
->debug
.arm64_regs
.bcr
[i
];
988 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->Bvr
[i
] = from
->debug
.arm64_regs
.bvr
[i
];
989 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->Wcr
[i
] = from
->debug
.arm64_regs
.wcr
[i
];
990 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->Wvr
[i
] = from
->debug
.arm64_regs
.wvr
[i
];
992 return STATUS_SUCCESS
;
996 return STATUS_INVALID_PARAMETER
;
1001 /***********************************************************************
1002 * contexts_to_server
1004 static void contexts_to_server( context_t server_contexts
[2], CONTEXT
*context
)
1006 unsigned int count
= 0;
1007 void *native_context
= get_native_context( context
);
1008 void *wow_context
= get_wow_context( context
);
1012 context_to_server( &server_contexts
[count
++], native_machine
, native_context
, native_machine
);
1013 if (wow_context
) context_to_server( &server_contexts
[count
++], main_image_info
.Machine
,
1014 wow_context
, main_image_info
.Machine
);
1015 else if (native_machine
!= main_image_info
.Machine
)
1016 context_to_server( &server_contexts
[count
++], main_image_info
.Machine
,
1017 native_context
, native_machine
);
1020 context_to_server( &server_contexts
[count
++], native_machine
,
1021 wow_context
, main_image_info
.Machine
);
1023 if (count
< 2) memset( &server_contexts
[1], 0, sizeof(server_contexts
[1]) );
1027 /***********************************************************************
1028 * contexts_from_server
1030 static void contexts_from_server( CONTEXT
*context
, context_t server_contexts
[2] )
1032 void *native_context
= get_native_context( context
);
1033 void *wow_context
= get_wow_context( context
);
1037 context_from_server( native_context
, &server_contexts
[0], native_machine
);
1038 if (wow_context
) context_from_server( wow_context
, &server_contexts
[1], main_image_info
.Machine
);
1040 else context_from_server( wow_context
, &server_contexts
[0], main_image_info
.Machine
);
1044 /***********************************************************************
1045 * pthread_exit_wrapper
1047 static void pthread_exit_wrapper( int status
)
1049 close( ntdll_get_thread_data()->wait_fd
[0] );
1050 close( ntdll_get_thread_data()->wait_fd
[1] );
1051 close( ntdll_get_thread_data()->reply_fd
);
1052 close( ntdll_get_thread_data()->request_fd
);
1053 pthread_exit( UIntToPtr(status
) );
1057 /***********************************************************************
1060 * Startup routine for a newly created thread.
1062 static void start_thread( TEB
*teb
)
1064 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1067 thread_data
->pthread_id
= pthread_self();
1068 signal_init_thread( teb
);
1069 server_init_thread( thread_data
->start
, &suspend
);
1070 signal_start_thread( thread_data
->start
, thread_data
->param
, suspend
, teb
);
1074 /***********************************************************************
1075 * get_machine_context_size
1077 static SIZE_T
get_machine_context_size( USHORT machine
)
1081 case IMAGE_FILE_MACHINE_I386
: return sizeof(I386_CONTEXT
);
1082 case IMAGE_FILE_MACHINE_ARMNT
: return sizeof(ARM_CONTEXT
);
1083 case IMAGE_FILE_MACHINE_AMD64
: return sizeof(AMD64_CONTEXT
);
1084 case IMAGE_FILE_MACHINE_ARM64
: return sizeof(ARM64_NT_CONTEXT
);
1090 /***********************************************************************
1093 * cf. RtlWow64GetCurrentCpuArea
1095 void *get_cpu_area( USHORT machine
)
1097 WOW64_CPURESERVED
*cpu
;
1100 if (!NtCurrentTeb()->WowTebOffset
) return NULL
;
1102 cpu
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_CPURESERVED
];
1104 cpu
= ULongToPtr( NtCurrentTeb64()->TlsSlots
[WOW64_TLS_CPURESERVED
] );
1106 if (cpu
->Machine
!= machine
) return NULL
;
1107 switch (cpu
->Machine
)
1109 case IMAGE_FILE_MACHINE_I386
: align
= TYPE_ALIGNMENT(I386_CONTEXT
); break;
1110 case IMAGE_FILE_MACHINE_AMD64
: align
= TYPE_ALIGNMENT(AMD64_CONTEXT
); break;
1111 case IMAGE_FILE_MACHINE_ARMNT
: align
= TYPE_ALIGNMENT(ARM_CONTEXT
); break;
1112 case IMAGE_FILE_MACHINE_ARM64
: align
= TYPE_ALIGNMENT(ARM64_NT_CONTEXT
); break;
1113 default: return NULL
;
1115 return (void *)(((ULONG_PTR
)(cpu
+ 1) + align
- 1) & ~((ULONG_PTR
)align
- 1));
1119 /***********************************************************************
1122 void set_thread_id( TEB
*teb
, DWORD pid
, DWORD tid
)
1124 WOW_TEB
*wow_teb
= get_wow_teb( teb
);
1126 teb
->ClientId
.UniqueProcess
= ULongToHandle( pid
);
1127 teb
->ClientId
.UniqueThread
= ULongToHandle( tid
);
1128 teb
->RealClientId
= teb
->ClientId
;
1131 wow_teb
->ClientId
.UniqueProcess
= pid
;
1132 wow_teb
->ClientId
.UniqueThread
= tid
;
1133 wow_teb
->RealClientId
= wow_teb
->ClientId
;
1138 /***********************************************************************
1141 NTSTATUS
init_thread_stack( TEB
*teb
, ULONG_PTR zero_bits
, SIZE_T reserve_size
, SIZE_T commit_size
)
1143 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1144 WOW_TEB
*wow_teb
= get_wow_teb( teb
);
1150 WOW64_CPURESERVED
*cpu
;
1151 SIZE_T cpusize
= sizeof(WOW64_CPURESERVED
) +
1152 ((get_machine_context_size( main_image_info
.Machine
) + 7) & ~7) + sizeof(ULONG64
);
1156 if ((status
= virtual_alloc_thread_stack( &stack
, zero_bits
? zero_bits
: 0x7fffffff,
1157 reserve_size
, commit_size
, 0 )))
1159 wow_teb
->Tib
.StackBase
= PtrToUlong( stack
.StackBase
);
1160 wow_teb
->Tib
.StackLimit
= PtrToUlong( stack
.StackLimit
);
1161 wow_teb
->DeallocationStack
= PtrToUlong( stack
.DeallocationStack
);
1164 if ((status
= virtual_alloc_thread_stack( &stack
, 0, 0x40000, 0x40000, kernel_stack_size
)))
1166 cpu
= (WOW64_CPURESERVED
*)(((ULONG_PTR
)stack
.StackBase
- cpusize
) & ~15);
1167 cpu
->Machine
= main_image_info
.Machine
;
1168 teb
->Tib
.StackBase
= teb
->TlsSlots
[WOW64_TLS_CPURESERVED
] = cpu
;
1169 teb
->Tib
.StackLimit
= stack
.StackLimit
;
1170 teb
->DeallocationStack
= stack
.DeallocationStack
;
1171 thread_data
->kernel_stack
= stack
.StackBase
;
1172 return STATUS_SUCCESS
;
1175 if ((status
= virtual_alloc_thread_stack( &stack
, 0, 0x40000, 0x40000, 0 ))) return status
;
1177 cpu
= (WOW64_CPURESERVED
*)(((ULONG_PTR
)stack
.StackBase
- cpusize
) & ~15);
1178 cpu
->Machine
= main_image_info
.Machine
;
1179 wow_teb
->Tib
.StackBase
= wow_teb
->TlsSlots
[WOW64_TLS_CPURESERVED
] = PtrToUlong( cpu
);
1180 wow_teb
->Tib
.StackLimit
= PtrToUlong( stack
.StackLimit
);
1181 wow_teb
->DeallocationStack
= PtrToUlong( stack
.DeallocationStack
);
1186 if ((status
= virtual_alloc_thread_stack( &stack
, zero_bits
, reserve_size
,
1187 commit_size
, kernel_stack_size
)))
1189 teb
->Tib
.StackBase
= stack
.StackBase
;
1190 teb
->Tib
.StackLimit
= stack
.StackLimit
;
1191 teb
->DeallocationStack
= stack
.DeallocationStack
;
1192 thread_data
->kernel_stack
= stack
.StackBase
;
1193 return STATUS_SUCCESS
;
1197 /***********************************************************************
1200 * Update the output attributes.
1202 static void update_attr_list( PS_ATTRIBUTE_LIST
*attr
, const CLIENT_ID
*id
, TEB
*teb
)
1204 SIZE_T i
, count
= (attr
->TotalLength
- sizeof(attr
->TotalLength
)) / sizeof(PS_ATTRIBUTE
);
1206 for (i
= 0; i
< count
; i
++)
1208 if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_CLIENT_ID
)
1210 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(*id
) );
1211 memcpy( attr
->Attributes
[i
].ValuePtr
, id
, size
);
1212 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
1214 else if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_TEB_ADDRESS
)
1216 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(teb
) );
1217 memcpy( attr
->Attributes
[i
].ValuePtr
, &teb
, size
);
1218 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
1223 /***********************************************************************
1224 * NtCreateThread (NTDLL.@)
1226 NTSTATUS WINAPI
NtCreateThread( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1227 HANDLE process
, CLIENT_ID
*id
, CONTEXT
*ctx
, INITIAL_TEB
*teb
,
1230 FIXME( "%p %d %p %p %p %p %p %d, stub!\n", handle
, access
, attr
, process
, id
, ctx
, teb
, suspended
);
1231 return STATUS_NOT_IMPLEMENTED
;
1234 /***********************************************************************
1235 * NtCreateThreadEx (NTDLL.@)
1237 NTSTATUS WINAPI
NtCreateThreadEx( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1238 HANDLE process
, PRTL_THREAD_START_ROUTINE start
, void *param
,
1239 ULONG flags
, ULONG_PTR zero_bits
, SIZE_T stack_commit
,
1240 SIZE_T stack_reserve
, PS_ATTRIBUTE_LIST
*attr_list
)
1242 static const ULONG supported_flags
= THREAD_CREATE_FLAGS_CREATE_SUSPENDED
| THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER
;
1244 pthread_t pthread_id
;
1245 pthread_attr_t pthread_attr
;
1247 struct object_attributes
*objattr
;
1248 struct ntdll_thread_data
*thread_data
;
1250 int request_pipe
[2];
1254 if (flags
& ~supported_flags
)
1255 FIXME( "Unsupported flags %#x.\n", flags
);
1257 if (zero_bits
> 21 && zero_bits
< 32) return STATUS_INVALID_PARAMETER_3
;
1259 if (!is_wow64
&& zero_bits
>= 32) return STATUS_INVALID_PARAMETER_3
;
1262 if (process
!= NtCurrentProcess())
1265 apc_result_t result
;
1267 memset( &call
, 0, sizeof(call
) );
1269 call
.create_thread
.type
= APC_CREATE_THREAD
;
1270 call
.create_thread
.flags
= flags
;
1271 call
.create_thread
.func
= wine_server_client_ptr( start
);
1272 call
.create_thread
.arg
= wine_server_client_ptr( param
);
1273 call
.create_thread
.zero_bits
= zero_bits
;
1274 call
.create_thread
.reserve
= stack_reserve
;
1275 call
.create_thread
.commit
= stack_commit
;
1276 status
= server_queue_process_apc( process
, &call
, &result
);
1277 if (status
!= STATUS_SUCCESS
) return status
;
1279 if (result
.create_thread
.status
== STATUS_SUCCESS
)
1281 CLIENT_ID client_id
;
1282 TEB
*teb
= wine_server_get_ptr( result
.create_thread
.teb
);
1283 *handle
= wine_server_ptr_handle( result
.create_thread
.handle
);
1284 client_id
.UniqueProcess
= ULongToHandle( result
.create_thread
.pid
);
1285 client_id
.UniqueThread
= ULongToHandle( result
.create_thread
.tid
);
1286 if (attr_list
) update_attr_list( attr_list
, &client_id
, teb
);
1288 return result
.create_thread
.status
;
1291 if ((status
= alloc_object_attributes( attr
, &objattr
, &len
))) return status
;
1293 if (server_pipe( request_pipe
) == -1)
1296 return STATUS_TOO_MANY_OPENED_FILES
;
1298 wine_server_send_fd( request_pipe
[0] );
1300 if (!access
) access
= THREAD_ALL_ACCESS
;
1302 SERVER_START_REQ( new_thread
)
1304 req
->process
= wine_server_obj_handle( process
);
1305 req
->access
= access
;
1307 req
->request_fd
= request_pipe
[0];
1308 wine_server_add_data( req
, objattr
, len
);
1309 if (!(status
= wine_server_call( req
)))
1311 *handle
= wine_server_ptr_handle( reply
->handle
);
1314 close( request_pipe
[0] );
1321 close( request_pipe
[1] );
1325 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &sigset
);
1327 if ((status
= virtual_alloc_teb( &teb
))) goto done
;
1329 if ((status
= init_thread_stack( teb
, zero_bits
, stack_reserve
, stack_commit
)))
1331 virtual_free_teb( teb
);
1335 set_thread_id( teb
, GetCurrentProcessId(), tid
);
1337 thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1338 thread_data
->request_fd
= request_pipe
[1];
1339 thread_data
->start
= start
;
1340 thread_data
->param
= param
;
1342 pthread_attr_init( &pthread_attr
);
1343 pthread_attr_setstack( &pthread_attr
, teb
->DeallocationStack
,
1344 (char *)thread_data
->kernel_stack
+ kernel_stack_size
- (char *)teb
->DeallocationStack
);
1345 pthread_attr_setguardsize( &pthread_attr
, 0 );
1346 pthread_attr_setscope( &pthread_attr
, PTHREAD_SCOPE_SYSTEM
); /* force creating a kernel thread */
1347 InterlockedIncrement( &nb_threads
);
1348 if (pthread_create( &pthread_id
, &pthread_attr
, (void * (*)(void *))start_thread
, teb
))
1350 InterlockedDecrement( &nb_threads
);
1351 virtual_free_teb( teb
);
1352 status
= STATUS_NO_MEMORY
;
1354 pthread_attr_destroy( &pthread_attr
);
1357 pthread_sigmask( SIG_SETMASK
, &sigset
, NULL
);
1361 close( request_pipe
[1] );
1364 if (attr_list
) update_attr_list( attr_list
, &teb
->ClientId
, teb
);
1365 return STATUS_SUCCESS
;
1369 /***********************************************************************
1372 void abort_thread( int status
)
1374 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1375 if (InterlockedDecrement( &nb_threads
) <= 0) abort_process( status
);
1376 signal_exit_thread( status
, pthread_exit_wrapper
, NtCurrentTeb() );
1380 /***********************************************************************
1383 void abort_process( int status
)
1385 _exit( get_unix_exit_code( status
));
1389 /***********************************************************************
1392 static DECLSPEC_NORETURN
void exit_thread( int status
)
1394 static void *prev_teb
;
1397 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1399 if ((teb
= InterlockedExchangePointer( &prev_teb
, NtCurrentTeb() )))
1401 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1403 if (thread_data
->pthread_id
)
1405 pthread_join( thread_data
->pthread_id
, NULL
);
1406 virtual_free_teb( teb
);
1409 signal_exit_thread( status
, pthread_exit_wrapper
, NtCurrentTeb() );
1413 /***********************************************************************
1416 void exit_process( int status
)
1418 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1419 signal_exit_thread( get_unix_exit_code( status
), process_exit_wrapper
, NtCurrentTeb() );
1423 /**********************************************************************
1426 * Wait until the thread is no longer suspended.
1428 void wait_suspend( CONTEXT
*context
)
1430 int saved_errno
= errno
;
1431 context_t server_contexts
[2];
1433 contexts_to_server( server_contexts
, context
);
1434 /* wait with 0 timeout, will only return once the thread is no longer suspended */
1435 server_select( NULL
, 0, SELECT_INTERRUPTIBLE
, 0, server_contexts
, NULL
);
1436 contexts_from_server( context
, server_contexts
);
1437 errno
= saved_errno
;
1441 /**********************************************************************
1444 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
1446 NTSTATUS
send_debug_event( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
1450 obj_handle_t handle
= 0;
1451 client_ptr_t params
[EXCEPTION_MAXIMUM_PARAMETERS
];
1452 select_op_t select_op
;
1455 if (!peb
->BeingDebugged
) return 0; /* no debugger present */
1457 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &old_set
);
1459 for (i
= 0; i
< min( rec
->NumberParameters
, EXCEPTION_MAXIMUM_PARAMETERS
); i
++)
1460 params
[i
] = rec
->ExceptionInformation
[i
];
1462 SERVER_START_REQ( queue_exception_event
)
1464 req
->first
= first_chance
;
1465 req
->code
= rec
->ExceptionCode
;
1466 req
->flags
= rec
->ExceptionFlags
;
1467 req
->record
= wine_server_client_ptr( rec
->ExceptionRecord
);
1468 req
->address
= wine_server_client_ptr( rec
->ExceptionAddress
);
1469 req
->len
= i
* sizeof(params
[0]);
1470 wine_server_add_data( req
, params
, req
->len
);
1471 if (!(ret
= wine_server_call( req
))) handle
= reply
->handle
;
1477 context_t server_contexts
[2];
1479 select_op
.wait
.op
= SELECT_WAIT
;
1480 select_op
.wait
.handles
[0] = handle
;
1482 contexts_to_server( server_contexts
, context
);
1483 server_select( &select_op
, offsetof( select_op_t
, wait
.handles
[1] ), SELECT_INTERRUPTIBLE
,
1484 TIMEOUT_INFINITE
, server_contexts
, NULL
);
1486 SERVER_START_REQ( get_exception_status
)
1488 req
->handle
= handle
;
1489 ret
= wine_server_call( req
);
1492 if (ret
>= 0) contexts_from_server( context
, server_contexts
);
1495 pthread_sigmask( SIG_SETMASK
, &old_set
, NULL
);
1500 /*******************************************************************
1501 * NtRaiseException (NTDLL.@)
1503 NTSTATUS WINAPI
NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
1505 NTSTATUS status
= send_debug_event( rec
, context
, first_chance
);
1507 if (status
== DBG_CONTINUE
|| status
== DBG_EXCEPTION_HANDLED
)
1508 return NtContinue( context
, FALSE
);
1510 if (first_chance
) return call_user_exception_dispatcher( rec
, context
);
1512 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
1513 ERR_(seh
)("Exception frame is not in stack limits => unable to dispatch exception.\n");
1514 else if (rec
->ExceptionCode
== STATUS_NONCONTINUABLE_EXCEPTION
)
1515 ERR_(seh
)("Process attempted to continue execution after noncontinuable exception.\n");
1517 ERR_(seh
)("Unhandled exception code %x flags %x addr %p\n",
1518 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
);
1520 NtTerminateProcess( NtCurrentProcess(), rec
->ExceptionCode
);
1521 return STATUS_SUCCESS
;
1525 /***********************************************************************
1526 * NtOpenThread (NTDLL.@)
1528 NTSTATUS WINAPI
NtOpenThread( HANDLE
*handle
, ACCESS_MASK access
,
1529 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
1535 SERVER_START_REQ( open_thread
)
1537 req
->tid
= HandleToULong(id
->UniqueThread
);
1538 req
->access
= access
;
1539 req
->attributes
= attr
? attr
->Attributes
: 0;
1540 ret
= wine_server_call( req
);
1541 *handle
= wine_server_ptr_handle( reply
->handle
);
1548 /******************************************************************************
1549 * NtSuspendThread (NTDLL.@)
1551 NTSTATUS WINAPI
NtSuspendThread( HANDLE handle
, ULONG
*count
)
1555 SERVER_START_REQ( suspend_thread
)
1557 req
->handle
= wine_server_obj_handle( handle
);
1558 if (!(ret
= wine_server_call( req
)))
1560 if (count
) *count
= reply
->count
;
1568 /******************************************************************************
1569 * NtResumeThread (NTDLL.@)
1571 NTSTATUS WINAPI
NtResumeThread( HANDLE handle
, ULONG
*count
)
1575 SERVER_START_REQ( resume_thread
)
1577 req
->handle
= wine_server_obj_handle( handle
);
1578 if (!(ret
= wine_server_call( req
)))
1580 if (count
) *count
= reply
->count
;
1588 /******************************************************************************
1589 * NtAlertResumeThread (NTDLL.@)
1591 NTSTATUS WINAPI
NtAlertResumeThread( HANDLE handle
, ULONG
*count
)
1593 FIXME( "stub: should alert thread %p\n", handle
);
1594 return NtResumeThread( handle
, count
);
1598 /******************************************************************************
1599 * NtAlertThread (NTDLL.@)
1601 NTSTATUS WINAPI
NtAlertThread( HANDLE handle
)
1603 FIXME( "stub: %p\n", handle
);
1604 return STATUS_NOT_IMPLEMENTED
;
1608 /******************************************************************************
1609 * NtTerminateThread (NTDLL.@)
1611 NTSTATUS WINAPI
NtTerminateThread( HANDLE handle
, LONG exit_code
)
1616 SERVER_START_REQ( terminate_thread
)
1618 req
->handle
= wine_server_obj_handle( handle
);
1619 req
->exit_code
= exit_code
;
1620 ret
= wine_server_call( req
);
1621 self
= !ret
&& reply
->self
;
1627 server_select( NULL
, 0, SELECT_INTERRUPTIBLE
, 0, NULL
, NULL
);
1628 exit_thread( exit_code
);
1634 /******************************************************************************
1635 * NtQueueApcThread (NTDLL.@)
1637 NTSTATUS WINAPI
NtQueueApcThread( HANDLE handle
, PNTAPCFUNC func
, ULONG_PTR arg1
,
1638 ULONG_PTR arg2
, ULONG_PTR arg3
)
1642 SERVER_START_REQ( queue_apc
)
1644 req
->handle
= wine_server_obj_handle( handle
);
1647 req
->call
.type
= APC_USER
;
1648 req
->call
.user
.func
= wine_server_client_ptr( func
);
1649 req
->call
.user
.args
[0] = arg1
;
1650 req
->call
.user
.args
[1] = arg2
;
1651 req
->call
.user
.args
[2] = arg3
;
1653 else req
->call
.type
= APC_NONE
; /* wake up only */
1654 ret
= wine_server_call( req
);
1661 /***********************************************************************
1662 * set_thread_context
1664 NTSTATUS
set_thread_context( HANDLE handle
, const void *context
, BOOL
*self
, USHORT machine
)
1666 context_t server_contexts
[2];
1667 unsigned int count
= 0;
1670 context_to_server( &server_contexts
[count
++], native_machine
, context
, machine
);
1671 if (machine
!= native_machine
)
1672 context_to_server( &server_contexts
[count
++], machine
, context
, machine
);
1674 SERVER_START_REQ( set_thread_context
)
1676 req
->handle
= wine_server_obj_handle( handle
);
1677 wine_server_add_data( req
, server_contexts
, count
* sizeof(server_contexts
[0]) );
1678 ret
= wine_server_call( req
);
1679 *self
= reply
->self
;
1687 /***********************************************************************
1688 * get_thread_context
1690 NTSTATUS
get_thread_context( HANDLE handle
, void *context
, BOOL
*self
, USHORT machine
)
1693 HANDLE context_handle
;
1694 context_t server_contexts
[2];
1696 unsigned int flags
= get_server_context_flags( context
, machine
);
1698 SERVER_START_REQ( get_thread_context
)
1700 req
->handle
= wine_server_obj_handle( handle
);
1702 req
->machine
= machine
;
1703 wine_server_set_reply( req
, server_contexts
, sizeof(server_contexts
) );
1704 ret
= wine_server_call( req
);
1705 *self
= reply
->self
;
1706 context_handle
= wine_server_ptr_handle( reply
->handle
);
1707 count
= wine_server_reply_size( reply
) / sizeof(server_contexts
[0]);
1711 if (ret
== STATUS_PENDING
)
1713 NtWaitForSingleObject( context_handle
, FALSE
, NULL
);
1715 SERVER_START_REQ( get_thread_context
)
1717 req
->context
= wine_server_obj_handle( context_handle
);
1719 req
->machine
= machine
;
1720 wine_server_set_reply( req
, server_contexts
, sizeof(server_contexts
) );
1721 ret
= wine_server_call( req
);
1722 count
= wine_server_reply_size( reply
) / sizeof(server_contexts
[0]);
1728 ret
= context_from_server( context
, &server_contexts
[0], machine
);
1729 if (!ret
&& count
> 1) ret
= context_from_server( context
, &server_contexts
[1], machine
);
1735 /***********************************************************************
1736 * ntdll_set_exception_jmp_buf
1738 void ntdll_set_exception_jmp_buf( __wine_jmp_buf
*jmp
)
1740 assert( !jmp
|| !ntdll_get_thread_data()->jmp_buf );
1741 ntdll_get_thread_data()->jmp_buf = jmp
;
1745 BOOL
get_thread_times(int unix_pid
, int unix_tid
, LARGE_INTEGER
*kernel_time
, LARGE_INTEGER
*user_time
)
1748 unsigned long clocks_per_sec
= sysconf( _SC_CLK_TCK
);
1749 unsigned long usr
, sys
;
1756 sprintf( buf
, "/proc/%u/stat", unix_pid
);
1758 sprintf( buf
, "/proc/%u/task/%u/stat", unix_pid
, unix_tid
);
1759 if (!(f
= fopen( buf
, "r" )))
1761 WARN("Failed to open %s: %s\n", buf
, strerror(errno
));
1765 pos
= fgets( buf
, sizeof(buf
), f
);
1768 /* the process name is printed unescaped, so we have to skip to the last ')'
1769 * to avoid misinterpreting the string */
1770 if (pos
) pos
= strrchr( pos
, ')' );
1771 if (pos
) pos
= strchr( pos
+ 1, ' ' );
1774 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
1775 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
1776 for (i
= 0; i
< 11 && pos
; i
++)
1778 pos
= strchr( pos
+ 1, ' ' );
1782 /* the next two values are user and system time */
1783 if (pos
&& (sscanf( pos
, "%lu %lu", &usr
, &sys
) == 2))
1785 kernel_time
->QuadPart
= (ULONGLONG
)sys
* 10000000 / clocks_per_sec
;
1786 user_time
->QuadPart
= (ULONGLONG
)usr
* 10000000 / clocks_per_sec
;
1790 ERR("Failed to parse %s\n", debugstr_a(buf
));
1792 #elif defined(HAVE_LIBPROCSTAT)
1793 struct procstat
*pstat
;
1794 struct kinfo_proc
*kip
;
1795 unsigned int proc_count
;
1798 pstat
= procstat_open_sysctl();
1802 kip
= procstat_getprocs(pstat
, KERN_PROC_PID
, unix_pid
, &proc_count
);
1804 kip
= procstat_getprocs(pstat
, KERN_PROC_PID
| KERN_PROC_INC_THREAD
, unix_pid
, &proc_count
);
1808 for (i
= 0; i
< proc_count
; i
++)
1810 if (unix_tid
== -1 || kip
[i
].ki_tid
== unix_tid
)
1812 kernel_time
->QuadPart
= 10000000 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_stime
.tv_sec
+
1813 10 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_stime
.tv_usec
;
1814 user_time
->QuadPart
= 10000000 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_utime
.tv_sec
+
1815 10 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_utime
.tv_usec
;
1820 procstat_freeprocs(pstat
, kip
);
1822 procstat_close(pstat
);
1826 if (!once
++) FIXME("not implemented on this platform\n");
1832 static BOOL
is_process_wow64( const CLIENT_ID
*id
)
1838 if (id
->UniqueProcess
== ULongToHandle(GetCurrentProcessId())) return is_wow64
;
1839 if (!NtOpenProcess( &handle
, PROCESS_QUERY_LIMITED_INFORMATION
, NULL
, id
))
1841 if (!NtQueryInformationProcess( handle
, ProcessWow64Information
, &info
, sizeof(info
), NULL
))
1849 /******************************************************************************
1850 * NtQueryInformationThread (NTDLL.@)
1852 NTSTATUS WINAPI
NtQueryInformationThread( HANDLE handle
, THREADINFOCLASS
class,
1853 void *data
, ULONG length
, ULONG
*ret_len
)
1857 TRACE("(%p,%d,%p,%x,%p)\n", handle
, class, data
, length
, ret_len
);
1861 case ThreadBasicInformation
:
1863 THREAD_BASIC_INFORMATION info
;
1864 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1866 SERVER_START_REQ( get_thread_info
)
1868 req
->handle
= wine_server_obj_handle( handle
);
1869 if (!(status
= wine_server_call( req
)))
1871 info
.ExitStatus
= reply
->exit_code
;
1872 info
.TebBaseAddress
= wine_server_get_ptr( reply
->teb
);
1873 info
.ClientId
.UniqueProcess
= ULongToHandle(reply
->pid
);
1874 info
.ClientId
.UniqueThread
= ULongToHandle(reply
->tid
);
1875 info
.AffinityMask
= reply
->affinity
& affinity_mask
;
1876 info
.Priority
= reply
->priority
;
1877 info
.BasePriority
= reply
->priority
; /* FIXME */
1881 if (status
== STATUS_SUCCESS
)
1886 if (is_process_wow64( &info
.ClientId
))
1887 info
.TebBaseAddress
= (char *)info
.TebBaseAddress
+ teb_offset
;
1889 info
.TebBaseAddress
= NULL
;
1892 if (data
) memcpy( data
, &info
, min( length
, sizeof(info
) ));
1893 if (ret_len
) *ret_len
= min( length
, sizeof(info
) );
1898 case ThreadAffinityMask
:
1900 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1901 ULONG_PTR affinity
= 0;
1903 SERVER_START_REQ( get_thread_info
)
1905 req
->handle
= wine_server_obj_handle( handle
);
1906 req
->access
= THREAD_QUERY_INFORMATION
;
1907 if (!(status
= wine_server_call( req
))) affinity
= reply
->affinity
& affinity_mask
;
1910 if (status
== STATUS_SUCCESS
)
1912 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
1913 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
1920 KERNEL_USER_TIMES kusrt
;
1921 int unix_pid
, unix_tid
;
1923 SERVER_START_REQ( get_thread_times
)
1925 req
->handle
= wine_server_obj_handle( handle
);
1926 status
= wine_server_call( req
);
1927 if (status
== STATUS_SUCCESS
)
1929 kusrt
.CreateTime
.QuadPart
= reply
->creation_time
;
1930 kusrt
.ExitTime
.QuadPart
= reply
->exit_time
;
1931 unix_pid
= reply
->unix_pid
;
1932 unix_tid
= reply
->unix_tid
;
1936 if (status
== STATUS_SUCCESS
)
1940 kusrt
.KernelTime
.QuadPart
= kusrt
.UserTime
.QuadPart
= 0;
1941 if (unix_pid
!= -1 && unix_tid
!= -1)
1942 ret
= get_thread_times( unix_pid
, unix_tid
, &kusrt
.KernelTime
, &kusrt
.UserTime
);
1943 if (!ret
&& handle
== GetCurrentThread())
1945 /* fall back to process times */
1946 struct tms time_buf
;
1947 long clocks_per_sec
= sysconf(_SC_CLK_TCK
);
1950 kusrt
.KernelTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_stime
* 10000000 / clocks_per_sec
;
1951 kusrt
.UserTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_utime
* 10000000 / clocks_per_sec
;
1953 if (data
) memcpy( data
, &kusrt
, min( length
, sizeof(kusrt
) ));
1954 if (ret_len
) *ret_len
= min( length
, sizeof(kusrt
) );
1959 case ThreadDescriptorTableEntry
:
1960 return get_thread_ldt_entry( handle
, data
, length
, ret_len
);
1962 case ThreadAmILastThread
:
1964 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
1965 SERVER_START_REQ( get_thread_info
)
1967 req
->handle
= wine_server_obj_handle( handle
);
1968 status
= wine_server_call( req
);
1969 if (status
== STATUS_SUCCESS
)
1971 ULONG last
= reply
->last
;
1972 if (data
) memcpy( data
, &last
, sizeof(last
) );
1973 if (ret_len
) *ret_len
= sizeof(last
);
1980 case ThreadQuerySetWin32StartAddress
:
1982 SERVER_START_REQ( get_thread_info
)
1984 req
->handle
= wine_server_obj_handle( handle
);
1985 req
->access
= THREAD_QUERY_INFORMATION
;
1986 status
= wine_server_call( req
);
1987 if (status
== STATUS_SUCCESS
)
1989 PRTL_THREAD_START_ROUTINE entry
= wine_server_get_ptr( reply
->entry_point
);
1990 if (data
) memcpy( data
, &entry
, min( length
, sizeof(entry
) ) );
1991 if (ret_len
) *ret_len
= min( length
, sizeof(entry
) );
1998 case ThreadGroupInformation
:
2000 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2001 GROUP_AFFINITY affinity
;
2003 memset( &affinity
, 0, sizeof(affinity
) );
2004 affinity
.Group
= 0; /* Wine only supports max 64 processors */
2006 SERVER_START_REQ( get_thread_info
)
2008 req
->handle
= wine_server_obj_handle( handle
);
2009 if (!(status
= wine_server_call( req
))) affinity
.Mask
= reply
->affinity
& affinity_mask
;
2012 if (status
== STATUS_SUCCESS
)
2014 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
2015 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
2020 case ThreadIsIoPending
:
2021 FIXME( "ThreadIsIoPending info class not supported yet\n" );
2022 if (length
!= sizeof(BOOL
)) return STATUS_INFO_LENGTH_MISMATCH
;
2023 if (!data
) return STATUS_ACCESS_DENIED
;
2024 *(BOOL
*)data
= FALSE
;
2025 if (ret_len
) *ret_len
= sizeof(BOOL
);
2026 return STATUS_SUCCESS
;
2028 case ThreadSuspendCount
:
2029 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
2030 if (!data
) return STATUS_ACCESS_VIOLATION
;
2032 SERVER_START_REQ( get_thread_info
)
2034 req
->handle
= wine_server_obj_handle( handle
);
2035 if (!(status
= wine_server_call( req
))) *(ULONG
*)data
= reply
->suspend_count
;
2040 case ThreadNameInformation
:
2042 THREAD_NAME_INFORMATION
*info
= data
;
2043 data_size_t len
, desc_len
= 0;
2046 len
= length
>= sizeof(*info
) ? length
- sizeof(*info
) : 0;
2047 ptr
= info
? (WCHAR
*)(info
+ 1) : NULL
;
2049 SERVER_START_REQ( get_thread_info
)
2051 req
->handle
= wine_server_obj_handle( handle
);
2052 if (ptr
) wine_server_set_reply( req
, ptr
, len
);
2053 status
= wine_server_call( req
);
2054 desc_len
= reply
->desc_len
;
2058 if (!info
) status
= STATUS_BUFFER_TOO_SMALL
;
2059 else if (status
== STATUS_SUCCESS
)
2061 info
->ThreadName
.Length
= info
->ThreadName
.MaximumLength
= desc_len
;
2062 info
->ThreadName
.Buffer
= ptr
;
2065 if (ret_len
&& (status
== STATUS_SUCCESS
|| status
== STATUS_BUFFER_TOO_SMALL
))
2066 *ret_len
= sizeof(*info
) + desc_len
;
2070 case ThreadWow64Context
:
2071 return get_thread_wow64_context( handle
, data
, length
);
2073 case ThreadHideFromDebugger
:
2074 if (length
!= sizeof(BOOLEAN
)) return STATUS_INFO_LENGTH_MISMATCH
;
2075 if (!data
) return STATUS_ACCESS_VIOLATION
;
2076 SERVER_START_REQ( get_thread_info
)
2078 req
->handle
= wine_server_obj_handle( handle
);
2079 req
->access
= THREAD_QUERY_INFORMATION
;
2080 if ((status
= wine_server_call( req
))) return status
;
2081 *(BOOLEAN
*)data
= reply
->dbg_hidden
;
2084 if (ret_len
) *ret_len
= sizeof(BOOLEAN
);
2085 return STATUS_SUCCESS
;
2087 case ThreadEnableAlignmentFaultFixup
:
2088 return STATUS_INVALID_INFO_CLASS
;
2090 case ThreadPriority
:
2091 case ThreadBasePriority
:
2092 case ThreadImpersonationToken
:
2093 case ThreadEventPair_Reusable
:
2094 case ThreadZeroTlsCell
:
2095 case ThreadPerformanceCount
:
2096 case ThreadIdealProcessor
:
2097 case ThreadPriorityBoost
:
2098 case ThreadSetTlsArrayAddress
:
2100 FIXME( "info class %d not supported yet\n", class );
2101 return STATUS_NOT_IMPLEMENTED
;
2106 /******************************************************************************
2107 * NtSetInformationThread (NTDLL.@)
2109 NTSTATUS WINAPI
NtSetInformationThread( HANDLE handle
, THREADINFOCLASS
class,
2110 const void *data
, ULONG length
)
2114 TRACE("(%p,%d,%p,%x)\n", handle
, class, data
, length
);
2118 case ThreadZeroTlsCell
:
2119 if (handle
== GetCurrentThread())
2121 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
2122 return virtual_clear_tls_index( *(const ULONG
*)data
);
2124 FIXME( "ZeroTlsCell not supported on other threads\n" );
2125 return STATUS_NOT_IMPLEMENTED
;
2127 case ThreadImpersonationToken
:
2129 const HANDLE
*token
= data
;
2131 if (length
!= sizeof(HANDLE
)) return STATUS_INVALID_PARAMETER
;
2132 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token
);
2133 SERVER_START_REQ( set_thread_info
)
2135 req
->handle
= wine_server_obj_handle( handle
);
2136 req
->token
= wine_server_obj_handle( *token
);
2137 req
->mask
= SET_THREAD_INFO_TOKEN
;
2138 status
= wine_server_call( req
);
2144 case ThreadBasePriority
:
2146 const DWORD
*pprio
= data
;
2147 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
2148 SERVER_START_REQ( set_thread_info
)
2150 req
->handle
= wine_server_obj_handle( handle
);
2151 req
->priority
= *pprio
;
2152 req
->mask
= SET_THREAD_INFO_PRIORITY
;
2153 status
= wine_server_call( req
);
2159 case ThreadAffinityMask
:
2161 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2164 if (length
!= sizeof(ULONG_PTR
)) return STATUS_INVALID_PARAMETER
;
2165 req_aff
= *(const ULONG_PTR
*)data
& affinity_mask
;
2166 if (!req_aff
) return STATUS_INVALID_PARAMETER
;
2168 SERVER_START_REQ( set_thread_info
)
2170 req
->handle
= wine_server_obj_handle( handle
);
2171 req
->affinity
= req_aff
;
2172 req
->mask
= SET_THREAD_INFO_AFFINITY
;
2173 status
= wine_server_call( req
);
2179 case ThreadHideFromDebugger
:
2180 if (length
) return STATUS_INFO_LENGTH_MISMATCH
;
2181 SERVER_START_REQ( set_thread_info
)
2183 req
->handle
= wine_server_obj_handle( handle
);
2184 req
->mask
= SET_THREAD_INFO_DBG_HIDDEN
;
2185 status
= wine_server_call( req
);
2190 case ThreadQuerySetWin32StartAddress
:
2192 const PRTL_THREAD_START_ROUTINE
*entry
= data
;
2193 if (length
!= sizeof(PRTL_THREAD_START_ROUTINE
)) return STATUS_INVALID_PARAMETER
;
2194 SERVER_START_REQ( set_thread_info
)
2196 req
->handle
= wine_server_obj_handle( handle
);
2197 req
->mask
= SET_THREAD_INFO_ENTRYPOINT
;
2198 req
->entry_point
= wine_server_client_ptr( *entry
);
2199 status
= wine_server_call( req
);
2205 case ThreadGroupInformation
:
2207 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2208 const GROUP_AFFINITY
*req_aff
;
2210 if (length
!= sizeof(*req_aff
)) return STATUS_INVALID_PARAMETER
;
2211 if (!data
) return STATUS_ACCESS_VIOLATION
;
2214 /* On Windows the request fails if the reserved fields are set */
2215 if (req_aff
->Reserved
[0] || req_aff
->Reserved
[1] || req_aff
->Reserved
[2])
2216 return STATUS_INVALID_PARAMETER
;
2218 /* Wine only supports max 64 processors */
2219 if (req_aff
->Group
) return STATUS_INVALID_PARAMETER
;
2220 if (req_aff
->Mask
& ~affinity_mask
) return STATUS_INVALID_PARAMETER
;
2221 if (!req_aff
->Mask
) return STATUS_INVALID_PARAMETER
;
2222 SERVER_START_REQ( set_thread_info
)
2224 req
->handle
= wine_server_obj_handle( handle
);
2225 req
->affinity
= req_aff
->Mask
;
2226 req
->mask
= SET_THREAD_INFO_AFFINITY
;
2227 status
= wine_server_call( req
);
2233 case ThreadNameInformation
:
2235 const THREAD_NAME_INFORMATION
*info
= data
;
2236 THREAD_BASIC_INFORMATION tbi
;
2238 if (length
!= sizeof(*info
)) return STATUS_INFO_LENGTH_MISMATCH
;
2239 if (!info
) return STATUS_ACCESS_VIOLATION
;
2240 if (info
->ThreadName
.Length
&& !info
->ThreadName
.Buffer
) return STATUS_ACCESS_VIOLATION
;
2242 if (handle
== GetCurrentThread())
2243 WARN_(threadname
)( "Thread renamed to %s\n", debugstr_us(&info
->ThreadName
) );
2244 else if (!NtQueryInformationThread( handle
, ThreadBasicInformation
, &tbi
, sizeof(tbi
), NULL
))
2245 WARN_(threadname
)( "Thread ID %04x renamed to %s\n", HandleToULong( tbi
.ClientId
.UniqueThread
), debugstr_us(&info
->ThreadName
) );
2247 WARN_(threadname
)( "Thread handle %p renamed to %s\n", handle
, debugstr_us(&info
->ThreadName
) );
2249 SERVER_START_REQ( set_thread_info
)
2251 req
->handle
= wine_server_obj_handle( handle
);
2252 req
->mask
= SET_THREAD_INFO_DESCRIPTION
;
2253 wine_server_add_data( req
, info
->ThreadName
.Buffer
, info
->ThreadName
.Length
);
2254 status
= wine_server_call( req
);
2260 case ThreadWow64Context
:
2261 return set_thread_wow64_context( handle
, data
, length
);
2263 case ThreadEnableAlignmentFaultFixup
:
2264 if (length
!= sizeof(BOOLEAN
)) return STATUS_INFO_LENGTH_MISMATCH
;
2265 if (!data
) return STATUS_ACCESS_VIOLATION
;
2266 FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" );
2267 return STATUS_SUCCESS
;
2269 case ThreadPowerThrottlingState
:
2270 if (length
!= sizeof(THREAD_POWER_THROTTLING_STATE
)) return STATUS_INFO_LENGTH_MISMATCH
;
2271 if (!data
) return STATUS_ACCESS_VIOLATION
;
2272 FIXME( "ThreadPowerThrottling stub!\n" );
2273 return STATUS_SUCCESS
;
2275 case ThreadBasicInformation
:
2277 case ThreadPriority
:
2278 case ThreadDescriptorTableEntry
:
2279 case ThreadEventPair_Reusable
:
2280 case ThreadPerformanceCount
:
2281 case ThreadAmILastThread
:
2282 case ThreadIdealProcessor
:
2283 case ThreadPriorityBoost
:
2284 case ThreadSetTlsArrayAddress
:
2285 case ThreadIsIoPending
:
2287 FIXME( "info class %d not supported yet\n", class );
2288 return STATUS_NOT_IMPLEMENTED
;
2293 /******************************************************************************
2294 * NtGetCurrentProcessorNumber (NTDLL.@)
2296 ULONG WINAPI
NtGetCurrentProcessorNumber(void)
2300 #if defined(__linux__) && defined(__NR_getcpu)
2301 int res
= syscall(__NR_getcpu
, &processor
, NULL
, NULL
);
2302 if (res
!= -1) return processor
;
2305 if (peb
->NumberOfProcessors
> 1)
2307 ULONG_PTR thread_mask
, processor_mask
;
2309 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask
,
2310 &thread_mask
, sizeof(thread_mask
), NULL
))
2312 for (processor
= 0; processor
< peb
->NumberOfProcessors
; processor
++)
2314 processor_mask
= (1 << processor
);
2315 if (thread_mask
& processor_mask
)
2317 if (thread_mask
!= processor_mask
)
2318 FIXME( "need multicore support (%d processors)\n",
2319 peb
->NumberOfProcessors
);
2325 /* fallback to the first processor */
2330 /******************************************************************************
2331 * NtGetNextThread (NTDLL.@)
2333 NTSTATUS WINAPI
NtGetNextThread( HANDLE process
, HANDLE thread
, ACCESS_MASK access
, ULONG attributes
,
2334 ULONG flags
, HANDLE
*handle
)
2336 HANDLE ret_handle
= 0;
2339 TRACE( "process %p, thread %p, access %#x, attributes %#x, flags %#x, handle %p.\n",
2340 process
, thread
, access
, attributes
, flags
, handle
);
2342 SERVER_START_REQ( get_next_thread
)
2344 req
->process
= wine_server_obj_handle( process
);
2345 req
->last
= wine_server_obj_handle( thread
);
2346 req
->access
= access
;
2347 req
->attributes
= attributes
;
2349 if (!(ret
= wine_server_call( req
))) ret_handle
= wine_server_ptr_handle( reply
->handle
);
2353 *handle
= ret_handle
;