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