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
);
74 static int nb_threads
= 1;
76 static inline int get_unix_exit_code( NTSTATUS status
)
78 /* prevent a nonzero exit code to end up truncated to zero in unix */
79 if (status
&& !(status
& 0xff)) return 1;
84 /***********************************************************************
87 * Build a standard i386 FPU context from an extended one.
89 void fpux_to_fpu( I386_FLOATING_SAVE_AREA
*fpu
, const XMM_SAVE_AREA32
*fpux
)
91 unsigned int i
, tag
, stack_top
;
93 fpu
->ControlWord
= fpux
->ControlWord
;
94 fpu
->StatusWord
= fpux
->StatusWord
;
95 fpu
->ErrorOffset
= fpux
->ErrorOffset
;
96 fpu
->ErrorSelector
= fpux
->ErrorSelector
| (fpux
->ErrorOpcode
<< 16);
97 fpu
->DataOffset
= fpux
->DataOffset
;
98 fpu
->DataSelector
= fpux
->DataSelector
;
99 fpu
->Cr0NpxState
= fpux
->StatusWord
| 0xffff0000;
101 stack_top
= (fpux
->StatusWord
>> 11) & 7;
102 fpu
->TagWord
= 0xffff0000;
103 for (i
= 0; i
< 8; i
++)
105 memcpy( &fpu
->RegisterArea
[10 * i
], &fpux
->FloatRegisters
[i
], 10 );
106 if (!(fpux
->TagWord
& (1 << i
))) tag
= 3; /* empty */
109 const M128A
*reg
= &fpux
->FloatRegisters
[(i
- stack_top
) & 7];
110 if ((reg
->High
& 0x7fff) == 0x7fff) /* exponent all ones */
112 tag
= 2; /* special */
114 else if (!(reg
->High
& 0x7fff)) /* exponent all zeroes */
116 if (reg
->Low
) tag
= 2; /* special */
117 else tag
= 1; /* zero */
121 if (reg
->Low
>> 63) tag
= 0; /* valid */
122 else tag
= 2; /* special */
125 fpu
->TagWord
|= tag
<< (2 * i
);
130 /***********************************************************************
133 * Fill extended i386 FPU context from standard one.
135 void fpu_to_fpux( XMM_SAVE_AREA32
*fpux
, const I386_FLOATING_SAVE_AREA
*fpu
)
139 fpux
->ControlWord
= fpu
->ControlWord
;
140 fpux
->StatusWord
= fpu
->StatusWord
;
141 fpux
->ErrorOffset
= fpu
->ErrorOffset
;
142 fpux
->ErrorSelector
= fpu
->ErrorSelector
;
143 fpux
->ErrorOpcode
= fpu
->ErrorSelector
>> 16;
144 fpux
->DataOffset
= fpu
->DataOffset
;
145 fpux
->DataSelector
= fpu
->DataSelector
;
147 for (i
= 0; i
< 8; i
++)
149 if (((fpu
->TagWord
>> (i
* 2)) & 3) != 3) fpux
->TagWord
|= 1 << i
;
150 memcpy( &fpux
->FloatRegisters
[i
], &fpu
->RegisterArea
[10 * i
], 10 );
155 /***********************************************************************
156 * get_server_context_flags
158 static unsigned int get_server_context_flags( const void *context
, USHORT machine
)
160 unsigned int flags
, ret
= 0;
164 case IMAGE_FILE_MACHINE_I386
:
165 flags
= ((const I386_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_i386
;
166 if (flags
& CONTEXT_I386_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
167 if (flags
& CONTEXT_I386_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
168 if (flags
& CONTEXT_I386_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
169 if (flags
& CONTEXT_I386_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
170 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
171 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
) ret
|= SERVER_CTX_EXTENDED_REGISTERS
| SERVER_CTX_FLOATING_POINT
;
172 if (flags
& CONTEXT_I386_XSTATE
) ret
|= SERVER_CTX_YMM_REGISTERS
;
174 case IMAGE_FILE_MACHINE_AMD64
:
175 flags
= ((const AMD64_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_AMD64
;
176 if (flags
& CONTEXT_AMD64_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
177 if (flags
& CONTEXT_AMD64_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
178 if (flags
& CONTEXT_AMD64_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
179 if (flags
& CONTEXT_AMD64_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
180 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
181 if (flags
& CONTEXT_AMD64_XSTATE
) ret
|= SERVER_CTX_YMM_REGISTERS
;
183 case IMAGE_FILE_MACHINE_ARMNT
:
184 flags
= ((const ARM_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_ARM
;
185 if (flags
& CONTEXT_ARM_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
186 if (flags
& CONTEXT_ARM_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
187 if (flags
& CONTEXT_ARM_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
188 if (flags
& CONTEXT_ARM_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
190 case IMAGE_FILE_MACHINE_ARM64
:
191 flags
= ((const ARM64_NT_CONTEXT
*)context
)->ContextFlags
& ~CONTEXT_ARM64
;
192 if (flags
& CONTEXT_ARM64_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
193 if (flags
& CONTEXT_ARM64_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
194 if (flags
& CONTEXT_ARM64_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
195 if (flags
& CONTEXT_ARM64_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
202 /***********************************************************************
205 * Convert a register context to the server format.
207 static NTSTATUS
context_to_server( context_t
*to
, USHORT to_machine
, const void *src
, USHORT from_machine
)
211 memset( to
, 0, sizeof(*to
) );
212 to
->machine
= to_machine
;
214 switch (MAKELONG( from_machine
, to_machine
))
216 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_I386
):
218 const I386_CONTEXT
*from
= src
;
220 flags
= from
->ContextFlags
& ~CONTEXT_i386
;
221 if (flags
& CONTEXT_I386_CONTROL
)
223 to
->flags
|= SERVER_CTX_CONTROL
;
224 to
->ctl
.i386_regs
.ebp
= from
->Ebp
;
225 to
->ctl
.i386_regs
.esp
= from
->Esp
;
226 to
->ctl
.i386_regs
.eip
= from
->Eip
;
227 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
228 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
229 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
231 if (flags
& CONTEXT_I386_INTEGER
)
233 to
->flags
|= SERVER_CTX_INTEGER
;
234 to
->integer
.i386_regs
.eax
= from
->Eax
;
235 to
->integer
.i386_regs
.ebx
= from
->Ebx
;
236 to
->integer
.i386_regs
.ecx
= from
->Ecx
;
237 to
->integer
.i386_regs
.edx
= from
->Edx
;
238 to
->integer
.i386_regs
.esi
= from
->Esi
;
239 to
->integer
.i386_regs
.edi
= from
->Edi
;
241 if (flags
& CONTEXT_I386_SEGMENTS
)
243 to
->flags
|= SERVER_CTX_SEGMENTS
;
244 to
->seg
.i386_regs
.ds
= from
->SegDs
;
245 to
->seg
.i386_regs
.es
= from
->SegEs
;
246 to
->seg
.i386_regs
.fs
= from
->SegFs
;
247 to
->seg
.i386_regs
.gs
= from
->SegGs
;
249 if (flags
& CONTEXT_I386_FLOATING_POINT
)
251 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
252 to
->fp
.i386_regs
.ctrl
= from
->FloatSave
.ControlWord
;
253 to
->fp
.i386_regs
.status
= from
->FloatSave
.StatusWord
;
254 to
->fp
.i386_regs
.tag
= from
->FloatSave
.TagWord
;
255 to
->fp
.i386_regs
.err_off
= from
->FloatSave
.ErrorOffset
;
256 to
->fp
.i386_regs
.err_sel
= from
->FloatSave
.ErrorSelector
;
257 to
->fp
.i386_regs
.data_off
= from
->FloatSave
.DataOffset
;
258 to
->fp
.i386_regs
.data_sel
= from
->FloatSave
.DataSelector
;
259 to
->fp
.i386_regs
.cr0npx
= from
->FloatSave
.Cr0NpxState
;
260 memcpy( to
->fp
.i386_regs
.regs
, from
->FloatSave
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
262 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
)
264 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
265 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
266 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
267 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
268 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
269 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
270 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
272 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
274 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
;
275 memcpy( to
->ext
.i386_regs
, from
->ExtendedRegisters
, sizeof(to
->ext
.i386_regs
) );
277 if (flags
& CONTEXT_I386_XSTATE
)
279 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
280 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
282 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
283 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
285 return STATUS_SUCCESS
;
288 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_AMD64
):
290 const I386_CONTEXT
*from
= src
;
292 flags
= from
->ContextFlags
& ~CONTEXT_i386
;
293 if (flags
& CONTEXT_I386_CONTROL
)
295 to
->flags
|= SERVER_CTX_CONTROL
;
296 to
->ctl
.x86_64_regs
.rbp
= from
->Ebp
;
297 to
->ctl
.x86_64_regs
.rsp
= from
->Esp
;
298 to
->ctl
.x86_64_regs
.rip
= from
->Eip
;
299 to
->ctl
.x86_64_regs
.cs
= from
->SegCs
;
300 to
->ctl
.x86_64_regs
.ss
= from
->SegSs
;
301 to
->ctl
.x86_64_regs
.flags
= from
->EFlags
;
303 if (flags
& CONTEXT_I386_INTEGER
)
305 to
->flags
|= SERVER_CTX_INTEGER
;
306 to
->integer
.x86_64_regs
.rax
= from
->Eax
;
307 to
->integer
.x86_64_regs
.rbx
= from
->Ebx
;
308 to
->integer
.x86_64_regs
.rcx
= from
->Ecx
;
309 to
->integer
.x86_64_regs
.rdx
= from
->Edx
;
310 to
->integer
.x86_64_regs
.rsi
= from
->Esi
;
311 to
->integer
.x86_64_regs
.rdi
= from
->Edi
;
313 if (flags
& CONTEXT_I386_SEGMENTS
)
315 to
->flags
|= SERVER_CTX_SEGMENTS
;
316 to
->seg
.x86_64_regs
.ds
= from
->SegDs
;
317 to
->seg
.x86_64_regs
.es
= from
->SegEs
;
318 to
->seg
.x86_64_regs
.fs
= from
->SegFs
;
319 to
->seg
.x86_64_regs
.gs
= from
->SegGs
;
321 if (flags
& CONTEXT_I386_DEBUG_REGISTERS
)
323 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
324 to
->debug
.x86_64_regs
.dr0
= from
->Dr0
;
325 to
->debug
.x86_64_regs
.dr1
= from
->Dr1
;
326 to
->debug
.x86_64_regs
.dr2
= from
->Dr2
;
327 to
->debug
.x86_64_regs
.dr3
= from
->Dr3
;
328 to
->debug
.x86_64_regs
.dr6
= from
->Dr6
;
329 to
->debug
.x86_64_regs
.dr7
= from
->Dr7
;
331 if (flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
333 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
334 memcpy( to
->fp
.x86_64_regs
.fpregs
, from
->ExtendedRegisters
, sizeof(to
->fp
.x86_64_regs
.fpregs
) );
336 else if (flags
& CONTEXT_I386_FLOATING_POINT
)
338 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
339 fpu_to_fpux( (XMM_SAVE_AREA32
*)to
->fp
.x86_64_regs
.fpregs
, &from
->FloatSave
);
341 if (flags
& CONTEXT_I386_XSTATE
)
343 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
344 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
346 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
347 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
349 return STATUS_SUCCESS
;
352 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_AMD64
):
354 const AMD64_CONTEXT
*from
= src
;
356 flags
= from
->ContextFlags
& ~CONTEXT_AMD64
;
357 if (flags
& CONTEXT_AMD64_CONTROL
)
359 to
->flags
|= SERVER_CTX_CONTROL
;
360 to
->ctl
.x86_64_regs
.rbp
= from
->Rbp
;
361 to
->ctl
.x86_64_regs
.rip
= from
->Rip
;
362 to
->ctl
.x86_64_regs
.rsp
= from
->Rsp
;
363 to
->ctl
.x86_64_regs
.cs
= from
->SegCs
;
364 to
->ctl
.x86_64_regs
.ss
= from
->SegSs
;
365 to
->ctl
.x86_64_regs
.flags
= from
->EFlags
;
367 if (flags
& CONTEXT_AMD64_INTEGER
)
369 to
->flags
|= SERVER_CTX_INTEGER
;
370 to
->integer
.x86_64_regs
.rax
= from
->Rax
;
371 to
->integer
.x86_64_regs
.rcx
= from
->Rcx
;
372 to
->integer
.x86_64_regs
.rdx
= from
->Rdx
;
373 to
->integer
.x86_64_regs
.rbx
= from
->Rbx
;
374 to
->integer
.x86_64_regs
.rsi
= from
->Rsi
;
375 to
->integer
.x86_64_regs
.rdi
= from
->Rdi
;
376 to
->integer
.x86_64_regs
.r8
= from
->R8
;
377 to
->integer
.x86_64_regs
.r9
= from
->R9
;
378 to
->integer
.x86_64_regs
.r10
= from
->R10
;
379 to
->integer
.x86_64_regs
.r11
= from
->R11
;
380 to
->integer
.x86_64_regs
.r12
= from
->R12
;
381 to
->integer
.x86_64_regs
.r13
= from
->R13
;
382 to
->integer
.x86_64_regs
.r14
= from
->R14
;
383 to
->integer
.x86_64_regs
.r15
= from
->R15
;
385 if (flags
& CONTEXT_AMD64_SEGMENTS
)
387 to
->flags
|= SERVER_CTX_SEGMENTS
;
388 to
->seg
.x86_64_regs
.ds
= from
->SegDs
;
389 to
->seg
.x86_64_regs
.es
= from
->SegEs
;
390 to
->seg
.x86_64_regs
.fs
= from
->SegFs
;
391 to
->seg
.x86_64_regs
.gs
= from
->SegGs
;
393 if (flags
& CONTEXT_AMD64_FLOATING_POINT
)
395 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
396 memcpy( to
->fp
.x86_64_regs
.fpregs
, &from
->u
.FltSave
, sizeof(to
->fp
.x86_64_regs
.fpregs
) );
398 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
)
400 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
401 to
->debug
.x86_64_regs
.dr0
= from
->Dr0
;
402 to
->debug
.x86_64_regs
.dr1
= from
->Dr1
;
403 to
->debug
.x86_64_regs
.dr2
= from
->Dr2
;
404 to
->debug
.x86_64_regs
.dr3
= from
->Dr3
;
405 to
->debug
.x86_64_regs
.dr6
= from
->Dr6
;
406 to
->debug
.x86_64_regs
.dr7
= from
->Dr7
;
408 if (flags
& CONTEXT_AMD64_XSTATE
)
410 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
411 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
413 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
414 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
416 return STATUS_SUCCESS
;
419 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_I386
):
421 const AMD64_CONTEXT
*from
= src
;
423 flags
= from
->ContextFlags
& ~CONTEXT_AMD64
;
424 if (flags
& CONTEXT_AMD64_CONTROL
)
426 to
->flags
|= SERVER_CTX_CONTROL
;
427 to
->ctl
.i386_regs
.ebp
= from
->Rbp
;
428 to
->ctl
.i386_regs
.eip
= from
->Rip
;
429 to
->ctl
.i386_regs
.esp
= from
->Rsp
;
430 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
431 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
432 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
434 if (flags
& CONTEXT_AMD64_INTEGER
)
436 to
->flags
|= SERVER_CTX_INTEGER
;
437 to
->integer
.i386_regs
.eax
= from
->Rax
;
438 to
->integer
.i386_regs
.ecx
= from
->Rcx
;
439 to
->integer
.i386_regs
.edx
= from
->Rdx
;
440 to
->integer
.i386_regs
.ebx
= from
->Rbx
;
441 to
->integer
.i386_regs
.esi
= from
->Rsi
;
442 to
->integer
.i386_regs
.edi
= from
->Rdi
;
444 if (flags
& CONTEXT_AMD64_SEGMENTS
)
446 to
->flags
|= SERVER_CTX_SEGMENTS
;
447 to
->seg
.i386_regs
.ds
= from
->SegDs
;
448 to
->seg
.i386_regs
.es
= from
->SegEs
;
449 to
->seg
.i386_regs
.fs
= from
->SegFs
;
450 to
->seg
.i386_regs
.gs
= from
->SegGs
;
452 if (flags
& CONTEXT_AMD64_FLOATING_POINT
)
454 I386_FLOATING_SAVE_AREA fpu
;
456 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
| SERVER_CTX_FLOATING_POINT
;
457 memcpy( to
->ext
.i386_regs
, &from
->u
.FltSave
, sizeof(to
->ext
.i386_regs
) );
458 fpux_to_fpu( &fpu
, &from
->u
.FltSave
);
459 to
->fp
.i386_regs
.ctrl
= fpu
.ControlWord
;
460 to
->fp
.i386_regs
.status
= fpu
.StatusWord
;
461 to
->fp
.i386_regs
.tag
= fpu
.TagWord
;
462 to
->fp
.i386_regs
.err_off
= fpu
.ErrorOffset
;
463 to
->fp
.i386_regs
.err_sel
= fpu
.ErrorSelector
;
464 to
->fp
.i386_regs
.data_off
= fpu
.DataOffset
;
465 to
->fp
.i386_regs
.data_sel
= fpu
.DataSelector
;
466 to
->fp
.i386_regs
.cr0npx
= fpu
.Cr0NpxState
;
467 memcpy( to
->fp
.i386_regs
.regs
, fpu
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
469 if (flags
& CONTEXT_AMD64_DEBUG_REGISTERS
)
471 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
472 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
473 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
474 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
475 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
476 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
477 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
479 if (flags
& CONTEXT_AMD64_XSTATE
)
481 const CONTEXT_EX
*xctx
= (const CONTEXT_EX
*)(from
+ 1);
482 const XSTATE
*xs
= (const XSTATE
*)((const char *)xctx
+ xctx
->XState
.Offset
);
484 to
->flags
|= SERVER_CTX_YMM_REGISTERS
;
485 if (xs
->Mask
& 4) memcpy( &to
->ymm
.regs
.ymm_high
, &xs
->YmmContext
, sizeof(xs
->YmmContext
) );
487 return STATUS_SUCCESS
;
490 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT
, IMAGE_FILE_MACHINE_ARMNT
):
492 const ARM_CONTEXT
*from
= src
;
494 flags
= from
->ContextFlags
& ~CONTEXT_ARM
;
495 if (flags
& CONTEXT_ARM_CONTROL
)
497 to
->flags
|= SERVER_CTX_CONTROL
;
498 to
->ctl
.arm_regs
.sp
= from
->Sp
;
499 to
->ctl
.arm_regs
.lr
= from
->Lr
;
500 to
->ctl
.arm_regs
.pc
= from
->Pc
;
501 to
->ctl
.arm_regs
.cpsr
= from
->Cpsr
;
503 if (flags
& CONTEXT_ARM_INTEGER
)
505 to
->flags
|= SERVER_CTX_INTEGER
;
506 to
->integer
.arm_regs
.r
[0] = from
->R0
;
507 to
->integer
.arm_regs
.r
[1] = from
->R1
;
508 to
->integer
.arm_regs
.r
[2] = from
->R2
;
509 to
->integer
.arm_regs
.r
[3] = from
->R3
;
510 to
->integer
.arm_regs
.r
[4] = from
->R4
;
511 to
->integer
.arm_regs
.r
[5] = from
->R5
;
512 to
->integer
.arm_regs
.r
[6] = from
->R6
;
513 to
->integer
.arm_regs
.r
[7] = from
->R7
;
514 to
->integer
.arm_regs
.r
[8] = from
->R8
;
515 to
->integer
.arm_regs
.r
[9] = from
->R9
;
516 to
->integer
.arm_regs
.r
[10] = from
->R10
;
517 to
->integer
.arm_regs
.r
[11] = from
->R11
;
518 to
->integer
.arm_regs
.r
[12] = from
->R12
;
520 if (flags
& CONTEXT_ARM_FLOATING_POINT
)
522 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
523 for (i
= 0; i
< 32; i
++) to
->fp
.arm_regs
.d
[i
] = from
->u
.D
[i
];
524 to
->fp
.arm_regs
.fpscr
= from
->Fpscr
;
526 if (flags
& CONTEXT_ARM_DEBUG_REGISTERS
)
528 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
529 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->debug
.arm_regs
.bvr
[i
] = from
->Bvr
[i
];
530 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->debug
.arm_regs
.bcr
[i
] = from
->Bcr
[i
];
531 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->debug
.arm_regs
.wvr
[i
] = from
->Wvr
[i
];
532 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->debug
.arm_regs
.wcr
[i
] = from
->Wcr
[i
];
534 return STATUS_SUCCESS
;
537 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_ARM64
):
539 const ARM64_NT_CONTEXT
*from
= src
;
541 flags
= from
->ContextFlags
& ~CONTEXT_ARM64
;
542 if (flags
& CONTEXT_ARM64_CONTROL
)
544 to
->flags
|= SERVER_CTX_CONTROL
;
545 to
->integer
.arm64_regs
.x
[29] = from
->u
.s
.Fp
;
546 to
->integer
.arm64_regs
.x
[30] = from
->u
.s
.Lr
;
547 to
->ctl
.arm64_regs
.sp
= from
->Sp
;
548 to
->ctl
.arm64_regs
.pc
= from
->Pc
;
549 to
->ctl
.arm64_regs
.pstate
= from
->Cpsr
;
551 if (flags
& CONTEXT_ARM64_INTEGER
)
553 to
->flags
|= SERVER_CTX_INTEGER
;
554 for (i
= 0; i
<= 28; i
++) to
->integer
.arm64_regs
.x
[i
] = from
->u
.X
[i
];
556 if (flags
& CONTEXT_ARM64_FLOATING_POINT
)
558 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
559 for (i
= 0; i
< 32; i
++)
561 to
->fp
.arm64_regs
.q
[i
].low
= from
->V
[i
].s
.Low
;
562 to
->fp
.arm64_regs
.q
[i
].high
= from
->V
[i
].s
.High
;
564 to
->fp
.arm64_regs
.fpcr
= from
->Fpcr
;
565 to
->fp
.arm64_regs
.fpsr
= from
->Fpsr
;
567 if (flags
& CONTEXT_ARM64_DEBUG_REGISTERS
)
569 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
570 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->debug
.arm64_regs
.bcr
[i
] = from
->Bcr
[i
];
571 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->debug
.arm64_regs
.bvr
[i
] = from
->Bvr
[i
];
572 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->debug
.arm64_regs
.wcr
[i
] = from
->Wcr
[i
];
573 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->debug
.arm64_regs
.wvr
[i
] = from
->Wvr
[i
];
575 return STATUS_SUCCESS
;
579 return STATUS_INVALID_PARAMETER
;
584 /***********************************************************************
585 * context_from_server
587 * Convert a register context from the server format.
589 static NTSTATUS
context_from_server( void *dst
, const context_t
*from
, USHORT machine
)
593 switch (MAKELONG( from
->machine
, machine
))
595 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_I386
):
597 I386_CONTEXT
*to
= dst
;
599 to_flags
= to
->ContextFlags
& ~CONTEXT_i386
;
600 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_I386_CONTROL
))
602 to
->ContextFlags
|= CONTEXT_I386_CONTROL
;
603 to
->Ebp
= from
->ctl
.i386_regs
.ebp
;
604 to
->Esp
= from
->ctl
.i386_regs
.esp
;
605 to
->Eip
= from
->ctl
.i386_regs
.eip
;
606 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
607 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
608 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
610 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_I386_INTEGER
))
612 to
->ContextFlags
|= CONTEXT_I386_INTEGER
;
613 to
->Eax
= from
->integer
.i386_regs
.eax
;
614 to
->Ebx
= from
->integer
.i386_regs
.ebx
;
615 to
->Ecx
= from
->integer
.i386_regs
.ecx
;
616 to
->Edx
= from
->integer
.i386_regs
.edx
;
617 to
->Esi
= from
->integer
.i386_regs
.esi
;
618 to
->Edi
= from
->integer
.i386_regs
.edi
;
620 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_I386_SEGMENTS
))
622 to
->ContextFlags
|= CONTEXT_I386_SEGMENTS
;
623 to
->SegDs
= from
->seg
.i386_regs
.ds
;
624 to
->SegEs
= from
->seg
.i386_regs
.es
;
625 to
->SegFs
= from
->seg
.i386_regs
.fs
;
626 to
->SegGs
= from
->seg
.i386_regs
.gs
;
628 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_I386_FLOATING_POINT
))
630 to
->ContextFlags
|= CONTEXT_I386_FLOATING_POINT
;
631 to
->FloatSave
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
632 to
->FloatSave
.StatusWord
= from
->fp
.i386_regs
.status
;
633 to
->FloatSave
.TagWord
= from
->fp
.i386_regs
.tag
;
634 to
->FloatSave
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
635 to
->FloatSave
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
636 to
->FloatSave
.DataOffset
= from
->fp
.i386_regs
.data_off
;
637 to
->FloatSave
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
638 to
->FloatSave
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
639 memcpy( to
->FloatSave
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(to
->FloatSave
.RegisterArea
) );
641 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_I386_DEBUG_REGISTERS
))
643 to
->ContextFlags
|= CONTEXT_I386_DEBUG_REGISTERS
;
644 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
645 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
646 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
647 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
648 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
649 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
651 if ((from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
) && (to_flags
& CONTEXT_I386_EXTENDED_REGISTERS
))
653 to
->ContextFlags
|= CONTEXT_I386_EXTENDED_REGISTERS
;
654 memcpy( to
->ExtendedRegisters
, from
->ext
.i386_regs
, sizeof(to
->ExtendedRegisters
) );
656 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_I386_XSTATE
))
658 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
659 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
662 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
663 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
665 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
666 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
671 return STATUS_SUCCESS
;
674 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_I386
):
676 I386_CONTEXT
*to
= dst
;
678 to_flags
= to
->ContextFlags
& ~CONTEXT_i386
;
679 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_I386_CONTROL
))
681 to
->ContextFlags
|= CONTEXT_I386_CONTROL
;
682 to
->Ebp
= from
->ctl
.x86_64_regs
.rbp
;
683 to
->Esp
= from
->ctl
.x86_64_regs
.rsp
;
684 to
->Eip
= from
->ctl
.x86_64_regs
.rip
;
685 to
->SegCs
= from
->ctl
.x86_64_regs
.cs
;
686 to
->SegSs
= from
->ctl
.x86_64_regs
.ss
;
687 to
->EFlags
= from
->ctl
.x86_64_regs
.flags
;
689 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_I386_INTEGER
))
691 to
->ContextFlags
|= CONTEXT_I386_INTEGER
;
692 to
->Eax
= from
->integer
.x86_64_regs
.rax
;
693 to
->Ebx
= from
->integer
.x86_64_regs
.rbx
;
694 to
->Ecx
= from
->integer
.x86_64_regs
.rcx
;
695 to
->Edx
= from
->integer
.x86_64_regs
.rdx
;
696 to
->Esi
= from
->integer
.x86_64_regs
.rsi
;
697 to
->Edi
= from
->integer
.x86_64_regs
.rdi
;
699 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_I386_SEGMENTS
))
701 to
->ContextFlags
|= CONTEXT_I386_SEGMENTS
;
702 to
->SegDs
= from
->seg
.x86_64_regs
.ds
;
703 to
->SegEs
= from
->seg
.x86_64_regs
.es
;
704 to
->SegFs
= from
->seg
.x86_64_regs
.fs
;
705 to
->SegGs
= from
->seg
.x86_64_regs
.gs
;
707 if (from
->flags
& SERVER_CTX_FLOATING_POINT
)
709 if (to_flags
& CONTEXT_I386_EXTENDED_REGISTERS
)
711 to
->ContextFlags
|= CONTEXT_I386_EXTENDED_REGISTERS
;
712 memcpy( to
->ExtendedRegisters
, from
->fp
.x86_64_regs
.fpregs
, sizeof(to
->ExtendedRegisters
) );
714 if (to_flags
& CONTEXT_I386_FLOATING_POINT
)
716 to
->ContextFlags
|= CONTEXT_I386_FLOATING_POINT
;
717 fpux_to_fpu( &to
->FloatSave
, (XMM_SAVE_AREA32
*)from
->fp
.x86_64_regs
.fpregs
);
720 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_I386_DEBUG_REGISTERS
))
722 to
->ContextFlags
|= CONTEXT_I386_DEBUG_REGISTERS
;
723 to
->Dr0
= from
->debug
.x86_64_regs
.dr0
;
724 to
->Dr1
= from
->debug
.x86_64_regs
.dr1
;
725 to
->Dr2
= from
->debug
.x86_64_regs
.dr2
;
726 to
->Dr3
= from
->debug
.x86_64_regs
.dr3
;
727 to
->Dr6
= from
->debug
.x86_64_regs
.dr6
;
728 to
->Dr7
= from
->debug
.x86_64_regs
.dr7
;
730 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_I386_XSTATE
))
732 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
733 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
736 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
737 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
739 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
740 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
745 return STATUS_SUCCESS
;
748 case MAKELONG( IMAGE_FILE_MACHINE_AMD64
, IMAGE_FILE_MACHINE_AMD64
):
750 AMD64_CONTEXT
*to
= dst
;
752 to_flags
= to
->ContextFlags
& ~CONTEXT_AMD64
;
753 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_AMD64_CONTROL
))
755 to
->ContextFlags
|= CONTEXT_AMD64_CONTROL
;
756 to
->Rbp
= from
->ctl
.x86_64_regs
.rbp
;
757 to
->Rip
= from
->ctl
.x86_64_regs
.rip
;
758 to
->Rsp
= from
->ctl
.x86_64_regs
.rsp
;
759 to
->SegCs
= from
->ctl
.x86_64_regs
.cs
;
760 to
->SegSs
= from
->ctl
.x86_64_regs
.ss
;
761 to
->EFlags
= from
->ctl
.x86_64_regs
.flags
;
763 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_AMD64_INTEGER
))
765 to
->ContextFlags
|= CONTEXT_AMD64_INTEGER
;
766 to
->Rax
= from
->integer
.x86_64_regs
.rax
;
767 to
->Rcx
= from
->integer
.x86_64_regs
.rcx
;
768 to
->Rdx
= from
->integer
.x86_64_regs
.rdx
;
769 to
->Rbx
= from
->integer
.x86_64_regs
.rbx
;
770 to
->Rsi
= from
->integer
.x86_64_regs
.rsi
;
771 to
->Rdi
= from
->integer
.x86_64_regs
.rdi
;
772 to
->R8
= from
->integer
.x86_64_regs
.r8
;
773 to
->R9
= from
->integer
.x86_64_regs
.r9
;
774 to
->R10
= from
->integer
.x86_64_regs
.r10
;
775 to
->R11
= from
->integer
.x86_64_regs
.r11
;
776 to
->R12
= from
->integer
.x86_64_regs
.r12
;
777 to
->R13
= from
->integer
.x86_64_regs
.r13
;
778 to
->R14
= from
->integer
.x86_64_regs
.r14
;
779 to
->R15
= from
->integer
.x86_64_regs
.r15
;
781 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_AMD64_SEGMENTS
))
783 to
->ContextFlags
|= CONTEXT_AMD64_SEGMENTS
;
784 to
->SegDs
= from
->seg
.x86_64_regs
.ds
;
785 to
->SegEs
= from
->seg
.x86_64_regs
.es
;
786 to
->SegFs
= from
->seg
.x86_64_regs
.fs
;
787 to
->SegGs
= from
->seg
.x86_64_regs
.gs
;
789 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
791 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
792 memcpy( &to
->u
.FltSave
, from
->fp
.x86_64_regs
.fpregs
, sizeof(from
->fp
.x86_64_regs
.fpregs
) );
793 to
->MxCsr
= to
->u
.FltSave
.MxCsr
;
795 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_AMD64_DEBUG_REGISTERS
))
797 to
->ContextFlags
|= CONTEXT_AMD64_DEBUG_REGISTERS
;
798 to
->Dr0
= from
->debug
.x86_64_regs
.dr0
;
799 to
->Dr1
= from
->debug
.x86_64_regs
.dr1
;
800 to
->Dr2
= from
->debug
.x86_64_regs
.dr2
;
801 to
->Dr3
= from
->debug
.x86_64_regs
.dr3
;
802 to
->Dr6
= from
->debug
.x86_64_regs
.dr6
;
803 to
->Dr7
= from
->debug
.x86_64_regs
.dr7
;
805 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_AMD64_XSTATE
))
807 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
808 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
811 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
812 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
814 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
815 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
820 return STATUS_SUCCESS
;
823 case MAKELONG( IMAGE_FILE_MACHINE_I386
, IMAGE_FILE_MACHINE_AMD64
):
825 AMD64_CONTEXT
*to
= dst
;
827 to_flags
= to
->ContextFlags
& ~CONTEXT_AMD64
;
828 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_AMD64_CONTROL
))
830 to
->ContextFlags
|= CONTEXT_AMD64_CONTROL
;
831 to
->Rbp
= from
->ctl
.i386_regs
.ebp
;
832 to
->Rip
= from
->ctl
.i386_regs
.eip
;
833 to
->Rsp
= from
->ctl
.i386_regs
.esp
;
834 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
835 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
836 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
838 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_AMD64_INTEGER
))
840 to
->ContextFlags
|= CONTEXT_AMD64_INTEGER
;
841 to
->Rax
= from
->integer
.i386_regs
.eax
;
842 to
->Rcx
= from
->integer
.i386_regs
.ecx
;
843 to
->Rdx
= from
->integer
.i386_regs
.edx
;
844 to
->Rbx
= from
->integer
.i386_regs
.ebx
;
845 to
->Rsi
= from
->integer
.i386_regs
.esi
;
846 to
->Rdi
= from
->integer
.i386_regs
.edi
;
848 if ((from
->flags
& SERVER_CTX_SEGMENTS
) && (to_flags
& CONTEXT_AMD64_SEGMENTS
))
850 to
->ContextFlags
|= CONTEXT_AMD64_SEGMENTS
;
851 to
->SegDs
= from
->seg
.i386_regs
.ds
;
852 to
->SegEs
= from
->seg
.i386_regs
.es
;
853 to
->SegFs
= from
->seg
.i386_regs
.fs
;
854 to
->SegGs
= from
->seg
.i386_regs
.gs
;
856 if ((from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
858 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
859 memcpy( &to
->u
.FltSave
, from
->ext
.i386_regs
, sizeof(to
->u
.FltSave
) );
861 else if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_AMD64_FLOATING_POINT
))
863 I386_FLOATING_SAVE_AREA fpu
;
865 to
->ContextFlags
|= CONTEXT_AMD64_FLOATING_POINT
;
866 fpu
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
867 fpu
.StatusWord
= from
->fp
.i386_regs
.status
;
868 fpu
.TagWord
= from
->fp
.i386_regs
.tag
;
869 fpu
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
870 fpu
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
871 fpu
.DataOffset
= from
->fp
.i386_regs
.data_off
;
872 fpu
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
873 fpu
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
874 memcpy( fpu
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(fpu
.RegisterArea
) );
875 fpu_to_fpux( &to
->u
.FltSave
, &fpu
);
877 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_AMD64_DEBUG_REGISTERS
))
879 to
->ContextFlags
|= CONTEXT_AMD64_DEBUG_REGISTERS
;
880 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
881 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
882 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
883 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
884 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
885 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
887 if ((from
->flags
& SERVER_CTX_YMM_REGISTERS
) && (to_flags
& CONTEXT_AMD64_XSTATE
))
889 CONTEXT_EX
*xctx
= (CONTEXT_EX
*)(to
+ 1);
890 XSTATE
*xs
= (XSTATE
*)((char *)xctx
+ xctx
->XState
.Offset
);
893 if (user_shared_data
->XState
.CompactionEnabled
) xs
->CompactionMask
= 0x8000000000000004;
894 for (i
= 0; i
< ARRAY_SIZE( from
->ymm
.regs
.ymm_high
); i
++)
896 if (!from
->ymm
.regs
.ymm_high
[i
].low
&& !from
->ymm
.regs
.ymm_high
[i
].high
) continue;
897 memcpy( &xs
->YmmContext
, &from
->ymm
.regs
, sizeof(xs
->YmmContext
) );
902 return STATUS_SUCCESS
;
905 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT
, IMAGE_FILE_MACHINE_ARMNT
):
907 ARM_CONTEXT
*to
= dst
;
909 to_flags
= to
->ContextFlags
& ~CONTEXT_ARM
;
910 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_ARM_CONTROL
))
912 to
->ContextFlags
|= CONTEXT_ARM_CONTROL
;
913 to
->Sp
= from
->ctl
.arm_regs
.sp
;
914 to
->Lr
= from
->ctl
.arm_regs
.lr
;
915 to
->Pc
= from
->ctl
.arm_regs
.pc
;
916 to
->Cpsr
= from
->ctl
.arm_regs
.cpsr
;
918 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_ARM_INTEGER
))
920 to
->ContextFlags
|= CONTEXT_ARM_INTEGER
;
921 to
->R0
= from
->integer
.arm_regs
.r
[0];
922 to
->R1
= from
->integer
.arm_regs
.r
[1];
923 to
->R2
= from
->integer
.arm_regs
.r
[2];
924 to
->R3
= from
->integer
.arm_regs
.r
[3];
925 to
->R4
= from
->integer
.arm_regs
.r
[4];
926 to
->R5
= from
->integer
.arm_regs
.r
[5];
927 to
->R6
= from
->integer
.arm_regs
.r
[6];
928 to
->R7
= from
->integer
.arm_regs
.r
[7];
929 to
->R8
= from
->integer
.arm_regs
.r
[8];
930 to
->R9
= from
->integer
.arm_regs
.r
[9];
931 to
->R10
= from
->integer
.arm_regs
.r
[10];
932 to
->R11
= from
->integer
.arm_regs
.r
[11];
933 to
->R12
= from
->integer
.arm_regs
.r
[12];
935 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_ARM_FLOATING_POINT
))
937 to
->ContextFlags
|= CONTEXT_ARM_FLOATING_POINT
;
938 for (i
= 0; i
< 32; i
++) to
->u
.D
[i
] = from
->fp
.arm_regs
.d
[i
];
939 to
->Fpscr
= from
->fp
.arm_regs
.fpscr
;
941 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_ARM_DEBUG_REGISTERS
))
943 to
->ContextFlags
|= CONTEXT_ARM_DEBUG_REGISTERS
;
944 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->Bvr
[i
] = from
->debug
.arm_regs
.bvr
[i
];
945 for (i
= 0; i
< ARM_MAX_BREAKPOINTS
; i
++) to
->Bcr
[i
] = from
->debug
.arm_regs
.bcr
[i
];
946 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->Wvr
[i
] = from
->debug
.arm_regs
.wvr
[i
];
947 for (i
= 0; i
< ARM_MAX_WATCHPOINTS
; i
++) to
->Wcr
[i
] = from
->debug
.arm_regs
.wcr
[i
];
949 return STATUS_SUCCESS
;
952 case MAKELONG( IMAGE_FILE_MACHINE_ARM64
, IMAGE_FILE_MACHINE_ARM64
):
954 ARM64_NT_CONTEXT
*to
= dst
;
956 to_flags
= to
->ContextFlags
& ~CONTEXT_ARM64
;
957 to
->ContextFlags
= CONTEXT_ARM64
;
958 if ((from
->flags
& SERVER_CTX_CONTROL
) && (to_flags
& CONTEXT_ARM64_CONTROL
))
960 to
->ContextFlags
|= CONTEXT_ARM64_CONTROL
;
961 to
->u
.s
.Fp
= from
->integer
.arm64_regs
.x
[29];
962 to
->u
.s
.Lr
= from
->integer
.arm64_regs
.x
[30];
963 to
->Sp
= from
->ctl
.arm64_regs
.sp
;
964 to
->Pc
= from
->ctl
.arm64_regs
.pc
;
965 to
->Cpsr
= from
->ctl
.arm64_regs
.pstate
;
967 if ((from
->flags
& SERVER_CTX_INTEGER
) && (to_flags
& CONTEXT_ARM64_INTEGER
))
969 to
->ContextFlags
|= CONTEXT_ARM64_INTEGER
;
970 for (i
= 0; i
<= 28; i
++) to
->u
.X
[i
] = from
->integer
.arm64_regs
.x
[i
];
972 if ((from
->flags
& SERVER_CTX_FLOATING_POINT
) && (to_flags
& CONTEXT_ARM64_FLOATING_POINT
))
974 to
->ContextFlags
|= CONTEXT_ARM64_FLOATING_POINT
;
975 for (i
= 0; i
< 32; i
++)
977 to
->V
[i
].s
.Low
= from
->fp
.arm64_regs
.q
[i
].low
;
978 to
->V
[i
].s
.High
= from
->fp
.arm64_regs
.q
[i
].high
;
980 to
->Fpcr
= from
->fp
.arm64_regs
.fpcr
;
981 to
->Fpsr
= from
->fp
.arm64_regs
.fpsr
;
983 if ((from
->flags
& SERVER_CTX_DEBUG_REGISTERS
) && (to_flags
& CONTEXT_ARM64_DEBUG_REGISTERS
))
985 to
->ContextFlags
|= CONTEXT_ARM64_DEBUG_REGISTERS
;
986 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->Bcr
[i
] = from
->debug
.arm64_regs
.bcr
[i
];
987 for (i
= 0; i
< ARM64_MAX_BREAKPOINTS
; i
++) to
->Bvr
[i
] = from
->debug
.arm64_regs
.bvr
[i
];
988 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->Wcr
[i
] = from
->debug
.arm64_regs
.wcr
[i
];
989 for (i
= 0; i
< ARM64_MAX_WATCHPOINTS
; i
++) to
->Wvr
[i
] = from
->debug
.arm64_regs
.wvr
[i
];
991 return STATUS_SUCCESS
;
995 return STATUS_INVALID_PARAMETER
;
1000 /***********************************************************************
1001 * contexts_to_server
1003 static void contexts_to_server( context_t server_contexts
[2], CONTEXT
*context
)
1005 unsigned int count
= 0;
1006 void *native_context
= get_native_context( context
);
1007 void *wow_context
= get_wow_context( context
);
1011 context_to_server( &server_contexts
[count
++], native_machine
, native_context
, native_machine
);
1012 if (wow_context
) context_to_server( &server_contexts
[count
++], main_image_info
.Machine
,
1013 wow_context
, main_image_info
.Machine
);
1014 else if (native_machine
!= main_image_info
.Machine
)
1015 context_to_server( &server_contexts
[count
++], main_image_info
.Machine
,
1016 native_context
, native_machine
);
1019 context_to_server( &server_contexts
[count
++], native_machine
,
1020 wow_context
, main_image_info
.Machine
);
1022 if (count
< 2) memset( &server_contexts
[1], 0, sizeof(server_contexts
[1]) );
1026 /***********************************************************************
1027 * contexts_from_server
1029 static void contexts_from_server( CONTEXT
*context
, context_t server_contexts
[2] )
1031 void *native_context
= get_native_context( context
);
1032 void *wow_context
= get_wow_context( context
);
1036 context_from_server( native_context
, &server_contexts
[0], native_machine
);
1037 if (wow_context
) context_from_server( wow_context
, &server_contexts
[1], main_image_info
.Machine
);
1039 else context_from_server( wow_context
, &server_contexts
[0], main_image_info
.Machine
);
1043 /***********************************************************************
1044 * pthread_exit_wrapper
1046 static void pthread_exit_wrapper( int status
)
1048 close( ntdll_get_thread_data()->wait_fd
[0] );
1049 close( ntdll_get_thread_data()->wait_fd
[1] );
1050 close( ntdll_get_thread_data()->reply_fd
);
1051 close( ntdll_get_thread_data()->request_fd
);
1052 pthread_exit( UIntToPtr(status
) );
1056 /***********************************************************************
1059 * Startup routine for a newly created thread.
1061 static void start_thread( TEB
*teb
)
1063 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1066 thread_data
->pthread_id
= pthread_self();
1067 signal_init_thread( teb
);
1068 server_init_thread( thread_data
->start
, &suspend
);
1069 signal_start_thread( thread_data
->start
, thread_data
->param
, suspend
, teb
);
1073 /***********************************************************************
1074 * get_machine_context_size
1076 static SIZE_T
get_machine_context_size( USHORT machine
)
1080 case IMAGE_FILE_MACHINE_I386
: return sizeof(I386_CONTEXT
);
1081 case IMAGE_FILE_MACHINE_ARMNT
: return sizeof(ARM_CONTEXT
);
1082 case IMAGE_FILE_MACHINE_AMD64
: return sizeof(AMD64_CONTEXT
);
1083 case IMAGE_FILE_MACHINE_ARM64
: return sizeof(ARM64_NT_CONTEXT
);
1089 /***********************************************************************
1092 * cf. RtlWow64GetCurrentCpuArea
1094 void *get_cpu_area( USHORT machine
)
1096 WOW64_CPURESERVED
*cpu
;
1099 if (!NtCurrentTeb()->WowTebOffset
) return NULL
;
1101 cpu
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_CPURESERVED
];
1103 cpu
= ULongToPtr( NtCurrentTeb64()->TlsSlots
[WOW64_TLS_CPURESERVED
] );
1105 if (cpu
->Machine
!= machine
) return NULL
;
1106 switch (cpu
->Machine
)
1108 case IMAGE_FILE_MACHINE_I386
: align
= TYPE_ALIGNMENT(I386_CONTEXT
); break;
1109 case IMAGE_FILE_MACHINE_AMD64
: align
= TYPE_ALIGNMENT(ARM_CONTEXT
); break;
1110 case IMAGE_FILE_MACHINE_ARMNT
: align
= TYPE_ALIGNMENT(AMD64_CONTEXT
); break;
1111 case IMAGE_FILE_MACHINE_ARM64
: align
= TYPE_ALIGNMENT(ARM64_NT_CONTEXT
); break;
1112 default: return NULL
;
1114 return (void *)(((ULONG_PTR
)(cpu
+ 1) + align
- 1) & ~(align
- 1));
1118 /***********************************************************************
1121 void set_thread_id( TEB
*teb
, DWORD pid
, DWORD tid
)
1123 WOW_TEB
*wow_teb
= get_wow_teb( teb
);
1125 teb
->ClientId
.UniqueProcess
= ULongToHandle( pid
);
1126 teb
->ClientId
.UniqueThread
= ULongToHandle( tid
);
1127 teb
->RealClientId
= teb
->ClientId
;
1130 wow_teb
->ClientId
.UniqueProcess
= pid
;
1131 wow_teb
->ClientId
.UniqueThread
= tid
;
1132 wow_teb
->RealClientId
= wow_teb
->ClientId
;
1137 /***********************************************************************
1140 NTSTATUS
init_thread_stack( TEB
*teb
, ULONG_PTR zero_bits
, SIZE_T reserve_size
, SIZE_T commit_size
)
1142 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1143 WOW_TEB
*wow_teb
= get_wow_teb( teb
);
1149 WOW64_CPURESERVED
*cpu
;
1150 SIZE_T cpusize
= sizeof(WOW64_CPURESERVED
) +
1151 ((get_machine_context_size( main_image_info
.Machine
) + 7) & ~7) + sizeof(ULONG64
);
1155 if ((status
= virtual_alloc_thread_stack( &stack
, zero_bits
? zero_bits
: 0x7fffffff,
1156 reserve_size
, commit_size
, 0 )))
1158 wow_teb
->Tib
.StackBase
= PtrToUlong( stack
.StackBase
);
1159 wow_teb
->Tib
.StackLimit
= PtrToUlong( stack
.StackLimit
);
1160 wow_teb
->DeallocationStack
= PtrToUlong( stack
.DeallocationStack
);
1163 if ((status
= virtual_alloc_thread_stack( &stack
, 0, 0x40000, 0x40000, kernel_stack_size
)))
1165 cpu
= (WOW64_CPURESERVED
*)(((ULONG_PTR
)stack
.StackBase
- cpusize
) & ~15);
1166 cpu
->Machine
= main_image_info
.Machine
;
1167 teb
->Tib
.StackBase
= teb
->TlsSlots
[WOW64_TLS_CPURESERVED
] = cpu
;
1168 teb
->Tib
.StackLimit
= stack
.StackLimit
;
1169 teb
->DeallocationStack
= stack
.DeallocationStack
;
1170 thread_data
->kernel_stack
= stack
.StackBase
;
1171 return STATUS_SUCCESS
;
1174 if ((status
= virtual_alloc_thread_stack( &stack
, 0, 0x40000, 0x40000, 0 ))) return status
;
1176 cpu
= (WOW64_CPURESERVED
*)(((ULONG_PTR
)stack
.StackBase
- cpusize
) & ~15);
1177 cpu
->Machine
= main_image_info
.Machine
;
1178 wow_teb
->Tib
.StackBase
= wow_teb
->TlsSlots
[WOW64_TLS_CPURESERVED
] = PtrToUlong( cpu
);
1179 wow_teb
->Tib
.StackLimit
= PtrToUlong( stack
.StackLimit
);
1180 wow_teb
->DeallocationStack
= PtrToUlong( stack
.DeallocationStack
);
1185 if ((status
= virtual_alloc_thread_stack( &stack
, zero_bits
, reserve_size
,
1186 commit_size
, kernel_stack_size
)))
1188 teb
->Tib
.StackBase
= stack
.StackBase
;
1189 teb
->Tib
.StackLimit
= stack
.StackLimit
;
1190 teb
->DeallocationStack
= stack
.DeallocationStack
;
1191 thread_data
->kernel_stack
= stack
.StackBase
;
1192 return STATUS_SUCCESS
;
1196 /***********************************************************************
1199 * Update the output attributes.
1201 static void update_attr_list( PS_ATTRIBUTE_LIST
*attr
, const CLIENT_ID
*id
, TEB
*teb
)
1203 SIZE_T i
, count
= (attr
->TotalLength
- sizeof(attr
->TotalLength
)) / sizeof(PS_ATTRIBUTE
);
1205 for (i
= 0; i
< count
; i
++)
1207 if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_CLIENT_ID
)
1209 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(*id
) );
1210 memcpy( attr
->Attributes
[i
].ValuePtr
, id
, size
);
1211 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
1213 else if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_TEB_ADDRESS
)
1215 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(teb
) );
1216 memcpy( attr
->Attributes
[i
].ValuePtr
, &teb
, size
);
1217 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
1222 /***********************************************************************
1223 * NtCreateThread (NTDLL.@)
1225 NTSTATUS WINAPI
NtCreateThread( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1226 HANDLE process
, CLIENT_ID
*id
, CONTEXT
*ctx
, INITIAL_TEB
*teb
,
1229 FIXME( "%p %d %p %p %p %p %p %d, stub!\n", handle
, access
, attr
, process
, id
, ctx
, teb
, suspended
);
1230 return STATUS_NOT_IMPLEMENTED
;
1233 /***********************************************************************
1234 * NtCreateThreadEx (NTDLL.@)
1236 NTSTATUS WINAPI
NtCreateThreadEx( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1237 HANDLE process
, PRTL_THREAD_START_ROUTINE start
, void *param
,
1238 ULONG flags
, ULONG_PTR zero_bits
, SIZE_T stack_commit
,
1239 SIZE_T stack_reserve
, PS_ATTRIBUTE_LIST
*attr_list
)
1241 static const ULONG supported_flags
= THREAD_CREATE_FLAGS_CREATE_SUSPENDED
| THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER
;
1243 pthread_t pthread_id
;
1244 pthread_attr_t pthread_attr
;
1246 struct object_attributes
*objattr
;
1247 struct ntdll_thread_data
*thread_data
;
1249 int request_pipe
[2];
1253 if (flags
& ~supported_flags
)
1254 FIXME( "Unsupported flags %#x.\n", flags
);
1256 if (zero_bits
> 21 && zero_bits
< 32) return STATUS_INVALID_PARAMETER_3
;
1258 if (!is_wow64
&& zero_bits
>= 32) return STATUS_INVALID_PARAMETER_3
;
1261 if (process
!= NtCurrentProcess())
1264 apc_result_t result
;
1266 memset( &call
, 0, sizeof(call
) );
1268 call
.create_thread
.type
= APC_CREATE_THREAD
;
1269 call
.create_thread
.flags
= flags
;
1270 call
.create_thread
.func
= wine_server_client_ptr( start
);
1271 call
.create_thread
.arg
= wine_server_client_ptr( param
);
1272 call
.create_thread
.zero_bits
= zero_bits
;
1273 call
.create_thread
.reserve
= stack_reserve
;
1274 call
.create_thread
.commit
= stack_commit
;
1275 status
= server_queue_process_apc( process
, &call
, &result
);
1276 if (status
!= STATUS_SUCCESS
) return status
;
1278 if (result
.create_thread
.status
== STATUS_SUCCESS
)
1280 CLIENT_ID client_id
;
1281 TEB
*teb
= wine_server_get_ptr( result
.create_thread
.teb
);
1282 *handle
= wine_server_ptr_handle( result
.create_thread
.handle
);
1283 client_id
.UniqueProcess
= ULongToHandle( result
.create_thread
.pid
);
1284 client_id
.UniqueThread
= ULongToHandle( result
.create_thread
.tid
);
1285 if (attr_list
) update_attr_list( attr_list
, &client_id
, teb
);
1287 return result
.create_thread
.status
;
1290 if ((status
= alloc_object_attributes( attr
, &objattr
, &len
))) return status
;
1292 if (server_pipe( request_pipe
) == -1)
1295 return STATUS_TOO_MANY_OPENED_FILES
;
1297 wine_server_send_fd( request_pipe
[0] );
1299 if (!access
) access
= THREAD_ALL_ACCESS
;
1301 SERVER_START_REQ( new_thread
)
1303 req
->process
= wine_server_obj_handle( process
);
1304 req
->access
= access
;
1306 req
->request_fd
= request_pipe
[0];
1307 wine_server_add_data( req
, objattr
, len
);
1308 if (!(status
= wine_server_call( req
)))
1310 *handle
= wine_server_ptr_handle( reply
->handle
);
1313 close( request_pipe
[0] );
1320 close( request_pipe
[1] );
1324 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &sigset
);
1326 if ((status
= virtual_alloc_teb( &teb
))) goto done
;
1328 if ((status
= init_thread_stack( teb
, zero_bits
, stack_reserve
, stack_commit
)))
1330 virtual_free_teb( teb
);
1334 set_thread_id( teb
, GetCurrentProcessId(), tid
);
1336 thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1337 thread_data
->request_fd
= request_pipe
[1];
1338 thread_data
->start
= start
;
1339 thread_data
->param
= param
;
1341 pthread_attr_init( &pthread_attr
);
1342 pthread_attr_setstack( &pthread_attr
, teb
->DeallocationStack
,
1343 (char *)thread_data
->kernel_stack
+ kernel_stack_size
- (char *)teb
->DeallocationStack
);
1344 pthread_attr_setguardsize( &pthread_attr
, 0 );
1345 pthread_attr_setscope( &pthread_attr
, PTHREAD_SCOPE_SYSTEM
); /* force creating a kernel thread */
1346 InterlockedIncrement( &nb_threads
);
1347 if (pthread_create( &pthread_id
, &pthread_attr
, (void * (*)(void *))start_thread
, teb
))
1349 InterlockedDecrement( &nb_threads
);
1350 virtual_free_teb( teb
);
1351 status
= STATUS_NO_MEMORY
;
1353 pthread_attr_destroy( &pthread_attr
);
1356 pthread_sigmask( SIG_SETMASK
, &sigset
, NULL
);
1360 close( request_pipe
[1] );
1363 if (attr_list
) update_attr_list( attr_list
, &teb
->ClientId
, teb
);
1364 return STATUS_SUCCESS
;
1368 /***********************************************************************
1371 void abort_thread( int status
)
1373 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1374 if (InterlockedDecrement( &nb_threads
) <= 0) abort_process( status
);
1375 signal_exit_thread( status
, pthread_exit_wrapper
, NtCurrentTeb() );
1379 /***********************************************************************
1382 void abort_process( int status
)
1384 _exit( get_unix_exit_code( status
));
1388 /***********************************************************************
1391 static DECLSPEC_NORETURN
void exit_thread( int status
)
1393 static void *prev_teb
;
1396 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1398 if ((teb
= InterlockedExchangePointer( &prev_teb
, NtCurrentTeb() )))
1400 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
1402 if (thread_data
->pthread_id
)
1404 pthread_join( thread_data
->pthread_id
, NULL
);
1405 virtual_free_teb( teb
);
1408 signal_exit_thread( status
, pthread_exit_wrapper
, NtCurrentTeb() );
1412 /***********************************************************************
1415 void exit_process( int status
)
1417 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
1418 signal_exit_thread( get_unix_exit_code( status
), process_exit_wrapper
, NtCurrentTeb() );
1422 /**********************************************************************
1425 * Wait until the thread is no longer suspended.
1427 void wait_suspend( CONTEXT
*context
)
1429 int saved_errno
= errno
;
1430 context_t server_contexts
[2];
1432 contexts_to_server( server_contexts
, context
);
1433 /* wait with 0 timeout, will only return once the thread is no longer suspended */
1434 server_select( NULL
, 0, SELECT_INTERRUPTIBLE
, 0, server_contexts
, NULL
);
1435 contexts_from_server( context
, server_contexts
);
1436 errno
= saved_errno
;
1440 /**********************************************************************
1443 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
1445 NTSTATUS
send_debug_event( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
1449 obj_handle_t handle
= 0;
1450 client_ptr_t params
[EXCEPTION_MAXIMUM_PARAMETERS
];
1451 select_op_t select_op
;
1454 if (!peb
->BeingDebugged
) return 0; /* no debugger present */
1456 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &old_set
);
1458 for (i
= 0; i
< min( rec
->NumberParameters
, EXCEPTION_MAXIMUM_PARAMETERS
); i
++)
1459 params
[i
] = rec
->ExceptionInformation
[i
];
1461 SERVER_START_REQ( queue_exception_event
)
1463 req
->first
= first_chance
;
1464 req
->code
= rec
->ExceptionCode
;
1465 req
->flags
= rec
->ExceptionFlags
;
1466 req
->record
= wine_server_client_ptr( rec
->ExceptionRecord
);
1467 req
->address
= wine_server_client_ptr( rec
->ExceptionAddress
);
1468 req
->len
= i
* sizeof(params
[0]);
1469 wine_server_add_data( req
, params
, req
->len
);
1470 if (!(ret
= wine_server_call( req
))) handle
= reply
->handle
;
1476 context_t server_contexts
[2];
1478 select_op
.wait
.op
= SELECT_WAIT
;
1479 select_op
.wait
.handles
[0] = handle
;
1481 contexts_to_server( server_contexts
, context
);
1482 server_select( &select_op
, offsetof( select_op_t
, wait
.handles
[1] ), SELECT_INTERRUPTIBLE
,
1483 TIMEOUT_INFINITE
, server_contexts
, NULL
);
1485 SERVER_START_REQ( get_exception_status
)
1487 req
->handle
= handle
;
1488 ret
= wine_server_call( req
);
1491 if (ret
>= 0) contexts_from_server( context
, server_contexts
);
1494 pthread_sigmask( SIG_SETMASK
, &old_set
, NULL
);
1499 /*******************************************************************
1500 * NtRaiseException (NTDLL.@)
1502 NTSTATUS WINAPI
NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
1504 NTSTATUS status
= send_debug_event( rec
, context
, first_chance
);
1506 if (status
== DBG_CONTINUE
|| status
== DBG_EXCEPTION_HANDLED
)
1507 return NtContinue( context
, FALSE
);
1509 if (first_chance
) return call_user_exception_dispatcher( rec
, context
);
1511 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
1512 ERR_(seh
)("Exception frame is not in stack limits => unable to dispatch exception.\n");
1513 else if (rec
->ExceptionCode
== STATUS_NONCONTINUABLE_EXCEPTION
)
1514 ERR_(seh
)("Process attempted to continue execution after noncontinuable exception.\n");
1516 ERR_(seh
)("Unhandled exception code %x flags %x addr %p\n",
1517 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
);
1519 NtTerminateProcess( NtCurrentProcess(), rec
->ExceptionCode
);
1520 return STATUS_SUCCESS
;
1524 /***********************************************************************
1525 * NtOpenThread (NTDLL.@)
1527 NTSTATUS WINAPI
NtOpenThread( HANDLE
*handle
, ACCESS_MASK access
,
1528 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
1534 SERVER_START_REQ( open_thread
)
1536 req
->tid
= HandleToULong(id
->UniqueThread
);
1537 req
->access
= access
;
1538 req
->attributes
= attr
? attr
->Attributes
: 0;
1539 ret
= wine_server_call( req
);
1540 *handle
= wine_server_ptr_handle( reply
->handle
);
1547 /******************************************************************************
1548 * NtSuspendThread (NTDLL.@)
1550 NTSTATUS WINAPI
NtSuspendThread( HANDLE handle
, ULONG
*count
)
1554 SERVER_START_REQ( suspend_thread
)
1556 req
->handle
= wine_server_obj_handle( handle
);
1557 if (!(ret
= wine_server_call( req
)))
1559 if (count
) *count
= reply
->count
;
1567 /******************************************************************************
1568 * NtResumeThread (NTDLL.@)
1570 NTSTATUS WINAPI
NtResumeThread( HANDLE handle
, ULONG
*count
)
1574 SERVER_START_REQ( resume_thread
)
1576 req
->handle
= wine_server_obj_handle( handle
);
1577 if (!(ret
= wine_server_call( req
)))
1579 if (count
) *count
= reply
->count
;
1587 /******************************************************************************
1588 * NtAlertResumeThread (NTDLL.@)
1590 NTSTATUS WINAPI
NtAlertResumeThread( HANDLE handle
, ULONG
*count
)
1592 FIXME( "stub: should alert thread %p\n", handle
);
1593 return NtResumeThread( handle
, count
);
1597 /******************************************************************************
1598 * NtAlertThread (NTDLL.@)
1600 NTSTATUS WINAPI
NtAlertThread( HANDLE handle
)
1602 FIXME( "stub: %p\n", handle
);
1603 return STATUS_NOT_IMPLEMENTED
;
1607 /******************************************************************************
1608 * NtTerminateThread (NTDLL.@)
1610 NTSTATUS WINAPI
NtTerminateThread( HANDLE handle
, LONG exit_code
)
1613 BOOL self
= (handle
== GetCurrentThread());
1615 if (!self
|| exit_code
)
1617 SERVER_START_REQ( terminate_thread
)
1619 req
->handle
= wine_server_obj_handle( handle
);
1620 req
->exit_code
= exit_code
;
1621 ret
= wine_server_call( req
);
1622 self
= !ret
&& reply
->self
;
1626 if (self
) exit_thread( exit_code
);
1631 /******************************************************************************
1632 * NtQueueApcThread (NTDLL.@)
1634 NTSTATUS WINAPI
NtQueueApcThread( HANDLE handle
, PNTAPCFUNC func
, ULONG_PTR arg1
,
1635 ULONG_PTR arg2
, ULONG_PTR arg3
)
1639 SERVER_START_REQ( queue_apc
)
1641 req
->handle
= wine_server_obj_handle( handle
);
1644 req
->call
.type
= APC_USER
;
1645 req
->call
.user
.func
= wine_server_client_ptr( func
);
1646 req
->call
.user
.args
[0] = arg1
;
1647 req
->call
.user
.args
[1] = arg2
;
1648 req
->call
.user
.args
[2] = arg3
;
1650 else req
->call
.type
= APC_NONE
; /* wake up only */
1651 ret
= wine_server_call( req
);
1658 /***********************************************************************
1659 * set_thread_context
1661 NTSTATUS
set_thread_context( HANDLE handle
, const void *context
, BOOL
*self
, USHORT machine
)
1663 context_t server_contexts
[2];
1664 unsigned int count
= 0;
1667 context_to_server( &server_contexts
[count
++], native_machine
, context
, machine
);
1668 if (machine
!= native_machine
)
1669 context_to_server( &server_contexts
[count
++], machine
, context
, machine
);
1671 SERVER_START_REQ( set_thread_context
)
1673 req
->handle
= wine_server_obj_handle( handle
);
1674 wine_server_add_data( req
, server_contexts
, count
* sizeof(server_contexts
[0]) );
1675 ret
= wine_server_call( req
);
1676 *self
= reply
->self
;
1684 /***********************************************************************
1685 * get_thread_context
1687 NTSTATUS
get_thread_context( HANDLE handle
, void *context
, BOOL
*self
, USHORT machine
)
1690 HANDLE context_handle
;
1691 context_t server_contexts
[2];
1693 unsigned int flags
= get_server_context_flags( context
, machine
);
1695 SERVER_START_REQ( get_thread_context
)
1697 req
->handle
= wine_server_obj_handle( handle
);
1699 req
->machine
= machine
;
1700 wine_server_set_reply( req
, server_contexts
, sizeof(server_contexts
) );
1701 ret
= wine_server_call( req
);
1702 *self
= reply
->self
;
1703 context_handle
= wine_server_ptr_handle( reply
->handle
);
1704 count
= wine_server_reply_size( reply
) / sizeof(server_contexts
[0]);
1708 if (ret
== STATUS_PENDING
)
1710 NtWaitForSingleObject( context_handle
, FALSE
, NULL
);
1712 SERVER_START_REQ( get_thread_context
)
1714 req
->context
= wine_server_obj_handle( context_handle
);
1716 req
->machine
= machine
;
1717 wine_server_set_reply( req
, server_contexts
, sizeof(server_contexts
) );
1718 ret
= wine_server_call( req
);
1719 count
= wine_server_reply_size( reply
) / sizeof(server_contexts
[0]);
1725 ret
= context_from_server( context
, &server_contexts
[0], machine
);
1726 if (!ret
&& count
> 1) ret
= context_from_server( context
, &server_contexts
[1], machine
);
1732 /***********************************************************************
1733 * ntdll_set_exception_jmp_buf
1735 void ntdll_set_exception_jmp_buf( __wine_jmp_buf
*jmp
)
1737 assert( !jmp
|| !ntdll_get_thread_data()->jmp_buf );
1738 ntdll_get_thread_data()->jmp_buf = jmp
;
1742 BOOL
get_thread_times(int unix_pid
, int unix_tid
, LARGE_INTEGER
*kernel_time
, LARGE_INTEGER
*user_time
)
1745 unsigned long clocks_per_sec
= sysconf( _SC_CLK_TCK
);
1746 unsigned long usr
, sys
;
1753 sprintf( buf
, "/proc/%u/stat", unix_pid
);
1755 sprintf( buf
, "/proc/%u/task/%u/stat", unix_pid
, unix_tid
);
1756 if (!(f
= fopen( buf
, "r" )))
1758 WARN("Failed to open %s: %s\n", buf
, strerror(errno
));
1762 pos
= fgets( buf
, sizeof(buf
), f
);
1765 /* the process name is printed unescaped, so we have to skip to the last ')'
1766 * to avoid misinterpreting the string */
1767 if (pos
) pos
= strrchr( pos
, ')' );
1768 if (pos
) pos
= strchr( pos
+ 1, ' ' );
1771 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
1772 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
1773 for (i
= 0; i
< 11 && pos
; i
++)
1775 pos
= strchr( pos
+ 1, ' ' );
1779 /* the next two values are user and system time */
1780 if (pos
&& (sscanf( pos
, "%lu %lu", &usr
, &sys
) == 2))
1782 kernel_time
->QuadPart
= (ULONGLONG
)sys
* 10000000 / clocks_per_sec
;
1783 user_time
->QuadPart
= (ULONGLONG
)usr
* 10000000 / clocks_per_sec
;
1787 ERR("Failed to parse %s\n", debugstr_a(buf
));
1789 #elif defined(HAVE_LIBPROCSTAT)
1790 struct procstat
*pstat
;
1791 struct kinfo_proc
*kip
;
1792 unsigned int proc_count
;
1795 pstat
= procstat_open_sysctl();
1799 kip
= procstat_getprocs(pstat
, KERN_PROC_PID
, unix_pid
, &proc_count
);
1801 kip
= procstat_getprocs(pstat
, KERN_PROC_PID
| KERN_PROC_INC_THREAD
, unix_pid
, &proc_count
);
1805 for (i
= 0; i
< proc_count
; i
++)
1807 if (unix_tid
== -1 || kip
[i
].ki_tid
== unix_tid
)
1809 kernel_time
->QuadPart
= 10000000 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_stime
.tv_sec
+
1810 10 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_stime
.tv_usec
;
1811 user_time
->QuadPart
= 10000000 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_utime
.tv_sec
+
1812 10 * (ULONGLONG
)kip
[i
].ki_rusage
.ru_utime
.tv_usec
;
1817 procstat_freeprocs(pstat
, kip
);
1819 procstat_close(pstat
);
1823 if (!once
++) FIXME("not implemented on this platform\n");
1829 static BOOL
is_process_wow64( const CLIENT_ID
*id
)
1835 if (id
->UniqueProcess
== ULongToHandle(GetCurrentProcessId())) return is_wow64
;
1836 if (!NtOpenProcess( &handle
, PROCESS_QUERY_LIMITED_INFORMATION
, NULL
, id
))
1838 if (!NtQueryInformationProcess( handle
, ProcessWow64Information
, &info
, sizeof(info
), NULL
))
1846 /******************************************************************************
1847 * NtQueryInformationThread (NTDLL.@)
1849 NTSTATUS WINAPI
NtQueryInformationThread( HANDLE handle
, THREADINFOCLASS
class,
1850 void *data
, ULONG length
, ULONG
*ret_len
)
1854 TRACE("(%p,%d,%p,%x,%p)\n", handle
, class, data
, length
, ret_len
);
1858 case ThreadBasicInformation
:
1860 THREAD_BASIC_INFORMATION info
;
1861 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1863 SERVER_START_REQ( get_thread_info
)
1865 req
->handle
= wine_server_obj_handle( handle
);
1866 if (!(status
= wine_server_call( req
)))
1868 info
.ExitStatus
= reply
->exit_code
;
1869 info
.TebBaseAddress
= wine_server_get_ptr( reply
->teb
);
1870 info
.ClientId
.UniqueProcess
= ULongToHandle(reply
->pid
);
1871 info
.ClientId
.UniqueThread
= ULongToHandle(reply
->tid
);
1872 info
.AffinityMask
= reply
->affinity
& affinity_mask
;
1873 info
.Priority
= reply
->priority
;
1874 info
.BasePriority
= reply
->priority
; /* FIXME */
1878 if (status
== STATUS_SUCCESS
)
1883 if (is_process_wow64( &info
.ClientId
))
1884 info
.TebBaseAddress
= (char *)info
.TebBaseAddress
+ teb_offset
;
1886 info
.TebBaseAddress
= NULL
;
1889 if (data
) memcpy( data
, &info
, min( length
, sizeof(info
) ));
1890 if (ret_len
) *ret_len
= min( length
, sizeof(info
) );
1895 case ThreadAffinityMask
:
1897 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1898 ULONG_PTR affinity
= 0;
1900 SERVER_START_REQ( get_thread_info
)
1902 req
->handle
= wine_server_obj_handle( handle
);
1903 req
->access
= THREAD_QUERY_INFORMATION
;
1904 if (!(status
= wine_server_call( req
))) affinity
= reply
->affinity
& affinity_mask
;
1907 if (status
== STATUS_SUCCESS
)
1909 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
1910 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
1917 KERNEL_USER_TIMES kusrt
;
1918 int unix_pid
, unix_tid
;
1920 SERVER_START_REQ( get_thread_times
)
1922 req
->handle
= wine_server_obj_handle( handle
);
1923 status
= wine_server_call( req
);
1924 if (status
== STATUS_SUCCESS
)
1926 kusrt
.CreateTime
.QuadPart
= reply
->creation_time
;
1927 kusrt
.ExitTime
.QuadPart
= reply
->exit_time
;
1928 unix_pid
= reply
->unix_pid
;
1929 unix_tid
= reply
->unix_tid
;
1933 if (status
== STATUS_SUCCESS
)
1937 kusrt
.KernelTime
.QuadPart
= kusrt
.UserTime
.QuadPart
= 0;
1938 if (unix_pid
!= -1 && unix_tid
!= -1)
1939 ret
= get_thread_times( unix_pid
, unix_tid
, &kusrt
.KernelTime
, &kusrt
.UserTime
);
1940 if (!ret
&& handle
== GetCurrentThread())
1942 /* fall back to process times */
1943 struct tms time_buf
;
1944 long clocks_per_sec
= sysconf(_SC_CLK_TCK
);
1947 kusrt
.KernelTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_stime
* 10000000 / clocks_per_sec
;
1948 kusrt
.UserTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_utime
* 10000000 / clocks_per_sec
;
1950 if (data
) memcpy( data
, &kusrt
, min( length
, sizeof(kusrt
) ));
1951 if (ret_len
) *ret_len
= min( length
, sizeof(kusrt
) );
1956 case ThreadDescriptorTableEntry
:
1957 return get_thread_ldt_entry( handle
, data
, length
, ret_len
);
1959 case ThreadAmILastThread
:
1961 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
1962 SERVER_START_REQ( get_thread_info
)
1964 req
->handle
= wine_server_obj_handle( handle
);
1965 status
= wine_server_call( req
);
1966 if (status
== STATUS_SUCCESS
)
1968 ULONG last
= reply
->last
;
1969 if (data
) memcpy( data
, &last
, sizeof(last
) );
1970 if (ret_len
) *ret_len
= sizeof(last
);
1977 case ThreadQuerySetWin32StartAddress
:
1979 SERVER_START_REQ( get_thread_info
)
1981 req
->handle
= wine_server_obj_handle( handle
);
1982 req
->access
= THREAD_QUERY_INFORMATION
;
1983 status
= wine_server_call( req
);
1984 if (status
== STATUS_SUCCESS
)
1986 PRTL_THREAD_START_ROUTINE entry
= wine_server_get_ptr( reply
->entry_point
);
1987 if (data
) memcpy( data
, &entry
, min( length
, sizeof(entry
) ) );
1988 if (ret_len
) *ret_len
= min( length
, sizeof(entry
) );
1995 case ThreadGroupInformation
:
1997 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1998 GROUP_AFFINITY affinity
;
2000 memset( &affinity
, 0, sizeof(affinity
) );
2001 affinity
.Group
= 0; /* Wine only supports max 64 processors */
2003 SERVER_START_REQ( get_thread_info
)
2005 req
->handle
= wine_server_obj_handle( handle
);
2006 if (!(status
= wine_server_call( req
))) affinity
.Mask
= reply
->affinity
& affinity_mask
;
2009 if (status
== STATUS_SUCCESS
)
2011 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
2012 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
2017 case ThreadIsIoPending
:
2018 FIXME( "ThreadIsIoPending info class not supported yet\n" );
2019 if (length
!= sizeof(BOOL
)) return STATUS_INFO_LENGTH_MISMATCH
;
2020 if (!data
) return STATUS_ACCESS_DENIED
;
2021 *(BOOL
*)data
= FALSE
;
2022 if (ret_len
) *ret_len
= sizeof(BOOL
);
2023 return STATUS_SUCCESS
;
2025 case ThreadSuspendCount
:
2026 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
2027 if (!data
) return STATUS_ACCESS_VIOLATION
;
2029 SERVER_START_REQ( get_thread_info
)
2031 req
->handle
= wine_server_obj_handle( handle
);
2032 if (!(status
= wine_server_call( req
))) *(ULONG
*)data
= reply
->suspend_count
;
2037 case ThreadNameInformation
:
2039 THREAD_NAME_INFORMATION
*info
= data
;
2040 data_size_t len
, desc_len
= 0;
2043 len
= length
>= sizeof(*info
) ? length
- sizeof(*info
) : 0;
2044 ptr
= info
? (WCHAR
*)(info
+ 1) : NULL
;
2046 SERVER_START_REQ( get_thread_info
)
2048 req
->handle
= wine_server_obj_handle( handle
);
2049 if (ptr
) wine_server_set_reply( req
, ptr
, len
);
2050 status
= wine_server_call( req
);
2051 desc_len
= reply
->desc_len
;
2055 if (!info
) status
= STATUS_BUFFER_TOO_SMALL
;
2056 else if (status
== STATUS_SUCCESS
)
2058 info
->ThreadName
.Length
= info
->ThreadName
.MaximumLength
= desc_len
;
2059 info
->ThreadName
.Buffer
= ptr
;
2062 if (ret_len
&& (status
== STATUS_SUCCESS
|| status
== STATUS_BUFFER_TOO_SMALL
))
2063 *ret_len
= sizeof(*info
) + desc_len
;
2067 case ThreadWow64Context
:
2068 return get_thread_wow64_context( handle
, data
, length
);
2070 case ThreadHideFromDebugger
:
2071 if (length
!= sizeof(BOOLEAN
)) return STATUS_INFO_LENGTH_MISMATCH
;
2072 if (!data
) return STATUS_ACCESS_VIOLATION
;
2073 SERVER_START_REQ( get_thread_info
)
2075 req
->handle
= wine_server_obj_handle( handle
);
2076 req
->access
= THREAD_QUERY_INFORMATION
;
2077 if ((status
= wine_server_call( req
))) return status
;
2078 *(BOOLEAN
*)data
= reply
->dbg_hidden
;
2081 if (ret_len
) *ret_len
= sizeof(BOOLEAN
);
2082 return STATUS_SUCCESS
;
2084 case ThreadEnableAlignmentFaultFixup
:
2085 return STATUS_INVALID_INFO_CLASS
;
2087 case ThreadPriority
:
2088 case ThreadBasePriority
:
2089 case ThreadImpersonationToken
:
2090 case ThreadEventPair_Reusable
:
2091 case ThreadZeroTlsCell
:
2092 case ThreadPerformanceCount
:
2093 case ThreadIdealProcessor
:
2094 case ThreadPriorityBoost
:
2095 case ThreadSetTlsArrayAddress
:
2097 FIXME( "info class %d not supported yet\n", class );
2098 return STATUS_NOT_IMPLEMENTED
;
2103 /******************************************************************************
2104 * NtSetInformationThread (NTDLL.@)
2106 NTSTATUS WINAPI
NtSetInformationThread( HANDLE handle
, THREADINFOCLASS
class,
2107 const void *data
, ULONG length
)
2111 TRACE("(%p,%d,%p,%x)\n", handle
, class, data
, length
);
2115 case ThreadZeroTlsCell
:
2116 if (handle
== GetCurrentThread())
2118 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
2119 return virtual_clear_tls_index( *(const ULONG
*)data
);
2121 FIXME( "ZeroTlsCell not supported on other threads\n" );
2122 return STATUS_NOT_IMPLEMENTED
;
2124 case ThreadImpersonationToken
:
2126 const HANDLE
*token
= data
;
2128 if (length
!= sizeof(HANDLE
)) return STATUS_INVALID_PARAMETER
;
2129 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token
);
2130 SERVER_START_REQ( set_thread_info
)
2132 req
->handle
= wine_server_obj_handle( handle
);
2133 req
->token
= wine_server_obj_handle( *token
);
2134 req
->mask
= SET_THREAD_INFO_TOKEN
;
2135 status
= wine_server_call( req
);
2141 case ThreadBasePriority
:
2143 const DWORD
*pprio
= data
;
2144 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
2145 SERVER_START_REQ( set_thread_info
)
2147 req
->handle
= wine_server_obj_handle( handle
);
2148 req
->priority
= *pprio
;
2149 req
->mask
= SET_THREAD_INFO_PRIORITY
;
2150 status
= wine_server_call( req
);
2156 case ThreadAffinityMask
:
2158 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2161 if (length
!= sizeof(ULONG_PTR
)) return STATUS_INVALID_PARAMETER
;
2162 req_aff
= *(const ULONG_PTR
*)data
& affinity_mask
;
2163 if (!req_aff
) return STATUS_INVALID_PARAMETER
;
2165 SERVER_START_REQ( set_thread_info
)
2167 req
->handle
= wine_server_obj_handle( handle
);
2168 req
->affinity
= req_aff
;
2169 req
->mask
= SET_THREAD_INFO_AFFINITY
;
2170 status
= wine_server_call( req
);
2176 case ThreadHideFromDebugger
:
2177 if (length
) return STATUS_INFO_LENGTH_MISMATCH
;
2178 SERVER_START_REQ( set_thread_info
)
2180 req
->handle
= wine_server_obj_handle( handle
);
2181 req
->mask
= SET_THREAD_INFO_DBG_HIDDEN
;
2182 status
= wine_server_call( req
);
2187 case ThreadQuerySetWin32StartAddress
:
2189 const PRTL_THREAD_START_ROUTINE
*entry
= data
;
2190 if (length
!= sizeof(PRTL_THREAD_START_ROUTINE
)) return STATUS_INVALID_PARAMETER
;
2191 SERVER_START_REQ( set_thread_info
)
2193 req
->handle
= wine_server_obj_handle( handle
);
2194 req
->mask
= SET_THREAD_INFO_ENTRYPOINT
;
2195 req
->entry_point
= wine_server_client_ptr( *entry
);
2196 status
= wine_server_call( req
);
2202 case ThreadGroupInformation
:
2204 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
2205 const GROUP_AFFINITY
*req_aff
;
2207 if (length
!= sizeof(*req_aff
)) return STATUS_INVALID_PARAMETER
;
2208 if (!data
) return STATUS_ACCESS_VIOLATION
;
2211 /* On Windows the request fails if the reserved fields are set */
2212 if (req_aff
->Reserved
[0] || req_aff
->Reserved
[1] || req_aff
->Reserved
[2])
2213 return STATUS_INVALID_PARAMETER
;
2215 /* Wine only supports max 64 processors */
2216 if (req_aff
->Group
) return STATUS_INVALID_PARAMETER
;
2217 if (req_aff
->Mask
& ~affinity_mask
) return STATUS_INVALID_PARAMETER
;
2218 if (!req_aff
->Mask
) return STATUS_INVALID_PARAMETER
;
2219 SERVER_START_REQ( set_thread_info
)
2221 req
->handle
= wine_server_obj_handle( handle
);
2222 req
->affinity
= req_aff
->Mask
;
2223 req
->mask
= SET_THREAD_INFO_AFFINITY
;
2224 status
= wine_server_call( req
);
2230 case ThreadNameInformation
:
2232 const THREAD_NAME_INFORMATION
*info
= data
;
2234 if (length
!= sizeof(*info
)) return STATUS_INFO_LENGTH_MISMATCH
;
2235 if (!info
) return STATUS_ACCESS_VIOLATION
;
2236 if (info
->ThreadName
.Length
&& !info
->ThreadName
.Buffer
) return STATUS_ACCESS_VIOLATION
;
2238 SERVER_START_REQ( set_thread_info
)
2240 req
->handle
= wine_server_obj_handle( handle
);
2241 req
->mask
= SET_THREAD_INFO_DESCRIPTION
;
2242 wine_server_add_data( req
, info
->ThreadName
.Buffer
, info
->ThreadName
.Length
);
2243 status
= wine_server_call( req
);
2249 case ThreadWow64Context
:
2250 return set_thread_wow64_context( handle
, data
, length
);
2252 case ThreadEnableAlignmentFaultFixup
:
2253 if (length
!= sizeof(BOOLEAN
)) return STATUS_INFO_LENGTH_MISMATCH
;
2254 if (!data
) return STATUS_ACCESS_VIOLATION
;
2255 FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" );
2256 return STATUS_SUCCESS
;
2258 case ThreadBasicInformation
:
2260 case ThreadPriority
:
2261 case ThreadDescriptorTableEntry
:
2262 case ThreadEventPair_Reusable
:
2263 case ThreadPerformanceCount
:
2264 case ThreadAmILastThread
:
2265 case ThreadIdealProcessor
:
2266 case ThreadPriorityBoost
:
2267 case ThreadSetTlsArrayAddress
:
2268 case ThreadIsIoPending
:
2270 FIXME( "info class %d not supported yet\n", class );
2271 return STATUS_NOT_IMPLEMENTED
;
2276 /******************************************************************************
2277 * NtGetCurrentProcessorNumber (NTDLL.@)
2279 ULONG WINAPI
NtGetCurrentProcessorNumber(void)
2283 #if defined(__linux__) && defined(__NR_getcpu)
2284 int res
= syscall(__NR_getcpu
, &processor
, NULL
, NULL
);
2285 if (res
!= -1) return processor
;
2288 if (peb
->NumberOfProcessors
> 1)
2290 ULONG_PTR thread_mask
, processor_mask
;
2292 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask
,
2293 &thread_mask
, sizeof(thread_mask
), NULL
))
2295 for (processor
= 0; processor
< peb
->NumberOfProcessors
; processor
++)
2297 processor_mask
= (1 << processor
);
2298 if (thread_mask
& processor_mask
)
2300 if (thread_mask
!= processor_mask
)
2301 FIXME( "need multicore support (%d processors)\n",
2302 peb
->NumberOfProcessors
);
2308 /* fallback to the first processor */
2313 /******************************************************************************
2314 * NtGetNextThread (NTDLL.@)
2316 NTSTATUS WINAPI
NtGetNextThread( HANDLE process
, HANDLE thread
, ACCESS_MASK access
, ULONG attributes
,
2317 ULONG flags
, HANDLE
*handle
)
2319 HANDLE ret_handle
= 0;
2322 TRACE( "process %p, thread %p, access %#x, attributes %#x, flags %#x, handle %p.\n",
2323 process
, thread
, access
, attributes
, flags
, handle
);
2325 SERVER_START_REQ( get_next_thread
)
2327 req
->process
= wine_server_obj_handle( process
);
2328 req
->last
= wine_server_obj_handle( thread
);
2329 req
->access
= access
;
2330 req
->attributes
= attributes
;
2332 if (!(ret
= wine_server_call( req
))) ret_handle
= wine_server_ptr_handle( reply
->handle
);
2336 *handle
= ret_handle
;