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
== -1U) dwProcessId
= (DWORD
)CsrGetProcessId();
237 /* Open a handle to the process */
238 ClientId
.UniqueThread
= NULL
;
239 ClientId
.UniqueProcess
= (HANDLE
)dwProcessId
;
240 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
241 Status
= NtOpenProcess(&Handle
,
245 if (!NT_SUCCESS(Status
))
248 SetLastErrorByStatus(Status
);
252 /* Return the handle */
256 /* PUBLIC FUNCTIONS **********************************************************/
263 CheckRemoteDebuggerPresent(IN HANDLE hProcess
,
264 OUT PBOOL pbDebuggerPresent
)
269 /* Make sure we have an output and process*/
270 if (!(pbDebuggerPresent
) || !(hProcess
))
273 SetLastError(ERROR_INVALID_PARAMETER
);
277 /* Check if the process has a debug object/port */
278 Status
= NtQueryInformationProcess(hProcess
,
283 if (NT_SUCCESS(Status
))
285 /* Return the current state */
286 *pbDebuggerPresent
= (DebugPort
) ? TRUE
: FALSE
;
290 /* Otherwise, fail */
291 SetLastErrorByStatus(Status
);
300 ContinueDebugEvent(IN DWORD dwProcessId
,
302 IN DWORD dwContinueStatus
)
307 /* Set the Client ID */
308 ClientId
.UniqueProcess
= (HANDLE
)dwProcessId
;
309 ClientId
.UniqueThread
= (HANDLE
)dwThreadId
;
311 /* Continue debugging */
312 Status
= DbgUiContinue(&ClientId
, dwContinueStatus
);
313 if (!NT_SUCCESS(Status
))
316 SetLastErrorByStatus(Status
);
320 /* Remove the process/thread handles */
321 RemoveHandles(dwProcessId
, dwThreadId
);
332 DebugActiveProcess(IN DWORD dwProcessId
)
337 /* Connect to the debugger */
338 Status
= DbgUiConnectToDbg();
339 if (!NT_SUCCESS(Status
))
341 SetLastErrorByStatus(Status
);
345 /* Get the process handle */
346 Handle
= ProcessIdToHandle(dwProcessId
);
347 if (!Handle
) return FALSE
;
349 /* Now debug the process */
350 Status
= DbgUiDebugActiveProcess(Handle
);
353 /* Check if debugging worked */
354 if (!NT_SUCCESS(Status
))
357 SetLastErrorByStatus(Status
);
370 DebugActiveProcessStop(IN DWORD dwProcessId
)
375 /* Get the process handle */
376 Handle
= ProcessIdToHandle(dwProcessId
);
377 if (!Handle
) return FALSE
;
379 /* Close all the process handles */
380 CloseAllProcessHandles(dwProcessId
);
382 /* Now stop debgging the process */
383 Status
= DbgUiStopDebugging(Handle
);
386 /* Check for failure */
387 if (!NT_SUCCESS(Status
))
390 SetLastError(ERROR_ACCESS_DENIED
);
403 DebugBreakProcess(IN HANDLE Process
)
407 /* Send the breakin request */
408 Status
= DbgUiIssueRemoteBreakin(Process
);
409 if(!NT_SUCCESS(Status
))
412 SetLastErrorByStatus(Status
);
425 DebugSetProcessKillOnExit(IN BOOL KillOnExit
)
431 /* Get the debug object */
432 Handle
= DbgUiGetThreadDebugObject();
436 SetLastErrorByStatus(STATUS_INVALID_HANDLE
);
440 /* Now set the kill-on-exit state */
442 Status
= NtSetInformationDebugObject(Handle
,
443 DebugObjectKillProcessOnExitInformation
,
447 if (!NT_SUCCESS(Status
))
450 SetLastError(Status
);
463 IsDebuggerPresent(VOID
)
465 return (BOOL
)NtCurrentPeb()->BeingDebugged
;
473 WaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent
,
474 IN DWORD dwMilliseconds
)
476 LARGE_INTEGER WaitTime
;
477 PLARGE_INTEGER Timeout
;
478 DBGUI_WAIT_STATE_CHANGE WaitStateChange
;
481 /* Check if this is an infinite wait */
482 if (dwMilliseconds
== INFINITE
)
484 /* Under NT, this means no timer argument */
489 /* Otherwise, convert the time to NT Format */
490 WaitTime
.QuadPart
= UInt32x32To64(-10000, dwMilliseconds
);
494 /* Loop while we keep getting interrupted */
497 /* Call the native API */
498 Status
= DbgUiWaitStateChange(&WaitStateChange
, Timeout
);
499 } while ((Status
== STATUS_ALERTED
) || (Status
== STATUS_USER_APC
));
501 /* Check if the wait failed */
502 if (!(NT_SUCCESS(Status
)) || (Status
== DBG_UNABLE_TO_PROVIDE_HANDLE
))
504 /* Set the error code and quit */
505 SetLastErrorByStatus(Status
);
509 /* Check if we timed out */
510 if (Status
== STATUS_TIMEOUT
)
512 /* Fail with a timeout error */
513 SetLastError(ERROR_SEM_TIMEOUT
);
517 /* Convert the structure */
518 Status
= DbgUiConvertStateChangeStructure(&WaitStateChange
, lpDebugEvent
);
519 if (!NT_SUCCESS(Status
))
521 /* Set the error code and quit */
522 SetLastErrorByStatus(Status
);
526 /* Check what kind of event this was */
527 switch (lpDebugEvent
->dwDebugEventCode
)
529 /* New thread was created */
530 case CREATE_THREAD_DEBUG_EVENT
:
532 /* Setup the thread data */
533 SaveThreadHandle(lpDebugEvent
->dwProcessId
,
534 lpDebugEvent
->dwThreadId
,
535 lpDebugEvent
->u
.CreateThread
.hThread
);
538 /* New process was created */
539 case CREATE_PROCESS_DEBUG_EVENT
:
541 /* Setup the process data */
542 SaveProcessHandle(lpDebugEvent
->dwProcessId
,
543 lpDebugEvent
->u
.CreateProcessInfo
.hProcess
);
545 /* Setup the thread data */
546 SaveThreadHandle(lpDebugEvent
->dwProcessId
,
547 lpDebugEvent
->dwThreadId
,
548 lpDebugEvent
->u
.CreateThread
.hThread
);
551 /* Process was exited */
552 case EXIT_PROCESS_DEBUG_EVENT
:
554 /* Mark the thread data as such */
555 MarkProcessHandle(lpDebugEvent
->dwProcessId
);
558 /* Thread was exited */
559 case EXIT_THREAD_DEBUG_EVENT
:
561 /* Mark the thread data */
562 MarkThreadHandle(lpDebugEvent
->dwThreadId
);
565 /* Nothing to do for anything else */