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