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