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
25 #define WIN32_NO_STATUS
35 #include "wine/exception.h"
36 #include "wine/server.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
)
58 if (!process
|| !present
)
60 SetLastError( ERROR_INVALID_PARAMETER
);
63 if (!set_ntstatus( NtQueryInformationProcess( process
, ProcessDebugPort
, &port
, sizeof(port
), NULL
)))
70 /**********************************************************************
71 * ContinueDebugEvent (kernelbase.@)
73 BOOL WINAPI DECLSPEC_HOTPATCH
ContinueDebugEvent( DWORD pid
, DWORD tid
, DWORD status
)
76 SERVER_START_REQ( continue_debug_event
)
81 ret
= !wine_server_call_err( req
);
88 /**********************************************************************
89 * DebugActiveProcess (kernelbase.@)
91 BOOL WINAPI DECLSPEC_HOTPATCH
DebugActiveProcess( DWORD pid
)
96 SERVER_START_REQ( debug_process
)
100 ret
= !wine_server_call_err( req
);
103 if (!ret
) return FALSE
;
105 if (!(process
= OpenProcess( PROCESS_CREATE_THREAD
, FALSE
, pid
))) return FALSE
;
106 ret
= set_ntstatus( DbgUiIssueRemoteBreakin( process
));
108 if (!ret
) DebugActiveProcessStop( pid
);
113 /**********************************************************************
114 * DebugActiveProcessStop (kernelbase.@)
116 BOOL WINAPI DECLSPEC_HOTPATCH
DebugActiveProcessStop( DWORD pid
)
120 SERVER_START_REQ( debug_process
)
124 ret
= !wine_server_call_err( req
);
131 /***********************************************************************
132 * DebugBreak (kernelbase.@)
134 #if defined(__i386__) || defined(__x86_64__)
135 __ASM_STDCALL_FUNC( DebugBreak
, 0, "jmp " __ASM_STDCALL("DbgBreakPoint", 0) )
137 void WINAPI
DebugBreak(void)
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
;
199 WARN( "%s\n", debugstr_a(str
) );
201 /* raise exception, WaitForDebugEvent() will generate a corresponding debug event */
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
;
214 if (caught_by_dbg
) return;
216 /* send string to a system-wide monitor */
219 /* first call to OutputDebugString, initialize mutex handle */
220 HANDLE mutex
= CreateMutexExW( NULL
, L
"DBWinMutex", 0, SYNCHRONIZE
);
223 if (InterlockedCompareExchangePointer( &DBWinMutex
, mutex
, 0 ) != 0)
224 /* someone beat us here... */
225 CloseHandle( mutex
);
234 mapping
= OpenFileMappingW( FILE_MAP_WRITE
, FALSE
, L
"DBWIN_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
);
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
)
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
;
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
)
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
);
354 event
->dwDebugEventCode
= data
.code
;
355 event
->dwProcessId
= (DWORD
)reply
->pid
;
356 event
->dwThreadId
= (DWORD
)reply
->tid
;
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];
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];
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
];
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
);
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
;
401 case EXIT_THREAD_DEBUG_EVENT
:
402 event
->u
.ExitThread
.dwExitCode
= data
.exit
.exit_code
;
404 case EXIT_PROCESS_DEBUG_EVENT
:
405 event
->u
.ExitProcess
.dwExitCode
= data
.exit
.exit_code
;
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
;
415 case UNLOAD_DLL_DEBUG_EVENT
:
416 event
->u
.UnloadDll
.lpBaseOfDll
= wine_server_get_ptr( data
.unload_dll
.base
);
423 if (ret
) return TRUE
;
425 res
= WaitForSingleObject( wait
, timeout
);
427 if (res
!= STATUS_WAIT_0
) break;
429 SetLastError( ERROR_SEM_TIMEOUT
);
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
;
442 switch(rec
->ExceptionCode
)
444 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
445 len
= snprintf( buffer
, size
, "Unhandled division by zero" );
447 case EXCEPTION_INT_OVERFLOW
:
448 len
= snprintf( buffer
, size
, "Unhandled overflow" );
450 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
451 len
= snprintf( buffer
, size
, "Unhandled array bounds" );
453 case EXCEPTION_ILLEGAL_INSTRUCTION
:
454 len
= snprintf( buffer
, size
, "Unhandled illegal instruction" );
456 case EXCEPTION_STACK_OVERFLOW
:
457 len
= snprintf( buffer
, size
, "Unhandled stack overflow" );
459 case EXCEPTION_PRIV_INSTRUCTION
:
460 len
= snprintf( buffer
, size
, "Unhandled privileged instruction" );
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]);
469 len
= snprintf( buffer
, size
, "Unhandled page fault");
471 case EXCEPTION_DATATYPE_MISALIGNMENT
:
472 len
= snprintf( buffer
, size
, "Unhandled alignment" );
475 len
= snprintf( buffer
, size
, "Unhandled ^C");
477 case STATUS_POSSIBLE_DEADLOCK
:
478 len
= snprintf( buffer
, size
, "Critical section %p wait failed",
479 (void *)rec
->ExceptionInformation
[0]);
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] );
486 len
= snprintf( buffer
, size
, "Unimplemented function %s.%ld called",
487 (char *)rec
->ExceptionInformation
[0], rec
->ExceptionInformation
[1] );
489 case EXCEPTION_WINE_ASSERTION
:
490 len
= snprintf( buffer
, size
, "Assertion failed" );
493 len
= snprintf( buffer
, size
, "Unhandled exception 0x%08x in thread %x",
494 rec
->ExceptionCode
, GetCurrentThreadId());
497 if (len
< 0 || len
>= size
) return;
498 snprintf( buffer
+ len
, size
- len
, " at address %p", ptr
->ExceptionRecord
->ExceptionAddress
);
502 /******************************************************************
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
;
513 DWORD autostart
= TRUE
;
514 PROCESS_INFORMATION info
;
515 STARTUPINFOW startup
;
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
;
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
)
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
);
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 );
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
);
586 cmdline
= HeapAlloc( GetProcessHeap(), 0, 80 * sizeof(WCHAR
) );
587 swprintf( cmdline
, 80, L
"winedbg --auto %ld %ld", (long)GetCurrentProcessId(), (long)HandleToLong(event
) );
592 HMODULE mod
= GetModuleHandleA( "user32.dll" );
593 MessageBoxA_funcptr pMessageBoxA
= NULL
;
595 if (mod
) pMessageBoxA
= (void *)GetProcAddress( mod
, "MessageBoxA" );
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" );
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
);
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
);
637 /* wait for debugger to come up... */
639 CloseHandle( info
.hThread
);
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() );
649 HeapFree(GetProcessHeap(), 0, cmdline
);
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
)
669 OBJECT_ATTRIBUTES attr
;
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
);
689 /* so that the other threads won't be stuck */
690 NtSetEvent( once
, NULL
);
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 */
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
)
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
)))
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
);
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
;
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 );
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
);
785 /***********************************************************************
786 * WerRegisterFile (kernelbase.@)
788 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerRegisterFile( const WCHAR
*file
, WER_REGISTER_FILE_TYPE type
,
791 FIXME( "(%s, %d, %d) stub\n", debugstr_w(file
), type
, flags
);
796 /***********************************************************************
797 * WerRegisterMemoryBlock (kernelbase.@)
799 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerRegisterMemoryBlock( void *block
, DWORD size
)
801 FIXME( "(%p %d) stub\n", block
, size
);
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
);
816 /***********************************************************************
817 * WerSetFlags (kernelbase.@)
819 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerSetFlags( DWORD flags
)
821 FIXME("(%d) stub\n", flags
);
826 /***********************************************************************
827 * WerUnregisterFile (kernelbase.@)
829 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerUnregisterFile( const WCHAR
*file
)
831 FIXME( "(%s) stub\n", debugstr_w(file
) );
836 /***********************************************************************
837 * WerUnregisterMemoryBlock (kernelbase.@)
839 HRESULT WINAPI
/* DECLSPEC_HOTPATCH */ WerUnregisterMemoryBlock( void *block
)
841 FIXME( "(%p) stub\n", block
);
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
);
856 /***********************************************************************
858 ***********************************************************************/
861 typedef struct _PEB32
863 BOOLEAN InheritedAddressSpace
;
864 BOOLEAN ReadImageFileExecOptions
;
865 BOOLEAN BeingDebugged
;
868 DWORD ImageBaseAddress
;
872 typedef struct _LIST_ENTRY32
878 typedef struct _PEB_LDR_DATA32
883 LIST_ENTRY32 InLoadOrderModuleList
;
886 typedef struct _UNICODE_STRING32
889 USHORT MaximumLength
;
893 typedef struct _LDR_DATA_TABLE_ENTRY32
895 LIST_ENTRY32 InLoadOrderModuleList
;
896 LIST_ENTRY32 InMemoryOrderModuleList
;
897 LIST_ENTRY32 InInitializationOrderModuleList
;
901 UNICODE_STRING32 FullDllName
;
902 UNICODE_STRING32 BaseDllName
;
903 } LDR_DATA_TABLE_ENTRY32
;
905 struct module_iterator
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
)))
928 if (is_win64
&& iter
->wow64
)
930 PEB_LDR_DATA32
*ldr_data32_ptr
;
931 DWORD ldr_data32
, first_module
;
934 peb32
= (PEB32
*)(DWORD_PTR
)pbi
.PebBaseAddress
;
935 if (!ReadProcessMemory( process
, &peb32
->LdrData
, &ldr_data32
, sizeof(ldr_data32
), NULL
))
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
))
941 iter
->head
= (LIST_ENTRY
*)&ldr_data32_ptr
->InLoadOrderModuleList
;
942 iter
->current
= (LIST_ENTRY
*)(DWORD_PTR
)first_module
;
943 iter
->process
= process
;
947 /* read address of LdrData from PEB */
948 if (!ReadProcessMemory( process
, &pbi
.PebBaseAddress
->LdrData
, &ldr_data
, sizeof(ldr_data
), NULL
))
951 /* read address of first module from LdrData */
952 if (!ReadProcessMemory( process
, &ldr_data
->InLoadOrderModuleList
.Flink
,
953 &iter
->current
, sizeof(iter
->current
), NULL
))
956 iter
->head
= &ldr_data
->InLoadOrderModuleList
;
957 iter
->process
= process
;
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
))
974 iter
->current
= (LIST_ENTRY
*)(DWORD_PTR
)iter
->ldr_module32
.InLoadOrderModuleList
.Flink
;
978 if (!ReadProcessMemory( iter
->process
,
979 CONTAINING_RECORD(iter
->current
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
),
980 &iter
->ldr_module
, sizeof(iter
->ldr_module
), NULL
))
983 iter
->current
= iter
->ldr_module
.InLoadOrderLinks
.Flink
;
988 static BOOL
get_ldr_module( HANDLE process
, HMODULE module
, LDR_DATA_TABLE_ENTRY
*ldr_module
)
990 struct module_iterator iter
;
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
;
1004 if (ret
== 0) SetLastError( ERROR_INVALID_HANDLE
);
1009 static BOOL
get_ldr_module32( HANDLE process
, HMODULE module
, LDR_DATA_TABLE_ENTRY32
*ldr_module
)
1011 struct module_iterator iter
;
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
;
1025 if (ret
== 0) SetLastError( ERROR_INVALID_HANDLE
);
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;
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
);
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
);
1070 /***********************************************************************
1071 * K32EnumProcessModules (kernelbase.@)
1073 BOOL WINAPI DECLSPEC_HOTPATCH
K32EnumProcessModules( HANDLE process
, HMODULE
*module
,
1074 DWORD count
, DWORD
*needed
)
1076 struct module_iterator iter
;
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
);
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
;
1104 SetLastError( ERROR_NOACCESS
);
1111 if (!init_module_iterator( &iter
, process
)) return FALSE
;
1113 if (count
&& !module
)
1115 SetLastError( ERROR_NOACCESS
);
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
;
1126 *module
++ = iter
.ldr_module
.DllBase
;
1127 count
-= sizeof(HMODULE
);
1129 size
+= sizeof(HMODULE
);
1134 SetLastError( ERROR_NOACCESS
);
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;
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
);
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
);
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;
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;
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;
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;
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;
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;
1255 /***********************************************************************
1256 * K32GetModuleBaseNameA (kernelbase.@)
1258 DWORD WINAPI DECLSPEC_HOTPATCH
K32GetModuleBaseNameA( HANDLE process
, HMODULE module
,
1259 char *name
, DWORD size
)
1266 SetLastError( ERROR_INVALID_PARAMETER
);
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
) );
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
);
1283 /***********************************************************************
1284 * K32GetModuleBaseNameW (kernelbase.@)
1286 DWORD WINAPI DECLSPEC_HOTPATCH
K32GetModuleBaseNameW( HANDLE process
, HMODULE module
,
1287 WCHAR
*name
, DWORD size
)
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
))
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
))
1318 /***********************************************************************
1319 * K32GetModuleFileNameExA (kernelbase.@)
1321 DWORD WINAPI DECLSPEC_HOTPATCH
K32GetModuleFileNameExA( HANDLE process
, HMODULE module
,
1322 char *name
, DWORD size
)
1327 TRACE( "(process=%p, module=%p, %p, %d)\n", process
, module
, name
, size
);
1331 SetLastError( ERROR_INVALID_PARAMETER
);
1334 if (process
== GetCurrentProcess())
1336 len
= GetModuleFileNameA( module
, name
, size
);
1337 name
[size
- 1] = '\0';
1341 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return 0;
1342 len
= K32GetModuleFileNameExW( process
, module
, ptr
, size
);
1349 if (!WideCharToMultiByte( CP_ACP
, 0, ptr
, -1, name
, size
, NULL
, NULL
))
1354 else if (len
< size
) len
= strlen( name
);
1356 HeapFree( GetProcessHeap(), 0, ptr
);
1361 /***********************************************************************
1362 * K32GetModuleFileNameExW (kernelbase.@)
1364 DWORD WINAPI DECLSPEC_HOTPATCH
K32GetModuleFileNameExW( HANDLE process
, HMODULE module
,
1365 WCHAR
*name
, DWORD size
)
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
))
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
))
1408 /***********************************************************************
1409 * K32GetModuleInformation (kernelbase.@)
1411 BOOL WINAPI
K32GetModuleInformation( HANDLE process
, HMODULE module
, MODULEINFO
*modinfo
, DWORD count
)
1415 if (count
< sizeof(MODULEINFO
))
1417 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
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
;
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
;
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
;
1456 TRACE( "(%p, %d)\n", info
, size
);
1458 if (size
< sizeof(*info
))
1460 SetLastError( ERROR_BAD_LENGTH
);
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
);
1485 process
= HeapAlloc( GetProcessHeap(), 0, info_size
);
1488 SetLastError( ERROR_OUTOFMEMORY
);
1491 status
= NtQuerySystemInformation( SystemProcessInformation
, process
, info_size
, &info_size
);
1493 HeapFree( GetProcessHeap(), 0, process
);
1494 if (status
!= STATUS_INFO_LENGTH_MISMATCH
)
1496 SetLastError( RtlNtStatusToDosError( status
) );
1500 info
->HandleCount
= info
->ProcessCount
= info
->ThreadCount
= 0;
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
);
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
,
1541 if (count
< sizeof(PROCESS_MEMORY_COUNTERS
))
1543 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1547 if (!set_ntstatus( NtQueryInformationProcess( process
, ProcessVmCounters
, &vmc
, sizeof(vmc
), NULL
)))
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
;
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
,
1580 FIXME( "(%p, %p, %p)\n", process
, info
, size
);
1581 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1586 /***********************************************************************
1587 * K32InitializeProcessForWsWatch (kernelbase.@)
1589 BOOL WINAPI
/* DECLSPEC_HOTPATCH */ K32InitializeProcessForWsWatch( HANDLE process
)
1591 FIXME( "(process=%p): stub\n", process
);
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
)
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
);
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
;
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
,
1656 result
= dynamic_buffer
;
1659 result
= (UNICODE_STRING
*)buffer
;
1661 if (status
) goto cleanup
;
1663 if (flags
& PROCESS_NAME_NATIVE
)
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
;
1676 /* Find this drive's NT device path */
1677 drive
[0] = result
->Buffer
[0];
1680 if (!QueryDosDeviceW(drive
, device
, ARRAY_SIZE(device
)))
1682 status
= STATUS_NO_SUCH_DEVICE
;
1686 devlen
= lstrlenW(device
);
1687 ntlen
= devlen
+ (result
->Length
/sizeof(WCHAR
) - 2);
1688 if (ntlen
+ 1 > *size
)
1690 status
= STATUS_BUFFER_TOO_SMALL
;
1695 memcpy( name
, device
, devlen
* sizeof(*device
) );
1696 memcpy( name
+ devlen
, result
->Buffer
+ 2, result
->Length
- 2 * sizeof(WCHAR
) );
1698 TRACE( "NT path: %s\n", debugstr_w(name
) );
1702 if (result
->Length
/sizeof(WCHAR
) + 1 > *size
)
1704 status
= STATUS_BUFFER_TOO_SMALL
;
1708 *size
= result
->Length
/sizeof(WCHAR
);
1709 memcpy( name
, result
->Buffer
, result
->Length
);
1714 HeapFree( GetProcessHeap(), 0, dynamic_buffer
);
1715 return set_ntstatus( status
);