2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/debug/debugger.c
5 * PURPOSE: Wrappers for the NT Debug Implementation
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 typedef struct _DBGSS_THREAD_DATA
17 struct _DBGSS_THREAD_DATA
*Next
;
23 } DBGSS_THREAD_DATA
, *PDBGSS_THREAD_DATA
;
25 #define DbgSsSetThreadData(d) \
26 NtCurrentTeb()->DbgSsReserved[0] = d
28 #define DbgSsGetThreadData() \
29 ((PDBGSS_THREAD_DATA)NtCurrentTeb()->DbgSsReserved[0])
31 /* PRIVATE FUNCTIONS *********************************************************/
35 SaveThreadHandle(IN DWORD dwProcessId
,
39 PDBGSS_THREAD_DATA ThreadData
;
41 /* Allocate a thread structure */
42 ThreadData
= RtlAllocateHeap(RtlGetProcessHeap(),
44 sizeof(DBGSS_THREAD_DATA
));
45 if (!ThreadData
) return;
48 ThreadData
->ThreadHandle
= hThread
;
49 ThreadData
->ProcessId
= dwProcessId
;
50 ThreadData
->ThreadId
= dwThreadId
;
51 ThreadData
->ProcessHandle
= NULL
;
52 ThreadData
->HandleMarked
= FALSE
;
55 ThreadData
->Next
= DbgSsGetThreadData();
56 DbgSsSetThreadData(ThreadData
);
61 SaveProcessHandle(IN DWORD dwProcessId
,
64 PDBGSS_THREAD_DATA ThreadData
;
66 /* Allocate a thread structure */
67 ThreadData
= RtlAllocateHeap(RtlGetProcessHeap(),
69 sizeof(DBGSS_THREAD_DATA
));
70 if (!ThreadData
) return;
73 ThreadData
->ProcessHandle
= hProcess
;
74 ThreadData
->ProcessId
= dwProcessId
;
75 ThreadData
->ThreadId
= 0;
76 ThreadData
->ThreadHandle
= NULL
;
77 ThreadData
->HandleMarked
= FALSE
;
80 ThreadData
->Next
= DbgSsGetThreadData();
81 DbgSsSetThreadData(ThreadData
);
86 MarkThreadHandle(IN DWORD dwThreadId
)
88 PDBGSS_THREAD_DATA ThreadData
;
90 /* Loop all thread data events */
91 ThreadData
= DbgSsGetThreadData();
94 /* Check if this one matches */
95 if (ThreadData
->ThreadId
== dwThreadId
)
97 /* Mark the structure and break out */
98 ThreadData
->HandleMarked
= TRUE
;
102 /* Move to the next one */
103 ThreadData
= ThreadData
->Next
;
109 MarkProcessHandle(IN DWORD dwProcessId
)
111 PDBGSS_THREAD_DATA ThreadData
;
113 /* Loop all thread data events */
114 ThreadData
= DbgSsGetThreadData();
117 /* Check if this one matches */
118 if (ThreadData
->ProcessId
== dwProcessId
)
120 /* Make sure the thread ID is empty */
121 if (!ThreadData
->ThreadId
)
123 /* Mark the structure and break out */
124 ThreadData
->HandleMarked
= TRUE
;
129 /* Move to the next one */
130 ThreadData
= ThreadData
->Next
;
136 RemoveHandles(IN DWORD dwProcessId
,
139 PDBGSS_THREAD_DATA ThreadData
;
141 /* Loop all thread data events */
142 ThreadData
= DbgSsGetThreadData();
145 /* Check if this one matches */
146 if (ThreadData
->ProcessId
== dwProcessId
)
148 /* Make sure the thread ID matches too */
149 if (ThreadData
->ThreadId
== dwThreadId
)
151 /* Check if we have a thread handle */
152 if (ThreadData
->ThreadHandle
)
155 CloseHandle(ThreadData
->ThreadHandle
);
158 /* Check if we have a process handle */
159 if (ThreadData
->ProcessHandle
)
162 CloseHandle(ThreadData
->ProcessHandle
);
165 /* Unlink the thread data */
166 DbgSsSetThreadData(ThreadData
->Next
);
169 RtlFreeHeap(RtlGetProcessHeap(), 0, ThreadData
);
171 /* Move to the next structure */
172 ThreadData
= DbgSsGetThreadData();
177 /* Move to the next one */
178 ThreadData
= ThreadData
->Next
;
184 CloseAllProcessHandles(IN DWORD dwProcessId
)
186 PDBGSS_THREAD_DATA ThreadData
;
188 /* Loop all thread data events */
189 ThreadData
= DbgSsGetThreadData();
192 /* Check if this one matches */
193 if (ThreadData
->ProcessId
== dwProcessId
)
195 /* Check if we have a thread handle */
196 if (ThreadData
->ThreadHandle
)
199 CloseHandle(ThreadData
->ThreadHandle
);
202 /* Check if we have a process handle */
203 if (ThreadData
->ProcessHandle
)
206 CloseHandle(ThreadData
->ProcessHandle
);
209 /* Unlink the thread data */
210 DbgSsSetThreadData(ThreadData
->Next
);
213 RtlFreeHeap(RtlGetProcessHeap(), 0, ThreadData
);
215 /* Move to the next structure */
216 ThreadData
= DbgSsGetThreadData();
220 /* Move to the next one */
221 ThreadData
= ThreadData
->Next
;
227 ProcessIdToHandle(IN DWORD dwProcessId
)
230 OBJECT_ATTRIBUTES ObjectAttributes
;
234 /* If we don't have a PID, look it up */
235 if (dwProcessId
== -1) dwProcessId
= (DWORD
)CsrGetProcessId();
237 /* Open a handle to the process */
238 ClientId
.UniqueProcess
= (HANDLE
)dwProcessId
;
239 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
240 Status
= NtOpenProcess(&Handle
,
244 if (!NT_SUCCESS(Status
))
247 SetLastErrorByStatus(Status
);
251 /* Return the handle */
255 /* PUBLIC FUNCTIONS **********************************************************/
262 CheckRemoteDebuggerPresent(IN HANDLE hProcess
,
263 OUT PBOOL pbDebuggerPresent
)
268 /* Make sure we have an output and process*/
269 if (!(pbDebuggerPresent
) || !(hProcess
))
272 SetLastError(ERROR_INVALID_PARAMETER
);
276 /* Check if the process has a debug object/port */
277 Status
= NtQueryInformationProcess(hProcess
,
282 if (NT_SUCCESS(Status
))
284 /* Return the current state */
285 *pbDebuggerPresent
= (DebugPort
) ? TRUE
: FALSE
;
289 /* Otherwise, fail */
290 SetLastErrorByStatus(Status
);
299 ContinueDebugEvent(IN DWORD dwProcessId
,
301 IN DWORD dwContinueStatus
)
306 /* Set the Client ID */
307 ClientId
.UniqueProcess
= (HANDLE
)dwProcessId
;
308 ClientId
.UniqueThread
= (HANDLE
)dwThreadId
;
310 /* Continue debugging */
311 Status
= DbgUiContinue(&ClientId
, dwContinueStatus
);
312 if (!NT_SUCCESS(Status
))
315 SetLastErrorByStatus(Status
);
319 /* Remove the process/thread handles */
320 RemoveHandles(dwProcessId
, dwThreadId
);
331 DebugActiveProcess(IN DWORD dwProcessId
)
336 /* Connect to the debugger */
337 Status
= DbgUiConnectToDbg();
338 if (!NT_SUCCESS(Status
))
340 SetLastErrorByStatus(Status
);
344 /* Get the process handle */
345 Handle
= ProcessIdToHandle(dwProcessId
);
346 if (!Handle
) return FALSE
;
348 /* Now debug the process */
349 Status
= DbgUiDebugActiveProcess(Handle
);
352 /* Check if debugging worked */
353 if (!NT_SUCCESS(Status
))
356 SetLastErrorByStatus(Status
);
369 DebugActiveProcessStop(IN DWORD dwProcessId
)
374 /* Get the process handle */
375 Handle
= ProcessIdToHandle(dwProcessId
);
376 if (!Handle
) return FALSE
;
378 /* Close all the process handles */
379 CloseAllProcessHandles(dwProcessId
);
381 /* Now stop debgging the process */
382 Status
= DbgUiStopDebugging(Handle
);
385 /* Check for failure */
386 if (!NT_SUCCESS(Status
))
389 SetLastError(ERROR_ACCESS_DENIED
);
402 DebugBreakProcess(IN HANDLE Process
)
406 /* Send the breakin request */
407 Status
= DbgUiIssueRemoteBreakin(Process
);
408 if(!NT_SUCCESS(Status
))
411 SetLastErrorByStatus(Status
);
424 DebugSetProcessKillOnExit(IN BOOL KillOnExit
)
430 /* Get the debug object */
431 Handle
= DbgUiGetThreadDebugObject();
435 SetLastErrorByStatus(STATUS_INVALID_HANDLE
);
439 /* Now set the kill-on-exit state */
441 Status
= NtSetInformationDebugObject(Handle
,
442 DebugObjectKillProcessOnExitInformation
,
446 if (!NT_SUCCESS(Status
))
449 SetLastError(Status
);
462 IsDebuggerPresent(VOID
)
464 return (BOOL
)NtCurrentPeb()->BeingDebugged
;
472 WaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent
,
473 IN DWORD dwMilliseconds
)
475 LARGE_INTEGER WaitTime
;
476 PLARGE_INTEGER Timeout
;
477 DBGUI_WAIT_STATE_CHANGE WaitStateChange
;
480 /* Check if this is an infinite wait */
481 if (dwMilliseconds
== INFINITE
)
483 /* Under NT, this means no timer argument */
488 /* Otherwise, convert the time to NT Format */
489 WaitTime
.QuadPart
= UInt32x32To64(-10000, dwMilliseconds
);
493 /* Loop while we keep getting interrupted */
496 /* Call the native API */
497 Status
= DbgUiWaitStateChange(&WaitStateChange
, Timeout
);
498 } while ((Status
== STATUS_ALERTED
) || (Status
== STATUS_USER_APC
));
500 /* Check if the wait failed */
501 if (!(NT_SUCCESS(Status
)) || (Status
!= DBG_UNABLE_TO_PROVIDE_HANDLE
))
503 /* Set the error code and quit */
504 SetLastErrorByStatus(Status
);
508 /* Check if we timed out */
509 if (Status
== STATUS_TIMEOUT
)
511 /* Fail with a timeout error */
512 SetLastError(ERROR_SEM_TIMEOUT
);
516 /* Convert the structure */
517 Status
= DbgUiConvertStateChangeStructure(&WaitStateChange
, lpDebugEvent
);
518 if (!NT_SUCCESS(Status
))
520 /* Set the error code and quit */
521 SetLastErrorByStatus(Status
);
525 /* Check what kind of event this was */
526 switch (lpDebugEvent
->dwDebugEventCode
)
528 /* New thread was created */
529 case CREATE_THREAD_DEBUG_EVENT
:
531 /* Setup the thread data */
532 SaveThreadHandle(lpDebugEvent
->dwProcessId
,
533 lpDebugEvent
->dwThreadId
,
534 lpDebugEvent
->u
.CreateThread
.hThread
);
537 /* New process was created */
538 case CREATE_PROCESS_DEBUG_EVENT
:
540 /* Setup the process data */
541 SaveProcessHandle(lpDebugEvent
->dwProcessId
,
542 lpDebugEvent
->u
.CreateProcessInfo
.hProcess
);
544 /* Setup the thread data */
545 SaveThreadHandle(lpDebugEvent
->dwProcessId
,
546 lpDebugEvent
->dwThreadId
,
547 lpDebugEvent
->u
.CreateThread
.hThread
);
550 /* Process was exited */
551 case EXIT_PROCESS_DEBUG_EVENT
:
553 /* Mark the thread data as such */
554 MarkProcessHandle(lpDebugEvent
->dwProcessId
);
557 /* Thread was exited */
558 case EXIT_THREAD_DEBUG_EVENT
:
560 /* Mark the thread data */
561 MarkThreadHandle(lpDebugEvent
->dwThreadId
);
564 /* Nothing to do for anything else */