4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018, 2020 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
40 #ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
43 #ifdef HAVE_SYS_TIMES_H
44 # include <sys/times.h>
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
53 #ifdef HAVE_MACH_MACH_H
54 # include <mach/mach.h>
58 #define WIN32_NO_STATUS
62 #include "unix_private.h"
63 #include "wine/condrv.h"
64 #include "wine/exception.h"
65 #include "wine/server.h"
66 #include "wine/debug.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(process
);
71 static ULONG execute_flags
= MEM_EXECUTE_OPTION_DISABLE
| (sizeof(void *) > sizeof(int) ?
72 MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
|
73 MEM_EXECUTE_OPTION_PERMANENT
: 0);
75 static UINT process_error_mode
;
77 static char **build_argv( const UNICODE_STRING
*cmdline
, int reserved
)
79 char **argv
, *arg
, *src
, *dst
;
80 int argc
, in_quotes
= 0, bcount
= 0, len
= cmdline
->Length
/ sizeof(WCHAR
);
82 if (!(src
= malloc( len
* 3 + 1 ))) return NULL
;
83 len
= ntdll_wcstoumbs( cmdline
->Buffer
, len
, src
, len
* 3, FALSE
);
86 argc
= reserved
+ 2 + len
/ 2;
87 argv
= malloc( argc
* sizeof(*argv
) + len
);
88 arg
= dst
= (char *)(argv
+ argc
);
92 if ((*src
== ' ' || *src
== '\t') && !in_quotes
)
94 /* skip the remaining spaces */
95 while (*src
== ' ' || *src
== '\t') src
++;
97 /* close the argument and copy it */
100 /* start with a new argument */
104 else if (*src
== '\\')
109 else if (*src
== '"')
111 if ((bcount
& 1) == 0)
113 /* Preceded by an even number of '\', this is half that
114 * number of '\', plus a '"' which we discard.
118 if (in_quotes
&& *src
== '"') *dst
++ = *src
++;
119 else in_quotes
= !in_quotes
;
123 /* Preceded by an odd number of '\', this is half that
124 * number of '\' followed by a '"'
126 dst
-= bcount
/ 2 + 1;
131 else /* a regular character */
144 /***********************************************************************
147 static BOOL
get_so_file_info( int fd
, pe_image_info_t
*info
)
153 unsigned char magic
[4];
156 unsigned char version
;
157 unsigned char ignored1
[9];
159 unsigned short machine
;
160 unsigned char ignored2
[8];
162 unsigned char ignored3
[12];
163 unsigned short phnum
;
167 unsigned char magic
[4];
170 unsigned char ignored1
[10];
172 unsigned short machine
;
173 unsigned char ignored2
[12];
174 unsigned __int64 phoff
;
175 unsigned char ignored3
[16];
176 unsigned short phnum
;
181 unsigned int cputype
;
182 unsigned int cpusubtype
;
183 unsigned int filetype
;
190 if (pread( fd
, &header
, sizeof(header
), 0 ) != sizeof(header
)) return FALSE
;
192 if (!memcmp( header
.elf
.magic
, "\177ELF", 4 ))
195 unsigned short phnum
;
197 if (header
.elf
.version
!= 1 /* EV_CURRENT */) return FALSE
;
198 #ifdef WORDS_BIGENDIAN
199 if (header
.elf
.data
!= 2 /* ELFDATA2MSB */) return FALSE
;
201 if (header
.elf
.data
!= 1 /* ELFDATA2LSB */) return FALSE
;
203 switch (header
.elf
.machine
)
205 case 3: info
->machine
= IMAGE_FILE_MACHINE_I386
; break;
206 case 40: info
->machine
= IMAGE_FILE_MACHINE_ARMNT
; break;
207 case 62: info
->machine
= IMAGE_FILE_MACHINE_AMD64
; break;
208 case 183: info
->machine
= IMAGE_FILE_MACHINE_ARM64
; break;
210 if (header
.elf
.type
!= 3 /* ET_DYN */) return FALSE
;
211 if (header
.elf
.class == 2 /* ELFCLASS64 */)
213 pos
= header
.elf64
.phoff
;
214 phnum
= header
.elf64
.phnum
;
218 pos
= header
.elf
.phoff
;
219 phnum
= header
.elf
.phnum
;
223 if (pread( fd
, &type
, sizeof(type
), pos
) != sizeof(type
)) return FALSE
;
224 if (type
== 3 /* PT_INTERP */) return FALSE
;
225 pos
+= (header
.elf
.class == 2) ? 56 : 32;
229 else if (header
.macho
.magic
== 0xfeedface || header
.macho
.magic
== 0xfeedfacf)
231 switch (header
.macho
.cputype
)
233 case 0x00000007: info
->machine
= IMAGE_FILE_MACHINE_I386
; break;
234 case 0x01000007: info
->machine
= IMAGE_FILE_MACHINE_AMD64
; break;
235 case 0x0000000c: info
->machine
= IMAGE_FILE_MACHINE_ARMNT
; break;
236 case 0x0100000c: info
->machine
= IMAGE_FILE_MACHINE_ARM64
; break;
238 if (header
.macho
.filetype
== 8) return TRUE
;
244 /***********************************************************************
247 static NTSTATUS
get_pe_file_info( OBJECT_ATTRIBUTES
*attr
, HANDLE
*handle
, pe_image_info_t
*info
)
254 memset( info
, 0, sizeof(*info
) );
255 if (!(status
= nt_to_unix_file_name( attr
, &unix_name
, FILE_OPEN
)))
257 status
= open_unix_file( handle
, unix_name
, GENERIC_READ
, attr
, 0,
258 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
259 FILE_OPEN
, FILE_SYNCHRONOUS_IO_NONALERT
, NULL
, 0 );
264 if (is_builtin_path( attr
->ObjectName
, &info
->machine
))
266 TRACE( "assuming %04x builtin for %s\n", info
->machine
, debugstr_us(attr
->ObjectName
));
267 return STATUS_SUCCESS
;
272 if (!(status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
273 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
274 NULL
, NULL
, PAGE_EXECUTE_READ
, SEC_IMAGE
, *handle
)))
276 SERVER_START_REQ( get_mapping_info
)
278 req
->handle
= wine_server_obj_handle( mapping
);
279 req
->access
= SECTION_QUERY
;
280 wine_server_set_reply( req
, info
, sizeof(*info
) );
281 status
= wine_server_call( req
);
285 if (info
->image_charact
& IMAGE_FILE_DLL
) return STATUS_INVALID_IMAGE_FORMAT
;
287 else if (status
== STATUS_INVALID_IMAGE_NOT_MZ
)
289 int unix_fd
, needs_close
;
291 if (!server_get_unix_fd( *handle
, FILE_READ_DATA
, &unix_fd
, &needs_close
, NULL
, NULL
))
293 if (get_so_file_info( unix_fd
, info
)) status
= STATUS_SUCCESS
;
294 if (needs_close
) close( unix_fd
);
301 /***********************************************************************
304 static ULONG
get_env_size( const RTL_USER_PROCESS_PARAMETERS
*params
, char **winedebug
)
306 WCHAR
*ptr
= params
->Environment
;
310 static const WCHAR WINEDEBUG
[] = {'W','I','N','E','D','E','B','U','G','=',0};
311 if (!*winedebug
&& !wcsncmp( ptr
, WINEDEBUG
, ARRAY_SIZE( WINEDEBUG
) - 1 ))
313 DWORD len
= wcslen(ptr
) * 3 + 1;
314 if ((*winedebug
= malloc( len
)))
315 ntdll_wcstoumbs( ptr
, wcslen(ptr
) + 1, *winedebug
, len
, FALSE
);
317 ptr
+= wcslen(ptr
) + 1;
320 return (ptr
- params
->Environment
) * sizeof(WCHAR
);
324 /***********************************************************************
327 * Simplified version of RtlDosPathNameToNtPathName_U.
329 static WCHAR
*get_nt_pathname( const UNICODE_STRING
*str
)
331 static const WCHAR ntprefixW
[] = {'\\','?','?','\\',0};
332 static const WCHAR uncprefixW
[] = {'U','N','C','\\',0};
333 const WCHAR
*name
= str
->Buffer
;
336 if (!(ret
= malloc( str
->Length
+ 8 * sizeof(WCHAR
) ))) return NULL
;
338 wcscpy( ret
, ntprefixW
);
339 if (name
[0] == '\\' && name
[1] == '\\')
341 if ((name
[2] == '.' || name
[2] == '?') && name
[3] == '\\') name
+= 4;
344 wcscat( ret
, uncprefixW
);
353 /***********************************************************************
356 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS
*params
)
358 UNICODE_STRING nt_name
, redir
;
359 OBJECT_ATTRIBUTES attr
;
365 if (!(nt_name
.Buffer
= get_nt_pathname( ¶ms
->CurrentDirectory
.DosPath
))) return -1;
366 nt_name
.Length
= wcslen( nt_name
.Buffer
) * sizeof(WCHAR
);
368 InitializeObjectAttributes( &attr
, &nt_name
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
369 get_redirect( &attr
, &redir
);
370 status
= nt_to_unix_file_name( &attr
, &unix_name
, FILE_OPEN
);
371 if (status
) goto done
;
372 status
= open_unix_file( &handle
, unix_name
, FILE_TRAVERSE
| SYNCHRONIZE
, &attr
, 0,
373 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
374 FILE_OPEN
, FILE_SYNCHRONOUS_IO_NONALERT
, NULL
, 0 );
376 if (status
) goto done
;
377 wine_server_handle_to_fd( handle
, FILE_TRAVERSE
, &fd
, NULL
);
381 free( nt_name
.Buffer
);
382 free( redir
.Buffer
);
387 /***********************************************************************
390 static void set_stdio_fd( int stdin_fd
, int stdout_fd
)
394 if (stdin_fd
== -1 || stdout_fd
== -1)
396 fd
= open( "/dev/null", O_RDWR
);
397 if (stdin_fd
== -1) stdin_fd
= fd
;
398 if (stdout_fd
== -1) stdout_fd
= fd
;
401 if (stdin_fd
!= 0) dup2( stdin_fd
, 0 );
402 if (stdout_fd
!= 1) dup2( stdout_fd
, 1 );
403 if (fd
!= -1) close( fd
);
407 /***********************************************************************
408 * is_unix_console_handle
410 static BOOL
is_unix_console_handle( HANDLE handle
)
412 IO_STATUS_BLOCK io
= {0};
413 return !NtDeviceIoControlFile( handle
, NULL
, NULL
, NULL
, &io
, IOCTL_CONDRV_IS_UNIX
,
418 /***********************************************************************
421 static NTSTATUS
spawn_process( const RTL_USER_PROCESS_PARAMETERS
*params
, int socketfd
,
422 int unixdir
, char *winedebug
, const pe_image_info_t
*pe_info
)
424 NTSTATUS status
= STATUS_SUCCESS
;
425 int stdin_fd
= -1, stdout_fd
= -1;
429 if (wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
) &&
430 isatty(0) && is_unix_console_handle( params
->hStdInput
))
433 if (wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
) &&
434 isatty(1) && is_unix_console_handle( params
->hStdOutput
))
437 if (!(pid
= fork())) /* child */
439 if (!(pid
= fork())) /* grandchild */
441 if (params
->ConsoleFlags
||
442 params
->ConsoleHandle
== (HANDLE
)1 /* KERNEL32_CONSOLE_ALLOC */ ||
443 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
446 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
448 else set_stdio_fd( stdin_fd
, stdout_fd
);
450 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
451 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
453 if (winedebug
) putenv( winedebug
);
459 argv
= build_argv( ¶ms
->CommandLine
, 2 );
461 exec_wineloader( argv
, socketfd
, pe_info
);
473 wret
= waitpid(pid
, NULL
, 0);
474 } while (wret
< 0 && errno
== EINTR
);
476 else status
= STATUS_NO_MEMORY
;
478 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
479 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
484 /***********************************************************************
487 * Fork and exec a new Unix binary, checking for errors.
489 static NTSTATUS
fork_and_exec( OBJECT_ATTRIBUTES
*attr
, int unixdir
,
490 const RTL_USER_PROCESS_PARAMETERS
*params
)
493 int fd
[2], stdin_fd
= -1, stdout_fd
= -1;
498 status
= nt_to_unix_file_name( attr
, &unix_name
, FILE_OPEN
);
499 if (status
) return status
;
502 if (pipe2( fd
, O_CLOEXEC
) == -1)
507 status
= STATUS_TOO_MANY_OPENED_FILES
;
510 fcntl( fd
[0], F_SETFD
, FD_CLOEXEC
);
511 fcntl( fd
[1], F_SETFD
, FD_CLOEXEC
);
514 if (wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
) &&
515 isatty(0) && is_unix_console_handle( params
->hStdInput
))
518 if (wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
) &&
519 isatty(1) && is_unix_console_handle( params
->hStdOutput
))
522 if (!(pid
= fork())) /* child */
524 if (!(pid
= fork())) /* grandchild */
528 if (params
->ConsoleFlags
||
529 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC
||
530 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
533 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
535 else set_stdio_fd( stdin_fd
, stdout_fd
);
537 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
538 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
540 /* Reset signals that we previously set to SIG_IGN */
541 signal( SIGPIPE
, SIG_DFL
);
543 argv
= build_argv( ¶ms
->CommandLine
, 0 );
544 envp
= build_envp( params
->Environment
);
550 execve( unix_name
, argv
, envp
);
553 if (pid
<= 0) /* grandchild if exec failed or child if fork failed */
558 case EACCES
: status
= STATUS_ACCESS_DENIED
; break;
559 case ENOENT
: status
= STATUS_OBJECT_NAME_NOT_FOUND
; break;
561 case ENFILE
: status
= STATUS_TOO_MANY_OPENED_FILES
; break;
563 case EINVAL
: status
= STATUS_INVALID_IMAGE_FORMAT
; break;
564 default: status
= STATUS_NO_MEMORY
; break;
566 write( fd
[1], &status
, sizeof(status
) );
569 _exit(0); /* child if fork succeeded */
578 wret
= waitpid(pid
, NULL
, 0);
579 } while (wret
< 0 && errno
== EINTR
);
580 read( fd
[0], &status
, sizeof(status
) ); /* if we read something, exec or second fork failed */
582 else status
= STATUS_NO_MEMORY
;
585 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
586 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
592 static NTSTATUS
alloc_handle_list( const PS_ATTRIBUTE
*handles_attr
, obj_handle_t
**handles
, data_size_t
*handles_len
)
600 if (!handles_attr
) return STATUS_SUCCESS
;
602 count
= handles_attr
->Size
/ sizeof(HANDLE
);
604 if (!(*handles
= calloc( sizeof(**handles
), count
))) return STATUS_NO_MEMORY
;
606 src
= handles_attr
->ValuePtr
;
607 for (i
= 0; i
< count
; ++i
)
608 (*handles
)[i
] = wine_server_obj_handle( src
[i
] );
610 *handles_len
= count
* sizeof(**handles
);
612 return STATUS_SUCCESS
;
615 /**********************************************************************
616 * NtCreateUserProcess (NTDLL.@)
618 NTSTATUS WINAPI
NtCreateUserProcess( HANDLE
*process_handle_ptr
, HANDLE
*thread_handle_ptr
,
619 ACCESS_MASK process_access
, ACCESS_MASK thread_access
,
620 OBJECT_ATTRIBUTES
*process_attr
, OBJECT_ATTRIBUTES
*thread_attr
,
621 ULONG process_flags
, ULONG thread_flags
,
622 RTL_USER_PROCESS_PARAMETERS
*params
, PS_CREATE_INFO
*info
,
623 PS_ATTRIBUTE_LIST
*ps_attr
)
626 BOOL success
= FALSE
;
627 HANDLE file_handle
, process_info
= 0, process_handle
= 0, thread_handle
= 0;
628 struct object_attributes
*objattr
;
629 data_size_t attr_len
;
630 char *winedebug
= NULL
;
631 startup_info_t
*startup_info
= NULL
;
632 ULONG startup_info_size
, env_size
;
633 int unixdir
, socketfd
[2] = { -1, -1 };
634 pe_image_info_t pe_info
;
636 HANDLE parent
= 0, debug
= 0, token
= 0;
637 UNICODE_STRING redir
, path
= {0};
638 OBJECT_ATTRIBUTES attr
, empty_attr
= { sizeof(empty_attr
) };
639 SIZE_T i
, attr_count
= (ps_attr
->TotalLength
- sizeof(ps_attr
->TotalLength
)) / sizeof(PS_ATTRIBUTE
);
640 const PS_ATTRIBUTE
*handles_attr
= NULL
, *jobs_attr
= NULL
;
641 data_size_t handles_size
, jobs_size
;
642 obj_handle_t
*handles
, *jobs
;
644 for (i
= 0; i
< attr_count
; i
++)
646 switch (ps_attr
->Attributes
[i
].Attribute
)
648 case PS_ATTRIBUTE_PARENT_PROCESS
:
649 parent
= ps_attr
->Attributes
[i
].ValuePtr
;
651 case PS_ATTRIBUTE_DEBUG_PORT
:
652 debug
= ps_attr
->Attributes
[i
].ValuePtr
;
654 case PS_ATTRIBUTE_IMAGE_NAME
:
655 path
.Length
= ps_attr
->Attributes
[i
].Size
;
656 path
.Buffer
= ps_attr
->Attributes
[i
].ValuePtr
;
658 case PS_ATTRIBUTE_TOKEN
:
659 token
= ps_attr
->Attributes
[i
].ValuePtr
;
661 case PS_ATTRIBUTE_HANDLE_LIST
:
662 if (process_flags
& PROCESS_CREATE_FLAGS_INHERIT_HANDLES
)
663 handles_attr
= &ps_attr
->Attributes
[i
];
665 case PS_ATTRIBUTE_JOB_LIST
:
666 jobs_attr
= &ps_attr
->Attributes
[i
];
669 if (ps_attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
)
670 FIXME( "unhandled input attribute %lx\n", ps_attr
->Attributes
[i
].Attribute
);
674 if (!process_attr
) process_attr
= &empty_attr
;
676 TRACE( "%s image %s cmdline %s parent %p\n", debugstr_us( &path
),
677 debugstr_us( ¶ms
->ImagePathName
), debugstr_us( ¶ms
->CommandLine
), parent
);
679 unixdir
= get_unix_curdir( params
);
681 InitializeObjectAttributes( &attr
, &path
, OBJ_CASE_INSENSITIVE
, 0, 0 );
682 get_redirect( &attr
, &redir
);
684 if ((status
= get_pe_file_info( &attr
, &file_handle
, &pe_info
)))
686 if (status
== STATUS_INVALID_IMAGE_NOT_MZ
&& !fork_and_exec( &attr
, unixdir
, params
))
688 memset( info
, 0, sizeof(*info
) );
689 free( redir
.Buffer
);
690 return STATUS_SUCCESS
;
694 if (!(startup_info
= create_startup_info( attr
.ObjectName
, params
, &startup_info_size
))) goto done
;
695 env_size
= get_env_size( params
, &winedebug
);
697 if ((status
= alloc_object_attributes( process_attr
, &objattr
, &attr_len
))) goto done
;
699 if ((status
= alloc_handle_list( handles_attr
, &handles
, &handles_size
)))
705 if ((status
= alloc_handle_list( jobs_attr
, &jobs
, &jobs_size
)))
712 /* create the socket for the new process */
714 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1)
716 status
= STATUS_TOO_MANY_OPENED_FILES
;
726 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
730 wine_server_send_fd( socketfd
[1] );
731 close( socketfd
[1] );
733 /* create the process on the server side */
735 SERVER_START_REQ( new_process
)
737 req
->token
= wine_server_obj_handle( token
);
738 req
->debug
= wine_server_obj_handle( debug
);
739 req
->parent_process
= wine_server_obj_handle( parent
);
740 req
->flags
= process_flags
;
741 req
->socket_fd
= socketfd
[1];
742 req
->access
= process_access
;
743 req
->info_size
= startup_info_size
;
744 req
->handles_size
= handles_size
;
745 req
->jobs_size
= jobs_size
;
746 wine_server_add_data( req
, objattr
, attr_len
);
747 wine_server_add_data( req
, handles
, handles_size
);
748 wine_server_add_data( req
, jobs
, jobs_size
);
749 wine_server_add_data( req
, startup_info
, startup_info_size
);
750 wine_server_add_data( req
, params
->Environment
, env_size
);
751 if (!(status
= wine_server_call( req
)))
753 process_handle
= wine_server_ptr_handle( reply
->handle
);
754 id
.UniqueProcess
= ULongToHandle( reply
->pid
);
756 process_info
= wine_server_ptr_handle( reply
->info
);
767 case STATUS_INVALID_IMAGE_WIN_64
:
768 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path
) );
770 case STATUS_INVALID_IMAGE_FORMAT
:
771 ERR( "%s not supported on this installation (machine %04x)\n",
772 debugstr_us(&path
), pe_info
.machine
);
778 if ((status
= alloc_object_attributes( thread_attr
, &objattr
, &attr_len
))) goto done
;
780 SERVER_START_REQ( new_thread
)
782 req
->process
= wine_server_obj_handle( process_handle
);
783 req
->access
= thread_access
;
784 req
->suspend
= !!(thread_flags
& THREAD_CREATE_FLAGS_CREATE_SUSPENDED
);
785 req
->request_fd
= -1;
786 wine_server_add_data( req
, objattr
, attr_len
);
787 if (!(status
= wine_server_call( req
)))
789 thread_handle
= wine_server_ptr_handle( reply
->handle
);
790 id
.UniqueThread
= ULongToHandle( reply
->tid
);
795 if (status
) goto done
;
797 /* create the child process */
799 if ((status
= spawn_process( params
, socketfd
[0], unixdir
, winedebug
, &pe_info
))) goto done
;
801 close( socketfd
[0] );
804 /* wait for the new process info to be ready */
806 NtWaitForSingleObject( process_info
, FALSE
, NULL
);
807 SERVER_START_REQ( get_new_process_info
)
809 req
->info
= wine_server_obj_handle( process_info
);
810 wine_server_call( req
);
811 success
= reply
->success
;
812 status
= reply
->exit_code
;
818 if (!status
) status
= STATUS_INTERNAL_ERROR
;
822 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us(&path
),
823 HandleToULong(id
.UniqueProcess
), HandleToULong(id
.UniqueThread
),
824 process_handle
, thread_handle
);
826 /* update output attributes */
828 for (i
= 0; i
< attr_count
; i
++)
830 switch (ps_attr
->Attributes
[i
].Attribute
)
832 case PS_ATTRIBUTE_CLIENT_ID
:
834 SIZE_T size
= min( ps_attr
->Attributes
[i
].Size
, sizeof(id
) );
835 memcpy( ps_attr
->Attributes
[i
].ValuePtr
, &id
, size
);
836 if (ps_attr
->Attributes
[i
].ReturnLength
) *ps_attr
->Attributes
[i
].ReturnLength
= size
;
839 case PS_ATTRIBUTE_IMAGE_INFO
:
841 SECTION_IMAGE_INFORMATION info
;
842 SIZE_T size
= min( ps_attr
->Attributes
[i
].Size
, sizeof(info
) );
843 virtual_fill_image_information( &pe_info
, &info
);
844 memcpy( ps_attr
->Attributes
[i
].ValuePtr
, &info
, size
);
845 if (ps_attr
->Attributes
[i
].ReturnLength
) *ps_attr
->Attributes
[i
].ReturnLength
= size
;
848 case PS_ATTRIBUTE_TEB_ADDRESS
:
850 if (!(ps_attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
))
851 FIXME( "unhandled output attribute %lx\n", ps_attr
->Attributes
[i
].Attribute
);
855 *process_handle_ptr
= process_handle
;
856 *thread_handle_ptr
= thread_handle
;
857 process_handle
= thread_handle
= 0;
858 status
= STATUS_SUCCESS
;
861 if (file_handle
) NtClose( file_handle
);
862 if (process_info
) NtClose( process_info
);
863 if (process_handle
) NtClose( process_handle
);
864 if (thread_handle
) NtClose( thread_handle
);
865 if (socketfd
[0] != -1) close( socketfd
[0] );
866 if (unixdir
!= -1) close( unixdir
);
867 free( startup_info
);
869 free( redir
.Buffer
);
874 /******************************************************************************
875 * NtTerminateProcess (NTDLL.@)
877 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
882 SERVER_START_REQ( terminate_process
)
884 req
->handle
= wine_server_obj_handle( handle
);
885 req
->exit_code
= exit_code
;
886 ret
= wine_server_call( req
);
892 if (!handle
) process_exiting
= TRUE
;
893 else if (process_exiting
) exit_process( exit_code
);
894 else abort_process( exit_code
);
900 #if defined(HAVE_MACH_MACH_H)
902 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
904 #if defined(MACH_TASK_BASIC_INFO)
905 struct mach_task_basic_info info
;
906 mach_msg_type_number_t infoCount
;
908 if (unix_pid
!= -1) return; /* FIXME: Retrieve information for other processes. */
910 infoCount
= MACH_TASK_BASIC_INFO_COUNT
;
911 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO
, (task_info_t
)&info
, &infoCount
) == KERN_SUCCESS
)
913 pvmi
->VirtualSize
= info
.resident_size
+ info
.virtual_size
;
914 pvmi
->PagefileUsage
= info
.virtual_size
;
915 pvmi
->WorkingSetSize
= info
.resident_size
;
916 pvmi
->PeakWorkingSetSize
= info
.resident_size_max
;
923 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
926 char line
[256], path
[26];
930 strcpy( path
, "/proc/self/status" );
932 sprintf( path
, "/proc/%u/status", unix_pid
);
933 f
= fopen( path
, "r" );
936 while (fgets(line
, sizeof(line
), f
))
938 if (sscanf(line
, "VmPeak: %lu", &value
))
939 pvmi
->PeakVirtualSize
= (ULONG64
)value
* 1024;
940 else if (sscanf(line
, "VmSize: %lu", &value
))
941 pvmi
->VirtualSize
= (ULONG64
)value
* 1024;
942 else if (sscanf(line
, "VmHWM: %lu", &value
))
943 pvmi
->PeakWorkingSetSize
= (ULONG64
)value
* 1024;
944 else if (sscanf(line
, "VmRSS: %lu", &value
))
945 pvmi
->WorkingSetSize
= (ULONG64
)value
* 1024;
946 else if (sscanf(line
, "RssAnon: %lu", &value
))
947 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
948 else if (sscanf(line
, "VmSwap: %lu", &value
))
949 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
951 pvmi
->PeakPagefileUsage
= pvmi
->PagefileUsage
;
958 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
960 /* FIXME : real data */
965 #define UNIMPLEMENTED_INFO_CLASS(c) \
967 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
968 ret = STATUS_INVALID_INFO_CLASS; \
971 /**********************************************************************
972 * NtQueryInformationProcess (NTDLL.@)
974 NTSTATUS WINAPI
NtQueryInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
,
975 ULONG size
, ULONG
*ret_len
)
977 NTSTATUS ret
= STATUS_SUCCESS
;
980 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle
, class, info
, size
, ret_len
);
984 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits
);
985 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority
);
986 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority
);
987 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort
);
988 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken
);
989 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation
);
990 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize
);
991 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers
);
992 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits
);
993 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch
);
994 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL
);
995 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup
);
996 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information
);
997 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost
);
998 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap
);
999 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation
);
1000 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled
);
1001 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination
);
1002 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing
);
1004 case ProcessBasicInformation
:
1006 PROCESS_BASIC_INFORMATION pbi
;
1007 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1009 if (size
>= sizeof(PROCESS_BASIC_INFORMATION
))
1011 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1014 SERVER_START_REQ(get_process_info
)
1016 req
->handle
= wine_server_obj_handle( handle
);
1017 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1019 pbi
.ExitStatus
= reply
->exit_code
;
1020 pbi
.PebBaseAddress
= wine_server_get_ptr( reply
->peb
);
1021 pbi
.AffinityMask
= reply
->affinity
& affinity_mask
;
1022 pbi
.BasePriority
= reply
->priority
;
1023 pbi
.UniqueProcessId
= reply
->pid
;
1024 pbi
.InheritedFromUniqueProcessId
= reply
->ppid
;
1028 if (reply
->machine
!= native_machine
)
1029 pbi
.PebBaseAddress
= (PEB
*)((char *)pbi
.PebBaseAddress
+ 0x1000);
1031 pbi
.PebBaseAddress
= NULL
;
1038 memcpy( info
, &pbi
, sizeof(PROCESS_BASIC_INFORMATION
) );
1039 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1041 if (size
> sizeof(PROCESS_BASIC_INFORMATION
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1045 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1046 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1051 case ProcessIoCounters
:
1055 if (size
>= sizeof(IO_COUNTERS
))
1057 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1058 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1061 /* FIXME : real data */
1062 memset(&pii
, 0 , sizeof(IO_COUNTERS
));
1063 memcpy(info
, &pii
, sizeof(IO_COUNTERS
));
1064 len
= sizeof(IO_COUNTERS
);
1066 if (size
> sizeof(IO_COUNTERS
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1070 len
= sizeof(IO_COUNTERS
);
1071 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1076 case ProcessVmCounters
:
1078 VM_COUNTERS_EX pvmi
;
1080 /* older Windows versions don't have the PrivateUsage field */
1081 if (size
>= sizeof(VM_COUNTERS
))
1083 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1086 memset(&pvmi
, 0, sizeof(pvmi
));
1087 if (handle
== GetCurrentProcess()) fill_vm_counters( &pvmi
, -1 );
1090 SERVER_START_REQ(get_process_vm_counters
)
1092 req
->handle
= wine_server_obj_handle( handle
);
1093 if (!(ret
= wine_server_call( req
)))
1095 pvmi
.PeakVirtualSize
= reply
->peak_virtual_size
;
1096 pvmi
.VirtualSize
= reply
->virtual_size
;
1097 pvmi
.PeakWorkingSetSize
= reply
->peak_working_set_size
;
1098 pvmi
.WorkingSetSize
= reply
->working_set_size
;
1099 pvmi
.PagefileUsage
= reply
->pagefile_usage
;
1100 pvmi
.PeakPagefileUsage
= reply
->peak_pagefile_usage
;
1106 if (size
>= sizeof(VM_COUNTERS_EX
))
1107 pvmi
.PrivateUsage
= pvmi
.PagefileUsage
;
1109 if (len
!= sizeof(VM_COUNTERS
)) len
= sizeof(VM_COUNTERS_EX
);
1110 memcpy(info
, &pvmi
, min(size
, sizeof(pvmi
)));
1112 if (size
!= sizeof(VM_COUNTERS
) && size
!= sizeof(VM_COUNTERS_EX
))
1113 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1118 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1125 KERNEL_USER_TIMES pti
= {{{0}}};
1127 if (size
>= sizeof(KERNEL_USER_TIMES
))
1129 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1130 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1133 long ticks
= sysconf(_SC_CLK_TCK
);
1136 /* FIXME: user/kernel times only work for current process */
1137 if (ticks
&& times( &tms
) != -1)
1139 pti
.UserTime
.QuadPart
= (ULONGLONG
)tms
.tms_utime
* 10000000 / ticks
;
1140 pti
.KernelTime
.QuadPart
= (ULONGLONG
)tms
.tms_stime
* 10000000 / ticks
;
1143 SERVER_START_REQ(get_process_info
)
1145 req
->handle
= wine_server_obj_handle( handle
);
1146 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1148 pti
.CreateTime
.QuadPart
= reply
->start_time
;
1149 pti
.ExitTime
.QuadPart
= reply
->end_time
;
1154 memcpy(info
, &pti
, sizeof(KERNEL_USER_TIMES
));
1155 len
= sizeof(KERNEL_USER_TIMES
);
1157 if (size
> sizeof(KERNEL_USER_TIMES
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1161 len
= sizeof(KERNEL_USER_TIMES
);
1162 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1167 case ProcessDebugPort
:
1168 len
= sizeof(DWORD_PTR
);
1171 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1176 SERVER_START_REQ(get_process_debug_info
)
1178 req
->handle
= wine_server_obj_handle( handle
);
1179 ret
= wine_server_call( req
);
1180 debug
= wine_server_ptr_handle( reply
->debug
);
1183 if (ret
== STATUS_SUCCESS
)
1185 *(DWORD_PTR
*)info
= ~0ul;
1188 else if (ret
== STATUS_PORT_NOT_SET
)
1190 *(DWORD_PTR
*)info
= 0;
1191 ret
= STATUS_SUCCESS
;
1195 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1198 case ProcessDebugFlags
:
1199 len
= sizeof(DWORD
);
1202 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1207 SERVER_START_REQ(get_process_debug_info
)
1209 req
->handle
= wine_server_obj_handle( handle
);
1210 ret
= wine_server_call( req
);
1211 debug
= wine_server_ptr_handle( reply
->debug
);
1212 *(DWORD
*)info
= reply
->debug_children
;
1215 if (ret
== STATUS_SUCCESS
) NtClose( debug
);
1216 else if (ret
== STATUS_PORT_NOT_SET
) ret
= STATUS_SUCCESS
;
1219 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1222 case ProcessDefaultHardErrorMode
:
1223 len
= sizeof(process_error_mode
);
1224 if (size
== len
) memcpy(info
, &process_error_mode
, len
);
1225 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1228 case ProcessDebugObjectHandle
:
1229 len
= sizeof(HANDLE
);
1232 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1235 SERVER_START_REQ(get_process_debug_info
)
1237 req
->handle
= wine_server_obj_handle( handle
);
1238 ret
= wine_server_call( req
);
1239 *(HANDLE
*)info
= wine_server_ptr_handle( reply
->debug
);
1244 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1247 case ProcessHandleCount
:
1250 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1251 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1257 if (size
> 4) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1262 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1266 case ProcessAffinityMask
:
1267 len
= sizeof(ULONG_PTR
);
1270 const ULONG_PTR system_mask
= get_system_affinity_mask();
1272 SERVER_START_REQ(get_process_info
)
1274 req
->handle
= wine_server_obj_handle( handle
);
1275 if (!(ret
= wine_server_call( req
)))
1276 *(ULONG_PTR
*)info
= reply
->affinity
& system_mask
;
1280 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1283 case ProcessSessionInformation
:
1284 len
= sizeof(DWORD
);
1287 SERVER_START_REQ(get_process_info
)
1289 req
->handle
= wine_server_obj_handle( handle
);
1290 if (!(ret
= wine_server_call( req
)))
1291 *(DWORD
*)info
= reply
->session_id
;
1295 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1298 case ProcessWow64Information
:
1299 len
= sizeof(ULONG_PTR
);
1300 if (size
!= len
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1301 else if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1302 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1303 else if (handle
== GetCurrentProcess()) *(ULONG_PTR
*)info
= !!NtCurrentTeb()->WowTebOffset
;
1308 SERVER_START_REQ( get_process_info
)
1310 req
->handle
= wine_server_obj_handle( handle
);
1311 if (!(ret
= wine_server_call( req
))) val
= (reply
->machine
!= native_machine
);
1314 *(ULONG_PTR
*)info
= val
;
1318 case ProcessImageFileName
:
1319 /* FIXME: Should return a device path */
1320 case ProcessImageFileNameWin32
:
1321 SERVER_START_REQ( get_process_image_name
)
1323 UNICODE_STRING
*str
= info
;
1325 req
->handle
= wine_server_obj_handle( handle
);
1326 req
->win32
= (class == ProcessImageFileNameWin32
);
1327 wine_server_set_reply( req
, str
? str
+ 1 : NULL
,
1328 size
> sizeof(UNICODE_STRING
) ? size
- sizeof(UNICODE_STRING
) : 0 );
1329 ret
= wine_server_call( req
);
1330 if (ret
== STATUS_BUFFER_TOO_SMALL
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1331 len
= sizeof(UNICODE_STRING
) + reply
->len
;
1332 if (ret
== STATUS_SUCCESS
)
1334 str
->MaximumLength
= str
->Length
= reply
->len
;
1335 str
->Buffer
= (PWSTR
)(str
+ 1);
1341 case ProcessExecuteFlags
:
1342 len
= sizeof(ULONG
);
1343 if (size
== len
) *(ULONG
*)info
= execute_flags
;
1344 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1347 case ProcessPriorityClass
:
1348 len
= sizeof(PROCESS_PRIORITY_CLASS
);
1351 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1354 PROCESS_PRIORITY_CLASS
*priority
= info
;
1356 SERVER_START_REQ(get_process_info
)
1358 req
->handle
= wine_server_obj_handle( handle
);
1359 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1361 priority
->PriorityClass
= reply
->priority
;
1362 /* FIXME: Not yet supported by the wineserver */
1363 priority
->Foreground
= FALSE
;
1369 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1373 FIXME( "ProcessCookie (%p,%p,0x%08x,%p) stub\n", handle
, info
, size
, ret_len
);
1374 if (handle
== NtCurrentProcess())
1376 len
= sizeof(ULONG
);
1377 if (size
== len
) *(ULONG
*)info
= 0;
1378 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1380 else ret
= STATUS_INVALID_PARAMETER
;
1383 case ProcessImageInformation
:
1384 len
= sizeof(SECTION_IMAGE_INFORMATION
);
1389 pe_image_info_t pe_info
;
1391 SERVER_START_REQ( get_process_info
)
1393 req
->handle
= wine_server_obj_handle( handle
);
1394 wine_server_set_reply( req
, &pe_info
, sizeof(pe_info
) );
1395 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1396 virtual_fill_image_information( &pe_info
, info
);
1400 else ret
= STATUS_ACCESS_VIOLATION
;
1402 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1406 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
1407 handle
, class, info
, size
, ret_len
);
1408 ret
= STATUS_INVALID_INFO_CLASS
;
1412 if (ret_len
) *ret_len
= len
;
1417 /**********************************************************************
1418 * NtSetInformationProcess (NTDLL.@)
1420 NTSTATUS WINAPI
NtSetInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
, ULONG size
)
1422 NTSTATUS ret
= STATUS_SUCCESS
;
1426 case ProcessDefaultHardErrorMode
:
1427 if (size
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
1428 process_error_mode
= *(UINT
*)info
;
1431 case ProcessAffinityMask
:
1433 const ULONG_PTR system_mask
= get_system_affinity_mask();
1435 if (size
!= sizeof(DWORD_PTR
)) return STATUS_INVALID_PARAMETER
;
1436 if (*(PDWORD_PTR
)info
& ~system_mask
)
1437 return STATUS_INVALID_PARAMETER
;
1438 if (!*(PDWORD_PTR
)info
)
1439 return STATUS_INVALID_PARAMETER
;
1440 SERVER_START_REQ( set_process_info
)
1442 req
->handle
= wine_server_obj_handle( handle
);
1443 req
->affinity
= *(PDWORD_PTR
)info
;
1444 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
1445 ret
= wine_server_call( req
);
1450 case ProcessPriorityClass
:
1451 if (size
!= sizeof(PROCESS_PRIORITY_CLASS
)) return STATUS_INVALID_PARAMETER
;
1454 PROCESS_PRIORITY_CLASS
* ppc
= info
;
1456 SERVER_START_REQ( set_process_info
)
1458 req
->handle
= wine_server_obj_handle( handle
);
1459 /* FIXME Foreground isn't used */
1460 req
->priority
= ppc
->PriorityClass
;
1461 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
1462 ret
= wine_server_call( req
);
1468 case ProcessExecuteFlags
:
1469 if (is_win64
|| size
!= sizeof(ULONG
)) return STATUS_INVALID_PARAMETER
;
1470 if (execute_flags
& MEM_EXECUTE_OPTION_PERMANENT
) return STATUS_ACCESS_DENIED
;
1474 switch (*(ULONG
*)info
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
1476 case MEM_EXECUTE_OPTION_ENABLE
:
1479 case MEM_EXECUTE_OPTION_DISABLE
:
1483 return STATUS_INVALID_PARAMETER
;
1485 execute_flags
= *(ULONG
*)info
;
1486 virtual_set_force_exec( enable
);
1490 case ProcessInstrumentationCallback
:
1492 PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION
*instr
= info
;
1494 FIXME( "ProcessInstrumentationCallback stub.\n" );
1496 if (size
< sizeof(*instr
)) return STATUS_INFO_LENGTH_MISMATCH
;
1497 ret
= STATUS_SUCCESS
;
1501 case ProcessThreadStackAllocation
:
1505 PROCESS_STACK_ALLOCATION_INFORMATION
*stack
= info
;
1506 if (size
== sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX
))
1507 stack
= &((PROCESS_STACK_ALLOCATION_INFORMATION_EX
*)info
)->AllocInfo
;
1508 else if (size
!= sizeof(*stack
)) return STATUS_INFO_LENGTH_MISMATCH
;
1510 reserve
= stack
->ReserveSize
;
1511 ret
= NtAllocateVirtualMemory( GetCurrentProcess(), &addr
, stack
->ZeroBits
, &reserve
,
1512 MEM_RESERVE
, PAGE_READWRITE
);
1515 #ifdef VALGRIND_STACK_REGISTER
1516 VALGRIND_STACK_REGISTER( addr
, (char *)addr
+ reserve
);
1518 stack
->StackBase
= addr
;
1523 case ProcessWineMakeProcessSystem
:
1524 if (size
!= sizeof(HANDLE
*)) return STATUS_INFO_LENGTH_MISMATCH
;
1525 SERVER_START_REQ( make_process_system
)
1527 req
->handle
= wine_server_obj_handle( handle
);
1528 if (!(ret
= wine_server_call( req
)))
1529 *(HANDLE
*)info
= wine_server_ptr_handle( reply
->event
);
1535 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle
, class, info
, size
);
1536 ret
= STATUS_NOT_IMPLEMENTED
;
1543 /**********************************************************************
1544 * NtOpenProcess (NTDLL.@)
1546 NTSTATUS WINAPI
NtOpenProcess( HANDLE
*handle
, ACCESS_MASK access
,
1547 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
1553 SERVER_START_REQ( open_process
)
1555 req
->pid
= HandleToULong( id
->UniqueProcess
);
1556 req
->access
= access
;
1557 req
->attributes
= attr
? attr
->Attributes
: 0;
1558 status
= wine_server_call( req
);
1559 if (!status
) *handle
= wine_server_ptr_handle( reply
->handle
);
1566 /**********************************************************************
1567 * NtSuspendProcess (NTDLL.@)
1569 NTSTATUS WINAPI
NtSuspendProcess( HANDLE handle
)
1573 SERVER_START_REQ( suspend_process
)
1575 req
->handle
= wine_server_obj_handle( handle
);
1576 ret
= wine_server_call( req
);
1583 /**********************************************************************
1584 * NtResumeProcess (NTDLL.@)
1586 NTSTATUS WINAPI
NtResumeProcess( HANDLE handle
)
1590 SERVER_START_REQ( resume_process
)
1592 req
->handle
= wine_server_obj_handle( handle
);
1593 ret
= wine_server_call( req
);
1600 /**********************************************************************
1601 * NtDebugActiveProcess (NTDLL.@)
1603 NTSTATUS WINAPI
NtDebugActiveProcess( HANDLE process
, HANDLE debug
)
1607 SERVER_START_REQ( debug_process
)
1609 req
->handle
= wine_server_obj_handle( process
);
1610 req
->debug
= wine_server_obj_handle( debug
);
1612 ret
= wine_server_call( req
);
1619 /**********************************************************************
1620 * NtRemoveProcessDebug (NTDLL.@)
1622 NTSTATUS WINAPI
NtRemoveProcessDebug( HANDLE process
, HANDLE debug
)
1626 SERVER_START_REQ( debug_process
)
1628 req
->handle
= wine_server_obj_handle( process
);
1629 req
->debug
= wine_server_obj_handle( debug
);
1631 ret
= wine_server_call( req
);
1638 /**********************************************************************
1639 * NtDebugContinue (NTDLL.@)
1641 NTSTATUS WINAPI
NtDebugContinue( HANDLE handle
, CLIENT_ID
*client
, NTSTATUS status
)
1645 SERVER_START_REQ( continue_debug_event
)
1647 req
->debug
= wine_server_obj_handle( handle
);
1648 req
->pid
= HandleToULong( client
->UniqueProcess
);
1649 req
->tid
= HandleToULong( client
->UniqueThread
);
1650 req
->status
= status
;
1651 ret
= wine_server_call( req
);