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