4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018 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
23 #include "wine/port.h"
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_WAIT_H
37 # include <sys/wait.h>
44 #define WIN32_NO_STATUS
45 #include "wine/debug.h"
48 #include "ntdll_misc.h"
49 #include "wine/library.h"
50 #include "wine/server.h"
51 #include "wine/unicode.h"
53 #ifdef HAVE_MACH_MACH_H
54 #include <mach/mach.h>
57 WINE_DEFAULT_DEBUG_CHANNEL(process
);
59 static ULONG execute_flags
= MEM_EXECUTE_OPTION_DISABLE
;
61 static const BOOL is_win64
= (sizeof(void *) > sizeof(int));
63 static const char * const cpu_names
[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
65 static inline BOOL
is_64bit_arch( client_cpu_t cpu
)
67 return (cpu
== CPU_x86_64
|| cpu
== CPU_ARM64
);
74 /******************************************************************************
75 * NtTerminateProcess [NTDLL.@]
77 * Native applications must kill themselves when done
79 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
83 SERVER_START_REQ( terminate_process
)
85 req
->handle
= wine_server_obj_handle( handle
);
86 req
->exit_code
= exit_code
;
87 ret
= wine_server_call( req
);
88 self
= !ret
&& reply
->self
;
91 if (self
&& handle
) _exit( get_unix_exit_code( exit_code
));
95 /******************************************************************************
96 * RtlGetCurrentPeb [NTDLL.@]
99 PEB
* WINAPI
RtlGetCurrentPeb(void)
101 return NtCurrentTeb()->Peb
;
104 /***********************************************************************
105 * __wine_make_process_system (NTDLL.@)
107 * Mark the current process as a system process.
108 * Returns the event that is signaled when all non-system processes have exited.
110 HANDLE CDECL
__wine_make_process_system(void)
113 SERVER_START_REQ( make_process_system
)
115 if (!wine_server_call( req
)) ret
= wine_server_ptr_handle( reply
->event
);
121 static UINT process_error_mode
;
123 #define UNIMPLEMENTED_INFO_CLASS(c) \
125 FIXME("(process=%p) Unimplemented information class: " #c "\n", ProcessHandle); \
126 ret = STATUS_INVALID_INFO_CLASS; \
129 ULONG_PTR
get_system_affinity_mask(void)
131 ULONG num_cpus
= NtCurrentTeb()->Peb
->NumberOfProcessors
;
132 if (num_cpus
>= sizeof(ULONG_PTR
) * 8) return ~(ULONG_PTR
)0;
133 return ((ULONG_PTR
)1 << num_cpus
) - 1;
136 #if defined(HAVE_MACH_MACH_H)
138 static void fill_VM_COUNTERS(VM_COUNTERS
* pvmi
)
140 #if defined(MACH_TASK_BASIC_INFO)
141 struct mach_task_basic_info info
;
142 mach_msg_type_number_t infoCount
= MACH_TASK_BASIC_INFO_COUNT
;
143 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO
, (task_info_t
)&info
, &infoCount
) == KERN_SUCCESS
)
145 pvmi
->VirtualSize
= info
.resident_size
+ info
.virtual_size
;
146 pvmi
->PagefileUsage
= info
.virtual_size
;
147 pvmi
->WorkingSetSize
= info
.resident_size
;
148 pvmi
->PeakWorkingSetSize
= info
.resident_size_max
;
155 static void fill_VM_COUNTERS(VM_COUNTERS
* pvmi
)
161 f
= fopen("/proc/self/status", "r");
164 while (fgets(line
, sizeof(line
), f
))
166 if (sscanf(line
, "VmPeak: %lu", &value
))
167 pvmi
->PeakVirtualSize
= (ULONG64
)value
* 1024;
168 else if (sscanf(line
, "VmSize: %lu", &value
))
169 pvmi
->VirtualSize
= (ULONG64
)value
* 1024;
170 else if (sscanf(line
, "VmHWM: %lu", &value
))
171 pvmi
->PeakWorkingSetSize
= (ULONG64
)value
* 1024;
172 else if (sscanf(line
, "VmRSS: %lu", &value
))
173 pvmi
->WorkingSetSize
= (ULONG64
)value
* 1024;
174 else if (sscanf(line
, "RssAnon: %lu", &value
))
175 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
176 else if (sscanf(line
, "VmSwap: %lu", &value
))
177 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
179 pvmi
->PeakPagefileUsage
= pvmi
->PagefileUsage
;
186 static void fill_VM_COUNTERS(VM_COUNTERS
* pvmi
)
188 /* FIXME : real data */
193 /******************************************************************************
194 * NtQueryInformationProcess [NTDLL.@]
195 * ZwQueryInformationProcess [NTDLL.@]
198 NTSTATUS WINAPI
NtQueryInformationProcess(
199 IN HANDLE ProcessHandle
,
200 IN PROCESSINFOCLASS ProcessInformationClass
,
201 OUT PVOID ProcessInformation
,
202 IN ULONG ProcessInformationLength
,
203 OUT PULONG ReturnLength
)
205 NTSTATUS ret
= STATUS_SUCCESS
;
208 TRACE("(%p,0x%08x,%p,0x%08x,%p)\n",
209 ProcessHandle
,ProcessInformationClass
,
210 ProcessInformation
,ProcessInformationLength
,
213 switch (ProcessInformationClass
)
215 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits
);
216 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority
);
217 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority
);
218 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort
);
219 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken
);
220 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation
);
221 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize
);
222 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers
);
223 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits
);
224 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch
);
225 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL
);
226 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup
);
227 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information
);
228 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost
);
229 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap
);
230 UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation
);
231 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation
);
232 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled
);
233 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination
);
234 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing
);
236 case ProcessBasicInformation
:
238 PROCESS_BASIC_INFORMATION pbi
;
239 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
241 if (ProcessInformationLength
>= sizeof(PROCESS_BASIC_INFORMATION
))
243 if (!ProcessInformation
)
244 ret
= STATUS_ACCESS_VIOLATION
;
245 else if (!ProcessHandle
)
246 ret
= STATUS_INVALID_HANDLE
;
249 SERVER_START_REQ(get_process_info
)
251 req
->handle
= wine_server_obj_handle( ProcessHandle
);
252 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
254 pbi
.ExitStatus
= reply
->exit_code
;
255 pbi
.PebBaseAddress
= wine_server_get_ptr( reply
->peb
);
256 pbi
.AffinityMask
= reply
->affinity
& affinity_mask
;
257 pbi
.BasePriority
= reply
->priority
;
258 pbi
.UniqueProcessId
= reply
->pid
;
259 pbi
.InheritedFromUniqueProcessId
= reply
->ppid
;
264 memcpy(ProcessInformation
, &pbi
, sizeof(PROCESS_BASIC_INFORMATION
));
266 len
= sizeof(PROCESS_BASIC_INFORMATION
);
269 if (ProcessInformationLength
> sizeof(PROCESS_BASIC_INFORMATION
))
270 ret
= STATUS_INFO_LENGTH_MISMATCH
;
274 len
= sizeof(PROCESS_BASIC_INFORMATION
);
275 ret
= STATUS_INFO_LENGTH_MISMATCH
;
279 case ProcessIoCounters
:
283 if (ProcessInformationLength
>= sizeof(IO_COUNTERS
))
285 if (!ProcessInformation
)
286 ret
= STATUS_ACCESS_VIOLATION
;
287 else if (!ProcessHandle
)
288 ret
= STATUS_INVALID_HANDLE
;
291 /* FIXME : real data */
292 memset(&pii
, 0 , sizeof(IO_COUNTERS
));
294 memcpy(ProcessInformation
, &pii
, sizeof(IO_COUNTERS
));
296 len
= sizeof(IO_COUNTERS
);
299 if (ProcessInformationLength
> sizeof(IO_COUNTERS
))
300 ret
= STATUS_INFO_LENGTH_MISMATCH
;
304 len
= sizeof(IO_COUNTERS
);
305 ret
= STATUS_INFO_LENGTH_MISMATCH
;
309 case ProcessVmCounters
:
313 /* older Windows versions don't have the PrivatePageCount field */
314 if (ProcessInformationLength
>= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
))
316 if (!ProcessInformation
)
317 ret
= STATUS_ACCESS_VIOLATION
;
320 memset(&pvmi
, 0 , sizeof(VM_COUNTERS
));
321 if (ProcessHandle
== GetCurrentProcess())
322 fill_VM_COUNTERS(&pvmi
);
325 SERVER_START_REQ(get_process_vm_counters
)
327 req
->handle
= wine_server_obj_handle( ProcessHandle
);
328 if (!(ret
= wine_server_call( req
)))
330 pvmi
.PeakVirtualSize
= reply
->peak_virtual_size
;
331 pvmi
.VirtualSize
= reply
->virtual_size
;
332 pvmi
.PeakWorkingSetSize
= reply
->peak_working_set_size
;
333 pvmi
.WorkingSetSize
= reply
->working_set_size
;
334 pvmi
.PagefileUsage
= reply
->pagefile_usage
;
335 pvmi
.PeakPagefileUsage
= reply
->peak_pagefile_usage
;
342 len
= ProcessInformationLength
;
343 if (len
!= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
)) len
= sizeof(VM_COUNTERS
);
345 memcpy(ProcessInformation
, &pvmi
, min(ProcessInformationLength
,sizeof(VM_COUNTERS
)));
348 if (ProcessInformationLength
!= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
) &&
349 ProcessInformationLength
!= sizeof(VM_COUNTERS
))
350 ret
= STATUS_INFO_LENGTH_MISMATCH
;
355 ret
= STATUS_INFO_LENGTH_MISMATCH
;
361 KERNEL_USER_TIMES pti
;
363 if (ProcessInformationLength
>= sizeof(KERNEL_USER_TIMES
))
365 if (!ProcessInformation
)
366 ret
= STATUS_ACCESS_VIOLATION
;
367 else if (!ProcessHandle
)
368 ret
= STATUS_INVALID_HANDLE
;
371 /* FIXME : User- and KernelTime have to be implemented */
372 memset(&pti
, 0, sizeof(KERNEL_USER_TIMES
));
374 SERVER_START_REQ(get_process_info
)
376 req
->handle
= wine_server_obj_handle( ProcessHandle
);
377 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
379 pti
.CreateTime
.QuadPart
= reply
->start_time
;
380 pti
.ExitTime
.QuadPart
= reply
->end_time
;
385 memcpy(ProcessInformation
, &pti
, sizeof(KERNEL_USER_TIMES
));
386 len
= sizeof(KERNEL_USER_TIMES
);
389 if (ProcessInformationLength
> sizeof(KERNEL_USER_TIMES
))
390 ret
= STATUS_INFO_LENGTH_MISMATCH
;
394 len
= sizeof(KERNEL_USER_TIMES
);
395 ret
= STATUS_INFO_LENGTH_MISMATCH
;
399 case ProcessDebugPort
:
400 len
= sizeof(DWORD_PTR
);
401 if (ProcessInformationLength
== len
)
403 if (!ProcessInformation
)
404 ret
= STATUS_ACCESS_VIOLATION
;
405 else if (!ProcessHandle
)
406 ret
= STATUS_INVALID_HANDLE
;
409 SERVER_START_REQ(get_process_info
)
411 req
->handle
= wine_server_obj_handle( ProcessHandle
);
412 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
414 *(DWORD_PTR
*)ProcessInformation
= reply
->debugger_present
? ~(DWORD_PTR
)0 : 0;
421 ret
= STATUS_INFO_LENGTH_MISMATCH
;
423 case ProcessDebugFlags
:
425 if (ProcessInformationLength
== len
)
427 if (!ProcessInformation
)
428 ret
= STATUS_ACCESS_VIOLATION
;
429 else if (!ProcessHandle
)
430 ret
= STATUS_INVALID_HANDLE
;
433 SERVER_START_REQ(get_process_info
)
435 req
->handle
= wine_server_obj_handle( ProcessHandle
);
436 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
438 *(DWORD
*)ProcessInformation
= reply
->debug_children
;
445 ret
= STATUS_INFO_LENGTH_MISMATCH
;
447 case ProcessDefaultHardErrorMode
:
448 len
= sizeof(process_error_mode
);
449 if (ProcessInformationLength
== len
)
450 memcpy(ProcessInformation
, &process_error_mode
, len
);
452 ret
= STATUS_INFO_LENGTH_MISMATCH
;
454 case ProcessDebugObjectHandle
:
455 /* "These are not the debuggers you are looking for." *
456 * set it to 0 aka "no debugger" to satisfy copy protections */
457 len
= sizeof(HANDLE
);
458 if (ProcessInformationLength
== len
)
460 if (!ProcessInformation
)
461 ret
= STATUS_ACCESS_VIOLATION
;
462 else if (!ProcessHandle
)
463 ret
= STATUS_INVALID_HANDLE
;
466 memset(ProcessInformation
, 0, ProcessInformationLength
);
467 ret
= STATUS_PORT_NOT_SET
;
471 ret
= STATUS_INFO_LENGTH_MISMATCH
;
473 case ProcessHandleCount
:
474 if (ProcessInformationLength
>= 4)
476 if (!ProcessInformation
)
477 ret
= STATUS_ACCESS_VIOLATION
;
478 else if (!ProcessHandle
)
479 ret
= STATUS_INVALID_HANDLE
;
482 memset(ProcessInformation
, 0, 4);
486 if (ProcessInformationLength
> 4)
487 ret
= STATUS_INFO_LENGTH_MISMATCH
;
492 ret
= STATUS_INFO_LENGTH_MISMATCH
;
496 case ProcessAffinityMask
:
497 len
= sizeof(ULONG_PTR
);
498 if (ProcessInformationLength
== len
)
500 const ULONG_PTR system_mask
= get_system_affinity_mask();
502 SERVER_START_REQ(get_process_info
)
504 req
->handle
= wine_server_obj_handle( ProcessHandle
);
505 if (!(ret
= wine_server_call( req
)))
506 *(ULONG_PTR
*)ProcessInformation
= reply
->affinity
& system_mask
;
510 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
513 case ProcessWow64Information
:
514 len
= sizeof(ULONG_PTR
);
515 if (ProcessInformationLength
!= len
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
516 else if (!ProcessInformation
) ret
= STATUS_ACCESS_VIOLATION
;
517 else if(!ProcessHandle
) ret
= STATUS_INVALID_HANDLE
;
522 if (ProcessHandle
== GetCurrentProcess()) val
= is_wow64
;
523 else if (server_cpus
& ((1 << CPU_x86_64
) | (1 << CPU_ARM64
)))
525 SERVER_START_REQ( get_process_info
)
527 req
->handle
= wine_server_obj_handle( ProcessHandle
);
528 if (!(ret
= wine_server_call( req
)))
529 val
= (reply
->cpu
!= CPU_x86_64
&& reply
->cpu
!= CPU_ARM64
);
533 *(ULONG_PTR
*)ProcessInformation
= val
;
536 case ProcessImageFileName
:
537 /* FIXME: Should return a device path */
538 case ProcessImageFileNameWin32
:
539 SERVER_START_REQ(get_dll_info
)
541 UNICODE_STRING
*image_file_name_str
= ProcessInformation
;
543 req
->handle
= wine_server_obj_handle( ProcessHandle
);
544 req
->base_address
= 0; /* main module */
545 wine_server_set_reply( req
, image_file_name_str
? image_file_name_str
+ 1 : NULL
,
546 ProcessInformationLength
> sizeof(UNICODE_STRING
) ? ProcessInformationLength
- sizeof(UNICODE_STRING
) : 0 );
547 ret
= wine_server_call( req
);
548 if (ret
== STATUS_BUFFER_TOO_SMALL
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
550 len
= sizeof(UNICODE_STRING
) + reply
->filename_len
;
551 if (ret
== STATUS_SUCCESS
)
553 image_file_name_str
->MaximumLength
= image_file_name_str
->Length
= reply
->filename_len
;
554 image_file_name_str
->Buffer
= (PWSTR
)(image_file_name_str
+ 1);
559 case ProcessExecuteFlags
:
561 if (ProcessInformationLength
== len
)
562 *(ULONG
*)ProcessInformation
= execute_flags
;
564 ret
= STATUS_INFO_LENGTH_MISMATCH
;
566 case ProcessPriorityClass
:
567 len
= sizeof(PROCESS_PRIORITY_CLASS
);
568 if (ProcessInformationLength
== len
)
570 if (!ProcessInformation
)
571 ret
= STATUS_ACCESS_VIOLATION
;
572 else if (!ProcessHandle
)
573 ret
= STATUS_INVALID_HANDLE
;
576 PROCESS_PRIORITY_CLASS
*priority
= ProcessInformation
;
578 SERVER_START_REQ(get_process_info
)
580 req
->handle
= wine_server_obj_handle( ProcessHandle
);
581 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
583 priority
->PriorityClass
= reply
->priority
;
584 /* FIXME: Not yet supported by the wineserver */
585 priority
->Foreground
= FALSE
;
592 ret
= STATUS_INFO_LENGTH_MISMATCH
;
595 FIXME("ProcessCookie (%p,%p,0x%08x,%p) stub\n",
596 ProcessHandle
,ProcessInformation
,
597 ProcessInformationLength
,ReturnLength
);
599 if(ProcessHandle
== NtCurrentProcess())
602 if (ProcessInformationLength
== len
)
603 *(ULONG
*)ProcessInformation
= 0;
605 ret
= STATUS_INFO_LENGTH_MISMATCH
;
608 ret
= STATUS_INVALID_PARAMETER
;
611 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
612 ProcessHandle
,ProcessInformationClass
,
613 ProcessInformation
,ProcessInformationLength
,
615 ret
= STATUS_INVALID_INFO_CLASS
;
619 if (ReturnLength
) *ReturnLength
= len
;
624 /******************************************************************************
625 * NtSetInformationProcess [NTDLL.@]
626 * ZwSetInformationProcess [NTDLL.@]
628 NTSTATUS WINAPI
NtSetInformationProcess(
629 IN HANDLE ProcessHandle
,
630 IN PROCESSINFOCLASS ProcessInformationClass
,
631 IN PVOID ProcessInformation
,
632 IN ULONG ProcessInformationLength
)
634 NTSTATUS ret
= STATUS_SUCCESS
;
636 switch (ProcessInformationClass
)
638 case ProcessDefaultHardErrorMode
:
639 if (ProcessInformationLength
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
640 process_error_mode
= *(UINT
*)ProcessInformation
;
642 case ProcessAffinityMask
:
644 const ULONG_PTR system_mask
= get_system_affinity_mask();
646 if (ProcessInformationLength
!= sizeof(DWORD_PTR
)) return STATUS_INVALID_PARAMETER
;
647 if (*(PDWORD_PTR
)ProcessInformation
& ~system_mask
)
648 return STATUS_INVALID_PARAMETER
;
649 if (!*(PDWORD_PTR
)ProcessInformation
)
650 return STATUS_INVALID_PARAMETER
;
651 SERVER_START_REQ( set_process_info
)
653 req
->handle
= wine_server_obj_handle( ProcessHandle
);
654 req
->affinity
= *(PDWORD_PTR
)ProcessInformation
;
655 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
656 ret
= wine_server_call( req
);
661 case ProcessPriorityClass
:
662 if (ProcessInformationLength
!= sizeof(PROCESS_PRIORITY_CLASS
))
663 return STATUS_INVALID_PARAMETER
;
666 PROCESS_PRIORITY_CLASS
* ppc
= ProcessInformation
;
668 SERVER_START_REQ( set_process_info
)
670 req
->handle
= wine_server_obj_handle( ProcessHandle
);
671 /* FIXME Foreground isn't used */
672 req
->priority
= ppc
->PriorityClass
;
673 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
674 ret
= wine_server_call( req
);
680 case ProcessExecuteFlags
:
681 if (ProcessInformationLength
!= sizeof(ULONG
))
682 return STATUS_INVALID_PARAMETER
;
683 else if (execute_flags
& MEM_EXECUTE_OPTION_PERMANENT
)
684 return STATUS_ACCESS_DENIED
;
688 switch (*(ULONG
*)ProcessInformation
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
690 case MEM_EXECUTE_OPTION_ENABLE
:
693 case MEM_EXECUTE_OPTION_DISABLE
:
697 return STATUS_INVALID_PARAMETER
;
699 execute_flags
= *(ULONG
*)ProcessInformation
;
700 VIRTUAL_SetForceExec( enable
);
705 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
706 ProcessHandle
,ProcessInformationClass
,ProcessInformation
,
707 ProcessInformationLength
);
708 ret
= STATUS_NOT_IMPLEMENTED
;
714 /******************************************************************************
715 * NtFlushInstructionCache [NTDLL.@]
716 * ZwFlushInstructionCache [NTDLL.@]
718 NTSTATUS WINAPI
NtFlushInstructionCache( HANDLE handle
, const void *addr
, SIZE_T size
)
720 #if defined(__x86_64__) || defined(__i386__)
722 #elif defined(HAVE___CLEAR_CACHE)
723 if (handle
== GetCurrentProcess())
725 __clear_cache( (char *)addr
, (char *)addr
+ size
);
730 if (!once
++) FIXME( "%p %p %ld other process not supported\n", handle
, addr
, size
);
734 if (!once
++) FIXME( "%p %p %ld\n", handle
, addr
, size
);
736 return STATUS_SUCCESS
;
739 /******************************************************************
740 * NtOpenProcess [NTDLL.@]
741 * ZwOpenProcess [NTDLL.@]
743 NTSTATUS WINAPI
NtOpenProcess(PHANDLE handle
, ACCESS_MASK access
,
744 const OBJECT_ATTRIBUTES
* attr
, const CLIENT_ID
* cid
)
748 SERVER_START_REQ( open_process
)
750 req
->pid
= HandleToULong(cid
->UniqueProcess
);
751 req
->access
= access
;
752 req
->attributes
= attr
? attr
->Attributes
: 0;
753 status
= wine_server_call( req
);
754 if (!status
) *handle
= wine_server_ptr_handle( reply
->handle
);
760 /******************************************************************************
764 NTSTATUS WINAPI
NtResumeProcess( HANDLE handle
)
768 SERVER_START_REQ( resume_process
)
770 req
->handle
= wine_server_obj_handle( handle
);
771 ret
= wine_server_call( req
);
778 /******************************************************************************
782 NTSTATUS WINAPI
NtSuspendProcess( HANDLE handle
)
786 SERVER_START_REQ( suspend_process
)
788 req
->handle
= wine_server_obj_handle( handle
);
789 ret
= wine_server_call( req
);
797 /***********************************************************************
800 * Build an argv array from a command-line.
801 * 'reserved' is the number of args to reserve before the first one.
803 static char **build_argv( const UNICODE_STRING
*cmdlineW
, int reserved
)
807 char *arg
, *s
, *d
, *cmdline
;
808 int in_quotes
, bcount
, len
;
810 len
= ntdll_wcstoumbs( 0, cmdlineW
->Buffer
, cmdlineW
->Length
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
811 if (!(cmdline
= RtlAllocateHeap( GetProcessHeap(), 0, len
+ 1 ))) return NULL
;
812 ntdll_wcstoumbs( 0, cmdlineW
->Buffer
, cmdlineW
->Length
/ sizeof(WCHAR
), cmdline
, len
, NULL
, NULL
);
821 if (*s
== '\0' || ((*s
== ' ' || *s
== '\t') && !in_quotes
))
825 /* skip the remaining spaces */
826 while (*s
== ' ' || *s
== '\t') s
++;
827 if (*s
== '\0') break;
831 else if (*s
== '\\') bcount
++; /* '\', count them */
832 else if ((*s
== '"') && ((bcount
& 1) == 0))
834 if (in_quotes
&& s
[1] == '"') s
++;
838 in_quotes
= !in_quotes
;
842 else bcount
= 0; /* a regular character */
845 if (!(argv
= RtlAllocateHeap( GetProcessHeap(), 0, argc
* sizeof(*argv
) + len
)))
847 RtlFreeHeap( GetProcessHeap(), 0, cmdline
);
851 arg
= d
= s
= (char *)(argv
+ argc
);
852 memcpy( d
, cmdline
, len
);
858 if ((*s
== ' ' || *s
== '\t') && !in_quotes
)
860 /* Close the argument and copy it */
863 /* skip the remaining spaces */
867 } while (*s
== ' ' || *s
== '\t');
869 /* Start with a new argument */
880 if ((bcount
& 1) == 0)
882 /* Preceded by an even number of '\', this is half that
883 * number of '\', plus a '"' which we discard.
887 if (in_quotes
&& *s
== '"')
892 else in_quotes
= !in_quotes
;
896 /* Preceded by an odd number of '\', this is half that
897 * number of '\' followed by a '"'
899 d
= d
- bcount
/ 2 - 1;
907 /* a regular character */
919 RtlFreeHeap( GetProcessHeap(), 0, cmdline
);
924 static inline const WCHAR
*get_params_string( const RTL_USER_PROCESS_PARAMETERS
*params
,
925 const UNICODE_STRING
*str
)
927 if (params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
) return str
->Buffer
;
928 return (const WCHAR
*)((const char *)params
+ (UINT_PTR
)str
->Buffer
);
931 static inline DWORD
append_string( void **ptr
, const RTL_USER_PROCESS_PARAMETERS
*params
,
932 const UNICODE_STRING
*str
)
934 const WCHAR
*buffer
= get_params_string( params
, str
);
935 memcpy( *ptr
, buffer
, str
->Length
);
936 *ptr
= (WCHAR
*)*ptr
+ str
->Length
/ sizeof(WCHAR
);
940 /***********************************************************************
941 * create_startup_info
943 static startup_info_t
*create_startup_info( const RTL_USER_PROCESS_PARAMETERS
*params
, DWORD
*info_size
)
945 startup_info_t
*info
;
949 size
= sizeof(*info
);
950 size
+= params
->CurrentDirectory
.DosPath
.Length
;
951 size
+= params
->DllPath
.Length
;
952 size
+= params
->ImagePathName
.Length
;
953 size
+= params
->CommandLine
.Length
;
954 size
+= params
->WindowTitle
.Length
;
955 size
+= params
->Desktop
.Length
;
956 size
+= params
->ShellInfo
.Length
;
957 size
+= params
->RuntimeInfo
.Length
;
958 size
= (size
+ 1) & ~1;
961 if (!(info
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
))) return NULL
;
963 info
->console_flags
= params
->ConsoleFlags
;
964 info
->console
= wine_server_obj_handle( params
->ConsoleHandle
);
965 info
->hstdin
= wine_server_obj_handle( params
->hStdInput
);
966 info
->hstdout
= wine_server_obj_handle( params
->hStdOutput
);
967 info
->hstderr
= wine_server_obj_handle( params
->hStdError
);
968 info
->x
= params
->dwX
;
969 info
->y
= params
->dwY
;
970 info
->xsize
= params
->dwXSize
;
971 info
->ysize
= params
->dwYSize
;
972 info
->xchars
= params
->dwXCountChars
;
973 info
->ychars
= params
->dwYCountChars
;
974 info
->attribute
= params
->dwFillAttribute
;
975 info
->flags
= params
->dwFlags
;
976 info
->show
= params
->wShowWindow
;
979 info
->curdir_len
= append_string( &ptr
, params
, ¶ms
->CurrentDirectory
.DosPath
);
980 info
->dllpath_len
= append_string( &ptr
, params
, ¶ms
->DllPath
);
981 info
->imagepath_len
= append_string( &ptr
, params
, ¶ms
->ImagePathName
);
982 info
->cmdline_len
= append_string( &ptr
, params
, ¶ms
->CommandLine
);
983 info
->title_len
= append_string( &ptr
, params
, ¶ms
->WindowTitle
);
984 info
->desktop_len
= append_string( &ptr
, params
, ¶ms
->Desktop
);
985 info
->shellinfo_len
= append_string( &ptr
, params
, ¶ms
->ShellInfo
);
986 info
->runtime_len
= append_string( &ptr
, params
, ¶ms
->RuntimeInfo
);
991 /***********************************************************************
992 * get_alternate_loader
994 * Get the name of the alternate (32 or 64 bit) Wine loader.
996 static const char *get_alternate_loader( char **ret_env
)
999 const char *loader
= NULL
;
1000 const char *loader_env
= getenv( "WINELOADER" );
1004 if (wine_get_build_dir()) loader
= is_win64
? "loader/wine" : "loader/wine64";
1008 int len
= strlen( loader_env
);
1011 if (!(env
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len
+ 2 ))) return NULL
;
1012 strcpy( env
, "WINELOADER=" );
1013 strcat( env
, loader_env
);
1014 strcat( env
, "64" );
1018 if (!(env
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len
))) return NULL
;
1019 strcpy( env
, "WINELOADER=" );
1020 strcat( env
, loader_env
);
1021 len
+= sizeof("WINELOADER=") - 1;
1022 if (!strcmp( env
+ len
- 2, "64" )) env
[len
- 2] = 0;
1026 if ((loader
= strrchr( env
, '/' ))) loader
++;
1031 if (!loader
) loader
= is_win64
? "wine" : "wine64";
1036 /***********************************************************************
1039 static void set_stdio_fd( int stdin_fd
, int stdout_fd
)
1043 if (stdin_fd
== -1 || stdout_fd
== -1)
1045 fd
= open( "/dev/null", O_RDWR
);
1046 if (stdin_fd
== -1) stdin_fd
= fd
;
1047 if (stdout_fd
== -1) stdout_fd
= fd
;
1050 dup2( stdin_fd
, 0 );
1051 dup2( stdout_fd
, 1 );
1052 if (fd
!= -1) close( fd
);
1056 /***********************************************************************
1059 static NTSTATUS
spawn_loader( const RTL_USER_PROCESS_PARAMETERS
*params
, int socketfd
,
1060 const char *unixdir
, char *winedebug
, const pe_image_info_t
*pe_info
)
1063 int stdin_fd
= -1, stdout_fd
= -1;
1064 char *wineloader
= NULL
;
1065 const char *loader
= NULL
;
1067 NTSTATUS status
= STATUS_SUCCESS
;
1069 argv
= build_argv( ¶ms
->CommandLine
, 1 );
1071 if (!is_win64
^ !is_64bit_arch( pe_info
->cpu
))
1072 loader
= get_alternate_loader( &wineloader
);
1074 wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
);
1075 wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
);
1077 if (!(pid
= fork())) /* child */
1079 if (!(pid
= fork())) /* grandchild */
1081 char preloader_reserve
[64], socket_env
[64];
1082 ULONGLONG res_start
= pe_info
->base
;
1083 ULONGLONG res_end
= pe_info
->base
+ pe_info
->map_size
;
1085 if (params
->ConsoleFlags
||
1086 params
->ConsoleHandle
== (HANDLE
)1 /* KERNEL32_CONSOLE_ALLOC */ ||
1087 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
1090 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
1092 else set_stdio_fd( stdin_fd
, stdout_fd
);
1094 if (stdin_fd
!= -1) close( stdin_fd
);
1095 if (stdout_fd
!= -1) close( stdout_fd
);
1097 /* Reset signals that we previously set to SIG_IGN */
1098 signal( SIGPIPE
, SIG_DFL
);
1100 sprintf( socket_env
, "WINESERVERSOCKET=%u", socketfd
);
1101 sprintf( preloader_reserve
, "WINEPRELOADRESERVE=%x%08x-%x%08x",
1102 (ULONG
)(res_start
>> 32), (ULONG
)res_start
, (ULONG
)(res_end
>> 32), (ULONG
)res_end
);
1104 putenv( preloader_reserve
);
1105 putenv( socket_env
);
1106 if (winedebug
) putenv( winedebug
);
1107 if (wineloader
) putenv( wineloader
);
1108 if (unixdir
) chdir( unixdir
);
1110 if (argv
) wine_exec_wine_binary( loader
, argv
, getenv("WINELOADER") );
1122 wret
= waitpid(pid
, NULL
, 0);
1123 } while (wret
< 0 && errno
== EINTR
);
1125 else status
= FILE_GetNtStatus();
1127 if (stdin_fd
!= -1) close( stdin_fd
);
1128 if (stdout_fd
!= -1) close( stdout_fd
);
1129 RtlFreeHeap( GetProcessHeap(), 0, wineloader
);
1130 RtlFreeHeap( GetProcessHeap(), 0, argv
);
1135 /***********************************************************************
1138 static NTSTATUS
get_pe_file_info( UNICODE_STRING
*path
, ULONG attributes
,
1139 HANDLE
*handle
, pe_image_info_t
*info
)
1143 OBJECT_ATTRIBUTES attr
;
1146 InitializeObjectAttributes( &attr
, path
, attributes
, 0, 0 );
1147 if ((status
= NtOpenFile( handle
, GENERIC_READ
, &attr
, &io
,
1148 FILE_SHARE_READ
| FILE_SHARE_DELETE
, 0 ))) return status
;
1150 if (!(status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
1151 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
1152 NULL
, NULL
, PAGE_EXECUTE_READ
, SEC_IMAGE
, *handle
)))
1154 SERVER_START_REQ( get_mapping_info
)
1156 req
->handle
= wine_server_obj_handle( mapping
);
1157 req
->access
= SECTION_QUERY
;
1158 wine_server_set_reply( req
, info
, sizeof(*info
) );
1159 status
= wine_server_call( req
);
1168 /***********************************************************************
1171 static ULONG
get_env_size( const RTL_USER_PROCESS_PARAMETERS
*params
, char **winedebug
)
1173 WCHAR
*ptr
= params
->Environment
;
1177 static const WCHAR WINEDEBUG
[] = {'W','I','N','E','D','E','B','U','G','=',0};
1178 if (!*winedebug
&& !strncmpW( ptr
, WINEDEBUG
, ARRAY_SIZE( WINEDEBUG
) - 1 ))
1180 DWORD len
= ntdll_wcstoumbs( 0, ptr
, strlenW(ptr
) + 1, NULL
, 0, NULL
, NULL
);
1181 if ((*winedebug
= RtlAllocateHeap( GetProcessHeap(), 0, len
)))
1182 ntdll_wcstoumbs( 0, ptr
, strlenW(ptr
) + 1, *winedebug
, len
, NULL
, NULL
);
1184 ptr
+= strlenW(ptr
) + 1;
1187 return (ptr
- params
->Environment
) * sizeof(WCHAR
);
1191 /***********************************************************************
1194 static char *get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS
*params
)
1196 UNICODE_STRING nt_name
;
1197 ANSI_STRING unix_name
;
1200 if (!RtlDosPathNameToNtPathName_U( params
->CurrentDirectory
.DosPath
.Buffer
, &nt_name
, NULL
, NULL
))
1202 status
= wine_nt_to_unix_file_name( &nt_name
, &unix_name
, FILE_OPEN_IF
, FALSE
);
1203 RtlFreeUnicodeString( &nt_name
);
1204 if (status
&& status
!= STATUS_NO_SUCH_FILE
) return NULL
;
1205 return unix_name
.Buffer
;
1209 /**********************************************************************
1210 * RtlCreateUserProcess (NTDLL.@)
1212 NTSTATUS WINAPI
RtlCreateUserProcess( UNICODE_STRING
*path
, ULONG attributes
,
1213 RTL_USER_PROCESS_PARAMETERS
*params
,
1214 SECURITY_DESCRIPTOR
*process_descr
,
1215 SECURITY_DESCRIPTOR
*thread_descr
,
1216 HANDLE parent
, BOOLEAN inherit
, HANDLE debug
, HANDLE exception
,
1217 RTL_USER_PROCESS_INFORMATION
*info
)
1220 BOOL success
= FALSE
;
1221 HANDLE file_handle
, process_info
= 0, process_handle
= 0, thread_handle
= 0;
1222 ULONG process_id
, thread_id
;
1223 struct object_attributes
*objattr
;
1224 data_size_t attr_len
;
1225 char *unixdir
= NULL
, *winedebug
= NULL
;
1226 startup_info_t
*startup_info
= NULL
;
1227 ULONG startup_info_size
, env_size
;
1228 int err
, socketfd
[2] = { -1, -1 };
1229 OBJECT_ATTRIBUTES attr
;
1230 pe_image_info_t pe_info
;
1232 RtlNormalizeProcessParams( params
);
1234 TRACE( "%s image %s cmdline %s\n", debugstr_us( path
),
1235 debugstr_us( ¶ms
->ImagePathName
), debugstr_us( ¶ms
->CommandLine
));
1237 if ((status
= get_pe_file_info( path
, attributes
, &file_handle
, &pe_info
))) goto done
;
1238 if (!(startup_info
= create_startup_info( params
, &startup_info_size
))) goto done
;
1239 env_size
= get_env_size( params
, &winedebug
);
1240 unixdir
= get_unix_curdir( params
);
1242 InitializeObjectAttributes( &attr
, NULL
, 0, NULL
, process_descr
);
1243 if ((status
= alloc_object_attributes( &attr
, &objattr
, &attr_len
))) goto done
;
1245 /* create the socket for the new process */
1247 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1)
1249 status
= STATUS_TOO_MANY_OPENED_FILES
;
1250 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
1257 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
1261 wine_server_send_fd( socketfd
[1] );
1262 close( socketfd
[1] );
1264 /* create the process on the server side */
1266 SERVER_START_REQ( new_process
)
1268 req
->inherit_all
= inherit
;
1269 req
->create_flags
= 0;
1270 req
->socket_fd
= socketfd
[1];
1271 req
->exe_file
= wine_server_obj_handle( file_handle
);
1272 req
->access
= PROCESS_ALL_ACCESS
;
1273 req
->cpu
= pe_info
.cpu
;
1274 req
->info_size
= startup_info_size
;
1275 wine_server_add_data( req
, objattr
, attr_len
);
1276 wine_server_add_data( req
, startup_info
, startup_info_size
);
1277 wine_server_add_data( req
, params
->Environment
, env_size
);
1278 if (!(status
= wine_server_call( req
)))
1280 process_id
= reply
->pid
;
1281 process_handle
= wine_server_ptr_handle( reply
->handle
);
1283 process_info
= wine_server_ptr_handle( reply
->info
);
1286 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
1292 case STATUS_INVALID_IMAGE_WIN_64
:
1293 ERR( "64-bit application %s not supported in 32-bit prefix\n",
1294 debugstr_us( ¶ms
->ImagePathName
));
1296 case STATUS_INVALID_IMAGE_FORMAT
:
1297 ERR( "%s not supported on this installation (%s binary)\n",
1298 debugstr_us( ¶ms
->ImagePathName
), cpu_names
[pe_info
.cpu
] );
1304 InitializeObjectAttributes( &attr
, NULL
, 0, NULL
, thread_descr
);
1305 if ((status
= alloc_object_attributes( &attr
, &objattr
, &attr_len
))) goto done
;
1307 SERVER_START_REQ( new_thread
)
1309 req
->process
= wine_server_obj_handle( process_handle
);
1310 req
->access
= THREAD_ALL_ACCESS
;
1312 req
->request_fd
= -1;
1313 wine_server_add_data( req
, objattr
, attr_len
);
1314 if (!(status
= wine_server_call( req
)))
1316 thread_handle
= wine_server_ptr_handle( reply
->handle
);
1317 thread_id
= reply
->tid
;
1321 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
1322 if (status
) goto done
;
1324 /* create the child process */
1326 if ((status
= spawn_loader( params
, socketfd
[0], unixdir
, winedebug
, &pe_info
))) goto done
;
1328 close( socketfd
[0] );
1331 /* wait for the new process info to be ready */
1333 NtWaitForSingleObject( process_info
, FALSE
, NULL
);
1334 SERVER_START_REQ( get_new_process_info
)
1336 req
->info
= wine_server_obj_handle( process_info
);
1337 wine_server_call( req
);
1338 success
= reply
->success
;
1339 err
= reply
->exit_code
;
1345 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us( path
),
1346 process_id
, thread_id
, process_handle
, thread_handle
);
1347 info
->Process
= process_handle
;
1348 info
->Thread
= thread_handle
;
1349 info
->ClientId
.UniqueProcess
= ULongToHandle( process_id
);
1350 info
->ClientId
.UniqueThread
= ULongToHandle( thread_id
);
1351 virtual_fill_image_information( &pe_info
, &info
->ImageInformation
);
1352 process_handle
= thread_handle
= 0;
1353 status
= STATUS_SUCCESS
;
1355 else status
= err
? err
: ERROR_INTERNAL_ERROR
;
1358 NtClose( file_handle
);
1359 if (process_info
) NtClose( process_info
);
1360 if (process_handle
) NtClose( process_handle
);
1361 if (thread_handle
) NtClose( thread_handle
);
1362 if (socketfd
[0] != -1) close( socketfd
[0] );
1363 RtlFreeHeap( GetProcessHeap(), 0, startup_info
);
1364 RtlFreeHeap( GetProcessHeap(), 0, winedebug
);
1365 RtlFreeHeap( GetProcessHeap(), 0, unixdir
);
1369 /***********************************************************************
1370 * DbgUiRemoteBreakin (NTDLL.@)
1372 void WINAPI
DbgUiRemoteBreakin( void *arg
)
1375 if (NtCurrentTeb()->Peb
->BeingDebugged
) DbgBreakPoint();
1376 RtlExitUserThread( STATUS_SUCCESS
);
1379 /***********************************************************************
1380 * DbgUiIssueRemoteBreakin (NTDLL.@)
1382 NTSTATUS WINAPI
DbgUiIssueRemoteBreakin( HANDLE process
)
1385 apc_result_t result
;
1388 TRACE( "(%p)\n", process
);
1390 memset( &call
, 0, sizeof(call
) );
1392 call
.type
= APC_BREAK_PROCESS
;
1393 status
= server_queue_process_apc( process
, &call
, &result
);
1394 if (status
) return status
;
1395 return result
.break_process
.status
;