xref: /reactos/dll/ntdll/dbg/dbgui.c (revision 9393fc32)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS NT Layer/System API
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            dll/ntdll/dbg/dbgui.c
5c2c66affSColin Finck  * PURPOSE:         Native Wrappers for the NT Debug Implementation
6c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES *****************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include <ntdll.h>
12c2c66affSColin Finck 
13c2c66affSColin Finck #include <ndk/dbgkfuncs.h>
14c2c66affSColin Finck 
15c2c66affSColin Finck #define NDEBUG
16c2c66affSColin Finck #include <debug.h>
17c2c66affSColin Finck 
18c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
19c2c66affSColin Finck 
20c2c66affSColin Finck /*
21c2c66affSColin Finck  * @implemented
22c2c66affSColin Finck  */
23c2c66affSColin Finck NTSTATUS
24c2c66affSColin Finck NTAPI
DbgUiConnectToDbg(VOID)25c2c66affSColin Finck DbgUiConnectToDbg(VOID)
26c2c66affSColin Finck {
27c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
28c2c66affSColin Finck 
29c2c66affSColin Finck     /* Don't connect twice */
30c2c66affSColin Finck     if (NtCurrentTeb()->DbgSsReserved[1]) return STATUS_SUCCESS;
31c2c66affSColin Finck 
32c2c66affSColin Finck     /* Setup the Attributes */
33c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, 0);
34c2c66affSColin Finck 
35c2c66affSColin Finck     /* Create the object */
36c2c66affSColin Finck     return ZwCreateDebugObject(&NtCurrentTeb()->DbgSsReserved[1],
37c2c66affSColin Finck                                DEBUG_OBJECT_ALL_ACCESS,
38c2c66affSColin Finck                                &ObjectAttributes,
39c2c66affSColin Finck                                DBGK_KILL_PROCESS_ON_EXIT);
40c2c66affSColin Finck }
41c2c66affSColin Finck 
42c2c66affSColin Finck /*
43c2c66affSColin Finck  * @implemented
44c2c66affSColin Finck  */
45c2c66affSColin Finck NTSTATUS
46c2c66affSColin Finck NTAPI
DbgUiContinue(IN PCLIENT_ID ClientId,IN NTSTATUS ContinueStatus)47c2c66affSColin Finck DbgUiContinue(IN PCLIENT_ID ClientId,
48c2c66affSColin Finck               IN NTSTATUS ContinueStatus)
49c2c66affSColin Finck {
50c2c66affSColin Finck     /* Tell the kernel object to continue */
51c2c66affSColin Finck     return ZwDebugContinue(NtCurrentTeb()->DbgSsReserved[1],
52c2c66affSColin Finck                            ClientId,
53c2c66affSColin Finck                            ContinueStatus);
54c2c66affSColin Finck }
55c2c66affSColin Finck 
56c2c66affSColin Finck /*
57c2c66affSColin Finck  * @implemented
58c2c66affSColin Finck  */
59c2c66affSColin Finck NTSTATUS
60c2c66affSColin Finck NTAPI
DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange,OUT PVOID Win32DebugEvent)61c2c66affSColin Finck DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
62c2c66affSColin Finck                                  OUT PVOID Win32DebugEvent)
63c2c66affSColin Finck {
64c2c66affSColin Finck     NTSTATUS Status;
65c2c66affSColin Finck     THREAD_BASIC_INFORMATION ThreadBasicInfo;
66c2c66affSColin Finck     LPDEBUG_EVENT DebugEvent = Win32DebugEvent;
67c2c66affSColin Finck 
68c2c66affSColin Finck     /* Write common data */
69*a2f7de7eSTimo Kreuzer     DebugEvent->dwProcessId = PtrToUlong(WaitStateChange->AppClientId.UniqueProcess);
70*a2f7de7eSTimo Kreuzer     DebugEvent->dwThreadId = PtrToUlong(WaitStateChange->AppClientId.UniqueThread);
71c2c66affSColin Finck 
72c2c66affSColin Finck     /* Check what kind of even this is */
73c2c66affSColin Finck     switch (WaitStateChange->NewState)
74c2c66affSColin Finck     {
75c2c66affSColin Finck         /* New thread */
76c2c66affSColin Finck         case DbgCreateThreadStateChange:
77c2c66affSColin Finck         {
78c2c66affSColin Finck             /* Setup Win32 code */
79c2c66affSColin Finck             DebugEvent->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT;
80c2c66affSColin Finck 
81c2c66affSColin Finck             /* Copy data over */
82c2c66affSColin Finck             DebugEvent->u.CreateThread.hThread =
83c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateThread.HandleToThread;
84c2c66affSColin Finck             DebugEvent->u.CreateThread.lpStartAddress =
85c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress;
86c2c66affSColin Finck 
87c2c66affSColin Finck             /* Query the TEB */
88c2c66affSColin Finck             Status = NtQueryInformationThread(WaitStateChange->StateInfo.
89c2c66affSColin Finck                                               CreateThread.HandleToThread,
90c2c66affSColin Finck                                               ThreadBasicInformation,
91c2c66affSColin Finck                                               &ThreadBasicInfo,
92c2c66affSColin Finck                                               sizeof(ThreadBasicInfo),
93c2c66affSColin Finck                                               NULL);
94c2c66affSColin Finck             if (!NT_SUCCESS(Status))
95c2c66affSColin Finck             {
96c2c66affSColin Finck                 /* Failed to get PEB address */
97c2c66affSColin Finck                 DebugEvent->u.CreateThread.lpThreadLocalBase = NULL;
98c2c66affSColin Finck             }
99c2c66affSColin Finck             else
100c2c66affSColin Finck             {
101c2c66affSColin Finck                 /* Write PEB Address */
102c2c66affSColin Finck                 DebugEvent->u.CreateThread.lpThreadLocalBase =
103c2c66affSColin Finck                     ThreadBasicInfo.TebBaseAddress;
104c2c66affSColin Finck             }
105c2c66affSColin Finck             break;
106c2c66affSColin Finck         }
107c2c66affSColin Finck 
108c2c66affSColin Finck         /* New process */
109c2c66affSColin Finck         case DbgCreateProcessStateChange:
110c2c66affSColin Finck         {
111c2c66affSColin Finck             /* Write Win32 debug code */
112c2c66affSColin Finck             DebugEvent->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT;
113c2c66affSColin Finck 
114c2c66affSColin Finck             /* Copy data over */
115c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.hProcess =
116c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess;
117c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.hThread =
118c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread;
119c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.hFile =
120c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
121c2c66affSColin Finck                 FileHandle;
122c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.lpBaseOfImage =
123c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
124c2c66affSColin Finck                 BaseOfImage;
125c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.dwDebugInfoFileOffset =
126c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
127c2c66affSColin Finck                 DebugInfoFileOffset;
128c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.nDebugInfoSize =
129c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
130c2c66affSColin Finck                 DebugInfoSize;
131c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.lpStartAddress =
132c2c66affSColin Finck                 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
133c2c66affSColin Finck                 InitialThread.StartAddress;
134c2c66affSColin Finck 
135c2c66affSColin Finck             /* Query TEB address */
136c2c66affSColin Finck             Status = NtQueryInformationThread(WaitStateChange->StateInfo.
137c2c66affSColin Finck                                               CreateProcessInfo.HandleToThread,
138c2c66affSColin Finck                                               ThreadBasicInformation,
139c2c66affSColin Finck                                               &ThreadBasicInfo,
140c2c66affSColin Finck                                               sizeof(ThreadBasicInfo),
141c2c66affSColin Finck                                               NULL);
142c2c66affSColin Finck             if (!NT_SUCCESS(Status))
143c2c66affSColin Finck             {
144c2c66affSColin Finck                 /* Failed to get PEB address */
145c2c66affSColin Finck                 DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = NULL;
146c2c66affSColin Finck             }
147c2c66affSColin Finck             else
148c2c66affSColin Finck             {
149c2c66affSColin Finck                 /* Write PEB Address */
150c2c66affSColin Finck                 DebugEvent->u.CreateProcessInfo.lpThreadLocalBase =
151c2c66affSColin Finck                     ThreadBasicInfo.TebBaseAddress;
152c2c66affSColin Finck             }
153c2c66affSColin Finck 
154c2c66affSColin Finck             /* Clear image name */
155c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.lpImageName = NULL;
156c2c66affSColin Finck             DebugEvent->u.CreateProcessInfo.fUnicode = TRUE;
157c2c66affSColin Finck             break;
158c2c66affSColin Finck         }
159c2c66affSColin Finck 
160c2c66affSColin Finck         /* Thread exited */
161c2c66affSColin Finck         case DbgExitThreadStateChange:
162c2c66affSColin Finck         {
163c2c66affSColin Finck             /* Write the Win32 debug code and the exit status */
164c2c66affSColin Finck             DebugEvent->dwDebugEventCode = EXIT_THREAD_DEBUG_EVENT;
165c2c66affSColin Finck             DebugEvent->u.ExitThread.dwExitCode =
166c2c66affSColin Finck                 WaitStateChange->StateInfo.ExitThread.ExitStatus;
167c2c66affSColin Finck             break;
168c2c66affSColin Finck         }
169c2c66affSColin Finck 
170c2c66affSColin Finck         /* Process exited */
171c2c66affSColin Finck         case DbgExitProcessStateChange:
172c2c66affSColin Finck         {
173c2c66affSColin Finck             /* Write the Win32 debug code and the exit status */
174c2c66affSColin Finck             DebugEvent->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
175c2c66affSColin Finck             DebugEvent->u.ExitProcess.dwExitCode =
176c2c66affSColin Finck                 WaitStateChange->StateInfo.ExitProcess.ExitStatus;
177c2c66affSColin Finck             break;
178c2c66affSColin Finck         }
179c2c66affSColin Finck 
180c2c66affSColin Finck         /* Any sort of exception */
181c2c66affSColin Finck         case DbgExceptionStateChange:
182c2c66affSColin Finck         case DbgBreakpointStateChange:
183c2c66affSColin Finck         case DbgSingleStepStateChange:
184c2c66affSColin Finck         {
185c2c66affSColin Finck             /* Check if this was a debug print */
186c2c66affSColin Finck             if (WaitStateChange->StateInfo.Exception.ExceptionRecord.
187c2c66affSColin Finck                 ExceptionCode == DBG_PRINTEXCEPTION_C)
188c2c66affSColin Finck             {
189c2c66affSColin Finck                 /* Set the Win32 code */
190c2c66affSColin Finck                 DebugEvent->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
191c2c66affSColin Finck 
192c2c66affSColin Finck                 /* Copy debug string information */
193c2c66affSColin Finck                 DebugEvent->u.DebugString.lpDebugStringData =
194c2c66affSColin Finck                     (PVOID)WaitStateChange->
195c2c66affSColin Finck                            StateInfo.Exception.ExceptionRecord.
196c2c66affSColin Finck                            ExceptionInformation[1];
197c2c66affSColin Finck                 DebugEvent->u.DebugString.nDebugStringLength =
198c2c66affSColin Finck                     WaitStateChange->StateInfo.Exception.ExceptionRecord.
199c2c66affSColin Finck                     ExceptionInformation[0];
200c2c66affSColin Finck                 DebugEvent->u.DebugString.fUnicode = FALSE;
201c2c66affSColin Finck             }
202c2c66affSColin Finck             else if (WaitStateChange->StateInfo.Exception.ExceptionRecord.
203c2c66affSColin Finck                      ExceptionCode == DBG_RIPEXCEPTION)
204c2c66affSColin Finck             {
205c2c66affSColin Finck                 /* Set the Win32 code */
206c2c66affSColin Finck                 DebugEvent->dwDebugEventCode = RIP_EVENT;
207c2c66affSColin Finck 
208c2c66affSColin Finck                 /* Set exception information */
209c2c66affSColin Finck                 DebugEvent->u.RipInfo.dwType =
210c2c66affSColin Finck                     WaitStateChange->StateInfo.Exception.ExceptionRecord.
211c2c66affSColin Finck                     ExceptionInformation[1];
212c2c66affSColin Finck                 DebugEvent->u.RipInfo.dwError =
213c2c66affSColin Finck                     WaitStateChange->StateInfo.Exception.ExceptionRecord.
214c2c66affSColin Finck                     ExceptionInformation[0];
215c2c66affSColin Finck             }
216c2c66affSColin Finck             else
217c2c66affSColin Finck             {
218c2c66affSColin Finck                 /* Otherwise, this is a debug event, copy info over */
219c2c66affSColin Finck                 DebugEvent->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
220c2c66affSColin Finck                 DebugEvent->u.Exception.ExceptionRecord =
221c2c66affSColin Finck                     WaitStateChange->StateInfo.Exception.ExceptionRecord;
222c2c66affSColin Finck                 DebugEvent->u.Exception.dwFirstChance =
223c2c66affSColin Finck                     WaitStateChange->StateInfo.Exception.FirstChance;
224c2c66affSColin Finck             }
225c2c66affSColin Finck             break;
226c2c66affSColin Finck         }
227c2c66affSColin Finck 
228c2c66affSColin Finck         /* DLL Load */
229c2c66affSColin Finck         case DbgLoadDllStateChange:
230c2c66affSColin Finck         {
231c2c66affSColin Finck             /* Set the Win32 debug code */
232c2c66affSColin Finck             DebugEvent->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
233c2c66affSColin Finck 
234c2c66affSColin Finck             /* Copy the rest of the data */
235c2c66affSColin Finck             DebugEvent->u.LoadDll.hFile =
236c2c66affSColin Finck                 WaitStateChange->StateInfo.LoadDll.FileHandle;
237c2c66affSColin Finck             DebugEvent->u.LoadDll.lpBaseOfDll =
238c2c66affSColin Finck                 WaitStateChange->StateInfo.LoadDll.BaseOfDll;
239c2c66affSColin Finck             DebugEvent->u.LoadDll.dwDebugInfoFileOffset =
240c2c66affSColin Finck                 WaitStateChange->StateInfo.LoadDll.DebugInfoFileOffset;
241c2c66affSColin Finck             DebugEvent->u.LoadDll.nDebugInfoSize =
242c2c66affSColin Finck                 WaitStateChange->StateInfo.LoadDll.DebugInfoSize;
243c2c66affSColin Finck             DebugEvent->u.LoadDll.lpImageName =
244c2c66affSColin Finck                 WaitStateChange->StateInfo.LoadDll.NamePointer;
245c2c66affSColin Finck 
246c2c66affSColin Finck             /* It's Unicode */
247c2c66affSColin Finck             DebugEvent->u.LoadDll.fUnicode = TRUE;
248c2c66affSColin Finck             break;
249c2c66affSColin Finck         }
250c2c66affSColin Finck 
251c2c66affSColin Finck         /* DLL Unload */
252c2c66affSColin Finck         case DbgUnloadDllStateChange:
253c2c66affSColin Finck         {
254c2c66affSColin Finck             /* Set Win32 code and DLL Base */
255c2c66affSColin Finck             DebugEvent->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
256c2c66affSColin Finck             DebugEvent->u.UnloadDll.lpBaseOfDll =
257c2c66affSColin Finck                 WaitStateChange->StateInfo.UnloadDll.BaseAddress;
258c2c66affSColin Finck             break;
259c2c66affSColin Finck         }
260c2c66affSColin Finck 
261c2c66affSColin Finck         /* Anything else, fail */
262c2c66affSColin Finck         default: return STATUS_UNSUCCESSFUL;
263c2c66affSColin Finck     }
264c2c66affSColin Finck 
265c2c66affSColin Finck     /* Return success */
266c2c66affSColin Finck     return STATUS_SUCCESS;
267c2c66affSColin Finck }
268c2c66affSColin Finck 
269c2c66affSColin Finck /*
270c2c66affSColin Finck  * @implemented
271c2c66affSColin Finck  */
272c2c66affSColin Finck NTSTATUS
273c2c66affSColin Finck NTAPI
DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange,IN PLARGE_INTEGER TimeOut OPTIONAL)274c2c66affSColin Finck DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
275c2c66affSColin Finck                      IN PLARGE_INTEGER TimeOut OPTIONAL)
276c2c66affSColin Finck {
277c2c66affSColin Finck     /* Tell the kernel to wait */
278c2c66affSColin Finck     return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved[1],
279c2c66affSColin Finck                                TRUE,
280c2c66affSColin Finck                                TimeOut,
281c2c66affSColin Finck                                WaitStateChange);
282c2c66affSColin Finck }
283c2c66affSColin Finck 
284c2c66affSColin Finck /*
285c2c66affSColin Finck  * @implemented
286c2c66affSColin Finck  */
287c2c66affSColin Finck VOID
288c2c66affSColin Finck NTAPI
DbgUiRemoteBreakin(VOID)289c2c66affSColin Finck DbgUiRemoteBreakin(VOID)
290c2c66affSColin Finck {
291c2c66affSColin Finck     /* Make sure a debugger is enabled; if so, breakpoint */
292c2c66affSColin Finck     if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
293c2c66affSColin Finck 
294c2c66affSColin Finck     /* Exit the thread */
295c2c66affSColin Finck     RtlExitUserThread(STATUS_SUCCESS);
296c2c66affSColin Finck }
297c2c66affSColin Finck 
298c2c66affSColin Finck /*
299c2c66affSColin Finck  * @implemented
300c2c66affSColin Finck  */
301c2c66affSColin Finck NTSTATUS
302c2c66affSColin Finck NTAPI
DbgUiIssueRemoteBreakin(IN HANDLE Process)303c2c66affSColin Finck DbgUiIssueRemoteBreakin(IN HANDLE Process)
304c2c66affSColin Finck {
305c2c66affSColin Finck     HANDLE hThread;
306c2c66affSColin Finck     CLIENT_ID ClientId;
307c2c66affSColin Finck     NTSTATUS Status;
308c2c66affSColin Finck 
309c2c66affSColin Finck     /* Create the thread that will do the breakin */
310c2c66affSColin Finck     Status = RtlCreateUserThread(Process,
311c2c66affSColin Finck                                  NULL,
312c2c66affSColin Finck                                  FALSE,
313c2c66affSColin Finck                                  0,
314c2c66affSColin Finck                                  0,
315c2c66affSColin Finck                                  PAGE_SIZE,
316c2c66affSColin Finck                                  (PVOID)DbgUiRemoteBreakin,
317c2c66affSColin Finck                                  NULL,
318c2c66affSColin Finck                                  &hThread,
319c2c66affSColin Finck                                  &ClientId);
320c2c66affSColin Finck 
321c2c66affSColin Finck     /* Close the handle on success */
322c2c66affSColin Finck     if(NT_SUCCESS(Status)) NtClose(hThread);
323c2c66affSColin Finck 
324c2c66affSColin Finck     /* Return status */
325c2c66affSColin Finck     return Status;
326c2c66affSColin Finck }
327c2c66affSColin Finck 
328c2c66affSColin Finck /*
329c2c66affSColin Finck  * @implemented
330c2c66affSColin Finck  */
331c2c66affSColin Finck HANDLE
332c2c66affSColin Finck NTAPI
DbgUiGetThreadDebugObject(VOID)333c2c66affSColin Finck DbgUiGetThreadDebugObject(VOID)
334c2c66affSColin Finck {
335c2c66affSColin Finck     /* Just return the handle from the TEB */
336c2c66affSColin Finck     return NtCurrentTeb()->DbgSsReserved[1];
337c2c66affSColin Finck }
338c2c66affSColin Finck 
339c2c66affSColin Finck /*
340c2c66affSColin Finck * @implemented
341c2c66affSColin Finck */
342c2c66affSColin Finck VOID
343c2c66affSColin Finck NTAPI
DbgUiSetThreadDebugObject(HANDLE DebugObject)344c2c66affSColin Finck DbgUiSetThreadDebugObject(HANDLE DebugObject)
345c2c66affSColin Finck {
346c2c66affSColin Finck     /* Just set the handle in the TEB */
347c2c66affSColin Finck     NtCurrentTeb()->DbgSsReserved[1] = DebugObject;
348c2c66affSColin Finck }
349c2c66affSColin Finck 
350c2c66affSColin Finck /*
351c2c66affSColin Finck  * @implemented
352c2c66affSColin Finck  */
353c2c66affSColin Finck NTSTATUS
354c2c66affSColin Finck NTAPI
DbgUiDebugActiveProcess(IN HANDLE Process)355c2c66affSColin Finck DbgUiDebugActiveProcess(IN HANDLE Process)
356c2c66affSColin Finck {
357c2c66affSColin Finck     NTSTATUS Status;
358c2c66affSColin Finck 
359c2c66affSColin Finck     /* Tell the kernel to start debugging */
360c2c66affSColin Finck     Status = NtDebugActiveProcess(Process, NtCurrentTeb()->DbgSsReserved[1]);
361c2c66affSColin Finck     if (NT_SUCCESS(Status))
362c2c66affSColin Finck     {
363c2c66affSColin Finck         /* Now break-in the process */
364c2c66affSColin Finck         Status = DbgUiIssueRemoteBreakin(Process);
365c2c66affSColin Finck         if (!NT_SUCCESS(Status))
366c2c66affSColin Finck         {
367c2c66affSColin Finck             /* We couldn't break-in, cancel debugging */
368c2c66affSColin Finck             DbgUiStopDebugging(Process);
369c2c66affSColin Finck         }
370c2c66affSColin Finck     }
371c2c66affSColin Finck 
372c2c66affSColin Finck     /* Return status */
373c2c66affSColin Finck     return Status;
374c2c66affSColin Finck }
375c2c66affSColin Finck 
376c2c66affSColin Finck /*
377c2c66affSColin Finck  * @implemented
378c2c66affSColin Finck  */
379c2c66affSColin Finck NTSTATUS
380c2c66affSColin Finck NTAPI
DbgUiStopDebugging(IN HANDLE Process)381c2c66affSColin Finck DbgUiStopDebugging(IN HANDLE Process)
382c2c66affSColin Finck {
383c2c66affSColin Finck     /* Call the kernel to remove the debug object */
384c2c66affSColin Finck     return NtRemoveProcessDebug(Process, NtCurrentTeb()->DbgSsReserved[1]);
385c2c66affSColin Finck }
386c2c66affSColin Finck 
387c2c66affSColin Finck /* EOF */
388