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)
9 /* INCLUDES *****************************************************************/
13 #include <ndk/dbgkfuncs.h>
18 /* FUNCTIONS *****************************************************************/
25 DbgUiConnectToDbg(VOID
)
27 OBJECT_ATTRIBUTES ObjectAttributes
;
29 /* Don't connect twice */
30 if (NtCurrentTeb()->DbgSsReserved
[1]) return STATUS_SUCCESS
;
32 /* Setup the Attributes */
33 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, 0);
35 /* Create the object */
36 return ZwCreateDebugObject(&NtCurrentTeb()->DbgSsReserved
[1],
37 DEBUG_OBJECT_ALL_ACCESS
,
39 DBGK_KILL_PROCESS_ON_EXIT
);
47 DbgUiContinue(IN PCLIENT_ID ClientId
,
48 IN NTSTATUS ContinueStatus
)
50 /* Tell the kernel object to continue */
51 return ZwDebugContinue(NtCurrentTeb()->DbgSsReserved
[1],
61 DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange
,
62 OUT PVOID Win32DebugEvent
)
65 OBJECT_ATTRIBUTES ObjectAttributes
;
66 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
67 LPDEBUG_EVENT DebugEvent
= Win32DebugEvent
;
73 /* Write common data */
74 DebugEvent
->dwProcessId
= (DWORD
)WaitStateChange
->
75 AppClientId
.UniqueProcess
;
76 DebugEvent
->dwThreadId
= (DWORD
)WaitStateChange
->AppClientId
.UniqueThread
;
78 /* Check what kind of even this is */
79 switch (WaitStateChange
->NewState
)
82 case DbgCreateThreadStateChange
:
84 /* Setup Win32 code */
85 DebugEvent
->dwDebugEventCode
= CREATE_THREAD_DEBUG_EVENT
;
88 DebugEvent
->u
.CreateThread
.hThread
=
89 WaitStateChange
->StateInfo
.CreateThread
.HandleToThread
;
90 DebugEvent
->u
.CreateThread
.lpStartAddress
=
91 WaitStateChange
->StateInfo
.CreateThread
.NewThread
.StartAddress
;
94 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
95 CreateThread
.HandleToThread
,
96 ThreadBasicInformation
,
98 sizeof(ThreadBasicInfo
),
100 if (!NT_SUCCESS(Status
))
102 /* Failed to get PEB address */
103 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
= NULL
;
107 /* Write PEB Address */
108 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
=
109 ThreadBasicInfo
.TebBaseAddress
;
114 case DbgCreateProcessStateChange
:
116 /* Write Win32 debug code */
117 DebugEvent
->dwDebugEventCode
= CREATE_PROCESS_DEBUG_EVENT
;
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
.
127 DebugEvent
->u
.CreateProcessInfo
.lpBaseOfImage
=
128 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
130 DebugEvent
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
=
131 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
133 DebugEvent
->u
.CreateProcessInfo
.nDebugInfoSize
=
134 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
136 DebugEvent
->u
.CreateProcessInfo
.lpStartAddress
=
137 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
138 InitialThread
.StartAddress
;
140 /* Query TEB address */
141 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
142 CreateProcessInfo
.HandleToThread
,
143 ThreadBasicInformation
,
145 sizeof(ThreadBasicInfo
),
147 if (!NT_SUCCESS(Status
))
149 /* Failed to get PEB address */
150 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
= NULL
;
154 /* Write PEB Address */
155 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
=
156 ThreadBasicInfo
.TebBaseAddress
;
159 /* Clear image name */
160 DebugEvent
->u
.CreateProcessInfo
.lpImageName
= NULL
;
161 DebugEvent
->u
.CreateProcessInfo
.fUnicode
= TRUE
;
165 case DbgExitThreadStateChange
:
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
;
174 case DbgExitProcessStateChange
:
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
;
182 /* Any sort of exception */
183 case DbgExceptionStateChange
:
184 case DbgBreakpointStateChange
:
185 case DbgSingleStepStateChange
:
187 /* Check if this was a debug print */
188 if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
189 ExceptionCode
== DBG_PRINTEXCEPTION_C
)
191 /* Set the Win32 code */
192 DebugEvent
->dwDebugEventCode
= OUTPUT_DEBUG_STRING_EVENT
;
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
;
204 else if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
205 ExceptionCode
== DBG_RIPEXCEPTION
)
207 /* Set the Win32 code */
208 DebugEvent
->dwDebugEventCode
= RIP_EVENT
;
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];
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
;
230 case DbgLoadDllStateChange
:
232 /* Set the Win32 debug code */
233 DebugEvent
->dwDebugEventCode
= LOAD_DLL_DEBUG_EVENT
;
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
;
245 /* Open the thread */
246 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
247 Status
= NtOpenThread(&ThreadHandle
,
248 THREAD_QUERY_INFORMATION
,
250 &WaitStateChange
->AppClientId
);
251 if (NT_SUCCESS(Status
))
253 /* Query thread information */
254 Status
= NtQueryInformationThread(ThreadHandle
,
255 ThreadBasicInformation
,
257 sizeof(ThreadBasicInfo
),
259 NtClose(ThreadHandle
);
262 /* If we got thread information, open the process */
263 if (NT_SUCCESS(Status
))
265 Status
= NtOpenProcess(&ProcessHandle
,
268 &WaitStateChange
->AppClientId
);
271 if (NT_SUCCESS(Status
))
273 /* Read the image name from the TIB */
274 Teb
= ThreadBasicInfo
.TebBaseAddress
;
275 Status
= NtReadVirtualMemory(ProcessHandle
,
276 &Teb
->NtTib
.ArbitraryUserPointer
,
280 NtClose(ProcessHandle
);
283 if (NT_SUCCESS(Status
))
285 /* If everything was successful, set the image name */
286 DebugEvent
->u
.LoadDll
.lpImageName
= Pointer
;
290 /* Otherwise, no name */
291 DebugEvent
->u
.LoadDll
.lpImageName
= NULL
;
295 DebugEvent
->u
.LoadDll
.fUnicode
= TRUE
;
299 case DbgUnloadDllStateChange
:
301 /* Set Win32 code and DLL Base */
302 DebugEvent
->dwDebugEventCode
= UNLOAD_DLL_DEBUG_EVENT
;
303 DebugEvent
->u
.UnloadDll
.lpBaseOfDll
=
304 WaitStateChange
->StateInfo
.UnloadDll
.BaseAddress
;
307 /* Anything else, fail */
308 default: return STATUS_UNSUCCESSFUL
;
312 return STATUS_SUCCESS
;
320 DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE DbgUiWaitStateCange
,
321 IN PLARGE_INTEGER TimeOut OPTIONAL
)
323 /* Tell the kernel to wait */
324 return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved
[1],
327 DbgUiWaitStateCange
);
335 DbgUiRemoteBreakin(VOID
)
337 /* Make sure a debugger is enabled; if so, breakpoint */
338 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
340 /* Exit the thread */
341 RtlExitUserThread(STATUS_SUCCESS
);
349 DbgUiIssueRemoteBreakin(IN HANDLE Process
)
355 /* Create the thread that will do the breakin */
356 Status
= RtlCreateUserThread(Process
,
362 (PVOID
)DbgUiRemoteBreakin
,
367 /* Close the handle on success */
368 if(NT_SUCCESS(Status
)) NtClose(hThread
);
379 DbgUiGetThreadDebugObject(VOID
)
381 /* Just return the handle from the TEB */
382 return NtCurrentTeb()->DbgSsReserved
[1];
390 DbgUiSetThreadDebugObject(HANDLE DebugObject
)
392 /* Just set the handle in the TEB */
393 NtCurrentTeb()->DbgSsReserved
[1] = DebugObject
;
401 DbgUiDebugActiveProcess(IN HANDLE Process
)
405 /* Tell the kernel to start debugging */
406 Status
= NtDebugActiveProcess(Process
, NtCurrentTeb()->DbgSsReserved
[1]);
407 if (NT_SUCCESS(Status
))
409 /* Now break-in the process */
410 Status
= DbgUiIssueRemoteBreakin(Process
);
411 if (!NT_SUCCESS(Status
))
413 /* We couldn't break-in, cancel debugging */
414 DbgUiStopDebugging(Process
);
427 DbgUiStopDebugging(IN HANDLE Process
)
429 /* Call the kernel to remove the debug object */
430 return NtRemoveProcessDebug(Process
, NtCurrentTeb()->DbgSsReserved
[1]);