diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 21de0410d39..df643445e7d 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -36,7 +36,7 @@ # @ stub DbgSetDebugFilterState @ stdcall DbgUiConnectToDbg() @ stdcall DbgUiContinue(ptr long) -@ stub DbgUiConvertStateChangeStructure +@ stdcall DbgUiConvertStateChangeStructure(ptr ptr) @ stdcall DbgUiDebugActiveProcess(long) @ stdcall DbgUiGetThreadDebugObject() @ stdcall DbgUiIssueRemoteBreakin(long) diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index 085b98bca5b..3ff38691bbc 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -178,6 +178,115 @@ NTSTATUS WINAPI DbgUiContinue( CLIENT_ID *client, NTSTATUS status ) return NtDebugContinue( DbgUiGetThreadDebugObject(), client, status ); } +/* helper for DbgUiConvertStateChangeStructure */ +static inline void *get_thread_teb( HANDLE thread ) +{ + THREAD_BASIC_INFORMATION info; + + if (NtQueryInformationThread( thread, ThreadBasicInformation, &info, sizeof(info), NULL )) return NULL; + return info.TebBaseAddress; +} + +/*********************************************************************** + * DbgUiConvertStateChangeStructure (NTDLL.@) + */ +NTSTATUS WINAPI DbgUiConvertStateChangeStructure( DBGUI_WAIT_STATE_CHANGE *state, DEBUG_EVENT *event ) +{ + event->dwProcessId = HandleToULong( state->AppClientId.UniqueProcess ); + event->dwThreadId = HandleToULong( state->AppClientId.UniqueThread ); + switch (state->NewState) + { + case DbgCreateThreadStateChange: + { + DBGUI_CREATE_THREAD *info = &state->StateInfo.CreateThread; + event->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT; + event->u.CreateThread.hThread = info->HandleToThread; + event->u.CreateThread.lpThreadLocalBase = get_thread_teb( info->HandleToThread ); + event->u.CreateThread.lpStartAddress = info->NewThread.StartAddress; + break; + } + case DbgCreateProcessStateChange: + { + DBGUI_CREATE_PROCESS *info = &state->StateInfo.CreateProcessInfo; + event->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT; + event->u.CreateProcessInfo.hFile = info->NewProcess.FileHandle; + event->u.CreateProcessInfo.hProcess = info->HandleToProcess; + event->u.CreateProcessInfo.hThread = info->HandleToThread; + event->u.CreateProcessInfo.lpBaseOfImage = info->NewProcess.BaseOfImage; + event->u.CreateProcessInfo.dwDebugInfoFileOffset = info->NewProcess.DebugInfoFileOffset; + event->u.CreateProcessInfo.nDebugInfoSize = info->NewProcess.DebugInfoSize; + event->u.CreateProcessInfo.lpThreadLocalBase = get_thread_teb( info->HandleToThread ); + event->u.CreateProcessInfo.lpStartAddress = info->NewProcess.InitialThread.StartAddress; + event->u.CreateProcessInfo.lpImageName = NULL; + event->u.CreateProcessInfo.fUnicode = TRUE; + break; + } + case DbgExitThreadStateChange: + { + DBGKM_EXIT_THREAD *info = &state->StateInfo.ExitThread; + event->dwDebugEventCode = EXIT_THREAD_DEBUG_EVENT; + event->u.ExitThread.dwExitCode = info->ExitStatus; + break; + } + case DbgExitProcessStateChange: + { + DBGKM_EXIT_PROCESS *info = &state->StateInfo.ExitProcess; + event->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT; + event->u.ExitProcess.dwExitCode = info->ExitStatus; + break; + } + case DbgExceptionStateChange: + case DbgBreakpointStateChange: + case DbgSingleStepStateChange: + { + DBGKM_EXCEPTION *info = &state->StateInfo.Exception; + DWORD code = info->ExceptionRecord.ExceptionCode; + if (code == DBG_PRINTEXCEPTION_C && info->ExceptionRecord.NumberParameters >= 2) + { + event->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; + event->u.DebugString.lpDebugStringData = (void *)info->ExceptionRecord.ExceptionInformation[1]; + event->u.DebugString.fUnicode = FALSE; + event->u.DebugString.nDebugStringLength = info->ExceptionRecord.ExceptionInformation[0]; + } + else if (code == DBG_RIPEXCEPTION && info->ExceptionRecord.NumberParameters >= 2) + { + event->dwDebugEventCode = RIP_EVENT; + event->u.RipInfo.dwError = info->ExceptionRecord.ExceptionInformation[0]; + event->u.RipInfo.dwType = info->ExceptionRecord.ExceptionInformation[1]; + } + else + { + event->dwDebugEventCode = EXCEPTION_DEBUG_EVENT; + event->u.Exception.ExceptionRecord = info->ExceptionRecord; + event->u.Exception.dwFirstChance = info->FirstChance; + } + break; + } + case DbgLoadDllStateChange: + { + DBGKM_LOAD_DLL *info = &state->StateInfo.LoadDll; + event->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT; + event->u.LoadDll.hFile = info->FileHandle; + event->u.LoadDll.lpBaseOfDll = info->BaseOfDll; + event->u.LoadDll.dwDebugInfoFileOffset = info->DebugInfoFileOffset; + event->u.LoadDll.nDebugInfoSize = info->DebugInfoSize; + event->u.LoadDll.lpImageName = info->NamePointer; + event->u.LoadDll.fUnicode = TRUE; + break; + } + case DbgUnloadDllStateChange: + { + DBGKM_UNLOAD_DLL *info = &state->StateInfo.UnloadDll; + event->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT; + event->u.UnloadDll.lpBaseOfDll = info->BaseAddress; + break; + } + default: + return STATUS_UNSUCCESSFUL; + } + return STATUS_SUCCESS; +} + /*********************************************************************** * DbgUiRemoteBreakin (NTDLL.@) */ diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index ec8f0ad6535..1673686bddf 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -45,6 +45,7 @@ static NTSTATUS (WINAPI * pNtOpenThread)(HANDLE *, ACCESS_MASK, const OBJECT_ATT static NTSTATUS (WINAPI * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, void *, ULONG, ULONG *); static NTSTATUS (WINAPI * pNtCreateDebugObject)( HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG ); static NTSTATUS (WINAPI * pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,PVOID,ULONG,ULONG*); +static NTSTATUS (WINAPI * pDbgUiConvertStateChangeStructure)(DBGUI_WAIT_STATE_CHANGE*,DEBUG_EVENT*); static BOOL is_wow64; @@ -96,6 +97,7 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(NtQueryObject); NTDLL_GET_PROC(NtCreateDebugObject); NTDLL_GET_PROC(NtSetInformationDebugObject); + NTDLL_GET_PROC(DbgUiConvertStateChangeStructure); /* not present before XP */ pNtGetCurrentProcessorNumber = (void *) GetProcAddress(hntdll, "NtGetCurrentProcessorNumber"); @@ -2759,6 +2761,8 @@ static void test_debug_object(void) HANDLE handle; OBJECT_ATTRIBUTES attr = { sizeof(attr) }; ULONG len, flag = 0; + DBGUI_WAIT_STATE_CHANGE state; + DEBUG_EVENT event; status = pNtCreateDebugObject( &handle, DEBUG_ALL_ACCESS, &attr, 0 ); ok( !status, "NtCreateDebugObject failed %x\n", status ); @@ -2802,6 +2806,57 @@ static void test_debug_object(void) } pNtClose( handle ); + + memset( &state, 0xdd, sizeof(state) ); + state.NewState = DbgIdle; + memset( &event, 0xcc, sizeof(event) ); + status = pDbgUiConvertStateChangeStructure( &state, &event ); + ok( status == STATUS_UNSUCCESSFUL, "DbgUiConvertStateChangeStructure failed %x\n", status ); + ok( event.dwProcessId == 0xdddddddd, "event not updated %x\n", event.dwProcessId ); + ok( event.dwThreadId == 0xdddddddd, "event not updated %x\n", event.dwThreadId ); + + state.NewState = DbgReplyPending; + memset( &event, 0xcc, sizeof(event) ); + status = pDbgUiConvertStateChangeStructure( &state, &event ); + ok( status == STATUS_UNSUCCESSFUL, "DbgUiConvertStateChangeStructure failed %x\n", status ); + ok( event.dwProcessId == 0xdddddddd, "event not updated %x\n", event.dwProcessId ); + ok( event.dwThreadId == 0xdddddddd, "event not updated %x\n", event.dwThreadId ); + + state.NewState = 11; + memset( &event, 0xcc, sizeof(event) ); + status = pDbgUiConvertStateChangeStructure( &state, &event ); + ok( status == STATUS_UNSUCCESSFUL, "DbgUiConvertStateChangeStructure failed %x\n", status ); + ok( event.dwProcessId == 0xdddddddd, "event not updated %x\n", event.dwProcessId ); + ok( event.dwThreadId == 0xdddddddd, "event not updated %x\n", event.dwThreadId ); + + state.NewState = DbgExitProcessStateChange; + state.StateInfo.ExitProcess.ExitStatus = 0x123456; + status = pDbgUiConvertStateChangeStructure( &state, &event ); + ok( !status, "DbgUiConvertStateChangeStructure failed %x\n", status ); + ok( event.dwProcessId == 0xdddddddd, "event not updated %x\n", event.dwProcessId ); + ok( event.dwThreadId == 0xdddddddd, "event not updated %x\n", event.dwThreadId ); + ok( event.u.ExitProcess.dwExitCode == 0x123456, "event not updated %x\n", event.u.ExitProcess.dwExitCode ); + + memset( &state, 0xdd, sizeof(state) ); + state.NewState = DbgCreateProcessStateChange; + status = pDbgUiConvertStateChangeStructure( &state, &event ); + ok( !status, "DbgUiConvertStateChangeStructure failed %x\n", status ); + ok( event.dwProcessId == 0xdddddddd, "event not updated %x\n", event.dwProcessId ); + ok( event.dwThreadId == 0xdddddddd, "event not updated %x\n", event.dwThreadId ); + ok( event.u.CreateProcessInfo.nDebugInfoSize == 0xdddddddd, "event not updated %x\n", event.u.CreateProcessInfo.nDebugInfoSize ); + ok( event.u.CreateProcessInfo.lpThreadLocalBase == NULL, "event not updated %p\n", event.u.CreateProcessInfo.lpThreadLocalBase ); + ok( event.u.CreateProcessInfo.lpImageName == NULL, "event not updated %p\n", event.u.CreateProcessInfo.lpImageName ); + ok( event.u.CreateProcessInfo.fUnicode == TRUE, "event not updated %x\n", event.u.CreateProcessInfo.fUnicode ); + + memset( &state, 0xdd, sizeof(state) ); + state.NewState = DbgLoadDllStateChange; + status = pDbgUiConvertStateChangeStructure( &state, &event ); + ok( !status, "DbgUiConvertStateChangeStructure failed %x\n", status ); + ok( event.dwProcessId == 0xdddddddd, "event not updated %x\n", event.dwProcessId ); + ok( event.dwThreadId == 0xdddddddd, "event not updated %x\n", event.dwThreadId ); + ok( event.u.LoadDll.nDebugInfoSize == 0xdddddddd, "event not updated %x\n", event.u.LoadDll.nDebugInfoSize ); + ok( PtrToUlong(event.u.LoadDll.lpImageName) == 0xdddddddd, "event not updated %p\n", event.u.LoadDll.lpImageName ); + ok( event.u.LoadDll.fUnicode == TRUE, "event not updated %x\n", event.u.LoadDll.fUnicode ); } START_TEST(info) diff --git a/include/winternl.h b/include/winternl.h index 000c7f6f987..5523544fd36 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3007,6 +3007,98 @@ typedef struct _PS_CREATE_INFO }; } PS_CREATE_INFO, *PPS_CREATE_INFO; +typedef struct _DBGKM_EXCEPTION +{ + EXCEPTION_RECORD ExceptionRecord; + ULONG FirstChance; +} DBGKM_EXCEPTION, *PDBGKM_EXCEPTION; + +typedef struct _DBGKM_CREATE_THREAD +{ + ULONG SubSystemKey; + PVOID StartAddress; +} DBGKM_CREATE_THREAD, *PDBGKM_CREATE_THREAD; + +typedef struct _DBGKM_CREATE_PROCESS +{ + ULONG SubSystemKey; + HANDLE FileHandle; + PVOID BaseOfImage; + ULONG DebugInfoFileOffset; + ULONG DebugInfoSize; + DBGKM_CREATE_THREAD InitialThread; +} DBGKM_CREATE_PROCESS, *PDBGKM_CREATE_PROCESS; + +typedef struct _DBGKM_EXIT_THREAD +{ + NTSTATUS ExitStatus; +} DBGKM_EXIT_THREAD, *PDBGKM_EXIT_THREAD; + +typedef struct _DBGKM_EXIT_PROCESS +{ + NTSTATUS ExitStatus; +} DBGKM_EXIT_PROCESS, *PDBGKM_EXIT_PROCESS; + +typedef struct _DBGKM_LOAD_DLL +{ + HANDLE FileHandle; + PVOID BaseOfDll; + ULONG DebugInfoFileOffset; + ULONG DebugInfoSize; + PVOID NamePointer; +} DBGKM_LOAD_DLL, *PDBGKM_LOAD_DLL; + +typedef struct _DBGKM_UNLOAD_DLL +{ + PVOID BaseAddress; +} DBGKM_UNLOAD_DLL, *PDBGKM_UNLOAD_DLL; + +typedef enum _DBG_STATE +{ + DbgIdle, + DbgReplyPending, + DbgCreateThreadStateChange, + DbgCreateProcessStateChange, + DbgExitThreadStateChange, + DbgExitProcessStateChange, + DbgExceptionStateChange, + DbgBreakpointStateChange, + DbgSingleStepStateChange, + DbgLoadDllStateChange, + DbgUnloadDllStateChange +} DBG_STATE, *PDBG_STATE; + +typedef struct _DBGUI_CREATE_THREAD +{ + HANDLE HandleToThread; + DBGKM_CREATE_THREAD NewThread; +} DBGUI_CREATE_THREAD, *PDBGUI_CREATE_THREAD; + +typedef struct _DBGUI_CREATE_PROCESS +{ + HANDLE HandleToProcess; + HANDLE HandleToThread; + DBGKM_CREATE_PROCESS NewProcess; +} DBGUI_CREATE_PROCESS, *PDBGUI_CREATE_PROCESS; + +typedef struct _DBGUI_WAIT_STATE_CHANGE +{ + DBG_STATE NewState; + CLIENT_ID AppClientId; + union + { + DBGKM_EXCEPTION Exception; + DBGUI_CREATE_THREAD CreateThread; + DBGUI_CREATE_PROCESS CreateProcessInfo; + DBGKM_EXIT_THREAD ExitThread; + DBGKM_EXIT_PROCESS ExitProcess; + DBGKM_LOAD_DLL LoadDll; + DBGKM_UNLOAD_DLL UnloadDll; + } StateInfo; +} DBGUI_WAIT_STATE_CHANGE, *PDBGUI_WAIT_STATE_CHANGE; + +struct _DEBUG_EVENT; + #define DEBUG_READ_EVENT 0x0001 #define DEBUG_PROCESS_ASSIGN 0x0002 #define DEBUG_SET_INFORMATION 0x0004 @@ -3030,6 +3122,7 @@ NTSYSAPI NTSTATUS WINAPIV DbgPrint(LPCSTR fmt, ...); NTSYSAPI NTSTATUS WINAPIV DbgPrintEx(ULONG iComponentId, ULONG Level, LPCSTR fmt, ...); NTSYSAPI NTSTATUS WINAPI DbgUiConnectToDbg(void); NTSYSAPI NTSTATUS WINAPI DbgUiContinue(CLIENT_ID*,NTSTATUS); +NTSYSAPI NTSTATUS WINAPI DbgUiConvertStateChangeStructure(DBGUI_WAIT_STATE_CHANGE*,struct _DEBUG_EVENT*); NTSYSAPI NTSTATUS WINAPI DbgUiDebugActiveProcess(HANDLE); NTSYSAPI HANDLE WINAPI DbgUiGetThreadDebugObject(void); NTSYSAPI NTSTATUS WINAPI DbgUiIssueRemoteBreakin(HANDLE);