uiautomationcore: Add support for UIA_ProviderDescriptionPropertyId.
[wine.git] / dlls / kernelbase / debug.c
blob4eff7ad1ccaf28e4cd6ebeecd14ef25507e10ec8
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 void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args )
288 EXCEPTION_RECORD record;
290 record.ExceptionCode = code;
291 record.ExceptionFlags = flags & EH_NONCONTINUABLE;
292 record.ExceptionRecord = NULL;
293 record.ExceptionAddress = RaiseException;
294 if (count && args)
296 if (count > EXCEPTION_MAXIMUM_PARAMETERS) count = EXCEPTION_MAXIMUM_PARAMETERS;
297 record.NumberParameters = count;
298 memcpy( record.ExceptionInformation, args, count * sizeof(*args) );
300 else record.NumberParameters = 0;
302 RtlRaiseException( &record );
304 __ASM_STDCALL_IMPORT(RaiseException,16)
306 /*******************************************************************
307 * RaiseFailFastException (kernelbase.@)
309 void WINAPI DECLSPEC_HOTPATCH RaiseFailFastException( EXCEPTION_RECORD *record, CONTEXT *context, DWORD flags )
311 FIXME( "(%p, %p, %ld) stub\n", record, context, flags );
312 TerminateProcess( GetCurrentProcess(), STATUS_FAIL_FAST_EXCEPTION );
315 /***********************************************************************
316 * SetUnhandledExceptionFilter (kernelbase.@)
318 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter(
319 LPTOP_LEVEL_EXCEPTION_FILTER filter )
321 return InterlockedExchangePointer( (void **)&top_filter, filter );
325 /*******************************************************************
326 * format_exception_msg
328 static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer, int size )
330 const EXCEPTION_RECORD *rec = ptr->ExceptionRecord;
331 int len;
333 switch(rec->ExceptionCode)
335 case EXCEPTION_INT_DIVIDE_BY_ZERO:
336 len = snprintf( buffer, size, "Unhandled division by zero" );
337 break;
338 case EXCEPTION_INT_OVERFLOW:
339 len = snprintf( buffer, size, "Unhandled overflow" );
340 break;
341 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
342 len = snprintf( buffer, size, "Unhandled array bounds" );
343 break;
344 case EXCEPTION_ILLEGAL_INSTRUCTION:
345 len = snprintf( buffer, size, "Unhandled illegal instruction" );
346 break;
347 case EXCEPTION_STACK_OVERFLOW:
348 len = snprintf( buffer, size, "Unhandled stack overflow" );
349 break;
350 case EXCEPTION_PRIV_INSTRUCTION:
351 len = snprintf( buffer, size, "Unhandled privileged instruction" );
352 break;
353 case EXCEPTION_ACCESS_VIOLATION:
354 if (rec->NumberParameters == 2)
355 len = snprintf( buffer, size, "Unhandled page fault on %s access to %p",
356 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
357 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
358 (void *)rec->ExceptionInformation[1]);
359 else
360 len = snprintf( buffer, size, "Unhandled page fault");
361 break;
362 case EXCEPTION_DATATYPE_MISALIGNMENT:
363 len = snprintf( buffer, size, "Unhandled alignment" );
364 break;
365 case CONTROL_C_EXIT:
366 len = snprintf( buffer, size, "Unhandled ^C");
367 break;
368 case STATUS_POSSIBLE_DEADLOCK:
369 len = snprintf( buffer, size, "Critical section %p wait failed",
370 (void *)rec->ExceptionInformation[0]);
371 break;
372 case EXCEPTION_WINE_STUB:
373 if ((ULONG_PTR)rec->ExceptionInformation[1] >> 16)
374 len = snprintf( buffer, size, "Unimplemented function %s.%s called",
375 (char *)rec->ExceptionInformation[0], (char *)rec->ExceptionInformation[1] );
376 else
377 len = snprintf( buffer, size, "Unimplemented function %s.%Id called",
378 (char *)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
379 break;
380 case EXCEPTION_WINE_ASSERTION:
381 len = snprintf( buffer, size, "Assertion failed" );
382 break;
383 default:
384 len = snprintf( buffer, size, "Unhandled exception 0x%08lx in thread %lx",
385 rec->ExceptionCode, GetCurrentThreadId());
386 break;
388 if (len < 0 || len >= size) return;
389 snprintf( buffer + len, size - len, " at address %p", ptr->ExceptionRecord->ExceptionAddress );
393 /******************************************************************
394 * start_debugger
396 * Does the effective debugger startup according to 'format'
398 static BOOL start_debugger( EXCEPTION_POINTERS *epointers, HANDLE event )
400 OBJECT_ATTRIBUTES attr;
401 UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" );
402 WCHAR *cmdline, *env, *p, *format = NULL;
403 HANDLE dbg_key;
404 DWORD autostart = TRUE;
405 PROCESS_INFORMATION info;
406 STARTUPINFOW startup;
407 BOOL ret = FALSE;
408 char buffer[256];
410 format_exception_msg( epointers, buffer, sizeof(buffer) );
411 MESSAGE( "wine: %s (thread %04lx), starting debugger...\n", buffer, GetCurrentThreadId() );
413 attr.Length = sizeof(attr);
414 attr.RootDirectory = 0;
415 attr.ObjectName = &nameW;
416 attr.Attributes = 0;
417 attr.SecurityDescriptor = NULL;
418 attr.SecurityQualityOfService = NULL;
420 if (!NtOpenKey( &dbg_key, KEY_READ, &attr ))
422 KEY_VALUE_PARTIAL_INFORMATION *info;
423 DWORD format_size = 0;
425 RtlInitUnicodeString( &nameW, L"Debugger" );
426 if (NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
427 NULL, 0, &format_size ) == STATUS_BUFFER_TOO_SMALL)
429 char *data = HeapAlloc( GetProcessHeap(), 0, format_size );
430 NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
431 data, format_size, &format_size );
432 info = (KEY_VALUE_PARTIAL_INFORMATION *)data;
433 format = HeapAlloc( GetProcessHeap(), 0, info->DataLength + sizeof(WCHAR) );
434 memcpy( format, info->Data, info->DataLength );
435 format[info->DataLength / sizeof(WCHAR)] = 0;
437 if (info->Type == REG_EXPAND_SZ)
439 WCHAR *tmp;
441 format_size = ExpandEnvironmentStringsW( format, NULL, 0 );
442 tmp = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR));
443 ExpandEnvironmentStringsW( format, tmp, format_size );
444 HeapFree( GetProcessHeap(), 0, format );
445 format = tmp;
447 HeapFree( GetProcessHeap(), 0, data );
450 RtlInitUnicodeString( &nameW, L"Auto" );
451 if (!NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
452 buffer, sizeof(buffer)-sizeof(WCHAR), &format_size ))
454 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
455 if (info->Type == REG_DWORD) memcpy( &autostart, info->Data, sizeof(DWORD) );
456 else if (info->Type == REG_SZ)
458 WCHAR *str = (WCHAR *)info->Data;
459 str[info->DataLength/sizeof(WCHAR)] = 0;
460 autostart = wcstol( str, NULL, 10 );
464 NtClose( dbg_key );
467 if (format)
469 size_t format_size = lstrlenW( format ) + 2*20;
470 cmdline = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR) );
471 swprintf( cmdline, format_size, format, GetCurrentProcessId(), HandleToLong(event) );
472 HeapFree( GetProcessHeap(), 0, format );
474 else
476 cmdline = HeapAlloc( GetProcessHeap(), 0, 80 * sizeof(WCHAR) );
477 swprintf( cmdline, 80, L"winedbg --auto %ld %ld", GetCurrentProcessId(), HandleToLong(event) );
480 if (!autostart)
482 HMODULE mod = GetModuleHandleA( "user32.dll" );
483 MessageBoxA_funcptr pMessageBoxA = NULL;
485 if (mod) pMessageBoxA = (void *)GetProcAddress( mod, "MessageBoxA" );
486 if (pMessageBoxA)
488 static const char msg[] = ".\nDo you wish to debug it?";
490 format_exception_msg( epointers, buffer, sizeof(buffer) - sizeof(msg) );
491 strcat( buffer, msg );
492 if (pMessageBoxA( 0, buffer, "Exception raised", MB_YESNO | MB_ICONHAND ) == IDNO)
494 TRACE( "Killing process\n" );
495 goto exit;
500 /* make WINEDEBUG empty in the environment */
501 env = GetEnvironmentStringsW();
502 if (!TRACE_ON(winedbg))
504 for (p = env; *p; p += lstrlenW(p) + 1)
506 if (!wcsncmp( p, L"WINEDEBUG=", 10 ))
508 WCHAR *next = p + lstrlenW(p);
509 WCHAR *end = next + 1;
510 while (*end) end += lstrlenW(end) + 1;
511 memmove( p + 10, next, end + 1 - next );
512 break;
517 TRACE( "Starting debugger %s\n", debugstr_w(cmdline) );
518 memset( &startup, 0, sizeof(startup) );
519 startup.cb = sizeof(startup);
520 startup.dwFlags = STARTF_USESHOWWINDOW;
521 startup.wShowWindow = SW_SHOWNORMAL;
522 ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, 0, env, NULL, &startup, &info );
523 FreeEnvironmentStringsW( env );
525 if (ret)
527 /* wait for debugger to come up... */
528 HANDLE handles[2];
529 CloseHandle( info.hThread );
530 handles[0] = event;
531 handles[1] = info.hProcess;
532 WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
533 CloseHandle( info.hProcess );
535 else ERR( "Couldn't start debugger %s (%ld)\n"
536 "Read the Wine Developers Guide on how to set up winedbg or another debugger\n",
537 debugstr_w(cmdline), GetLastError() );
538 exit:
539 HeapFree(GetProcessHeap(), 0, cmdline);
540 return ret;
543 /******************************************************************
544 * start_debugger_atomic
546 * starts the debugger in an atomic way:
547 * - either the debugger is not started and it is started
548 * - or the debugger has already been started by another thread
549 * - or the debugger couldn't be started
551 * returns TRUE for the two first conditions, FALSE for the last
553 static BOOL start_debugger_atomic( EXCEPTION_POINTERS *epointers )
555 static HANDLE once;
557 if (once == 0)
559 OBJECT_ATTRIBUTES attr;
560 HANDLE event;
562 attr.Length = sizeof(attr);
563 attr.RootDirectory = 0;
564 attr.Attributes = OBJ_INHERIT;
565 attr.ObjectName = NULL;
566 attr.SecurityDescriptor = NULL;
567 attr.SecurityQualityOfService = NULL;
569 /* ask for manual reset, so that once the debugger is started,
570 * every thread will know it */
571 NtCreateEvent( &event, EVENT_ALL_ACCESS, &attr, NotificationEvent, FALSE );
572 if (InterlockedCompareExchangePointer( &once, event, 0 ) == 0)
574 /* ok, our event has been set... we're the winning thread */
575 BOOL ret = start_debugger( epointers, once );
577 if (!ret)
579 /* so that the other threads won't be stuck */
580 NtSetEvent( once, NULL );
582 return ret;
585 /* someone beat us here... */
586 CloseHandle( event );
589 /* and wait for the winner to have actually created the debugger */
590 WaitForSingleObject( once, INFINITE );
591 /* in fact, here, we only know that someone has tried to start the debugger,
592 * we'll know by reposting the exception if it has actually attached
593 * to the current process */
594 return TRUE;
598 /*******************************************************************
599 * check_resource_write
601 * Check if the exception is a write attempt to the resource data.
602 * If yes, we unprotect the resources to let broken apps continue
603 * (Windows does this too).
605 static BOOL check_resource_write( void *addr )
607 DWORD old_prot;
608 void *rsrc;
609 DWORD size;
610 MEMORY_BASIC_INFORMATION info;
612 if (!VirtualQuery( addr, &info, sizeof(info) )) return FALSE;
613 if (info.State == MEM_FREE || !(info.Type & MEM_IMAGE)) return FALSE;
614 if (!(rsrc = RtlImageDirectoryEntryToData( info.AllocationBase, TRUE,
615 IMAGE_DIRECTORY_ENTRY_RESOURCE, &size )))
616 return FALSE;
617 if (addr < rsrc || (char *)addr >= (char *)rsrc + size) return FALSE;
618 TRACE( "Broken app is writing to the resource data, enabling work-around\n" );
619 VirtualProtect( rsrc, size, PAGE_READWRITE, &old_prot );
620 return TRUE;
624 /*******************************************************************
625 * UnhandledExceptionFilter (kernelbase.@)
627 LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers )
629 const EXCEPTION_RECORD *rec = epointers->ExceptionRecord;
631 if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && rec->NumberParameters >= 2)
633 switch (rec->ExceptionInformation[0])
635 case EXCEPTION_WRITE_FAULT:
636 if (check_resource_write( (void *)rec->ExceptionInformation[1] ))
637 return EXCEPTION_CONTINUE_EXECUTION;
638 break;
642 if (!NtCurrentTeb()->Peb->BeingDebugged)
644 if (rec->ExceptionCode == CONTROL_C_EXIT)
646 /* do not launch the debugger on ^C, simply terminate the process */
647 TerminateProcess( GetCurrentProcess(), 1 );
650 if (top_filter)
652 LONG ret = top_filter( epointers );
653 if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
656 /* FIXME: Should check the current error mode */
658 if (!start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged)
659 return EXCEPTION_EXECUTE_HANDLER;
661 return EXCEPTION_CONTINUE_SEARCH;
665 /***********************************************************************
666 * WerGetFlags (kernelbase.@)
668 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerGetFlags( HANDLE process, DWORD *flags )
670 FIXME( "(%p, %p) stub\n", process, flags );
671 return E_NOTIMPL;
675 /***********************************************************************
676 * WerRegisterFile (kernelbase.@)
678 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterFile( const WCHAR *file, WER_REGISTER_FILE_TYPE type,
679 DWORD flags )
681 FIXME( "(%s, %d, %ld) stub\n", debugstr_w(file), type, flags );
682 return E_NOTIMPL;
686 /***********************************************************************
687 * WerRegisterMemoryBlock (kernelbase.@)
689 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterMemoryBlock( void *block, DWORD size )
691 FIXME( "(%p %ld) stub\n", block, size );
692 return E_NOTIMPL;
696 /***********************************************************************
697 * WerRegisterRuntimeExceptionModule (kernelbase.@)
699 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterRuntimeExceptionModule( const WCHAR *dll, void *context )
701 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context );
702 return S_OK;
706 /***********************************************************************
707 * WerSetFlags (kernelbase.@)
709 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerSetFlags( DWORD flags )
711 FIXME("(%ld) stub\n", flags);
712 return S_OK;
716 /***********************************************************************
717 * WerUnregisterFile (kernelbase.@)
719 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterFile( const WCHAR *file )
721 FIXME( "(%s) stub\n", debugstr_w(file) );
722 return E_NOTIMPL;
726 /***********************************************************************
727 * WerUnregisterMemoryBlock (kernelbase.@)
729 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterMemoryBlock( void *block )
731 FIXME( "(%p) stub\n", block );
732 return E_NOTIMPL;
736 /***********************************************************************
737 * WerUnregisterRuntimeExceptionModule (kernelbase.@)
739 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterRuntimeExceptionModule( const WCHAR *dll, void *context )
741 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context );
742 return S_OK;
746 /***********************************************************************
747 * psapi functions
748 ***********************************************************************/
751 typedef struct _LDR_DATA_TABLE_ENTRY32
753 LIST_ENTRY32 InLoadOrderModuleList;
754 LIST_ENTRY32 InMemoryOrderModuleList;
755 LIST_ENTRY32 InInitializationOrderModuleList;
756 DWORD BaseAddress;
757 DWORD EntryPoint;
758 ULONG SizeOfImage;
759 UNICODE_STRING32 FullDllName;
760 UNICODE_STRING32 BaseDllName;
761 } LDR_DATA_TABLE_ENTRY32;
763 struct module_iterator
765 HANDLE process;
766 LIST_ENTRY *head;
767 LIST_ENTRY *current;
768 BOOL wow64;
769 LDR_DATA_TABLE_ENTRY ldr_module;
770 LDR_DATA_TABLE_ENTRY32 ldr_module32;
774 /* Caller must ensure that wow64=TRUE is only passed from 64bit for 'process' being a wow64 process */
775 static BOOL init_module_iterator( struct module_iterator *iter, HANDLE process, BOOL wow64 )
777 PROCESS_BASIC_INFORMATION pbi;
778 PPEB_LDR_DATA ldr_data;
780 /* get address of PEB */
781 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation,
782 &pbi, sizeof(pbi), NULL )))
783 return FALSE;
785 iter->wow64 = wow64;
786 if (wow64)
788 PEB_LDR_DATA32 *ldr_data32_ptr;
789 DWORD ldr_data32, first_module;
790 PEB32 *peb32;
792 peb32 = (PEB32 *)((char *)pbi.PebBaseAddress + 0x1000);
793 if (!ReadProcessMemory( process, &peb32->LdrData, &ldr_data32, sizeof(ldr_data32), NULL ))
794 return FALSE;
795 ldr_data32_ptr = (PEB_LDR_DATA32 *)(DWORD_PTR) ldr_data32;
796 if (!ReadProcessMemory( process, &ldr_data32_ptr->InLoadOrderModuleList.Flink,
797 &first_module, sizeof(first_module), NULL ))
798 return FALSE;
799 iter->head = (LIST_ENTRY *)&ldr_data32_ptr->InLoadOrderModuleList;
800 iter->current = (LIST_ENTRY *)(DWORD_PTR)first_module;
801 iter->process = process;
802 return TRUE;
805 /* read address of LdrData from PEB */
806 if (!ReadProcessMemory( process, &pbi.PebBaseAddress->LdrData, &ldr_data, sizeof(ldr_data), NULL ))
807 return FALSE;
809 /* This happens when running "old" wow64 configuration. Mark it as such. */
810 if (!ldr_data)
812 SetLastError( ERROR_EMPTY );
813 return FALSE;
815 /* read address of first module from LdrData */
816 if (!ReadProcessMemory( process, &ldr_data->InLoadOrderModuleList.Flink,
817 &iter->current, sizeof(iter->current), NULL ))
818 return FALSE;
820 iter->head = &ldr_data->InLoadOrderModuleList;
821 iter->process = process;
822 return TRUE;
826 static int module_iterator_next( struct module_iterator *iter )
828 if (iter->current == iter->head) return 0;
830 if (is_win64 && iter->wow64)
832 LIST_ENTRY32 *entry32 = (LIST_ENTRY32 *)iter->current;
834 if (!ReadProcessMemory( iter->process,
835 CONTAINING_RECORD(entry32, LDR_DATA_TABLE_ENTRY32, InLoadOrderModuleList),
836 &iter->ldr_module32, sizeof(iter->ldr_module32), NULL ))
837 return -1;
838 iter->current = (LIST_ENTRY *)(DWORD_PTR)iter->ldr_module32.InLoadOrderModuleList.Flink;
839 return 1;
842 if (!ReadProcessMemory( iter->process,
843 CONTAINING_RECORD(iter->current, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks),
844 &iter->ldr_module, sizeof(iter->ldr_module), NULL ))
845 return -1;
847 iter->current = iter->ldr_module.InLoadOrderLinks.Flink;
848 return 1;
852 static BOOL get_ldr_module( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY *ldr_module )
854 struct module_iterator iter;
855 INT ret;
857 if (!init_module_iterator( &iter, process, FALSE )) return FALSE;
859 while ((ret = module_iterator_next( &iter )) > 0)
860 /* When hModule is NULL we return the process image - which will be
861 * the first module since our iterator uses InLoadOrderModuleList */
862 if (!module || module == iter.ldr_module.DllBase)
864 *ldr_module = iter.ldr_module;
865 return TRUE;
868 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE );
869 return FALSE;
873 static BOOL get_ldr_module32( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY32 *ldr_module )
875 struct module_iterator iter;
876 INT ret;
878 #ifdef _WIN64
879 if ((ULONG_PTR)module >> 32)
881 SetLastError( ERROR_INVALID_HANDLE );
882 return FALSE;
884 #endif
885 if (!init_module_iterator( &iter, process, TRUE )) return FALSE;
887 while ((ret = module_iterator_next( &iter )) > 0)
888 /* When hModule is NULL we return the process image - which will be
889 * the first module since our iterator uses InLoadOrderModuleList */
890 if (!module || (DWORD)(DWORD_PTR)module == iter.ldr_module32.BaseAddress)
892 *ldr_module = iter.ldr_module32;
893 return TRUE;
896 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE );
897 return FALSE;
901 /***********************************************************************
902 * EmptyWorkingSet (kernelbase.@)
903 * K32EmptyWorkingSet (kernelbase.@)
905 BOOL WINAPI DECLSPEC_HOTPATCH EmptyWorkingSet( HANDLE process )
907 return SetProcessWorkingSetSizeEx( process, (SIZE_T)-1, (SIZE_T)-1, 0 );
911 /***********************************************************************
912 * EnumDeviceDrivers (kernelbase.@)
913 * K32EnumDeviceDrivers (kernelbase.@)
915 BOOL WINAPI EnumDeviceDrivers( void **image_base, DWORD count, DWORD *needed )
917 FIXME( "(%p, %ld, %p): stub\n", image_base, count, needed );
918 if (needed) *needed = 0;
919 return TRUE;
923 /***********************************************************************
924 * EnumPageFilesA (kernelbase.@)
925 * K32EnumPageFilesA (kernelbase.@)
927 BOOL WINAPI /* DECLSPEC_HOTPATCH */ EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, void *context )
929 FIXME( "(%p, %p) stub\n", callback, context );
930 return FALSE;
934 /***********************************************************************
935 * EnumPageFilesW (kernelbase.@)
936 * K32EnumPageFilesW (kernelbase.@)
938 BOOL WINAPI /* DECLSPEC_HOTPATCH */ EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, void *context )
940 FIXME( "(%p, %p) stub\n", callback, context );
941 return FALSE;
945 /***********************************************************************
946 * EnumProcessModules (kernelbase.@)
947 * K32EnumProcessModules (kernelbase.@)
949 BOOL WINAPI DECLSPEC_HOTPATCH EnumProcessModules( HANDLE process, HMODULE *module,
950 DWORD count, DWORD *needed )
952 return EnumProcessModulesEx( process, module, count, needed, LIST_MODULES_DEFAULT );
956 struct module_push
958 HMODULE *module;
959 unsigned count;
960 unsigned size;
963 static void module_push( struct module_push *mp, HMODULE module )
965 if (mp->count >= sizeof(HMODULE))
967 *mp->module++ = module;
968 mp->count -= sizeof(HMODULE);
970 mp->size += sizeof(HMODULE);
973 static void module_push_iter( struct module_push *mp, struct module_iterator *iter )
975 if (is_win64 && iter->wow64)
976 module_push( mp, (HMODULE) (DWORD_PTR)iter->ldr_module32.BaseAddress );
977 else
978 module_push( mp, iter->ldr_module.DllBase );
981 static int module_push_all( struct module_push *mp, struct module_iterator *iter )
983 int ret;
985 while ((ret = module_iterator_next( iter )) > 0)
986 module_push_iter( mp, iter );
988 return ret;
991 /***********************************************************************
992 * EnumProcessModulesEx (kernelbase.@)
993 * K32EnumProcessModulesEx (kernelbase.@)
995 BOOL WINAPI EnumProcessModulesEx( HANDLE process, HMODULE *module, DWORD count,
996 DWORD *needed, DWORD filter )
998 struct module_push mp = {module, count, 0};
999 unsigned list_mode;
1000 BOOL target_wow64;
1001 INT ret = 0;
1003 TRACE( "(%p, %p, %ld, %p, %ld)\n", process, module, count, needed, filter );
1005 if (process != GetCurrentProcess())
1007 if (!IsWow64Process( process, &target_wow64 )) return FALSE;
1009 else target_wow64 = is_wow64;
1011 if (filter & ~LIST_MODULES_ALL)
1013 SetLastError( ERROR_INVALID_PARAMETER );
1014 return FALSE;
1016 list_mode = filter & LIST_MODULES_ALL;
1017 /* Can't access 64bit process from (wow64) 32bit */
1018 if (is_wow64 && !target_wow64)
1020 SetLastError( ERROR_PARTIAL_COPY );
1021 return FALSE;
1023 if (count && !module)
1025 SetLastError( ERROR_NOACCESS );
1026 return FALSE;
1029 if (process == GetCurrentProcess())
1031 if (!(is_win64 && list_mode == LIST_MODULES_32BIT))
1033 PPEB_LDR_DATA ldr_data = NtCurrentTeb()->Peb->LdrData;
1034 PLIST_ENTRY head = &ldr_data->InLoadOrderModuleList;
1035 PLIST_ENTRY entry = head->Flink;
1037 while (entry != head)
1039 LDR_DATA_TABLE_ENTRY *ldr = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
1040 module_push( &mp, ldr->DllBase );
1041 entry = entry->Flink;
1045 else
1047 struct module_iterator iter;
1049 if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_32BIT))
1051 if (!init_module_iterator( &iter, process, TRUE ) || module_push_all( &mp, &iter ) < 0)
1052 return FALSE;
1054 if (!(is_win64 && list_mode == LIST_MODULES_32BIT))
1056 if (init_module_iterator( &iter, process, FALSE ))
1058 if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_64BIT))
1059 /* Don't add main module twice in _ALL mode */
1060 ret = module_iterator_next( &iter );
1061 if (ret >= 0) ret = module_push_all( &mp, &iter );
1063 else if (GetLastError() == ERROR_EMPTY)
1065 /* We're running on "old" wow configuration.
1066 * Fallback to PEB32 to get at least main module if requested.
1068 if (list_mode == LIST_MODULES_DEFAULT)
1070 if (init_module_iterator( &iter, process, TRUE ) && module_iterator_next( &iter ) > 0)
1071 module_push_iter( &mp, &iter );
1072 else
1073 ret = -1;
1076 else
1077 return FALSE;
1081 if (!needed)
1083 SetLastError( ERROR_NOACCESS );
1084 return FALSE;
1086 *needed = mp.size;
1087 return ret == 0;
1091 /***********************************************************************
1092 * EnumProcesses (kernelbase.@)
1093 * K32EnumProcesses (kernelbase.@)
1095 BOOL WINAPI EnumProcesses( DWORD *ids, DWORD count, DWORD *used )
1097 SYSTEM_PROCESS_INFORMATION *spi;
1098 ULONG size = 0x4000;
1099 void *buf = NULL;
1100 NTSTATUS status;
1104 size *= 2;
1105 HeapFree( GetProcessHeap(), 0, buf );
1106 if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
1107 status = NtQuerySystemInformation( SystemProcessInformation, buf, size, NULL );
1108 } while (status == STATUS_INFO_LENGTH_MISMATCH);
1110 if (!set_ntstatus( status ))
1112 HeapFree( GetProcessHeap(), 0, buf );
1113 return FALSE;
1115 spi = buf;
1116 for (*used = 0; count >= sizeof(DWORD); count -= sizeof(DWORD))
1118 *ids++ = HandleToUlong( spi->UniqueProcessId );
1119 *used += sizeof(DWORD);
1120 if (spi->NextEntryOffset == 0) break;
1121 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
1123 HeapFree( GetProcessHeap(), 0, buf );
1124 return TRUE;
1128 /***********************************************************************
1129 * GetDeviceDriverBaseNameA (kernelbase.@)
1130 * K32GetDeviceDriverBaseNameA (kernelbase.@)
1132 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverBaseNameA( void *image_base, char *name, DWORD size )
1134 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1135 if (name && size) name[0] = 0;
1136 return 0;
1140 /***********************************************************************
1141 * GetDeviceDriverBaseNameW (kernelbase.@)
1142 * K32GetDeviceDriverBaseNameW (kernelbase.@)
1144 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverBaseNameW( void *image_base, WCHAR *name, DWORD size )
1146 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1147 if (name && size) name[0] = 0;
1148 return 0;
1152 /***********************************************************************
1153 * GetDeviceDriverFileNameA (kernelbase.@)
1154 * K32GetDeviceDriverFileNameA (kernelbase.@)
1156 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverFileNameA( void *image_base, char *name, DWORD size )
1158 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1159 if (name && size) name[0] = 0;
1160 return 0;
1164 /***********************************************************************
1165 * GetDeviceDriverFileNameW (kernelbase.@)
1166 * K32GetDeviceDriverFileNameW (kernelbase.@)
1168 DWORD WINAPI DECLSPEC_HOTPATCH GetDeviceDriverFileNameW( void *image_base, WCHAR *name, DWORD size )
1170 FIXME( "(%p, %p, %ld): stub\n", image_base, name, size );
1171 if (name && size) name[0] = 0;
1172 return 0;
1176 /***********************************************************************
1177 * GetMappedFileNameA (kernelbase.@)
1178 * K32GetMappedFileNameA (kernelbase.@)
1180 DWORD WINAPI DECLSPEC_HOTPATCH GetMappedFileNameA( HANDLE process, void *addr, char *name, DWORD size )
1182 WCHAR nameW[MAX_PATH];
1183 DWORD len;
1185 if (size && !name)
1187 SetLastError( ERROR_INVALID_PARAMETER );
1188 return 0;
1190 if (!GetMappedFileNameW( process, addr, nameW, MAX_PATH )) return 0;
1191 if (!size)
1193 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1194 return 0;
1196 len = file_name_WtoA( nameW, wcslen(nameW), name, size );
1197 name[min(len, size - 1)] = 0;
1198 return len;
1202 /***********************************************************************
1203 * GetMappedFileNameW (kernelbase.@)
1204 * K32GetMappedFileNameW (kernelbase.@)
1206 DWORD WINAPI DECLSPEC_HOTPATCH GetMappedFileNameW( HANDLE process, void *addr, WCHAR *name, DWORD size )
1208 ULONG_PTR buffer[(sizeof(MEMORY_SECTION_NAME) + MAX_PATH * sizeof(WCHAR)) / sizeof(ULONG_PTR)];
1209 MEMORY_SECTION_NAME *mem = (MEMORY_SECTION_NAME *)buffer;
1210 DWORD len;
1212 if (size && !name)
1214 SetLastError( ERROR_INVALID_PARAMETER );
1215 return 0;
1217 if (!set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryMappedFilenameInformation,
1218 mem, sizeof(buffer), NULL )))
1219 return 0;
1221 len = mem->SectionFileName.Length / sizeof(WCHAR);
1222 memcpy( name, mem->SectionFileName.Buffer, min( mem->SectionFileName.Length, size * sizeof(WCHAR) ));
1223 if (len >= size) SetLastError( ERROR_INSUFFICIENT_BUFFER );
1224 name[min(len, size - 1)] = 0;
1225 return len;
1229 /***********************************************************************
1230 * GetModuleBaseNameA (kernelbase.@)
1231 * K32GetModuleBaseNameA (kernelbase.@)
1233 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleBaseNameA( HANDLE process, HMODULE module,
1234 char *name, DWORD size )
1236 WCHAR *name_w;
1237 DWORD len, ret = 0;
1239 if (!name || !size)
1241 SetLastError( ERROR_INVALID_PARAMETER );
1242 return 0;
1244 if (!(name_w = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * size ))) return 0;
1246 len = GetModuleBaseNameW( process, module, name_w, size );
1247 TRACE( "%ld, %s\n", len, debugstr_w(name_w) );
1248 if (len)
1250 ret = WideCharToMultiByte( CP_ACP, 0, name_w, len, name, size, NULL, NULL );
1251 if (ret < size) name[ret] = 0;
1253 HeapFree( GetProcessHeap(), 0, name_w );
1254 return ret;
1258 /***********************************************************************
1259 * GetModuleBaseNameW (kernelbase.@)
1260 * K32GetModuleBaseNameW (kernelbase.@)
1262 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleBaseNameW( HANDLE process, HMODULE module,
1263 WCHAR *name, DWORD size )
1265 BOOL wow64, found = FALSE;
1267 if (!IsWow64Process( process, &wow64 )) return 0;
1269 if (is_win64 && wow64)
1271 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1273 if (get_ldr_module32(process, module, &ldr_module32))
1275 size = min( ldr_module32.BaseDllName.Length / sizeof(WCHAR), size );
1276 if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.BaseDllName.Buffer,
1277 name, size * sizeof(WCHAR), NULL ))
1278 found = TRUE;
1281 if (!found)
1283 LDR_DATA_TABLE_ENTRY ldr_module;
1285 if (!get_ldr_module( process, module, &ldr_module )) return 0;
1286 size = min( ldr_module.BaseDllName.Length / sizeof(WCHAR), size );
1287 if (!ReadProcessMemory( process, ldr_module.BaseDllName.Buffer,
1288 name, size * sizeof(WCHAR), NULL ))
1289 return 0;
1291 name[size] = 0;
1292 return size;
1296 /***********************************************************************
1297 * GetModuleFileNameExA (kernelbase.@)
1298 * K32GetModuleFileNameExA (kernelbase.@)
1300 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExA( HANDLE process, HMODULE module,
1301 char *name, DWORD size )
1303 WCHAR *ptr;
1304 DWORD len;
1306 TRACE( "(process=%p, module=%p, %p, %ld)\n", process, module, name, size );
1308 if (!name || !size)
1310 SetLastError( ERROR_INVALID_PARAMETER );
1311 return 0;
1313 if (process == GetCurrentProcess())
1315 len = GetModuleFileNameA( module, name, size );
1316 name[size - 1] = '\0';
1317 return len;
1320 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return 0;
1321 len = GetModuleFileNameExW( process, module, ptr, size );
1322 if (!len)
1324 name[0] = 0;
1326 else
1328 if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, name, size, NULL, NULL ))
1330 name[size - 1] = 0;
1331 len = size;
1333 else if (len < size) len = strlen( name );
1335 HeapFree( GetProcessHeap(), 0, ptr );
1336 return len;
1340 /***********************************************************************
1341 * GetModuleFileNameExW (kernelbase.@)
1342 * K32GetModuleFileNameExW (kernelbase.@)
1344 DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExW( HANDLE process, HMODULE module,
1345 WCHAR *name, DWORD size )
1347 BOOL wow64, found = FALSE;
1348 DWORD len;
1350 if (!size) return 0;
1352 if (!IsWow64Process( process, &wow64 )) return 0;
1354 if (is_win64 && wow64)
1356 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1358 if (get_ldr_module32( process, module, &ldr_module32 ))
1360 len = ldr_module32.FullDllName.Length / sizeof(WCHAR);
1361 if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.FullDllName.Buffer,
1362 name, min( len, size ) * sizeof(WCHAR), NULL ))
1363 found = TRUE;
1366 if (!found)
1368 LDR_DATA_TABLE_ENTRY ldr_module;
1370 if (!get_ldr_module(process, module, &ldr_module)) return 0;
1371 len = ldr_module.FullDllName.Length / sizeof(WCHAR);
1372 if (!ReadProcessMemory( process, ldr_module.FullDllName.Buffer,
1373 name, min( len, size ) * sizeof(WCHAR), NULL ))
1374 return 0;
1377 if (len < size)
1379 name[len] = 0;
1380 return len;
1382 else
1384 name[size - 1] = 0;
1385 return size;
1390 /***********************************************************************
1391 * GetModuleInformation (kernelbase.@)
1392 * K32GetModuleInformation (kernelbase.@)
1394 BOOL WINAPI GetModuleInformation( HANDLE process, HMODULE module, MODULEINFO *modinfo, DWORD count )
1396 BOOL wow64, found = FALSE;
1398 if (count < sizeof(MODULEINFO))
1400 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1401 return FALSE;
1404 if (!IsWow64Process( process, &wow64 )) return FALSE;
1406 if (is_win64 && wow64)
1408 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1410 if (get_ldr_module32( process, module, &ldr_module32 ))
1412 modinfo->lpBaseOfDll = (void *)(DWORD_PTR)ldr_module32.BaseAddress;
1413 modinfo->SizeOfImage = ldr_module32.SizeOfImage;
1414 modinfo->EntryPoint = (void *)(DWORD_PTR)ldr_module32.EntryPoint;
1415 found = TRUE;
1418 if (!found)
1420 LDR_DATA_TABLE_ENTRY ldr_module;
1422 if (!get_ldr_module( process, module, &ldr_module )) return FALSE;
1423 modinfo->lpBaseOfDll = ldr_module.DllBase;
1424 modinfo->SizeOfImage = ldr_module.SizeOfImage;
1425 modinfo->EntryPoint = ldr_module.EntryPoint;
1427 return TRUE;
1431 /***********************************************************************
1432 * GetPerformanceInfo (kernelbase.@)
1433 * K32GetPerformanceInfo (kernelbase.@)
1435 BOOL WINAPI DECLSPEC_HOTPATCH GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
1437 SYSTEM_PERFORMANCE_INFORMATION perf;
1438 SYSTEM_BASIC_INFORMATION basic;
1439 SYSTEM_PROCESS_INFORMATION *process, *spi;
1440 DWORD info_size;
1441 NTSTATUS status;
1443 TRACE( "(%p, %ld)\n", info, size );
1445 if (size < sizeof(*info))
1447 SetLastError( ERROR_BAD_LENGTH );
1448 return FALSE;
1451 status = NtQuerySystemInformation( SystemPerformanceInformation, &perf, sizeof(perf), NULL );
1452 if (!set_ntstatus( status )) return FALSE;
1453 status = NtQuerySystemInformation( SystemBasicInformation, &basic, sizeof(basic), NULL );
1454 if (!set_ntstatus( status )) return FALSE;
1456 info->cb = sizeof(*info);
1457 info->CommitTotal = perf.TotalCommittedPages;
1458 info->CommitLimit = perf.TotalCommitLimit;
1459 info->CommitPeak = perf.PeakCommitment;
1460 info->PhysicalTotal = basic.MmNumberOfPhysicalPages;
1461 info->PhysicalAvailable = perf.AvailablePages;
1462 info->SystemCache = 0;
1463 info->KernelTotal = perf.PagedPoolUsage + perf.NonPagedPoolUsage;
1464 info->KernelPaged = perf.PagedPoolUsage;
1465 info->KernelNonpaged = perf.NonPagedPoolUsage;
1466 info->PageSize = basic.PageSize;
1468 /* fields from SYSTEM_PROCESS_INFORMATION */
1469 NtQuerySystemInformation( SystemProcessInformation, NULL, 0, &info_size );
1470 for (;;)
1472 process = HeapAlloc( GetProcessHeap(), 0, info_size );
1473 if (!process)
1475 SetLastError( ERROR_OUTOFMEMORY );
1476 return FALSE;
1478 status = NtQuerySystemInformation( SystemProcessInformation, process, info_size, &info_size );
1479 if (!status) break;
1480 HeapFree( GetProcessHeap(), 0, process );
1481 if (status != STATUS_INFO_LENGTH_MISMATCH)
1483 SetLastError( RtlNtStatusToDosError( status ) );
1484 return FALSE;
1487 info->HandleCount = info->ProcessCount = info->ThreadCount = 0;
1488 spi = process;
1489 for (;;)
1491 info->ProcessCount++;
1492 info->HandleCount += spi->HandleCount;
1493 info->ThreadCount += spi->dwThreadCount;
1494 if (spi->NextEntryOffset == 0) break;
1495 spi = (SYSTEM_PROCESS_INFORMATION *)((char *)spi + spi->NextEntryOffset);
1497 HeapFree( GetProcessHeap(), 0, process );
1498 return TRUE;
1502 /***********************************************************************
1503 * GetProcessImageFileNameA (kernelbase.@)
1504 * K32GetProcessImageFileNameA (kernelbase.@)
1506 DWORD WINAPI DECLSPEC_HOTPATCH GetProcessImageFileNameA( HANDLE process, char *file, DWORD size )
1508 return QueryFullProcessImageNameA( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0;
1512 /***********************************************************************
1513 * GetProcessImageFileNameW (kernelbase.@)
1514 * K32GetProcessImageFileNameW (kernelbase.@)
1516 DWORD WINAPI DECLSPEC_HOTPATCH GetProcessImageFileNameW( HANDLE process, WCHAR *file, DWORD size )
1518 return QueryFullProcessImageNameW( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0;
1522 /***********************************************************************
1523 * GetProcessMemoryInfo (kernelbase.@)
1524 * K32GetProcessMemoryInfo (kernelbase.@)
1526 BOOL WINAPI DECLSPEC_HOTPATCH GetProcessMemoryInfo( HANDLE process, PROCESS_MEMORY_COUNTERS *pmc,
1527 DWORD count )
1529 VM_COUNTERS vmc;
1531 if (count < sizeof(PROCESS_MEMORY_COUNTERS))
1533 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1534 return FALSE;
1537 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessVmCounters, &vmc, sizeof(vmc), NULL )))
1538 return FALSE;
1540 pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
1541 pmc->PageFaultCount = vmc.PageFaultCount;
1542 pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
1543 pmc->WorkingSetSize = vmc.WorkingSetSize;
1544 pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
1545 pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
1546 pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
1547 pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
1548 pmc->PagefileUsage = vmc.PagefileUsage;
1549 pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
1550 return TRUE;
1554 /***********************************************************************
1555 * GetWsChanges (kernelbase.@)
1556 * K32GetWsChanges (kernelbase.@)
1558 BOOL WINAPI DECLSPEC_HOTPATCH GetWsChanges( HANDLE process, PSAPI_WS_WATCH_INFORMATION *info, DWORD size )
1560 TRACE( "(%p, %p, %ld)\n", process, info, size );
1561 return set_ntstatus( NtQueryInformationProcess( process, ProcessWorkingSetWatch, info, size, NULL ));
1565 /***********************************************************************
1566 * GetWsChangesEx (kernelbase.@)
1567 * K32GetWsChangesEx (kernelbase.@)
1569 BOOL WINAPI DECLSPEC_HOTPATCH GetWsChangesEx( HANDLE process, PSAPI_WS_WATCH_INFORMATION_EX *info,
1570 DWORD *size )
1572 FIXME( "(%p, %p, %p)\n", process, info, size );
1573 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1574 return FALSE;
1578 /***********************************************************************
1579 * InitializeProcessForWsWatch (kernelbase.@)
1580 * K32InitializeProcessForWsWatch (kernelbase.@)
1582 BOOL WINAPI /* DECLSPEC_HOTPATCH */ InitializeProcessForWsWatch( HANDLE process )
1584 FIXME( "(process=%p): stub\n", process );
1585 return TRUE;
1589 /***********************************************************************
1590 * QueryWorkingSet (kernelbase.@)
1591 * K32QueryWorkingSet (kernelbase.@)
1593 BOOL WINAPI DECLSPEC_HOTPATCH QueryWorkingSet( HANDLE process, void *buffer, DWORD size )
1595 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
1596 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetInformation,
1597 buffer, size, NULL ));
1601 /***********************************************************************
1602 * QueryWorkingSetEx (kernelbase.@)
1603 * K32QueryWorkingSetEx (kernelbase.@)
1605 BOOL WINAPI QueryWorkingSetEx( HANDLE process, void *buffer, DWORD size )
1607 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
1608 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetExInformation,
1609 buffer, size, NULL ));
1613 /******************************************************************
1614 * QueryFullProcessImageNameA (kernelbase.@)
1616 BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameA( HANDLE process, DWORD flags,
1617 char *name, DWORD *size )
1619 BOOL ret;
1620 DWORD sizeW = *size;
1621 WCHAR *nameW = HeapAlloc( GetProcessHeap(), 0, *size * sizeof(WCHAR) );
1623 ret = QueryFullProcessImageNameW( process, flags, nameW, &sizeW );
1624 if (ret) ret = (WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, *size, NULL, NULL) > 0);
1625 if (ret) *size = strlen( name );
1626 HeapFree( GetProcessHeap(), 0, nameW );
1627 return ret;
1631 /******************************************************************
1632 * QueryFullProcessImageNameW (kernelbase.@)
1634 BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameW( HANDLE process, DWORD flags,
1635 WCHAR *name, DWORD *size )
1637 BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */
1638 UNICODE_STRING *dynamic_buffer = NULL;
1639 UNICODE_STRING *result = NULL;
1640 NTSTATUS status;
1641 DWORD needed;
1643 /* FIXME: Use ProcessImageFileName for the PROCESS_NAME_NATIVE case */
1644 status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, buffer,
1645 sizeof(buffer) - sizeof(WCHAR), &needed );
1646 if (status == STATUS_INFO_LENGTH_MISMATCH)
1648 dynamic_buffer = HeapAlloc( GetProcessHeap(), 0, needed + sizeof(WCHAR) );
1649 status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, dynamic_buffer,
1650 needed, &needed );
1651 result = dynamic_buffer;
1653 else
1654 result = (UNICODE_STRING *)buffer;
1656 if (status) goto cleanup;
1658 if (flags & PROCESS_NAME_NATIVE && result->Length > 2 * sizeof(WCHAR))
1660 WCHAR drive[3];
1661 WCHAR device[1024];
1662 DWORD ntlen, devlen;
1664 if (result->Buffer[1] != ':' || result->Buffer[0] < 'A' || result->Buffer[0] > 'Z')
1666 /* We cannot convert it to an NT device path so fail */
1667 status = STATUS_NO_SUCH_DEVICE;
1668 goto cleanup;
1671 /* Find this drive's NT device path */
1672 drive[0] = result->Buffer[0];
1673 drive[1] = ':';
1674 drive[2] = 0;
1675 if (!QueryDosDeviceW(drive, device, ARRAY_SIZE(device)))
1677 status = STATUS_NO_SUCH_DEVICE;
1678 goto cleanup;
1681 devlen = lstrlenW(device);
1682 ntlen = devlen + (result->Length/sizeof(WCHAR) - 2);
1683 if (ntlen + 1 > *size)
1685 status = STATUS_BUFFER_TOO_SMALL;
1686 goto cleanup;
1688 *size = ntlen;
1690 memcpy( name, device, devlen * sizeof(*device) );
1691 memcpy( name + devlen, result->Buffer + 2, result->Length - 2 * sizeof(WCHAR) );
1692 name[*size] = 0;
1693 TRACE( "NT path: %s\n", debugstr_w(name) );
1695 else
1697 if (result->Length/sizeof(WCHAR) + 1 > *size)
1699 status = STATUS_BUFFER_TOO_SMALL;
1700 goto cleanup;
1703 *size = result->Length/sizeof(WCHAR);
1704 memcpy( name, result->Buffer, result->Length );
1705 name[*size] = 0;
1708 cleanup:
1709 HeapFree( GetProcessHeap(), 0, dynamic_buffer );
1710 return set_ntstatus( status );