server: Use the helper to reset the clip rect when the desktop size changes.
[wine.git] / dlls / kernelbase / debug.c
blobdf1b9a63604b255af6e802a8719aa6991e0263cc
1 /*
2 * Win32 debugger functions
4 * Copyright (C) 1999 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
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winternl.h"
30 #include "winnls.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #define PSAPI_VERSION 1 /* avoid K32 function remapping */
34 #include "psapi.h"
35 #include "werapi.h"
37 #include "wine/exception.h"
38 #include "wine/asm.h"
39 #include "kernelbase.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(seh);
43 WINE_DECLARE_DEBUG_CHANNEL(winedbg);
45 typedef INT (WINAPI *MessageBoxA_funcptr)(HWND,LPCSTR,LPCSTR,UINT);
46 typedef INT (WINAPI *MessageBoxW_funcptr)(HWND,LPCWSTR,LPCWSTR,UINT);
48 static PTOP_LEVEL_EXCEPTION_FILTER top_filter;
50 void *dummy = RtlUnwind; /* force importing RtlUnwind from ntdll */
52 /***********************************************************************
53 * CheckRemoteDebuggerPresent (kernelbase.@)
55 BOOL WINAPI DECLSPEC_HOTPATCH CheckRemoteDebuggerPresent( HANDLE process, BOOL *present )
57 DWORD_PTR port;
59 if (!process || !present)
61 SetLastError( ERROR_INVALID_PARAMETER );
62 return FALSE;
64 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessDebugPort, &port, sizeof(port), NULL )))
65 return FALSE;
66 *present = !!port;
67 return TRUE;
71 /**********************************************************************
72 * ContinueDebugEvent (kernelbase.@)
74 BOOL WINAPI DECLSPEC_HOTPATCH ContinueDebugEvent( DWORD pid, DWORD tid, DWORD status )
76 CLIENT_ID id;
78 id.UniqueProcess = ULongToHandle( pid );
79 id.UniqueThread = ULongToHandle( tid );
80 return set_ntstatus( DbgUiContinue( &id, status ));
84 /**********************************************************************
85 * DebugActiveProcess (kernelbase.@)
87 BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcess( DWORD pid )
89 HANDLE process;
90 NTSTATUS status;
92 if (!set_ntstatus( DbgUiConnectToDbg() )) return FALSE;
93 if (!(process = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME |
94 PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD, FALSE, pid )))
95 return FALSE;
96 status = DbgUiDebugActiveProcess( process );
97 NtClose( process );
98 return set_ntstatus( status );
102 /**********************************************************************
103 * DebugActiveProcessStop (kernelbase.@)
105 BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcessStop( DWORD pid )
107 HANDLE process;
108 NTSTATUS status;
110 if (!(process = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME, FALSE, pid )))
111 return FALSE;
112 status = DbgUiStopDebugging( process );
113 NtClose( process );
114 return set_ntstatus( status );
118 /***********************************************************************
119 * DebugBreak (kernelbase.@)
121 #if defined(__i386__) || defined(__x86_64__)
122 __ASM_STDCALL_FUNC( DebugBreak, 0, "jmp " __ASM_STDCALL("DbgBreakPoint", 0) )
123 #else
124 void WINAPI DebugBreak(void)
126 DbgBreakPoint();
128 #endif
131 /**************************************************************************
132 * FatalAppExitA (kernelbase.@)
134 void WINAPI DECLSPEC_HOTPATCH FatalAppExitA( UINT action, LPCSTR str )
136 HMODULE mod = GetModuleHandleA( "user32.dll" );
137 MessageBoxA_funcptr pMessageBoxA = NULL;
139 if (mod) pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" );
140 if (pMessageBoxA) pMessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
141 else ERR( "%s\n", debugstr_a(str) );
142 RtlExitUserProcess( 1 );
146 /**************************************************************************
147 * FatalAppExitW (kernelbase.@)
149 void WINAPI DECLSPEC_HOTPATCH FatalAppExitW( UINT action, LPCWSTR str )
151 HMODULE mod = GetModuleHandleW( L"user32.dll" );
152 MessageBoxW_funcptr pMessageBoxW = NULL;
154 if (mod) pMessageBoxW = (MessageBoxW_funcptr)GetProcAddress( mod, "MessageBoxW" );
155 if (pMessageBoxW) pMessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
156 else ERR( "%s\n", debugstr_w(str) );
157 RtlExitUserProcess( 1 );
161 /***********************************************************************
162 * IsDebuggerPresent (kernelbase.@)
164 BOOL WINAPI IsDebuggerPresent(void)
166 return NtCurrentTeb()->Peb->BeingDebugged;
170 static LONG WINAPI debug_exception_handler( EXCEPTION_POINTERS *eptr )
172 EXCEPTION_RECORD *rec = eptr->ExceptionRecord;
173 return (rec->ExceptionCode == DBG_PRINTEXCEPTION_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
176 /***********************************************************************
177 * OutputDebugStringA (kernelbase.@)
179 void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str )
181 static HANDLE DBWinMutex = NULL;
182 static BOOL mutex_inited = FALSE;
183 BOOL caught_by_dbg = TRUE;
185 if (!str) str = "";
186 WARN( "%s\n", debugstr_a(str) );
188 /* raise exception, WaitForDebugEvent() will generate a corresponding debug event */
189 __TRY
191 ULONG_PTR args[2];
192 args[0] = strlen(str) + 1;
193 args[1] = (ULONG_PTR)str;
194 RaiseException( DBG_PRINTEXCEPTION_C, 0, 2, args );
196 __EXCEPT(debug_exception_handler)
198 caught_by_dbg = FALSE;
200 __ENDTRY
201 if (caught_by_dbg) return;
203 /* send string to a system-wide monitor */
204 if (!mutex_inited)
206 /* first call to OutputDebugString, initialize mutex handle */
207 HANDLE mutex = CreateMutexExW( NULL, L"DBWinMutex", 0, SYNCHRONIZE );
208 if (mutex)
210 if (InterlockedCompareExchangePointer( &DBWinMutex, mutex, 0 ) != 0)
211 /* someone beat us here... */
212 CloseHandle( mutex );
214 mutex_inited = TRUE;
217 if (DBWinMutex)
219 HANDLE mapping;
221 mapping = OpenFileMappingW( FILE_MAP_WRITE, FALSE, L"DBWIN_BUFFER" );
222 if (mapping)
224 LPVOID buffer;
225 HANDLE eventbuffer, eventdata;
227 buffer = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
228 eventbuffer = OpenEventW( SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY" );
229 eventdata = OpenEventW( EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY" );
231 if (buffer && eventbuffer && eventdata)
233 /* monitor is present, synchronize with other OutputDebugString invocations */
234 WaitForSingleObject( DBWinMutex, INFINITE );
236 /* acquire control over the buffer */
237 if (WaitForSingleObject( eventbuffer, 10000 ) == WAIT_OBJECT_0)
239 int str_len = strlen( str );
240 struct _mon_buffer_t
242 DWORD pid;
243 char buffer[1];
244 } *mon_buffer = (struct _mon_buffer_t*) buffer;
246 if (str_len > (4096 - sizeof(DWORD) - 1)) str_len = 4096 - sizeof(DWORD) - 1;
247 mon_buffer->pid = GetCurrentProcessId();
248 memcpy( mon_buffer->buffer, str, str_len );
249 mon_buffer->buffer[str_len] = 0;
251 /* signal data ready */
252 SetEvent( eventdata );
254 ReleaseMutex( DBWinMutex );
257 if (buffer) UnmapViewOfFile( buffer );
258 if (eventbuffer) CloseHandle( eventbuffer );
259 if (eventdata) CloseHandle( eventdata );
260 CloseHandle( mapping );
266 /***********************************************************************
267 * OutputDebugStringW (kernelbase.@)
269 void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str )
271 UNICODE_STRING strW;
272 STRING strA;
274 RtlInitUnicodeString( &strW, str );
275 if (!RtlUnicodeStringToAnsiString( &strA, &strW, TRUE ))
277 OutputDebugStringA( strA.Buffer );
278 RtlFreeAnsiString( &strA );
283 /*******************************************************************
284 * RaiseException (kernelbase.@)
286 #if defined(__x86_64__)
287 /* Some DRMs depend on RaiseException not altering non-volatile registers. */
288 __ASM_GLOBAL_FUNC( RaiseException,
289 ".byte 0x48,0x8d,0xa4,0x24,0x00,0x00,0x00,0x00\n\t" /* hotpatch prolog */
290 "sub $0xc8,%rsp\n\t"
291 __ASM_SEH(".seh_stackalloc 0xc8\n\t")
292 __ASM_SEH(".seh_endprologue\n\t")
293 __ASM_CFI(".cfi_adjust_cfa_offset 0xc8\n\t")
294 "leaq 0x20(%rsp),%rax\n\t"
295 "movl %ecx,(%rax)\n\t" /* ExceptionCode */
296 "and $1,%edx\n\t"
297 "movl %edx,4(%rax)\n\t" /* ExceptionFlags */
298 "movq $0,8(%rax)\n\t" /* ExceptionRecord */
299 "leaq " __ASM_NAME("RaiseException") "(%rip),%rcx\n\t"
300 "movq %rcx,0x10(%rax)\n\t" /* ExceptionAddress */
301 "movq %rax,%rcx\n\t"
302 "movl $0,0x18(%rcx)\n\t" /* NumberParameters */
303 "testl %r8d,%r8d\n\t"
304 "jz 2f\n\t"
305 "testq %r9,%r9\n\t"
306 "jz 2f\n\t"
307 "movl $15,%edx\n\t"
308 "cmp %edx,%r8d\n\t"
309 "cmovb %r8d,%edx\n\t"
310 "movl %edx,0x18(%rcx)\n\t" /* NumberParameters */
311 "leaq 0x20(%rcx),%rax\n" /* ExceptionInformation */
312 "1:\tmovq (%r9),%r8\n\t"
313 "movq %r8,(%rax)\n\t"
314 "decl %edx\n\t"
315 "jz 2f\n\t"
316 "addq $8,%rax\n\t"
317 "addq $8,%r9\n\t"
318 "jmp 1b\n"
319 "2:\tcall " __ASM_NAME("RtlRaiseException") "\n\t"
320 "add $0xc8,%rsp\n\t"
321 __ASM_CFI(".cfi_adjust_cfa_offset -0xc8\n\t")
322 "ret" )
324 C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionCode) == 0 );
325 C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionFlags) == 4 );
326 C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionRecord) == 8 );
327 C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionAddress) == 0x10 );
328 C_ASSERT( offsetof(EXCEPTION_RECORD, NumberParameters) == 0x18 );
329 C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionInformation) == 0x20 );
330 #else
331 void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args )
333 EXCEPTION_RECORD record;
335 record.ExceptionCode = code;
336 record.ExceptionFlags = flags & EH_NONCONTINUABLE;
337 record.ExceptionRecord = NULL;
338 record.ExceptionAddress = RaiseException;
339 if (count && args)
341 if (count > EXCEPTION_MAXIMUM_PARAMETERS) count = EXCEPTION_MAXIMUM_PARAMETERS;
342 record.NumberParameters = count;
343 memcpy( record.ExceptionInformation, args, count * sizeof(*args) );
345 else record.NumberParameters = 0;
347 RtlRaiseException( &record );
349 #endif
350 __ASM_STDCALL_IMPORT(RaiseException,16)
352 /*******************************************************************
353 * RaiseFailFastException (kernelbase.@)
355 void WINAPI DECLSPEC_HOTPATCH RaiseFailFastException( EXCEPTION_RECORD *record, CONTEXT *context, DWORD flags )
357 FIXME( "(%p, %p, %ld) stub\n", record, context, flags );
358 TerminateProcess( GetCurrentProcess(), STATUS_FAIL_FAST_EXCEPTION );
361 /***********************************************************************
362 * SetUnhandledExceptionFilter (kernelbase.@)
364 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter(
365 LPTOP_LEVEL_EXCEPTION_FILTER filter )
367 return InterlockedExchangePointer( (void **)&top_filter, filter );
371 /*******************************************************************
372 * format_exception_msg
374 static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer, int size )
376 const EXCEPTION_RECORD *rec = ptr->ExceptionRecord;
377 int len;
379 switch(rec->ExceptionCode)
381 case EXCEPTION_INT_DIVIDE_BY_ZERO:
382 len = snprintf( buffer, size, "Unhandled division by zero" );
383 break;
384 case EXCEPTION_INT_OVERFLOW:
385 len = snprintf( buffer, size, "Unhandled overflow" );
386 break;
387 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
388 len = snprintf( buffer, size, "Unhandled array bounds" );
389 break;
390 case EXCEPTION_ILLEGAL_INSTRUCTION:
391 len = snprintf( buffer, size, "Unhandled illegal instruction" );
392 break;
393 case EXCEPTION_STACK_OVERFLOW:
394 len = snprintf( buffer, size, "Unhandled stack overflow" );
395 break;
396 case EXCEPTION_PRIV_INSTRUCTION:
397 len = snprintf( buffer, size, "Unhandled privileged instruction" );
398 break;
399 case EXCEPTION_ACCESS_VIOLATION:
400 if (rec->NumberParameters == 2)
401 len = snprintf( buffer, size, "Unhandled page fault on %s access to %p",
402 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
403 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
404 (void *)rec->ExceptionInformation[1]);
405 else
406 len = snprintf( buffer, size, "Unhandled page fault");
407 break;
408 case EXCEPTION_DATATYPE_MISALIGNMENT:
409 len = snprintf( buffer, size, "Unhandled alignment" );
410 break;
411 case CONTROL_C_EXIT:
412 len = snprintf( buffer, size, "Unhandled ^C");
413 break;
414 case STATUS_POSSIBLE_DEADLOCK:
415 len = snprintf( buffer, size, "Critical section %p wait failed",
416 (void *)rec->ExceptionInformation[0]);
417 break;
418 case EXCEPTION_WINE_STUB:
419 if ((ULONG_PTR)rec->ExceptionInformation[1] >> 16)
420 len = snprintf( buffer, size, "Unimplemented function %s.%s called",
421 (char *)rec->ExceptionInformation[0], (char *)rec->ExceptionInformation[1] );
422 else
423 len = snprintf( buffer, size, "Unimplemented function %s.%Id called",
424 (char *)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
425 break;
426 case EXCEPTION_WINE_ASSERTION:
427 len = snprintf( buffer, size, "Assertion failed" );
428 break;
429 default:
430 len = snprintf( buffer, size, "Unhandled exception 0x%08lx in thread %lx",
431 rec->ExceptionCode, GetCurrentThreadId());
432 break;
434 if (len < 0 || len >= size) return;
435 snprintf( buffer + len, size - len, " at address %p", ptr->ExceptionRecord->ExceptionAddress );
439 /******************************************************************
440 * start_debugger
442 * Does the effective debugger startup according to 'format'
444 static BOOL start_debugger( EXCEPTION_POINTERS *epointers, HANDLE event )
446 OBJECT_ATTRIBUTES attr;
447 UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" );
448 WCHAR *cmdline, *env, *p, *format = NULL;
449 HANDLE dbg_key;
450 DWORD autostart = TRUE;
451 PROCESS_INFORMATION info;
452 STARTUPINFOW startup;
453 BOOL ret = FALSE;
454 char buffer[256];
456 format_exception_msg( epointers, buffer, sizeof(buffer) );
457 MESSAGE( "wine: %s (thread %04lx), starting debugger...\n", buffer, GetCurrentThreadId() );
459 attr.Length = sizeof(attr);
460 attr.RootDirectory = 0;
461 attr.ObjectName = &nameW;
462 attr.Attributes = 0;
463 attr.SecurityDescriptor = NULL;
464 attr.SecurityQualityOfService = NULL;
466 if (!NtOpenKey( &dbg_key, KEY_READ, &attr ))
468 KEY_VALUE_PARTIAL_INFORMATION *info;
469 DWORD format_size = 0;
471 RtlInitUnicodeString( &nameW, L"Debugger" );
472 if (NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
473 NULL, 0, &format_size ) == STATUS_BUFFER_TOO_SMALL)
475 char *data = HeapAlloc( GetProcessHeap(), 0, format_size );
476 NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
477 data, format_size, &format_size );
478 info = (KEY_VALUE_PARTIAL_INFORMATION *)data;
479 format = HeapAlloc( GetProcessHeap(), 0, info->DataLength + sizeof(WCHAR) );
480 memcpy( format, info->Data, info->DataLength );
481 format[info->DataLength / sizeof(WCHAR)] = 0;
483 if (info->Type == REG_EXPAND_SZ)
485 WCHAR *tmp;
487 format_size = ExpandEnvironmentStringsW( format, NULL, 0 );
488 tmp = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR));
489 ExpandEnvironmentStringsW( format, tmp, format_size );
490 HeapFree( GetProcessHeap(), 0, format );
491 format = tmp;
493 HeapFree( GetProcessHeap(), 0, data );
496 RtlInitUnicodeString( &nameW, L"Auto" );
497 if (!NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
498 buffer, sizeof(buffer)-sizeof(WCHAR), &format_size ))
500 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
501 if (info->Type == REG_DWORD) memcpy( &autostart, info->Data, sizeof(DWORD) );
502 else if (info->Type == REG_SZ)
504 WCHAR *str = (WCHAR *)info->Data;
505 str[info->DataLength/sizeof(WCHAR)] = 0;
506 autostart = wcstol( str, NULL, 10 );
510 NtClose( dbg_key );
513 if (format)
515 size_t format_size = lstrlenW( format ) + 2*20;
516 cmdline = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR) );
517 swprintf( cmdline, format_size, format, GetCurrentProcessId(), HandleToLong(event) );
518 HeapFree( GetProcessHeap(), 0, format );
520 else
522 cmdline = HeapAlloc( GetProcessHeap(), 0, 80 * sizeof(WCHAR) );
523 swprintf( cmdline, 80, L"winedbg --auto %ld %ld", GetCurrentProcessId(), HandleToLong(event) );
526 if (!autostart)
528 HMODULE mod = GetModuleHandleA( "user32.dll" );
529 MessageBoxA_funcptr pMessageBoxA = NULL;
531 if (mod) pMessageBoxA = (void *)GetProcAddress( mod, "MessageBoxA" );
532 if (pMessageBoxA)
534 static const char msg[] = ".\nDo you wish to debug it?";
536 format_exception_msg( epointers, buffer, sizeof(buffer) - sizeof(msg) );
537 strcat( buffer, msg );
538 if (pMessageBoxA( 0, buffer, "Exception raised", MB_YESNO | MB_ICONHAND ) == IDNO)
540 TRACE( "Killing process\n" );
541 goto exit;
546 /* make WINEDEBUG empty in the environment */
547 env = GetEnvironmentStringsW();
548 if (!TRACE_ON(winedbg))
550 for (p = env; *p; p += lstrlenW(p) + 1)
552 if (!wcsncmp( p, L"WINEDEBUG=", 10 ))
554 WCHAR *next = p + lstrlenW(p);
555 WCHAR *end = next + 1;
556 while (*end) end += lstrlenW(end) + 1;
557 memmove( p + 10, next, end + 1 - next );
558 break;
563 TRACE( "Starting debugger %s\n", debugstr_w(cmdline) );
564 memset( &startup, 0, sizeof(startup) );
565 startup.cb = sizeof(startup);
566 startup.dwFlags = STARTF_USESHOWWINDOW;
567 startup.wShowWindow = SW_SHOWNORMAL;
568 ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, 0, env, NULL, &startup, &info );
569 FreeEnvironmentStringsW( env );
571 if (ret)
573 /* wait for debugger to come up... */
574 HANDLE handles[2];
575 CloseHandle( info.hThread );
576 handles[0] = event;
577 handles[1] = info.hProcess;
578 WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
579 CloseHandle( info.hProcess );
581 else ERR( "Couldn't start debugger %s (%ld)\n"
582 "Read the Wine Developers Guide on how to set up winedbg or another debugger\n",
583 debugstr_w(cmdline), GetLastError() );
584 exit:
585 HeapFree(GetProcessHeap(), 0, cmdline);
586 return ret;
589 /******************************************************************
590 * start_debugger_atomic
592 * starts the debugger in an atomic way:
593 * - either the debugger is not started and it is started
594 * - or the debugger has already been started by another thread
595 * - or the debugger couldn't be started
597 * returns TRUE for the two first conditions, FALSE for the last
599 static BOOL start_debugger_atomic( EXCEPTION_POINTERS *epointers )
601 static HANDLE once;
603 if (once == 0)
605 OBJECT_ATTRIBUTES attr;
606 HANDLE event;
608 attr.Length = sizeof(attr);
609 attr.RootDirectory = 0;
610 attr.Attributes = OBJ_INHERIT;
611 attr.ObjectName = NULL;
612 attr.SecurityDescriptor = NULL;
613 attr.SecurityQualityOfService = NULL;
615 /* ask for manual reset, so that once the debugger is started,
616 * every thread will know it */
617 NtCreateEvent( &event, EVENT_ALL_ACCESS, &attr, NotificationEvent, FALSE );
618 if (InterlockedCompareExchangePointer( &once, event, 0 ) == 0)
620 /* ok, our event has been set... we're the winning thread */
621 BOOL ret = start_debugger( epointers, once );
623 if (!ret)
625 /* so that the other threads won't be stuck */
626 NtSetEvent( once, NULL );
628 return ret;
631 /* someone beat us here... */
632 CloseHandle( event );
635 /* and wait for the winner to have actually created the debugger */
636 WaitForSingleObject( once, INFINITE );
637 /* in fact, here, we only know that someone has tried to start the debugger,
638 * we'll know by reposting the exception if it has actually attached
639 * to the current process */
640 return TRUE;
644 /*******************************************************************
645 * check_resource_write
647 * Check if the exception is a write attempt to the resource data.
648 * If yes, we unprotect the resources to let broken apps continue
649 * (Windows does this too).
651 static BOOL check_resource_write( void *addr )
653 DWORD old_prot;
654 void *rsrc;
655 DWORD size;
656 MEMORY_BASIC_INFORMATION info;
658 if (!VirtualQuery( addr, &info, sizeof(info) )) return FALSE;
659 if (info.State == MEM_FREE || !(info.Type & MEM_IMAGE)) return FALSE;
660 if (!(rsrc = RtlImageDirectoryEntryToData( info.AllocationBase, TRUE,
661 IMAGE_DIRECTORY_ENTRY_RESOURCE, &size )))
662 return FALSE;
663 if (addr < rsrc || (char *)addr >= (char *)rsrc + size) return FALSE;
664 TRACE( "Broken app is writing to the resource data, enabling work-around\n" );
665 VirtualProtect( rsrc, size, PAGE_READWRITE, &old_prot );
666 return TRUE;
670 /*******************************************************************
671 * UnhandledExceptionFilter (kernelbase.@)
673 LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers )
675 const EXCEPTION_RECORD *rec = epointers->ExceptionRecord;
677 if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && rec->NumberParameters >= 2)
679 switch (rec->ExceptionInformation[0])
681 case EXCEPTION_WRITE_FAULT:
682 if (check_resource_write( (void *)rec->ExceptionInformation[1] ))
683 return EXCEPTION_CONTINUE_EXECUTION;
684 break;
688 if (!NtCurrentTeb()->Peb->BeingDebugged)
690 if (rec->ExceptionCode == CONTROL_C_EXIT)
692 /* do not launch the debugger on ^C, simply terminate the process */
693 TerminateProcess( GetCurrentProcess(), 1 );
696 if (top_filter)
698 LONG ret = top_filter( epointers );
699 if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
702 /* FIXME: Should check the current error mode */
704 if (!start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged)
705 return EXCEPTION_EXECUTE_HANDLER;
707 return EXCEPTION_CONTINUE_SEARCH;
711 /***********************************************************************
712 * WerGetFlags (kernelbase.@)
714 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerGetFlags( HANDLE process, DWORD *flags )
716 FIXME( "(%p, %p) stub\n", process, flags );
717 return E_NOTIMPL;
721 /***********************************************************************
722 * WerRegisterFile (kernelbase.@)
724 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterFile( const WCHAR *file, WER_REGISTER_FILE_TYPE type,
725 DWORD flags )
727 FIXME( "(%s, %d, %ld) stub\n", debugstr_w(file), type, flags );
728 return E_NOTIMPL;
732 /***********************************************************************
733 * WerRegisterMemoryBlock (kernelbase.@)
735 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterMemoryBlock( void *block, DWORD size )
737 FIXME( "(%p %ld) stub\n", block, size );
738 return E_NOTIMPL;
742 /***********************************************************************
743 * WerRegisterRuntimeExceptionModule (kernelbase.@)
745 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterRuntimeExceptionModule( const WCHAR *dll, void *context )
747 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context );
748 return S_OK;
752 /***********************************************************************
753 * WerSetFlags (kernelbase.@)
755 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerSetFlags( DWORD flags )
757 FIXME("(%ld) stub\n", flags);
758 return S_OK;
762 /***********************************************************************
763 * WerUnregisterFile (kernelbase.@)
765 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterFile( const WCHAR *file )
767 FIXME( "(%s) stub\n", debugstr_w(file) );
768 return E_NOTIMPL;
772 /***********************************************************************
773 * WerUnregisterMemoryBlock (kernelbase.@)
775 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterMemoryBlock( void *block )
777 FIXME( "(%p) stub\n", block );
778 return E_NOTIMPL;
782 /***********************************************************************
783 * WerUnregisterRuntimeExceptionModule (kernelbase.@)
785 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterRuntimeExceptionModule( const WCHAR *dll, void *context )
787 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context );
788 return S_OK;
792 /***********************************************************************
793 * psapi functions
794 ***********************************************************************/
797 typedef struct _LDR_DATA_TABLE_ENTRY32
799 LIST_ENTRY32 InLoadOrderModuleList;
800 LIST_ENTRY32 InMemoryOrderModuleList;
801 LIST_ENTRY32 InInitializationOrderModuleList;
802 DWORD BaseAddress;
803 DWORD EntryPoint;
804 ULONG SizeOfImage;
805 UNICODE_STRING32 FullDllName;
806 UNICODE_STRING32 BaseDllName;
807 } LDR_DATA_TABLE_ENTRY32;
809 struct module_iterator
811 HANDLE process;
812 LIST_ENTRY *head;
813 LIST_ENTRY *current;
814 BOOL wow64;
815 LDR_DATA_TABLE_ENTRY ldr_module;
816 LDR_DATA_TABLE_ENTRY32 ldr_module32;
820 /* Caller must ensure that wow64=TRUE is only passed from 64bit for 'process' being a wow64 process */
821 static BOOL init_module_iterator( struct module_iterator *iter, HANDLE process, BOOL wow64 )
823 PROCESS_BASIC_INFORMATION pbi;
824 PPEB_LDR_DATA ldr_data;
826 /* get address of PEB */
827 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation,
828 &pbi, sizeof(pbi), NULL )))
829 return FALSE;
831 iter->wow64 = wow64;
832 if (wow64)
834 PEB_LDR_DATA32 *ldr_data32_ptr;
835 DWORD ldr_data32, first_module;
836 PEB32 *peb32;
838 peb32 = (PEB32 *)((char *)pbi.PebBaseAddress + 0x1000);
839 if (!ReadProcessMemory( process, &peb32->LdrData, &ldr_data32, sizeof(ldr_data32), NULL ))
840 return FALSE;
841 ldr_data32_ptr = (PEB_LDR_DATA32 *)(DWORD_PTR) ldr_data32;
842 if (!ReadProcessMemory( process, &ldr_data32_ptr->InLoadOrderModuleList.Flink,
843 &first_module, sizeof(first_module), NULL ))
844 return FALSE;
845 iter->head = (LIST_ENTRY *)&ldr_data32_ptr->InLoadOrderModuleList;
846 iter->current = (LIST_ENTRY *)(DWORD_PTR)first_module;
847 iter->process = process;
848 return TRUE;
851 /* read address of LdrData from PEB */
852 if (!ReadProcessMemory( process, &pbi.PebBaseAddress->LdrData, &ldr_data, sizeof(ldr_data), NULL ))
853 return FALSE;
855 /* This happens when running "old" wow64 configuration. Mark it as such. */
856 if (!ldr_data)
858 SetLastError( ERROR_EMPTY );
859 return FALSE;
861 /* read address of first module from LdrData */
862 if (!ReadProcessMemory( process, &ldr_data->InLoadOrderModuleList.Flink,
863 &iter->current, sizeof(iter->current), NULL ))
864 return FALSE;
866 iter->head = &ldr_data->InLoadOrderModuleList;
867 iter->process = process;
868 return TRUE;
872 static int module_iterator_next( struct module_iterator *iter )
874 if (iter->current == iter->head) return 0;
876 if (is_win64 && iter->wow64)
878 LIST_ENTRY32 *entry32 = (LIST_ENTRY32 *)iter->current;
880 if (!ReadProcessMemory( iter->process,
881 CONTAINING_RECORD(entry32, LDR_DATA_TABLE_ENTRY32, InLoadOrderModuleList),
882 &iter->ldr_module32, sizeof(iter->ldr_module32), NULL ))
883 return -1;
884 iter->current = (LIST_ENTRY *)(DWORD_PTR)iter->ldr_module32.InLoadOrderModuleList.Flink;
885 return 1;
888 if (!ReadProcessMemory( iter->process,
889 CONTAINING_RECORD(iter->current, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks),
890 &iter->ldr_module, sizeof(iter->ldr_module), NULL ))
891 return -1;
893 iter->current = iter->ldr_module.InLoadOrderLinks.Flink;
894 return 1;
898 static BOOL get_ldr_module( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY *ldr_module )
900 struct module_iterator iter;
901 INT ret;
903 if (!init_module_iterator( &iter, process, FALSE )) return FALSE;
905 while ((ret = module_iterator_next( &iter )) > 0)
906 /* When hModule is NULL we return the process image - which will be
907 * the first module since our iterator uses InLoadOrderModuleList */
908 if (!module || module == iter.ldr_module.DllBase)
910 *ldr_module = iter.ldr_module;
911 return TRUE;
914 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE );
915 return FALSE;
919 static BOOL get_ldr_module32( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY32 *ldr_module )
921 struct module_iterator iter;
922 INT ret;
924 #ifdef _WIN64
925 if ((ULONG_PTR)module >> 32)
927 SetLastError( ERROR_INVALID_HANDLE );
928 return FALSE;
930 #endif
931 if (!init_module_iterator( &iter, process, TRUE )) return FALSE;
933 while ((ret = module_iterator_next( &iter )) > 0)
934 /* When hModule is NULL we return the process image - which will be
935 * the first module since our iterator uses InLoadOrderModuleList */
936 if (!module || (DWORD)(DWORD_PTR)module == iter.ldr_module32.BaseAddress)
938 *ldr_module = iter.ldr_module32;
939 return TRUE;
942 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE );
943 return FALSE;
947 /***********************************************************************
948 * EmptyWorkingSet (kernelbase.@)
949 * K32EmptyWorkingSet (kernelbase.@)
951 BOOL WINAPI DECLSPEC_HOTPATCH EmptyWorkingSet( HANDLE process )
953 return SetProcessWorkingSetSizeEx( process, (SIZE_T)-1, (SIZE_T)-1, 0 );
957 /***********************************************************************
958 * EnumDeviceDrivers (kernelbase.@)
959 * K32EnumDeviceDrivers (kernelbase.@)
961 BOOL WINAPI EnumDeviceDrivers( void **image_base, DWORD count, DWORD *needed )
963 FIXME( "(%p, %ld, %p): stub\n", image_base, count, needed );
964 if (needed) *needed = 0;
965 return TRUE;
969 /***********************************************************************
970 * EnumPageFilesA (kernelbase.@)
971 * K32EnumPageFilesA (kernelbase.@)
973 BOOL WINAPI /* DECLSPEC_HOTPATCH */ EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, void *context )
975 FIXME( "(%p, %p) stub\n", callback, context );
976 return FALSE;
980 /***********************************************************************
981 * EnumPageFilesW (kernelbase.@)
982 * K32EnumPageFilesW (kernelbase.@)
984 BOOL WINAPI /* DECLSPEC_HOTPATCH */ EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, void *context )
986 FIXME( "(%p, %p) stub\n", callback, context );
987 return FALSE;
991 /***********************************************************************
992 * EnumProcessModules (kernelbase.@)
993 * K32EnumProcessModules (kernelbase.@)
995 BOOL WINAPI DECLSPEC_HOTPATCH EnumProcessModules( HANDLE process, HMODULE *module,
996 DWORD count, DWORD *needed )
998 return EnumProcessModulesEx( process, module, count, needed, LIST_MODULES_DEFAULT );
1002 struct module_push
1004 HMODULE *module;
1005 unsigned count;
1006 unsigned size;
1009 static void module_push( struct module_push *mp, HMODULE module )
1011 if (mp->count >= sizeof(HMODULE))
1013 *mp->module++ = module;
1014 mp->count -= sizeof(HMODULE);
1016 mp->size += sizeof(HMODULE);
1019 static void module_push_iter( struct module_push *mp, struct module_iterator *iter )
1021 if (is_win64 && iter->wow64)
1022 module_push( mp, (HMODULE) (DWORD_PTR)iter->ldr_module32.BaseAddress );
1023 else
1024 module_push( mp, iter->ldr_module.DllBase );
1027 static int module_push_all( struct module_push *mp, struct module_iterator *iter )
1029 int ret;
1031 while ((ret = module_iterator_next( iter )) > 0)
1032 module_push_iter( mp, iter );
1034 return ret;
1037 /***********************************************************************
1038 * EnumProcessModulesEx (kernelbase.@)
1039 * K32EnumProcessModulesEx (kernelbase.@)
1041 BOOL WINAPI EnumProcessModulesEx( HANDLE process, HMODULE *module, DWORD count,
1042 DWORD *needed, DWORD filter )
1044 struct module_push mp = {module, count, 0};
1045 unsigned list_mode;
1046 BOOL target_wow64;
1047 INT ret = 0;
1049 TRACE( "(%p, %p, %ld, %p, %ld)\n", process, module, count, needed, filter );
1051 if (process != GetCurrentProcess())
1053 if (!IsWow64Process( process, &target_wow64 )) return FALSE;
1055 else target_wow64 = is_wow64;
1057 if (filter & ~LIST_MODULES_ALL)
1059 SetLastError( ERROR_INVALID_PARAMETER );
1060 return FALSE;
1062 list_mode = filter & LIST_MODULES_ALL;
1063 /* Can't access 64bit process from (wow64) 32bit */
1064 if (is_wow64 && !target_wow64)
1066 SetLastError( ERROR_PARTIAL_COPY );
1067 return FALSE;
1069 if (count && !module)
1071 SetLastError( ERROR_NOACCESS );
1072 return FALSE;
1075 if (process == GetCurrentProcess())
1077 if (!(is_win64 && list_mode == LIST_MODULES_32BIT))
1079 PPEB_LDR_DATA ldr_data = NtCurrentTeb()->Peb->LdrData;
1080 PLIST_ENTRY head = &ldr_data->InLoadOrderModuleList;
1081 PLIST_ENTRY entry = head->Flink;
1083 while (entry != head)
1085 LDR_DATA_TABLE_ENTRY *ldr = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
1086 module_push( &mp, ldr->DllBase );
1087 entry = entry->Flink;
1091 else
1093 struct module_iterator iter;
1095 if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_32BIT))
1097 if (!init_module_iterator( &iter, process, TRUE ) || module_push_all( &mp, &iter ) < 0)
1098 return FALSE;
1100 if (!(is_win64 && list_mode == LIST_MODULES_32BIT))
1102 if (init_module_iterator( &iter, process, FALSE ))
1104 if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_64BIT))
1105 /* Don't add main module twice in _ALL mode */
1106 ret = module_iterator_next( &iter );
1107 if (ret >= 0) ret = module_push_all( &mp, &iter );
1109 else if (GetLastError() == ERROR_EMPTY)
1111 /* We're running on "old" wow configuration.
1112 * Fallback to PEB32 to get at least main module if requested.
1114 if (list_mode == LIST_MODULES_DEFAULT)
1116 if (init_module_iterator( &iter, process, TRUE ) && module_iterator_next( &iter ) > 0)
1117 module_push_iter( &mp, &iter );
1118 else
1119 ret = -1;
1122 else
1123 return FALSE;
1127 if (!needed)
1129 SetLastError( ERROR_NOACCESS );
1130 return FALSE;
1132 *needed = mp.size;
1133 return ret == 0;
1137 /***********************************************************************
1138 * EnumProcesses (kernelbase.@)
1139 * K32EnumProcesses (kernelbase.@)
1141 BOOL WINAPI EnumProcesses( DWORD *ids, DWORD count, DWORD *used )
1143 SYSTEM_PROCESS_INFORMATION *spi;
1144 ULONG size = 0x4000;
1145 void *buf = NULL;
1146 NTSTATUS status;
1150 size *= 2;
1151 HeapFree( GetProcessHeap(), 0, buf );
1152 if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
1153 status = NtQuerySystemInformation( SystemProcessInformation, buf, size, NULL );
1154 } while (status == STATUS_INFO_LENGTH_MISMATCH);
1156 if (!set_ntstatus( status ))
1158 HeapFree( GetProcessHeap(), 0, buf );
1159 return FALSE;
1161 spi = buf;
1162 for (*used = 0; count >= sizeof(DWORD); count -= sizeof(DWORD))
1164 *ids++ = HandleToUlong( spi->UniqueProcessId );
1165 *used += sizeof(DWORD);
1166 if (spi->NextEntryOffset == 0) break;
1167 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
1169 HeapFree( GetProcessHeap(), 0, buf );
1170 return TRUE;
1174 /***********************************************************************
1175 * GetDeviceDriverBaseNameA (kernelbase.@)
1176 * K32GetDeviceDriverBaseNameA (kernelbase.@)
1178 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverBaseNameA( void *image_base, char *name, DWORD size )
1180 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1181 if (name && size) name[0] = 0;
1182 return 0;
1186 /***********************************************************************
1187 * GetDeviceDriverBaseNameW (kernelbase.@)
1188 * K32GetDeviceDriverBaseNameW (kernelbase.@)
1190 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverBaseNameW( void *image_base, WCHAR *name, DWORD size )
1192 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1193 if (name && size) name[0] = 0;
1194 return 0;
1198 /***********************************************************************
1199 * GetDeviceDriverFileNameA (kernelbase.@)
1200 * K32GetDeviceDriverFileNameA (kernelbase.@)
1202 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverFileNameA( void *image_base, char *name, DWORD size )
1204 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1205 if (name && size) name[0] = 0;
1206 return 0;
1210 /***********************************************************************
1211 * GetDeviceDriverFileNameW (kernelbase.@)
1212 * K32GetDeviceDriverFileNameW (kernelbase.@)
1214 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverFileNameW( void *image_base, WCHAR *name, DWORD size )
1216 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1217 if (name && size) name[0] = 0;
1218 return 0;
1222 /***********************************************************************
1223 * GetMappedFileNameA (kernelbase.@)
1224 * K32GetMappedFileNameA (kernelbase.@)
1226 DWORD WINAPI DECLSPEC_HOTPATCH GetMappedFileNameA( HANDLE process, void *addr, char *name, DWORD size )
1228 WCHAR nameW[MAX_PATH];
1229 DWORD len;
1231 if (size && !name)
1233 SetLastError( ERROR_INVALID_PARAMETER );
1234 return 0;
1236 if (!GetMappedFileNameW( process, addr, nameW, MAX_PATH )) return 0;
1237 if (!size)
1239 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1240 return 0;
1242 len = file_name_WtoA( nameW, wcslen(nameW), name, size );
1243 name[min(len, size - 1)] = 0;
1244 return len;
1248 /***********************************************************************
1249 * GetMappedFileNameW (kernelbase.@)
1250 * K32GetMappedFileNameW (kernelbase.@)
1252 DWORD WINAPI DECLSPEC_HOTPATCH GetMappedFileNameW( HANDLE process, void *addr, WCHAR *name, DWORD size )
1254 ULONG_PTR buffer[(sizeof(MEMORY_SECTION_NAME) + MAX_PATH * sizeof(WCHAR)) / sizeof(ULONG_PTR)];
1255 MEMORY_SECTION_NAME *mem = (MEMORY_SECTION_NAME *)buffer;
1256 DWORD len;
1258 if (size && !name)
1260 SetLastError( ERROR_INVALID_PARAMETER );
1261 return 0;
1263 if (!set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryMappedFilenameInformation,
1264 mem, sizeof(buffer), NULL )))
1265 return 0;
1267 len = mem->SectionFileName.Length / sizeof(WCHAR);
1268 memcpy( name, mem->SectionFileName.Buffer, min( mem->SectionFileName.Length, size * sizeof(WCHAR) ));
1269 if (len >= size) SetLastError( ERROR_INSUFFICIENT_BUFFER );
1270 name[min(len, size - 1)] = 0;
1271 return len;
1275 /***********************************************************************
1276 * GetModuleBaseNameA (kernelbase.@)
1277 * K32GetModuleBaseNameA (kernelbase.@)
1279 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleBaseNameA( HANDLE process, HMODULE module,
1280 char *name, DWORD size )
1282 WCHAR *name_w;
1283 DWORD len, ret = 0;
1285 if (!name || !size)
1287 SetLastError( ERROR_INVALID_PARAMETER );
1288 return 0;
1290 if (!(name_w = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * size ))) return 0;
1292 len = GetModuleBaseNameW( process, module, name_w, size );
1293 TRACE( "%ld, %s\n", len, debugstr_w(name_w) );
1294 if (len)
1296 ret = WideCharToMultiByte( CP_ACP, 0, name_w, len, name, size, NULL, NULL );
1297 if (ret < size) name[ret] = 0;
1299 HeapFree( GetProcessHeap(), 0, name_w );
1300 return ret;
1304 /***********************************************************************
1305 * GetModuleBaseNameW (kernelbase.@)
1306 * K32GetModuleBaseNameW (kernelbase.@)
1308 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleBaseNameW( HANDLE process, HMODULE module,
1309 WCHAR *name, DWORD size )
1311 BOOL wow64, found = FALSE;
1313 if (!IsWow64Process( process, &wow64 )) return 0;
1315 if (is_win64 && wow64)
1317 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1319 if (get_ldr_module32(process, module, &ldr_module32))
1321 size = min( ldr_module32.BaseDllName.Length / sizeof(WCHAR), size );
1322 if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.BaseDllName.Buffer,
1323 name, size * sizeof(WCHAR), NULL ))
1324 found = TRUE;
1327 if (!found)
1329 LDR_DATA_TABLE_ENTRY ldr_module;
1331 if (!get_ldr_module( process, module, &ldr_module )) return 0;
1332 size = min( ldr_module.BaseDllName.Length / sizeof(WCHAR), size );
1333 if (!ReadProcessMemory( process, ldr_module.BaseDllName.Buffer,
1334 name, size * sizeof(WCHAR), NULL ))
1335 return 0;
1337 name[size] = 0;
1338 return size;
1342 /***********************************************************************
1343 * GetModuleFileNameExA (kernelbase.@)
1344 * K32GetModuleFileNameExA (kernelbase.@)
1346 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExA( HANDLE process, HMODULE module,
1347 char *name, DWORD size )
1349 WCHAR *ptr;
1350 DWORD len;
1352 TRACE( "(process=%p, module=%p, %p, %ld)\n", process, module, name, size );
1354 if (!name || !size)
1356 SetLastError( ERROR_INVALID_PARAMETER );
1357 return 0;
1359 if (process == GetCurrentProcess())
1361 len = GetModuleFileNameA( module, name, size );
1362 name[size - 1] = '\0';
1363 return len;
1366 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return 0;
1367 len = GetModuleFileNameExW( process, module, ptr, size );
1368 if (!len)
1370 name[0] = 0;
1372 else
1374 if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, name, size, NULL, NULL ))
1376 name[size - 1] = 0;
1377 len = size;
1379 else if (len < size) len = strlen( name );
1381 HeapFree( GetProcessHeap(), 0, ptr );
1382 return len;
1386 /***********************************************************************
1387 * GetModuleFileNameExW (kernelbase.@)
1388 * K32GetModuleFileNameExW (kernelbase.@)
1390 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExW( HANDLE process, HMODULE module,
1391 WCHAR *name, DWORD size )
1393 BOOL wow64, found = FALSE;
1394 DWORD len;
1396 if (!size) return 0;
1398 if (!IsWow64Process( process, &wow64 )) return 0;
1400 if (is_win64 && wow64)
1402 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1404 if (get_ldr_module32( process, module, &ldr_module32 ))
1406 len = ldr_module32.FullDllName.Length / sizeof(WCHAR);
1407 if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.FullDllName.Buffer,
1408 name, min( len, size ) * sizeof(WCHAR), NULL ))
1409 found = TRUE;
1412 if (!found)
1414 LDR_DATA_TABLE_ENTRY ldr_module;
1416 if (!get_ldr_module(process, module, &ldr_module)) return 0;
1417 len = ldr_module.FullDllName.Length / sizeof(WCHAR);
1418 if (!ReadProcessMemory( process, ldr_module.FullDllName.Buffer,
1419 name, min( len, size ) * sizeof(WCHAR), NULL ))
1420 return 0;
1423 if (len < size)
1425 name[len] = 0;
1426 return len;
1428 else
1430 name[size - 1] = 0;
1431 return size;
1436 /***********************************************************************
1437 * GetModuleInformation (kernelbase.@)
1438 * K32GetModuleInformation (kernelbase.@)
1440 BOOL WINAPI GetModuleInformation( HANDLE process, HMODULE module, MODULEINFO *modinfo, DWORD count )
1442 BOOL wow64, found = FALSE;
1444 if (count < sizeof(MODULEINFO))
1446 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1447 return FALSE;
1450 if (!IsWow64Process( process, &wow64 )) return FALSE;
1452 if (is_win64 && wow64)
1454 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1456 if (get_ldr_module32( process, module, &ldr_module32 ))
1458 modinfo->lpBaseOfDll = (void *)(DWORD_PTR)ldr_module32.BaseAddress;
1459 modinfo->SizeOfImage = ldr_module32.SizeOfImage;
1460 modinfo->EntryPoint = (void *)(DWORD_PTR)ldr_module32.EntryPoint;
1461 found = TRUE;
1464 if (!found)
1466 LDR_DATA_TABLE_ENTRY ldr_module;
1468 if (!get_ldr_module( process, module, &ldr_module )) return FALSE;
1469 modinfo->lpBaseOfDll = ldr_module.DllBase;
1470 modinfo->SizeOfImage = ldr_module.SizeOfImage;
1471 modinfo->EntryPoint = ldr_module.EntryPoint;
1473 return TRUE;
1477 /***********************************************************************
1478 * GetPerformanceInfo (kernelbase.@)
1479 * K32GetPerformanceInfo (kernelbase.@)
1481 BOOL WINAPI DECLSPEC_HOTPATCH GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
1483 SYSTEM_PERFORMANCE_INFORMATION perf;
1484 SYSTEM_BASIC_INFORMATION basic;
1485 SYSTEM_PROCESS_INFORMATION *process, *spi;
1486 DWORD info_size;
1487 NTSTATUS status;
1489 TRACE( "(%p, %ld)\n", info, size );
1491 if (size < sizeof(*info))
1493 SetLastError( ERROR_BAD_LENGTH );
1494 return FALSE;
1497 status = NtQuerySystemInformation( SystemPerformanceInformation, &perf, sizeof(perf), NULL );
1498 if (!set_ntstatus( status )) return FALSE;
1499 status = NtQuerySystemInformation( SystemBasicInformation, &basic, sizeof(basic), NULL );
1500 if (!set_ntstatus( status )) return FALSE;
1502 info->cb = sizeof(*info);
1503 info->CommitTotal = perf.TotalCommittedPages;
1504 info->CommitLimit = perf.TotalCommitLimit;
1505 info->CommitPeak = perf.PeakCommitment;
1506 info->PhysicalTotal = basic.MmNumberOfPhysicalPages;
1507 info->PhysicalAvailable = perf.AvailablePages;
1508 info->SystemCache = 0;
1509 info->KernelTotal = perf.PagedPoolUsage + perf.NonPagedPoolUsage;
1510 info->KernelPaged = perf.PagedPoolUsage;
1511 info->KernelNonpaged = perf.NonPagedPoolUsage;
1512 info->PageSize = basic.PageSize;
1514 /* fields from SYSTEM_PROCESS_INFORMATION */
1515 NtQuerySystemInformation( SystemProcessInformation, NULL, 0, &info_size );
1516 for (;;)
1518 process = HeapAlloc( GetProcessHeap(), 0, info_size );
1519 if (!process)
1521 SetLastError( ERROR_OUTOFMEMORY );
1522 return FALSE;
1524 status = NtQuerySystemInformation( SystemProcessInformation, process, info_size, &info_size );
1525 if (!status) break;
1526 HeapFree( GetProcessHeap(), 0, process );
1527 if (status != STATUS_INFO_LENGTH_MISMATCH)
1529 SetLastError( RtlNtStatusToDosError( status ) );
1530 return FALSE;
1533 info->HandleCount = info->ProcessCount = info->ThreadCount = 0;
1534 spi = process;
1535 for (;;)
1537 info->ProcessCount++;
1538 info->HandleCount += spi->HandleCount;
1539 info->ThreadCount += spi->dwThreadCount;
1540 if (spi->NextEntryOffset == 0) break;
1541 spi = (SYSTEM_PROCESS_INFORMATION *)((char *)spi + spi->NextEntryOffset);
1543 HeapFree( GetProcessHeap(), 0, process );
1544 return TRUE;
1548 /***********************************************************************
1549 * GetProcessImageFileNameA (kernelbase.@)
1550 * K32GetProcessImageFileNameA (kernelbase.@)
1552 DWORD WINAPI DECLSPEC_HOTPATCH GetProcessImageFileNameA( HANDLE process, char *file, DWORD size )
1554 return QueryFullProcessImageNameA( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0;
1558 /***********************************************************************
1559 * GetProcessImageFileNameW (kernelbase.@)
1560 * K32GetProcessImageFileNameW (kernelbase.@)
1562 DWORD WINAPI DECLSPEC_HOTPATCH GetProcessImageFileNameW( HANDLE process, WCHAR *file, DWORD size )
1564 return QueryFullProcessImageNameW( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0;
1568 /***********************************************************************
1569 * GetProcessMemoryInfo (kernelbase.@)
1570 * K32GetProcessMemoryInfo (kernelbase.@)
1572 BOOL WINAPI DECLSPEC_HOTPATCH GetProcessMemoryInfo( HANDLE process, PROCESS_MEMORY_COUNTERS *pmc,
1573 DWORD count )
1575 VM_COUNTERS vmc;
1577 if (count < sizeof(PROCESS_MEMORY_COUNTERS))
1579 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1580 return FALSE;
1583 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessVmCounters, &vmc, sizeof(vmc), NULL )))
1584 return FALSE;
1586 pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
1587 pmc->PageFaultCount = vmc.PageFaultCount;
1588 pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
1589 pmc->WorkingSetSize = vmc.WorkingSetSize;
1590 pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
1591 pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
1592 pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
1593 pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
1594 pmc->PagefileUsage = vmc.PagefileUsage;
1595 pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
1596 return TRUE;
1600 /***********************************************************************
1601 * GetWsChanges (kernelbase.@)
1602 * K32GetWsChanges (kernelbase.@)
1604 BOOL WINAPI DECLSPEC_HOTPATCH GetWsChanges( HANDLE process, PSAPI_WS_WATCH_INFORMATION *info, DWORD size )
1606 TRACE( "(%p, %p, %ld)\n", process, info, size );
1607 return set_ntstatus( NtQueryInformationProcess( process, ProcessWorkingSetWatch, info, size, NULL ));
1611 /***********************************************************************
1612 * GetWsChangesEx (kernelbase.@)
1613 * K32GetWsChangesEx (kernelbase.@)
1615 BOOL WINAPI DECLSPEC_HOTPATCH GetWsChangesEx( HANDLE process, PSAPI_WS_WATCH_INFORMATION_EX *info,
1616 DWORD *size )
1618 FIXME( "(%p, %p, %p)\n", process, info, size );
1619 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1620 return FALSE;
1624 /***********************************************************************
1625 * InitializeProcessForWsWatch (kernelbase.@)
1626 * K32InitializeProcessForWsWatch (kernelbase.@)
1628 BOOL WINAPI /* DECLSPEC_HOTPATCH */ InitializeProcessForWsWatch( HANDLE process )
1630 FIXME( "(process=%p): stub\n", process );
1631 return TRUE;
1635 /***********************************************************************
1636 * QueryWorkingSet (kernelbase.@)
1637 * K32QueryWorkingSet (kernelbase.@)
1639 BOOL WINAPI DECLSPEC_HOTPATCH QueryWorkingSet( HANDLE process, void *buffer, DWORD size )
1641 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
1642 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetInformation,
1643 buffer, size, NULL ));
1647 /***********************************************************************
1648 * QueryWorkingSetEx (kernelbase.@)
1649 * K32QueryWorkingSetEx (kernelbase.@)
1651 BOOL WINAPI QueryWorkingSetEx( HANDLE process, void *buffer, DWORD size )
1653 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
1654 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetExInformation,
1655 buffer, size, NULL ));
1659 /******************************************************************
1660 * QueryFullProcessImageNameA (kernelbase.@)
1662 BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameA( HANDLE process, DWORD flags,
1663 char *name, DWORD *size )
1665 BOOL ret;
1666 DWORD sizeW = *size;
1667 WCHAR *nameW = HeapAlloc( GetProcessHeap(), 0, *size * sizeof(WCHAR) );
1669 ret = QueryFullProcessImageNameW( process, flags, nameW, &sizeW );
1670 if (ret) ret = (WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, *size, NULL, NULL) > 0);
1671 if (ret) *size = strlen( name );
1672 HeapFree( GetProcessHeap(), 0, nameW );
1673 return ret;
1677 /******************************************************************
1678 * QueryFullProcessImageNameW (kernelbase.@)
1680 BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameW( HANDLE process, DWORD flags,
1681 WCHAR *name, DWORD *size )
1683 BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */
1684 UNICODE_STRING *dynamic_buffer = NULL;
1685 UNICODE_STRING *result = NULL;
1686 NTSTATUS status;
1687 DWORD needed;
1689 /* FIXME: Use ProcessImageFileName for the PROCESS_NAME_NATIVE case */
1690 status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, buffer,
1691 sizeof(buffer) - sizeof(WCHAR), &needed );
1692 if (status == STATUS_INFO_LENGTH_MISMATCH)
1694 dynamic_buffer = HeapAlloc( GetProcessHeap(), 0, needed + sizeof(WCHAR) );
1695 status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, dynamic_buffer,
1696 needed, &needed );
1697 result = dynamic_buffer;
1699 else
1700 result = (UNICODE_STRING *)buffer;
1702 if (status) goto cleanup;
1704 if (flags & PROCESS_NAME_NATIVE && result->Length > 2 * sizeof(WCHAR))
1706 WCHAR drive[3];
1707 WCHAR device[1024];
1708 DWORD ntlen, devlen;
1710 if (result->Buffer[1] != ':' || result->Buffer[0] < 'A' || result->Buffer[0] > 'Z')
1712 /* We cannot convert it to an NT device path so fail */
1713 status = STATUS_NO_SUCH_DEVICE;
1714 goto cleanup;
1717 /* Find this drive's NT device path */
1718 drive[0] = result->Buffer[0];
1719 drive[1] = ':';
1720 drive[2] = 0;
1721 if (!QueryDosDeviceW(drive, device, ARRAY_SIZE(device)))
1723 status = STATUS_NO_SUCH_DEVICE;
1724 goto cleanup;
1727 devlen = lstrlenW(device);
1728 ntlen = devlen + (result->Length/sizeof(WCHAR) - 2);
1729 if (ntlen + 1 > *size)
1731 status = STATUS_BUFFER_TOO_SMALL;
1732 goto cleanup;
1734 *size = ntlen;
1736 memcpy( name, device, devlen * sizeof(*device) );
1737 memcpy( name + devlen, result->Buffer + 2, result->Length - 2 * sizeof(WCHAR) );
1738 name[*size] = 0;
1739 TRACE( "NT path: %s\n", debugstr_w(name) );
1741 else
1743 if (result->Length/sizeof(WCHAR) + 1 > *size)
1745 status = STATUS_BUFFER_TOO_SMALL;
1746 goto cleanup;
1749 *size = result->Length/sizeof(WCHAR);
1750 memcpy( name, result->Buffer, result->Length );
1751 name[*size] = 0;
1754 cleanup:
1755 HeapFree( GetProcessHeap(), 0, dynamic_buffer );
1756 return set_ntstatus( status );