* Sync up to trunk head (r65120).
[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
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 OBJECT_ATTRIBUTES ObjectAttributes;
66 THREAD_BASIC_INFORMATION ThreadBasicInfo;
67 LPDEBUG_EVENT DebugEvent = Win32DebugEvent;
68 HANDLE ThreadHandle;
69 HANDLE ProcessHandle;
70 PTEB Teb;
71 PVOID Pointer;
72
73 /* Write common data */
74 DebugEvent->dwProcessId = (DWORD)WaitStateChange->
75 AppClientId.UniqueProcess;
76 DebugEvent->dwThreadId = (DWORD)WaitStateChange->AppClientId.UniqueThread;
77
78 /* Check what kind of even this is */
79 switch (WaitStateChange->NewState)
80 {
81 /* New thread */
82 case DbgCreateThreadStateChange:
83
84 /* Setup Win32 code */
85 DebugEvent->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT;
86
87 /* Copy data over */
88 DebugEvent->u.CreateThread.hThread =
89 WaitStateChange->StateInfo.CreateThread.HandleToThread;
90 DebugEvent->u.CreateThread.lpStartAddress =
91 WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress;
92
93 /* Query the TEB */
94 Status = NtQueryInformationThread(WaitStateChange->StateInfo.
95 CreateThread.HandleToThread,
96 ThreadBasicInformation,
97 &ThreadBasicInfo,
98 sizeof(ThreadBasicInfo),
99 NULL);
100 if (!NT_SUCCESS(Status))
101 {
102 /* Failed to get PEB address */
103 DebugEvent->u.CreateThread.lpThreadLocalBase = NULL;
104 }
105 else
106 {
107 /* Write PEB Address */
108 DebugEvent->u.CreateThread.lpThreadLocalBase =
109 ThreadBasicInfo.TebBaseAddress;
110 }
111 break;
112
113 /* New process */
114 case DbgCreateProcessStateChange:
115
116 /* Write Win32 debug code */
117 DebugEvent->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT;
118
119 /* Copy data over */
120 DebugEvent->u.CreateProcessInfo.hProcess =
121 WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess;
122 DebugEvent->u.CreateProcessInfo.hThread =
123 WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread;
124 DebugEvent->u.CreateProcessInfo.hFile =
125 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
126 FileHandle;
127 DebugEvent->u.CreateProcessInfo.lpBaseOfImage =
128 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
129 BaseOfImage;
130 DebugEvent->u.CreateProcessInfo.dwDebugInfoFileOffset =
131 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
132 DebugInfoFileOffset;
133 DebugEvent->u.CreateProcessInfo.nDebugInfoSize =
134 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
135 DebugInfoSize;
136 DebugEvent->u.CreateProcessInfo.lpStartAddress =
137 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
138 InitialThread.StartAddress;
139
140 /* Query TEB address */
141 Status = NtQueryInformationThread(WaitStateChange->StateInfo.
142 CreateProcessInfo.HandleToThread,
143 ThreadBasicInformation,
144 &ThreadBasicInfo,
145 sizeof(ThreadBasicInfo),
146 NULL);
147 if (!NT_SUCCESS(Status))
148 {
149 /* Failed to get PEB address */
150 DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = NULL;
151 }
152 else
153 {
154 /* Write PEB Address */
155 DebugEvent->u.CreateProcessInfo.lpThreadLocalBase =
156 ThreadBasicInfo.TebBaseAddress;
157 }
158
159 /* Clear image name */
160 DebugEvent->u.CreateProcessInfo.lpImageName = NULL;
161 DebugEvent->u.CreateProcessInfo.fUnicode = TRUE;
162 break;
163
164 /* Thread exited */
165 case DbgExitThreadStateChange:
166
167 /* Write the Win32 debug code and the exit status */
168 DebugEvent->dwDebugEventCode = EXIT_THREAD_DEBUG_EVENT;
169 DebugEvent->u.ExitThread.dwExitCode =
170 WaitStateChange->StateInfo.ExitThread.ExitStatus;
171 break;
172
173 /* Process exited */
174 case DbgExitProcessStateChange:
175
176 /* Write the Win32 debug code and the exit status */
177 DebugEvent->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
178 DebugEvent->u.ExitProcess.dwExitCode =
179 WaitStateChange->StateInfo.ExitProcess.ExitStatus;
180 break;
181
182 /* Any sort of exception */
183 case DbgExceptionStateChange:
184 case DbgBreakpointStateChange:
185 case DbgSingleStepStateChange:
186
187 /* Check if this was a debug print */
188 if (WaitStateChange->StateInfo.Exception.ExceptionRecord.
189 ExceptionCode == DBG_PRINTEXCEPTION_C)
190 {
191 /* Set the Win32 code */
192 DebugEvent->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
193
194 /* Copy debug string information */
195 DebugEvent->u.DebugString.lpDebugStringData =
196 (PVOID)WaitStateChange->
197 StateInfo.Exception.ExceptionRecord.
198 ExceptionInformation[1];
199 DebugEvent->u.DebugString.nDebugStringLength =
200 WaitStateChange->StateInfo.Exception.ExceptionRecord.
201 ExceptionInformation[0];
202 DebugEvent->u.DebugString.fUnicode = FALSE;
203 }
204 else if (WaitStateChange->StateInfo.Exception.ExceptionRecord.
205 ExceptionCode == DBG_RIPEXCEPTION)
206 {
207 /* Set the Win32 code */
208 DebugEvent->dwDebugEventCode = RIP_EVENT;
209
210 /* Set exception information */
211 DebugEvent->u.RipInfo.dwType =
212 WaitStateChange->StateInfo.Exception.ExceptionRecord.
213 ExceptionInformation[1];
214 DebugEvent->u.RipInfo.dwError =
215 WaitStateChange->StateInfo.Exception.ExceptionRecord.
216 ExceptionInformation[0];
217 }
218 else
219 {
220 /* Otherwise, this is a debug event, copy info over */
221 DebugEvent->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
222 DebugEvent->u.Exception.ExceptionRecord =
223 WaitStateChange->StateInfo.Exception.ExceptionRecord;
224 DebugEvent->u.Exception.dwFirstChance =
225 WaitStateChange->StateInfo.Exception.FirstChance;
226 }
227 break;
228
229 /* DLL Load */
230 case DbgLoadDllStateChange:
231
232 /* Set the Win32 debug code */
233 DebugEvent->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
234
235 /* Copy the rest of the data */
236 DebugEvent->u.LoadDll.lpBaseOfDll =
237 WaitStateChange->StateInfo.LoadDll.BaseOfDll;
238 DebugEvent->u.LoadDll.hFile =
239 WaitStateChange->StateInfo.LoadDll.FileHandle;
240 DebugEvent->u.LoadDll.dwDebugInfoFileOffset =
241 WaitStateChange->StateInfo.LoadDll.DebugInfoFileOffset;
242 DebugEvent->u.LoadDll.nDebugInfoSize =
243 WaitStateChange->StateInfo.LoadDll.DebugInfoSize;
244
245 /* Open the thread */
246 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
247 Status = NtOpenThread(&ThreadHandle,
248 THREAD_QUERY_INFORMATION,
249 &ObjectAttributes,
250 &WaitStateChange->AppClientId);
251 if (NT_SUCCESS(Status))
252 {
253 /* Query thread information */
254 Status = NtQueryInformationThread(ThreadHandle,
255 ThreadBasicInformation,
256 &ThreadBasicInfo,
257 sizeof(ThreadBasicInfo),
258 NULL);
259 NtClose(ThreadHandle);
260 }
261
262 /* If we got thread information, open the process */
263 if (NT_SUCCESS(Status))
264 {
265 Status = NtOpenProcess(&ProcessHandle,
266 PROCESS_VM_READ,
267 &ObjectAttributes,
268 &WaitStateChange->AppClientId);
269 }
270
271 if (NT_SUCCESS(Status))
272 {
273 /* Read the image name from the TIB */
274 Teb = ThreadBasicInfo.TebBaseAddress;
275 Status = NtReadVirtualMemory(ProcessHandle,
276 &Teb->NtTib.ArbitraryUserPointer,
277 &Pointer,
278 sizeof(Pointer),
279 NULL);
280 NtClose(ProcessHandle);
281 }
282
283 if (NT_SUCCESS(Status))
284 {
285 /* If everything was successful, set the image name */
286 DebugEvent->u.LoadDll.lpImageName = Pointer;
287 }
288 else
289 {
290 /* Otherwise, no name */
291 DebugEvent->u.LoadDll.lpImageName = NULL;
292 }
293
294 /* It's Unicode */
295 DebugEvent->u.LoadDll.fUnicode = TRUE;
296 break;
297
298 /* DLL Unload */
299 case DbgUnloadDllStateChange:
300
301 /* Set Win32 code and DLL Base */
302 DebugEvent->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
303 DebugEvent->u.UnloadDll.lpBaseOfDll =
304 WaitStateChange->StateInfo.UnloadDll.BaseAddress;
305 break;
306
307 /* Anything else, fail */
308 default: return STATUS_UNSUCCESSFUL;
309 }
310
311 /* Return success */
312 return STATUS_SUCCESS;
313 }
314
315 /*
316 * @implemented
317 */
318 NTSTATUS
319 NTAPI
320 DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE DbgUiWaitStateCange,
321 IN PLARGE_INTEGER TimeOut OPTIONAL)
322 {
323 /* Tell the kernel to wait */
324 return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved[1],
325 TRUE,
326 TimeOut,
327 DbgUiWaitStateCange);
328 }
329
330 /*
331 * @implemented
332 */
333 VOID
334 NTAPI
335 DbgUiRemoteBreakin(VOID)
336 {
337 /* Make sure a debugger is enabled; if so, breakpoint */
338 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
339
340 /* Exit the thread */
341 RtlExitUserThread(STATUS_SUCCESS);
342 }
343
344 /*
345 * @implemented
346 */
347 NTSTATUS
348 NTAPI
349 DbgUiIssueRemoteBreakin(IN HANDLE Process)
350 {
351 HANDLE hThread;
352 CLIENT_ID ClientId;
353 NTSTATUS Status;
354
355 /* Create the thread that will do the breakin */
356 Status = RtlCreateUserThread(Process,
357 NULL,
358 FALSE,
359 0,
360 0,
361 PAGE_SIZE,
362 (PVOID)DbgUiRemoteBreakin,
363 NULL,
364 &hThread,
365 &ClientId);
366
367 /* Close the handle on success */
368 if(NT_SUCCESS(Status)) NtClose(hThread);
369
370 /* Return status */
371 return Status;
372 }
373
374 /*
375 * @implemented
376 */
377 HANDLE
378 NTAPI
379 DbgUiGetThreadDebugObject(VOID)
380 {
381 /* Just return the handle from the TEB */
382 return NtCurrentTeb()->DbgSsReserved[1];
383 }
384
385 /*
386 * @implemented
387 */
388 VOID
389 NTAPI
390 DbgUiSetThreadDebugObject(HANDLE DebugObject)
391 {
392 /* Just set the handle in the TEB */
393 NtCurrentTeb()->DbgSsReserved[1] = DebugObject;
394 }
395
396 /*
397 * @implemented
398 */
399 NTSTATUS
400 NTAPI
401 DbgUiDebugActiveProcess(IN HANDLE Process)
402 {
403 NTSTATUS Status;
404
405 /* Tell the kernel to start debugging */
406 Status = NtDebugActiveProcess(Process, NtCurrentTeb()->DbgSsReserved[1]);
407 if (NT_SUCCESS(Status))
408 {
409 /* Now break-in the process */
410 Status = DbgUiIssueRemoteBreakin(Process);
411 if (!NT_SUCCESS(Status))
412 {
413 /* We couldn't break-in, cancel debugging */
414 DbgUiStopDebugging(Process);
415 }
416 }
417
418 /* Return status */
419 return Status;
420 }
421
422 /*
423 * @implemented
424 */
425 NTSTATUS
426 NTAPI
427 DbgUiStopDebugging(IN HANDLE Process)
428 {
429 /* Call the kernel to remove the debug object */
430 return NtRemoveProcessDebug(Process, NtCurrentTeb()->DbgSsReserved[1]);
431 }
432
433 /* EOF */