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