quartz/tests: Fix a leak in test_fm2_enummatchingfilters().
[wine.git] / dlls / kernelbase / debug.c
blob6acdf0f1ea952643fb5db22b800801086354b15e
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>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #include "winnls.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "psapi.h"
33 #include "werapi.h"
35 #include "wine/exception.h"
36 #include "wine/server.h"
37 #include "wine/asm.h"
38 #include "kernelbase.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(seh);
42 WINE_DECLARE_DEBUG_CHANNEL(winedbg);
44 typedef INT (WINAPI *MessageBoxA_funcptr)(HWND,LPCSTR,LPCSTR,UINT);
45 typedef INT (WINAPI *MessageBoxW_funcptr)(HWND,LPCWSTR,LPCWSTR,UINT);
47 static PTOP_LEVEL_EXCEPTION_FILTER top_filter;
49 void *dummy = RtlUnwind; /* force importing RtlUnwind from ntdll */
51 /***********************************************************************
52 * CheckRemoteDebuggerPresent (kernelbase.@)
54 BOOL WINAPI DECLSPEC_HOTPATCH CheckRemoteDebuggerPresent( HANDLE process, BOOL *present )
56 DWORD_PTR port;
58 if (!process || !present)
60 SetLastError( ERROR_INVALID_PARAMETER );
61 return FALSE;
63 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessDebugPort, &port, sizeof(port), NULL )))
64 return FALSE;
65 *present = !!port;
66 return TRUE;
70 /**********************************************************************
71 * ContinueDebugEvent (kernelbase.@)
73 BOOL WINAPI DECLSPEC_HOTPATCH ContinueDebugEvent( DWORD pid, DWORD tid, DWORD status )
75 BOOL ret;
76 SERVER_START_REQ( continue_debug_event )
78 req->pid = pid;
79 req->tid = tid;
80 req->status = status;
81 ret = !wine_server_call_err( req );
83 SERVER_END_REQ;
84 return ret;
88 /**********************************************************************
89 * DebugActiveProcess (kernelbase.@)
91 BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcess( DWORD pid )
93 HANDLE process;
94 BOOL ret;
96 SERVER_START_REQ( debug_process )
98 req->pid = pid;
99 req->attach = 1;
100 ret = !wine_server_call_err( req );
102 SERVER_END_REQ;
103 if (!ret) return FALSE;
105 if (!(process = OpenProcess( PROCESS_CREATE_THREAD, FALSE, pid ))) return FALSE;
106 ret = set_ntstatus( DbgUiIssueRemoteBreakin( process ));
107 NtClose( process );
108 if (!ret) DebugActiveProcessStop( pid );
109 return ret;
113 /**********************************************************************
114 * DebugActiveProcessStop (kernelbase.@)
116 BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcessStop( DWORD pid )
118 BOOL ret;
120 SERVER_START_REQ( debug_process )
122 req->pid = pid;
123 req->attach = 0;
124 ret = !wine_server_call_err( req );
126 SERVER_END_REQ;
127 return ret;
131 /***********************************************************************
132 * DebugBreak (kernelbase.@)
134 #if defined(__i386__) || defined(__x86_64__)
135 __ASM_STDCALL_FUNC( DebugBreak, 0, "jmp " __ASM_STDCALL("DbgBreakPoint", 0) )
136 #else
137 void WINAPI DebugBreak(void)
139 DbgBreakPoint();
141 #endif
144 /**************************************************************************
145 * FatalAppExitA (kernelbase.@)
147 void WINAPI DECLSPEC_HOTPATCH FatalAppExitA( UINT action, LPCSTR str )
149 HMODULE mod = GetModuleHandleA( "user32.dll" );
150 MessageBoxA_funcptr pMessageBoxA = NULL;
152 if (mod) pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" );
153 if (pMessageBoxA) pMessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
154 else ERR( "%s\n", debugstr_a(str) );
155 RtlExitUserProcess( 1 );
159 /**************************************************************************
160 * FatalAppExitW (kernelbase.@)
162 void WINAPI DECLSPEC_HOTPATCH FatalAppExitW( UINT action, LPCWSTR str )
164 HMODULE mod = GetModuleHandleW( L"user32.dll" );
165 MessageBoxW_funcptr pMessageBoxW = NULL;
167 if (mod) pMessageBoxW = (MessageBoxW_funcptr)GetProcAddress( mod, "MessageBoxW" );
168 if (pMessageBoxW) pMessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
169 else ERR( "%s\n", debugstr_w(str) );
170 RtlExitUserProcess( 1 );
174 /***********************************************************************
175 * IsDebuggerPresent (kernelbase.@)
177 BOOL WINAPI IsDebuggerPresent(void)
179 return NtCurrentTeb()->Peb->BeingDebugged;
183 static LONG WINAPI debug_exception_handler( EXCEPTION_POINTERS *eptr )
185 EXCEPTION_RECORD *rec = eptr->ExceptionRecord;
186 return (rec->ExceptionCode == DBG_PRINTEXCEPTION_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
189 /***********************************************************************
190 * OutputDebugStringA (kernelbase.@)
192 void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str )
194 static HANDLE DBWinMutex = NULL;
195 static BOOL mutex_inited = FALSE;
196 BOOL caught_by_dbg = TRUE;
198 if (!str) str = "";
199 WARN( "%s\n", debugstr_a(str) );
201 /* raise exception, WaitForDebugEvent() will generate a corresponding debug event */
202 __TRY
204 ULONG_PTR args[2];
205 args[0] = strlen(str) + 1;
206 args[1] = (ULONG_PTR)str;
207 RaiseException( DBG_PRINTEXCEPTION_C, 0, 2, args );
209 __EXCEPT(debug_exception_handler)
211 caught_by_dbg = FALSE;
213 __ENDTRY
214 if (caught_by_dbg) return;
216 /* send string to a system-wide monitor */
217 if (!mutex_inited)
219 /* first call to OutputDebugString, initialize mutex handle */
220 HANDLE mutex = CreateMutexExW( NULL, L"DBWinMutex", 0, SYNCHRONIZE );
221 if (mutex)
223 if (InterlockedCompareExchangePointer( &DBWinMutex, mutex, 0 ) != 0)
224 /* someone beat us here... */
225 CloseHandle( mutex );
227 mutex_inited = TRUE;
230 if (DBWinMutex)
232 HANDLE mapping;
234 mapping = OpenFileMappingW( FILE_MAP_WRITE, FALSE, L"DBWIN_BUFFER" );
235 if (mapping)
237 LPVOID buffer;
238 HANDLE eventbuffer, eventdata;
240 buffer = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
241 eventbuffer = OpenEventW( SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY" );
242 eventdata = OpenEventW( EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY" );
244 if (buffer && eventbuffer && eventdata)
246 /* monitor is present, synchronize with other OutputDebugString invocations */
247 WaitForSingleObject( DBWinMutex, INFINITE );
249 /* acquire control over the buffer */
250 if (WaitForSingleObject( eventbuffer, 10000 ) == WAIT_OBJECT_0)
252 int str_len = strlen( str );
253 struct _mon_buffer_t
255 DWORD pid;
256 char buffer[1];
257 } *mon_buffer = (struct _mon_buffer_t*) buffer;
259 if (str_len > (4096 - sizeof(DWORD) - 1)) str_len = 4096 - sizeof(DWORD) - 1;
260 mon_buffer->pid = GetCurrentProcessId();
261 memcpy( mon_buffer->buffer, str, str_len );
262 mon_buffer->buffer[str_len] = 0;
264 /* signal data ready */
265 SetEvent( eventdata );
267 ReleaseMutex( DBWinMutex );
270 if (buffer) UnmapViewOfFile( buffer );
271 if (eventbuffer) CloseHandle( eventbuffer );
272 if (eventdata) CloseHandle( eventdata );
273 CloseHandle( mapping );
279 /***********************************************************************
280 * OutputDebugStringW (kernelbase.@)
282 void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str )
284 UNICODE_STRING strW;
285 STRING strA;
287 RtlInitUnicodeString( &strW, str );
288 if (!RtlUnicodeStringToAnsiString( &strA, &strW, TRUE ))
290 OutputDebugStringA( strA.Buffer );
291 RtlFreeAnsiString( &strA );
296 /*******************************************************************
297 * RaiseException (kernelbase.@)
299 void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args )
301 EXCEPTION_RECORD record;
303 record.ExceptionCode = code;
304 record.ExceptionFlags = flags & EH_NONCONTINUABLE;
305 record.ExceptionRecord = NULL;
306 record.ExceptionAddress = RaiseException;
307 if (count && args)
309 if (count > EXCEPTION_MAXIMUM_PARAMETERS) count = EXCEPTION_MAXIMUM_PARAMETERS;
310 record.NumberParameters = count;
311 memcpy( record.ExceptionInformation, args, count * sizeof(*args) );
313 else record.NumberParameters = 0;
315 RtlRaiseException( &record );
319 /***********************************************************************
320 * SetUnhandledExceptionFilter (kernelbase.@)
322 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter(
323 LPTOP_LEVEL_EXCEPTION_FILTER filter )
325 return InterlockedExchangePointer( (void **)&top_filter, filter );
329 /******************************************************************************
330 * WaitForDebugEvent (kernelbase.@)
332 BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEvent( DEBUG_EVENT *event, DWORD timeout )
334 BOOL ret;
335 DWORD res;
336 int i;
338 for (;;)
340 HANDLE wait = 0;
341 debug_event_t data;
342 SERVER_START_REQ( wait_debug_event )
344 req->get_handle = (timeout != 0);
345 wine_server_set_reply( req, &data, sizeof(data) );
346 if (!(ret = !wine_server_call_err( req ))) goto done;
348 if (!wine_server_reply_size( reply )) /* timeout */
350 wait = wine_server_ptr_handle( reply->wait );
351 ret = FALSE;
352 goto done;
354 event->dwDebugEventCode = data.code;
355 event->dwProcessId = (DWORD)reply->pid;
356 event->dwThreadId = (DWORD)reply->tid;
357 switch (data.code)
359 case EXCEPTION_DEBUG_EVENT:
360 if (data.exception.exc_code == DBG_PRINTEXCEPTION_C && data.exception.nb_params >= 2)
362 event->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
363 event->u.DebugString.lpDebugStringData = wine_server_get_ptr( data.exception.params[1] );
364 event->u.DebugString.fUnicode = FALSE;
365 event->u.DebugString.nDebugStringLength = data.exception.params[0];
366 break;
368 else if (data.exception.exc_code == DBG_RIPEXCEPTION && data.exception.nb_params >= 2)
370 event->dwDebugEventCode = RIP_EVENT;
371 event->u.RipInfo.dwError = data.exception.params[0];
372 event->u.RipInfo.dwType = data.exception.params[1];
373 break;
375 event->u.Exception.dwFirstChance = data.exception.first;
376 event->u.Exception.ExceptionRecord.ExceptionCode = data.exception.exc_code;
377 event->u.Exception.ExceptionRecord.ExceptionFlags = data.exception.flags;
378 event->u.Exception.ExceptionRecord.ExceptionRecord = wine_server_get_ptr( data.exception.record );
379 event->u.Exception.ExceptionRecord.ExceptionAddress = wine_server_get_ptr( data.exception.address );
380 event->u.Exception.ExceptionRecord.NumberParameters = data.exception.nb_params;
381 for (i = 0; i < data.exception.nb_params; i++)
382 event->u.Exception.ExceptionRecord.ExceptionInformation[i] = data.exception.params[i];
383 break;
384 case CREATE_THREAD_DEBUG_EVENT:
385 event->u.CreateThread.hThread = wine_server_ptr_handle( data.create_thread.handle );
386 event->u.CreateThread.lpThreadLocalBase = wine_server_get_ptr( data.create_thread.teb );
387 event->u.CreateThread.lpStartAddress = wine_server_get_ptr( data.create_thread.start );
388 break;
389 case CREATE_PROCESS_DEBUG_EVENT:
390 event->u.CreateProcessInfo.hFile = wine_server_ptr_handle( data.create_process.file );
391 event->u.CreateProcessInfo.hProcess = wine_server_ptr_handle( data.create_process.process );
392 event->u.CreateProcessInfo.hThread = wine_server_ptr_handle( data.create_process.thread );
393 event->u.CreateProcessInfo.lpBaseOfImage = wine_server_get_ptr( data.create_process.base );
394 event->u.CreateProcessInfo.dwDebugInfoFileOffset = data.create_process.dbg_offset;
395 event->u.CreateProcessInfo.nDebugInfoSize = data.create_process.dbg_size;
396 event->u.CreateProcessInfo.lpThreadLocalBase = wine_server_get_ptr( data.create_process.teb );
397 event->u.CreateProcessInfo.lpStartAddress = wine_server_get_ptr( data.create_process.start );
398 event->u.CreateProcessInfo.lpImageName = wine_server_get_ptr( data.create_process.name );
399 event->u.CreateProcessInfo.fUnicode = data.create_process.unicode;
400 break;
401 case EXIT_THREAD_DEBUG_EVENT:
402 event->u.ExitThread.dwExitCode = data.exit.exit_code;
403 break;
404 case EXIT_PROCESS_DEBUG_EVENT:
405 event->u.ExitProcess.dwExitCode = data.exit.exit_code;
406 break;
407 case LOAD_DLL_DEBUG_EVENT:
408 event->u.LoadDll.hFile = wine_server_ptr_handle( data.load_dll.handle );
409 event->u.LoadDll.lpBaseOfDll = wine_server_get_ptr( data.load_dll.base );
410 event->u.LoadDll.dwDebugInfoFileOffset = data.load_dll.dbg_offset;
411 event->u.LoadDll.nDebugInfoSize = data.load_dll.dbg_size;
412 event->u.LoadDll.lpImageName = wine_server_get_ptr( data.load_dll.name );
413 event->u.LoadDll.fUnicode = data.load_dll.unicode;
414 break;
415 case UNLOAD_DLL_DEBUG_EVENT:
416 event->u.UnloadDll.lpBaseOfDll = wine_server_get_ptr( data.unload_dll.base );
417 break;
419 done:
420 /* nothing */ ;
422 SERVER_END_REQ;
423 if (ret) return TRUE;
424 if (!wait) break;
425 res = WaitForSingleObject( wait, timeout );
426 CloseHandle( wait );
427 if (res != STATUS_WAIT_0) break;
429 SetLastError( ERROR_SEM_TIMEOUT );
430 return FALSE;
434 /*******************************************************************
435 * format_exception_msg
437 static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer, int size )
439 const EXCEPTION_RECORD *rec = ptr->ExceptionRecord;
440 int len;
442 switch(rec->ExceptionCode)
444 case EXCEPTION_INT_DIVIDE_BY_ZERO:
445 len = snprintf( buffer, size, "Unhandled division by zero" );
446 break;
447 case EXCEPTION_INT_OVERFLOW:
448 len = snprintf( buffer, size, "Unhandled overflow" );
449 break;
450 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
451 len = snprintf( buffer, size, "Unhandled array bounds" );
452 break;
453 case EXCEPTION_ILLEGAL_INSTRUCTION:
454 len = snprintf( buffer, size, "Unhandled illegal instruction" );
455 break;
456 case EXCEPTION_STACK_OVERFLOW:
457 len = snprintf( buffer, size, "Unhandled stack overflow" );
458 break;
459 case EXCEPTION_PRIV_INSTRUCTION:
460 len = snprintf( buffer, size, "Unhandled privileged instruction" );
461 break;
462 case EXCEPTION_ACCESS_VIOLATION:
463 if (rec->NumberParameters == 2)
464 len = snprintf( buffer, size, "Unhandled page fault on %s access to %p",
465 rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
466 rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
467 (void *)rec->ExceptionInformation[1]);
468 else
469 len = snprintf( buffer, size, "Unhandled page fault");
470 break;
471 case EXCEPTION_DATATYPE_MISALIGNMENT:
472 len = snprintf( buffer, size, "Unhandled alignment" );
473 break;
474 case CONTROL_C_EXIT:
475 len = snprintf( buffer, size, "Unhandled ^C");
476 break;
477 case STATUS_POSSIBLE_DEADLOCK:
478 len = snprintf( buffer, size, "Critical section %p wait failed",
479 (void *)rec->ExceptionInformation[0]);
480 break;
481 case EXCEPTION_WINE_STUB:
482 if ((ULONG_PTR)rec->ExceptionInformation[1] >> 16)
483 len = snprintf( buffer, size, "Unimplemented function %s.%s called",
484 (char *)rec->ExceptionInformation[0], (char *)rec->ExceptionInformation[1] );
485 else
486 len = snprintf( buffer, size, "Unimplemented function %s.%ld called",
487 (char *)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
488 break;
489 case EXCEPTION_WINE_ASSERTION:
490 len = snprintf( buffer, size, "Assertion failed" );
491 break;
492 default:
493 len = snprintf( buffer, size, "Unhandled exception 0x%08x in thread %x",
494 rec->ExceptionCode, GetCurrentThreadId());
495 break;
497 if (len < 0 || len >= size) return;
498 snprintf( buffer + len, size - len, " at address %p", ptr->ExceptionRecord->ExceptionAddress );
502 /******************************************************************
503 * start_debugger
505 * Does the effective debugger startup according to 'format'
507 static BOOL start_debugger( EXCEPTION_POINTERS *epointers, HANDLE event )
509 OBJECT_ATTRIBUTES attr;
510 UNICODE_STRING nameW;
511 WCHAR *cmdline, *env, *p, *format = NULL;
512 HANDLE dbg_key;
513 DWORD autostart = TRUE;
514 PROCESS_INFORMATION info;
515 STARTUPINFOW startup;
516 BOOL ret = FALSE;
517 char buffer[256];
519 format_exception_msg( epointers, buffer, sizeof(buffer) );
520 MESSAGE( "wine: %s (thread %04x), starting debugger...\n", buffer, GetCurrentThreadId() );
522 attr.Length = sizeof(attr);
523 attr.RootDirectory = 0;
524 attr.ObjectName = &nameW;
525 attr.Attributes = 0;
526 attr.SecurityDescriptor = NULL;
527 attr.SecurityQualityOfService = NULL;
528 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" );
530 if (!NtOpenKey( &dbg_key, KEY_READ, &attr ))
532 KEY_VALUE_PARTIAL_INFORMATION *info;
533 DWORD format_size = 0;
535 RtlInitUnicodeString( &nameW, L"Debugger" );
536 if (NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
537 NULL, 0, &format_size ) == STATUS_BUFFER_TOO_SMALL)
539 char *data = HeapAlloc( GetProcessHeap(), 0, format_size );
540 NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
541 data, format_size, &format_size );
542 info = (KEY_VALUE_PARTIAL_INFORMATION *)data;
543 format = HeapAlloc( GetProcessHeap(), 0, info->DataLength + sizeof(WCHAR) );
544 memcpy( format, info->Data, info->DataLength );
545 format[info->DataLength / sizeof(WCHAR)] = 0;
547 if (info->Type == REG_EXPAND_SZ)
549 WCHAR *tmp;
551 format_size = ExpandEnvironmentStringsW( format, NULL, 0 );
552 tmp = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR));
553 ExpandEnvironmentStringsW( format, tmp, format_size );
554 HeapFree( GetProcessHeap(), 0, format );
555 format = tmp;
557 HeapFree( GetProcessHeap(), 0, data );
560 RtlInitUnicodeString( &nameW, L"Auto" );
561 if (!NtQueryValueKey( dbg_key, &nameW, KeyValuePartialInformation,
562 buffer, sizeof(buffer)-sizeof(WCHAR), &format_size ))
564 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
565 if (info->Type == REG_DWORD) memcpy( &autostart, info->Data, sizeof(DWORD) );
566 else if (info->Type == REG_SZ)
568 WCHAR *str = (WCHAR *)info->Data;
569 str[info->DataLength/sizeof(WCHAR)] = 0;
570 autostart = wcstol( str, NULL, 10 );
574 NtClose( dbg_key );
577 if (format)
579 size_t format_size = lstrlenW( format ) + 2*20;
580 cmdline = HeapAlloc( GetProcessHeap(), 0, format_size * sizeof(WCHAR) );
581 swprintf( cmdline, format_size, format, (long)GetCurrentProcessId(), (long)HandleToLong(event) );
582 HeapFree( GetProcessHeap(), 0, format );
584 else
586 cmdline = HeapAlloc( GetProcessHeap(), 0, 80 * sizeof(WCHAR) );
587 swprintf( cmdline, 80, L"winedbg --auto %ld %ld", (long)GetCurrentProcessId(), (long)HandleToLong(event) );
590 if (!autostart)
592 HMODULE mod = GetModuleHandleA( "user32.dll" );
593 MessageBoxA_funcptr pMessageBoxA = NULL;
595 if (mod) pMessageBoxA = (void *)GetProcAddress( mod, "MessageBoxA" );
596 if (pMessageBoxA)
598 static const char msg[] = ".\nDo you wish to debug it?";
600 format_exception_msg( epointers, buffer, sizeof(buffer) - sizeof(msg) );
601 strcat( buffer, msg );
602 if (pMessageBoxA( 0, buffer, "Exception raised", MB_YESNO | MB_ICONHAND ) == IDNO)
604 TRACE( "Killing process\n" );
605 goto exit;
610 /* make WINEDEBUG empty in the environment */
611 env = GetEnvironmentStringsW();
612 if (!TRACE_ON(winedbg))
614 for (p = env; *p; p += lstrlenW(p) + 1)
616 if (!wcsncmp( p, L"WINEDEBUG=", 10 ))
618 WCHAR *next = p + lstrlenW(p);
619 WCHAR *end = next + 1;
620 while (*end) end += lstrlenW(end) + 1;
621 memmove( p + 10, next, end + 1 - next );
622 break;
627 TRACE( "Starting debugger %s\n", debugstr_w(cmdline) );
628 memset( &startup, 0, sizeof(startup) );
629 startup.cb = sizeof(startup);
630 startup.dwFlags = STARTF_USESHOWWINDOW;
631 startup.wShowWindow = SW_SHOWNORMAL;
632 ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, 0, env, NULL, &startup, &info );
633 FreeEnvironmentStringsW( env );
635 if (ret)
637 /* wait for debugger to come up... */
638 HANDLE handles[2];
639 CloseHandle( info.hThread );
640 handles[0] = event;
641 handles[1] = info.hProcess;
642 WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
643 CloseHandle( info.hProcess );
645 else ERR( "Couldn't start debugger %s (%d)\n"
646 "Read the Wine Developers Guide on how to set up winedbg or another debugger\n",
647 debugstr_w(cmdline), GetLastError() );
648 exit:
649 HeapFree(GetProcessHeap(), 0, cmdline);
650 return ret;
653 /******************************************************************
654 * start_debugger_atomic
656 * starts the debugger in an atomic way:
657 * - either the debugger is not started and it is started
658 * - or the debugger has already been started by another thread
659 * - or the debugger couldn't be started
661 * returns TRUE for the two first conditions, FALSE for the last
663 static BOOL start_debugger_atomic( EXCEPTION_POINTERS *epointers )
665 static HANDLE once;
667 if (once == 0)
669 OBJECT_ATTRIBUTES attr;
670 HANDLE event;
672 attr.Length = sizeof(attr);
673 attr.RootDirectory = 0;
674 attr.Attributes = OBJ_INHERIT;
675 attr.ObjectName = NULL;
676 attr.SecurityDescriptor = NULL;
677 attr.SecurityQualityOfService = NULL;
679 /* ask for manual reset, so that once the debugger is started,
680 * every thread will know it */
681 NtCreateEvent( &event, EVENT_ALL_ACCESS, &attr, NotificationEvent, FALSE );
682 if (InterlockedCompareExchangePointer( &once, event, 0 ) == 0)
684 /* ok, our event has been set... we're the winning thread */
685 BOOL ret = start_debugger( epointers, once );
687 if (!ret)
689 /* so that the other threads won't be stuck */
690 NtSetEvent( once, NULL );
692 return ret;
695 /* someone beat us here... */
696 CloseHandle( event );
699 /* and wait for the winner to have actually created the debugger */
700 WaitForSingleObject( once, INFINITE );
701 /* in fact, here, we only know that someone has tried to start the debugger,
702 * we'll know by reposting the exception if it has actually attached
703 * to the current process */
704 return TRUE;
708 /*******************************************************************
709 * check_resource_write
711 * Check if the exception is a write attempt to the resource data.
712 * If yes, we unprotect the resources to let broken apps continue
713 * (Windows does this too).
715 static BOOL check_resource_write( void *addr )
717 DWORD old_prot;
718 void *rsrc;
719 DWORD size;
720 MEMORY_BASIC_INFORMATION info;
722 if (!VirtualQuery( addr, &info, sizeof(info) )) return FALSE;
723 if (info.State == MEM_FREE || !(info.Type & MEM_IMAGE)) return FALSE;
724 if (!(rsrc = RtlImageDirectoryEntryToData( info.AllocationBase, TRUE,
725 IMAGE_DIRECTORY_ENTRY_RESOURCE, &size )))
726 return FALSE;
727 if (addr < rsrc || (char *)addr >= (char *)rsrc + size) return FALSE;
728 TRACE( "Broken app is writing to the resource data, enabling work-around\n" );
729 VirtualProtect( rsrc, size, PAGE_READWRITE, &old_prot );
730 return TRUE;
734 /*******************************************************************
735 * UnhandledExceptionFilter (kernelbase.@)
737 LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers )
739 const EXCEPTION_RECORD *rec = epointers->ExceptionRecord;
741 if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && rec->NumberParameters >= 2)
743 switch (rec->ExceptionInformation[0])
745 case EXCEPTION_WRITE_FAULT:
746 if (check_resource_write( (void *)rec->ExceptionInformation[1] ))
747 return EXCEPTION_CONTINUE_EXECUTION;
748 break;
752 if (!NtCurrentTeb()->Peb->BeingDebugged)
754 if (rec->ExceptionCode == CONTROL_C_EXIT)
756 /* do not launch the debugger on ^C, simply terminate the process */
757 TerminateProcess( GetCurrentProcess(), 1 );
760 if (top_filter)
762 LONG ret = top_filter( epointers );
763 if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
766 /* FIXME: Should check the current error mode */
768 if (!start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged)
769 return EXCEPTION_EXECUTE_HANDLER;
771 return EXCEPTION_CONTINUE_SEARCH;
775 /***********************************************************************
776 * WerGetFlags (kernelbase.@)
778 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerGetFlags( HANDLE process, DWORD *flags )
780 FIXME( "(%p, %p) stub\n", process, flags );
781 return E_NOTIMPL;
785 /***********************************************************************
786 * WerRegisterFile (kernelbase.@)
788 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterFile( const WCHAR *file, WER_REGISTER_FILE_TYPE type,
789 DWORD flags )
791 FIXME( "(%s, %d, %d) stub\n", debugstr_w(file), type, flags );
792 return E_NOTIMPL;
796 /***********************************************************************
797 * WerRegisterMemoryBlock (kernelbase.@)
799 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterMemoryBlock( void *block, DWORD size )
801 FIXME( "(%p %d) stub\n", block, size );
802 return E_NOTIMPL;
806 /***********************************************************************
807 * WerRegisterRuntimeExceptionModule (kernelbase.@)
809 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterRuntimeExceptionModule( const WCHAR *dll, void *context )
811 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context );
812 return S_OK;
816 /***********************************************************************
817 * WerSetFlags (kernelbase.@)
819 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerSetFlags( DWORD flags )
821 FIXME("(%d) stub\n", flags);
822 return E_NOTIMPL;
826 /***********************************************************************
827 * WerUnregisterFile (kernelbase.@)
829 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterFile( const WCHAR *file )
831 FIXME( "(%s) stub\n", debugstr_w(file) );
832 return E_NOTIMPL;
836 /***********************************************************************
837 * WerUnregisterMemoryBlock (kernelbase.@)
839 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterMemoryBlock( void *block )
841 FIXME( "(%p) stub\n", block );
842 return E_NOTIMPL;
846 /***********************************************************************
847 * WerUnregisterRuntimeExceptionModule (kernelbase.@)
849 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterRuntimeExceptionModule( const WCHAR *dll, void *context )
851 FIXME( "(%s, %p) stub\n", debugstr_w(dll), context );
852 return S_OK;
856 /***********************************************************************
857 * psapi functions
858 ***********************************************************************/
861 typedef struct _PEB32
863 BOOLEAN InheritedAddressSpace;
864 BOOLEAN ReadImageFileExecOptions;
865 BOOLEAN BeingDebugged;
866 BOOLEAN SpareBool;
867 DWORD Mutant;
868 DWORD ImageBaseAddress;
869 DWORD LdrData;
870 } PEB32;
872 typedef struct _LIST_ENTRY32
874 DWORD Flink;
875 DWORD Blink;
876 } LIST_ENTRY32;
878 typedef struct _PEB_LDR_DATA32
880 ULONG Length;
881 BOOLEAN Initialized;
882 DWORD SsHandle;
883 LIST_ENTRY32 InLoadOrderModuleList;
884 } PEB_LDR_DATA32;
886 typedef struct _UNICODE_STRING32
888 USHORT Length;
889 USHORT MaximumLength;
890 DWORD Buffer;
891 } UNICODE_STRING32;
893 typedef struct _LDR_DATA_TABLE_ENTRY32
895 LIST_ENTRY32 InLoadOrderModuleList;
896 LIST_ENTRY32 InMemoryOrderModuleList;
897 LIST_ENTRY32 InInitializationOrderModuleList;
898 DWORD BaseAddress;
899 DWORD EntryPoint;
900 ULONG SizeOfImage;
901 UNICODE_STRING32 FullDllName;
902 UNICODE_STRING32 BaseDllName;
903 } LDR_DATA_TABLE_ENTRY32;
905 struct module_iterator
907 HANDLE process;
908 LIST_ENTRY *head;
909 LIST_ENTRY *current;
910 BOOL wow64;
911 LDR_DATA_TABLE_ENTRY ldr_module;
912 LDR_DATA_TABLE_ENTRY32 ldr_module32;
916 static BOOL init_module_iterator( struct module_iterator *iter, HANDLE process )
918 PROCESS_BASIC_INFORMATION pbi;
919 PPEB_LDR_DATA ldr_data;
921 if (!IsWow64Process( process, &iter->wow64 )) return FALSE;
923 /* get address of PEB */
924 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation,
925 &pbi, sizeof(pbi), NULL )))
926 return FALSE;
928 if (is_win64 && iter->wow64)
930 PEB_LDR_DATA32 *ldr_data32_ptr;
931 DWORD ldr_data32, first_module;
932 PEB32 *peb32;
934 peb32 = (PEB32 *)(DWORD_PTR)pbi.PebBaseAddress;
935 if (!ReadProcessMemory( process, &peb32->LdrData, &ldr_data32, sizeof(ldr_data32), NULL ))
936 return FALSE;
937 ldr_data32_ptr = (PEB_LDR_DATA32 *)(DWORD_PTR) ldr_data32;
938 if (!ReadProcessMemory( process, &ldr_data32_ptr->InLoadOrderModuleList.Flink,
939 &first_module, sizeof(first_module), NULL ))
940 return FALSE;
941 iter->head = (LIST_ENTRY *)&ldr_data32_ptr->InLoadOrderModuleList;
942 iter->current = (LIST_ENTRY *)(DWORD_PTR)first_module;
943 iter->process = process;
944 return TRUE;
947 /* read address of LdrData from PEB */
948 if (!ReadProcessMemory( process, &pbi.PebBaseAddress->LdrData, &ldr_data, sizeof(ldr_data), NULL ))
949 return FALSE;
951 /* read address of first module from LdrData */
952 if (!ReadProcessMemory( process, &ldr_data->InLoadOrderModuleList.Flink,
953 &iter->current, sizeof(iter->current), NULL ))
954 return FALSE;
956 iter->head = &ldr_data->InLoadOrderModuleList;
957 iter->process = process;
958 return TRUE;
962 static int module_iterator_next( struct module_iterator *iter )
964 if (iter->current == iter->head) return 0;
966 if (is_win64 && iter->wow64)
968 LIST_ENTRY32 *entry32 = (LIST_ENTRY32 *)iter->current;
970 if (!ReadProcessMemory( iter->process,
971 CONTAINING_RECORD(entry32, LDR_DATA_TABLE_ENTRY32, InLoadOrderModuleList),
972 &iter->ldr_module32, sizeof(iter->ldr_module32), NULL ))
973 return -1;
974 iter->current = (LIST_ENTRY *)(DWORD_PTR)iter->ldr_module32.InLoadOrderModuleList.Flink;
975 return 1;
978 if (!ReadProcessMemory( iter->process,
979 CONTAINING_RECORD(iter->current, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks),
980 &iter->ldr_module, sizeof(iter->ldr_module), NULL ))
981 return -1;
983 iter->current = iter->ldr_module.InLoadOrderLinks.Flink;
984 return 1;
988 static BOOL get_ldr_module( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY *ldr_module )
990 struct module_iterator iter;
991 INT ret;
993 if (!init_module_iterator( &iter, process )) return FALSE;
995 while ((ret = module_iterator_next( &iter )) > 0)
996 /* When hModule is NULL we return the process image - which will be
997 * the first module since our iterator uses InLoadOrderModuleList */
998 if (!module || module == iter.ldr_module.DllBase)
1000 *ldr_module = iter.ldr_module;
1001 return TRUE;
1004 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE );
1005 return FALSE;
1009 static BOOL get_ldr_module32( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY32 *ldr_module )
1011 struct module_iterator iter;
1012 INT ret;
1014 if (!init_module_iterator( &iter, process )) return FALSE;
1016 while ((ret = module_iterator_next( &iter )) > 0)
1017 /* When hModule is NULL we return the process image - which will be
1018 * the first module since our iterator uses InLoadOrderModuleList */
1019 if (!module || (DWORD)(DWORD_PTR)module == iter.ldr_module32.BaseAddress)
1021 *ldr_module = iter.ldr_module32;
1022 return TRUE;
1025 if (ret == 0) SetLastError( ERROR_INVALID_HANDLE );
1026 return FALSE;
1030 /***********************************************************************
1031 * K32EmptyWorkingSet (kernelbase.@)
1033 BOOL WINAPI DECLSPEC_HOTPATCH K32EmptyWorkingSet( HANDLE process )
1035 return SetProcessWorkingSetSizeEx( process, (SIZE_T)-1, (SIZE_T)-1, 0 );
1039 /***********************************************************************
1040 * K32EnumDeviceDrivers (kernelbase.@)
1042 BOOL WINAPI K32EnumDeviceDrivers( void **image_base, DWORD count, DWORD *needed )
1044 FIXME( "(%p, %d, %p): stub\n", image_base, count, needed );
1045 if (needed) *needed = 0;
1046 return TRUE;
1050 /***********************************************************************
1051 * K32EnumPageFilesA (kernelbase.@)
1053 BOOL WINAPI /* DECLSPEC_HOTPATCH */ K32EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, void *context )
1055 FIXME( "(%p, %p) stub\n", callback, context );
1056 return FALSE;
1060 /***********************************************************************
1061 * K32EnumPageFilesW (kernelbase.@)
1063 BOOL WINAPI /* DECLSPEC_HOTPATCH */ K32EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, void *context )
1065 FIXME( "(%p, %p) stub\n", callback, context );
1066 return FALSE;
1070 /***********************************************************************
1071 * K32EnumProcessModules (kernelbase.@)
1073 BOOL WINAPI DECLSPEC_HOTPATCH K32EnumProcessModules( HANDLE process, HMODULE *module,
1074 DWORD count, DWORD *needed )
1076 struct module_iterator iter;
1077 DWORD size = 0;
1078 INT ret;
1080 if (process == GetCurrentProcess())
1082 PPEB_LDR_DATA ldr_data = NtCurrentTeb()->Peb->LdrData;
1083 PLIST_ENTRY head = &ldr_data->InLoadOrderModuleList;
1084 PLIST_ENTRY entry = head->Flink;
1086 if (count && !module)
1088 SetLastError( ERROR_NOACCESS );
1089 return FALSE;
1091 while (entry != head)
1093 LDR_DATA_TABLE_ENTRY *ldr = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
1094 if (count >= sizeof(HMODULE))
1096 *module++ = ldr->DllBase;
1097 count -= sizeof(HMODULE);
1099 size += sizeof(HMODULE);
1100 entry = entry->Flink;
1102 if (!needed)
1104 SetLastError( ERROR_NOACCESS );
1105 return FALSE;
1107 *needed = size;
1108 return TRUE;
1111 if (!init_module_iterator( &iter, process )) return FALSE;
1113 if (count && !module)
1115 SetLastError( ERROR_NOACCESS );
1116 return FALSE;
1119 while ((ret = module_iterator_next( &iter )) > 0)
1121 if (count >= sizeof(HMODULE))
1123 if (sizeof(void *) == 8 && iter.wow64)
1124 *module++ = (HMODULE) (DWORD_PTR)iter.ldr_module32.BaseAddress;
1125 else
1126 *module++ = iter.ldr_module.DllBase;
1127 count -= sizeof(HMODULE);
1129 size += sizeof(HMODULE);
1132 if (!needed)
1134 SetLastError( ERROR_NOACCESS );
1135 return FALSE;
1137 *needed = size;
1138 return ret == 0;
1142 /***********************************************************************
1143 * K32EnumProcessModulesEx (kernelbase.@)
1145 BOOL WINAPI K32EnumProcessModulesEx( HANDLE process, HMODULE *module, DWORD count,
1146 DWORD *needed, DWORD filter )
1148 FIXME( "(%p, %p, %d, %p, %d) semi-stub\n", process, module, count, needed, filter );
1149 return K32EnumProcessModules( process, module, count, needed );
1153 /***********************************************************************
1154 * K32EnumProcesses (kernelbase.@)
1156 BOOL WINAPI K32EnumProcesses( DWORD *ids, DWORD count, DWORD *used )
1158 SYSTEM_PROCESS_INFORMATION *spi;
1159 ULONG size = 0x4000;
1160 void *buf = NULL;
1161 NTSTATUS status;
1165 size *= 2;
1166 HeapFree( GetProcessHeap(), 0, buf );
1167 if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
1168 status = NtQuerySystemInformation( SystemProcessInformation, buf, size, NULL );
1169 } while (status == STATUS_INFO_LENGTH_MISMATCH);
1171 if (!set_ntstatus( status ))
1173 HeapFree( GetProcessHeap(), 0, buf );
1174 return FALSE;
1176 spi = buf;
1177 for (*used = 0; count >= sizeof(DWORD); count -= sizeof(DWORD))
1179 *ids++ = HandleToUlong( spi->UniqueProcessId );
1180 *used += sizeof(DWORD);
1181 if (spi->NextEntryOffset == 0) break;
1182 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
1184 HeapFree( GetProcessHeap(), 0, buf );
1185 return TRUE;
1189 /***********************************************************************
1190 * K32GetDeviceDriverBaseNameA (kernelbase.@)
1192 DWORD WINAPI DECLSPEC_HOTPATCH K32GetDeviceDriverBaseNameA( void *image_base, char *name, DWORD size )
1194 FIXME( "(%p, %p, %d): stub\n", image_base, name, size );
1195 if (name && size) name[0] = 0;
1196 return 0;
1200 /***********************************************************************
1201 * K32GetDeviceDriverBaseNameW (kernelbase.@)
1203 DWORD WINAPI DECLSPEC_HOTPATCH K32GetDeviceDriverBaseNameW( void *image_base, WCHAR *name, DWORD size )
1205 FIXME( "(%p, %p, %d): stub\n", image_base, name, size );
1206 if (name && size) name[0] = 0;
1207 return 0;
1211 /***********************************************************************
1212 * K32GetDeviceDriverFileNameA (kernelbase.@)
1214 DWORD WINAPI DECLSPEC_HOTPATCH K32GetDeviceDriverFileNameA( void *image_base, char *name, DWORD size )
1216 FIXME( "(%p, %p, %d): stub\n", image_base, name, size );
1217 if (name && size) name[0] = 0;
1218 return 0;
1222 /***********************************************************************
1223 * K32GetDeviceDriverFileNameW (kernelbase.@)
1225 DWORD WINAPI DECLSPEC_HOTPATCH K32GetDeviceDriverFileNameW( void *image_base, WCHAR *name, DWORD size )
1227 FIXME( "(%p, %p, %d): stub\n", image_base, name, size );
1228 if (name && size) name[0] = 0;
1229 return 0;
1233 /***********************************************************************
1234 * K32GetMappedFileNameA (kernelbase.@)
1236 DWORD WINAPI DECLSPEC_HOTPATCH K32GetMappedFileNameA( HANDLE process, void *addr, char *name, DWORD size )
1238 FIXME( "(%p, %p, %p, %d): stub\n", process, addr, name, size );
1239 if (name && size) name[0] = 0;
1240 return 0;
1244 /***********************************************************************
1245 * K32GetMappedFileNameW (kernelbase.@)
1247 DWORD WINAPI DECLSPEC_HOTPATCH K32GetMappedFileNameW( HANDLE process, void *addr, WCHAR *name, DWORD size )
1249 FIXME( "(%p, %p, %p, %d): stub\n", process, addr, name, size );
1250 if (name && size) name[0] = 0;
1251 return 0;
1255 /***********************************************************************
1256 * K32GetModuleBaseNameA (kernelbase.@)
1258 DWORD WINAPI DECLSPEC_HOTPATCH K32GetModuleBaseNameA( HANDLE process, HMODULE module,
1259 char *name, DWORD size )
1261 WCHAR *name_w;
1262 DWORD len, ret = 0;
1264 if (!name || !size)
1266 SetLastError( ERROR_INVALID_PARAMETER );
1267 return 0;
1269 if (!(name_w = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * size ))) return 0;
1271 len = K32GetModuleBaseNameW( process, module, name_w, size );
1272 TRACE( "%d, %s\n", len, debugstr_w(name_w) );
1273 if (len)
1275 ret = WideCharToMultiByte( CP_ACP, 0, name_w, len, name, size, NULL, NULL );
1276 if (ret < size) name[ret] = 0;
1278 HeapFree( GetProcessHeap(), 0, name_w );
1279 return ret;
1283 /***********************************************************************
1284 * K32GetModuleBaseNameW (kernelbase.@)
1286 DWORD WINAPI DECLSPEC_HOTPATCH K32GetModuleBaseNameW( HANDLE process, HMODULE module,
1287 WCHAR *name, DWORD size )
1289 BOOL wow64;
1291 if (!IsWow64Process( process, &wow64 )) return 0;
1293 if (is_win64 && wow64)
1295 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1297 if (!get_ldr_module32(process, module, &ldr_module32)) return 0;
1298 size = min( ldr_module32.BaseDllName.Length / sizeof(WCHAR), size );
1299 if (!ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.BaseDllName.Buffer,
1300 name, size * sizeof(WCHAR), NULL ))
1301 return 0;
1303 else
1305 LDR_DATA_TABLE_ENTRY ldr_module;
1307 if (!get_ldr_module( process, module, &ldr_module )) return 0;
1308 size = min( ldr_module.BaseDllName.Length / sizeof(WCHAR), size );
1309 if (!ReadProcessMemory( process, ldr_module.BaseDllName.Buffer,
1310 name, size * sizeof(WCHAR), NULL ))
1311 return 0;
1313 name[size] = 0;
1314 return size;
1318 /***********************************************************************
1319 * K32GetModuleFileNameExA (kernelbase.@)
1321 DWORD WINAPI DECLSPEC_HOTPATCH K32GetModuleFileNameExA( HANDLE process, HMODULE module,
1322 char *name, DWORD size )
1324 WCHAR *ptr;
1325 DWORD len;
1327 TRACE( "(process=%p, module=%p, %p, %d)\n", process, module, name, size );
1329 if (!name || !size)
1331 SetLastError( ERROR_INVALID_PARAMETER );
1332 return 0;
1334 if (process == GetCurrentProcess())
1336 len = GetModuleFileNameA( module, name, size );
1337 name[size - 1] = '\0';
1338 return len;
1341 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return 0;
1342 len = K32GetModuleFileNameExW( process, module, ptr, size );
1343 if (!len)
1345 name[0] = 0;
1347 else
1349 if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, name, size, NULL, NULL ))
1351 name[size - 1] = 0;
1352 len = size;
1354 else if (len < size) len = strlen( name );
1356 HeapFree( GetProcessHeap(), 0, ptr );
1357 return len;
1361 /***********************************************************************
1362 * K32GetModuleFileNameExW (kernelbase.@)
1364 DWORD WINAPI DECLSPEC_HOTPATCH K32GetModuleFileNameExW( HANDLE process, HMODULE module,
1365 WCHAR *name, DWORD size )
1367 BOOL wow64;
1368 DWORD len;
1370 if (!size) return 0;
1372 if (!IsWow64Process( process, &wow64 )) return 0;
1374 if (is_win64 && wow64)
1376 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1378 if (!get_ldr_module32( process, module, &ldr_module32 )) return 0;
1379 len = ldr_module32.FullDllName.Length / sizeof(WCHAR);
1380 if (!ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.FullDllName.Buffer,
1381 name, min( len, size ) * sizeof(WCHAR), NULL ))
1382 return 0;
1384 else
1386 LDR_DATA_TABLE_ENTRY ldr_module;
1388 if (!get_ldr_module(process, module, &ldr_module)) return 0;
1389 len = ldr_module.FullDllName.Length / sizeof(WCHAR);
1390 if (!ReadProcessMemory( process, ldr_module.FullDllName.Buffer,
1391 name, min( len, size ) * sizeof(WCHAR), NULL ))
1392 return 0;
1395 if (len < size)
1397 name[len] = 0;
1398 return len;
1400 else
1402 name[size - 1] = 0;
1403 return size;
1408 /***********************************************************************
1409 * K32GetModuleInformation (kernelbase.@)
1411 BOOL WINAPI K32GetModuleInformation( HANDLE process, HMODULE module, MODULEINFO *modinfo, DWORD count )
1413 BOOL wow64;
1415 if (count < sizeof(MODULEINFO))
1417 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1418 return FALSE;
1421 if (!IsWow64Process( process, &wow64 )) return FALSE;
1423 if (is_win64 && wow64)
1425 LDR_DATA_TABLE_ENTRY32 ldr_module32;
1427 if (!get_ldr_module32( process, module, &ldr_module32 )) return FALSE;
1428 modinfo->lpBaseOfDll = (void *)(DWORD_PTR)ldr_module32.BaseAddress;
1429 modinfo->SizeOfImage = ldr_module32.SizeOfImage;
1430 modinfo->EntryPoint = (void *)(DWORD_PTR)ldr_module32.EntryPoint;
1432 else
1434 LDR_DATA_TABLE_ENTRY ldr_module;
1436 if (!get_ldr_module( process, module, &ldr_module )) return FALSE;
1437 modinfo->lpBaseOfDll = ldr_module.DllBase;
1438 modinfo->SizeOfImage = ldr_module.SizeOfImage;
1439 modinfo->EntryPoint = ldr_module.EntryPoint;
1441 return TRUE;
1445 /***********************************************************************
1446 * K32GetPerformanceInfo (kernelbase.@)
1448 BOOL WINAPI DECLSPEC_HOTPATCH K32GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
1450 SYSTEM_PERFORMANCE_INFORMATION perf;
1451 SYSTEM_BASIC_INFORMATION basic;
1452 SYSTEM_PROCESS_INFORMATION *process, *spi;
1453 DWORD info_size;
1454 NTSTATUS status;
1456 TRACE( "(%p, %d)\n", info, size );
1458 if (size < sizeof(*info))
1460 SetLastError( ERROR_BAD_LENGTH );
1461 return FALSE;
1464 status = NtQuerySystemInformation( SystemPerformanceInformation, &perf, sizeof(perf), NULL );
1465 if (!set_ntstatus( status )) return FALSE;
1466 status = NtQuerySystemInformation( SystemBasicInformation, &basic, sizeof(basic), NULL );
1467 if (!set_ntstatus( status )) return FALSE;
1469 info->cb = sizeof(*info);
1470 info->CommitTotal = perf.TotalCommittedPages;
1471 info->CommitLimit = perf.TotalCommitLimit;
1472 info->CommitPeak = perf.PeakCommitment;
1473 info->PhysicalTotal = basic.MmNumberOfPhysicalPages;
1474 info->PhysicalAvailable = perf.AvailablePages;
1475 info->SystemCache = 0;
1476 info->KernelTotal = perf.PagedPoolUsage + perf.NonPagedPoolUsage;
1477 info->KernelPaged = perf.PagedPoolUsage;
1478 info->KernelNonpaged = perf.NonPagedPoolUsage;
1479 info->PageSize = basic.PageSize;
1481 /* fields from SYSTEM_PROCESS_INFORMATION */
1482 NtQuerySystemInformation( SystemProcessInformation, NULL, 0, &info_size );
1483 for (;;)
1485 process = HeapAlloc( GetProcessHeap(), 0, info_size );
1486 if (!process)
1488 SetLastError( ERROR_OUTOFMEMORY );
1489 return FALSE;
1491 status = NtQuerySystemInformation( SystemProcessInformation, process, info_size, &info_size );
1492 if (!status) break;
1493 HeapFree( GetProcessHeap(), 0, process );
1494 if (status != STATUS_INFO_LENGTH_MISMATCH)
1496 SetLastError( RtlNtStatusToDosError( status ) );
1497 return FALSE;
1500 info->HandleCount = info->ProcessCount = info->ThreadCount = 0;
1501 spi = process;
1502 for (;;)
1504 info->ProcessCount++;
1505 info->HandleCount += spi->HandleCount;
1506 info->ThreadCount += spi->dwThreadCount;
1507 if (spi->NextEntryOffset == 0) break;
1508 spi = (SYSTEM_PROCESS_INFORMATION *)((char *)spi + spi->NextEntryOffset);
1510 HeapFree( GetProcessHeap(), 0, process );
1511 return TRUE;
1515 /***********************************************************************
1516 * K32GetProcessImageFileNameA (kernelbase.@)
1518 DWORD WINAPI DECLSPEC_HOTPATCH K32GetProcessImageFileNameA( HANDLE process, char *file, DWORD size )
1520 return QueryFullProcessImageNameA( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0;
1524 /***********************************************************************
1525 * K32GetProcessImageFileNameW (kernelbase.@)
1527 DWORD WINAPI DECLSPEC_HOTPATCH K32GetProcessImageFileNameW( HANDLE process, WCHAR *file, DWORD size )
1529 return QueryFullProcessImageNameW( process, PROCESS_NAME_NATIVE, file, &size ) ? size : 0;
1533 /***********************************************************************
1534 * K32GetProcessMemoryInfo (kernelbase.@)
1536 BOOL WINAPI DECLSPEC_HOTPATCH K32GetProcessMemoryInfo( HANDLE process, PROCESS_MEMORY_COUNTERS *pmc,
1537 DWORD count )
1539 VM_COUNTERS vmc;
1541 if (count < sizeof(PROCESS_MEMORY_COUNTERS))
1543 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1544 return FALSE;
1547 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessVmCounters, &vmc, sizeof(vmc), NULL )))
1548 return FALSE;
1550 pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
1551 pmc->PageFaultCount = vmc.PageFaultCount;
1552 pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
1553 pmc->WorkingSetSize = vmc.WorkingSetSize;
1554 pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
1555 pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
1556 pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
1557 pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
1558 pmc->PagefileUsage = vmc.PagefileUsage;
1559 pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
1560 return TRUE;
1564 /***********************************************************************
1565 * K32GetWsChanges (kernelbase.@)
1567 BOOL WINAPI DECLSPEC_HOTPATCH K32GetWsChanges( HANDLE process, PSAPI_WS_WATCH_INFORMATION *info, DWORD size )
1569 TRACE( "(%p, %p, %d)\n", process, info, size );
1570 return set_ntstatus( NtQueryInformationProcess( process, ProcessWorkingSetWatch, info, size, NULL ));
1574 /***********************************************************************
1575 * K32GetWsChangesEx (kernelbase.@)
1577 BOOL WINAPI DECLSPEC_HOTPATCH K32GetWsChangesEx( HANDLE process, PSAPI_WS_WATCH_INFORMATION_EX *info,
1578 DWORD *size )
1580 FIXME( "(%p, %p, %p)\n", process, info, size );
1581 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1582 return FALSE;
1586 /***********************************************************************
1587 * K32InitializeProcessForWsWatch (kernelbase.@)
1589 BOOL WINAPI /* DECLSPEC_HOTPATCH */ K32InitializeProcessForWsWatch( HANDLE process )
1591 FIXME( "(process=%p): stub\n", process );
1592 return TRUE;
1596 /***********************************************************************
1597 * K32QueryWorkingSet (kernelbase.@)
1599 BOOL WINAPI DECLSPEC_HOTPATCH K32QueryWorkingSet( HANDLE process, void *buffer, DWORD size )
1601 TRACE( "(%p, %p, %d)\n", process, buffer, size );
1602 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL ));
1606 /***********************************************************************
1607 * K32QueryWorkingSetEx (kernelbase.@)
1609 BOOL WINAPI K32QueryWorkingSetEx( HANDLE process, void *buffer, DWORD size )
1611 TRACE( "(%p, %p, %d)\n", process, buffer, size );
1612 return set_ntstatus( NtQueryVirtualMemory( process, NULL, MemoryWorkingSetExInformation,
1613 buffer, size, NULL ));
1617 /******************************************************************
1618 * QueryFullProcessImageNameA (kernelbase.@)
1620 BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameA( HANDLE process, DWORD flags,
1621 char *name, DWORD *size )
1623 BOOL ret;
1624 DWORD sizeW = *size;
1625 WCHAR *nameW = HeapAlloc( GetProcessHeap(), 0, *size * sizeof(WCHAR) );
1627 ret = QueryFullProcessImageNameW( process, flags, nameW, &sizeW );
1628 if (ret) ret = (WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, *size, NULL, NULL) > 0);
1629 if (ret) *size = strlen( name );
1630 HeapFree( GetProcessHeap(), 0, nameW );
1631 return ret;
1635 /******************************************************************
1636 * QueryFullProcessImageNameW (kernelbase.@)
1638 BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameW( HANDLE process, DWORD flags,
1639 WCHAR *name, DWORD *size )
1641 BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */
1642 UNICODE_STRING *dynamic_buffer = NULL;
1643 UNICODE_STRING *result = NULL;
1644 NTSTATUS status;
1645 DWORD needed;
1647 /* FIXME: On Windows, ProcessImageFileName return an NT path. In Wine it
1648 * is a DOS path and we depend on this. */
1649 status = NtQueryInformationProcess( process, ProcessImageFileName, buffer,
1650 sizeof(buffer) - sizeof(WCHAR), &needed );
1651 if (status == STATUS_INFO_LENGTH_MISMATCH)
1653 dynamic_buffer = HeapAlloc( GetProcessHeap(), 0, needed + sizeof(WCHAR) );
1654 status = NtQueryInformationProcess( process, ProcessImageFileName, dynamic_buffer,
1655 needed, &needed );
1656 result = dynamic_buffer;
1658 else
1659 result = (UNICODE_STRING *)buffer;
1661 if (status) goto cleanup;
1663 if (flags & PROCESS_NAME_NATIVE)
1665 WCHAR drive[3];
1666 WCHAR device[1024];
1667 DWORD ntlen, devlen;
1669 if (result->Buffer[1] != ':' || result->Buffer[0] < 'A' || result->Buffer[0] > 'Z')
1671 /* We cannot convert it to an NT device path so fail */
1672 status = STATUS_NO_SUCH_DEVICE;
1673 goto cleanup;
1676 /* Find this drive's NT device path */
1677 drive[0] = result->Buffer[0];
1678 drive[1] = ':';
1679 drive[2] = 0;
1680 if (!QueryDosDeviceW(drive, device, ARRAY_SIZE(device)))
1682 status = STATUS_NO_SUCH_DEVICE;
1683 goto cleanup;
1686 devlen = lstrlenW(device);
1687 ntlen = devlen + (result->Length/sizeof(WCHAR) - 2);
1688 if (ntlen + 1 > *size)
1690 status = STATUS_BUFFER_TOO_SMALL;
1691 goto cleanup;
1693 *size = ntlen;
1695 memcpy( name, device, devlen * sizeof(*device) );
1696 memcpy( name + devlen, result->Buffer + 2, result->Length - 2 * sizeof(WCHAR) );
1697 name[*size] = 0;
1698 TRACE( "NT path: %s\n", debugstr_w(name) );
1700 else
1702 if (result->Length/sizeof(WCHAR) + 1 > *size)
1704 status = STATUS_BUFFER_TOO_SMALL;
1705 goto cleanup;
1708 *size = result->Length/sizeof(WCHAR);
1709 memcpy( name, result->Buffer, result->Length );
1710 name[*size] = 0;
1713 cleanup:
1714 HeapFree( GetProcessHeap(), 0, dynamic_buffer );
1715 return set_ntstatus( status );