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
DbgUiConnectToDbg(VOID)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
DbgUiContinue(IN PCLIENT_ID ClientId,IN NTSTATUS ContinueStatus)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
DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange,OUT PVOID Win32DebugEvent)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
DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange,IN PLARGE_INTEGER TimeOut OPTIONAL)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
DbgUiRemoteBreakin(VOID)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
DbgUiIssueRemoteBreakin(IN HANDLE Process)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
DbgUiGetThreadDebugObject(VOID)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
DbgUiSetThreadDebugObject(HANDLE DebugObject)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
DbgUiDebugActiveProcess(IN HANDLE Process)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
DbgUiStopDebugging(IN HANDLE Process)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